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
49 #include "debugtools.h"
51 DEFAULT_DEBUG_CHANNEL(listview);
53 /* Some definitions for inline edit control */
54 typedef BOOL (*EditlblCallback)(HWND, LPSTR, DWORD);
56 typedef struct tagEDITLABEL_ITEM
60 EditlblCallback EditLblCb;
63 typedef struct tagLISTVIEW_SUBITEM
71 typedef struct tagLISTVIEW_ITEM
82 typedef struct tagLISTVIEW_SELECTION
88 typedef struct tagLISTVIEW_INFO
93 HIMAGELIST himlNormal;
99 HDPA hdpaSelectionRanges;
114 DWORD dwExStyle; /* extended listview style */
116 PFNLVCOMPARE pfnCompare;
120 EDITLABEL_ITEM *pedititem;
123 WPARAM charCode; /* Added */
124 CHAR szSearchParam[ MAX_PATH ]; /* Added */
125 DWORD timeSinceLastKeyPress; /* Added */
126 INT nSearchParamLength; /* Added */
133 /* maximum size of a label */
134 #define DISP_TEXT_SIZE 512
136 /* padding for items in list and small icon display modes */
137 #define WIDTH_PADDING 12
139 /* padding for items in list, report and small icon display modes */
140 #define HEIGHT_PADDING 1
142 /* offset of items in report display mode */
143 #define REPORT_MARGINX 2
145 /* padding for icon in large icon display mode */
146 #define ICON_TOP_PADDING 2
147 #define ICON_BOTTOM_PADDING 2
149 /* padding for label in large icon display mode */
150 #define LABEL_VERT_OFFSET 2
152 /* default label width for items in list and small icon display modes */
153 #define DEFAULT_LABEL_WIDTH 40
155 /* default column width for items in list display mode */
156 #define DEFAULT_COLUMN_WIDTH 96
158 /* Increment size of the horizontal scroll bar */
159 #define LISTVIEW_SCROLL_DIV_SIZE 10
161 /* Padding betwen image and label */
162 #define IMAGE_PADDING 2
164 /* Padding behind the label */
165 #define TRAILING_PADDING 5
167 /* Border for the icon caption */
168 #define CAPTION_BORDER 2
172 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
173 #define ListView_LVNotify(hwnd,lCtrlId,plvnm) \
174 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMLISTVIEW)(plvnm))
175 #define ListView_Notify(hwnd,lCtrlId,pnmh) \
176 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMHDR)(pnmh))
177 /* retrieve the number of items in the listview */
178 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
180 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
181 INT width, INT height, HWND parent, HINSTANCE hinst,
182 EditlblCallback EditLblCb, DWORD param);
185 * forward declarations
187 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem, BOOL internal);
188 static INT LISTVIEW_HitTestItem(HWND, LPLVHITTESTINFO);
189 static INT LISTVIEW_GetCountPerRow(HWND);
190 static INT LISTVIEW_GetCountPerColumn(HWND);
191 static VOID LISTVIEW_AlignLeft(HWND);
192 static VOID LISTVIEW_AlignTop(HWND);
193 static VOID LISTVIEW_AddGroupSelection(HWND, INT);
194 static VOID LISTVIEW_AddSelection(HWND, INT);
195 static BOOL LISTVIEW_AddSubItem(HWND, LPLVITEMA);
196 static INT LISTVIEW_FindInsertPosition(HDPA, INT);
197 static INT LISTVIEW_GetItemHeight(HWND);
198 static BOOL LISTVIEW_GetItemPosition(HWND, INT, LPPOINT);
199 static LRESULT LISTVIEW_GetItemRect(HWND, INT, LPRECT);
200 static INT LISTVIEW_GetItemWidth(HWND);
201 static INT LISTVIEW_GetLabelWidth(HWND, INT);
202 static LRESULT LISTVIEW_GetOrigin(HWND, LPPOINT);
203 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem);
204 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA, INT);
205 static LRESULT LISTVIEW_GetViewRect(HWND, LPRECT);
206 static BOOL LISTVIEW_InitItem(HWND, LISTVIEW_ITEM *, LPLVITEMA);
207 static BOOL LISTVIEW_InitSubItem(HWND, LISTVIEW_SUBITEM *, LPLVITEMA);
208 static LRESULT LISTVIEW_MouseSelection(HWND, POINT);
209 static BOOL LISTVIEW_RemoveColumn(HDPA, INT);
210 static BOOL LISTVIEW_RemoveSubItem(HDPA, INT);
211 static VOID LISTVIEW_SetGroupSelection(HWND, INT);
212 static BOOL LISTVIEW_SetItem(HWND, LPLVITEMA);
213 static BOOL LISTVIEW_SetItemFocus(HWND, INT);
214 static BOOL LISTVIEW_SetItemPosition(HWND, INT, INT, INT);
215 static VOID LISTVIEW_UpdateScroll(HWND);
216 static VOID LISTVIEW_SetSelection(HWND, INT);
217 static VOID LISTVIEW_UpdateSize(HWND);
218 static BOOL LISTVIEW_SetSubItem(HWND, LPLVITEMA);
219 static LRESULT LISTVIEW_SetViewRect(HWND, LPRECT);
220 static BOOL LISTVIEW_ToggleSelection(HWND, INT);
221 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle);
222 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem);
223 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem);
224 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam);
225 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam);
226 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText);
227 static INT LISTVIEW_ProcessLetterKeys( HWND hwnd, WPARAM charCode, LPARAM keyData );
228 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem);
229 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask);
230 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem);
231 static BOOL LISTVIEW_IsSelected(HWND hwnd, INT nItem);
233 /******** Defines that LISTVIEW_ProcessLetterKeys uses ****************/
234 #define KEY_DELAY 900
235 #define LISTVIEW_InitLvItemStruct(item,idx,TEXT) \
236 ZeroMemory(&(item), sizeof(LVITEMA)); \
237 (item).mask = LVIF_TEXT; \
238 (item).iItem = (idx); \
239 (item).iSubItem = 0; \
240 (item).pszText = (TEXT); \
241 (item).cchTextMax = MAX_PATH
244 LISTVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
247 LISTVIEW_INFO *infoPtr;
248 NMLVCUSTOMDRAW nmcdhdr;
251 TRACE("drawstage:%lx hdc:%x\n", dwDrawStage, hdc);
253 infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
255 nmcd= & nmcdhdr.nmcd;
256 nmcd->hdr.hwndFrom = hwnd;
257 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
258 nmcd->hdr.code = NM_CUSTOMDRAW;
259 nmcd->dwDrawStage= dwDrawStage;
261 nmcd->rc.left = rc.left;
262 nmcd->rc.right = rc.right;
263 nmcd->rc.bottom = rc.bottom;
264 nmcd->rc.top = rc.top;
265 nmcd->dwItemSpec = 0;
266 nmcd->uItemState = 0;
267 nmcd->lItemlParam= 0;
268 nmcdhdr.clrText = infoPtr->clrText;
269 nmcdhdr.clrTextBk= infoPtr->clrBk;
271 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
272 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
276 LISTVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
277 UINT iItem, UINT iSubItem,
280 LISTVIEW_INFO *infoPtr;
281 NMLVCUSTOMDRAW nmcdhdr;
283 DWORD dwDrawStage,dwItemSpec;
289 infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
291 ZeroMemory(&item,sizeof(LVITEMA));
293 item.mask = LVIF_PARAM;
294 ListView_GetItemA(hwnd,&item);
296 dwDrawStage=CDDS_ITEM | uItemDrawState;
300 if (LISTVIEW_IsSelected(hwnd,iItem)) uItemState|=CDIS_SELECTED;
301 if (iItem==infoPtr->nFocusedItem) uItemState|=CDIS_FOCUS;
302 if (iItem==infoPtr->nHotItem) uItemState|=CDIS_HOT;
304 itemRect.left = LVIR_BOUNDS;
305 LISTVIEW_GetItemRect(hwnd, iItem, &itemRect);
307 nmcd= & nmcdhdr.nmcd;
308 nmcd->hdr.hwndFrom = hwnd;
309 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
310 nmcd->hdr.code = NM_CUSTOMDRAW;
311 nmcd->dwDrawStage= dwDrawStage;
313 nmcd->rc.left = itemRect.left;
314 nmcd->rc.right = itemRect.right;
315 nmcd->rc.bottom = itemRect.bottom;
316 nmcd->rc.top = itemRect.top;
317 nmcd->dwItemSpec = dwItemSpec;
318 nmcd->uItemState = uItemState;
319 nmcd->lItemlParam= item.lParam;
320 nmcdhdr.clrText = infoPtr->clrText;
321 nmcdhdr.clrTextBk= infoPtr->clrBk;
322 nmcdhdr.iSubItem =iSubItem;
324 TRACE("drawstage:%lx hdc:%x item:%lx, itemstate:%x, lItemlParam:%lx\n",
325 nmcd->dwDrawStage, nmcd->hdc, nmcd->dwItemSpec,
326 nmcd->uItemState, nmcd->lItemlParam);
328 retval=SendMessageA (GetParent (hwnd), WM_NOTIFY,
329 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
331 infoPtr->clrText=nmcdhdr.clrText;
332 infoPtr->clrBk =nmcdhdr.clrTextBk;
333 return (BOOL) retval;
337 /*************************************************************************
339 * Processes keyboard messages generated by pressing the letter keys on the keyboard.
340 * Assumes the list is sorted alphabetically, without regard to case.
343 * [I] HWND: handle to the window
344 * [I] WPARAM: the character code, the actual character
345 * [I] LPARAM: key data
355 static INT LISTVIEW_ProcessLetterKeys( HWND hwnd, WPARAM charCode, LPARAM keyData )
357 LISTVIEW_INFO *infoPtr = NULL;
362 BOOL bFoundMatchingFiles = FALSE;
364 CHAR TEXT[ MAX_PATH ];
365 CHAR szCharCode[ 2 ];
366 DWORD timeSinceLastKeyPress = 0;
368 szCharCode[0] = charCode;
371 /* simple parameter checking */
372 if ( !hwnd || !charCode || !keyData )
375 infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
380 /* only allow the valid WM_CHARs through */
381 if ( isalnum( charCode ) || charCode == '.' || charCode == '`' || charCode == '!'
382 || charCode == '@' || charCode == '#' || charCode == '$' || charCode == '%'
383 || charCode == '^' || charCode == '&' || charCode == '*' || charCode == '('
384 || charCode == ')' || charCode == '-' || charCode == '_' || charCode == '+'
385 || charCode == '=' || charCode == '\\'|| charCode == ']' || charCode == '}'
386 || charCode == '[' || charCode == '{' || charCode == '/' || charCode == '?'
387 || charCode == '>' || charCode == '<' || charCode == ',' || charCode == '~')
389 timeSinceLastKeyPress = GetTickCount();
391 nSize = GETITEMCOUNT( infoPtr );
392 /* if there are 0 items, there is no where to go */
396 * If the last charCode equals the current charCode then look
397 * to the next element in list to see if it matches the previous
400 if ( infoPtr->charCode == charCode )
402 if ( timeSinceLastKeyPress - infoPtr->timeSinceLastKeyPress < KEY_DELAY )
403 { /* append new character to search string */
404 strcat( infoPtr->szSearchParam, szCharCode );
405 infoPtr->nSearchParamLength++;
407 /* loop from start of list view */
408 for( idx = infoPtr->nFocusedItem; idx < nSize; idx++ )
410 LISTVIEW_InitLvItemStruct( item, idx, TEXT );
411 ListView_GetItemA( hwnd, &item );
414 if ( strncasecmp( item.pszText, infoPtr->szSearchParam,
415 infoPtr->nSearchParamLength ) == 0 )
422 else if ( infoPtr->timeSinceLastKeyPress > timeSinceLastKeyPress )
423 { /* The DWORD went over it's boundery?? Ergo assuming too slow??. */
424 for ( idx = 0; idx < nSize; idx++ )
426 LISTVIEW_InitLvItemStruct( item, idx, TEXT );
427 ListView_GetItemA( hwnd, &item );
429 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
435 strcpy( infoPtr->szSearchParam, szCharCode );
436 infoPtr->nSearchParamLength = 1;
439 { /* Save szCharCode for use in later searches */
440 strcpy( infoPtr->szSearchParam, szCharCode );
441 infoPtr->nSearchParamLength = 1;
443 LISTVIEW_InitLvItemStruct( item, infoPtr->nFocusedItem + 1, TEXT );
444 ListView_GetItemA( hwnd, &item );
446 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
447 nItem = infoPtr->nFocusedItem + 1;
450 * Ok so there are no more folders that match
451 * now we look for files.
453 for ( idx = infoPtr->nFocusedItem + 1; idx < nSize; idx ++ )
455 LISTVIEW_InitLvItemStruct( item, idx, TEXT );
456 ListView_GetItemA( hwnd, &item );
458 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
461 bFoundMatchingFiles = TRUE;
465 if ( !bFoundMatchingFiles )
466 { /* go back to first instance */
467 for ( idx = 0; idx < nSize; idx ++ )
469 LISTVIEW_InitLvItemStruct( item,idx, TEXT );
470 ListView_GetItemA( hwnd, &item );
472 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
481 } /*END: if ( infoPtr->charCode == charCode )*/
483 else /* different keypressed */
485 /* could be that they are spelling the file/directory for us */
486 if ( timeSinceLastKeyPress - infoPtr->timeSinceLastKeyPress > KEY_DELAY )
488 * Too slow, move to the first instance of the
491 for ( idx = 0; idx < nSize; idx++ )
493 LISTVIEW_InitLvItemStruct( item,idx, TEXT );
494 ListView_GetItemA( hwnd, &item );
496 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
502 strcpy( infoPtr->szSearchParam, szCharCode );
503 infoPtr->nSearchParamLength = 1;
505 else if ( infoPtr->timeSinceLastKeyPress > timeSinceLastKeyPress )
506 { /* The DWORD went over it's boundery?? Ergo assuming too slow??. */
507 for ( idx = 0; idx < nSize; idx++ )
509 LISTVIEW_InitLvItemStruct( item,idx, TEXT );
510 ListView_GetItemA( hwnd, &item );
512 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
518 strcpy( infoPtr->szSearchParam, szCharCode );
519 infoPtr->nSearchParamLength = 1;
521 else /* Search for the string the user is typing */
523 /* append new character to search string */
524 strcat( infoPtr->szSearchParam, szCharCode );
525 infoPtr->nSearchParamLength++;
527 /* loop from start of list view */
528 for( idx = 0; idx < nSize; idx++ )
530 LISTVIEW_InitLvItemStruct( item, idx, TEXT );
531 ListView_GetItemA( hwnd, &item );
534 if ( strncasecmp( item.pszText, infoPtr->szSearchParam,
535 infoPtr->nSearchParamLength ) == 0 )
547 bRedraw = LISTVIEW_KeySelection(hwnd, nItem );
548 if (bRedraw != FALSE)
550 /* refresh client area */
551 InvalidateRect(hwnd, NULL, TRUE);
555 /* Store the WM_CHAR for next time */
556 infoPtr->charCode = charCode;
559 infoPtr->timeSinceLastKeyPress = timeSinceLastKeyPress;
565 /*************************************************************************
566 * LISTVIEW_UpdateHeaderSize [Internal]
568 * Function to resize the header control
571 * hwnd [I] handle to a window
572 * nNewScrollPos [I] Scroll Pos to Set
579 static VOID LISTVIEW_UpdateHeaderSize(HWND hwnd, INT nNewScrollPos)
581 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
585 GetWindowRect(infoPtr->hwndHeader, &winRect);
586 point[0].x = winRect.left;
587 point[0].y = winRect.top;
588 point[1].x = winRect.right;
589 point[1].y = winRect.bottom;
591 MapWindowPoints(HWND_DESKTOP, hwnd, point, 2);
592 point[0].x = -(nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
593 point[1].x += (nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
595 SetWindowPos(infoPtr->hwndHeader,0,
596 point[0].x,point[0].y,point[1].x,point[1].y,
597 SWP_NOZORDER | SWP_NOACTIVATE);
602 * Update the scrollbars. This functions should be called whenever
603 * the content, size or view changes.
606 * [I] HWND : window handle
611 static VOID LISTVIEW_UpdateScroll(HWND hwnd)
613 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
614 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
615 UINT uView = lStyle & LVS_TYPEMASK;
616 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
617 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
618 SCROLLINFO scrollInfo;
620 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
621 scrollInfo.cbSize = sizeof(SCROLLINFO);
623 if (uView == LVS_LIST)
625 /* update horizontal scrollbar */
627 INT nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
628 INT nCountPerRow = LISTVIEW_GetCountPerRow(hwnd);
629 INT nNumOfItems = GETITEMCOUNT(infoPtr);
631 scrollInfo.nMax = nNumOfItems / nCountPerColumn;
632 if((nNumOfItems % nCountPerColumn) == 0)
636 scrollInfo.nPos = ListView_GetTopIndex(hwnd) / nCountPerColumn;
637 scrollInfo.nPage = nCountPerRow;
638 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
639 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
640 ShowScrollBar(hwnd, SB_VERT, FALSE);
642 else if (uView == LVS_REPORT)
644 /* update vertical scrollbar */
646 scrollInfo.nMax = GETITEMCOUNT(infoPtr) - 1;
647 scrollInfo.nPos = ListView_GetTopIndex(hwnd);
648 scrollInfo.nPage = LISTVIEW_GetCountPerColumn(hwnd);
649 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
650 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
652 /* update horizontal scrollbar */
653 nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
654 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE
655 || GETITEMCOUNT(infoPtr) == 0)
660 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE ;
661 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
662 scrollInfo.nMax = max(infoPtr->nItemWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
663 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
665 /* Update the Header Control */
666 scrollInfo.fMask = SIF_POS;
667 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
668 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
675 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
677 INT nViewWidth = rcView.right - rcView.left;
678 INT nViewHeight = rcView.bottom - rcView.top;
680 /* Update Horizontal Scrollbar */
681 scrollInfo.fMask = SIF_POS;
682 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE
683 || GETITEMCOUNT(infoPtr) == 0)
687 scrollInfo.nMax = max(nViewWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
689 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
690 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
691 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
693 /* Update Vertical Scrollbar */
694 nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
695 scrollInfo.fMask = SIF_POS;
696 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) == FALSE
697 || GETITEMCOUNT(infoPtr) == 0)
701 scrollInfo.nMax = max(nViewHeight / LISTVIEW_SCROLL_DIV_SIZE,0)-1;
703 scrollInfo.nPage = nListHeight / LISTVIEW_SCROLL_DIV_SIZE;
704 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
705 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
712 * Prints a message for unsupported window styles.
713 * A kind of TODO list for window styles.
716 * [I] LONG : window style
721 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle)
723 if ((LVS_TYPEMASK & lStyle) == LVS_EDITLABELS)
725 FIXME(" LVS_EDITLABELS\n");
728 if ((LVS_TYPEMASK & lStyle) == LVS_NOLABELWRAP)
730 FIXME(" LVS_NOLABELWRAP\n");
733 if ((LVS_TYPEMASK & lStyle) == LVS_NOSCROLL)
735 FIXME(" LVS_NOSCROLL\n");
738 if ((LVS_TYPEMASK & lStyle) == LVS_NOSORTHEADER)
740 FIXME(" LVS_NOSORTHEADER\n");
743 if ((LVS_TYPEMASK & lStyle) == LVS_OWNERDRAWFIXED)
745 FIXME(" LVS_OWNERDRAWFIXED\n");
748 if ((LVS_TYPEMASK & lStyle) == LVS_SHAREIMAGELISTS)
750 FIXME(" LVS_SHAREIMAGELISTS\n");
753 if ((LVS_TYPEMASK & lStyle) == LVS_SORTASCENDING)
755 FIXME(" LVS_SORTASCENDING\n");
758 if ((LVS_TYPEMASK & lStyle) == LVS_SORTDESCENDING)
760 FIXME(" LVS_SORTDESCENDING\n");
766 * Aligns the items with the top edge of the window.
769 * [I] HWND : window handle
774 static VOID LISTVIEW_AlignTop(HWND hwnd)
776 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
777 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
778 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
783 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
785 ZeroMemory(&ptItem, sizeof(POINT));
786 ZeroMemory(&rcView, sizeof(RECT));
788 if (nListWidth > infoPtr->nItemWidth)
790 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
792 if (ptItem.x + infoPtr->nItemWidth > nListWidth)
795 ptItem.y += infoPtr->nItemHeight;
798 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
799 ptItem.x += infoPtr->nItemWidth;
800 rcView.right = max(rcView.right, ptItem.x);
803 rcView.bottom = ptItem.y + infoPtr->nItemHeight;
807 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
809 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
810 ptItem.y += infoPtr->nItemHeight;
813 rcView.right = infoPtr->nItemWidth;
814 rcView.bottom = ptItem.y;
817 LISTVIEW_SetViewRect(hwnd, &rcView);
823 * Aligns the items with the left edge of the window.
826 * [I] HWND : window handle
831 static VOID LISTVIEW_AlignLeft(HWND hwnd)
833 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
834 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
835 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
840 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
842 ZeroMemory(&ptItem, sizeof(POINT));
843 ZeroMemory(&rcView, sizeof(RECT));
845 if (nListHeight > infoPtr->nItemHeight)
847 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
849 if (ptItem.y + infoPtr->nItemHeight > nListHeight)
852 ptItem.x += infoPtr->nItemWidth;
855 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
856 ptItem.y += infoPtr->nItemHeight;
857 rcView.bottom = max(rcView.bottom, ptItem.y);
860 rcView.right = ptItem.x + infoPtr->nItemWidth;
864 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
866 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
867 ptItem.x += infoPtr->nItemWidth;
870 rcView.bottom = infoPtr->nItemHeight;
871 rcView.right = ptItem.x;
874 LISTVIEW_SetViewRect(hwnd, &rcView);
880 * Set the bounding rectangle of all the items.
883 * [I] HWND : window handle
884 * [I] LPRECT : bounding rectangle
890 static LRESULT LISTVIEW_SetViewRect(HWND hwnd, LPRECT lprcView)
892 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
893 BOOL bResult = FALSE;
895 TRACE("(hwnd=%x, left=%d, top=%d, right=%d, bottom=%d)\n", hwnd,
896 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
898 if (lprcView != NULL)
901 infoPtr->rcView.left = lprcView->left;
902 infoPtr->rcView.top = lprcView->top;
903 infoPtr->rcView.right = lprcView->right;
904 infoPtr->rcView.bottom = lprcView->bottom;
912 * Retrieves the bounding rectangle of all the items.
915 * [I] HWND : window handle
916 * [O] LPRECT : bounding rectangle
922 static LRESULT LISTVIEW_GetViewRect(HWND hwnd, LPRECT lprcView)
924 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
925 BOOL bResult = FALSE;
928 TRACE("(hwnd=%x, lprcView=%p)\n", hwnd, lprcView);
930 if (lprcView != NULL)
932 bResult = LISTVIEW_GetOrigin(hwnd, &ptOrigin);
933 if (bResult != FALSE)
935 lprcView->left = infoPtr->rcView.left + ptOrigin.x;
936 lprcView->top = infoPtr->rcView.top + ptOrigin.y;
937 lprcView->right = infoPtr->rcView.right + ptOrigin.x;
938 lprcView->bottom = infoPtr->rcView.bottom + ptOrigin.y;
941 TRACE("(left=%d, top=%d, right=%d, bottom=%d)\n",
942 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
950 * Retrieves the subitem pointer associated with the subitem index.
953 * [I] HDPA : DPA handle for a specific item
954 * [I] INT : index of subitem
957 * SUCCESS : subitem pointer
960 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems,
963 LISTVIEW_SUBITEM *lpSubItem;
966 for (i = 1; i < hdpaSubItems->nItemCount; i++)
968 lpSubItem = (LISTVIEW_SUBITEM *) DPA_GetPtr(hdpaSubItems, i);
969 if (lpSubItem != NULL)
971 if (lpSubItem->iSubItem == nSubItem)
983 * Calculates the width of an item.
986 * [I] HWND : window handle
987 * [I] LONG : window style
990 * Returns item width.
992 static INT LISTVIEW_GetItemWidth(HWND hwnd)
994 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
995 LONG style = GetWindowLongA(hwnd, GWL_STYLE);
996 UINT uView = style & LVS_TYPEMASK;
997 INT nHeaderItemCount;
1003 TRACE("(hwnd=%x)\n", hwnd);
1005 if (uView == LVS_ICON)
1007 nItemWidth = infoPtr->iconSpacing.cx;
1009 else if (uView == LVS_REPORT && (!(LVS_NOCOLUMNHEADER & style)) )
1011 /* calculate width of header */
1012 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
1013 for (i = 0; i < nHeaderItemCount; i++)
1015 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
1017 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
1023 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
1025 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, i);
1026 nItemWidth = max(nItemWidth, nLabelWidth);
1029 /* default label size */
1030 if (GETITEMCOUNT(infoPtr) == 0)
1032 nItemWidth = DEFAULT_COLUMN_WIDTH;
1036 if (nItemWidth == 0)
1038 nItemWidth = DEFAULT_LABEL_WIDTH;
1043 nItemWidth += WIDTH_PADDING;
1045 if (infoPtr->himlSmall != NULL)
1047 nItemWidth += infoPtr->iconSize.cx;
1050 if (infoPtr->himlState != NULL)
1052 nItemWidth += infoPtr->iconSize.cx;
1059 /* nItemWidth Cannot be Zero */
1067 * Calculates the width of a specific item.
1070 * [I] HWND : window handle
1071 * [I] LPSTR : string
1074 * Returns the width of an item width a specified string.
1076 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem)
1078 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1079 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
1080 INT nHeaderItemCount;
1085 TRACE("(hwnd=%x)\n", hwnd);
1087 if (uView == LVS_ICON)
1089 nItemWidth = infoPtr->iconSpacing.cx;
1091 else if (uView == LVS_REPORT)
1093 /* calculate width of header */
1094 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
1095 for (i = 0; i < nHeaderItemCount; i++)
1097 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
1099 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
1105 /* get width of string */
1106 nItemWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
1108 /* default label size */
1109 if (GETITEMCOUNT(infoPtr) == 0)
1111 nItemWidth = DEFAULT_COLUMN_WIDTH;
1115 if (nItemWidth == 0)
1117 nItemWidth = DEFAULT_LABEL_WIDTH;
1122 nItemWidth += WIDTH_PADDING;
1124 if (infoPtr->himlSmall != NULL)
1126 nItemWidth += infoPtr->iconSize.cx;
1129 if (infoPtr->himlState != NULL)
1131 nItemWidth += infoPtr->iconSize.cx;
1142 * Calculates the height of an item.
1145 * [I] HWND : window handle
1146 * [I] LONG : window style
1149 * Returns item height.
1151 static INT LISTVIEW_GetItemHeight(HWND hwnd)
1153 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1154 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
1155 INT nItemHeight = 0;
1157 if (uView == LVS_ICON)
1159 nItemHeight = infoPtr->iconSpacing.cy;
1164 HDC hdc = GetDC(hwnd);
1165 HFONT hOldFont = SelectObject(hdc, infoPtr->hFont);
1166 GetTextMetricsA(hdc, &tm);
1168 if(infoPtr->himlState || infoPtr->himlSmall)
1169 nItemHeight = max(tm.tmHeight, infoPtr->iconSize.cy) + HEIGHT_PADDING;
1171 nItemHeight = tm.tmHeight;
1173 SelectObject(hdc, hOldFont);
1174 ReleaseDC(hwnd, hdc);
1181 static void LISTVIEW_PrintSelectionRanges(hwnd)
1183 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1184 LISTVIEW_SELECTION *selection;
1185 INT topSelection = infoPtr->hdpaSelectionRanges->nItemCount;
1188 TRACE("Selections are:\n");
1189 for (i = 0; i < topSelection; i++)
1191 selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,i);
1192 TRACE(" %lu - %lu\n",selection->lower,selection->upper);
1198 * A compare function for selection ranges
1201 * [I] LPVOID : Item 1;
1202 * [I] LPVOID : Item 2;
1203 * [I] LPARAM : flags
1206 * >0 : if Item 1 > Item 2
1207 * <0 : if Item 2 > Item 1
1208 * 0 : if Item 1 == Item 2
1210 static INT CALLBACK LISTVIEW_CompareSelectionRanges(LPVOID range1, LPVOID range2,
1213 int l1 = ((LISTVIEW_SELECTION*)(range1))->lower;
1214 int l2 = ((LISTVIEW_SELECTION*)(range2))->lower;
1215 int u1 = ((LISTVIEW_SELECTION*)(range1))->upper;
1216 int u2 = ((LISTVIEW_SELECTION*)(range2))->upper;
1230 * Adds a selection range.
1233 * [I] HWND : window handle
1234 * [I] INT : lower item index
1235 * [I] INT : upper item index
1240 static VOID LISTVIEW_AddSelectionRange(HWND hwnd, INT lItem, INT uItem)
1242 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1243 LISTVIEW_SELECTION *selection;
1244 INT topSelection = infoPtr->hdpaSelectionRanges->nItemCount;
1245 BOOL lowerzero=FALSE;
1247 selection = (LISTVIEW_SELECTION *)COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION));
1248 selection->lower = lItem;
1249 selection->upper = uItem;
1251 TRACE("Add range %i - %i\n",lItem,uItem);
1254 LISTVIEW_SELECTION *checkselection,*checkselection2;
1255 INT index,mergeindex;
1257 /* find overlapping selections */
1258 /* we want to catch adjacent ranges so expand our range by 1 */
1261 if (selection->lower == 0)
1266 index = DPA_Search(infoPtr->hdpaSelectionRanges, selection, 0,
1267 LISTVIEW_CompareSelectionRanges,
1269 selection->upper --;
1273 selection->lower ++;
1277 checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,index);
1278 TRACE("Merge with index %i (%lu - %lu)\n",index,checkselection->lower,
1279 checkselection->upper);
1281 checkselection->lower = min(selection->lower,checkselection->lower);
1282 checkselection->upper = max(selection->upper,checkselection->upper);
1284 TRACE("New range (%lu - %lu)\n", checkselection->lower,
1285 checkselection->upper);
1287 COMCTL32_Free(selection);
1289 /* merge now common selection ranges in the lower group*/
1292 checkselection->upper ++;
1293 if (checkselection->lower == 0)
1296 checkselection->lower --;
1298 TRACE("search lower range (%lu - %lu)\n", checkselection->lower,
1299 checkselection->upper);
1301 /* not sorted yet */
1302 mergeindex = DPA_Search(infoPtr->hdpaSelectionRanges, checkselection, 0,
1303 LISTVIEW_CompareSelectionRanges, 0,
1306 checkselection->upper --;
1310 checkselection->lower ++;
1312 if (mergeindex >=0 && mergeindex != index)
1314 TRACE("Merge with index %i\n",mergeindex);
1315 checkselection2 = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
1317 checkselection->lower = min(checkselection->lower,
1318 checkselection2->lower);
1319 checkselection->upper = max(checkselection->upper,
1320 checkselection2->upper);
1321 COMCTL32_Free(checkselection2);
1322 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,mergeindex);
1326 while (mergeindex > -1 && mergeindex <index);
1328 /* merge now common selection ranges in the upper group*/
1331 checkselection->upper ++;
1332 if (checkselection->lower == 0)
1335 checkselection->lower --;
1337 TRACE("search upper range %i (%lu - %lu)\n",index,
1338 checkselection->lower, checkselection->upper);
1340 /* not sorted yet */
1341 mergeindex = DPA_Search(infoPtr->hdpaSelectionRanges, checkselection,
1343 LISTVIEW_CompareSelectionRanges, 0,
1346 checkselection->upper --;
1350 checkselection->lower ++;
1352 if (mergeindex >=0 && mergeindex !=index)
1354 TRACE("Merge with index %i\n",mergeindex);
1355 checkselection2 = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
1357 checkselection->lower = min(checkselection->lower,
1358 checkselection2->lower);
1359 checkselection->upper = max(checkselection->upper,
1360 checkselection2->upper);
1361 COMCTL32_Free(checkselection2);
1362 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,mergeindex);
1365 while (mergeindex > -1);
1370 index = DPA_Search(infoPtr->hdpaSelectionRanges, selection, 0,
1371 LISTVIEW_CompareSelectionRanges, 0,
1374 TRACE("Insert before index %i\n",index);
1377 DPA_InsertPtr(infoPtr->hdpaSelectionRanges,index,selection);
1382 DPA_InsertPtr(infoPtr->hdpaSelectionRanges,0,selection);
1387 DPA_Sort(infoPtr->hdpaSelectionRanges,LISTVIEW_CompareSelectionRanges,0);
1388 LISTVIEW_PrintSelectionRanges(hwnd);
1393 * check if a specified index is selected.
1396 * [I] HWND : window handle
1397 * [I] INT : item index
1402 static BOOL LISTVIEW_IsSelected(HWND hwnd, INT nItem)
1404 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1405 LISTVIEW_SELECTION selection;
1408 selection.upper = nItem;
1409 selection.lower = nItem;
1411 index = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, 0,
1412 LISTVIEW_CompareSelectionRanges,
1422 * Removes all selection ranges
1425 * HWND: window handle
1431 static LRESULT LISTVIEW_RemoveAllSelections(HWND hwnd)
1433 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1434 LISTVIEW_SELECTION *selection;
1438 TRACE("(0x%x)\n",hwnd);
1440 ZeroMemory(&item,sizeof(LVITEMA));
1441 item.stateMask = LVIS_SELECTED;
1445 selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,0);
1448 TRACE("Removing %lu to %lu\n",selection->lower, selection->upper);
1449 for (i = selection->lower; i<=selection->upper; i++)
1450 LISTVIEW_SetItemState(hwnd,i,&item);
1453 while (infoPtr->hdpaSelectionRanges->nItemCount>0);
1462 * Removes a range selections.
1465 * [I] HWND : window handle
1466 * [I] INT : lower item index
1467 * [I] INT : upper item index
1472 static VOID LISTVIEW_RemoveSelectionRange(HWND hwnd, INT lItem, INT uItem)
1474 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1475 LISTVIEW_SELECTION removeselection,*checkselection;
1478 removeselection.lower = lItem;
1479 removeselection.upper = uItem;
1481 TRACE("Remove range %lu - %lu\n",removeselection.lower,removeselection.upper);
1482 LISTVIEW_PrintSelectionRanges(hwnd);
1484 index = DPA_Search(infoPtr->hdpaSelectionRanges, &removeselection, 0,
1485 LISTVIEW_CompareSelectionRanges,
1492 checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
1495 TRACE("Matches range index %i (%lu-%lu)\n",index,checkselection->lower,
1496 checkselection->upper);
1499 if ((checkselection->upper == removeselection.upper) &&
1500 (checkselection->lower == removeselection.lower))
1502 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,index);
1505 /* case 2: engulf */
1506 else if (((checkselection->upper < removeselection.upper) &&
1507 (checkselection->lower > removeselection.lower))||
1508 ((checkselection->upper <= removeselection.upper) &&
1509 (checkselection->lower > removeselection.lower)) ||
1510 ((checkselection->upper < removeselection.upper) &&
1511 (checkselection->lower >= removeselection.lower)))
1514 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,index);
1515 /* do it again because others may also get caught */
1517 LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
1519 /* case 3: overlap upper */
1520 else if ((checkselection->upper < removeselection.upper) &&
1521 (checkselection->lower < removeselection.lower))
1523 checkselection->upper = removeselection.lower - 1;
1525 LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
1527 /* case 4: overlap lower */
1528 else if ((checkselection->upper > removeselection.upper) &&
1529 (checkselection->lower > removeselection.lower))
1531 checkselection->lower = removeselection.upper + 1;
1533 LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
1535 /* case 5: fully internal */
1536 else if (checkselection->upper == removeselection.upper)
1537 checkselection->upper = removeselection.lower - 1;
1538 else if (checkselection->lower == removeselection.lower)
1539 checkselection->lower = removeselection.upper + 1;
1542 /* bisect the range */
1543 LISTVIEW_SELECTION *newselection;
1545 newselection = (LISTVIEW_SELECTION *)
1546 COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION));
1547 newselection -> lower = checkselection->lower;
1548 newselection -> upper = removeselection.lower - 1;
1549 checkselection -> lower = removeselection.upper + 1;
1550 DPA_InsertPtr(infoPtr->hdpaSelectionRanges,index,newselection);
1552 DPA_Sort(infoPtr->hdpaSelectionRanges,LISTVIEW_CompareSelectionRanges,0);
1554 LISTVIEW_PrintSelectionRanges(hwnd);
1559 * shifts all selection indexs starting with the indesx specified
1560 * in the direction specified.
1563 * [I] HWND : window handle
1564 * [I] INT : item index
1565 * [I] INT : amount and direction of shift
1570 static VOID LISTVIEW_ShiftSelections(HWND hwnd, INT nItem, INT direction)
1572 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1573 LISTVIEW_SELECTION selection,*checkselection;
1576 selection.upper = nItem;
1577 selection.lower = nItem;
1579 index = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, 0,
1580 LISTVIEW_CompareSelectionRanges,
1581 0,DPAS_SORTED|DPAS_INSERTAFTER);
1583 while ((index < infoPtr->hdpaSelectionRanges->nItemCount)&&(index != -1))
1585 checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,index);
1586 if (checkselection->lower >= nItem)
1587 checkselection->lower += direction;
1588 if (checkselection->upper >= nItem)
1589 checkselection->upper += direction;
1597 * Adds a block of selections.
1600 * [I] HWND : window handle
1601 * [I] INT : item index
1606 static VOID LISTVIEW_AddGroupSelection(HWND hwnd, INT nItem)
1608 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1609 INT nFirst = min(infoPtr->nSelectionMark, nItem);
1610 INT nLast = max(infoPtr->nSelectionMark, nItem);
1614 ZeroMemory(&item,sizeof(LVITEMA));
1615 item.stateMask = LVIS_SELECTED;
1616 item.state = LVIS_SELECTED;
1618 for (i = nFirst; i <= nLast; i++);
1620 LISTVIEW_SetItemState(hwnd,i,&item);
1623 LISTVIEW_SetItemFocus(hwnd, nItem);
1624 infoPtr->nSelectionMark = nItem;
1630 * Adds a single selection.
1633 * [I] HWND : window handle
1634 * [I] INT : item index
1639 static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem)
1641 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1644 ZeroMemory(&item,sizeof(LVITEMA));
1645 item.state = LVIS_SELECTED;
1646 item.stateMask = LVIS_SELECTED;
1648 LISTVIEW_SetItemState(hwnd,nItem,&item);
1650 LISTVIEW_SetItemFocus(hwnd, nItem);
1651 infoPtr->nSelectionMark = nItem;
1656 * Selects or unselects an item.
1659 * [I] HWND : window handle
1660 * [I] INT : item index
1666 static BOOL LISTVIEW_ToggleSelection(HWND hwnd, INT nItem)
1668 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1672 ZeroMemory(&item,sizeof(LVITEMA));
1673 item.stateMask = LVIS_SELECTED;
1675 if (LISTVIEW_IsSelected(hwnd,nItem))
1678 LISTVIEW_SetItemState(hwnd,nItem,&item);
1683 item.state = LVIS_SELECTED;
1684 LISTVIEW_SetItemState(hwnd,nItem,&item);
1688 LISTVIEW_SetItemFocus(hwnd, nItem);
1689 infoPtr->nSelectionMark = nItem;
1696 * Selects items based on view coordinates.
1699 * [I] HWND : window handle
1700 * [I] RECT : selection rectangle
1705 static VOID LISTVIEW_SetSelectionRect(HWND hwnd, RECT rcSelRect)
1707 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1712 ZeroMemory(&item,sizeof(LVITEMA));
1713 item.stateMask = LVIS_SELECTED;
1715 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
1717 LISTVIEW_GetItemPosition(hwnd, i, &ptItem);
1719 if (PtInRect(&rcSelRect, ptItem) != FALSE)
1721 item.state = LVIS_SELECTED;
1722 LISTVIEW_SetItemState(hwnd,i,&item);
1727 LISTVIEW_SetItemState(hwnd,i,&item);
1734 * Sets a single group selection.
1737 * [I] HWND : window handle
1738 * [I] INT : item index
1743 static VOID LISTVIEW_SetGroupSelection(HWND hwnd, INT nItem)
1745 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1746 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
1749 ZeroMemory(&item,sizeof(LVITEMA));
1750 item.stateMask = LVIS_SELECTED;
1752 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
1755 INT nFirst = min(infoPtr->nSelectionMark, nItem);
1756 INT nLast = max(infoPtr->nSelectionMark, nItem);
1758 for (i = 0; i <= GETITEMCOUNT(infoPtr); i++)
1760 if ((i < nFirst) || (i > nLast))
1763 LISTVIEW_SetItemState(hwnd,i,&item);
1767 item.state = LVIS_SELECTED;
1768 LISTVIEW_SetItemState(hwnd,i,&item);
1777 LISTVIEW_GetItemPosition(hwnd, nItem, &ptItem);
1778 LISTVIEW_GetItemPosition(hwnd, infoPtr->nSelectionMark, &ptSelMark);
1779 rcSel.left = min(ptSelMark.x, ptItem.x);
1780 rcSel.top = min(ptSelMark.y, ptItem.y);
1781 rcSel.right = max(ptSelMark.x, ptItem.x) + infoPtr->nItemWidth;
1782 rcSel.bottom = max(ptSelMark.y, ptItem.y) + infoPtr->nItemHeight;
1783 LISTVIEW_SetSelectionRect(hwnd, rcSel);
1786 LISTVIEW_SetItemFocus(hwnd, nItem);
1791 * Manages the item focus.
1794 * [I] HWND : window handle
1795 * [I] INT : item index
1798 * TRUE : focused item changed
1799 * FALSE : focused item has NOT changed
1801 static BOOL LISTVIEW_SetItemFocus(HWND hwnd, INT nItem)
1803 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1804 BOOL bResult = FALSE;
1807 if (infoPtr->nFocusedItem != nItem)
1809 if (infoPtr->nFocusedItem >= 0)
1811 INT oldFocus = infoPtr->nFocusedItem;
1813 infoPtr->nFocusedItem = -1;
1814 ZeroMemory(&lvItem, sizeof(LVITEMA));
1815 lvItem.stateMask = LVIS_FOCUSED;
1816 ListView_SetItemState(hwnd, oldFocus, &lvItem);
1820 lvItem.state = LVIS_FOCUSED;
1821 lvItem.stateMask = LVIS_FOCUSED;
1822 ListView_SetItemState(hwnd, nItem, &lvItem);
1824 infoPtr->nFocusedItem = nItem;
1825 ListView_EnsureVisible(hwnd, nItem, FALSE);
1833 * Sets a single selection.
1836 * [I] HWND : window handle
1837 * [I] INT : item index
1842 static VOID LISTVIEW_SetSelection(HWND hwnd, INT nItem)
1844 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1847 ZeroMemory(&lvItem, sizeof(LVITEMA));
1848 lvItem.stateMask = LVIS_FOCUSED;
1849 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
1851 LISTVIEW_RemoveAllSelections(hwnd);
1853 lvItem.state = LVIS_FOCUSED|LVIS_SELECTED;
1854 lvItem.stateMask = LVIS_FOCUSED|LVIS_SELECTED;
1855 ListView_SetItemState(hwnd, nItem, &lvItem);
1857 infoPtr->nFocusedItem = nItem;
1858 infoPtr->nSelectionMark = nItem;
1863 * Set selection(s) with keyboard.
1866 * [I] HWND : window handle
1867 * [I] INT : item index
1870 * SUCCESS : TRUE (needs to be repainted)
1871 * FAILURE : FALSE (nothing has changed)
1873 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem)
1875 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1876 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1877 WORD wShift = HIWORD(GetKeyState(VK_SHIFT));
1878 WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL));
1879 BOOL bResult = FALSE;
1881 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
1883 if (lStyle & LVS_SINGLESEL)
1886 LISTVIEW_SetSelection(hwnd, nItem);
1887 ListView_EnsureVisible(hwnd, nItem, FALSE);
1894 LISTVIEW_SetGroupSelection(hwnd, nItem);
1898 bResult = LISTVIEW_SetItemFocus(hwnd, nItem);
1903 LISTVIEW_SetSelection(hwnd, nItem);
1904 ListView_EnsureVisible(hwnd, nItem, FALSE);
1914 * Called when the mouse is being actively tracked and has hovered for a specified
1918 * [I] HWND : window handle
1919 * [I] wParam : key indicator
1920 * [I] lParam : mouse position
1923 * 0 if the message was processed, non-zero if there was an error
1926 * LVS_EX_TRACKSELECT: An item is automatically selected when the cursor remains
1927 * over the item for a certain period of time.
1930 static LRESULT LISTVIEW_MouseHover(hwnd, wParam, lParam)
1932 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1935 pt.x = (INT)LOWORD(lParam);
1936 pt.y = (INT)HIWORD(lParam);
1938 if(infoPtr->dwExStyle & LVS_EX_TRACKSELECT) {
1939 /* select the item under the cursor */
1940 LISTVIEW_MouseSelection(hwnd, pt);
1948 * Called whenever WM_MOUSEMOVE is recieved.
1951 * [I] HWND : window handle
1952 * [I] wParam : key indicators
1953 * [I] lParam : cursor position
1956 * 0 if the message is processed, non-zero if there was an error
1958 static LRESULT LISTVIEW_MouseMove(HWND hwnd, WPARAM wParam, LPARAM lParam)
1960 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1961 TRACKMOUSEEVENT trackinfo;
1963 /* see if we are supposed to be tracking mouse hovering */
1964 if(infoPtr->dwExStyle & LVS_EX_TRACKSELECT) {
1965 /* fill in the trackinfo struct */
1966 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
1967 trackinfo.dwFlags = TME_QUERY;
1968 trackinfo.hwndTrack = hwnd;
1969 trackinfo.dwHoverTime = infoPtr->dwHoverTime;
1971 /* see if we are already tracking this hwnd */
1972 _TrackMouseEvent(&trackinfo);
1974 if(!(trackinfo.dwFlags & TME_HOVER)) {
1975 trackinfo.dwFlags = TME_HOVER;
1977 /* call TRACKMOUSEEVENT so we recieve WM_MOUSEHOVER messages */
1978 _TrackMouseEvent(&trackinfo);
1987 * Selects an item based on coordinates.
1990 * [I] HWND : window handle
1991 * [I] POINT : mouse click ccordinates
1994 * SUCCESS : item index
1997 static LRESULT LISTVIEW_MouseSelection(HWND hwnd, POINT pt)
1999 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2001 INT i,topindex,bottomindex;
2002 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2003 UINT uView = lStyle & LVS_TYPEMASK;
2005 topindex = ListView_GetTopIndex(hwnd);
2006 if (uView == LVS_REPORT)
2008 bottomindex = topindex + LISTVIEW_GetCountPerColumn(hwnd) + 1;
2009 bottomindex = min(bottomindex,GETITEMCOUNT(infoPtr));
2013 bottomindex = GETITEMCOUNT(infoPtr);
2016 for (i = topindex; i < bottomindex; i++)
2018 rcItem.left = LVIR_SELECTBOUNDS;
2019 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) == TRUE)
2021 if (PtInRect(&rcItem, pt) != FALSE)
2036 * [IO] HDPA : dynamic pointer array handle
2037 * [I] INT : column index (subitem index)
2043 static BOOL LISTVIEW_RemoveColumn(HDPA hdpaItems, INT nSubItem)
2045 BOOL bResult = TRUE;
2049 for (i = 0; i < hdpaItems->nItemCount; i++)
2051 hdpaSubItems = (HDPA)DPA_GetPtr(hdpaItems, i);
2052 if (hdpaSubItems != NULL)
2054 if (LISTVIEW_RemoveSubItem(hdpaSubItems, nSubItem) == FALSE)
2066 * Removes a subitem at a given position.
2069 * [IO] HDPA : dynamic pointer array handle
2070 * [I] INT : subitem index
2076 static BOOL LISTVIEW_RemoveSubItem(HDPA hdpaSubItems, INT nSubItem)
2078 LISTVIEW_SUBITEM *lpSubItem;
2081 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2083 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2084 if (lpSubItem != NULL)
2086 if (lpSubItem->iSubItem == nSubItem)
2089 if ((lpSubItem->pszText != NULL) &&
2090 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2092 COMCTL32_Free(lpSubItem->pszText);
2096 COMCTL32_Free(lpSubItem);
2098 /* free dpa memory */
2099 if (DPA_DeletePtr(hdpaSubItems, i) == NULL)
2104 else if (lpSubItem->iSubItem > nSubItem)
2116 * Compares the item information.
2119 * [I] LISTVIEW_ITEM *: destination item
2120 * [I] LPLVITEM : source item
2123 * SUCCCESS : TRUE (EQUAL)
2124 * FAILURE : FALSE (NOT EQUAL)
2126 static UINT LISTVIEW_GetItemChanges(LISTVIEW_ITEM *lpItem, LPLVITEMA lpLVItem)
2130 if ((lpItem != NULL) && (lpLVItem != NULL))
2132 if (lpLVItem->mask & LVIF_STATE)
2134 if ((lpItem->state & lpLVItem->stateMask) !=
2135 (lpLVItem->state & lpLVItem->stateMask))
2137 uChanged |= LVIF_STATE;
2141 if (lpLVItem->mask & LVIF_IMAGE)
2143 if (lpItem->iImage != lpLVItem->iImage)
2145 uChanged |= LVIF_IMAGE;
2149 if (lpLVItem->mask & LVIF_PARAM)
2151 if (lpItem->lParam != lpLVItem->lParam)
2153 uChanged |= LVIF_PARAM;
2157 if (lpLVItem->mask & LVIF_INDENT)
2159 if (lpItem->iIndent != lpLVItem->iIndent)
2161 uChanged |= LVIF_INDENT;
2165 if (lpLVItem->mask & LVIF_TEXT)
2167 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
2169 if (lpItem->pszText != LPSTR_TEXTCALLBACKA)
2171 uChanged |= LVIF_TEXT;
2176 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
2178 uChanged |= LVIF_TEXT;
2182 if (lpLVItem->pszText)
2184 if (lpItem->pszText)
2186 if (strcmp(lpLVItem->pszText, lpItem->pszText) != 0)
2188 uChanged |= LVIF_TEXT;
2193 uChanged |= LVIF_TEXT;
2198 if (lpItem->pszText)
2200 uChanged |= LVIF_TEXT;
2212 * Initializes item attributes.
2215 * [I] HWND : window handle
2216 * [O] LISTVIEW_ITEM *: destination item
2217 * [I] LPLVITEM : source item
2223 static BOOL LISTVIEW_InitItem(HWND hwnd, LISTVIEW_ITEM *lpItem,
2226 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2227 BOOL bResult = FALSE;
2229 if ((lpItem != NULL) && (lpLVItem != NULL))
2233 if (lpLVItem->mask & LVIF_STATE)
2235 lpItem->state &= ~lpLVItem->stateMask;
2236 lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
2239 if (lpLVItem->mask & LVIF_IMAGE)
2241 lpItem->iImage = lpLVItem->iImage;
2244 if (lpLVItem->mask & LVIF_PARAM)
2246 lpItem->lParam = lpLVItem->lParam;
2249 if (lpLVItem->mask & LVIF_INDENT)
2251 lpItem->iIndent = lpLVItem->iIndent;
2254 if (lpLVItem->mask & LVIF_TEXT)
2256 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
2258 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
2263 if ((lpItem->pszText != NULL) &&
2264 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2266 COMCTL32_Free(lpItem->pszText);
2269 lpItem->pszText = LPSTR_TEXTCALLBACKA;
2273 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
2275 lpItem->pszText = NULL;
2278 bResult = Str_SetPtrA(&lpItem->pszText, lpLVItem->pszText);
2288 * Initializes subitem attributes.
2290 * NOTE: The documentation specifies that the operation fails if the user
2291 * tries to set the indent of a subitem.
2294 * [I] HWND : window handle
2295 * [O] LISTVIEW_SUBITEM *: destination subitem
2296 * [I] LPLVITEM : source subitem
2302 static BOOL LISTVIEW_InitSubItem(HWND hwnd, LISTVIEW_SUBITEM *lpSubItem,
2305 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2306 BOOL bResult = FALSE;
2308 if ((lpSubItem != NULL) && (lpLVItem != NULL))
2310 if (!(lpLVItem->mask & LVIF_INDENT))
2314 lpSubItem->iSubItem = lpLVItem->iSubItem;
2316 if (lpLVItem->mask & LVIF_IMAGE)
2318 lpSubItem->iImage = lpLVItem->iImage;
2321 if (lpLVItem->mask & LVIF_TEXT)
2323 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
2325 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
2330 if ((lpSubItem->pszText != NULL) &&
2331 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2333 COMCTL32_Free(lpSubItem->pszText);
2336 lpSubItem->pszText = LPSTR_TEXTCALLBACKA;
2340 if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
2342 lpSubItem->pszText = NULL;
2345 bResult = Str_SetPtrA(&lpSubItem->pszText, lpLVItem->pszText);
2356 * Adds a subitem at a given position (column index).
2359 * [I] HWND : window handle
2360 * [I] LPLVITEM : new subitem atttributes
2366 static BOOL LISTVIEW_AddSubItem(HWND hwnd, LPLVITEMA lpLVItem)
2368 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2369 LISTVIEW_SUBITEM *lpSubItem = NULL;
2370 BOOL bResult = FALSE;
2372 INT nPosition, nItem;
2373 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2375 if (lStyle & LVS_OWNERDATA)
2378 if (lpLVItem != NULL)
2380 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
2381 if (hdpaSubItems != NULL)
2383 lpSubItem = (LISTVIEW_SUBITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM));
2384 if (lpSubItem != NULL)
2386 ZeroMemory(lpSubItem, sizeof(LISTVIEW_SUBITEM));
2387 if (LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem) != FALSE)
2389 nPosition = LISTVIEW_FindInsertPosition(hdpaSubItems,
2390 lpSubItem->iSubItem);
2391 nItem = DPA_InsertPtr(hdpaSubItems, nPosition, lpSubItem);
2401 /* cleanup if unsuccessful */
2402 if ((bResult == FALSE) && (lpSubItem != NULL))
2404 COMCTL32_Free(lpSubItem);
2412 * Finds the dpa insert position (array index).
2415 * [I] HWND : window handle
2416 * [I] INT : subitem index
2422 static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem)
2424 LISTVIEW_SUBITEM *lpSubItem;
2427 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2429 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2430 if (lpSubItem != NULL)
2432 if (lpSubItem->iSubItem > nSubItem)
2439 return hdpaSubItems->nItemCount;
2444 * Retrieves a listview subitem at a given position (column index).
2447 * [I] HWND : window handle
2448 * [I] INT : subitem index
2454 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem)
2456 LISTVIEW_SUBITEM *lpSubItem;
2459 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2461 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2462 if (lpSubItem != NULL)
2464 if (lpSubItem->iSubItem == nSubItem)
2468 else if (lpSubItem->iSubItem > nSubItem)
2480 * Sets item attributes.
2483 * [I] HWND : window handle
2484 * [I] LPLVITEM : new item atttributes
2490 static BOOL LISTVIEW_SetItem(HWND hwnd, LPLVITEMA lpLVItem)
2492 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2493 BOOL bResult = FALSE;
2495 LISTVIEW_ITEM *lpItem;
2497 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2498 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2500 UINT uView = lStyle & LVS_TYPEMASK;
2504 if (lStyle & LVS_OWNERDATA)
2506 if ((lpLVItem->iSubItem == 0)&&(lpLVItem->mask == LVIF_STATE))
2510 ZeroMemory(&itm,sizeof(LVITEMA));
2511 itm.mask = LVIF_STATE | LVIF_PARAM;
2512 itm.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
2513 itm.iItem = lpLVItem->iItem;
2515 ListView_GetItemA(hwnd,&itm);
2518 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2519 nmlv.hdr.hwndFrom = hwnd;
2520 nmlv.hdr.idFrom = lCtrlId;
2521 nmlv.hdr.code = LVN_ITEMCHANGING;
2522 nmlv.uNewState = lpLVItem->state;
2523 nmlv.uOldState = itm.state;
2524 nmlv.uChanged = LVIF_STATE;
2525 nmlv.lParam = itm.lParam;
2526 nmlv.iItem = lpLVItem->iItem;
2528 if ((itm.state & lpLVItem->stateMask) !=
2529 (lpLVItem->state & lpLVItem->stateMask))
2531 /* send LVN_ITEMCHANGING notification */
2532 if (!ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv))
2534 if (lpLVItem->stateMask & LVIS_FOCUSED)
2536 if (lpLVItem->state & LVIS_FOCUSED)
2537 infoPtr->nFocusedItem = lpLVItem->iItem;
2538 else if (infoPtr->nFocusedItem == lpLVItem->iItem)
2539 infoPtr->nFocusedItem = -1;
2541 if (lpLVItem->stateMask & LVIS_SELECTED)
2543 if (lpLVItem->state & LVIS_SELECTED)
2544 LISTVIEW_AddSelectionRange(hwnd,lpLVItem->iItem,lpLVItem->iItem);
2546 LISTVIEW_RemoveSelectionRange(hwnd,lpLVItem->iItem,
2550 nmlv.hdr.code = LVN_ITEMCHANGED;
2552 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2554 rcItem.left = LVIR_BOUNDS;
2555 LISTVIEW_GetItemRect(hwnd, lpLVItem->iItem, &rcItem);
2556 InvalidateRect(hwnd, &rcItem, TRUE);
2564 if (lpLVItem != NULL)
2566 if (lpLVItem->iSubItem == 0)
2568 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
2569 if (hdpaSubItems != NULL && hdpaSubItems != (HDPA)-1)
2571 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem);
2574 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2575 nmlv.hdr.hwndFrom = hwnd;
2576 nmlv.hdr.idFrom = lCtrlId;
2577 nmlv.hdr.code = LVN_ITEMCHANGING;
2578 nmlv.lParam = lpItem->lParam;
2579 uChanged = LISTVIEW_GetItemChanges(lpItem, lpLVItem);
2582 if (uChanged & LVIF_STATE)
2584 nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask;
2585 nmlv.uOldState = lpItem->state & lpLVItem->stateMask;
2587 if (nmlv.uNewState & LVIS_SELECTED)
2590 * This is redundant if called through SetSelection
2592 * however is required if the used directly calls SetItem
2593 * to set the selection.
2595 if (lStyle & LVS_SINGLESEL)
2597 LISTVIEW_RemoveAllSelections(hwnd);
2600 LISTVIEW_AddSelectionRange(hwnd,lpLVItem->iItem,
2603 else if (lpLVItem->stateMask & LVIS_SELECTED)
2605 LISTVIEW_RemoveSelectionRange(hwnd,lpLVItem->iItem,
2608 if (nmlv.uNewState & LVIS_FOCUSED)
2611 * This is a fun hoop to jump to try to catch if
2612 * the user is calling us directly to call focus or if
2613 * this function is being called as a result of a
2614 * SetItemFocus call.
2616 if (infoPtr->nFocusedItem >= 0)
2617 LISTVIEW_SetItemFocus(hwnd, lpLVItem->iItem);
2621 nmlv.uChanged = uChanged;
2622 nmlv.iItem = lpLVItem->iItem;
2623 nmlv.lParam = lpItem->lParam;
2624 /* send LVN_ITEMCHANGING notification */
2625 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2627 /* copy information */
2628 bResult = LISTVIEW_InitItem(hwnd, lpItem, lpLVItem);
2630 /* if LVS_LIST or LVS_SMALLICON, update the width of the items
2631 based on the width of the items text */
2632 if((uView == LVS_LIST) || (uView == LVS_SMALLICON))
2634 item_width = LISTVIEW_GetStringWidthA(hwnd, lpItem->pszText);
2636 if(item_width > infoPtr->nItemWidth)
2637 infoPtr->nItemWidth = item_width;
2640 /* send LVN_ITEMCHANGED notification */
2641 nmlv.hdr.code = LVN_ITEMCHANGED;
2642 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2651 rcItem.left = LVIR_BOUNDS;
2652 LISTVIEW_GetItemRect(hwnd, lpLVItem->iItem, &rcItem);
2653 InvalidateRect(hwnd, &rcItem, TRUE);
2665 * Sets subitem attributes.
2668 * [I] HWND : window handle
2669 * [I] LPLVITEM : new subitem atttributes
2675 static BOOL LISTVIEW_SetSubItem(HWND hwnd, LPLVITEMA lpLVItem)
2677 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2678 BOOL bResult = FALSE;
2680 LISTVIEW_SUBITEM *lpSubItem;
2681 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2684 if (lStyle & LVS_OWNERDATA)
2687 if (lpLVItem != NULL)
2689 if (lpLVItem->iSubItem > 0)
2691 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
2692 if (hdpaSubItems != NULL)
2694 /* set subitem only if column is present */
2695 if (Header_GetItemCount(infoPtr->hwndHeader) > lpLVItem->iSubItem)
2697 lpSubItem = LISTVIEW_GetSubItem(hdpaSubItems, lpLVItem->iSubItem);
2698 if (lpSubItem != NULL)
2700 bResult = LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem);
2704 bResult = LISTVIEW_AddSubItem(hwnd, lpLVItem);
2707 rcItem.left = LVIR_BOUNDS;
2708 LISTVIEW_GetItemRect(hwnd, lpLVItem->iItem, &rcItem);
2709 InvalidateRect(hwnd, &rcItem, FALSE);
2720 * Retrieves the index of the item at coordinate (0, 0) of the client area.
2723 * [I] HWND : window handle
2728 static INT LISTVIEW_GetTopIndex(HWND hwnd)
2730 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2731 UINT uView = lStyle & LVS_TYPEMASK;
2733 SCROLLINFO scrollInfo;
2735 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2736 scrollInfo.cbSize = sizeof(SCROLLINFO);
2737 scrollInfo.fMask = SIF_POS;
2739 if (uView == LVS_LIST)
2741 if (lStyle & WS_HSCROLL)
2743 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2745 nItem = scrollInfo.nPos * LISTVIEW_GetCountPerColumn(hwnd);
2749 else if (uView == LVS_REPORT)
2751 if (lStyle & WS_VSCROLL)
2753 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
2755 nItem = scrollInfo.nPos;
2768 * [I] HWND : window handle
2769 * [I] HDC : device context handle
2770 * [I] INT : item index
2771 * [I] INT : subitem index
2772 * [I] RECT * : clipping rectangle
2777 static VOID LISTVIEW_DrawSubItem(HWND hwnd, HDC hdc, INT nItem, INT nSubItem,
2778 RECT rcItem, BOOL Selected)
2780 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2781 CHAR szDispText[DISP_TEXT_SIZE];
2783 UINT textoutOptions = ETO_CLIPPED | ETO_OPAQUE;
2785 TRACE("(hwnd=%x, hdc=%x, nItem=%d, nSubItem=%d)\n", hwnd, hdc,
2788 /* get information needed for drawing the item */
2789 ZeroMemory(&lvItem, sizeof(LVITEMA));
2790 lvItem.mask = LVIF_TEXT;
2791 lvItem.iItem = nItem;
2792 lvItem.iSubItem = nSubItem;
2793 lvItem.cchTextMax = DISP_TEXT_SIZE;
2794 lvItem.pszText = szDispText;
2795 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
2797 /* set item colors */
2798 if (ListView_GetItemState(hwnd,nItem,LVIS_SELECTED)
2799 &&(infoPtr->bFocus != FALSE) && Selected)
2801 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
2802 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2806 if ( (infoPtr->clrTextBk == CLR_DEFAULT) || (infoPtr->clrTextBk == CLR_NONE) )
2808 SetBkMode(hdc, TRANSPARENT);
2809 textoutOptions &= ~ETO_OPAQUE;
2813 SetBkMode(hdc, OPAQUE);
2814 SetBkColor(hdc, infoPtr->clrTextBk);
2817 SetTextColor(hdc, infoPtr->clrText);
2820 ExtTextOutA(hdc, rcItem.left, rcItem.top, textoutOptions,
2821 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
2825 /* fill in the gap */
2827 if (nSubItem < Header_GetItemCount(infoPtr->hwndHeader)-1)
2829 CopyRect(&rec,&rcItem);
2830 rec.left = rec.right;
2831 rec.right = rec.left+REPORT_MARGINX;
2832 ExtTextOutA(hdc, rec.left , rec.top, textoutOptions,
2833 &rec, NULL, 0, NULL);
2835 CopyRect(&rec,&rcItem);
2836 rec.right = rec.left;
2837 rec.left = rec.left - REPORT_MARGINX;
2838 ExtTextOutA(hdc, rec.left , rec.top, textoutOptions,
2839 &rec, NULL, 0, NULL);
2849 * [I] HWND : window handle
2850 * [I] HDC : device context handle
2851 * [I] INT : item index
2852 * [I] RECT * : clipping rectangle
2857 static VOID LISTVIEW_DrawItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem, BOOL FullSelect, RECT* SuggestedFocus)
2859 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2860 CHAR szDispText[DISP_TEXT_SIZE];
2865 DWORD dwTextColor,dwTextX;
2866 BOOL bImage = FALSE;
2868 UINT textoutOptions = ETO_OPAQUE | ETO_CLIPPED;
2871 TRACE("(hwnd=%x, hdc=%x, nItem=%d)\n", hwnd, hdc, nItem);
2874 /* get information needed for drawing the item */
2875 ZeroMemory(&lvItem, sizeof(LVITEMA));
2876 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_INDENT;
2877 lvItem.stateMask = LVIS_SELECTED | LVIS_STATEIMAGEMASK;
2878 lvItem.iItem = nItem;
2879 lvItem.iSubItem = 0;
2880 lvItem.cchTextMax = DISP_TEXT_SIZE;
2881 lvItem.pszText = szDispText;
2882 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
2885 if (lvItem.iIndent>0 && infoPtr->iconSize.cx > 0)
2887 rcItem.left += infoPtr->iconSize.cx * lvItem.iIndent;
2890 SuggestedFocus->left += infoPtr->iconSize.cx * lvItem.iIndent;
2894 if (infoPtr->himlState != NULL)
2896 UINT uStateImage = (lvItem.state & LVIS_STATEIMAGEMASK) >> 12;
2897 if (uStateImage > 0)
2899 ImageList_Draw(infoPtr->himlState, uStateImage - 1, hdc, rcItem.left,
2900 rcItem.top, ILD_NORMAL);
2903 rcItem.left += infoPtr->iconSize.cx;
2905 SuggestedFocus->left += infoPtr->iconSize.cx;
2910 if (infoPtr->himlSmall != NULL)
2912 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE) &&
2915 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
2916 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
2917 rcItem.top, ILD_SELECTED);
2919 else if (lvItem.iImage>=0)
2921 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
2922 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
2923 rcItem.top, ILD_NORMAL);
2926 rcItem.left += infoPtr->iconSize.cx;
2929 SuggestedFocus->left += infoPtr->iconSize.cx;
2933 /* Don't bother painting item being edited */
2934 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED && !FullSelect)
2937 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
2939 /* set item colors */
2940 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
2941 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2942 /* set raster mode */
2943 nMixMode = SetROP2(hdc, R2_XORPEN);
2945 else if ((GetWindowLongA(hwnd, GWL_STYLE) & LVS_SHOWSELALWAYS) &&
2946 (lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus == FALSE))
2948 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
2949 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
2950 /* set raster mode */
2951 nMixMode = SetROP2(hdc, R2_COPYPEN);
2955 /* set item colors */
2956 if ( (infoPtr->clrTextBk == CLR_DEFAULT) || (infoPtr->clrTextBk == CLR_NONE) )
2958 dwBkColor = GetBkColor(hdc);
2959 iBkMode = SetBkMode(hdc, TRANSPARENT);
2960 textoutOptions &= ~ETO_OPAQUE;
2964 dwBkColor = SetBkColor(hdc, infoPtr->clrTextBk);
2965 iBkMode = SetBkMode(hdc, OPAQUE);
2968 dwTextColor = SetTextColor(hdc, infoPtr->clrText);
2969 /* set raster mode */
2970 nMixMode = SetROP2(hdc, R2_COPYPEN);
2973 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
2974 if (rcItem.left + nLabelWidth < rcItem.right)
2977 rcItem.right = rcItem.left + nLabelWidth + TRAILING_PADDING;
2979 rcItem.right += IMAGE_PADDING;
2983 dwTextX = rcItem.left + 1;
2985 dwTextX += IMAGE_PADDING;
2987 ExtTextOutA(hdc, dwTextX, rcItem.top, textoutOptions,
2988 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
2990 if ((FullSelect)&&(Header_GetItemCount(infoPtr->hwndHeader) > 1))
2992 /* fill in the gap */
2994 CopyRect(&rec,&rcItem);
2995 rec.left = rec.right;
2996 rec.right = rec.left+REPORT_MARGINX;
2997 ExtTextOutA(hdc, rec.left , rec.top, textoutOptions,
2998 &rec, NULL, 0, NULL);
3002 CopyRect(SuggestedFocus,&rcItem);
3006 SetROP2(hdc, R2_COPYPEN);
3007 SetBkColor(hdc, dwBkColor);
3008 SetTextColor(hdc, dwTextColor);
3010 SetBkMode(hdc, iBkMode);
3016 * Draws an item when in large icon display mode.
3019 * [I] HWND : window handle
3020 * [I] HDC : device context handle
3021 * [I] LISTVIEW_ITEM * : item
3022 * [I] INT : item index
3023 * [I] RECT * : clipping rectangle
3028 static VOID LISTVIEW_DrawLargeItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem,
3029 RECT *SuggestedFocus)
3031 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3032 CHAR szDispText[DISP_TEXT_SIZE];
3033 INT nDrawPosX = rcItem.left;
3034 INT nLabelWidth, rcWidth;
3037 UINT textoutOptions = ETO_CLIPPED | ETO_OPAQUE;
3039 TRACE("(hwnd=%x, hdc=%x, nItem=%d, left=%d, top=%d, right=%d, \
3040 bottom=%d)\n", hwnd, hdc, nItem, rcItem.left, rcItem.top, rcItem.right,
3043 /* get information needed for drawing the item */
3044 ZeroMemory(&lvItem, sizeof(LVITEMA));
3045 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
3046 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
3047 lvItem.iItem = nItem;
3048 lvItem.iSubItem = 0;
3049 lvItem.cchTextMax = DISP_TEXT_SIZE;
3050 lvItem.pszText = szDispText;
3051 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
3053 if (lvItem.state & LVIS_SELECTED)
3055 /* set item colors */
3056 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
3057 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
3058 /* set raster mode */
3059 SetROP2(hdc, R2_XORPEN);
3063 /* set item colors */
3064 if ( (infoPtr->clrTextBk == CLR_DEFAULT) || (infoPtr->clrTextBk == CLR_NONE) )
3066 SetBkMode(hdc, TRANSPARENT);
3067 textoutOptions &= ~ETO_OPAQUE;
3071 SetBkMode(hdc, OPAQUE);
3072 SetBkColor(hdc, infoPtr->clrTextBk);
3075 SetTextColor(hdc, infoPtr->clrText);
3076 /* set raster mode */
3077 SetROP2(hdc, R2_COPYPEN);
3080 if (infoPtr->himlNormal != NULL)
3082 rcItem.top += ICON_TOP_PADDING;
3083 nDrawPosX += (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
3084 if ((lvItem.state & LVIS_SELECTED) && (lvItem.iImage>=0))
3086 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
3087 rcItem.top, ILD_SELECTED);
3089 else if (lvItem.iImage>=0)
3091 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
3092 rcItem.top, ILD_NORMAL);
3096 /* Don't bother painting item being edited */
3097 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED)
3100 InflateRect(&rcItem, -(2*CAPTION_BORDER), 0);
3101 rcItem.top += infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
3102 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
3103 GetTextMetricsA(hdc, &tm);
3105 /* append an ellipse ('...') if the caption won't fit in the rect */
3106 rcWidth = max(0, rcItem.right - rcItem.left);
3107 if (nLabelWidth > rcWidth)
3109 INT i, len, eos, nCharsFit;
3110 /* give or take a couple, how many average sized chars would fit? */
3111 nCharsFit = tm.tmAveCharWidth > 0 ? (rcWidth/tm.tmAveCharWidth)+2 : 0;
3112 /* place the ellipse accordingly, without overrunning the buffer */
3113 len = strlen(szDispText);
3114 eos = min((nCharsFit > 1 && nCharsFit < len) ? nCharsFit+3 : len+2,
3115 sizeof(szDispText)-1);
3117 nLabelWidth = ListView_GetStringWidthA(hwnd, szDispText);
3118 while ((nLabelWidth > rcWidth) && (eos > 3))
3120 for (i = 1; i < 4; i++)
3121 szDispText[eos-i] = '.';
3122 /* shift the ellipse one char to the left for each iteration */
3123 szDispText[eos--] = '\0';
3124 nLabelWidth = ListView_GetStringWidthA(hwnd, szDispText);
3128 InflateRect(&rcItem, 2*CAPTION_BORDER, 0);
3129 nDrawPosX = infoPtr->iconSpacing.cx - 2*CAPTION_BORDER - nLabelWidth;
3132 rcItem.left += nDrawPosX / 2;
3133 rcItem.right = rcItem.left + nLabelWidth + 2*CAPTION_BORDER;
3138 rcItem.right = rcItem.left + infoPtr->iconSpacing.cx - 1;
3142 rcItem.bottom = rcItem.top + tm.tmHeight + HEIGHT_PADDING;
3144 ExtTextOutA(hdc, rcItem.left + CAPTION_BORDER, rcItem.top, textoutOptions,
3145 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
3148 CopyRect(SuggestedFocus,&rcItem);
3153 * Draws listview items when in report display mode.
3156 * [I] HWND : window handle
3157 * [I] HDC : device context handle
3162 static VOID LISTVIEW_RefreshReport(HWND hwnd, HDC hdc, DWORD cdmode)
3164 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
3165 SCROLLINFO scrollInfo;
3166 INT nDrawPosY = infoPtr->rcList.top;
3173 DWORD cditemmode = CDRF_DODEFAULT;
3174 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3176 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
3177 scrollInfo.cbSize = sizeof(SCROLLINFO);
3178 scrollInfo.fMask = SIF_POS;
3180 nItem = ListView_GetTopIndex(hwnd);
3182 /* add 1 for displaying a partial item at the bottom */
3183 nLast = nItem + LISTVIEW_GetCountPerColumn(hwnd) + 1;
3184 nLast = min(nLast, GETITEMCOUNT(infoPtr));
3186 /* send cache hint notification */
3187 if (GetWindowLongA(hwnd,GWL_STYLE) & LVS_OWNERDATA)
3191 nmlv.hdr.hwndFrom = hwnd;
3192 nmlv.hdr.idFrom = GetWindowLongA(hwnd,GWL_ID);
3193 nmlv.hdr.code = LVN_ODCACHEHINT;
3197 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)nmlv.hdr.idFrom,
3201 nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
3202 FullSelected = infoPtr->dwExStyle & LVS_EX_FULLROWSELECT;
3204 for (; nItem < nLast; nItem++)
3206 RECT SuggestedFocusRect;
3209 if (lStyle & LVS_OWNERDRAWFIXED)
3211 UINT uID = GetWindowLongA( hwnd, GWL_ID);
3216 TRACE("Owner Drawn\n");
3217 dis.CtlType = ODT_LISTVIEW;
3220 dis.itemAction = ODA_DRAWENTIRE;
3223 if (LISTVIEW_IsSelected(hwnd,nItem)) dis.itemState|=ODS_SELECTED;
3224 if (nItem==infoPtr->nFocusedItem) dis.itemState|=ODS_FOCUS;
3226 dis.hwndItem = hwnd;
3229 Header_GetItemRect(infoPtr->hwndHeader, 0, &dis.rcItem);
3230 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
3233 dis.rcItem.right = max(dis.rcItem.left, br.right);
3234 dis.rcItem.top = nDrawPosY;
3235 dis.rcItem.bottom = dis.rcItem.top + infoPtr->nItemHeight;
3237 ZeroMemory(&item,sizeof(LVITEMA));
3239 item.mask = LVIF_PARAM;
3240 ListView_GetItemA(hwnd,&item);
3242 dis.itemData = item.lParam;
3244 if (SendMessageA(GetParent(hwnd),WM_DRAWITEM,(WPARAM)uID,(LPARAM)&dis))
3246 nDrawPosY += infoPtr->nItemHeight;
3255 Header_GetItemRect(infoPtr->hwndHeader, 0, &ir);
3256 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
3258 ir.left += REPORT_MARGINX;
3259 ir.right = max(ir.left, br.right - REPORT_MARGINX);
3261 ir.bottom = ir.top + infoPtr->nItemHeight;
3263 CopyRect(&SuggestedFocusRect,&ir);
3266 for (j = 0; j < nColumnCount; j++)
3268 if (cdmode & CDRF_NOTIFYITEMDRAW)
3269 cditemmode = LISTVIEW_SendCustomDrawItemNotify (hwnd, hdc, nItem, j,
3271 if (cditemmode & CDRF_SKIPDEFAULT)
3274 Header_GetItemRect(infoPtr->hwndHeader, j, &rcItem);
3276 rcItem.left += REPORT_MARGINX;
3277 rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX);
3278 rcItem.top = nDrawPosY;
3279 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
3281 /* Offset the Scroll Bar Pos */
3282 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
3284 rcItem.left -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
3285 rcItem.right -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
3290 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem, FullSelected,
3291 &SuggestedFocusRect);
3295 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, j, rcItem,
3299 if (cditemmode & CDRF_NOTIFYPOSTPAINT)
3300 LISTVIEW_SendCustomDrawItemNotify(hwnd, hdc, nItem, 0,
3301 CDDS_ITEMPOSTPAINT);
3306 if (LISTVIEW_GetItemState(hwnd,nItem,LVIS_FOCUSED) && infoPtr->bFocus)
3309 if (FullSelected && LISTVIEW_GetItemState(hwnd,nItem,LVIS_SELECTED))
3310 rop = SetROP2(hdc, R2_XORPEN);
3312 Rectangle(hdc, SuggestedFocusRect.left, SuggestedFocusRect.top,
3313 SuggestedFocusRect.right,SuggestedFocusRect.bottom);
3316 SetROP2(hdc, R2_COPYPEN);
3318 nDrawPosY += infoPtr->nItemHeight;
3324 * Retrieves the number of items that can fit vertically in the client area.
3327 * [I] HWND : window handle
3330 * Number of items per row.
3332 static INT LISTVIEW_GetCountPerRow(HWND hwnd)
3334 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
3335 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3336 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
3337 INT nCountPerRow = 1;
3341 if (uView == LVS_REPORT)
3347 nCountPerRow = nListWidth / infoPtr->nItemWidth;
3348 if (nCountPerRow == 0)
3355 return nCountPerRow;
3360 * Retrieves the number of items that can fit horizontally in the client
3364 * [I] HWND : window handle
3367 * Number of items per column.
3369 static INT LISTVIEW_GetCountPerColumn(HWND hwnd)
3371 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
3372 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
3373 INT nCountPerColumn = 1;
3375 if (nListHeight > 0)
3377 nCountPerColumn = nListHeight / infoPtr->nItemHeight;
3378 if (nCountPerColumn == 0)
3380 nCountPerColumn = 1;
3384 return nCountPerColumn;
3389 * Retrieves the number of columns needed to display all the items when in
3390 * list display mode.
3393 * [I] HWND : window handle
3396 * Number of columns.
3398 static INT LISTVIEW_GetColumnCount(HWND hwnd)
3400 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3401 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3402 INT nColumnCount = 0;
3404 if ((lStyle & LVS_TYPEMASK) == LVS_LIST)
3406 if (infoPtr->rcList.right % infoPtr->nItemWidth == 0)
3408 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth;
3412 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth + 1;
3416 return nColumnCount;
3422 * Draws listview items when in list display mode.
3425 * [I] HWND : window handle
3426 * [I] HDC : device context handle
3431 static VOID LISTVIEW_RefreshList(HWND hwnd, HDC hdc, DWORD cdmode)
3433 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3434 RECT rcItem,FocusRect;
3438 INT nCountPerColumn;
3439 INT nItemWidth = infoPtr->nItemWidth;
3440 INT nItemHeight = infoPtr->nItemHeight;
3441 DWORD cditemmode = CDRF_DODEFAULT;
3443 /* get number of fully visible columns */
3444 nColumnCount = LISTVIEW_GetColumnCount(hwnd);
3445 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
3446 nItem = ListView_GetTopIndex(hwnd);
3448 for (i = 0; i < nColumnCount; i++)
3450 for (j = 0; j < nCountPerColumn; j++, nItem++)
3452 if (nItem >= GETITEMCOUNT(infoPtr))
3455 if (cdmode & CDRF_NOTIFYITEMDRAW)
3456 cditemmode = LISTVIEW_SendCustomDrawItemNotify (hwnd, hdc, nItem, 0,
3458 if (cditemmode & CDRF_SKIPDEFAULT)
3461 rcItem.top = j * nItemHeight;
3462 rcItem.left = i * nItemWidth;
3463 rcItem.bottom = rcItem.top + nItemHeight;
3464 rcItem.right = rcItem.left + nItemWidth;
3465 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem, FALSE, &FocusRect);
3469 if (LISTVIEW_GetItemState(hwnd,nItem,LVIS_FOCUSED) && infoPtr->bFocus)
3470 Rectangle(hdc, FocusRect.left, FocusRect.top,
3471 FocusRect.right,FocusRect.bottom);
3473 if (cditemmode & CDRF_NOTIFYPOSTPAINT)
3474 LISTVIEW_SendCustomDrawItemNotify(hwnd, hdc, nItem, 0,
3475 CDDS_ITEMPOSTPAINT);
3483 * Draws listview items when in icon or small icon display mode.
3486 * [I] HWND : window handle
3487 * [I] HDC : device context handle
3492 static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc, BOOL bSmall, DWORD cdmode)
3494 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3497 RECT rcItem,SuggestedFocus;
3499 DWORD cditemmode = CDRF_DODEFAULT;
3502 LISTVIEW_GetOrigin(hwnd, &ptOrigin);
3503 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
3505 if (cdmode & CDRF_NOTIFYITEMDRAW)
3506 cditemmode = LISTVIEW_SendCustomDrawItemNotify (hwnd, hdc, i, 0,
3508 if (cditemmode & CDRF_SKIPDEFAULT)
3511 LISTVIEW_GetItemPosition(hwnd, i, &ptPosition);
3512 ptPosition.x += ptOrigin.x;
3513 ptPosition.y += ptOrigin.y;
3515 if (ptPosition.y + infoPtr->nItemHeight > infoPtr->rcList.top)
3517 if (ptPosition.x + infoPtr->nItemWidth > infoPtr->rcList.left)
3519 if (ptPosition.y < infoPtr->rcList.bottom)
3521 if (ptPosition.x < infoPtr->rcList.right)
3523 rcItem.top = ptPosition.y;
3524 rcItem.left = ptPosition.x;
3525 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
3526 rcItem.right = rcItem.left + infoPtr->nItemWidth;
3527 if (bSmall == FALSE)
3529 LISTVIEW_DrawLargeItem(hwnd, hdc, i, rcItem, &SuggestedFocus);
3533 LISTVIEW_DrawItem(hwnd, hdc, i, rcItem, FALSE, &SuggestedFocus);
3538 if (LISTVIEW_GetItemState(hwnd,i,LVIS_FOCUSED) &&
3540 Rectangle(hdc, SuggestedFocus.left, SuggestedFocus.top,
3541 SuggestedFocus.right,SuggestedFocus.bottom);
3546 if (cditemmode & CDRF_NOTIFYPOSTPAINT)
3547 LISTVIEW_SendCustomDrawItemNotify(hwnd, hdc, i, 0,
3548 CDDS_ITEMPOSTPAINT);
3554 * Draws listview items.
3557 * [I] HWND : window handle
3558 * [I] HDC : device context handle
3563 static VOID LISTVIEW_Refresh(HWND hwnd, HDC hdc)
3565 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3566 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3572 GetClientRect(hwnd, &rect);
3573 cdmode = LISTVIEW_SendCustomDrawNotify(hwnd,CDDS_PREPAINT,hdc,rect);
3575 if (cdmode == CDRF_SKIPDEFAULT) return;
3578 hOldFont = SelectObject(hdc, infoPtr->hFont);
3580 /* select the dotted pen (for drawing the focus box) */
3581 hPen = CreatePen(PS_DOT, 1, 0);
3582 hOldPen = SelectObject(hdc, hPen);
3584 /* select transparent brush (for drawing the focus box) */
3585 SelectObject(hdc, GetStockObject(NULL_BRUSH));
3587 if (uView == LVS_LIST)
3589 LISTVIEW_RefreshList(hwnd, hdc, cdmode);
3591 else if (uView == LVS_REPORT)
3593 LISTVIEW_RefreshReport(hwnd, hdc, cdmode);
3595 else if (uView == LVS_SMALLICON)
3597 LISTVIEW_RefreshIcon(hwnd, hdc, TRUE, cdmode);
3599 else if (uView == LVS_ICON)
3601 LISTVIEW_RefreshIcon(hwnd, hdc, FALSE, cdmode);
3604 /* unselect objects */
3605 SelectObject(hdc, hOldFont);
3606 SelectObject(hdc, hOldPen);
3611 if (cdmode & CDRF_NOTIFYPOSTPAINT)
3612 LISTVIEW_SendCustomDrawNotify(hwnd, CDDS_POSTPAINT, hdc, rect);
3618 * Calculates the approximate width and height of a given number of items.
3621 * [I] HWND : window handle
3622 * [I] INT : number of items
3627 * Returns a DWORD. The width in the low word and the height in high word.
3629 static LRESULT LISTVIEW_ApproximateViewRect(HWND hwnd, INT nItemCount,
3630 WORD wWidth, WORD wHeight)
3632 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3633 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3634 INT nItemCountPerColumn = 1;
3635 INT nColumnCount = 0;
3636 DWORD dwViewRect = 0;
3638 if (nItemCount == -1)
3640 nItemCount = GETITEMCOUNT(infoPtr);
3643 if (uView == LVS_LIST)
3645 if (wHeight == 0xFFFF)
3647 /* use current height */
3648 wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
3651 if (wHeight < infoPtr->nItemHeight)
3653 wHeight = infoPtr->nItemHeight;
3658 if (infoPtr->nItemHeight > 0)
3660 nItemCountPerColumn = wHeight / infoPtr->nItemHeight;
3661 if (nItemCountPerColumn == 0)
3663 nItemCountPerColumn = 1;
3666 if (nItemCount % nItemCountPerColumn != 0)
3668 nColumnCount = nItemCount / nItemCountPerColumn;
3672 nColumnCount = nItemCount / nItemCountPerColumn + 1;
3677 /* Microsoft padding magic */
3678 wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2;
3679 wWidth = nColumnCount * infoPtr->nItemWidth + 2;
3681 dwViewRect = MAKELONG(wWidth, wHeight);
3683 else if (uView == LVS_REPORT)
3687 else if (uView == LVS_SMALLICON)
3691 else if (uView == LVS_ICON)
3701 * Arranges listview items in icon display mode.
3704 * [I] HWND : window handle
3705 * [I] INT : alignment code
3711 static LRESULT LISTVIEW_Arrange(HWND hwnd, INT nAlignCode)
3713 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3714 BOOL bResult = FALSE;
3716 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
3729 case LVA_SNAPTOGRID:
3738 /* << LISTVIEW_CreateDragImage >> */
3743 * Removes all listview items and subitems.
3746 * [I] HWND : window handle
3752 static LRESULT LISTVIEW_DeleteAllItems(HWND hwnd)
3754 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3755 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
3756 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3757 UINT uView = lStyle & LVS_TYPEMASK;
3758 LISTVIEW_ITEM *lpItem;
3759 LISTVIEW_SUBITEM *lpSubItem;
3762 BOOL bResult = FALSE;
3767 TRACE("(hwnd=%x,)\n", hwnd);
3768 LISTVIEW_RemoveAllSelections(hwnd);
3770 if (lStyle & LVS_OWNERDATA)
3772 infoPtr->hdpaItems->nItemCount = 0;
3773 InvalidateRect(hwnd, NULL, TRUE);
3777 if (GETITEMCOUNT(infoPtr) > 0)
3779 /* initialize memory */
3780 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
3782 /* send LVN_DELETEALLITEMS notification */
3783 nmlv.hdr.hwndFrom = hwnd;
3784 nmlv.hdr.idFrom = lCtrlId;
3785 nmlv.hdr.code = LVN_DELETEALLITEMS;
3788 /* verify if subsequent LVN_DELETEITEM notifications should be
3790 bSuppress = ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
3792 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
3794 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
3795 if (hdpaSubItems != NULL)
3797 for (j = 1; j < hdpaSubItems->nItemCount; j++)
3799 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, j);
3800 if (lpSubItem != NULL)
3802 /* free subitem string */
3803 if ((lpSubItem->pszText != NULL) &&
3804 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
3806 COMCTL32_Free(lpSubItem->pszText);
3810 COMCTL32_Free(lpSubItem);
3814 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3817 if (bSuppress == FALSE)
3819 /* send LVN_DELETEITEM notification */
3820 nmlv.hdr.code = LVN_DELETEITEM;
3822 nmlv.lParam = lpItem->lParam;
3823 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
3826 /* free item string */
3827 if ((lpItem->pszText != NULL) &&
3828 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
3830 COMCTL32_Free(lpItem->pszText);
3834 COMCTL32_Free(lpItem);
3837 DPA_Destroy(hdpaSubItems);
3841 /* reinitialize listview memory */
3842 bResult = DPA_DeleteAllPtrs(infoPtr->hdpaItems);
3844 /* align items (set position of each item) */
3845 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
3847 if (lStyle & LVS_ALIGNLEFT)
3849 LISTVIEW_AlignLeft(hwnd);
3853 LISTVIEW_AlignTop(hwnd);
3857 LISTVIEW_UpdateScroll(hwnd);
3859 /* invalidate client area (optimization needed) */
3860 InvalidateRect(hwnd, NULL, TRUE);
3868 * Removes a column from the listview control.
3871 * [I] HWND : window handle
3872 * [I] INT : column index
3878 static LRESULT LISTVIEW_DeleteColumn(HWND hwnd, INT nColumn)
3880 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3881 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3882 BOOL bResult = FALSE;
3884 if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) != FALSE)
3886 bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
3888 /* Need to reset the item width when deleting a column */
3889 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
3891 /* reset scroll parameters */
3892 if (uView == LVS_REPORT)
3894 /* update scrollbar(s) */
3895 LISTVIEW_UpdateScroll(hwnd);
3897 /* refresh client area */
3898 InvalidateRect(hwnd, NULL, FALSE);
3907 * Removes an item from the listview control.
3910 * [I] HWND : window handle
3911 * [I] INT : item index
3917 static LRESULT LISTVIEW_DeleteItem(HWND hwnd, INT nItem)
3919 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3920 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3921 UINT uView = lStyle & LVS_TYPEMASK;
3922 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
3924 BOOL bResult = FALSE;
3926 LISTVIEW_ITEM *lpItem;
3927 LISTVIEW_SUBITEM *lpSubItem;
3930 TRACE("(hwnd=%x,nItem=%d)\n", hwnd, nItem);
3932 LISTVIEW_ShiftSelections(hwnd,nItem,-1);
3934 if (lStyle & LVS_OWNERDATA)
3936 infoPtr->hdpaItems->nItemCount --;
3937 InvalidateRect(hwnd, NULL, TRUE);
3941 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
3943 /* initialize memory */
3944 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
3946 hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem);
3947 if (hdpaSubItems != NULL)
3949 for (i = 1; i < hdpaSubItems->nItemCount; i++)
3951 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
3952 if (lpSubItem != NULL)
3954 /* free item string */
3955 if ((lpSubItem->pszText != NULL) &&
3956 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
3958 COMCTL32_Free(lpSubItem->pszText);
3962 COMCTL32_Free(lpSubItem);
3966 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3969 /* send LVN_DELETEITEM notification */
3970 nmlv.hdr.hwndFrom = hwnd;
3971 nmlv.hdr.idFrom = lCtrlId;
3972 nmlv.hdr.code = LVN_DELETEITEM;
3974 nmlv.lParam = lpItem->lParam;
3975 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId,
3978 /* free item string */
3979 if ((lpItem->pszText != NULL) &&
3980 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
3982 COMCTL32_Free(lpItem->pszText);
3986 COMCTL32_Free(lpItem);
3989 bResult = DPA_Destroy(hdpaSubItems);
3992 /* align items (set position of each item) */
3993 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
3995 if (lStyle & LVS_ALIGNLEFT)
3997 LISTVIEW_AlignLeft(hwnd);
4001 LISTVIEW_AlignTop(hwnd);
4005 /* If this item had focus change focus to next or previous item */
4006 if (GETITEMCOUNT(infoPtr) > 0)
4008 int sItem = nItem < GETITEMCOUNT(infoPtr) ? nItem : nItem - 1;
4009 if (infoPtr->nFocusedItem == nItem)
4010 LISTVIEW_SetItemFocus(hwnd, sItem);
4013 infoPtr->nFocusedItem = -1;
4015 LISTVIEW_UpdateScroll(hwnd);
4017 /* refresh client area */
4018 InvalidateRect(hwnd, NULL, TRUE);
4027 * Return edit control handle of current edit label
4030 * [I] HWND : window handle
4036 static LRESULT LISTVIEW_GetEditControl(hwnd)
4038 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4039 return infoPtr->hwndEdit;
4045 * Callback implementation for editlabel control
4048 * [I] HWND : window handle
4049 * [I] LPSTR : modified text
4050 * [I] DWORD : item index
4057 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem)
4059 NMLVDISPINFOA dispInfo;
4060 LISTVIEW_ITEM *lpItem;
4061 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
4062 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4063 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4065 BOOL bUpdateItemText;
4066 LISTVIEW_ITEM lvItemRef;
4069 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
4071 if (!(lStyle & LVS_OWNERDATA))
4073 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
4076 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
4081 ZeroMemory(&lvItemRef,sizeof(LISTVIEW_ITEM));
4082 ZeroMemory(&item,sizeof(LVITEMA));
4085 item.mask = LVIF_PARAM | LVIF_STATE;
4086 ListView_GetItemA(hwnd,&item);
4087 lvItemRef.state = item.state;
4088 lvItemRef.iImage = item.iImage;
4089 lvItemRef.lParam = item.lParam;
4090 lpItem = &lvItemRef;
4093 dispInfo.hdr.hwndFrom = hwnd;
4094 dispInfo.hdr.idFrom = nCtrlId;
4095 dispInfo.hdr.code = LVN_ENDLABELEDITA;
4096 dispInfo.item.mask = 0;
4097 dispInfo.item.iItem = nItem;
4098 dispInfo.item.state = lpItem->state;
4099 dispInfo.item.stateMask = 0;
4100 dispInfo.item.pszText = pszText;
4101 dispInfo.item.cchTextMax = pszText ? strlen(pszText) : 0;
4102 dispInfo.item.iImage = lpItem->iImage;
4103 dispInfo.item.lParam = lpItem->lParam;
4104 infoPtr->hwndEdit = 0;
4106 bUpdateItemText = ListView_Notify(GetParent(hwnd), nCtrlId, &dispInfo);
4108 /* Do we need to update the Item Text */
4111 if ((lpItem->pszText != LPSTR_TEXTCALLBACKA)&&(!(lStyle & LVS_OWNERDATA)))
4113 Str_SetPtrA(&lpItem->pszText, pszText);
4122 * Begin in place editing of specified list view item
4125 * [I] HWND : window handle
4126 * [I] INT : item index
4133 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem)
4135 NMLVDISPINFOA dispInfo;
4137 LISTVIEW_ITEM *lpItem;
4139 HINSTANCE hinst = GetWindowLongA(hwnd, GWL_HINSTANCE);
4140 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
4141 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4143 CHAR szDispText[DISP_TEXT_SIZE];
4144 LVITEMA lvItem,item;
4145 LISTVIEW_ITEM lvItemRef;
4146 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4148 if (~GetWindowLongA(hwnd, GWL_STYLE) & LVS_EDITLABELS)
4151 /* Is the EditBox still there, if so remove it */
4152 if(infoPtr->hwndEdit != 0)
4157 LISTVIEW_SetSelection(hwnd, nItem);
4158 LISTVIEW_SetItemFocus(hwnd, nItem);
4160 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
4161 if (!(lStyle & LVS_OWNERDATA))
4163 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
4166 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
4171 ZeroMemory(&lvItemRef,sizeof(LISTVIEW_ITEM));
4172 ZeroMemory(&item,sizeof(LVITEMA));
4175 item.mask = LVIF_PARAM | LVIF_STATE;
4176 ListView_GetItemA(hwnd,&item);
4177 lvItemRef.iImage = item.iImage;
4178 lvItemRef.state = item.state;
4179 lvItemRef.lParam = item.lParam;
4180 lpItem = &lvItemRef;
4183 /* get information needed for drawing the item */
4184 ZeroMemory(&lvItem, sizeof(LVITEMA));
4185 lvItem.mask = LVIF_TEXT;
4186 lvItem.iItem = nItem;
4187 lvItem.iSubItem = 0;
4188 lvItem.cchTextMax = DISP_TEXT_SIZE;
4189 lvItem.pszText = szDispText;
4190 ListView_GetItemA(hwnd, &lvItem);
4192 dispInfo.hdr.hwndFrom = hwnd;
4193 dispInfo.hdr.idFrom = nCtrlId;
4194 dispInfo.hdr.code = LVN_BEGINLABELEDITA;
4195 dispInfo.item.mask = 0;
4196 dispInfo.item.iItem = nItem;
4197 dispInfo.item.state = lpItem->state;
4198 dispInfo.item.stateMask = 0;
4199 dispInfo.item.pszText = lvItem.pszText;
4200 dispInfo.item.cchTextMax = strlen(lvItem.pszText);
4201 dispInfo.item.iImage = lpItem->iImage;
4202 dispInfo.item.lParam = lpItem->lParam;
4204 if (ListView_LVNotify(GetParent(hwnd), nCtrlId, &dispInfo))
4207 rect.left = LVIR_LABEL;
4208 if (!LISTVIEW_GetItemRect(hwnd, nItem, &rect))
4211 if (!(hedit = CreateEditLabel(szDispText , WS_VISIBLE,
4212 rect.left-2, rect.top-1, 0,
4213 rect.bottom - rect.top+2,
4214 hwnd, hinst, LISTVIEW_EndEditLabel, nItem)))
4217 infoPtr->hwndEdit = hedit;
4219 SendMessageA(hedit, EM_SETSEL, 0, -1);
4227 * Ensures the specified item is visible, scrolling into view if necessary.
4230 * [I] HWND : window handle
4231 * [I] INT : item index
4232 * [I] BOOL : partially or entirely visible
4238 static BOOL LISTVIEW_EnsureVisible(HWND hwnd, INT nItem, BOOL bPartial)
4240 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4241 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4242 INT nScrollPosHeight = 0;
4243 INT nScrollPosWidth = 0;
4244 SCROLLINFO scrollInfo;
4246 BOOL bRedraw = FALSE;
4248 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
4249 scrollInfo.cbSize = sizeof(SCROLLINFO);
4250 scrollInfo.fMask = SIF_POS;
4252 /* ALWAYS bPartial == FALSE, FOR NOW! */
4254 rcItem.left = LVIR_BOUNDS;
4255 if (LISTVIEW_GetItemRect(hwnd, nItem, &rcItem) != FALSE)
4257 if (rcItem.left < infoPtr->rcList.left)
4259 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4263 if (uView == LVS_LIST)
4265 nScrollPosWidth = infoPtr->nItemWidth;
4266 rcItem.left += infoPtr->rcList.left;
4268 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4270 nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
4271 rcItem.left += infoPtr->rcList.left;
4274 /* When in LVS_REPORT view, the scroll position should
4276 if (nScrollPosWidth != 0)
4278 if (rcItem.left % nScrollPosWidth == 0)
4280 scrollInfo.nPos += rcItem.left / nScrollPosWidth;
4284 scrollInfo.nPos += rcItem.left / nScrollPosWidth - 1;
4287 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
4291 else if (rcItem.right > infoPtr->rcList.right)
4293 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4297 if (uView == LVS_LIST)
4299 rcItem.right -= infoPtr->rcList.right;
4300 nScrollPosWidth = infoPtr->nItemWidth;
4302 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4304 rcItem.right -= infoPtr->rcList.right;
4305 nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
4308 /* When in LVS_REPORT view, the scroll position should
4310 if (nScrollPosWidth != 0)
4312 if (rcItem.right % nScrollPosWidth == 0)
4314 scrollInfo.nPos += rcItem.right / nScrollPosWidth;
4318 scrollInfo.nPos += rcItem.right / nScrollPosWidth + 1;
4321 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
4326 if (rcItem.top < infoPtr->rcList.top)
4330 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4332 if (uView == LVS_REPORT)
4334 rcItem.top -= infoPtr->rcList.top;
4335 nScrollPosHeight = infoPtr->nItemHeight;
4337 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
4339 nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
4340 rcItem.top += infoPtr->rcList.top;
4343 if (rcItem.top % nScrollPosHeight == 0)
4345 scrollInfo.nPos += rcItem.top / nScrollPosHeight;
4349 scrollInfo.nPos += rcItem.top / nScrollPosHeight - 1;
4352 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
4355 else if (rcItem.bottom > infoPtr->rcList.bottom)
4359 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4361 if (uView == LVS_REPORT)
4363 rcItem.bottom -= infoPtr->rcList.bottom;
4364 nScrollPosHeight = infoPtr->nItemHeight;
4366 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
4368 nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
4369 rcItem.bottom -= infoPtr->rcList.bottom;
4372 if (rcItem.bottom % nScrollPosHeight == 0)
4374 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight;
4378 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight + 1;
4381 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
4387 InvalidateRect(hwnd,NULL,TRUE);
4393 * Retrieves the nearest item, given a position and a direction.
4396 * [I] HWND : window handle
4397 * [I] POINT : start position
4398 * [I] UINT : direction
4401 * Item index if successdful, -1 otherwise.
4403 static INT LISTVIEW_GetNearestItem(HWND hwnd, POINT pt, UINT vkDirection)
4405 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4406 LVHITTESTINFO lvHitTestInfo;
4410 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
4412 ZeroMemory(&lvHitTestInfo, sizeof(LVHITTESTINFO));
4413 LISTVIEW_GetOrigin(hwnd, &lvHitTestInfo.pt);
4414 lvHitTestInfo.pt.x += pt.x;
4415 lvHitTestInfo.pt.y += pt.y;
4419 if (vkDirection == VK_DOWN)
4421 lvHitTestInfo.pt.y += infoPtr->nItemHeight;
4423 else if (vkDirection == VK_UP)
4425 lvHitTestInfo.pt.y -= infoPtr->nItemHeight;
4427 else if (vkDirection == VK_LEFT)
4429 lvHitTestInfo.pt.x -= infoPtr->nItemWidth;
4431 else if (vkDirection == VK_RIGHT)
4433 lvHitTestInfo.pt.x += infoPtr->nItemWidth;
4436 if (PtInRect(&rcView, lvHitTestInfo.pt) == FALSE)
4442 nItem = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo);
4446 while (nItem == -1);
4454 * Searches for an item with specific characteristics.
4457 * [I] HWND : window handle
4458 * [I] INT : base item index
4459 * [I] LPLVFINDINFO : item information to look for
4462 * SUCCESS : index of item
4465 static LRESULT LISTVIEW_FindItem(HWND hwnd, INT nStart,
4466 LPLVFINDINFO lpFindInfo)
4468 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4470 CHAR szDispText[DISP_TEXT_SIZE];
4474 INT nLast = GETITEMCOUNT(infoPtr);
4476 if ((nItem >= -1) && (lpFindInfo != NULL))
4478 ZeroMemory(&lvItem, sizeof(LVITEMA));
4480 if (lpFindInfo->flags & LVFI_PARAM)
4482 lvItem.mask |= LVIF_PARAM;
4485 if (lpFindInfo->flags & LVFI_STRING)
4487 lvItem.mask |= LVIF_TEXT;
4488 lvItem.pszText = szDispText;
4489 lvItem.cchTextMax = DISP_TEXT_SIZE;
4492 if (lpFindInfo->flags & LVFI_PARTIAL)
4494 lvItem.mask |= LVIF_TEXT;
4495 lvItem.pszText = szDispText;
4496 lvItem.cchTextMax = DISP_TEXT_SIZE;
4499 if (lpFindInfo->flags & LVFI_WRAP)
4504 if (lpFindInfo->flags & LVFI_NEARESTXY)
4506 ptItem.x = lpFindInfo->pt.x;
4507 ptItem.y = lpFindInfo->pt.y;
4512 while (nItem < nLast)
4514 if (lpFindInfo->flags & LVFI_NEARESTXY)
4516 nItem = LISTVIEW_GetNearestItem(hwnd, ptItem,
4517 lpFindInfo->vkDirection);
4520 /* get position of the new item index */
4521 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) == FALSE)
4532 lvItem.iItem = nItem;
4533 lvItem.iSubItem = 0;
4534 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
4536 if (lvItem.mask & LVIF_TEXT)
4538 if (lpFindInfo->flags & LVFI_PARTIAL)
4540 if (strstr(lvItem.pszText, lpFindInfo->psz) == NULL)
4545 if (strcmp(lvItem.pszText, lpFindInfo->psz) != 0)
4550 if (lvItem.mask & LVIF_PARAM)
4552 if (lpFindInfo->lParam != lvItem.lParam)
4578 * Retrieves the background color of the listview control.
4581 * [I] HWND : window handle
4584 * COLORREF associated with the background.
4586 static LRESULT LISTVIEW_GetBkColor(HWND hwnd)
4588 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4590 return infoPtr->clrBk;
4595 * Retrieves the background image of the listview control.
4598 * [I] HWND : window handle
4599 * [O] LPLVMKBIMAGE : background image attributes
4605 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
4607 /* FIXME (listview, "empty stub!\n"); */
4613 * Retrieves the callback mask.
4616 * [I] HWND : window handle
4621 static UINT LISTVIEW_GetCallbackMask(HWND hwnd)
4623 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4625 return infoPtr->uCallbackMask;
4630 * Retrieves column attributes.
4633 * [I] HWND : window handle
4634 * [I] INT : column index
4635 * [IO] LPLVCOLUMNA : column information
4641 static LRESULT LISTVIEW_GetColumnA(HWND hwnd, INT nItem, LPLVCOLUMNA lpColumn)
4643 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4645 BOOL bResult = FALSE;
4647 if (lpColumn != NULL)
4649 /* initialize memory */
4650 ZeroMemory(&hdi, sizeof(HDITEMA));
4652 if (lpColumn->mask & LVCF_FMT)
4654 hdi.mask |= HDI_FORMAT;
4657 if (lpColumn->mask & LVCF_WIDTH)
4659 hdi.mask |= HDI_WIDTH;
4662 if (lpColumn->mask & LVCF_TEXT)
4664 hdi.mask |= HDI_TEXT;
4665 hdi.cchTextMax = lpColumn->cchTextMax;
4666 hdi.pszText = lpColumn->pszText;
4669 if (lpColumn->mask & LVCF_IMAGE)
4671 hdi.mask |= HDI_IMAGE;
4674 if (lpColumn->mask & LVCF_ORDER)
4676 hdi.mask |= HDI_ORDER;
4679 bResult = Header_GetItemA(infoPtr->hwndHeader, nItem, &hdi);
4680 if (bResult != FALSE)
4682 if (lpColumn->mask & LVCF_FMT)
4686 if (hdi.fmt & HDF_LEFT)
4688 lpColumn->fmt |= LVCFMT_LEFT;
4690 else if (hdi.fmt & HDF_RIGHT)
4692 lpColumn->fmt |= LVCFMT_RIGHT;
4694 else if (hdi.fmt & HDF_CENTER)
4696 lpColumn->fmt |= LVCFMT_CENTER;
4699 if (hdi.fmt & HDF_IMAGE)
4701 lpColumn->fmt |= LVCFMT_COL_HAS_IMAGES;
4704 if (hdi.fmt & HDF_BITMAP_ON_RIGHT)
4706 lpColumn->fmt |= LVCFMT_BITMAP_ON_RIGHT;
4710 if (lpColumn->mask & LVCF_WIDTH)
4712 lpColumn->cx = hdi.cxy;
4715 if (lpColumn->mask & LVCF_IMAGE)
4717 lpColumn->iImage = hdi.iImage;
4720 if (lpColumn->mask & LVCF_ORDER)
4722 lpColumn->iOrder = hdi.iOrder;
4730 /* LISTVIEW_GetColumnW */
4733 static LRESULT LISTVIEW_GetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
4735 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
4742 for (i = 0; i < iCount; i++)
4750 * Retrieves the column width.
4753 * [I] HWND : window handle
4754 * [I] int : column index
4757 * SUCCESS : column width
4760 static LRESULT LISTVIEW_GetColumnWidth(HWND hwnd, INT nColumn)
4762 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4763 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4764 INT nColumnWidth = 0;
4767 if (uView == LVS_LIST)
4769 nColumnWidth = infoPtr->nItemWidth;
4771 else if (uView == LVS_REPORT)
4773 /* get column width from header */
4774 ZeroMemory(&hdi, sizeof(HDITEMA));
4775 hdi.mask = HDI_WIDTH;
4776 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdi) != FALSE)
4778 nColumnWidth = hdi.cxy;
4782 return nColumnWidth;
4787 * In list or report display mode, retrieves the number of items that can fit
4788 * vertically in the visible area. In icon or small icon display mode,
4789 * retrieves the total number of visible items.
4792 * [I] HWND : window handle
4795 * Number of fully visible items.
4797 static LRESULT LISTVIEW_GetCountPerPage(HWND hwnd)
4799 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4800 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4803 if (uView == LVS_LIST)
4805 if (infoPtr->rcList.right > infoPtr->nItemWidth)
4807 nItemCount = LISTVIEW_GetCountPerRow(hwnd) *
4808 LISTVIEW_GetCountPerColumn(hwnd);
4811 else if (uView == LVS_REPORT)
4813 nItemCount = LISTVIEW_GetCountPerColumn(hwnd);
4817 nItemCount = GETITEMCOUNT(infoPtr);
4823 /* LISTVIEW_GetEditControl */
4827 * Retrieves the extended listview style.
4830 * [I] HWND : window handle
4833 * SUCCESS : previous style
4836 static LRESULT LISTVIEW_GetExtendedListViewStyle(HWND hwnd)
4838 LISTVIEW_INFO *infoPtr;
4840 /* make sure we can get the listview info */
4841 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
4844 return (infoPtr->dwExStyle);
4849 * Retrieves the handle to the header control.
4852 * [I] HWND : window handle
4857 static LRESULT LISTVIEW_GetHeader(HWND hwnd)
4859 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4861 return infoPtr->hwndHeader;
4864 /* LISTVIEW_GetHotCursor */
4868 * Returns the time that the mouse cursor must hover over an item
4869 * before it is selected.
4872 * [I] HWND : window handle
4875 * Returns the previously set hover time or (DWORD)-1 to indicate that the
4876 * hover time is set to the default hover time.
4878 static LRESULT LISTVIEW_GetHoverTime(HWND hwnd)
4880 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4882 return infoPtr->dwHoverTime;
4887 * Retrieves an image list handle.
4890 * [I] HWND : window handle
4891 * [I] INT : image list identifier
4894 * SUCCESS : image list handle
4897 static LRESULT LISTVIEW_GetImageList(HWND hwnd, INT nImageList)
4899 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4900 HIMAGELIST himl = NULL;
4905 himl = infoPtr->himlNormal;
4908 himl = infoPtr->himlSmall;
4911 himl = infoPtr->himlState;
4915 return (LRESULT)himl;
4918 /* LISTVIEW_GetISearchString */
4922 * Retrieves item attributes.
4925 * [I] HWND : window handle
4926 * [IO] LPLVITEMA : item info
4927 * [I] internal : if true then we will use tricks that avoid copies
4928 * but are not compatible with the regular interface
4934 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem, BOOL internal)
4936 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4937 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
4938 NMLVDISPINFOA dispInfo;
4939 LISTVIEW_SUBITEM *lpSubItem;
4940 LISTVIEW_ITEM *lpItem;
4944 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4945 /* In the following:
4946 * lpLVItem describes the information requested by the user
4947 * lpItem/lpSubItem is what we have
4948 * dispInfo is a structure we use to request the missing
4949 * information from the application
4952 TRACE("(hwnd=%x, lpLVItem=%p)\n", hwnd, lpLVItem);
4954 if ((lpLVItem == NULL) ||
4955 (lpLVItem->iItem < 0) ||
4956 (lpLVItem->iItem >= GETITEMCOUNT(infoPtr))
4960 if (lStyle & LVS_OWNERDATA)
4962 if (lpLVItem->mask & ~LVIF_STATE)
4964 dispInfo.hdr.hwndFrom = hwnd;
4965 dispInfo.hdr.idFrom = lCtrlId;
4966 dispInfo.hdr.code = LVN_GETDISPINFOA;
4967 memcpy(&dispInfo.item,lpLVItem,sizeof(LVITEMA));
4969 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
4970 memcpy(lpLVItem,&dispInfo.item,sizeof(LVITEMA));
4973 if ((lpLVItem->mask & LVIF_STATE)&&(lpLVItem->iSubItem == 0))
4975 lpLVItem->state = 0;
4976 if (infoPtr->nFocusedItem == lpLVItem->iItem)
4977 lpLVItem->state |= LVIS_FOCUSED;
4978 if (LISTVIEW_IsSelected(hwnd,lpLVItem->iItem))
4979 lpLVItem->state |= LVIS_SELECTED;
4986 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
4987 if (hdpaSubItems == NULL)
4990 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
4994 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
4995 if (lpLVItem->iSubItem == 0)
4997 piImage=&lpItem->iImage;
4998 ppszText=&lpItem->pszText;
4999 if ((infoPtr->uCallbackMask != 0) && (lpLVItem->mask & LVIF_STATE))
5001 dispInfo.item.mask |= LVIF_STATE;
5002 dispInfo.item.stateMask = infoPtr->uCallbackMask;
5007 lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem);
5008 if (lpSubItem != NULL)
5010 piImage=&lpSubItem->iImage;
5011 ppszText=&lpSubItem->pszText;
5020 if ((lpLVItem->mask & LVIF_IMAGE) &&
5021 ((piImage==NULL) || (*piImage == I_IMAGECALLBACK)))
5023 dispInfo.item.mask |= LVIF_IMAGE;
5026 if ((lpLVItem->mask & LVIF_TEXT) &&
5027 ((ppszText==NULL) || (*ppszText == LPSTR_TEXTCALLBACKA)))
5029 dispInfo.item.mask |= LVIF_TEXT;
5030 dispInfo.item.pszText = lpLVItem->pszText;
5031 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
5034 if (dispInfo.item.mask != 0)
5036 /* We don't have all the requested info, query the application */
5037 dispInfo.hdr.hwndFrom = hwnd;
5038 dispInfo.hdr.idFrom = lCtrlId;
5039 dispInfo.hdr.code = LVN_GETDISPINFOA;
5040 dispInfo.item.iItem = lpLVItem->iItem;
5041 dispInfo.item.iSubItem = lpLVItem->iSubItem;
5042 dispInfo.item.lParam = lpItem->lParam;
5043 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
5046 if (dispInfo.item.mask & LVIF_IMAGE)
5048 lpLVItem->iImage = dispInfo.item.iImage;
5050 else if (lpLVItem->mask & LVIF_IMAGE)
5052 lpLVItem->iImage = *piImage;
5055 if (dispInfo.item.mask & LVIF_PARAM)
5057 lpLVItem->lParam = dispInfo.item.lParam;
5059 else if (lpLVItem->mask & LVIF_PARAM)
5061 lpLVItem->lParam = lpItem->lParam;
5064 if (dispInfo.item.mask & LVIF_TEXT)
5066 if ((dispInfo.item.mask & LVIF_DI_SETITEM) && (ppszText != NULL))
5068 Str_SetPtrA(ppszText, dispInfo.item.pszText);
5070 /* If lpLVItem->pszText==dispInfo.item.pszText a copy is unnecessary, but */
5071 /* some apps give a new pointer in ListView_Notify so we can't be sure. */
5072 if (lpLVItem->pszText!=dispInfo.item.pszText) {
5073 lstrcpynA(lpLVItem->pszText, dispInfo.item.pszText, lpLVItem->cchTextMax);
5076 else if (lpLVItem->mask & LVIF_TEXT)
5080 lpLVItem->pszText=*ppszText;
5082 lstrcpynA(lpLVItem->pszText, *ppszText, lpLVItem->cchTextMax);
5086 if (lpLVItem->iSubItem == 0)
5088 if (dispInfo.item.mask & LVIF_STATE)
5090 lpLVItem->state = lpItem->state;
5091 lpLVItem->state &= ~dispInfo.item.stateMask;
5092 lpLVItem->state |= (dispInfo.item.state & dispInfo.item.stateMask);
5094 lpLVItem->state &= ~LVIS_SELECTED;
5095 if ((dispInfo.item.stateMask & LVIS_SELECTED) &&
5096 (LISTVIEW_IsSelected(hwnd,dispInfo.item.iItem)))
5097 lpLVItem->state |= LVIS_SELECTED;
5099 else if (lpLVItem->mask & LVIF_STATE)
5101 lpLVItem->state = lpItem->state & lpLVItem->stateMask;
5103 lpLVItem->state &= ~LVIS_SELECTED;
5104 if ((lpLVItem->stateMask & LVIS_SELECTED) &&
5105 (LISTVIEW_IsSelected(hwnd,lpLVItem->iItem)))
5106 lpLVItem->state |= LVIS_SELECTED;
5109 if (lpLVItem->mask & LVIF_PARAM)
5111 lpLVItem->lParam = lpItem->lParam;
5114 if (lpLVItem->mask & LVIF_INDENT)
5116 lpLVItem->iIndent = lpItem->iIndent;
5123 /* LISTVIEW_GetItemW */
5124 /* LISTVIEW_GetHotCursor */
5128 * Retrieves the index of the hot item.
5131 * [I] HWND : window handle
5134 * SUCCESS : hot item index
5135 * FAILURE : -1 (no hot item)
5137 static LRESULT LISTVIEW_GetHotItem(HWND hwnd)
5139 LISTVIEW_INFO *infoPtr;
5141 /* make sure we can get the listview info */
5142 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5145 return (infoPtr->nHotItem);
5148 /* LISTVIEW_GetHoverTime */
5152 * Retrieves the number of items in the listview control.
5155 * [I] HWND : window handle
5160 static LRESULT LISTVIEW_GetItemCount(HWND hwnd)
5162 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5164 return GETITEMCOUNT(infoPtr);
5169 * Retrieves the position (upper-left) of the listview control item.
5172 * [I] HWND : window handle
5173 * [I] INT : item index
5174 * [O] LPPOINT : coordinate information
5180 static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem,
5181 LPPOINT lpptPosition)
5183 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5184 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5185 BOOL bResult = FALSE;
5187 LISTVIEW_ITEM *lpItem;
5188 INT nCountPerColumn;
5191 TRACE("(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd, nItem,
5194 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
5195 (lpptPosition != NULL))
5197 if (uView == LVS_LIST)
5200 nItem = nItem - ListView_GetTopIndex(hwnd);
5201 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
5204 nRow = nItem % nCountPerColumn;
5207 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
5208 lpptPosition->y = 0;
5212 lpptPosition->x = (nItem / nCountPerColumn -1) * infoPtr->nItemWidth;
5213 lpptPosition->y = (nRow + nCountPerColumn) * infoPtr->nItemHeight;
5218 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
5219 lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight;
5222 else if (uView == LVS_REPORT)
5225 lpptPosition->x = REPORT_MARGINX;
5226 lpptPosition->y = ((nItem - ListView_GetTopIndex(hwnd)) *
5227 infoPtr->nItemHeight) + infoPtr->rcList.top;
5231 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
5232 if (hdpaSubItems != NULL)
5234 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
5238 lpptPosition->x = lpItem->ptPosition.x;
5239 lpptPosition->y = lpItem->ptPosition.y;
5249 * Retrieves the bounding rectangle for a listview control item.
5252 * [I] HWND : window handle
5253 * [I] INT : item index
5254 * [IO] LPRECT : bounding rectangle coordinates
5260 static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc)
5262 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5263 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5264 BOOL bResult = FALSE;
5275 TRACE("(hwnd=%x, nItem=%d, lprc=%p)\n", hwnd, nItem, lprc);
5277 if (uView & LVS_REPORT)
5279 ZeroMemory(&lvItem, sizeof(LVITEMA));
5280 lvItem.mask = LVIF_INDENT;
5281 lvItem.iItem = nItem;
5282 lvItem.iSubItem = 0;
5283 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
5286 if (lvItem.iIndent>0 && infoPtr->iconSize.cx > 0)
5288 nIndent = infoPtr->iconSize.cx * lvItem.iIndent;
5296 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL))
5298 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) != FALSE)
5303 if (uView == LVS_ICON)
5305 if (infoPtr->himlNormal != NULL)
5307 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5310 lprc->left = ptItem.x + ptOrigin.x;
5311 lprc->top = ptItem.y + ptOrigin.y;
5312 lprc->right = lprc->left + infoPtr->iconSize.cx;
5313 lprc->bottom = (lprc->top + infoPtr->iconSize.cy +
5314 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
5318 else if (uView == LVS_SMALLICON)
5320 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5323 lprc->left = ptItem.x + ptOrigin.x;
5324 lprc->top = ptItem.y + ptOrigin.y;
5325 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5327 if (infoPtr->himlState != NULL)
5328 lprc->left += infoPtr->iconSize.cx;
5330 if (infoPtr->himlSmall != NULL)
5331 lprc->right = lprc->left + infoPtr->iconSize.cx;
5333 lprc->right = lprc->left;
5339 lprc->left = ptItem.x;
5340 if (uView & LVS_REPORT)
5341 lprc->left += nIndent;
5342 lprc->top = ptItem.y;
5343 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5345 if (infoPtr->himlState != NULL)
5347 lprc->left += infoPtr->iconSize.cx;
5350 if (infoPtr->himlSmall != NULL)
5352 lprc->right = lprc->left + infoPtr->iconSize.cx;
5356 lprc->right = lprc->left;
5362 if (uView == LVS_ICON)
5364 if (infoPtr->himlNormal != NULL)
5366 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5369 lprc->left = ptItem.x + ptOrigin.x;
5370 lprc->top = (ptItem.y + ptOrigin.y + infoPtr->iconSize.cy +
5371 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
5372 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5373 if (infoPtr->iconSpacing.cx - nLabelWidth > 1)
5375 lprc->left += (infoPtr->iconSpacing.cx - nLabelWidth) / 2;
5376 lprc->right = lprc->left + nLabelWidth;
5381 lprc->right = lprc->left + infoPtr->iconSpacing.cx - 1;
5385 hOldFont = SelectObject(hdc, infoPtr->hFont);
5386 GetTextMetricsA(hdc, &tm);
5387 lprc->bottom = lprc->top + tm.tmHeight + HEIGHT_PADDING;
5388 SelectObject(hdc, hOldFont);
5389 ReleaseDC(hwnd, hdc);
5393 else if (uView == LVS_SMALLICON)
5395 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5398 nLeftPos = lprc->left = ptItem.x + ptOrigin.x;
5399 lprc->top = ptItem.y + ptOrigin.y;
5400 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5402 if (infoPtr->himlState != NULL)
5404 lprc->left += infoPtr->iconSize.cx;
5407 if (infoPtr->himlSmall != NULL)
5409 lprc->left += infoPtr->iconSize.cx;
5412 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5413 nLabelWidth += TRAILING_PADDING;
5414 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5416 lprc->right = lprc->left + nLabelWidth;
5420 lprc->right = nLeftPos + infoPtr->nItemWidth;
5427 if (uView & LVS_REPORT)
5428 nLeftPos = lprc->left = ptItem.x + nIndent;
5430 nLeftPos = lprc->left = ptItem.x;
5431 lprc->top = ptItem.y;
5432 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5434 if (infoPtr->himlState != NULL)
5436 lprc->left += infoPtr->iconSize.cx;
5439 if (infoPtr->himlSmall != NULL)
5441 lprc->left += infoPtr->iconSize.cx;
5444 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5445 nLabelWidth += TRAILING_PADDING;
5446 if (infoPtr->himlSmall)
5447 nLabelWidth += IMAGE_PADDING;
5448 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5450 lprc->right = lprc->left + nLabelWidth;
5454 lprc->right = nLeftPos + infoPtr->nItemWidth;
5460 if (uView == LVS_ICON)
5462 if (infoPtr->himlNormal != NULL)
5464 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5467 lprc->left = ptItem.x + ptOrigin.x;
5468 lprc->top = ptItem.y + ptOrigin.y;
5469 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
5470 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
5474 else if (uView == LVS_SMALLICON)
5476 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5479 lprc->left = ptItem.x + ptOrigin.x;
5480 lprc->right = lprc->left;
5481 lprc->top = ptItem.y + ptOrigin.y;
5482 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5483 if (infoPtr->himlState != NULL)
5484 lprc->right += infoPtr->iconSize.cx;
5485 if (infoPtr->himlSmall != NULL)
5486 lprc->right += infoPtr->iconSize.cx;
5488 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5489 nLabelWidth += TRAILING_PADDING;
5490 if (infoPtr->himlSmall)
5491 nLabelWidth += IMAGE_PADDING;
5492 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
5494 lprc->right += nLabelWidth;
5498 lprc->right = lprc->left + infoPtr->nItemWidth;
5505 lprc->left = ptItem.x;
5506 if (!(infoPtr->dwExStyle&LVS_EX_FULLROWSELECT) && uView&LVS_REPORT)
5507 lprc->left += nIndent;
5508 lprc->right = lprc->left;
5509 lprc->top = ptItem.y;
5510 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5512 if (infoPtr->dwExStyle & LVS_EX_FULLROWSELECT)
5515 int nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
5516 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
5518 lprc->right = max(lprc->left, br.right - REPORT_MARGINX);
5522 if (infoPtr->himlState != NULL)
5524 lprc->right += infoPtr->iconSize.cx;
5527 if (infoPtr->himlSmall != NULL)
5529 lprc->right += infoPtr->iconSize.cx;
5532 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5533 nLabelWidth += TRAILING_PADDING;
5534 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
5536 lprc->right += nLabelWidth;
5540 lprc->right = lprc->left + infoPtr->nItemWidth;
5546 case LVIR_SELECTBOUNDS:
5547 if (uView == LVS_ICON)
5549 if (infoPtr->himlNormal != NULL)
5551 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5554 lprc->left = ptItem.x + ptOrigin.x;
5555 lprc->top = ptItem.y + ptOrigin.y;
5556 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
5557 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
5561 else if (uView == LVS_SMALLICON)
5563 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5566 nLeftPos= lprc->left = ptItem.x + ptOrigin.x;
5567 lprc->top = ptItem.y + ptOrigin.y;
5568 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5570 if (infoPtr->himlState != NULL)
5572 lprc->left += infoPtr->iconSize.cx;
5575 lprc->right = lprc->left;
5577 if (infoPtr->himlSmall != NULL)
5579 lprc->right += infoPtr->iconSize.cx;
5582 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5583 nLabelWidth += TRAILING_PADDING;
5584 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5586 lprc->right += nLabelWidth;
5590 lprc->right = nLeftPos + infoPtr->nItemWidth;
5597 if (!(infoPtr->dwExStyle&LVS_EX_FULLROWSELECT) && (uView&LVS_REPORT))
5598 nLeftPos = lprc->left = ptItem.x + nIndent;
5600 nLeftPos = lprc->left = ptItem.x;
5601 lprc->top = ptItem.y;
5602 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5604 if (infoPtr->himlState != NULL)
5606 lprc->left += infoPtr->iconSize.cx;
5609 lprc->right = lprc->left;
5611 if (infoPtr->dwExStyle & LVS_EX_FULLROWSELECT)
5614 int nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
5615 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
5617 lprc->right = max(lprc->left, br.right - REPORT_MARGINX);
5621 if (infoPtr->himlSmall != NULL)
5623 lprc->right += infoPtr->iconSize.cx;
5626 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5627 nLabelWidth += TRAILING_PADDING;
5628 if (infoPtr->himlSmall)
5629 nLabelWidth += IMAGE_PADDING;
5630 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5632 lprc->right += nLabelWidth;
5636 lprc->right = nLeftPos + infoPtr->nItemWidth;
5649 * Retrieves the width of a label.
5652 * [I] HWND : window handle
5655 * SUCCESS : string width (in pixels)
5658 static INT LISTVIEW_GetLabelWidth(HWND hwnd, INT nItem)
5660 CHAR szDispText[DISP_TEXT_SIZE];
5661 INT nLabelWidth = 0;
5664 TRACE("(hwnd=%x, nItem=%d)\n", hwnd, nItem);
5666 ZeroMemory(&lvItem, sizeof(LVITEMA));
5667 lvItem.mask = LVIF_TEXT;
5668 lvItem.iItem = nItem;
5669 lvItem.cchTextMax = DISP_TEXT_SIZE;
5670 lvItem.pszText = szDispText;
5671 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
5673 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
5681 * Retrieves the spacing between listview control items.
5684 * [I] HWND : window handle
5685 * [I] BOOL : flag for small or large icon
5688 * Horizontal + vertical spacing
5690 static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall)
5692 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5695 if (bSmall == FALSE)
5697 lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
5701 /* TODO: need to store width of smallicon item */
5702 lResult = MAKELONG(0, infoPtr->nItemHeight);
5710 * Retrieves the state of a listview control item.
5713 * [I] HWND : window handle
5714 * [I] INT : item index
5715 * [I] UINT : state mask
5718 * State specified by the mask.
5720 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask)
5722 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5726 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5728 ZeroMemory(&lvItem, sizeof(LVITEMA));
5729 lvItem.iItem = nItem;
5730 lvItem.stateMask = uMask;
5731 lvItem.mask = LVIF_STATE;
5732 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
5734 uState = lvItem.state;
5743 * Retrieves the text of a listview control item or subitem.
5746 * [I] HWND : window handle
5747 * [I] INT : item index
5748 * [IO] LPLVITEMA : item information
5751 * SUCCESS : string length
5754 static LRESULT LISTVIEW_GetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5756 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5759 if (lpLVItem != NULL)
5761 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5763 lpLVItem->mask = LVIF_TEXT;
5764 lpLVItem->iItem = nItem;
5765 if (LISTVIEW_GetItemA(hwnd, lpLVItem, FALSE) != FALSE)
5767 nLength = lstrlenA(lpLVItem->pszText);
5777 * Searches for an item based on properties + relationships.
5780 * [I] HWND : window handle
5781 * [I] INT : item index
5782 * [I] INT : relationship flag
5785 * SUCCESS : item index
5788 static LRESULT LISTVIEW_GetNextItem(HWND hwnd, INT nItem, UINT uFlags)
5790 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5791 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5793 LVFINDINFO lvFindInfo;
5794 INT nCountPerColumn;
5797 if ((nItem >= -1) && (nItem < GETITEMCOUNT(infoPtr)))
5799 ZeroMemory(&lvFindInfo, sizeof(LVFINDINFO));
5801 if (uFlags & LVNI_CUT)
5804 if (uFlags & LVNI_DROPHILITED)
5805 uMask |= LVIS_DROPHILITED;
5807 if (uFlags & LVNI_FOCUSED)
5808 uMask |= LVIS_FOCUSED;
5810 if (uFlags & LVNI_SELECTED)
5811 uMask |= LVIS_SELECTED;
5813 if (uFlags & LVNI_ABOVE)
5815 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
5820 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5826 lvFindInfo.flags = LVFI_NEARESTXY;
5827 lvFindInfo.vkDirection = VK_UP;
5828 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5829 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5831 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5836 else if (uFlags & LVNI_BELOW)
5838 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
5840 while (nItem < GETITEMCOUNT(infoPtr))
5843 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5849 lvFindInfo.flags = LVFI_NEARESTXY;
5850 lvFindInfo.vkDirection = VK_DOWN;
5851 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5852 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5854 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5859 else if (uFlags & LVNI_TOLEFT)
5861 if (uView == LVS_LIST)
5863 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
5864 while (nItem - nCountPerColumn >= 0)
5866 nItem -= nCountPerColumn;
5867 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5871 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
5873 lvFindInfo.flags = LVFI_NEARESTXY;
5874 lvFindInfo.vkDirection = VK_LEFT;
5875 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5876 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5878 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5883 else if (uFlags & LVNI_TORIGHT)
5885 if (uView == LVS_LIST)
5887 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
5888 while (nItem + nCountPerColumn < GETITEMCOUNT(infoPtr))
5890 nItem += nCountPerColumn;
5891 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5895 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
5897 lvFindInfo.flags = LVFI_NEARESTXY;
5898 lvFindInfo.vkDirection = VK_RIGHT;
5899 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5900 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5902 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5911 /* search by index */
5912 for (i = nItem; i < GETITEMCOUNT(infoPtr); i++)
5914 if ((ListView_GetItemState(hwnd, i, uMask) & uMask) == uMask)
5923 /* LISTVIEW_GetNumberOfWorkAreas */
5927 * Retrieves the origin coordinates when in icon or small icon display mode.
5930 * [I] HWND : window handle
5931 * [O] LPPOINT : coordinate information
5937 static LRESULT LISTVIEW_GetOrigin(HWND hwnd, LPPOINT lpptOrigin)
5939 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5940 UINT uView = lStyle & LVS_TYPEMASK;
5941 BOOL bResult = FALSE;
5943 TRACE("(hwnd=%x, lpptOrigin=%p)\n", hwnd, lpptOrigin);
5945 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
5947 SCROLLINFO scrollInfo;
5948 ZeroMemory(lpptOrigin, sizeof(POINT));
5949 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
5950 scrollInfo.cbSize = sizeof(SCROLLINFO);
5952 if (lStyle & WS_HSCROLL)
5954 scrollInfo.fMask = SIF_POS;
5955 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
5957 lpptOrigin->x = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
5961 if (lStyle & WS_VSCROLL)
5963 scrollInfo.fMask = SIF_POS;
5964 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
5966 lpptOrigin->y = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
5978 * Retrieves the number of items that are marked as selected.
5981 * [I] HWND : window handle
5984 * Number of items selected.
5986 static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd)
5989 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5990 INT nSelectedCount = 0;
5993 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
5995 if (ListView_GetItemState(hwnd, i, LVIS_SELECTED) & LVIS_SELECTED)
6001 return nSelectedCount;
6006 * Retrieves item index that marks the start of a multiple selection.
6009 * [I] HWND : window handle
6012 * Index number or -1 if there is no selection mark.
6014 static LRESULT LISTVIEW_GetSelectionMark(HWND hwnd)
6016 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6018 return infoPtr->nSelectionMark;
6023 * Retrieves the width of a string.
6026 * [I] HWND : window handle
6029 * SUCCESS : string width (in pixels)
6032 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText)
6034 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6035 HFONT hFont, hOldFont;
6039 ZeroMemory(&stringSize, sizeof(SIZE));
6040 if (lpszText != NULL && lpszText != (LPCSTR)-1)
6042 hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
6044 hOldFont = SelectObject(hdc, hFont);
6045 GetTextExtentPointA(hdc, lpszText, lstrlenA(lpszText), &stringSize);
6046 SelectObject(hdc, hOldFont);
6047 ReleaseDC(hwnd, hdc);
6050 return stringSize.cx;
6055 * Retrieves the text backgound color.
6058 * [I] HWND : window handle
6061 * COLORREF associated with the the background.
6063 static LRESULT LISTVIEW_GetTextBkColor(HWND hwnd)
6065 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
6067 return infoPtr->clrTextBk;
6072 * Retrieves the text color.
6075 * [I] HWND : window handle
6078 * COLORREF associated with the text.
6080 static LRESULT LISTVIEW_GetTextColor(HWND hwnd)
6082 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
6084 return infoPtr->clrText;
6089 * Determines which section of the item was selected (if any).
6092 * [I] HWND : window handle
6093 * [IO] LPLVHITTESTINFO : hit test information
6096 * SUCCESS : item index
6099 static INT LISTVIEW_HitTestItem(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
6101 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6103 INT i,topindex,bottomindex;
6104 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6105 UINT uView = lStyle & LVS_TYPEMASK;
6108 TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpHitTestInfo->pt.x,
6109 lpHitTestInfo->pt.y);
6111 topindex = ListView_GetTopIndex(hwnd);
6112 if (uView == LVS_REPORT)
6114 bottomindex = topindex + LISTVIEW_GetCountPerColumn(hwnd) + 1;
6115 bottomindex = min(bottomindex,GETITEMCOUNT(infoPtr));
6119 bottomindex = GETITEMCOUNT(infoPtr);
6122 for (i = topindex; i < bottomindex; i++)
6124 rcItem.left = LVIR_BOUNDS;
6125 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
6127 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
6129 rcItem.left = LVIR_ICON;
6130 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
6132 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
6134 lpHitTestInfo->flags = LVHT_ONITEMICON;
6135 lpHitTestInfo->iItem = i;
6136 lpHitTestInfo->iSubItem = 0;
6141 rcItem.left = LVIR_LABEL;
6142 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
6144 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
6146 lpHitTestInfo->flags = LVHT_ONITEMLABEL;
6147 lpHitTestInfo->iItem = i;
6148 lpHitTestInfo->iSubItem = 0;
6153 lpHitTestInfo->flags = LVHT_ONITEMSTATEICON;
6154 lpHitTestInfo->iItem = i;
6155 lpHitTestInfo->iSubItem = 0;
6161 lpHitTestInfo->flags = LVHT_NOWHERE;
6168 * Determines which listview item is located at the specified position.
6171 * [I] HWND : window handle
6172 * [IO} LPLVHITTESTINFO : hit test information
6175 * SUCCESS : item index
6178 static LRESULT LISTVIEW_HitTest(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
6180 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6183 lpHitTestInfo->flags = 0;
6185 if (infoPtr->rcList.left > lpHitTestInfo->pt.x)
6187 lpHitTestInfo->flags = LVHT_TOLEFT;
6189 else if (infoPtr->rcList.right < lpHitTestInfo->pt.x)
6191 lpHitTestInfo->flags = LVHT_TORIGHT;
6193 if (infoPtr->rcList.top > lpHitTestInfo->pt.y)
6195 lpHitTestInfo->flags |= LVHT_ABOVE;
6197 else if (infoPtr->rcList.bottom < lpHitTestInfo->pt.y)
6199 lpHitTestInfo->flags |= LVHT_BELOW;
6202 if (lpHitTestInfo->flags == 0)
6204 nItem = LISTVIEW_HitTestItem(hwnd, lpHitTestInfo);
6212 * Inserts a new column.
6215 * [I] HWND : window handle
6216 * [I] INT : column index
6217 * [I] LPLVCOLUMNA : column information
6220 * SUCCESS : new column index
6223 static LRESULT LISTVIEW_InsertColumnA(HWND hwnd, INT nColumn,
6224 LPLVCOLUMNA lpColumn)
6226 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6228 INT nNewColumn = -1;
6230 TRACE("(hwnd=%x, nColumn=%d, lpColumn=%p)\n",hwnd, nColumn,
6233 if (lpColumn != NULL)
6235 /* initialize memory */
6236 ZeroMemory(&hdi, sizeof(HDITEMA));
6238 if (lpColumn->mask & LVCF_FMT)
6240 /* format member is valid */
6241 hdi.mask |= HDI_FORMAT;
6243 /* set text alignment (leftmost column must be left-aligned) */
6246 hdi.fmt |= HDF_LEFT;
6250 if (lpColumn->fmt & LVCFMT_LEFT)
6252 hdi.fmt |= HDF_LEFT;
6254 else if (lpColumn->fmt & LVCFMT_RIGHT)
6256 hdi.fmt |= HDF_RIGHT;
6258 else if (lpColumn->fmt & LVCFMT_CENTER)
6260 hdi.fmt |= HDF_CENTER;
6264 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
6266 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
6270 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
6275 if (lpColumn->fmt & LVCFMT_IMAGE)
6277 hdi.fmt |= HDF_IMAGE;
6278 hdi.iImage = I_IMAGECALLBACK;
6282 if (lpColumn->mask & LVCF_WIDTH)
6284 hdi.mask |= HDI_WIDTH;
6285 hdi.cxy = lpColumn->cx;
6288 if (lpColumn->mask & LVCF_TEXT)
6290 hdi.mask |= HDI_TEXT | HDI_FORMAT;
6291 hdi.pszText = lpColumn->pszText;
6292 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
6293 hdi.fmt |= HDF_STRING;
6296 if (lpColumn->mask & LVCF_IMAGE)
6298 hdi.mask |= HDI_IMAGE;
6299 hdi.iImage = lpColumn->iImage;
6302 if (lpColumn->mask & LVCF_ORDER)
6304 hdi.mask |= HDI_ORDER;
6305 hdi.iOrder = lpColumn->iOrder;
6308 /* insert item in header control */
6309 nNewColumn = SendMessageA(infoPtr->hwndHeader, HDM_INSERTITEMA,
6310 (WPARAM)nColumn, (LPARAM)&hdi);
6312 /* Need to reset the item width when inserting a new column */
6313 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6315 LISTVIEW_UpdateScroll(hwnd);
6316 InvalidateRect(hwnd, NULL, FALSE);
6322 static LRESULT LISTVIEW_InsertColumnW(HWND hwnd, INT nColumn,
6323 LPLVCOLUMNW lpColumn)
6328 memcpy(&lvca,lpColumn,sizeof(lvca));
6329 if (lpColumn->mask & LVCF_TEXT)
6330 lvca.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpColumn->pszText);
6331 lres = LISTVIEW_InsertColumnA(hwnd,nColumn,&lvca);
6332 if (lpColumn->mask & LVCF_TEXT)
6333 HeapFree(GetProcessHeap(),0,lvca.pszText);
6337 /* LISTVIEW_InsertCompare: callback routine for comparing pszText members of the LV_ITEMS
6338 in a LISTVIEW on insert. Passed to DPA_Sort in LISTVIEW_InsertItem.
6339 This function should only be used for inserting items into a sorted list (LVM_INSERTITEM)
6340 and not during the processing of a LVM_SORTITEMS message. Applications should provide
6341 their own sort proc. when sending LVM_SORTITEMS.
6344 (remarks on LVITEM: LVM_INSERTITEM will insert the new item in the proper sort postion...
6346 LVS_SORTXXX must be specified,
6347 LVS_OWNERDRAW is not set,
6348 <item>.pszText is not LPSTR_TEXTCALLBACK.
6350 (LVS_SORT* flags): "For the LVS_SORTASCENDING... styles, item indices
6351 are sorted based on item text..."
6353 static INT WINAPI LISTVIEW_InsertCompare( LPVOID first, LPVOID second, LPARAM lParam)
6355 HDPA hdpa_first = (HDPA) first;
6356 HDPA hdpa_second = (HDPA) second;
6357 LISTVIEW_ITEM* lv_first = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_first, 0 );
6358 LISTVIEW_ITEM* lv_second = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_second, 0 );
6359 LONG lStyle = GetWindowLongA((HWND) lParam, GWL_STYLE);
6360 INT cmpv = lstrcmpA( lv_first->pszText, lv_second->pszText );
6361 /* if we're sorting descending, negate the return value */
6362 return (lStyle & LVS_SORTDESCENDING) ? -cmpv : cmpv;
6367 * Inserts a new item in the listview control.
6370 * [I] HWND : window handle
6371 * [I] LPLVITEMA : item information
6374 * SUCCESS : new item index
6377 static LRESULT LISTVIEW_InsertItemA(HWND hwnd, LPLVITEMA lpLVItem)
6379 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6380 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6381 UINT uView = lStyle & LVS_TYPEMASK;
6382 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
6387 LISTVIEW_ITEM *lpItem = NULL;
6389 TRACE("(hwnd=%x,lpLVItem=%p)\n", hwnd, lpLVItem);
6391 if (lStyle & LVS_OWNERDATA)
6393 nItem = infoPtr->hdpaItems->nItemCount;
6394 infoPtr->hdpaItems->nItemCount ++;
6398 if (lpLVItem != NULL)
6400 /* make sure it's not a subitem; cannot insert a subitem */
6401 if (lpLVItem->iSubItem == 0)
6403 lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM));
6406 ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
6407 if (LISTVIEW_InitItem(hwnd, lpItem, lpLVItem) != FALSE)
6409 /* insert item in listview control data structure */
6410 hdpaSubItems = DPA_Create(8);
6411 if (hdpaSubItems != NULL)
6413 nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem);
6416 if ( ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
6417 && !(lStyle & LVS_OWNERDRAWFIXED)
6418 && (LPSTR_TEXTCALLBACKA != lpLVItem->pszText) )
6420 /* Insert the item in the proper sort order based on the pszText
6421 member. See comments for LISTVIEW_InsertCompare() for greater detail */
6422 nItem = DPA_InsertPtr( infoPtr->hdpaItems,
6423 GETITEMCOUNT( infoPtr ) + 1, hdpaSubItems );
6424 DPA_Sort( infoPtr->hdpaItems, LISTVIEW_InsertCompare, hwnd );
6425 nItem = DPA_GetPtrIndex( infoPtr->hdpaItems, hdpaSubItems );
6429 nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpLVItem->iItem,
6434 LISTVIEW_ShiftSelections(hwnd,nItem,1);
6436 /* manage item focus */
6437 if (lpLVItem->mask & LVIF_STATE)
6439 lpItem->state &= ~(LVIS_FOCUSED|LVIS_SELECTED);
6440 if (lpLVItem->stateMask & LVIS_SELECTED)
6442 LISTVIEW_SetSelection(hwnd, nItem);
6444 else if (lpLVItem->stateMask & LVIS_FOCUSED)
6446 LISTVIEW_SetItemFocus(hwnd, nItem);
6450 /* send LVN_INSERTITEM notification */
6451 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
6452 nmlv.hdr.hwndFrom = hwnd;
6453 nmlv.hdr.idFrom = lCtrlId;
6454 nmlv.hdr.code = LVN_INSERTITEM;
6456 nmlv.lParam = lpItem->lParam;;
6457 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
6459 if ((uView == LVS_SMALLICON) || (uView == LVS_LIST))
6461 nItemWidth = LISTVIEW_CalculateWidth(hwnd, lpLVItem->iItem);
6462 if (nItemWidth > infoPtr->nItemWidth)
6464 infoPtr->nItemWidth = nItemWidth;
6468 /* align items (set position of each item) */
6469 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
6471 if (lStyle & LVS_ALIGNLEFT)
6473 LISTVIEW_AlignLeft(hwnd);
6477 LISTVIEW_AlignTop(hwnd);
6481 LISTVIEW_UpdateScroll(hwnd);
6482 /* refresh client area */
6483 InvalidateRect(hwnd, NULL, FALSE);
6492 /* free memory if unsuccessful */
6493 if ((nItem == -1) && (lpItem != NULL))
6495 COMCTL32_Free(lpItem);
6501 static LRESULT LISTVIEW_InsertItemW(HWND hwnd, LPLVITEMW lpLVItem) {
6505 memcpy(&lvia,lpLVItem,sizeof(LVITEMA));
6506 if (lvia.mask & LVIF_TEXT) {
6507 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKW)
6508 lvia.pszText = LPSTR_TEXTCALLBACKA;
6510 lvia.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpLVItem->pszText);
6512 lres = LISTVIEW_InsertItemA(hwnd, &lvia);
6513 if (lvia.mask & LVIF_TEXT) {
6514 if (lpLVItem->pszText != LPSTR_TEXTCALLBACKW)
6515 HeapFree(GetProcessHeap(),0,lvia.pszText);
6520 /* LISTVIEW_InsertItemW */
6524 * Redraws a range of items.
6527 * [I] HWND : window handle
6528 * [I] INT : first item
6529 * [I] INT : last item
6535 static LRESULT LISTVIEW_RedrawItems(HWND hwnd, INT nFirst, INT nLast)
6537 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6538 BOOL bResult = FALSE;
6541 if (nFirst <= nLast)
6543 if ((nFirst >= 0) && (nFirst < GETITEMCOUNT(infoPtr)))
6545 if ((nLast >= 0) && (nLast < GETITEMCOUNT(infoPtr)))
6548 InvalidateRect(hwnd, &rc, FALSE);
6556 /* LISTVIEW_Scroll */
6560 * Sets the background color.
6563 * [I] HWND : window handle
6564 * [I] COLORREF : background color
6570 static LRESULT LISTVIEW_SetBkColor(HWND hwnd, COLORREF clrBk)
6572 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6574 infoPtr->clrBk = clrBk;
6575 InvalidateRect(hwnd, NULL, TRUE);
6580 /* LISTVIEW_SetBkImage */
6584 * Sets the callback mask. This mask will be used when the parent
6585 * window stores state information (some or all).
6588 * [I] HWND : window handle
6589 * [I] UINT : state mask
6595 static BOOL LISTVIEW_SetCallbackMask(HWND hwnd, UINT uMask)
6597 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6599 infoPtr->uCallbackMask = uMask;
6606 * Sets the attributes of a header item.
6609 * [I] HWND : window handle
6610 * [I] INT : column index
6611 * [I] LPLVCOLUMNA : column attributes
6617 static LRESULT LISTVIEW_SetColumnA(HWND hwnd, INT nColumn,
6618 LPLVCOLUMNA lpColumn)
6620 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6621 BOOL bResult = FALSE;
6622 HDITEMA hdi, hdiget;
6624 if ((lpColumn != NULL) && (nColumn >= 0) &&
6625 (nColumn < Header_GetItemCount(infoPtr->hwndHeader)))
6627 /* initialize memory */
6628 ZeroMemory(&hdi, sizeof(HDITEMA));
6630 if (lpColumn->mask & LVCF_FMT)
6632 /* format member is valid */
6633 hdi.mask |= HDI_FORMAT;
6635 /* get current format first */
6636 hdiget.mask = HDI_FORMAT;
6637 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdiget))
6638 /* preserve HDF_STRING if present */
6639 hdi.fmt = hdiget.fmt & HDF_STRING;
6641 /* set text alignment (leftmost column must be left-aligned) */
6644 hdi.fmt |= HDF_LEFT;
6648 if (lpColumn->fmt & LVCFMT_LEFT)
6650 hdi.fmt |= HDF_LEFT;
6652 else if (lpColumn->fmt & LVCFMT_RIGHT)
6654 hdi.fmt |= HDF_RIGHT;
6656 else if (lpColumn->fmt & LVCFMT_CENTER)
6658 hdi.fmt |= HDF_CENTER;
6662 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
6664 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
6667 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
6669 hdi.fmt |= HDF_IMAGE;
6672 if (lpColumn->fmt & LVCFMT_IMAGE)
6674 hdi.fmt |= HDF_IMAGE;
6675 hdi.iImage = I_IMAGECALLBACK;
6679 if (lpColumn->mask & LVCF_WIDTH)
6681 hdi.mask |= HDI_WIDTH;
6682 hdi.cxy = lpColumn->cx;
6685 if (lpColumn->mask & LVCF_TEXT)
6687 hdi.mask |= HDI_TEXT | HDI_FORMAT;
6688 hdi.pszText = lpColumn->pszText;
6689 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
6690 hdi.fmt |= HDF_STRING;
6693 if (lpColumn->mask & LVCF_IMAGE)
6695 hdi.mask |= HDI_IMAGE;
6696 hdi.iImage = lpColumn->iImage;
6699 if (lpColumn->mask & LVCF_ORDER)
6701 hdi.mask |= HDI_ORDER;
6702 hdi.iOrder = lpColumn->iOrder;
6705 /* set header item attributes */
6706 bResult = Header_SetItemA(infoPtr->hwndHeader, nColumn, &hdi);
6712 /* LISTVIEW_SetColumnW */
6716 * Sets the column order array
6719 * [I] HWND : window handle
6720 * [I] INT : number of elements in column order array
6721 * [I] INT : pointer to column order array
6727 static LRESULT LISTVIEW_SetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
6729 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
6731 FIXME("iCount %d lpiArray %p\n", iCount, lpiArray);
6742 * Sets the width of a column
6745 * [I] HWND : window handle
6746 * [I] INT : column index
6747 * [I] INT : column width
6753 static LRESULT LISTVIEW_SetColumnWidth(HWND hwnd, INT iCol, INT cx)
6755 LISTVIEW_INFO *infoPtr;
6758 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6759 UINT uView = lStyle & LVS_TYPEMASK;
6764 CHAR text_buffer[DISP_TEXT_SIZE];
6765 INT header_item_count;
6770 /* make sure we can get the listview info */
6771 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
6774 if (!infoPtr->hwndHeader) /* make sure we have a header */
6777 /* set column width only if in report or list mode */
6778 if ((uView != LVS_REPORT) && (uView != LVS_LIST))
6781 /* take care of invalid cx values */
6782 if((uView == LVS_REPORT) && (cx < -2))
6783 cx = LVSCW_AUTOSIZE;
6784 else if (uView == LVS_LIST && (cx < 1))
6787 /* resize all columns if in LVS_LIST mode */
6788 if(uView == LVS_LIST) {
6789 infoPtr->nItemWidth = cx;
6790 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
6794 /* autosize based on listview items width */
6795 if(cx == LVSCW_AUTOSIZE)
6797 /* set the width of the header to the width of the widest item */
6798 for(item_index = 0; item_index < GETITEMCOUNT(infoPtr); item_index++)
6800 if(cx < LISTVIEW_GetLabelWidth(hwnd, item_index))
6801 cx = LISTVIEW_GetLabelWidth(hwnd, item_index);
6803 } /* autosize based on listview header width */
6804 else if(cx == LVSCW_AUTOSIZE_USEHEADER)
6806 header_item_count = Header_GetItemCount(infoPtr->hwndHeader);
6808 /* if iCol is the last column make it fill the remainder of the controls width */
6809 if(iCol == (header_item_count - 1)) {
6810 /* get the width of every item except the current one */
6811 hdi.mask = HDI_WIDTH;
6814 for(item_index = 0; item_index < (header_item_count - 1); item_index++) {
6815 Header_GetItemA(infoPtr->hwndHeader, item_index, (LPARAM)(&hdi));
6819 /* retrieve the layout of the header */
6820 GetWindowRect(infoPtr->hwndHeader, &rcHeader);
6822 cx = (rcHeader.right - rcHeader.left) - cx;
6826 /* retrieve header font */
6827 header_font = SendMessageA(infoPtr->hwndHeader, WM_GETFONT, 0L, 0L);
6829 /* retrieve header text */
6830 hdi.mask = HDI_TEXT;
6831 hdi.cchTextMax = sizeof(text_buffer);
6832 hdi.pszText = text_buffer;
6834 Header_GetItemA(infoPtr->hwndHeader, iCol, (LPARAM)(&hdi));
6836 /* determine the width of the text in the header */
6838 old_font = SelectObject(hdc, header_font); /* select the font into hdc */
6840 GetTextExtentPoint32A(hdc, text_buffer, strlen(text_buffer), &size);
6842 SelectObject(hdc, old_font); /* restore the old font */
6843 ReleaseDC(hwnd, hdc);
6845 /* set the width of this column to the width of the text */
6850 /* call header to update the column change */
6851 hdi.mask = HDI_WIDTH;
6854 lret = Header_SetItemA(infoPtr->hwndHeader, (WPARAM)iCol, (LPARAM)&hdi);
6856 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
6863 * Sets the extended listview style.
6866 * [I] HWND : window handle
6871 * SUCCESS : previous style
6874 static LRESULT LISTVIEW_SetExtendedListViewStyle(HWND hwnd, DWORD dwMask, DWORD dwStyle)
6876 LISTVIEW_INFO *infoPtr;
6879 /* make sure we can get the listview info */
6880 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
6883 /* store previous style */
6884 dwOldStyle = infoPtr->dwExStyle;
6888 infoPtr->dwExStyle = (dwOldStyle & ~dwMask) | (dwStyle & dwMask);
6890 infoPtr->dwExStyle = dwStyle;
6892 return (dwOldStyle);
6895 /* LISTVIEW_SetHotCursor */
6899 * Sets the hot item index.
6902 * [I] HWND : window handle
6906 * SUCCESS : previous hot item index
6907 * FAILURE : -1 (no hot item)
6909 static LRESULT LISTVIEW_SetHotItem(HWND hwnd, INT iIndex)
6911 LISTVIEW_INFO *infoPtr;
6914 /* make sure we can get the listview info */
6915 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
6918 /* store previous index */
6919 iOldIndex = infoPtr->nHotItem;
6922 infoPtr->nHotItem = iIndex;
6929 * Sets the amount of time the cursor must hover over an item before it is selected.
6932 * [I] HWND : window handle
6933 * [I] DWORD : dwHoverTime, if -1 the hover time is set to the default
6936 * Returns the previous hover time
6938 static LRESULT LISTVIEW_SetHoverTime(HWND hwnd, DWORD dwHoverTime)
6940 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6941 DWORD oldHoverTime = infoPtr->dwHoverTime;
6943 infoPtr->dwHoverTime = dwHoverTime;
6945 return oldHoverTime;
6948 /* LISTVIEW_SetIconSpacing */
6955 * [I] HWND : window handle
6956 * [I] INT : image list type
6957 * [I] HIMAGELIST : image list handle
6960 * SUCCESS : old image list
6963 static LRESULT LISTVIEW_SetImageList(HWND hwnd, INT nType, HIMAGELIST himl)
6965 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6966 HIMAGELIST himlTemp = 0;
6971 himlTemp = infoPtr->himlNormal;
6972 infoPtr->himlNormal = himl;
6973 return (LRESULT)himlTemp;
6976 himlTemp = infoPtr->himlSmall;
6977 infoPtr->himlSmall = himl;
6978 return (LRESULT)himlTemp;
6981 himlTemp = infoPtr->himlState;
6982 infoPtr->himlState = himl;
6983 ImageList_SetBkColor(infoPtr->himlState, CLR_NONE);
6984 return (LRESULT)himlTemp;
6987 return (LRESULT)NULL;
6993 * Sets the attributes of an item.
6996 * [I] HWND : window handle
6997 * [I] LPLVITEM : item information
7003 static LRESULT LISTVIEW_SetItemA(HWND hwnd, LPLVITEMA lpLVItem)
7005 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7006 BOOL bResult = FALSE;
7008 if (lpLVItem != NULL)
7010 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
7012 if (lpLVItem->iSubItem == 0)
7014 bResult = LISTVIEW_SetItem(hwnd, lpLVItem);
7018 bResult = LISTVIEW_SetSubItem(hwnd, lpLVItem);
7027 /* LISTVIEW_SetItemW */
7031 * Preallocates memory.
7034 * [I] HWND : window handle
7035 * [I] INT : item count (projected number of items)
7036 * [I] DWORD : update flags
7042 static BOOL LISTVIEW_SetItemCount(HWND hwnd, INT nItems, DWORD dwFlags)
7044 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
7046 FIXME("(%d %08lx)stub!\n", nItems, dwFlags);
7049 return LISTVIEW_DeleteAllItems (hwnd);
7051 if (GetWindowLongA(hwnd, GWL_STYLE) & LVS_OWNERDATA)
7053 int precount,topvisible;
7054 TRACE("LVS_OWNERDATA is set!\n");
7056 precount = infoPtr->hdpaItems->nItemCount;
7057 topvisible = ListView_GetTopIndex(hwnd) +
7058 LISTVIEW_GetCountPerColumn(hwnd) + 1;
7060 infoPtr->hdpaItems->nItemCount = nItems;
7062 LISTVIEW_UpdateSize(hwnd);
7063 LISTVIEW_UpdateScroll(hwnd);
7064 if (min(precount,infoPtr->hdpaItems->nItemCount)<topvisible)
7065 InvalidateRect(hwnd, NULL, TRUE);
7069 if (nItems > GETITEMCOUNT(infoPtr))
7072 FIXME("append items\n");
7075 else if (nItems < GETITEMCOUNT(infoPtr))
7078 while(nItems < GETITEMCOUNT(infoPtr)) {
7079 LISTVIEW_DeleteItem(hwnd, GETITEMCOUNT(infoPtr) - 1);
7089 * Sets the position of an item.
7092 * [I] HWND : window handle
7093 * [I] INT : item index
7094 * [I] INT : x coordinate
7095 * [I] INT : y coordinate
7101 static BOOL LISTVIEW_SetItemPosition(HWND hwnd, INT nItem,
7102 INT nPosX, INT nPosY)
7104 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
7105 UINT lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7106 UINT uView = lStyle & LVS_TYPEMASK;
7107 LISTVIEW_ITEM *lpItem;
7109 BOOL bResult = FALSE;
7111 TRACE("(hwnd=%x,nItem=%d,X=%d,Y=%d)\n", hwnd, nItem, nPosX, nPosY);
7113 if (lStyle & LVS_OWNERDATA)
7116 if ((nItem >= 0) || (nItem < GETITEMCOUNT(infoPtr)))
7118 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
7120 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
7121 if (hdpaSubItems != NULL)
7123 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
7127 lpItem->ptPosition.x = nPosX;
7128 lpItem->ptPosition.y = nPosY;
7137 /* LISTVIEW_SetItemPosition32 */
7141 * Sets the state of one or many items.
7144 * [I] HWND : window handle
7145 * [I]INT : item index
7146 * [I] LPLVITEM : item or subitem info
7152 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
7154 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7155 BOOL bResult = FALSE;
7162 ZeroMemory(&lvItem, sizeof(LVITEMA));
7163 lvItem.mask = LVIF_STATE;
7164 lvItem.state = lpLVItem->state;
7165 lvItem.stateMask = lpLVItem->stateMask ;
7167 /* apply to all items */
7168 for (i = 0; i< GETITEMCOUNT(infoPtr); i++)
7171 if (ListView_SetItemA(hwnd, &lvItem) == FALSE)
7179 ZeroMemory(&lvItem, sizeof(LVITEMA));
7180 lvItem.mask = LVIF_STATE;
7181 lvItem.state = lpLVItem->state;
7182 lvItem.stateMask = lpLVItem->stateMask;
7183 lvItem.iItem = nItem;
7184 bResult = ListView_SetItemA(hwnd, &lvItem);
7192 * Sets the text of an item or subitem.
7195 * [I] HWND : window handle
7196 * [I] INT : item index
7197 * [I] LPLVITEMA : item or subitem info
7203 static BOOL LISTVIEW_SetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
7205 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7206 BOOL bResult = FALSE;
7209 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
7211 ZeroMemory(&lvItem, sizeof(LVITEMA));
7212 lvItem.mask = LVIF_TEXT;
7213 lvItem.pszText = lpLVItem->pszText;
7214 lvItem.iItem = nItem;
7215 lvItem.iSubItem = lpLVItem->iSubItem;
7216 bResult = ListView_SetItemA(hwnd, &lvItem);
7222 /* LISTVIEW_SetItemTextW */
7226 * Set item index that marks the start of a multiple selection.
7229 * [I] HWND : window handle
7233 * Index number or -1 if there is no selection mark.
7235 static LRESULT LISTVIEW_SetSelectionMark(HWND hwnd, INT nIndex)
7237 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7238 INT nOldIndex = infoPtr->nSelectionMark;
7240 infoPtr->nSelectionMark = nIndex;
7247 * Sets the text background color.
7250 * [I] HWND : window handle
7251 * [I] COLORREF : text background color
7257 static LRESULT LISTVIEW_SetTextBkColor(HWND hwnd, COLORREF clrTextBk)
7259 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7261 infoPtr->clrTextBk = clrTextBk;
7262 InvalidateRect(hwnd, NULL, TRUE);
7269 * Sets the text foreground color.
7272 * [I] HWND : window handle
7273 * [I] COLORREF : text color
7279 static LRESULT LISTVIEW_SetTextColor (HWND hwnd, COLORREF clrText)
7281 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7283 infoPtr->clrText = clrText;
7284 InvalidateRect(hwnd, NULL, TRUE);
7289 /* LISTVIEW_SetToolTips */
7290 /* LISTVIEW_SetUnicodeFormat */
7291 /* LISTVIEW_SetWorkAreas */
7295 * Callback internally used by LISTVIEW_SortItems()
7298 * [I] LPVOID : first LISTVIEW_ITEM to compare
7299 * [I] LPVOID : second LISTVIEW_ITEM to compare
7300 * [I] LPARAM : HWND of control
7303 * if first comes before second : negative
7304 * if first comes after second : positive
7305 * if first and second are equivalent : zero
7307 static INT WINAPI LISTVIEW_CallBackCompare(
7312 /* Forward the call to the client defined callback */
7314 HWND hwnd = (HWND)lParam;
7315 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7317 rv = (infoPtr->pfnCompare)( ((LISTVIEW_ITEM*) first)->lParam,
7318 ((LISTVIEW_ITEM*) second)->lParam, infoPtr->lParamSort );
7325 * Sorts the listview items.
7328 * [I] HWND : window handle
7329 * [I] WPARAM : application-defined value
7330 * [I] LPARAM : pointer to comparision callback
7336 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam)
7338 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7340 LISTVIEW_ITEM *lpItem;
7343 UINT lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7345 if (lStyle & LVS_OWNERDATA)
7348 if (!infoPtr || !infoPtr->hdpaItems)
7351 nCount = GETITEMCOUNT(infoPtr);
7352 /* if there are 0 or 1 items, there is no need to sort */
7355 sortList = DPA_Create(nCount);
7357 infoPtr->pfnCompare = (PFNLVCOMPARE)lParam;
7358 infoPtr->lParamSort = (LPARAM)wParam;
7360 /* append pointers one by one to sortList */
7361 for (i = 0; i < nCount; i++)
7363 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)))
7364 if ((lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(hdpaSubItems, 0)))
7365 DPA_InsertPtr(sortList, nCount + 1, lpItem);
7368 /* sort the sortList */
7369 DPA_Sort(sortList, LISTVIEW_CallBackCompare, hwnd);
7371 /* copy the pointers back */
7372 for (i = 0; i < nCount; i++)
7374 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)) &&
7375 (lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(sortList, i)))
7376 DPA_SetPtr(hdpaSubItems, 0, lpItem);
7379 DPA_Destroy(sortList);
7385 /* LISTVIEW_SubItemHitTest */
7389 * Updates an items or rearranges the listview control.
7392 * [I] HWND : window handle
7393 * [I] INT : item index
7399 static LRESULT LISTVIEW_Update(HWND hwnd, INT nItem)
7401 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7402 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7403 BOOL bResult = FALSE;
7406 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
7410 /* rearrange with default alignment style */
7411 if ((lStyle & LVS_AUTOARRANGE) && (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
7412 ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON)))
7414 ListView_Arrange(hwnd, 0);
7418 /* get item bounding rectangle */
7419 rc.left = LVIR_BOUNDS;
7420 ListView_GetItemRect(hwnd, nItem, &rc);
7421 InvalidateRect(hwnd, &rc, TRUE);
7430 * Creates the listview control.
7433 * [I] HWND : window handle
7438 static LRESULT LISTVIEW_Create(HWND hwnd, WPARAM wParam, LPARAM lParam)
7440 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7441 LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam;
7442 UINT uView = lpcs->style & LVS_TYPEMASK;
7445 /* initialize info pointer */
7446 ZeroMemory(infoPtr, sizeof(LISTVIEW_INFO));
7448 /* determine the type of structures to use */
7449 infoPtr->notifyFormat = SendMessageA(GetParent(hwnd), WM_NOTIFYFORMAT,
7450 (WPARAM)hwnd, (LPARAM)NF_QUERY);
7451 if (infoPtr->notifyFormat != NFR_ANSI)
7453 FIXME("ANSI notify format is NOT used\n");
7456 /* initialize color information */
7457 infoPtr->clrBk = GetSysColor(COLOR_WINDOW);
7458 infoPtr->clrText = GetSysColor(COLOR_WINDOWTEXT);
7459 infoPtr->clrTextBk = CLR_DEFAULT;
7461 /* set default values */
7462 infoPtr->uCallbackMask = 0;
7463 infoPtr->nFocusedItem = -1;
7464 infoPtr->nSelectionMark = -1;
7465 infoPtr->nHotItem = -1;
7466 infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING);
7467 infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING);
7468 ZeroMemory(&infoPtr->rcList, sizeof(RECT));
7469 infoPtr->hwndEdit = 0;
7470 infoPtr->pedititem = NULL;
7471 infoPtr->nEditLabelItem = -1;
7473 /* get default font (icon title) */
7474 SystemParametersInfoA(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
7475 infoPtr->hDefaultFont = CreateFontIndirectA(&logFont);
7476 infoPtr->hFont = infoPtr->hDefaultFont;
7479 infoPtr->hwndHeader = CreateWindowA(WC_HEADERA, (LPCSTR)NULL,
7480 WS_CHILD | HDS_HORZ | HDS_BUTTONS,
7481 0, 0, 0, 0, hwnd, (HMENU)0,
7482 lpcs->hInstance, NULL);
7484 /* set header font */
7485 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont,
7488 if (uView == LVS_ICON)
7490 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
7491 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
7493 else if (uView == LVS_REPORT)
7495 if (!(LVS_NOCOLUMNHEADER & lpcs->style))
7497 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
7501 /* resize our header to nothing */
7505 memset(&zeroRect,0,sizeof(RECT));
7509 Header_Layout(infoPtr->hwndHeader,&hd);
7513 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7514 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7518 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7519 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7522 /* display unsupported listview window styles */
7523 LISTVIEW_UnsupportedStyles(lpcs->style);
7525 /* allocate memory for the data structure */
7526 infoPtr->hdpaItems = DPA_Create(10);
7528 /* allocate memory for the selection ranges */
7529 infoPtr->hdpaSelectionRanges = DPA_Create(10);
7531 /* initialize size of items */
7532 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7533 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7535 /* initialize the hover time to -1(indicating the default system hover time) */
7536 infoPtr->dwHoverTime = -1;
7543 * Erases the background of the listview control.
7546 * [I] HWND : window handle
7547 * [I] WPARAM : device context handle
7548 * [I] LPARAM : not used
7554 static LRESULT LISTVIEW_EraseBackground(HWND hwnd, WPARAM wParam,
7557 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7560 if (infoPtr->clrBk == CLR_NONE)
7562 bResult = SendMessageA(GetParent(hwnd), WM_ERASEBKGND, wParam, lParam);
7567 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
7568 GetClientRect(hwnd, &rc);
7569 FillRect((HDC)wParam, &rc, hBrush);
7570 DeleteObject(hBrush);
7579 * Retrieves the listview control font.
7582 * [I] HWND : window handle
7587 static LRESULT LISTVIEW_GetFont(HWND hwnd)
7589 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7591 return infoPtr->hFont;
7596 * Performs vertical scrolling.
7599 * [I] HWND : window handle
7600 * [I] INT : scroll code
7601 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
7603 * [I] HWND : scrollbar control window handle
7608 static LRESULT LISTVIEW_VScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
7611 SCROLLINFO scrollInfo;
7613 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
7614 scrollInfo.cbSize = sizeof(SCROLLINFO);
7615 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
7617 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
7619 INT nOldScrollPos = scrollInfo.nPos;
7620 switch (nScrollCode)
7623 if (scrollInfo.nPos > scrollInfo.nMin)
7630 if (scrollInfo.nPos < scrollInfo.nMax)
7637 if (scrollInfo.nPos > scrollInfo.nMin)
7639 if (scrollInfo.nPos >= scrollInfo.nPage)
7641 scrollInfo.nPos -= scrollInfo.nPage;
7645 scrollInfo.nPos = scrollInfo.nMin;
7651 if (scrollInfo.nPos < scrollInfo.nMax)
7653 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
7655 scrollInfo.nPos += scrollInfo.nPage;
7659 scrollInfo.nPos = scrollInfo.nMax;
7665 scrollInfo.nPos = nCurrentPos;
7666 if (scrollInfo.nPos > scrollInfo.nMax)
7667 scrollInfo.nPos=scrollInfo.nMax;
7669 if (scrollInfo.nPos < scrollInfo.nMin)
7670 scrollInfo.nPos=scrollInfo.nMin;
7675 if (nOldScrollPos != scrollInfo.nPos)
7677 scrollInfo.fMask = SIF_POS;
7678 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
7679 InvalidateRect(hwnd, NULL, TRUE);
7688 * Performs horizontal scrolling.
7691 * [I] HWND : window handle
7692 * [I] INT : scroll code
7693 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
7695 * [I] HWND : scrollbar control window handle
7700 static LRESULT LISTVIEW_HScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
7703 SCROLLINFO scrollInfo;
7705 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
7706 scrollInfo.cbSize = sizeof(SCROLLINFO);
7707 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
7709 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
7711 INT nOldScrollPos = scrollInfo.nPos;
7713 switch (nScrollCode)
7716 if (scrollInfo.nPos > scrollInfo.nMin)
7723 if (scrollInfo.nPos < scrollInfo.nMax)
7730 if (scrollInfo.nPos > scrollInfo.nMin)
7732 if (scrollInfo.nPos >= scrollInfo.nPage)
7734 scrollInfo.nPos -= scrollInfo.nPage;
7738 scrollInfo.nPos = scrollInfo.nMin;
7744 if (scrollInfo.nPos < scrollInfo.nMax)
7746 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
7748 scrollInfo.nPos += scrollInfo.nPage;
7752 scrollInfo.nPos = scrollInfo.nMax;
7758 scrollInfo.nPos = nCurrentPos;
7760 if (scrollInfo.nPos > scrollInfo.nMax)
7761 scrollInfo.nPos=scrollInfo.nMax;
7763 if (scrollInfo.nPos < scrollInfo.nMin)
7764 scrollInfo.nPos=scrollInfo.nMin;
7768 if (nOldScrollPos != scrollInfo.nPos)
7770 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
7771 scrollInfo.fMask = SIF_POS;
7772 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
7773 if(uView == LVS_REPORT)
7775 scrollInfo.fMask = SIF_POS;
7776 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
7777 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
7779 InvalidateRect(hwnd, NULL, TRUE);
7786 static LRESULT LISTVIEW_MouseWheel(HWND hwnd, INT wheelDelta)
7788 INT gcWheelDelta = 0;
7789 UINT pulScrollLines = 3;
7790 SCROLLINFO scrollInfo;
7792 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
7794 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
7795 gcWheelDelta -= wheelDelta;
7797 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
7798 scrollInfo.cbSize = sizeof(SCROLLINFO);
7799 scrollInfo.fMask = SIF_POS | SIF_RANGE;
7806 * listview should be scrolled by a multiple of 37 dependently on its dimension or its visible item number
7807 * should be fixed in the future.
7809 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
7810 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + (gcWheelDelta < 0) ? 37 : -37, 0);
7814 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
7816 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
7818 int cLineScroll = min(LISTVIEW_GetCountPerColumn(hwnd), pulScrollLines);
7819 cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
7820 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + cLineScroll, 0);
7826 LISTVIEW_HScroll(hwnd, (gcWheelDelta < 0) ? SB_LINELEFT : SB_LINERIGHT, 0, 0);
7837 * [I] HWND : window handle
7838 * [I] INT : virtual key
7839 * [I] LONG : key data
7844 static LRESULT LISTVIEW_KeyDown(HWND hwnd, INT nVirtualKey, LONG lKeyData)
7846 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7847 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
7848 HWND hwndParent = GetParent(hwnd);
7849 NMLVKEYDOWN nmKeyDown;
7852 BOOL bRedraw = FALSE;
7854 /* send LVN_KEYDOWN notification */
7855 ZeroMemory(&nmKeyDown, sizeof(NMLVKEYDOWN));
7856 nmKeyDown.hdr.hwndFrom = hwnd;
7857 nmKeyDown.hdr.idFrom = nCtrlId;
7858 nmKeyDown.hdr.code = LVN_KEYDOWN;
7859 nmKeyDown.wVKey = nVirtualKey;
7860 nmKeyDown.flags = 0;
7861 SendMessageA(hwndParent, WM_NOTIFY, (WPARAM)nCtrlId, (LPARAM)&nmKeyDown);
7864 nmh.hwndFrom = hwnd;
7865 nmh.idFrom = nCtrlId;
7867 switch (nVirtualKey)
7870 if ((GETITEMCOUNT(infoPtr) > 0) && (infoPtr->nFocusedItem != -1))
7872 /* send NM_RETURN notification */
7873 nmh.code = NM_RETURN;
7874 ListView_Notify(hwndParent, nCtrlId, &nmh);
7876 /* send LVN_ITEMACTIVATE notification */
7877 nmh.code = LVN_ITEMACTIVATE;
7878 ListView_Notify(hwndParent, nCtrlId, &nmh);
7883 if (GETITEMCOUNT(infoPtr) > 0)
7890 if (GETITEMCOUNT(infoPtr) > 0)
7892 nItem = GETITEMCOUNT(infoPtr) - 1;
7897 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TOLEFT);
7901 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_ABOVE);
7905 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TORIGHT);
7909 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_BELOW);
7921 if ((nItem != -1) && (nItem != infoPtr->nFocusedItem))
7923 bRedraw = LISTVIEW_KeySelection(hwnd, nItem);
7924 if (bRedraw != FALSE)
7926 /* refresh client area */
7939 * [I] HWND : window handle
7944 static LRESULT LISTVIEW_KillFocus(HWND hwnd)
7946 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
7947 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
7951 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7952 UINT uView = lStyle & LVS_TYPEMASK;
7954 TRACE("(hwnd=%x)\n", hwnd);
7956 /* send NM_KILLFOCUS notification */
7957 nmh.hwndFrom = hwnd;
7958 nmh.idFrom = nCtrlId;
7959 nmh.code = NM_KILLFOCUS;
7960 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
7962 /* set window focus flag */
7963 infoPtr->bFocus = FALSE;
7965 /* NEED drawing optimization ; redraw the selected items */
7966 if (uView & LVS_REPORT)
7968 nTop = LISTVIEW_GetTopIndex(hwnd);
7970 LISTVIEW_GetCountPerColumn(hwnd) + 1;
7975 nBottom = GETITEMCOUNT(infoPtr);
7977 for (i = nTop; i<nBottom; i++)
7979 if (LISTVIEW_IsSelected(hwnd,i))
7981 rcItem.left = LVIR_BOUNDS;
7982 LISTVIEW_GetItemRect(hwnd, i, &rcItem);
7983 InvalidateRect(hwnd, &rcItem, FALSE);
7992 * Processes double click messages (left mouse button).
7995 * [I] HWND : window handle
7996 * [I] WORD : key flag
7997 * [I] WORD : x coordinate
7998 * [I] WORD : y coordinate
8003 static LRESULT LISTVIEW_LButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
8006 LONG nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8008 LVHITTESTINFO htInfo;
8010 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8012 /* send NM_DBLCLK notification */
8013 nmh.hwndFrom = hwnd;
8014 nmh.idFrom = nCtrlId;
8015 nmh.code = NM_DBLCLK;
8016 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8018 /* To send the LVN_ITEMACTIVATE, it must be on an Item */
8019 ZeroMemory(&htInfo, sizeof(LVHITTESTINFO));
8020 htInfo.pt.x = wPosX;
8021 htInfo.pt.y = wPosY;
8022 if(LISTVIEW_HitTest(hwnd, &htInfo) != -1)
8024 /* send LVN_ITEMACTIVATE notification */
8025 nmh.code = LVN_ITEMACTIVATE;
8026 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8034 * Processes mouse down messages (left mouse button).
8037 * [I] HWND : window handle
8038 * [I] WORD : key flag
8039 * [I] WORD : x coordinate
8040 * [I] WORD : y coordinate
8045 static LRESULT LISTVIEW_LButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
8048 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8049 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8050 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8051 static BOOL bGroupSelect = TRUE;
8056 TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd, wKey, wPosX,
8059 /* send NM_RELEASEDCAPTURE notification */
8060 nmh.hwndFrom = hwnd;
8061 nmh.idFrom = nCtrlId;
8062 nmh.code = NM_RELEASEDCAPTURE;
8063 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8065 if (infoPtr->bFocus == FALSE)
8070 /* set left button down flag */
8071 infoPtr->bLButtonDown = TRUE;
8073 ptPosition.x = wPosX;
8074 ptPosition.y = wPosY;
8075 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
8076 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
8078 if (lStyle & LVS_SINGLESEL)
8080 if ((ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
8081 && infoPtr->nEditLabelItem == -1)
8083 infoPtr->nEditLabelItem = nItem;
8087 LISTVIEW_SetSelection(hwnd, nItem);
8092 if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
8094 if (bGroupSelect != FALSE)
8096 LISTVIEW_AddGroupSelection(hwnd, nItem);
8100 LISTVIEW_AddSelection(hwnd, nItem);
8103 else if (wKey & MK_CONTROL)
8105 bGroupSelect = LISTVIEW_ToggleSelection(hwnd, nItem);
8107 else if (wKey & MK_SHIFT)
8109 LISTVIEW_SetGroupSelection(hwnd, nItem);
8114 (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED);
8116 /* set selection (clears other pre-existing selections) */
8117 LISTVIEW_SetSelection(hwnd, nItem);
8119 if (was_selected && infoPtr->nEditLabelItem == -1)
8121 infoPtr->nEditLabelItem = nItem;
8128 /* remove all selections */
8129 LISTVIEW_RemoveAllSelections(hwnd);
8132 InvalidateRect(hwnd, NULL, TRUE);
8139 * Processes mouse up messages (left mouse button).
8142 * [I] HWND : window handle
8143 * [I] WORD : key flag
8144 * [I] WORD : x coordinate
8145 * [I] WORD : y coordinate
8150 static LRESULT LISTVIEW_LButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
8153 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8155 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8157 if (infoPtr->bLButtonDown != FALSE)
8159 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8162 /* send NM_CLICK notification */
8163 nmh.hwndFrom = hwnd;
8164 nmh.idFrom = nCtrlId;
8165 nmh.code = NM_CLICK;
8166 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8168 /* set left button flag */
8169 infoPtr->bLButtonDown = FALSE;
8171 if(infoPtr->nEditLabelItem != -1)
8175 ptPosition.x = wPosX;
8176 ptPosition.y = wPosY;
8177 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
8178 if(nItem == infoPtr->nEditLabelItem)
8180 LISTVIEW_EditLabelA(hwnd, nItem);
8182 infoPtr->nEditLabelItem = -1;
8191 * Creates the listview control (called before WM_CREATE).
8194 * [I] HWND : window handle
8195 * [I] WPARAM : unhandled
8196 * [I] LPARAM : widow creation info
8201 static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
8203 LISTVIEW_INFO *infoPtr;
8205 TRACE("(hwnd=%x,wParam=%x,lParam=%lx)\n", hwnd, wParam, lParam);
8207 /* allocate memory for info structure */
8208 infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc(sizeof(LISTVIEW_INFO));
8209 SetWindowLongA(hwnd, 0, (LONG)infoPtr);
8210 if (infoPtr == NULL)
8212 ERR("could not allocate info memory!\n");
8216 if ((LISTVIEW_INFO *)GetWindowLongA(hwnd, 0) != infoPtr)
8218 ERR("pointer assignment error!\n");
8222 return DefWindowProcA(hwnd, WM_NCCREATE, wParam, lParam);
8227 * Destroys the listview control (called after WM_DESTROY).
8230 * [I] HWND : window handle
8235 static LRESULT LISTVIEW_NCDestroy(HWND hwnd)
8237 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8239 TRACE("(hwnd=%x)\n", hwnd);
8241 /* delete all items */
8242 LISTVIEW_DeleteAllItems(hwnd);
8244 /* destroy data structure */
8245 DPA_Destroy(infoPtr->hdpaItems);
8246 DPA_Destroy(infoPtr->hdpaSelectionRanges);
8249 infoPtr->hFont = (HFONT)0;
8250 if (infoPtr->hDefaultFont)
8252 DeleteObject(infoPtr->hDefaultFont);
8255 /* free listview info pointer*/
8256 COMCTL32_Free(infoPtr);
8258 SetWindowLongA(hwnd, 0, 0);
8264 * Handles notifications from children.
8267 * [I] HWND : window handle
8268 * [I] INT : control identifier
8269 * [I] LPNMHDR : notification information
8274 static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh)
8276 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8278 if (lpnmh->hwndFrom == infoPtr->hwndHeader)
8280 /* handle notification from header control */
8281 if (lpnmh->code == HDN_ENDTRACKA)
8283 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8284 InvalidateRect(hwnd, NULL, TRUE);
8286 else if(lpnmh->code == HDN_ITEMCLICKA)
8288 /* Handle sorting by Header Column */
8290 LPNMHEADERA pnmHeader = (LPNMHEADERA) lpnmh;
8291 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
8293 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
8294 nmlv.hdr.hwndFrom = hwnd;
8295 nmlv.hdr.idFrom = lCtrlId;
8296 nmlv.hdr.code = LVN_COLUMNCLICK;
8298 nmlv.iSubItem = pnmHeader->iItem;
8300 ListView_LVNotify(GetParent(hwnd),lCtrlId, &nmlv);
8303 else if(lpnmh->code == NM_RELEASEDCAPTURE)
8305 /* Idealy this should be done in HDN_ENDTRACKA
8306 * but since SetItemBounds in Header.c is called after
8307 * the notification is sent, it is neccessary to handle the
8308 * update of the scroll bar here (Header.c works fine as it is,
8309 * no need to disturb it)
8311 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8312 LISTVIEW_UpdateScroll(hwnd);
8313 InvalidateRect(hwnd, NULL, TRUE);
8323 * Determines the type of structure to use.
8326 * [I] HWND : window handle of the sender
8327 * [I] HWND : listview window handle
8328 * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
8333 static LRESULT LISTVIEW_NotifyFormat(HWND hwndFrom, HWND hwnd, INT nCommand)
8335 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8337 if (nCommand == NF_REQUERY)
8339 /* determine the type of structure to use */
8340 infoPtr->notifyFormat = SendMessageA(hwndFrom, WM_NOTIFYFORMAT,
8341 (WPARAM)hwnd, (LPARAM)NF_QUERY);
8342 if (infoPtr->notifyFormat == NFR_UNICODE)
8344 FIXME("NO support for unicode structures");
8353 * Paints/Repaints the listview control.
8356 * [I] HWND : window handle
8357 * [I] HDC : device context handle
8362 static LRESULT LISTVIEW_Paint(HWND hwnd, HDC hdc)
8366 TRACE("(hwnd=%x,hdc=%x)\n", hwnd, hdc);
8370 hdc = BeginPaint(hwnd, &ps);
8371 LISTVIEW_Refresh(hwnd, hdc);
8372 EndPaint(hwnd, &ps);
8376 LISTVIEW_Refresh(hwnd, hdc);
8384 * Processes double click messages (right mouse button).
8387 * [I] HWND : window handle
8388 * [I] WORD : key flag
8389 * [I] WORD : x coordinate
8390 * [I] WORD : y coordinate
8395 static LRESULT LISTVIEW_RButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
8398 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8401 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8403 /* send NM_RELEASEDCAPTURE notification */
8404 nmh.hwndFrom = hwnd;
8405 nmh.idFrom = nCtrlId;
8406 nmh.code = NM_RELEASEDCAPTURE;
8407 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8409 /* send NM_RDBLCLK notification */
8410 nmh.code = NM_RDBLCLK;
8411 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8418 * Processes mouse down messages (right mouse button).
8421 * [I] HWND : window handle
8422 * [I] WORD : key flag
8423 * [I] WORD : x coordinate
8424 * [I] WORD : y coordinate
8429 static LRESULT LISTVIEW_RButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
8432 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8433 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8438 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8440 /* send NM_RELEASEDCAPTURE notification */
8441 nmh.hwndFrom = hwnd;
8442 nmh.idFrom = nCtrlId;
8443 nmh.code = NM_RELEASEDCAPTURE;
8444 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8446 /* make sure the listview control window has the focus */
8447 if (infoPtr->bFocus == FALSE)
8452 /* set right button down flag */
8453 infoPtr->bRButtonDown = TRUE;
8455 /* determine the index of the selected item */
8456 ptPosition.x = wPosX;
8457 ptPosition.y = wPosY;
8458 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
8459 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
8461 if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)))
8463 LISTVIEW_SetSelection(hwnd, nItem);
8468 LISTVIEW_RemoveAllSelections(hwnd);
8476 * Processes mouse up messages (right mouse button).
8479 * [I] HWND : window handle
8480 * [I] WORD : key flag
8481 * [I] WORD : x coordinate
8482 * [I] WORD : y coordinate
8487 static LRESULT LISTVIEW_RButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
8490 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8491 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8494 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8496 if (infoPtr->bRButtonDown != FALSE)
8502 /* Send NM_RClICK notification */
8503 ZeroMemory(&nmh, sizeof(NMHDR));
8504 nmh.hwndFrom = hwnd;
8505 nmh.idFrom = nCtrlId;
8506 nmh.code = NM_RCLICK;
8507 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8509 /* set button flag */
8510 infoPtr->bRButtonDown = FALSE;
8512 /* Change to screen coordinate for WM_CONTEXTMENU */
8513 ClientToScreen(hwnd, &pt);
8515 /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
8516 SendMessageA( hwnd, WM_CONTEXTMENU, (WPARAM) hwnd, MAKELPARAM(pt.x, pt.y));
8527 * [I] HWND : window handle
8528 * [I] HWND : window handle of previously focused window
8533 static LRESULT LISTVIEW_SetFocus(HWND hwnd, HWND hwndLoseFocus)
8535 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8536 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8539 TRACE("(hwnd=%x, hwndLoseFocus=%x)\n", hwnd, hwndLoseFocus);
8541 /* send NM_SETFOCUS notification */
8542 nmh.hwndFrom = hwnd;
8543 nmh.idFrom = nCtrlId;
8544 nmh.code = NM_SETFOCUS;
8545 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8547 /* set window focus flag */
8548 infoPtr->bFocus = TRUE;
8560 * [I] HWND : window handle
8561 * [I] HFONT : font handle
8562 * [I] WORD : redraw flag
8567 static LRESULT LISTVIEW_SetFont(HWND hwnd, HFONT hFont, WORD fRedraw)
8569 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8570 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
8572 TRACE("(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd, hFont, fRedraw);
8576 infoPtr->hFont = infoPtr->hDefaultFont;
8580 infoPtr->hFont = hFont;
8583 if (uView == LVS_REPORT)
8585 /* set header font */
8586 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont,
8587 MAKELPARAM(fRedraw, 0));
8590 /* invalidate listview control client area */
8591 InvalidateRect(hwnd, NULL, TRUE);
8593 if (fRedraw != FALSE)
8603 * Message handling for WM_SETREDRAW.
8604 * For the Listview, it invalidates the entire window (the doc specifies otherwise)
8607 * [I] HWND : window handle
8608 * [I] bRedraw: state of redraw flag
8611 * DefWinProc return value
8613 static LRESULT LISTVIEW_SetRedraw(HWND hwnd, BOOL bRedraw)
8616 lResult = DefWindowProcA(hwnd, WM_SETREDRAW, bRedraw, 0);
8619 RedrawWindow(hwnd, NULL, 0,
8620 RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN | RDW_ERASENOW);
8627 * Resizes the listview control. This function processes WM_SIZE
8628 * messages. At this time, the width and height are not used.
8631 * [I] HWND : window handle
8632 * [I] WORD : new width
8633 * [I] WORD : new height
8638 static LRESULT LISTVIEW_Size(HWND hwnd, int Width, int Height)
8640 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8641 UINT uView = lStyle & LVS_TYPEMASK;
8643 TRACE("(hwnd=%x, width=%d, height=%d)\n",hwnd, Width, Height);
8645 LISTVIEW_UpdateSize(hwnd);
8647 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
8649 if (lStyle & LVS_ALIGNLEFT)
8651 LISTVIEW_AlignLeft(hwnd);
8655 LISTVIEW_AlignTop(hwnd);
8659 LISTVIEW_UpdateScroll(hwnd);
8661 /* invalidate client area + erase background */
8662 InvalidateRect(hwnd, NULL, TRUE);
8669 * Sets the size information.
8672 * [I] HWND : window handle
8677 static VOID LISTVIEW_UpdateSize(HWND hwnd)
8679 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8680 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8681 UINT uView = lStyle & LVS_TYPEMASK;
8684 GetClientRect(hwnd, &rcList);
8685 infoPtr->rcList.left = 0;
8686 infoPtr->rcList.right = max(rcList.right - rcList.left, 1);
8687 infoPtr->rcList.top = 0;
8688 infoPtr->rcList.bottom = max(rcList.bottom - rcList.top, 1);
8690 if (uView == LVS_LIST)
8692 if ((lStyle & WS_HSCROLL) == 0)
8694 INT nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
8695 if (infoPtr->rcList.bottom > nHScrollHeight)
8697 infoPtr->rcList.bottom -= nHScrollHeight;
8701 else if ((uView == LVS_REPORT)&&(!(LVS_NOCOLUMNHEADER & lStyle)))
8708 Header_Layout(infoPtr->hwndHeader, &hl);
8710 SetWindowPos(wp.hwnd, wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
8712 if (!(LVS_NOCOLUMNHEADER & lStyle))
8714 infoPtr->rcList.top = max(wp.cy, 0);
8721 * Processes WM_STYLECHANGED messages.
8724 * [I] HWND : window handle
8725 * [I] WPARAM : window style type (normal or extended)
8726 * [I] LPSTYLESTRUCT : window style information
8731 static INT LISTVIEW_StyleChanged(HWND hwnd, WPARAM wStyleType,
8734 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8735 UINT uNewView = lpss->styleNew & LVS_TYPEMASK;
8736 UINT uOldView = lpss->styleOld & LVS_TYPEMASK;
8737 RECT rcList = infoPtr->rcList;
8739 TRACE("(hwnd=%x, styletype=%x, stylestruct=%p)\n",
8740 hwnd, wStyleType, lpss);
8742 if (wStyleType == GWL_STYLE)
8744 if (uOldView == LVS_REPORT)
8746 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
8749 if ((lpss->styleOld & WS_HSCROLL) != 0)
8751 ShowScrollBar(hwnd, SB_HORZ, FALSE);
8754 if ((lpss->styleOld & WS_VSCROLL) != 0)
8756 ShowScrollBar(hwnd, SB_VERT, FALSE);
8759 if (uNewView == LVS_ICON)
8761 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
8762 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
8763 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8764 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8765 if (lpss->styleNew & LVS_ALIGNLEFT)
8767 LISTVIEW_AlignLeft(hwnd);
8771 LISTVIEW_AlignTop(hwnd);
8774 else if (uNewView == LVS_REPORT)
8779 if (!(LVS_NOCOLUMNHEADER & lpss->styleNew))
8783 Header_Layout(infoPtr->hwndHeader, &hl);
8784 SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, wp.cy,
8786 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
8791 ZeroMemory(&zeroRect,sizeof(RECT));
8795 Header_Layout(infoPtr->hwndHeader, &hl);
8798 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
8799 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
8800 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8801 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8803 else if (uNewView == LVS_LIST)
8805 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
8806 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
8807 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8808 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8812 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
8813 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
8814 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8815 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8816 if (lpss->styleNew & LVS_ALIGNLEFT)
8818 LISTVIEW_AlignLeft(hwnd);
8822 LISTVIEW_AlignTop(hwnd);
8826 /* update the size of the client area */
8827 LISTVIEW_UpdateSize(hwnd);
8829 /* add scrollbars if needed */
8830 LISTVIEW_UpdateScroll(hwnd);
8832 /* invalidate client area + erase background */
8833 InvalidateRect(hwnd, NULL, TRUE);
8835 /* print the list of unsupported window styles */
8836 LISTVIEW_UnsupportedStyles(lpss->styleNew);
8839 /* If they change the view and we have an active edit control
8840 we will need to kill the control since the redraw will
8841 misplace the edit control.
8843 if (infoPtr->hwndEdit &&
8844 ((uNewView & (LVS_ICON|LVS_LIST|LVS_SMALLICON)) !=
8845 ((LVS_ICON|LVS_LIST|LVS_SMALLICON) & uOldView)))
8847 SendMessageA(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
8855 * Window procedure of the listview control.
8858 static LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
8861 TRACE("hwnd=%x uMsg=%x wParam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam);
8862 if (!GetWindowLongA(hwnd, 0) && (uMsg != WM_NCCREATE))
8863 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
8866 case LVM_APPROXIMATEVIEWRECT:
8867 return LISTVIEW_ApproximateViewRect(hwnd, (INT)wParam,
8868 LOWORD(lParam), HIWORD(lParam));
8870 return LISTVIEW_Arrange(hwnd, (INT)wParam);
8872 /* case LVM_CREATEDRAGIMAGE: */
8874 case LVM_DELETEALLITEMS:
8875 return LISTVIEW_DeleteAllItems(hwnd);
8877 case LVM_DELETECOLUMN:
8878 return LISTVIEW_DeleteColumn(hwnd, (INT)wParam);
8880 case LVM_DELETEITEM:
8881 return LISTVIEW_DeleteItem(hwnd, (INT)wParam);
8883 case LVM_EDITLABELW:
8884 case LVM_EDITLABELA:
8885 return LISTVIEW_EditLabelA(hwnd, (INT)wParam);
8887 case LVM_ENSUREVISIBLE:
8888 return LISTVIEW_EnsureVisible(hwnd, (INT)wParam, (BOOL)lParam);
8891 return LISTVIEW_FindItem(hwnd, (INT)wParam, (LPLVFINDINFO)lParam);
8893 case LVM_GETBKCOLOR:
8894 return LISTVIEW_GetBkColor(hwnd);
8896 /* case LVM_GETBKIMAGE: */
8898 case LVM_GETCALLBACKMASK:
8899 return LISTVIEW_GetCallbackMask(hwnd);
8901 case LVM_GETCOLUMNA:
8902 return LISTVIEW_GetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
8904 /* case LVM_GETCOLUMNW: */
8906 case LVM_GETCOLUMNORDERARRAY:
8907 return LISTVIEW_GetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
8909 case LVM_GETCOLUMNWIDTH:
8910 return LISTVIEW_GetColumnWidth(hwnd, (INT)wParam);
8912 case LVM_GETCOUNTPERPAGE:
8913 return LISTVIEW_GetCountPerPage(hwnd);
8915 case LVM_GETEDITCONTROL:
8916 return LISTVIEW_GetEditControl(hwnd);
8918 case LVM_GETEXTENDEDLISTVIEWSTYLE:
8919 return LISTVIEW_GetExtendedListViewStyle(hwnd);
8922 return LISTVIEW_GetHeader(hwnd);
8924 /* case LVM_GETHOTCURSOR: */
8926 case LVM_GETHOTITEM:
8927 return LISTVIEW_GetHotItem(hwnd);
8929 case LVM_GETHOVERTIME:
8930 return LISTVIEW_GetHoverTime(hwnd);
8932 case LVM_GETIMAGELIST:
8933 return LISTVIEW_GetImageList(hwnd, (INT)wParam);
8935 /* case LVM_GETISEARCHSTRING: */
8938 return LISTVIEW_GetItemA(hwnd, (LPLVITEMA)lParam, FALSE);
8940 /* case LVM_GETITEMW: */
8942 case LVM_GETITEMCOUNT:
8943 return LISTVIEW_GetItemCount(hwnd);
8945 case LVM_GETITEMPOSITION:
8946 return LISTVIEW_GetItemPosition(hwnd, (INT)wParam, (LPPOINT)lParam);
8948 case LVM_GETITEMRECT:
8949 return LISTVIEW_GetItemRect(hwnd, (INT)wParam, (LPRECT)lParam);
8951 case LVM_GETITEMSPACING:
8952 return LISTVIEW_GetItemSpacing(hwnd, (BOOL)wParam);
8954 case LVM_GETITEMSTATE:
8955 return LISTVIEW_GetItemState(hwnd, (INT)wParam, (UINT)lParam);
8957 case LVM_GETITEMTEXTA:
8958 LISTVIEW_GetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
8961 /* case LVM_GETITEMTEXTW: */
8963 case LVM_GETNEXTITEM:
8964 return LISTVIEW_GetNextItem(hwnd, (INT)wParam, LOWORD(lParam));
8966 /* case LVM_GETNUMBEROFWORKAREAS: */
8969 return LISTVIEW_GetOrigin(hwnd, (LPPOINT)lParam);
8971 case LVM_GETSELECTEDCOUNT:
8972 return LISTVIEW_GetSelectedCount(hwnd);
8974 case LVM_GETSELECTIONMARK:
8975 return LISTVIEW_GetSelectionMark(hwnd);
8977 case LVM_GETSTRINGWIDTHA:
8978 return LISTVIEW_GetStringWidthA (hwnd, (LPCSTR)lParam);
8980 /* case LVM_GETSTRINGWIDTHW: */
8981 /* case LVM_GETSUBITEMRECT: */
8983 case LVM_GETTEXTBKCOLOR:
8984 return LISTVIEW_GetTextBkColor(hwnd);
8986 case LVM_GETTEXTCOLOR:
8987 return LISTVIEW_GetTextColor(hwnd);
8989 /* case LVM_GETTOOLTIPS: */
8991 case LVM_GETTOPINDEX:
8992 return LISTVIEW_GetTopIndex(hwnd);
8994 /* case LVM_GETUNICODEFORMAT: */
8996 case LVM_GETVIEWRECT:
8997 return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam);
8999 /* case LVM_GETWORKAREAS: */
9002 return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam);
9004 case LVM_INSERTCOLUMNA:
9005 return LISTVIEW_InsertColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
9007 case LVM_INSERTCOLUMNW:
9008 return LISTVIEW_InsertColumnW(hwnd, (INT)wParam, (LPLVCOLUMNW)lParam);
9010 case LVM_INSERTITEMA:
9011 return LISTVIEW_InsertItemA(hwnd, (LPLVITEMA)lParam);
9013 case LVM_INSERTITEMW:
9014 return LISTVIEW_InsertItemW(hwnd, (LPLVITEMW)lParam);
9016 case LVM_REDRAWITEMS:
9017 return LISTVIEW_RedrawItems(hwnd, (INT)wParam, (INT)lParam);
9019 /* case LVM_SCROLL: */
9020 /* return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); */
9022 case LVM_SETBKCOLOR:
9023 return LISTVIEW_SetBkColor(hwnd, (COLORREF)lParam);
9025 /* case LVM_SETBKIMAGE: */
9027 case LVM_SETCALLBACKMASK:
9028 return LISTVIEW_SetCallbackMask(hwnd, (UINT)wParam);
9030 case LVM_SETCOLUMNA:
9031 return LISTVIEW_SetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
9033 case LVM_SETCOLUMNW:
9034 FIXME("Unimplemented msg LVM_SETCOLUMNW\n");
9037 case LVM_SETCOLUMNORDERARRAY:
9038 return LISTVIEW_SetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
9040 case LVM_SETCOLUMNWIDTH:
9041 return LISTVIEW_SetColumnWidth(hwnd, (INT)wParam, SLOWORD(lParam));
9043 case LVM_SETEXTENDEDLISTVIEWSTYLE:
9044 return LISTVIEW_SetExtendedListViewStyle(hwnd, (DWORD)wParam, (DWORD)lParam);
9046 /* case LVM_SETHOTCURSOR: */
9048 case LVM_SETHOTITEM:
9049 return LISTVIEW_SetHotItem(hwnd, (INT)wParam);
9051 case LVM_SETHOVERTIME:
9052 return LISTVIEW_SetHoverTime(hwnd, (DWORD)wParam);
9054 /* case LVM_SETICONSPACING: */
9056 case LVM_SETIMAGELIST:
9057 return LISTVIEW_SetImageList(hwnd, (INT)wParam, (HIMAGELIST)lParam);
9060 return LISTVIEW_SetItemA(hwnd, (LPLVITEMA)lParam);
9062 /* case LVM_SETITEMW: */
9064 case LVM_SETITEMCOUNT:
9065 return LISTVIEW_SetItemCount(hwnd, (INT)wParam, (DWORD)lParam);
9067 case LVM_SETITEMPOSITION:
9068 return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, (INT)LOWORD(lParam),
9069 (INT)HIWORD(lParam));
9071 /* case LVM_SETITEMPOSITION32: */
9073 case LVM_SETITEMSTATE:
9074 return LISTVIEW_SetItemState(hwnd, (INT)wParam, (LPLVITEMA)lParam);
9076 case LVM_SETITEMTEXTA:
9077 return LISTVIEW_SetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
9079 /* case LVM_SETITEMTEXTW: */
9081 case LVM_SETSELECTIONMARK:
9082 return LISTVIEW_SetSelectionMark(hwnd, (INT)lParam);
9084 case LVM_SETTEXTBKCOLOR:
9085 return LISTVIEW_SetTextBkColor(hwnd, (COLORREF)lParam);
9087 case LVM_SETTEXTCOLOR:
9088 return LISTVIEW_SetTextColor(hwnd, (COLORREF)lParam);
9090 /* case LVM_SETTOOLTIPS: */
9091 /* case LVM_SETUNICODEFORMAT: */
9092 /* case LVM_SETWORKAREAS: */
9095 return LISTVIEW_SortItems(hwnd, wParam, lParam);
9097 /* case LVM_SUBITEMHITTEST: */
9100 return LISTVIEW_Update(hwnd, (INT)wParam);
9104 return LISTVIEW_ProcessLetterKeys( hwnd, wParam, lParam );
9107 return LISTVIEW_Command(hwnd, wParam, lParam);
9110 return LISTVIEW_Create(hwnd, wParam, lParam);
9113 return LISTVIEW_EraseBackground(hwnd, wParam, lParam);
9116 return DLGC_WANTCHARS | DLGC_WANTARROWS;
9119 return LISTVIEW_GetFont(hwnd);
9122 return LISTVIEW_HScroll(hwnd, (INT)LOWORD(wParam),
9123 (INT)HIWORD(wParam), (HWND)lParam);
9126 return LISTVIEW_KeyDown(hwnd, (INT)wParam, (LONG)lParam);
9129 return LISTVIEW_KillFocus(hwnd);
9131 case WM_LBUTTONDBLCLK:
9132 return LISTVIEW_LButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
9135 case WM_LBUTTONDOWN:
9136 return LISTVIEW_LButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
9139 return LISTVIEW_LButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
9142 return LISTVIEW_MouseMove (hwnd, wParam, lParam);
9145 return LISTVIEW_MouseHover(hwnd, wParam, lParam);
9148 return LISTVIEW_NCCreate(hwnd, wParam, lParam);
9151 return LISTVIEW_NCDestroy(hwnd);
9154 return LISTVIEW_Notify(hwnd, (INT)wParam, (LPNMHDR)lParam);
9156 case WM_NOTIFYFORMAT:
9157 return LISTVIEW_NotifyFormat(hwnd, (HWND)wParam, (INT)lParam);
9160 return LISTVIEW_Paint(hwnd, (HDC)wParam);
9162 case WM_RBUTTONDBLCLK:
9163 return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
9166 case WM_RBUTTONDOWN:
9167 return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
9171 return LISTVIEW_RButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
9175 return LISTVIEW_SetFocus(hwnd, (HWND)wParam);
9178 return LISTVIEW_SetFont(hwnd, (HFONT)wParam, (WORD)lParam);
9181 return LISTVIEW_SetRedraw(hwnd, (BOOL)wParam);
9184 return LISTVIEW_Size(hwnd, (int)SLOWORD(lParam), (int)SHIWORD(lParam));
9186 case WM_STYLECHANGED:
9187 return LISTVIEW_StyleChanged(hwnd, wParam, (LPSTYLESTRUCT)lParam);
9189 /* case WM_TIMER: */
9192 return LISTVIEW_VScroll(hwnd, (INT)LOWORD(wParam),
9193 (INT)HIWORD(wParam), (HWND)lParam);
9196 if (wParam & (MK_SHIFT | MK_CONTROL))
9197 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
9198 return LISTVIEW_MouseWheel(hwnd, (short int)HIWORD(wParam));/* case WM_WINDOWPOSCHANGED: */
9200 /* case WM_WININICHANGE: */
9203 if (uMsg >= WM_USER)
9205 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam,
9209 /* call default window procedure */
9210 return DefWindowProcA(hwnd, uMsg, wParam, lParam);
9218 * Registers the window class.
9226 VOID LISTVIEW_Register(void)
9230 ZeroMemory(&wndClass, sizeof(WNDCLASSA));
9231 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
9232 wndClass.lpfnWndProc = (WNDPROC)LISTVIEW_WindowProc;
9233 wndClass.cbClsExtra = 0;
9234 wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *);
9235 wndClass.hCursor = LoadCursorA(0, IDC_ARROWA);
9236 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
9237 wndClass.lpszClassName = WC_LISTVIEWA;
9238 RegisterClassA(&wndClass);
9243 * Unregisters the window class.
9251 VOID LISTVIEW_Unregister(void)
9253 UnregisterClassA(WC_LISTVIEWA, (HINSTANCE)NULL);
9258 * Handle any WM_COMMAND messages
9264 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam)
9266 switch (HIWORD(wParam))
9271 * Adjust the edit window size
9274 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
9275 HDC hdc = GetDC(infoPtr->hwndEdit);
9276 HFONT hFont, hOldFont = 0;
9281 len = GetWindowTextA(infoPtr->hwndEdit, buffer, 1023);
9282 GetWindowRect(infoPtr->hwndEdit, &rect);
9284 /* Select font to get the right dimension of the string */
9285 hFont = SendMessageA(infoPtr->hwndEdit, WM_GETFONT, 0, 0);
9288 hOldFont = SelectObject(hdc, hFont);
9291 if (GetTextExtentPoint32A(hdc, buffer, strlen(buffer), &sz))
9293 TEXTMETRICA textMetric;
9295 /* Add Extra spacing for the next character */
9296 GetTextMetricsA(hdc, &textMetric);
9297 sz.cx += (textMetric.tmMaxCharWidth * 2);
9305 rect.bottom - rect.top,
9306 SWP_DRAWFRAME|SWP_NOMOVE);
9310 SelectObject(hdc, hOldFont);
9313 ReleaseDC(hwnd, hdc);
9319 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
9328 * Subclassed edit control windproc function
9334 LRESULT CALLBACK EditLblWndProc(HWND hwnd, UINT uMsg,
9335 WPARAM wParam, LPARAM lParam)
9337 BOOL cancel = FALSE;
9338 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(GetParent(hwnd), 0);
9339 EDITLABEL_ITEM *einfo = infoPtr->pedititem;
9340 static BOOL bIgnoreKillFocus = FALSE;
9344 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
9347 if(bIgnoreKillFocus)
9355 WNDPROC editProc = einfo->EditWndProc;
9356 SetWindowLongA(hwnd, GWL_WNDPROC, (LONG)editProc);
9357 COMCTL32_Free(einfo);
9358 infoPtr->pedititem = NULL;
9359 return CallWindowProcA(editProc, hwnd, uMsg, wParam, lParam);
9363 if (VK_ESCAPE == (INT)wParam)
9369 else if (VK_RETURN == (INT)wParam)
9373 return CallWindowProcA(einfo->EditWndProc, hwnd,
9374 uMsg, wParam, lParam);
9377 if (einfo->EditLblCb)
9379 char *buffer = NULL;
9384 int len = 1 + GetWindowTextLengthA(hwnd);
9388 if (NULL != (buffer = (char *)COMCTL32_Alloc(len*sizeof(char))))
9390 GetWindowTextA(hwnd, buffer, len);
9394 /* Processing LVN_ENDLABELEDIT message could kill the focus */
9395 /* eg. Using a messagebox */
9396 bIgnoreKillFocus = TRUE;
9397 einfo->EditLblCb(GetParent(hwnd), buffer, einfo->param);
9400 COMCTL32_Free(buffer);
9402 einfo->EditLblCb = NULL;
9403 bIgnoreKillFocus = FALSE;
9406 SendMessageA(hwnd, WM_CLOSE, 0, 0);
9413 * Creates a subclassed edit cotrol
9419 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
9420 INT width, INT height, HWND parent, HINSTANCE hinst,
9421 EditlblCallback EditLblCb, DWORD param)
9427 TEXTMETRICA textMetric;
9428 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(parent, 0);
9430 if (NULL == (infoPtr->pedititem = COMCTL32_Alloc(sizeof(EDITLABEL_ITEM))))
9433 style |= WS_CHILDWINDOW|WS_CLIPSIBLINGS|ES_LEFT|WS_BORDER;
9434 hdc = GetDC(parent);
9436 /* Select the font to get appropriate metric dimensions */
9437 if(infoPtr->hFont != 0)
9439 hOldFont = SelectObject(hdc, infoPtr->hFont);
9442 /*Get String Lenght in pixels */
9443 GetTextExtentPoint32A(hdc, text, strlen(text), &sz);
9445 /*Add Extra spacing for the next character */
9446 GetTextMetricsA(hdc, &textMetric);
9447 sz.cx += (textMetric.tmMaxCharWidth * 2);
9449 if(infoPtr->hFont != 0)
9451 SelectObject(hdc, hOldFont);
9454 ReleaseDC(parent, hdc);
9455 if (!(hedit = CreateWindowA("Edit", text, style, x, y, sz.cx, height,
9456 parent, 0, hinst, 0)))
9458 COMCTL32_Free(infoPtr->pedititem);
9462 infoPtr->pedititem->param = param;
9463 infoPtr->pedititem->EditLblCb = EditLblCb;
9464 infoPtr->pedititem->EditWndProc = (WNDPROC)SetWindowLongA(hedit,
9465 GWL_WNDPROC, (LONG) EditLblWndProc);
9467 SendMessageA(hedit, WM_SETFONT, infoPtr->hFont, FALSE);