4 * Copyright 1998, 1999 Eric Kohl
5 * Copyright 1999 Luc Tourangeau
6 * Copyright 2000 Jason Mawdsley
9 * Listview control implementation.
12 * 1. No horizontal scrolling when header is larger than the client area.
13 * 2. Drawing optimizations.
14 * 3. Hot item handling.
17 * LISTVIEW_Notify : most notifications from children (editbox and header)
20 * LISTVIEW_SetItemCount : not completed for non OWNERDATA
23 * LISTVIEW_SetItemW : no unicode support
24 * LISTVIEW_InsertItemW : no unicode support
25 * LISTVIEW_InsertColumnW : no unicode support
26 * LISTVIEW_GetColumnW : no unicode support
27 * LISTVIEW_SetColumnW : no unicode support
29 * Advanced functionality:
30 * LISTVIEW_GetNumberOfWorkAreas : not implemented
31 * LISTVIEW_GetHotCursor : not implemented
32 * LISTVIEW_GetISearchString : not implemented
33 * LISTVIEW_GetBkImage : not implemented
34 * LISTVIEW_SetBkImage : not implemented
35 * LISTVIEW_GetColumnOrderArray : simple hack only
36 * LISTVIEW_SetColumnOrderArray : simple hack only
37 * LISTVIEW_Arrange : empty stub
38 * LISTVIEW_ApproximateViewRect : incomplete
39 * LISTVIEW_Scroll : not implemented
40 * LISTVIEW_Update : not completed
50 #include "debugtools.h"
52 DEFAULT_DEBUG_CHANNEL(listview);
54 /* Some definitions for inline edit control */
55 typedef BOOL (*EditlblCallback)(HWND, LPSTR, DWORD);
57 typedef struct tagEDITLABEL_ITEM
61 EditlblCallback EditLblCb;
64 typedef struct tagLISTVIEW_SUBITEM
72 typedef struct tagLISTVIEW_ITEM
83 typedef struct tagLISTVIEW_SELECTION
89 typedef struct tagLISTVIEW_INFO
94 HIMAGELIST himlNormal;
100 HDPA hdpaSelectionRanges;
115 DWORD dwExStyle; /* extended listview style */
117 PFNLVCOMPARE pfnCompare;
121 EDITLABEL_ITEM *pedititem;
123 INT nColumnCount; /* the number of columns in this control */
125 WPARAM charCode; /* Added */
126 CHAR szSearchParam[ MAX_PATH ]; /* Added */
127 DWORD timeSinceLastKeyPress; /* Added */
128 INT nSearchParamLength; /* Added */
135 /* maximum size of a label */
136 #define DISP_TEXT_SIZE 512
138 /* padding for items in list and small icon display modes */
139 #define WIDTH_PADDING 12
141 /* padding for items in list, report and small icon display modes */
142 #define HEIGHT_PADDING 1
144 /* offset of items in report display mode */
145 #define REPORT_MARGINX 2
147 /* padding for icon in large icon display mode */
148 #define ICON_TOP_PADDING 2
149 #define ICON_BOTTOM_PADDING 2
151 /* padding for label in large icon display mode */
152 #define LABEL_VERT_OFFSET 2
154 /* default label width for items in list and small icon display modes */
155 #define DEFAULT_LABEL_WIDTH 40
157 /* default column width for items in list display mode */
158 #define DEFAULT_COLUMN_WIDTH 96
160 /* Increment size of the horizontal scroll bar */
161 #define LISTVIEW_SCROLL_DIV_SIZE 10
163 /* Padding betwen image and label */
164 #define IMAGE_PADDING 2
166 /* Padding behind the label */
167 #define TRAILING_PADDING 5
169 /* Border for the icon caption */
170 #define CAPTION_BORDER 2
174 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
175 #define ListView_LVNotify(hwnd,lCtrlId,plvnm) \
176 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMLISTVIEW)(plvnm))
177 #define ListView_Notify(hwnd,lCtrlId,pnmh) \
178 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMHDR)(pnmh))
179 /* retrieve the number of items in the listview */
180 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
182 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
183 INT width, INT height, HWND parent, HINSTANCE hinst,
184 EditlblCallback EditLblCb, DWORD param);
187 * forward declarations
189 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem, BOOL internal);
190 static INT LISTVIEW_HitTestItem(HWND, LPLVHITTESTINFO, BOOL);
191 static INT LISTVIEW_GetCountPerRow(HWND);
192 static INT LISTVIEW_GetCountPerColumn(HWND);
193 static VOID LISTVIEW_AlignLeft(HWND);
194 static VOID LISTVIEW_AlignTop(HWND);
195 static VOID LISTVIEW_AddGroupSelection(HWND, INT);
196 static VOID LISTVIEW_AddSelection(HWND, INT);
197 static BOOL LISTVIEW_AddSubItem(HWND, LPLVITEMA);
198 static INT LISTVIEW_FindInsertPosition(HDPA, INT);
199 static INT LISTVIEW_GetItemHeight(HWND);
200 static BOOL LISTVIEW_GetItemPosition(HWND, INT, LPPOINT);
201 static LRESULT LISTVIEW_GetItemRect(HWND, INT, LPRECT);
202 static INT LISTVIEW_GetItemWidth(HWND);
203 static INT LISTVIEW_GetLabelWidth(HWND, INT);
204 static LRESULT LISTVIEW_GetOrigin(HWND, LPPOINT);
205 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem);
206 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA, INT);
207 static LRESULT LISTVIEW_GetViewRect(HWND, LPRECT);
208 static BOOL LISTVIEW_InitItem(HWND, LISTVIEW_ITEM *, LPLVITEMA);
209 static BOOL LISTVIEW_InitSubItem(HWND, LISTVIEW_SUBITEM *, LPLVITEMA);
210 static LRESULT LISTVIEW_MouseSelection(HWND, POINT);
211 static BOOL LISTVIEW_RemoveColumn(HDPA, INT);
212 static BOOL LISTVIEW_RemoveSubItem(HDPA, INT);
213 static VOID LISTVIEW_SetGroupSelection(HWND, INT);
214 static BOOL LISTVIEW_SetItem(HWND, LPLVITEMA);
215 static BOOL LISTVIEW_SetItemFocus(HWND, INT);
216 static BOOL LISTVIEW_SetItemPosition(HWND, INT, LONG, LONG);
217 static VOID LISTVIEW_UpdateScroll(HWND);
218 static VOID LISTVIEW_SetSelection(HWND, INT);
219 static VOID LISTVIEW_UpdateSize(HWND);
220 static BOOL LISTVIEW_SetSubItem(HWND, LPLVITEMA);
221 static LRESULT LISTVIEW_SetViewRect(HWND, LPRECT);
222 static BOOL LISTVIEW_ToggleSelection(HWND, INT);
223 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle);
224 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem);
225 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem);
226 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam);
227 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam);
228 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText);
229 static INT LISTVIEW_ProcessLetterKeys( HWND hwnd, WPARAM charCode, LPARAM keyData );
230 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem);
231 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask);
232 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem);
233 static BOOL LISTVIEW_IsSelected(HWND hwnd, INT nItem);
234 static VOID LISTVIEW_RemoveSelectionRange(HWND hwnd, INT lItem, INT uItem);
235 static void LISTVIEW_FillBackground(HWND hwnd, HDC hdc, LPRECT rc);
237 /******** Defines that LISTVIEW_ProcessLetterKeys uses ****************/
238 #define KEY_DELAY 900
239 #define LISTVIEW_InitLvItemStruct(item,idx,TEXT) \
240 ZeroMemory(&(item), sizeof(LVITEMA)); \
241 (item).mask = LVIF_TEXT; \
242 (item).iItem = (idx); \
243 (item).iSubItem = 0; \
244 (item).pszText = (TEXT); \
245 (item).cchTextMax = MAX_PATH
248 LISTVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
251 LISTVIEW_INFO *infoPtr;
252 NMLVCUSTOMDRAW nmcdhdr;
255 TRACE("drawstage:%lx hdc:%x\n", dwDrawStage, hdc);
257 infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
259 nmcd= & nmcdhdr.nmcd;
260 nmcd->hdr.hwndFrom = hwnd;
261 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
262 nmcd->hdr.code = NM_CUSTOMDRAW;
263 nmcd->dwDrawStage= dwDrawStage;
265 nmcd->rc.left = rc.left;
266 nmcd->rc.right = rc.right;
267 nmcd->rc.bottom = rc.bottom;
268 nmcd->rc.top = rc.top;
269 nmcd->dwItemSpec = 0;
270 nmcd->uItemState = 0;
271 nmcd->lItemlParam= 0;
272 nmcdhdr.clrText = infoPtr->clrText;
273 nmcdhdr.clrTextBk= infoPtr->clrBk;
275 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
276 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
280 LISTVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
281 UINT iItem, UINT iSubItem,
284 LISTVIEW_INFO *infoPtr;
285 NMLVCUSTOMDRAW nmcdhdr;
287 DWORD dwDrawStage,dwItemSpec;
293 infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
295 ZeroMemory(&item,sizeof(LVITEMA));
297 item.mask = LVIF_PARAM;
298 ListView_GetItemA(hwnd,&item);
300 dwDrawStage=CDDS_ITEM | uItemDrawState;
304 if (LISTVIEW_IsSelected(hwnd,iItem)) uItemState|=CDIS_SELECTED;
305 if (iItem==infoPtr->nFocusedItem) uItemState|=CDIS_FOCUS;
306 if (iItem==infoPtr->nHotItem) uItemState|=CDIS_HOT;
308 itemRect.left = LVIR_BOUNDS;
309 LISTVIEW_GetItemRect(hwnd, iItem, &itemRect);
311 nmcd= & nmcdhdr.nmcd;
312 nmcd->hdr.hwndFrom = hwnd;
313 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
314 nmcd->hdr.code = NM_CUSTOMDRAW;
315 nmcd->dwDrawStage= dwDrawStage;
317 nmcd->rc.left = itemRect.left;
318 nmcd->rc.right = itemRect.right;
319 nmcd->rc.bottom = itemRect.bottom;
320 nmcd->rc.top = itemRect.top;
321 nmcd->dwItemSpec = dwItemSpec;
322 nmcd->uItemState = uItemState;
323 nmcd->lItemlParam= item.lParam;
324 nmcdhdr.clrText = infoPtr->clrText;
325 nmcdhdr.clrTextBk= infoPtr->clrBk;
326 nmcdhdr.iSubItem =iSubItem;
328 TRACE("drawstage:%lx hdc:%x item:%lx, itemstate:%x, lItemlParam:%lx\n",
329 nmcd->dwDrawStage, nmcd->hdc, nmcd->dwItemSpec,
330 nmcd->uItemState, nmcd->lItemlParam);
332 retval=SendMessageA (GetParent (hwnd), WM_NOTIFY,
333 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
335 infoPtr->clrText=nmcdhdr.clrText;
336 infoPtr->clrBk =nmcdhdr.clrTextBk;
337 return (BOOL) retval;
341 /*************************************************************************
343 * Processes keyboard messages generated by pressing the letter keys on the keyboard.
344 * Assumes the list is sorted alphabetically, without regard to case.
347 * [I] HWND: handle to the window
348 * [I] WPARAM: the character code, the actual character
349 * [I] LPARAM: key data
359 static INT LISTVIEW_ProcessLetterKeys( HWND hwnd, WPARAM charCode, LPARAM keyData )
361 LISTVIEW_INFO *infoPtr = NULL;
366 BOOL bFoundMatchingFiles = FALSE;
368 CHAR TEXT[ MAX_PATH ];
369 CHAR szCharCode[ 2 ];
370 DWORD timeSinceLastKeyPress = 0;
372 szCharCode[0] = charCode;
375 /* simple parameter checking */
376 if ( !hwnd || !charCode || !keyData )
379 infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
384 /* only allow the valid WM_CHARs through */
385 if ( isalnum( charCode ) || charCode == '.' || charCode == '`' || charCode == '!'
386 || charCode == '@' || charCode == '#' || charCode == '$' || charCode == '%'
387 || charCode == '^' || charCode == '&' || charCode == '*' || charCode == '('
388 || charCode == ')' || charCode == '-' || charCode == '_' || charCode == '+'
389 || charCode == '=' || charCode == '\\'|| charCode == ']' || charCode == '}'
390 || charCode == '[' || charCode == '{' || charCode == '/' || charCode == '?'
391 || charCode == '>' || charCode == '<' || charCode == ',' || charCode == '~')
393 timeSinceLastKeyPress = GetTickCount();
395 nSize = GETITEMCOUNT( infoPtr );
396 /* if there are 0 items, there is no where to go */
400 * If the last charCode equals the current charCode then look
401 * to the next element in list to see if it matches the previous
404 if ( infoPtr->charCode == charCode )
406 if ( timeSinceLastKeyPress - infoPtr->timeSinceLastKeyPress < KEY_DELAY )
407 { /* append new character to search string */
408 strcat( infoPtr->szSearchParam, szCharCode );
409 infoPtr->nSearchParamLength++;
411 /* loop from start of list view */
412 for( idx = infoPtr->nFocusedItem; idx < nSize; idx++ )
414 LISTVIEW_InitLvItemStruct( item, idx, TEXT );
415 ListView_GetItemA( hwnd, &item );
418 if ( strncasecmp( item.pszText, infoPtr->szSearchParam,
419 infoPtr->nSearchParamLength ) == 0 )
426 else if ( infoPtr->timeSinceLastKeyPress > timeSinceLastKeyPress )
427 { /* The DWORD went over it's boundery?? Ergo assuming too slow??. */
428 for ( idx = 0; idx < nSize; idx++ )
430 LISTVIEW_InitLvItemStruct( item, idx, TEXT );
431 ListView_GetItemA( hwnd, &item );
433 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
439 strcpy( infoPtr->szSearchParam, szCharCode );
440 infoPtr->nSearchParamLength = 1;
443 { /* Save szCharCode for use in later searches */
444 strcpy( infoPtr->szSearchParam, szCharCode );
445 infoPtr->nSearchParamLength = 1;
447 LISTVIEW_InitLvItemStruct( item, infoPtr->nFocusedItem + 1, TEXT );
448 ListView_GetItemA( hwnd, &item );
450 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
451 nItem = infoPtr->nFocusedItem + 1;
454 * Ok so there are no more folders that match
455 * now we look for files.
457 for ( idx = infoPtr->nFocusedItem + 1; idx < nSize; idx ++ )
459 LISTVIEW_InitLvItemStruct( item, idx, TEXT );
460 ListView_GetItemA( hwnd, &item );
462 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
465 bFoundMatchingFiles = TRUE;
469 if ( !bFoundMatchingFiles )
470 { /* go back to first instance */
471 for ( idx = 0; idx < nSize; idx ++ )
473 LISTVIEW_InitLvItemStruct( item,idx, TEXT );
474 ListView_GetItemA( hwnd, &item );
476 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
485 } /*END: if ( infoPtr->charCode == charCode )*/
487 else /* different keypressed */
489 /* could be that they are spelling the file/directory for us */
490 if ( timeSinceLastKeyPress - infoPtr->timeSinceLastKeyPress > KEY_DELAY )
492 * Too slow, move to the first instance of the
495 for ( idx = 0; idx < nSize; idx++ )
497 LISTVIEW_InitLvItemStruct( item,idx, TEXT );
498 ListView_GetItemA( hwnd, &item );
500 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
506 strcpy( infoPtr->szSearchParam, szCharCode );
507 infoPtr->nSearchParamLength = 1;
509 else if ( infoPtr->timeSinceLastKeyPress > timeSinceLastKeyPress )
510 { /* The DWORD went over it's boundery?? Ergo assuming too slow??. */
511 for ( idx = 0; idx < nSize; idx++ )
513 LISTVIEW_InitLvItemStruct( item,idx, TEXT );
514 ListView_GetItemA( hwnd, &item );
516 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
522 strcpy( infoPtr->szSearchParam, szCharCode );
523 infoPtr->nSearchParamLength = 1;
525 else /* Search for the string the user is typing */
527 /* append new character to search string */
528 strcat( infoPtr->szSearchParam, szCharCode );
529 infoPtr->nSearchParamLength++;
531 /* loop from start of list view */
532 for( idx = 0; idx < nSize; idx++ )
534 LISTVIEW_InitLvItemStruct( item, idx, TEXT );
535 ListView_GetItemA( hwnd, &item );
538 if ( strncasecmp( item.pszText, infoPtr->szSearchParam,
539 infoPtr->nSearchParamLength ) == 0 )
551 bRedraw = LISTVIEW_KeySelection(hwnd, nItem );
552 if (bRedraw != FALSE)
554 /* refresh client area */
555 InvalidateRect(hwnd, NULL, TRUE);
559 /* Store the WM_CHAR for next time */
560 infoPtr->charCode = charCode;
563 infoPtr->timeSinceLastKeyPress = timeSinceLastKeyPress;
569 /*************************************************************************
570 * LISTVIEW_UpdateHeaderSize [Internal]
572 * Function to resize the header control
575 * hwnd [I] handle to a window
576 * nNewScrollPos [I] Scroll Pos to Set
583 static VOID LISTVIEW_UpdateHeaderSize(HWND hwnd, INT nNewScrollPos)
585 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
589 GetWindowRect(infoPtr->hwndHeader, &winRect);
590 point[0].x = winRect.left;
591 point[0].y = winRect.top;
592 point[1].x = winRect.right;
593 point[1].y = winRect.bottom;
595 MapWindowPoints(HWND_DESKTOP, hwnd, point, 2);
596 point[0].x = -(nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
597 point[1].x += (nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
599 SetWindowPos(infoPtr->hwndHeader,0,
600 point[0].x,point[0].y,point[1].x,point[1].y,
601 SWP_NOZORDER | SWP_NOACTIVATE);
606 * Update the scrollbars. This functions should be called whenever
607 * the content, size or view changes.
610 * [I] HWND : window handle
615 static VOID LISTVIEW_UpdateScroll(HWND hwnd)
617 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
618 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
619 UINT uView = lStyle & LVS_TYPEMASK;
620 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
621 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
622 SCROLLINFO scrollInfo;
624 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
625 scrollInfo.cbSize = sizeof(SCROLLINFO);
627 if (uView == LVS_LIST)
629 /* update horizontal scrollbar */
631 INT nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
632 INT nCountPerRow = LISTVIEW_GetCountPerRow(hwnd);
633 INT nNumOfItems = GETITEMCOUNT(infoPtr);
635 scrollInfo.nMax = nNumOfItems / nCountPerColumn;
636 if((nNumOfItems % nCountPerColumn) == 0)
640 scrollInfo.nPos = ListView_GetTopIndex(hwnd) / nCountPerColumn;
641 scrollInfo.nPage = nCountPerRow;
642 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
643 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
644 ShowScrollBar(hwnd, SB_VERT, FALSE);
646 else if (uView == LVS_REPORT)
648 /* update vertical scrollbar */
650 scrollInfo.nMax = GETITEMCOUNT(infoPtr) - 1;
651 scrollInfo.nPos = ListView_GetTopIndex(hwnd);
652 scrollInfo.nPage = LISTVIEW_GetCountPerColumn(hwnd);
653 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
654 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
656 /* update horizontal scrollbar */
657 nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
658 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE
659 || GETITEMCOUNT(infoPtr) == 0)
664 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE ;
665 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
666 scrollInfo.nMax = max(infoPtr->nItemWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
667 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
669 /* Update the Header Control */
670 scrollInfo.fMask = SIF_POS;
671 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
672 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
679 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
681 INT nViewWidth = rcView.right - rcView.left;
682 INT nViewHeight = rcView.bottom - rcView.top;
684 /* Update Horizontal Scrollbar */
685 scrollInfo.fMask = SIF_POS;
686 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE
687 || GETITEMCOUNT(infoPtr) == 0)
691 scrollInfo.nMax = max(nViewWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
693 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
694 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
695 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
697 /* Update Vertical Scrollbar */
698 nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
699 scrollInfo.fMask = SIF_POS;
700 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) == FALSE
701 || GETITEMCOUNT(infoPtr) == 0)
705 scrollInfo.nMax = max(nViewHeight / LISTVIEW_SCROLL_DIV_SIZE,0)-1;
707 scrollInfo.nPage = nListHeight / LISTVIEW_SCROLL_DIV_SIZE;
708 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
709 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
716 * Prints a message for unsupported window styles.
717 * A kind of TODO list for window styles.
720 * [I] LONG : window style
725 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle)
727 if ((LVS_TYPEMASK & lStyle) == LVS_EDITLABELS)
729 FIXME(" LVS_EDITLABELS\n");
732 if ((LVS_TYPEMASK & lStyle) == LVS_NOLABELWRAP)
734 FIXME(" LVS_NOLABELWRAP\n");
737 if ((LVS_TYPEMASK & lStyle) == LVS_NOSCROLL)
739 FIXME(" LVS_NOSCROLL\n");
742 if ((LVS_TYPEMASK & lStyle) == LVS_NOSORTHEADER)
744 FIXME(" LVS_NOSORTHEADER\n");
747 if ((LVS_TYPEMASK & lStyle) == LVS_OWNERDRAWFIXED)
749 FIXME(" LVS_OWNERDRAWFIXED\n");
752 if ((LVS_TYPEMASK & lStyle) == LVS_SHAREIMAGELISTS)
754 FIXME(" LVS_SHAREIMAGELISTS\n");
757 if ((LVS_TYPEMASK & lStyle) == LVS_SORTASCENDING)
759 FIXME(" LVS_SORTASCENDING\n");
762 if ((LVS_TYPEMASK & lStyle) == LVS_SORTDESCENDING)
764 FIXME(" LVS_SORTDESCENDING\n");
770 * Aligns the items with the top edge of the window.
773 * [I] HWND : window handle
778 static VOID LISTVIEW_AlignTop(HWND hwnd)
780 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
781 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
782 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
787 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
789 ZeroMemory(&ptItem, sizeof(POINT));
790 ZeroMemory(&rcView, sizeof(RECT));
792 if (nListWidth > infoPtr->nItemWidth)
794 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
796 if (ptItem.x + infoPtr->nItemWidth > nListWidth)
799 ptItem.y += infoPtr->nItemHeight;
802 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
803 ptItem.x += infoPtr->nItemWidth;
804 rcView.right = max(rcView.right, ptItem.x);
807 rcView.bottom = ptItem.y + infoPtr->nItemHeight;
811 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
813 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
814 ptItem.y += infoPtr->nItemHeight;
817 rcView.right = infoPtr->nItemWidth;
818 rcView.bottom = ptItem.y;
821 LISTVIEW_SetViewRect(hwnd, &rcView);
827 * Aligns the items with the left edge of the window.
830 * [I] HWND : window handle
835 static VOID LISTVIEW_AlignLeft(HWND hwnd)
837 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
838 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
839 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
844 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
846 ZeroMemory(&ptItem, sizeof(POINT));
847 ZeroMemory(&rcView, sizeof(RECT));
849 if (nListHeight > infoPtr->nItemHeight)
851 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
853 if (ptItem.y + infoPtr->nItemHeight > nListHeight)
856 ptItem.x += infoPtr->nItemWidth;
859 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
860 ptItem.y += infoPtr->nItemHeight;
861 rcView.bottom = max(rcView.bottom, ptItem.y);
864 rcView.right = ptItem.x + infoPtr->nItemWidth;
868 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
870 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
871 ptItem.x += infoPtr->nItemWidth;
874 rcView.bottom = infoPtr->nItemHeight;
875 rcView.right = ptItem.x;
878 LISTVIEW_SetViewRect(hwnd, &rcView);
884 * Set the bounding rectangle of all the items.
887 * [I] HWND : window handle
888 * [I] LPRECT : bounding rectangle
894 static LRESULT LISTVIEW_SetViewRect(HWND hwnd, LPRECT lprcView)
896 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
897 BOOL bResult = FALSE;
899 TRACE("(hwnd=%x, left=%d, top=%d, right=%d, bottom=%d)\n", hwnd,
900 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
902 if (lprcView != NULL)
905 infoPtr->rcView.left = lprcView->left;
906 infoPtr->rcView.top = lprcView->top;
907 infoPtr->rcView.right = lprcView->right;
908 infoPtr->rcView.bottom = lprcView->bottom;
916 * Retrieves the bounding rectangle of all the items.
919 * [I] HWND : window handle
920 * [O] LPRECT : bounding rectangle
926 static LRESULT LISTVIEW_GetViewRect(HWND hwnd, LPRECT lprcView)
928 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
929 BOOL bResult = FALSE;
932 TRACE("(hwnd=%x, lprcView=%p)\n", hwnd, lprcView);
934 if (lprcView != NULL)
936 bResult = LISTVIEW_GetOrigin(hwnd, &ptOrigin);
937 if (bResult != FALSE)
939 lprcView->left = infoPtr->rcView.left + ptOrigin.x;
940 lprcView->top = infoPtr->rcView.top + ptOrigin.y;
941 lprcView->right = infoPtr->rcView.right + ptOrigin.x;
942 lprcView->bottom = infoPtr->rcView.bottom + ptOrigin.y;
945 TRACE("(left=%d, top=%d, right=%d, bottom=%d)\n",
946 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
954 * Retrieves the subitem pointer associated with the subitem index.
957 * [I] HDPA : DPA handle for a specific item
958 * [I] INT : index of subitem
961 * SUCCESS : subitem pointer
964 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems,
967 LISTVIEW_SUBITEM *lpSubItem;
970 for (i = 1; i < hdpaSubItems->nItemCount; i++)
972 lpSubItem = (LISTVIEW_SUBITEM *) DPA_GetPtr(hdpaSubItems, i);
973 if (lpSubItem != NULL)
975 if (lpSubItem->iSubItem == nSubItem)
987 * Calculates the width of an item.
990 * [I] HWND : window handle
991 * [I] LONG : window style
994 * Returns item width.
996 static INT LISTVIEW_GetItemWidth(HWND hwnd)
998 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
999 LONG style = GetWindowLongA(hwnd, GWL_STYLE);
1000 UINT uView = style & LVS_TYPEMASK;
1001 INT nHeaderItemCount;
1007 TRACE("(hwnd=%x)\n", hwnd);
1009 if (uView == LVS_ICON)
1011 nItemWidth = infoPtr->iconSpacing.cx;
1013 else if (uView == LVS_REPORT)
1015 /* calculate width of header */
1016 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
1017 for (i = 0; i < nHeaderItemCount; i++)
1019 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
1021 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
1027 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
1029 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, i);
1030 nItemWidth = max(nItemWidth, nLabelWidth);
1033 /* default label size */
1034 if (GETITEMCOUNT(infoPtr) == 0)
1036 nItemWidth = DEFAULT_COLUMN_WIDTH;
1040 if (nItemWidth == 0)
1042 nItemWidth = DEFAULT_LABEL_WIDTH;
1047 nItemWidth += WIDTH_PADDING;
1049 if (infoPtr->himlSmall != NULL)
1051 nItemWidth += infoPtr->iconSize.cx;
1054 if (infoPtr->himlState != NULL)
1056 nItemWidth += infoPtr->iconSize.cx;
1063 /* nItemWidth Cannot be Zero */
1071 * Calculates the width of a specific item.
1074 * [I] HWND : window handle
1075 * [I] LPSTR : string
1078 * Returns the width of an item width a specified string.
1080 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem)
1082 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1083 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
1084 INT nHeaderItemCount;
1089 TRACE("(hwnd=%x)\n", hwnd);
1091 if (uView == LVS_ICON)
1093 nItemWidth = infoPtr->iconSpacing.cx;
1095 else if (uView == LVS_REPORT)
1097 /* calculate width of header */
1098 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
1099 for (i = 0; i < nHeaderItemCount; i++)
1101 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
1103 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
1109 /* get width of string */
1110 nItemWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
1112 /* default label size */
1113 if (GETITEMCOUNT(infoPtr) == 0)
1115 nItemWidth = DEFAULT_COLUMN_WIDTH;
1119 if (nItemWidth == 0)
1121 nItemWidth = DEFAULT_LABEL_WIDTH;
1126 nItemWidth += WIDTH_PADDING;
1128 if (infoPtr->himlSmall != NULL)
1130 nItemWidth += infoPtr->iconSize.cx;
1133 if (infoPtr->himlState != NULL)
1135 nItemWidth += infoPtr->iconSize.cx;
1146 * Calculates the height of an item.
1149 * [I] HWND : window handle
1150 * [I] LONG : window style
1153 * Returns item height.
1155 static INT LISTVIEW_GetItemHeight(HWND hwnd)
1157 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1158 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
1159 INT nItemHeight = 0;
1161 if (uView == LVS_ICON)
1163 nItemHeight = infoPtr->iconSpacing.cy;
1168 HDC hdc = GetDC(hwnd);
1169 HFONT hOldFont = SelectObject(hdc, infoPtr->hFont);
1170 GetTextMetricsA(hdc, &tm);
1172 if(infoPtr->himlState || infoPtr->himlSmall)
1173 nItemHeight = max(tm.tmHeight, infoPtr->iconSize.cy) + HEIGHT_PADDING;
1175 nItemHeight = tm.tmHeight;
1177 SelectObject(hdc, hOldFont);
1178 ReleaseDC(hwnd, hdc);
1185 static void LISTVIEW_PrintSelectionRanges(HWND hwnd)
1187 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1188 LISTVIEW_SELECTION *selection;
1189 INT topSelection = infoPtr->hdpaSelectionRanges->nItemCount;
1192 TRACE("Selections are:\n");
1193 for (i = 0; i < topSelection; i++)
1195 selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,i);
1196 TRACE(" %lu - %lu\n",selection->lower,selection->upper);
1202 * A compare function for selection ranges
1205 * [I] LPVOID : Item 1;
1206 * [I] LPVOID : Item 2;
1207 * [I] LPARAM : flags
1210 * >0 : if Item 1 > Item 2
1211 * <0 : if Item 2 > Item 1
1212 * 0 : if Item 1 == Item 2
1214 static INT CALLBACK LISTVIEW_CompareSelectionRanges(LPVOID range1, LPVOID range2,
1217 int l1 = ((LISTVIEW_SELECTION*)(range1))->lower;
1218 int l2 = ((LISTVIEW_SELECTION*)(range2))->lower;
1219 int u1 = ((LISTVIEW_SELECTION*)(range1))->upper;
1220 int u2 = ((LISTVIEW_SELECTION*)(range2))->upper;
1234 * Adds a selection range.
1237 * [I] HWND : window handle
1238 * [I] INT : lower item index
1239 * [I] INT : upper item index
1244 static VOID LISTVIEW_AddSelectionRange(HWND hwnd, INT lItem, INT uItem)
1246 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1247 LISTVIEW_SELECTION *selection;
1248 INT topSelection = infoPtr->hdpaSelectionRanges->nItemCount;
1249 BOOL lowerzero=FALSE;
1251 selection = (LISTVIEW_SELECTION *)COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION));
1252 selection->lower = lItem;
1253 selection->upper = uItem;
1255 TRACE("Add range %i - %i\n",lItem,uItem);
1258 LISTVIEW_SELECTION *checkselection,*checkselection2;
1259 INT index,mergeindex;
1261 /* find overlapping selections */
1262 /* we want to catch adjacent ranges so expand our range by 1 */
1265 if (selection->lower == 0)
1270 index = DPA_Search(infoPtr->hdpaSelectionRanges, selection, 0,
1271 LISTVIEW_CompareSelectionRanges,
1273 selection->upper --;
1277 selection->lower ++;
1281 checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,index);
1282 TRACE("Merge with index %i (%lu - %lu)\n",index,checkselection->lower,
1283 checkselection->upper);
1285 checkselection->lower = min(selection->lower,checkselection->lower);
1286 checkselection->upper = max(selection->upper,checkselection->upper);
1288 TRACE("New range (%lu - %lu)\n", checkselection->lower,
1289 checkselection->upper);
1291 COMCTL32_Free(selection);
1293 /* merge now common selection ranges in the lower group*/
1296 checkselection->upper ++;
1297 if (checkselection->lower == 0)
1300 checkselection->lower --;
1302 TRACE("search lower range (%lu - %lu)\n", checkselection->lower,
1303 checkselection->upper);
1305 /* not sorted yet */
1306 mergeindex = DPA_Search(infoPtr->hdpaSelectionRanges, checkselection, 0,
1307 LISTVIEW_CompareSelectionRanges, 0,
1310 checkselection->upper --;
1314 checkselection->lower ++;
1316 if (mergeindex >=0 && mergeindex != index)
1318 TRACE("Merge with index %i\n",mergeindex);
1319 checkselection2 = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
1321 checkselection->lower = min(checkselection->lower,
1322 checkselection2->lower);
1323 checkselection->upper = max(checkselection->upper,
1324 checkselection2->upper);
1325 COMCTL32_Free(checkselection2);
1326 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,mergeindex);
1330 while (mergeindex > -1 && mergeindex <index);
1332 /* merge now common selection ranges in the upper group*/
1335 checkselection->upper ++;
1336 if (checkselection->lower == 0)
1339 checkselection->lower --;
1341 TRACE("search upper range %i (%lu - %lu)\n",index,
1342 checkselection->lower, checkselection->upper);
1344 /* not sorted yet */
1345 mergeindex = DPA_Search(infoPtr->hdpaSelectionRanges, checkselection,
1347 LISTVIEW_CompareSelectionRanges, 0,
1350 checkselection->upper --;
1354 checkselection->lower ++;
1356 if (mergeindex >=0 && mergeindex !=index)
1358 TRACE("Merge with index %i\n",mergeindex);
1359 checkselection2 = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
1361 checkselection->lower = min(checkselection->lower,
1362 checkselection2->lower);
1363 checkselection->upper = max(checkselection->upper,
1364 checkselection2->upper);
1365 COMCTL32_Free(checkselection2);
1366 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,mergeindex);
1369 while (mergeindex > -1);
1374 index = DPA_Search(infoPtr->hdpaSelectionRanges, selection, 0,
1375 LISTVIEW_CompareSelectionRanges, 0,
1378 TRACE("Insert before index %i\n",index);
1381 DPA_InsertPtr(infoPtr->hdpaSelectionRanges,index,selection);
1386 DPA_InsertPtr(infoPtr->hdpaSelectionRanges,0,selection);
1391 DPA_Sort(infoPtr->hdpaSelectionRanges,LISTVIEW_CompareSelectionRanges,0);
1392 LISTVIEW_PrintSelectionRanges(hwnd);
1397 * check if a specified index is selected.
1400 * [I] HWND : window handle
1401 * [I] INT : item index
1406 static BOOL LISTVIEW_IsSelected(HWND hwnd, INT nItem)
1408 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1409 LISTVIEW_SELECTION selection;
1412 selection.upper = nItem;
1413 selection.lower = nItem;
1415 index = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, 0,
1416 LISTVIEW_CompareSelectionRanges,
1426 * Removes all selection ranges
1429 * HWND: window handle
1435 static LRESULT LISTVIEW_RemoveAllSelections(HWND hwnd)
1437 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1438 LISTVIEW_SELECTION *selection;
1442 TRACE("(0x%x)\n",hwnd);
1444 ZeroMemory(&item,sizeof(LVITEMA));
1445 item.stateMask = LVIS_SELECTED;
1449 selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,0);
1452 TRACE("Removing %lu to %lu\n",selection->lower, selection->upper);
1453 for (i = selection->lower; i<=selection->upper; i++)
1454 LISTVIEW_SetItemState(hwnd,i,&item);
1455 LISTVIEW_RemoveSelectionRange(hwnd,selection->lower,selection->upper);
1458 while (infoPtr->hdpaSelectionRanges->nItemCount>0);
1466 * Removes a range selections.
1469 * [I] HWND : window handle
1470 * [I] INT : lower item index
1471 * [I] INT : upper item index
1476 static VOID LISTVIEW_RemoveSelectionRange(HWND hwnd, INT lItem, INT uItem)
1478 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1479 LISTVIEW_SELECTION removeselection,*checkselection;
1482 removeselection.lower = lItem;
1483 removeselection.upper = uItem;
1485 TRACE("Remove range %lu - %lu\n",removeselection.lower,removeselection.upper);
1486 LISTVIEW_PrintSelectionRanges(hwnd);
1488 index = DPA_Search(infoPtr->hdpaSelectionRanges, &removeselection, 0,
1489 LISTVIEW_CompareSelectionRanges,
1496 checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
1499 TRACE("Matches range index %i (%lu-%lu)\n",index,checkselection->lower,
1500 checkselection->upper);
1503 if ((checkselection->upper == removeselection.upper) &&
1504 (checkselection->lower == removeselection.lower))
1506 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,index);
1509 /* case 2: engulf */
1510 else if (((checkselection->upper < removeselection.upper) &&
1511 (checkselection->lower > removeselection.lower))||
1512 ((checkselection->upper <= removeselection.upper) &&
1513 (checkselection->lower > removeselection.lower)) ||
1514 ((checkselection->upper < removeselection.upper) &&
1515 (checkselection->lower >= removeselection.lower)))
1518 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,index);
1519 /* do it again because others may also get caught */
1521 LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
1523 /* case 3: overlap upper */
1524 else if ((checkselection->upper < removeselection.upper) &&
1525 (checkselection->lower < removeselection.lower))
1527 checkselection->upper = removeselection.lower - 1;
1529 LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
1531 /* case 4: overlap lower */
1532 else if ((checkselection->upper > removeselection.upper) &&
1533 (checkselection->lower > removeselection.lower))
1535 checkselection->lower = removeselection.upper + 1;
1537 LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
1539 /* case 5: fully internal */
1540 else if (checkselection->upper == removeselection.upper)
1541 checkselection->upper = removeselection.lower - 1;
1542 else if (checkselection->lower == removeselection.lower)
1543 checkselection->lower = removeselection.upper + 1;
1546 /* bisect the range */
1547 LISTVIEW_SELECTION *newselection;
1549 newselection = (LISTVIEW_SELECTION *)
1550 COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION));
1551 newselection -> lower = checkselection->lower;
1552 newselection -> upper = removeselection.lower - 1;
1553 checkselection -> lower = removeselection.upper + 1;
1554 DPA_InsertPtr(infoPtr->hdpaSelectionRanges,index,newselection);
1556 DPA_Sort(infoPtr->hdpaSelectionRanges,LISTVIEW_CompareSelectionRanges,0);
1558 LISTVIEW_PrintSelectionRanges(hwnd);
1563 * shifts all selection indexs starting with the indesx specified
1564 * in the direction specified.
1567 * [I] HWND : window handle
1568 * [I] INT : item index
1569 * [I] INT : amount and direction of shift
1574 static VOID LISTVIEW_ShiftSelections(HWND hwnd, INT nItem, INT direction)
1576 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1577 LISTVIEW_SELECTION selection,*checkselection;
1580 TRACE("Shifting %iu, %i steps\n",nItem,direction);
1582 selection.upper = nItem;
1583 selection.lower = nItem;
1585 index = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, 0,
1586 LISTVIEW_CompareSelectionRanges,
1587 0,DPAS_SORTED|DPAS_INSERTAFTER);
1589 while ((index < infoPtr->hdpaSelectionRanges->nItemCount)&&(index != -1))
1591 checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,index);
1592 if ((checkselection->lower >= nItem)&&
1593 (checkselection->lower + direction >= 0))
1594 checkselection->lower += direction;
1595 if ((checkselection->upper >= nItem)&&
1596 (checkselection->upper + direction >=0))
1597 checkselection->upper += direction;
1605 * Adds a block of selections.
1608 * [I] HWND : window handle
1609 * [I] INT : item index
1614 static VOID LISTVIEW_AddGroupSelection(HWND hwnd, INT nItem)
1616 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1617 INT nFirst = min(infoPtr->nSelectionMark, nItem);
1618 INT nLast = max(infoPtr->nSelectionMark, nItem);
1622 ZeroMemory(&item,sizeof(LVITEMA));
1623 item.stateMask = LVIS_SELECTED;
1624 item.state = LVIS_SELECTED;
1626 for (i = nFirst; i <= nLast; i++);
1628 LISTVIEW_SetItemState(hwnd,i,&item);
1631 LISTVIEW_SetItemFocus(hwnd, nItem);
1632 infoPtr->nSelectionMark = nItem;
1638 * Adds a single selection.
1641 * [I] HWND : window handle
1642 * [I] INT : item index
1647 static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem)
1649 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1652 ZeroMemory(&item,sizeof(LVITEMA));
1653 item.state = LVIS_SELECTED;
1654 item.stateMask = LVIS_SELECTED;
1656 LISTVIEW_SetItemState(hwnd,nItem,&item);
1658 LISTVIEW_SetItemFocus(hwnd, nItem);
1659 infoPtr->nSelectionMark = nItem;
1664 * Selects or unselects an item.
1667 * [I] HWND : window handle
1668 * [I] INT : item index
1674 static BOOL LISTVIEW_ToggleSelection(HWND hwnd, INT nItem)
1676 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1680 ZeroMemory(&item,sizeof(LVITEMA));
1681 item.stateMask = LVIS_SELECTED;
1683 if (LISTVIEW_IsSelected(hwnd,nItem))
1686 LISTVIEW_SetItemState(hwnd,nItem,&item);
1691 item.state = LVIS_SELECTED;
1692 LISTVIEW_SetItemState(hwnd,nItem,&item);
1696 LISTVIEW_SetItemFocus(hwnd, nItem);
1697 infoPtr->nSelectionMark = nItem;
1704 * Selects items based on view coordinates.
1707 * [I] HWND : window handle
1708 * [I] RECT : selection rectangle
1713 static VOID LISTVIEW_SetSelectionRect(HWND hwnd, RECT rcSelRect)
1715 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1720 ZeroMemory(&item,sizeof(LVITEMA));
1721 item.stateMask = LVIS_SELECTED;
1723 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
1725 LISTVIEW_GetItemPosition(hwnd, i, &ptItem);
1727 if (PtInRect(&rcSelRect, ptItem) != FALSE)
1729 item.state = LVIS_SELECTED;
1730 LISTVIEW_SetItemState(hwnd,i,&item);
1735 LISTVIEW_SetItemState(hwnd,i,&item);
1742 * Sets a single group selection.
1745 * [I] HWND : window handle
1746 * [I] INT : item index
1751 static VOID LISTVIEW_SetGroupSelection(HWND hwnd, INT nItem)
1753 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1754 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
1757 ZeroMemory(&item,sizeof(LVITEMA));
1758 item.stateMask = LVIS_SELECTED;
1760 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
1763 INT nFirst = min(infoPtr->nSelectionMark, nItem);
1764 INT nLast = max(infoPtr->nSelectionMark, nItem);
1766 for (i = 0; i <= GETITEMCOUNT(infoPtr); i++)
1768 if ((i < nFirst) || (i > nLast))
1771 LISTVIEW_SetItemState(hwnd,i,&item);
1775 item.state = LVIS_SELECTED;
1776 LISTVIEW_SetItemState(hwnd,i,&item);
1785 LISTVIEW_GetItemPosition(hwnd, nItem, &ptItem);
1786 LISTVIEW_GetItemPosition(hwnd, infoPtr->nSelectionMark, &ptSelMark);
1787 rcSel.left = min(ptSelMark.x, ptItem.x);
1788 rcSel.top = min(ptSelMark.y, ptItem.y);
1789 rcSel.right = max(ptSelMark.x, ptItem.x) + infoPtr->nItemWidth;
1790 rcSel.bottom = max(ptSelMark.y, ptItem.y) + infoPtr->nItemHeight;
1791 LISTVIEW_SetSelectionRect(hwnd, rcSel);
1794 LISTVIEW_SetItemFocus(hwnd, nItem);
1799 * Manages the item focus.
1802 * [I] HWND : window handle
1803 * [I] INT : item index
1806 * TRUE : focused item changed
1807 * FALSE : focused item has NOT changed
1809 static BOOL LISTVIEW_SetItemFocus(HWND hwnd, INT nItem)
1811 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1812 BOOL bResult = FALSE;
1815 if (infoPtr->nFocusedItem != nItem)
1817 if (infoPtr->nFocusedItem >= 0)
1819 INT oldFocus = infoPtr->nFocusedItem;
1821 infoPtr->nFocusedItem = -1;
1822 ZeroMemory(&lvItem, sizeof(LVITEMA));
1823 lvItem.stateMask = LVIS_FOCUSED;
1824 ListView_SetItemState(hwnd, oldFocus, &lvItem);
1828 lvItem.state = LVIS_FOCUSED;
1829 lvItem.stateMask = LVIS_FOCUSED;
1830 ListView_SetItemState(hwnd, nItem, &lvItem);
1832 infoPtr->nFocusedItem = nItem;
1833 ListView_EnsureVisible(hwnd, nItem, FALSE);
1841 * Sets a single selection.
1844 * [I] HWND : window handle
1845 * [I] INT : item index
1850 static VOID LISTVIEW_SetSelection(HWND hwnd, INT nItem)
1852 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1855 ZeroMemory(&lvItem, sizeof(LVITEMA));
1856 lvItem.stateMask = LVIS_FOCUSED;
1857 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
1859 LISTVIEW_RemoveAllSelections(hwnd);
1861 lvItem.state = LVIS_FOCUSED|LVIS_SELECTED;
1862 lvItem.stateMask = LVIS_FOCUSED|LVIS_SELECTED;
1863 ListView_SetItemState(hwnd, nItem, &lvItem);
1865 infoPtr->nFocusedItem = nItem;
1866 infoPtr->nSelectionMark = nItem;
1871 * Set selection(s) with keyboard.
1874 * [I] HWND : window handle
1875 * [I] INT : item index
1878 * SUCCESS : TRUE (needs to be repainted)
1879 * FAILURE : FALSE (nothing has changed)
1881 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem)
1883 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1884 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1885 WORD wShift = HIWORD(GetKeyState(VK_SHIFT));
1886 WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL));
1887 BOOL bResult = FALSE;
1889 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
1891 if (lStyle & LVS_SINGLESEL)
1894 LISTVIEW_SetSelection(hwnd, nItem);
1895 ListView_EnsureVisible(hwnd, nItem, FALSE);
1902 LISTVIEW_SetGroupSelection(hwnd, nItem);
1906 bResult = LISTVIEW_SetItemFocus(hwnd, nItem);
1911 LISTVIEW_SetSelection(hwnd, nItem);
1912 ListView_EnsureVisible(hwnd, nItem, FALSE);
1922 * Called when the mouse is being actively tracked and has hovered for a specified
1926 * [I] HWND : window handle
1927 * [I] wParam : key indicator
1928 * [I] lParam : mouse position
1931 * 0 if the message was processed, non-zero if there was an error
1934 * LVS_EX_TRACKSELECT: An item is automatically selected when the cursor remains
1935 * over the item for a certain period of time.
1938 static LRESULT LISTVIEW_MouseHover(HWND hwnd, WPARAM wParam, LPARAM lParam)
1940 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1943 pt.x = (INT)LOWORD(lParam);
1944 pt.y = (INT)HIWORD(lParam);
1946 if(infoPtr->dwExStyle & LVS_EX_TRACKSELECT) {
1947 /* select the item under the cursor */
1948 LISTVIEW_MouseSelection(hwnd, pt);
1956 * Called whenever WM_MOUSEMOVE is recieved.
1959 * [I] HWND : window handle
1960 * [I] wParam : key indicators
1961 * [I] lParam : cursor position
1964 * 0 if the message is processed, non-zero if there was an error
1966 static LRESULT LISTVIEW_MouseMove(HWND hwnd, WPARAM wParam, LPARAM lParam)
1968 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1969 TRACKMOUSEEVENT trackinfo;
1971 /* see if we are supposed to be tracking mouse hovering */
1972 if(infoPtr->dwExStyle & LVS_EX_TRACKSELECT) {
1973 /* fill in the trackinfo struct */
1974 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
1975 trackinfo.dwFlags = TME_QUERY;
1976 trackinfo.hwndTrack = hwnd;
1977 trackinfo.dwHoverTime = infoPtr->dwHoverTime;
1979 /* see if we are already tracking this hwnd */
1980 _TrackMouseEvent(&trackinfo);
1982 if(!(trackinfo.dwFlags & TME_HOVER)) {
1983 trackinfo.dwFlags = TME_HOVER;
1985 /* call TRACKMOUSEEVENT so we recieve WM_MOUSEHOVER messages */
1986 _TrackMouseEvent(&trackinfo);
1995 * Selects an item based on coordinates.
1998 * [I] HWND : window handle
1999 * [I] POINT : mouse click ccordinates
2002 * SUCCESS : item index
2005 static LRESULT LISTVIEW_MouseSelection(HWND hwnd, POINT pt)
2007 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2009 INT i,topindex,bottomindex;
2010 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2011 UINT uView = lStyle & LVS_TYPEMASK;
2013 topindex = ListView_GetTopIndex(hwnd);
2014 if (uView == LVS_REPORT)
2016 bottomindex = topindex + LISTVIEW_GetCountPerColumn(hwnd) + 1;
2017 bottomindex = min(bottomindex,GETITEMCOUNT(infoPtr));
2021 bottomindex = GETITEMCOUNT(infoPtr);
2024 for (i = topindex; i < bottomindex; i++)
2026 rcItem.left = LVIR_SELECTBOUNDS;
2027 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) == TRUE)
2029 if (PtInRect(&rcItem, pt) != FALSE)
2044 * [IO] HDPA : dynamic pointer array handle
2045 * [I] INT : column index (subitem index)
2051 static BOOL LISTVIEW_RemoveColumn(HDPA hdpaItems, INT nSubItem)
2053 BOOL bResult = TRUE;
2057 for (i = 0; i < hdpaItems->nItemCount; i++)
2059 hdpaSubItems = (HDPA)DPA_GetPtr(hdpaItems, i);
2060 if (hdpaSubItems != NULL)
2062 if (LISTVIEW_RemoveSubItem(hdpaSubItems, nSubItem) == FALSE)
2074 * Removes a subitem at a given position.
2077 * [IO] HDPA : dynamic pointer array handle
2078 * [I] INT : subitem index
2084 static BOOL LISTVIEW_RemoveSubItem(HDPA hdpaSubItems, INT nSubItem)
2086 LISTVIEW_SUBITEM *lpSubItem;
2089 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2091 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2092 if (lpSubItem != NULL)
2094 if (lpSubItem->iSubItem == nSubItem)
2097 if ((lpSubItem->pszText != NULL) &&
2098 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2100 COMCTL32_Free(lpSubItem->pszText);
2104 COMCTL32_Free(lpSubItem);
2106 /* free dpa memory */
2107 if (DPA_DeletePtr(hdpaSubItems, i) == NULL)
2112 else if (lpSubItem->iSubItem > nSubItem)
2124 * Compares the item information.
2127 * [I] LISTVIEW_ITEM *: destination item
2128 * [I] LPLVITEM : source item
2131 * SUCCCESS : TRUE (EQUAL)
2132 * FAILURE : FALSE (NOT EQUAL)
2134 static UINT LISTVIEW_GetItemChanges(LISTVIEW_ITEM *lpItem, LPLVITEMA lpLVItem)
2138 if ((lpItem != NULL) && (lpLVItem != NULL))
2140 if (lpLVItem->mask & LVIF_STATE)
2142 if ((lpItem->state & lpLVItem->stateMask) !=
2143 (lpLVItem->state & lpLVItem->stateMask))
2145 uChanged |= LVIF_STATE;
2149 if (lpLVItem->mask & LVIF_IMAGE)
2151 if (lpItem->iImage != lpLVItem->iImage)
2153 uChanged |= LVIF_IMAGE;
2157 if (lpLVItem->mask & LVIF_PARAM)
2159 if (lpItem->lParam != lpLVItem->lParam)
2161 uChanged |= LVIF_PARAM;
2165 if (lpLVItem->mask & LVIF_INDENT)
2167 if (lpItem->iIndent != lpLVItem->iIndent)
2169 uChanged |= LVIF_INDENT;
2173 if (lpLVItem->mask & LVIF_TEXT)
2175 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
2177 if (lpItem->pszText != LPSTR_TEXTCALLBACKA)
2179 uChanged |= LVIF_TEXT;
2184 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
2186 uChanged |= LVIF_TEXT;
2190 if (lpLVItem->pszText)
2192 if (lpItem->pszText)
2194 if (strcmp(lpLVItem->pszText, lpItem->pszText) != 0)
2196 uChanged |= LVIF_TEXT;
2201 uChanged |= LVIF_TEXT;
2206 if (lpItem->pszText)
2208 uChanged |= LVIF_TEXT;
2220 * Initializes item attributes.
2223 * [I] HWND : window handle
2224 * [O] LISTVIEW_ITEM *: destination item
2225 * [I] LPLVITEM : source item
2231 static BOOL LISTVIEW_InitItem(HWND hwnd, LISTVIEW_ITEM *lpItem,
2234 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2235 BOOL bResult = FALSE;
2237 if ((lpItem != NULL) && (lpLVItem != NULL))
2241 if (lpLVItem->mask & LVIF_STATE)
2243 lpItem->state &= ~lpLVItem->stateMask;
2244 lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
2247 if (lpLVItem->mask & LVIF_IMAGE)
2249 lpItem->iImage = lpLVItem->iImage;
2252 if (lpLVItem->mask & LVIF_PARAM)
2254 lpItem->lParam = lpLVItem->lParam;
2257 if (lpLVItem->mask & LVIF_INDENT)
2259 lpItem->iIndent = lpLVItem->iIndent;
2262 if (lpLVItem->mask & LVIF_TEXT)
2264 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
2266 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
2271 if ((lpItem->pszText != NULL) &&
2272 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2274 COMCTL32_Free(lpItem->pszText);
2277 lpItem->pszText = LPSTR_TEXTCALLBACKA;
2281 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
2283 lpItem->pszText = NULL;
2286 bResult = Str_SetPtrA(&lpItem->pszText, lpLVItem->pszText);
2296 * Initializes subitem attributes.
2298 * NOTE: The documentation specifies that the operation fails if the user
2299 * tries to set the indent of a subitem.
2302 * [I] HWND : window handle
2303 * [O] LISTVIEW_SUBITEM *: destination subitem
2304 * [I] LPLVITEM : source subitem
2310 static BOOL LISTVIEW_InitSubItem(HWND hwnd, LISTVIEW_SUBITEM *lpSubItem,
2313 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2314 BOOL bResult = FALSE;
2316 if ((lpSubItem != NULL) && (lpLVItem != NULL))
2318 if (!(lpLVItem->mask & LVIF_INDENT))
2322 lpSubItem->iSubItem = lpLVItem->iSubItem;
2324 if (lpLVItem->mask & LVIF_IMAGE)
2326 lpSubItem->iImage = lpLVItem->iImage;
2329 if (lpLVItem->mask & LVIF_TEXT)
2331 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
2333 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
2338 if ((lpSubItem->pszText != NULL) &&
2339 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2341 COMCTL32_Free(lpSubItem->pszText);
2344 lpSubItem->pszText = LPSTR_TEXTCALLBACKA;
2348 if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
2350 lpSubItem->pszText = NULL;
2353 bResult = Str_SetPtrA(&lpSubItem->pszText, lpLVItem->pszText);
2364 * Adds a subitem at a given position (column index).
2367 * [I] HWND : window handle
2368 * [I] LPLVITEM : new subitem atttributes
2374 static BOOL LISTVIEW_AddSubItem(HWND hwnd, LPLVITEMA lpLVItem)
2376 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2377 LISTVIEW_SUBITEM *lpSubItem = NULL;
2378 BOOL bResult = FALSE;
2380 INT nPosition, nItem;
2381 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2383 if (lStyle & LVS_OWNERDATA)
2386 if (lpLVItem != NULL)
2388 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
2389 if (hdpaSubItems != NULL)
2391 lpSubItem = (LISTVIEW_SUBITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM));
2392 if (lpSubItem != NULL)
2394 ZeroMemory(lpSubItem, sizeof(LISTVIEW_SUBITEM));
2395 if (LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem) != FALSE)
2397 nPosition = LISTVIEW_FindInsertPosition(hdpaSubItems,
2398 lpSubItem->iSubItem);
2399 nItem = DPA_InsertPtr(hdpaSubItems, nPosition, lpSubItem);
2409 /* cleanup if unsuccessful */
2410 if ((bResult == FALSE) && (lpSubItem != NULL))
2412 COMCTL32_Free(lpSubItem);
2420 * Finds the dpa insert position (array index).
2423 * [I] HWND : window handle
2424 * [I] INT : subitem index
2430 static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem)
2432 LISTVIEW_SUBITEM *lpSubItem;
2435 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2437 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2438 if (lpSubItem != NULL)
2440 if (lpSubItem->iSubItem > nSubItem)
2447 return hdpaSubItems->nItemCount;
2452 * Retrieves a listview subitem at a given position (column index).
2455 * [I] HWND : window handle
2456 * [I] INT : subitem index
2462 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem)
2464 LISTVIEW_SUBITEM *lpSubItem;
2467 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2469 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2470 if (lpSubItem != NULL)
2472 if (lpSubItem->iSubItem == nSubItem)
2476 else if (lpSubItem->iSubItem > nSubItem)
2488 * Sets item attributes.
2491 * [I] HWND : window handle
2492 * [I] LPLVITEM : new item atttributes
2498 static BOOL LISTVIEW_SetItem(HWND hwnd, LPLVITEMA lpLVItem)
2500 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2501 BOOL bResult = FALSE;
2503 LISTVIEW_ITEM *lpItem;
2505 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2506 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2508 UINT uView = lStyle & LVS_TYPEMASK;
2512 if (lStyle & LVS_OWNERDATA)
2514 if ((lpLVItem->iSubItem == 0)&&(lpLVItem->mask == LVIF_STATE))
2518 ZeroMemory(&itm,sizeof(LVITEMA));
2519 itm.mask = LVIF_STATE | LVIF_PARAM;
2520 itm.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
2521 itm.iItem = lpLVItem->iItem;
2523 ListView_GetItemA(hwnd,&itm);
2526 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2527 nmlv.hdr.hwndFrom = hwnd;
2528 nmlv.hdr.idFrom = lCtrlId;
2529 nmlv.hdr.code = LVN_ITEMCHANGING;
2530 nmlv.uNewState = lpLVItem->state;
2531 nmlv.uOldState = itm.state;
2532 nmlv.uChanged = LVIF_STATE;
2533 nmlv.lParam = itm.lParam;
2534 nmlv.iItem = lpLVItem->iItem;
2536 if ((itm.state & lpLVItem->stateMask) !=
2537 (lpLVItem->state & lpLVItem->stateMask))
2539 /* send LVN_ITEMCHANGING notification */
2540 if (!ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv))
2542 if (lpLVItem->stateMask & LVIS_FOCUSED)
2544 if (lpLVItem->state & LVIS_FOCUSED)
2545 infoPtr->nFocusedItem = lpLVItem->iItem;
2546 else if (infoPtr->nFocusedItem == lpLVItem->iItem)
2547 infoPtr->nFocusedItem = -1;
2549 if (lpLVItem->stateMask & LVIS_SELECTED)
2551 if (lpLVItem->state & LVIS_SELECTED)
2553 if (lStyle & LVS_SINGLESEL)
2555 LISTVIEW_RemoveAllSelections(hwnd);
2557 LISTVIEW_AddSelectionRange(hwnd,lpLVItem->iItem,lpLVItem->iItem);
2560 LISTVIEW_RemoveSelectionRange(hwnd,lpLVItem->iItem,
2564 nmlv.hdr.code = LVN_ITEMCHANGED;
2566 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2568 rcItem.left = LVIR_BOUNDS;
2569 LISTVIEW_GetItemRect(hwnd, lpLVItem->iItem, &rcItem);
2570 InvalidateRect(hwnd, &rcItem, TRUE);
2578 if (lpLVItem != NULL)
2580 if (lpLVItem->iSubItem == 0)
2582 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
2583 if (hdpaSubItems != NULL && hdpaSubItems != (HDPA)-1)
2585 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem);
2588 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2589 nmlv.hdr.hwndFrom = hwnd;
2590 nmlv.hdr.idFrom = lCtrlId;
2591 nmlv.hdr.code = LVN_ITEMCHANGING;
2592 nmlv.lParam = lpItem->lParam;
2593 uChanged = LISTVIEW_GetItemChanges(lpItem, lpLVItem);
2596 if (uChanged & LVIF_STATE)
2598 nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask;
2599 nmlv.uOldState = lpItem->state & lpLVItem->stateMask;
2601 if (nmlv.uNewState & LVIS_SELECTED)
2604 * This is redundant if called through SetSelection
2606 * however is required if the used directly calls SetItem
2607 * to set the selection.
2609 if (lStyle & LVS_SINGLESEL)
2611 LISTVIEW_RemoveAllSelections(hwnd);
2614 LISTVIEW_AddSelectionRange(hwnd,lpLVItem->iItem,
2617 else if (lpLVItem->stateMask & LVIS_SELECTED)
2619 LISTVIEW_RemoveSelectionRange(hwnd,lpLVItem->iItem,
2622 if (nmlv.uNewState & LVIS_FOCUSED)
2625 * This is a fun hoop to jump to try to catch if
2626 * the user is calling us directly to call focus or if
2627 * this function is being called as a result of a
2628 * SetItemFocus call.
2630 if (infoPtr->nFocusedItem >= 0)
2631 LISTVIEW_SetItemFocus(hwnd, lpLVItem->iItem);
2635 nmlv.uChanged = uChanged;
2636 nmlv.iItem = lpLVItem->iItem;
2637 nmlv.lParam = lpItem->lParam;
2638 /* send LVN_ITEMCHANGING notification */
2639 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2641 /* copy information */
2642 bResult = LISTVIEW_InitItem(hwnd, lpItem, lpLVItem);
2644 /* if LVS_LIST or LVS_SMALLICON, update the width of the items
2645 based on the width of the items text */
2646 if((uView == LVS_LIST) || (uView == LVS_SMALLICON))
2648 item_width = LISTVIEW_GetStringWidthA(hwnd, lpItem->pszText);
2650 if(item_width > infoPtr->nItemWidth)
2651 infoPtr->nItemWidth = item_width;
2654 /* send LVN_ITEMCHANGED notification */
2655 nmlv.hdr.code = LVN_ITEMCHANGED;
2656 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2665 rcItem.left = LVIR_BOUNDS;
2666 LISTVIEW_GetItemRect(hwnd, lpLVItem->iItem, &rcItem);
2667 InvalidateRect(hwnd, &rcItem, TRUE);
2679 * Sets subitem attributes.
2682 * [I] HWND : window handle
2683 * [I] LPLVITEM : new subitem atttributes
2689 static BOOL LISTVIEW_SetSubItem(HWND hwnd, LPLVITEMA lpLVItem)
2691 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2692 BOOL bResult = FALSE;
2694 LISTVIEW_SUBITEM *lpSubItem;
2695 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2698 if (lStyle & LVS_OWNERDATA)
2701 if (lpLVItem != NULL)
2703 if (lpLVItem->iSubItem > 0)
2705 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
2706 if (hdpaSubItems != NULL)
2708 /* set subitem only if column is present */
2709 if (Header_GetItemCount(infoPtr->hwndHeader) > lpLVItem->iSubItem)
2711 lpSubItem = LISTVIEW_GetSubItem(hdpaSubItems, lpLVItem->iSubItem);
2712 if (lpSubItem != NULL)
2714 bResult = LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem);
2718 bResult = LISTVIEW_AddSubItem(hwnd, lpLVItem);
2721 rcItem.left = LVIR_BOUNDS;
2722 LISTVIEW_GetItemRect(hwnd, lpLVItem->iItem, &rcItem);
2723 InvalidateRect(hwnd, &rcItem, FALSE);
2734 * Retrieves the index of the item at coordinate (0, 0) of the client area.
2737 * [I] HWND : window handle
2742 static INT LISTVIEW_GetTopIndex(HWND hwnd)
2744 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2745 UINT uView = lStyle & LVS_TYPEMASK;
2747 SCROLLINFO scrollInfo;
2749 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2750 scrollInfo.cbSize = sizeof(SCROLLINFO);
2751 scrollInfo.fMask = SIF_POS;
2753 if (uView == LVS_LIST)
2755 if (lStyle & WS_HSCROLL)
2757 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2759 nItem = scrollInfo.nPos * LISTVIEW_GetCountPerColumn(hwnd);
2763 else if (uView == LVS_REPORT)
2765 if (lStyle & WS_VSCROLL)
2767 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
2769 nItem = scrollInfo.nPos;
2782 * [I] HWND : window handle
2783 * [I] HDC : device context handle
2784 * [I] INT : item index
2785 * [I] INT : subitem index
2786 * [I] RECT * : clipping rectangle
2791 static VOID LISTVIEW_DrawSubItem(HWND hwnd, HDC hdc, INT nItem, INT nSubItem,
2792 RECT rcItem, BOOL Selected)
2794 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2795 CHAR szDispText[DISP_TEXT_SIZE];
2797 UINT textoutOptions = ETO_CLIPPED | ETO_OPAQUE;
2800 TRACE("(hwnd=%x, hdc=%x, nItem=%d, nSubItem=%d)\n", hwnd, hdc,
2803 /* get information needed for drawing the item */
2804 ZeroMemory(&lvItem, sizeof(LVITEMA));
2805 lvItem.mask = LVIF_TEXT;
2806 lvItem.iItem = nItem;
2807 lvItem.iSubItem = nSubItem;
2808 lvItem.cchTextMax = DISP_TEXT_SIZE;
2809 lvItem.pszText = szDispText;
2810 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
2812 /* redraw the background of the item */
2814 if(infoPtr->nColumnCount == (nSubItem + 1))
2815 rcTemp.right = infoPtr->rcList.right;
2817 rcTemp.right+=WIDTH_PADDING;
2819 LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
2821 /* set item colors */
2822 if (ListView_GetItemState(hwnd,nItem,LVIS_SELECTED) && Selected)
2824 if (infoPtr->bFocus)
2826 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
2827 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2831 SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
2832 SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
2837 if ( (infoPtr->clrTextBk == CLR_DEFAULT) || (infoPtr->clrTextBk == CLR_NONE) )
2839 SetBkMode(hdc, TRANSPARENT);
2840 textoutOptions &= ~ETO_OPAQUE;
2844 SetBkMode(hdc, OPAQUE);
2845 SetBkColor(hdc, infoPtr->clrTextBk);
2848 SetTextColor(hdc, infoPtr->clrText);
2851 ExtTextOutA(hdc, rcItem.left, rcItem.top, textoutOptions,
2852 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
2856 /* fill in the gap */
2858 if (nSubItem < Header_GetItemCount(infoPtr->hwndHeader)-1)
2860 CopyRect(&rec,&rcItem);
2861 rec.left = rec.right;
2862 rec.right = rec.left+REPORT_MARGINX;
2863 ExtTextOutA(hdc, rec.left , rec.top, textoutOptions,
2864 &rec, NULL, 0, NULL);
2866 CopyRect(&rec,&rcItem);
2867 rec.right = rec.left;
2868 rec.left = rec.left - REPORT_MARGINX;
2869 ExtTextOutA(hdc, rec.left , rec.top, textoutOptions,
2870 &rec, NULL, 0, NULL);
2880 * [I] HWND : window handle
2881 * [I] HDC : device context handle
2882 * [I] INT : item index
2883 * [I] RECT * : clipping rectangle
2888 static VOID LISTVIEW_DrawItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem, BOOL FullSelect, RECT* SuggestedFocus)
2890 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2891 CHAR szDispText[DISP_TEXT_SIZE];
2896 DWORD dwTextColor,dwTextX;
2897 BOOL bImage = FALSE;
2899 UINT textoutOptions = ETO_OPAQUE | ETO_CLIPPED;
2902 TRACE("(hwnd=%x, hdc=%x, nItem=%d)\n", hwnd, hdc, nItem);
2905 /* get information needed for drawing the item */
2906 ZeroMemory(&lvItem, sizeof(LVITEMA));
2907 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_INDENT;
2908 lvItem.stateMask = LVIS_SELECTED | LVIS_STATEIMAGEMASK;
2909 lvItem.iItem = nItem;
2910 lvItem.iSubItem = 0;
2911 lvItem.cchTextMax = DISP_TEXT_SIZE;
2912 lvItem.pszText = szDispText;
2913 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
2915 /* redraw the background of the item */
2917 if(infoPtr->nColumnCount == (nItem + 1))
2918 rcTemp.right = infoPtr->rcList.right;
2920 rcTemp.right+=WIDTH_PADDING;
2922 LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
2925 if (lvItem.iIndent>0 && infoPtr->iconSize.cx > 0)
2927 rcItem.left += infoPtr->iconSize.cx * lvItem.iIndent;
2930 SuggestedFocus->left += infoPtr->iconSize.cx * lvItem.iIndent;
2934 if (infoPtr->himlState != NULL)
2936 UINT uStateImage = (lvItem.state & LVIS_STATEIMAGEMASK) >> 12;
2937 if (uStateImage > 0)
2939 ImageList_Draw(infoPtr->himlState, uStateImage - 1, hdc, rcItem.left,
2940 rcItem.top, ILD_NORMAL);
2943 rcItem.left += infoPtr->iconSize.cx;
2945 SuggestedFocus->left += infoPtr->iconSize.cx;
2950 if (infoPtr->himlSmall != NULL)
2952 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE) &&
2955 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
2956 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
2957 rcItem.top, ILD_SELECTED);
2959 else if (lvItem.iImage>=0)
2961 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
2962 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
2963 rcItem.top, ILD_NORMAL);
2966 rcItem.left += infoPtr->iconSize.cx;
2969 SuggestedFocus->left += infoPtr->iconSize.cx;
2973 /* Don't bother painting item being edited */
2974 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED && !FullSelect)
2977 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
2979 /* set item colors */
2980 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
2981 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2982 /* set raster mode */
2983 nMixMode = SetROP2(hdc, R2_XORPEN);
2985 else if ((GetWindowLongA(hwnd, GWL_STYLE) & LVS_SHOWSELALWAYS) &&
2986 (lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus == FALSE))
2988 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
2989 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
2990 /* set raster mode */
2991 nMixMode = SetROP2(hdc, R2_COPYPEN);
2995 /* set item colors */
2996 if ( (infoPtr->clrTextBk == CLR_DEFAULT) || (infoPtr->clrTextBk == CLR_NONE) )
2998 dwBkColor = GetBkColor(hdc);
2999 iBkMode = SetBkMode(hdc, TRANSPARENT);
3000 textoutOptions &= ~ETO_OPAQUE;
3004 dwBkColor = SetBkColor(hdc, infoPtr->clrTextBk);
3005 iBkMode = SetBkMode(hdc, OPAQUE);
3008 dwTextColor = SetTextColor(hdc, infoPtr->clrText);
3009 /* set raster mode */
3010 nMixMode = SetROP2(hdc, R2_COPYPEN);
3013 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
3014 if (rcItem.left + nLabelWidth < rcItem.right)
3017 rcItem.right = rcItem.left + nLabelWidth + TRAILING_PADDING;
3019 rcItem.right += IMAGE_PADDING;
3023 dwTextX = rcItem.left + 1;
3025 dwTextX += IMAGE_PADDING;
3028 ExtTextOutA(hdc, dwTextX, rcItem.top, textoutOptions,
3029 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
3031 if ((FullSelect)&&(Header_GetItemCount(infoPtr->hwndHeader) > 1))
3033 /* fill in the gap */
3035 CopyRect(&rec,&rcItem);
3036 rec.left = rec.right;
3037 rec.right = rec.left+REPORT_MARGINX;
3038 ExtTextOutA(hdc, rec.left , rec.top, textoutOptions,
3039 &rec, NULL, 0, NULL);
3043 CopyRect(SuggestedFocus,&rcItem);
3047 SetROP2(hdc, R2_COPYPEN);
3048 SetBkColor(hdc, dwBkColor);
3049 SetTextColor(hdc, dwTextColor);
3051 SetBkMode(hdc, iBkMode);
3057 * Draws an item when in large icon display mode.
3060 * [I] HWND : window handle
3061 * [I] HDC : device context handle
3062 * [I] LISTVIEW_ITEM * : item
3063 * [I] INT : item index
3064 * [I] RECT * : clipping rectangle
3069 static VOID LISTVIEW_DrawLargeItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem,
3070 RECT *SuggestedFocus)
3072 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3073 CHAR szDispText[DISP_TEXT_SIZE];
3074 INT nDrawPosX = rcItem.left;
3075 INT nLabelWidth, rcWidth;
3078 UINT textoutOptions = ETO_CLIPPED | ETO_OPAQUE;
3081 TRACE("(hwnd=%x, hdc=%x, nItem=%d, left=%d, top=%d, right=%d, \
3082 bottom=%d)\n", hwnd, hdc, nItem, rcItem.left, rcItem.top, rcItem.right,
3085 /* get information needed for drawing the item */
3086 ZeroMemory(&lvItem, sizeof(LVITEMA));
3087 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
3088 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
3089 lvItem.iItem = nItem;
3090 lvItem.iSubItem = 0;
3091 lvItem.cchTextMax = DISP_TEXT_SIZE;
3092 lvItem.pszText = szDispText;
3093 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
3095 /* redraw the background of the item */
3097 if(infoPtr->nColumnCount == (nItem + 1))
3098 rcTemp.right = infoPtr->rcList.right;
3100 rcTemp.right+=WIDTH_PADDING;
3102 LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
3104 if (lvItem.state & LVIS_SELECTED)
3106 /* set item colors */
3107 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
3108 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
3109 /* set raster mode */
3110 SetROP2(hdc, R2_XORPEN);
3114 /* set item colors */
3115 if ( (infoPtr->clrTextBk == CLR_DEFAULT) || (infoPtr->clrTextBk == CLR_NONE) )
3117 SetBkMode(hdc, TRANSPARENT);
3118 textoutOptions &= ~ETO_OPAQUE;
3122 SetBkMode(hdc, OPAQUE);
3123 SetBkColor(hdc, infoPtr->clrTextBk);
3126 SetTextColor(hdc, infoPtr->clrText);
3127 /* set raster mode */
3128 SetROP2(hdc, R2_COPYPEN);
3131 if (infoPtr->himlNormal != NULL)
3133 rcItem.top += ICON_TOP_PADDING;
3134 nDrawPosX += (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
3135 if ((lvItem.state & LVIS_SELECTED) && (lvItem.iImage>=0))
3137 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
3138 rcItem.top, ILD_SELECTED);
3140 else if (lvItem.iImage>=0)
3142 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
3143 rcItem.top, ILD_NORMAL);
3147 /* Don't bother painting item being edited */
3148 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED)
3151 InflateRect(&rcItem, -(2*CAPTION_BORDER), 0);
3152 rcItem.top += infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
3153 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
3154 GetTextMetricsA(hdc, &tm);
3156 /* append an ellipse ('...') if the caption won't fit in the rect */
3157 rcWidth = max(0, rcItem.right - rcItem.left);
3158 if (nLabelWidth > rcWidth)
3160 INT i, len, eos, nCharsFit;
3161 /* give or take a couple, how many average sized chars would fit? */
3162 nCharsFit = tm.tmAveCharWidth > 0 ? (rcWidth/tm.tmAveCharWidth)+2 : 0;
3163 /* place the ellipse accordingly, without overrunning the buffer */
3164 len = strlen(szDispText);
3165 eos = min((nCharsFit > 1 && nCharsFit < len) ? nCharsFit+3 : len+2,
3166 sizeof(szDispText)-1);
3168 nLabelWidth = ListView_GetStringWidthA(hwnd, szDispText);
3169 while ((nLabelWidth > rcWidth) && (eos > 3))
3171 for (i = 1; i < 4; i++)
3172 szDispText[eos-i] = '.';
3173 /* shift the ellipse one char to the left for each iteration */
3174 szDispText[eos--] = '\0';
3175 nLabelWidth = ListView_GetStringWidthA(hwnd, szDispText);
3179 InflateRect(&rcItem, 2*CAPTION_BORDER, 0);
3180 nDrawPosX = infoPtr->iconSpacing.cx - 2*CAPTION_BORDER - nLabelWidth;
3183 rcItem.left += nDrawPosX / 2;
3184 rcItem.right = rcItem.left + nLabelWidth + 2*CAPTION_BORDER;
3189 rcItem.right = rcItem.left + infoPtr->iconSpacing.cx - 1;
3193 rcItem.bottom = rcItem.top + tm.tmHeight + HEIGHT_PADDING;
3195 ExtTextOutA(hdc, rcItem.left + CAPTION_BORDER, rcItem.top, textoutOptions,
3196 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
3199 CopyRect(SuggestedFocus,&rcItem);
3204 * Draws listview items when in report display mode.
3207 * [I] HWND : window handle
3208 * [I] HDC : device context handle
3213 static VOID LISTVIEW_RefreshReport(HWND hwnd, HDC hdc, DWORD cdmode)
3215 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
3216 SCROLLINFO scrollInfo;
3217 INT nDrawPosY = infoPtr->rcList.top;
3219 RECT rcItem, rcTemp;
3224 DWORD cditemmode = CDRF_DODEFAULT;
3225 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3227 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
3228 scrollInfo.cbSize = sizeof(SCROLLINFO);
3229 scrollInfo.fMask = SIF_POS;
3231 nItem = ListView_GetTopIndex(hwnd);
3233 /* add 1 for displaying a partial item at the bottom */
3234 nLast = nItem + LISTVIEW_GetCountPerColumn(hwnd) + 1;
3235 nLast = min(nLast, GETITEMCOUNT(infoPtr));
3237 /* send cache hint notification */
3238 if (GetWindowLongA(hwnd,GWL_STYLE) & LVS_OWNERDATA)
3242 nmlv.hdr.hwndFrom = hwnd;
3243 nmlv.hdr.idFrom = GetWindowLongA(hwnd,GWL_ID);
3244 nmlv.hdr.code = LVN_ODCACHEHINT;
3248 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)nmlv.hdr.idFrom,
3252 nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
3253 infoPtr->nColumnCount = nColumnCount; /* update nColumnCount */
3254 FullSelected = infoPtr->dwExStyle & LVS_EX_FULLROWSELECT;
3256 /* clear the background of any part of the control that doesn't contain items */
3257 SubtractRect(&rcTemp, &infoPtr->rcList, &infoPtr->rcView);
3258 LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
3260 /* nothing to draw */
3261 if(GETITEMCOUNT(infoPtr) == 0)
3264 for (; nItem < nLast; nItem++)
3266 RECT SuggestedFocusRect;
3269 if (lStyle & LVS_OWNERDRAWFIXED)
3271 UINT uID = GetWindowLongA( hwnd, GWL_ID);
3276 TRACE("Owner Drawn\n");
3277 dis.CtlType = ODT_LISTVIEW;
3280 dis.itemAction = ODA_DRAWENTIRE;
3283 if (LISTVIEW_IsSelected(hwnd,nItem)) dis.itemState|=ODS_SELECTED;
3284 if (nItem==infoPtr->nFocusedItem) dis.itemState|=ODS_FOCUS;
3286 dis.hwndItem = hwnd;
3289 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
3292 dis.rcItem.right = max(dis.rcItem.left, br.right);
3293 dis.rcItem.top = nDrawPosY;
3294 dis.rcItem.bottom = dis.rcItem.top + infoPtr->nItemHeight;
3296 ZeroMemory(&item,sizeof(LVITEMA));
3298 item.mask = LVIF_PARAM;
3299 ListView_GetItemA(hwnd,&item);
3301 dis.itemData = item.lParam;
3303 if (SendMessageA(GetParent(hwnd),WM_DRAWITEM,(WPARAM)uID,(LPARAM)&dis))
3305 nDrawPosY += infoPtr->nItemHeight;
3314 Header_GetItemRect(infoPtr->hwndHeader, 0, &ir);
3315 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
3317 ir.left += REPORT_MARGINX;
3318 ir.right = max(ir.left, br.right - REPORT_MARGINX);
3320 ir.bottom = ir.top + infoPtr->nItemHeight;
3322 CopyRect(&SuggestedFocusRect,&ir);
3325 for (j = 0; j < nColumnCount; j++)
3327 if (cdmode & CDRF_NOTIFYITEMDRAW)
3328 cditemmode = LISTVIEW_SendCustomDrawItemNotify (hwnd, hdc, nItem, j,
3330 if (cditemmode & CDRF_SKIPDEFAULT)
3333 Header_GetItemRect(infoPtr->hwndHeader, j, &rcItem);
3335 rcItem.left += REPORT_MARGINX;
3336 rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX);
3337 rcItem.top = nDrawPosY;
3338 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
3340 /* Offset the Scroll Bar Pos */
3341 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
3343 rcItem.left -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
3344 rcItem.right -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
3349 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem, FullSelected,
3350 &SuggestedFocusRect);
3354 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, j, rcItem,
3358 if (cditemmode & CDRF_NOTIFYPOSTPAINT)
3359 LISTVIEW_SendCustomDrawItemNotify(hwnd, hdc, nItem, 0,
3360 CDDS_ITEMPOSTPAINT);
3365 if (LISTVIEW_GetItemState(hwnd,nItem,LVIS_FOCUSED) && infoPtr->bFocus)
3368 if (FullSelected && LISTVIEW_GetItemState(hwnd,nItem,LVIS_SELECTED))
3369 rop = SetROP2(hdc, R2_XORPEN);
3371 Rectangle(hdc, SuggestedFocusRect.left, SuggestedFocusRect.top,
3372 SuggestedFocusRect.right,SuggestedFocusRect.bottom);
3375 SetROP2(hdc, R2_COPYPEN);
3377 nDrawPosY += infoPtr->nItemHeight;
3383 * Retrieves the number of items that can fit vertically in the client area.
3386 * [I] HWND : window handle
3389 * Number of items per row.
3391 static INT LISTVIEW_GetCountPerRow(HWND hwnd)
3393 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
3394 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3395 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
3396 INT nCountPerRow = 1;
3400 if (uView == LVS_REPORT)
3406 nCountPerRow = nListWidth / infoPtr->nItemWidth;
3407 if (nCountPerRow == 0)
3414 return nCountPerRow;
3419 * Retrieves the number of items that can fit horizontally in the client
3423 * [I] HWND : window handle
3426 * Number of items per column.
3428 static INT LISTVIEW_GetCountPerColumn(HWND hwnd)
3430 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
3431 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
3432 INT nCountPerColumn = 1;
3434 if (nListHeight > 0)
3436 nCountPerColumn = nListHeight / infoPtr->nItemHeight;
3437 if (nCountPerColumn == 0)
3439 nCountPerColumn = 1;
3443 return nCountPerColumn;
3448 * Retrieves the number of columns needed to display all the items when in
3449 * list display mode.
3452 * [I] HWND : window handle
3455 * Number of columns.
3457 static INT LISTVIEW_GetColumnCount(HWND hwnd)
3459 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3460 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3461 INT nColumnCount = 0;
3463 if ((lStyle & LVS_TYPEMASK) == LVS_LIST)
3465 if (infoPtr->rcList.right % infoPtr->nItemWidth == 0)
3467 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth;
3471 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth + 1;
3475 return nColumnCount;
3481 * Draws listview items when in list display mode.
3484 * [I] HWND : window handle
3485 * [I] HDC : device context handle
3490 static VOID LISTVIEW_RefreshList(HWND hwnd, HDC hdc, DWORD cdmode)
3492 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3493 RECT rcItem, FocusRect, rcTemp;
3497 INT nCountPerColumn;
3498 INT nItemWidth = infoPtr->nItemWidth;
3499 INT nItemHeight = infoPtr->nItemHeight;
3500 DWORD cditemmode = CDRF_DODEFAULT;
3502 /* get number of fully visible columns */
3503 nColumnCount = LISTVIEW_GetColumnCount(hwnd);
3504 infoPtr->nColumnCount = nColumnCount;
3505 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
3506 nItem = ListView_GetTopIndex(hwnd);
3508 /* paint the background of the control that doesn't contain any items */
3509 SubtractRect(&rcTemp, &infoPtr->rcList, &infoPtr->rcView);
3510 LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
3512 /* nothing to draw, return here */
3513 if(GETITEMCOUNT(infoPtr) == 0)
3516 for (i = 0; i < nColumnCount; i++)
3518 for (j = 0; j < nCountPerColumn; j++, nItem++)
3520 if (nItem >= GETITEMCOUNT(infoPtr))
3523 if (cdmode & CDRF_NOTIFYITEMDRAW)
3524 cditemmode = LISTVIEW_SendCustomDrawItemNotify (hwnd, hdc, nItem, 0,
3526 if (cditemmode & CDRF_SKIPDEFAULT)
3529 rcItem.top = j * nItemHeight;
3530 rcItem.left = i * nItemWidth;
3531 rcItem.bottom = rcItem.top + nItemHeight;
3532 rcItem.right = rcItem.left + nItemWidth;
3533 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem, FALSE, &FocusRect);
3537 if (LISTVIEW_GetItemState(hwnd,nItem,LVIS_FOCUSED) && infoPtr->bFocus)
3538 Rectangle(hdc, FocusRect.left, FocusRect.top,
3539 FocusRect.right,FocusRect.bottom);
3541 if (cditemmode & CDRF_NOTIFYPOSTPAINT)
3542 LISTVIEW_SendCustomDrawItemNotify(hwnd, hdc, nItem, 0,
3543 CDDS_ITEMPOSTPAINT);
3551 * Draws listview items when in icon or small icon display mode.
3554 * [I] HWND : window handle
3555 * [I] HDC : device context handle
3560 static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc, BOOL bSmall, DWORD cdmode)
3562 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3565 RECT rcItem, SuggestedFocus, rcTemp;
3567 DWORD cditemmode = CDRF_DODEFAULT;
3569 infoPtr->nColumnCount = 1; /* set this to an arbitrary value to prevent */
3570 /* DrawItem from erasing the incorrect background area */
3572 /* paint the background of the control that doesn't contain any items */
3573 SubtractRect(&rcTemp, &infoPtr->rcList, &infoPtr->rcView);
3574 LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
3576 /* nothing to draw, return here */
3577 if(GETITEMCOUNT(infoPtr) == 0)
3580 LISTVIEW_GetOrigin(hwnd, &ptOrigin);
3581 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
3583 if (cdmode & CDRF_NOTIFYITEMDRAW)
3584 cditemmode = LISTVIEW_SendCustomDrawItemNotify (hwnd, hdc, i, 0,
3586 if (cditemmode & CDRF_SKIPDEFAULT)
3589 LISTVIEW_GetItemPosition(hwnd, i, &ptPosition);
3590 ptPosition.x += ptOrigin.x;
3591 ptPosition.y += ptOrigin.y;
3593 if (ptPosition.y + infoPtr->nItemHeight > infoPtr->rcList.top)
3595 if (ptPosition.x + infoPtr->nItemWidth > infoPtr->rcList.left)
3597 if (ptPosition.y < infoPtr->rcList.bottom)
3599 if (ptPosition.x < infoPtr->rcList.right)
3601 rcItem.top = ptPosition.y;
3602 rcItem.left = ptPosition.x;
3603 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
3604 rcItem.right = rcItem.left + infoPtr->nItemWidth;
3605 if (bSmall == FALSE)
3607 LISTVIEW_DrawLargeItem(hwnd, hdc, i, rcItem, &SuggestedFocus);
3611 LISTVIEW_DrawItem(hwnd, hdc, i, rcItem, FALSE, &SuggestedFocus);
3616 if (LISTVIEW_GetItemState(hwnd,i,LVIS_FOCUSED) &&
3618 Rectangle(hdc, SuggestedFocus.left, SuggestedFocus.top,
3619 SuggestedFocus.right,SuggestedFocus.bottom);
3624 if (cditemmode & CDRF_NOTIFYPOSTPAINT)
3625 LISTVIEW_SendCustomDrawItemNotify(hwnd, hdc, i, 0,
3626 CDDS_ITEMPOSTPAINT);
3632 * Draws listview items.
3635 * [I] HWND : window handle
3636 * [I] HDC : device context handle
3641 static VOID LISTVIEW_Refresh(HWND hwnd, HDC hdc)
3643 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3644 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3650 GetClientRect(hwnd, &rect);
3651 cdmode = LISTVIEW_SendCustomDrawNotify(hwnd,CDDS_PREPAINT,hdc,rect);
3653 if (cdmode == CDRF_SKIPDEFAULT) return;
3656 hOldFont = SelectObject(hdc, infoPtr->hFont);
3658 /* select the dotted pen (for drawing the focus box) */
3659 hPen = CreatePen(PS_ALTERNATE, 1, 0);
3660 hOldPen = SelectObject(hdc, hPen);
3662 /* select transparent brush (for drawing the focus box) */
3663 SelectObject(hdc, GetStockObject(NULL_BRUSH));
3665 if (uView == LVS_LIST)
3667 LISTVIEW_RefreshList(hwnd, hdc, cdmode);
3669 else if (uView == LVS_REPORT)
3671 LISTVIEW_RefreshReport(hwnd, hdc, cdmode);
3673 else if (uView == LVS_SMALLICON)
3675 LISTVIEW_RefreshIcon(hwnd, hdc, TRUE, cdmode);
3677 else if (uView == LVS_ICON)
3679 LISTVIEW_RefreshIcon(hwnd, hdc, FALSE, cdmode);
3682 /* unselect objects */
3683 SelectObject(hdc, hOldFont);
3684 SelectObject(hdc, hOldPen);
3689 if (cdmode & CDRF_NOTIFYPOSTPAINT)
3690 LISTVIEW_SendCustomDrawNotify(hwnd, CDDS_POSTPAINT, hdc, rect);
3696 * Calculates the approximate width and height of a given number of items.
3699 * [I] HWND : window handle
3700 * [I] INT : number of items
3705 * Returns a DWORD. The width in the low word and the height in high word.
3707 static LRESULT LISTVIEW_ApproximateViewRect(HWND hwnd, INT nItemCount,
3708 WORD wWidth, WORD wHeight)
3710 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3711 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3712 INT nItemCountPerColumn = 1;
3713 INT nColumnCount = 0;
3714 DWORD dwViewRect = 0;
3716 if (nItemCount == -1)
3718 nItemCount = GETITEMCOUNT(infoPtr);
3721 if (uView == LVS_LIST)
3723 if (wHeight == 0xFFFF)
3725 /* use current height */
3726 wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
3729 if (wHeight < infoPtr->nItemHeight)
3731 wHeight = infoPtr->nItemHeight;
3736 if (infoPtr->nItemHeight > 0)
3738 nItemCountPerColumn = wHeight / infoPtr->nItemHeight;
3739 if (nItemCountPerColumn == 0)
3741 nItemCountPerColumn = 1;
3744 if (nItemCount % nItemCountPerColumn != 0)
3746 nColumnCount = nItemCount / nItemCountPerColumn;
3750 nColumnCount = nItemCount / nItemCountPerColumn + 1;
3755 /* Microsoft padding magic */
3756 wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2;
3757 wWidth = nColumnCount * infoPtr->nItemWidth + 2;
3759 dwViewRect = MAKELONG(wWidth, wHeight);
3761 else if (uView == LVS_REPORT)
3765 else if (uView == LVS_SMALLICON)
3769 else if (uView == LVS_ICON)
3779 * Arranges listview items in icon display mode.
3782 * [I] HWND : window handle
3783 * [I] INT : alignment code
3789 static LRESULT LISTVIEW_Arrange(HWND hwnd, INT nAlignCode)
3791 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3792 BOOL bResult = FALSE;
3794 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
3807 case LVA_SNAPTOGRID:
3816 /* << LISTVIEW_CreateDragImage >> */
3821 * Removes all listview items and subitems.
3824 * [I] HWND : window handle
3830 static LRESULT LISTVIEW_DeleteAllItems(HWND hwnd)
3832 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3833 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
3834 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3835 UINT uView = lStyle & LVS_TYPEMASK;
3836 LISTVIEW_ITEM *lpItem;
3837 LISTVIEW_SUBITEM *lpSubItem;
3840 BOOL bResult = FALSE;
3845 TRACE("(hwnd=%x,)\n", hwnd);
3846 LISTVIEW_RemoveAllSelections(hwnd);
3848 if (lStyle & LVS_OWNERDATA)
3850 infoPtr->hdpaItems->nItemCount = 0;
3851 InvalidateRect(hwnd, NULL, TRUE);
3855 if (GETITEMCOUNT(infoPtr) > 0)
3857 /* initialize memory */
3858 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
3860 /* send LVN_DELETEALLITEMS notification */
3861 nmlv.hdr.hwndFrom = hwnd;
3862 nmlv.hdr.idFrom = lCtrlId;
3863 nmlv.hdr.code = LVN_DELETEALLITEMS;
3866 /* verify if subsequent LVN_DELETEITEM notifications should be
3868 bSuppress = ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
3870 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
3872 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
3873 if (hdpaSubItems != NULL)
3875 for (j = 1; j < hdpaSubItems->nItemCount; j++)
3877 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, j);
3878 if (lpSubItem != NULL)
3880 /* free subitem string */
3881 if ((lpSubItem->pszText != NULL) &&
3882 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
3884 COMCTL32_Free(lpSubItem->pszText);
3888 COMCTL32_Free(lpSubItem);
3892 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3895 if (bSuppress == FALSE)
3897 /* send LVN_DELETEITEM notification */
3898 nmlv.hdr.code = LVN_DELETEITEM;
3900 nmlv.lParam = lpItem->lParam;
3901 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
3904 /* free item string */
3905 if ((lpItem->pszText != NULL) &&
3906 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
3908 COMCTL32_Free(lpItem->pszText);
3912 COMCTL32_Free(lpItem);
3915 DPA_Destroy(hdpaSubItems);
3919 /* reinitialize listview memory */
3920 bResult = DPA_DeleteAllPtrs(infoPtr->hdpaItems);
3922 /* align items (set position of each item) */
3923 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
3925 if (lStyle & LVS_ALIGNLEFT)
3927 LISTVIEW_AlignLeft(hwnd);
3931 LISTVIEW_AlignTop(hwnd);
3935 LISTVIEW_UpdateScroll(hwnd);
3937 /* invalidate client area (optimization needed) */
3938 InvalidateRect(hwnd, NULL, TRUE);
3946 * Removes a column from the listview control.
3949 * [I] HWND : window handle
3950 * [I] INT : column index
3956 static LRESULT LISTVIEW_DeleteColumn(HWND hwnd, INT nColumn)
3958 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3959 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3960 UINT uOwnerData = GetWindowLongA(hwnd, GWL_STYLE) & LVS_OWNERDATA;
3961 BOOL bResult = FALSE;
3963 if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) != FALSE)
3966 bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
3968 /* Need to reset the item width when deleting a column */
3969 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
3971 /* reset scroll parameters */
3972 if (uView == LVS_REPORT)
3974 /* update scrollbar(s) */
3975 LISTVIEW_UpdateScroll(hwnd);
3977 /* refresh client area */
3978 InvalidateRect(hwnd, NULL, FALSE);
3987 * Removes an item from the listview control.
3990 * [I] HWND : window handle
3991 * [I] INT : item index
3997 static LRESULT LISTVIEW_DeleteItem(HWND hwnd, INT nItem)
3999 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4000 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4001 UINT uView = lStyle & LVS_TYPEMASK;
4002 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
4004 BOOL bResult = FALSE;
4006 LISTVIEW_ITEM *lpItem;
4007 LISTVIEW_SUBITEM *lpSubItem;
4011 TRACE("(hwnd=%x,nItem=%d)\n", hwnd, nItem);
4013 /* remove it from the selection range */
4014 ZeroMemory(&item,sizeof(LVITEMA));
4015 item.stateMask = LVIS_SELECTED;
4016 LISTVIEW_SetItemState(hwnd,nItem,&item);
4018 LISTVIEW_ShiftSelections(hwnd,nItem,-1);
4020 if (lStyle & LVS_OWNERDATA)
4022 infoPtr->hdpaItems->nItemCount --;
4023 InvalidateRect(hwnd, NULL, TRUE);
4027 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4029 /* initialize memory */
4030 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
4032 hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem);
4033 if (hdpaSubItems != NULL)
4035 for (i = 1; i < hdpaSubItems->nItemCount; i++)
4037 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
4038 if (lpSubItem != NULL)
4040 /* free item string */
4041 if ((lpSubItem->pszText != NULL) &&
4042 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
4044 COMCTL32_Free(lpSubItem->pszText);
4048 COMCTL32_Free(lpSubItem);
4052 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
4055 /* send LVN_DELETEITEM notification */
4056 nmlv.hdr.hwndFrom = hwnd;
4057 nmlv.hdr.idFrom = lCtrlId;
4058 nmlv.hdr.code = LVN_DELETEITEM;
4060 nmlv.lParam = lpItem->lParam;
4061 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId,
4064 /* free item string */
4065 if ((lpItem->pszText != NULL) &&
4066 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
4068 COMCTL32_Free(lpItem->pszText);
4072 COMCTL32_Free(lpItem);
4075 bResult = DPA_Destroy(hdpaSubItems);
4078 /* align items (set position of each item) */
4079 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4081 if (lStyle & LVS_ALIGNLEFT)
4083 LISTVIEW_AlignLeft(hwnd);
4087 LISTVIEW_AlignTop(hwnd);
4091 /* If this item had focus change focus to next or previous item */
4092 if (GETITEMCOUNT(infoPtr) > 0)
4094 int sItem = nItem < GETITEMCOUNT(infoPtr) ? nItem : nItem - 1;
4095 if (infoPtr->nFocusedItem == nItem)
4096 LISTVIEW_SetItemFocus(hwnd, sItem);
4099 infoPtr->nFocusedItem = -1;
4101 LISTVIEW_UpdateScroll(hwnd);
4103 /* refresh client area */
4104 InvalidateRect(hwnd, NULL, TRUE);
4113 * Return edit control handle of current edit label
4116 * [I] HWND : window handle
4122 static LRESULT LISTVIEW_GetEditControl(HWND hwnd)
4124 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4125 return infoPtr->hwndEdit;
4131 * Callback implementation for editlabel control
4134 * [I] HWND : window handle
4135 * [I] LPSTR : modified text
4136 * [I] DWORD : item index
4143 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem)
4145 NMLVDISPINFOA dispInfo;
4146 LISTVIEW_ITEM *lpItem;
4147 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
4148 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4149 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4151 BOOL bUpdateItemText;
4152 LISTVIEW_ITEM lvItemRef;
4155 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
4157 if (!(lStyle & LVS_OWNERDATA))
4159 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
4162 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
4167 ZeroMemory(&lvItemRef,sizeof(LISTVIEW_ITEM));
4168 ZeroMemory(&item,sizeof(LVITEMA));
4171 item.mask = LVIF_PARAM | LVIF_STATE;
4172 ListView_GetItemA(hwnd,&item);
4173 lvItemRef.state = item.state;
4174 lvItemRef.iImage = item.iImage;
4175 lvItemRef.lParam = item.lParam;
4176 lpItem = &lvItemRef;
4179 dispInfo.hdr.hwndFrom = hwnd;
4180 dispInfo.hdr.idFrom = nCtrlId;
4181 dispInfo.hdr.code = LVN_ENDLABELEDITA;
4182 dispInfo.item.mask = 0;
4183 dispInfo.item.iItem = nItem;
4184 dispInfo.item.state = lpItem->state;
4185 dispInfo.item.stateMask = 0;
4186 dispInfo.item.pszText = pszText;
4187 dispInfo.item.cchTextMax = pszText ? strlen(pszText) : 0;
4188 dispInfo.item.iImage = lpItem->iImage;
4189 dispInfo.item.lParam = lpItem->lParam;
4190 infoPtr->hwndEdit = 0;
4192 bUpdateItemText = ListView_Notify(GetParent(hwnd), nCtrlId, &dispInfo);
4194 /* Do we need to update the Item Text */
4197 if ((lpItem->pszText != LPSTR_TEXTCALLBACKA)&&(!(lStyle & LVS_OWNERDATA)))
4199 Str_SetPtrA(&lpItem->pszText, pszText);
4208 * Begin in place editing of specified list view item
4211 * [I] HWND : window handle
4212 * [I] INT : item index
4219 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem)
4221 NMLVDISPINFOA dispInfo;
4223 LISTVIEW_ITEM *lpItem;
4225 HINSTANCE hinst = GetWindowLongA(hwnd, GWL_HINSTANCE);
4226 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
4227 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4229 CHAR szDispText[DISP_TEXT_SIZE];
4230 LVITEMA lvItem,item;
4231 LISTVIEW_ITEM lvItemRef;
4232 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4234 if (~GetWindowLongA(hwnd, GWL_STYLE) & LVS_EDITLABELS)
4237 /* Is the EditBox still there, if so remove it */
4238 if(infoPtr->hwndEdit != 0)
4243 LISTVIEW_SetSelection(hwnd, nItem);
4244 LISTVIEW_SetItemFocus(hwnd, nItem);
4246 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
4247 if (!(lStyle & LVS_OWNERDATA))
4249 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
4252 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
4257 ZeroMemory(&lvItemRef,sizeof(LISTVIEW_ITEM));
4258 ZeroMemory(&item,sizeof(LVITEMA));
4261 item.mask = LVIF_PARAM | LVIF_STATE;
4262 ListView_GetItemA(hwnd,&item);
4263 lvItemRef.iImage = item.iImage;
4264 lvItemRef.state = item.state;
4265 lvItemRef.lParam = item.lParam;
4266 lpItem = &lvItemRef;
4269 /* get information needed for drawing the item */
4270 ZeroMemory(&lvItem, sizeof(LVITEMA));
4271 lvItem.mask = LVIF_TEXT;
4272 lvItem.iItem = nItem;
4273 lvItem.iSubItem = 0;
4274 lvItem.cchTextMax = DISP_TEXT_SIZE;
4275 lvItem.pszText = szDispText;
4276 ListView_GetItemA(hwnd, &lvItem);
4278 dispInfo.hdr.hwndFrom = hwnd;
4279 dispInfo.hdr.idFrom = nCtrlId;
4280 dispInfo.hdr.code = LVN_BEGINLABELEDITA;
4281 dispInfo.item.mask = 0;
4282 dispInfo.item.iItem = nItem;
4283 dispInfo.item.state = lpItem->state;
4284 dispInfo.item.stateMask = 0;
4285 dispInfo.item.pszText = lvItem.pszText;
4286 dispInfo.item.cchTextMax = strlen(lvItem.pszText);
4287 dispInfo.item.iImage = lpItem->iImage;
4288 dispInfo.item.lParam = lpItem->lParam;
4290 if (ListView_LVNotify(GetParent(hwnd), nCtrlId, &dispInfo))
4293 rect.left = LVIR_LABEL;
4294 if (!LISTVIEW_GetItemRect(hwnd, nItem, &rect))
4297 if (!(hedit = CreateEditLabel(szDispText , WS_VISIBLE,
4298 rect.left-2, rect.top-1, 0,
4299 rect.bottom - rect.top+2,
4300 hwnd, hinst, LISTVIEW_EndEditLabel, nItem)))
4303 infoPtr->hwndEdit = hedit;
4305 SendMessageA(hedit, EM_SETSEL, 0, -1);
4313 * Ensures the specified item is visible, scrolling into view if necessary.
4316 * [I] HWND : window handle
4317 * [I] INT : item index
4318 * [I] BOOL : partially or entirely visible
4324 static BOOL LISTVIEW_EnsureVisible(HWND hwnd, INT nItem, BOOL bPartial)
4326 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4327 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4328 INT nScrollPosHeight = 0;
4329 INT nScrollPosWidth = 0;
4330 SCROLLINFO scrollInfo;
4332 BOOL bRedraw = FALSE;
4334 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
4335 scrollInfo.cbSize = sizeof(SCROLLINFO);
4336 scrollInfo.fMask = SIF_POS;
4338 /* ALWAYS bPartial == FALSE, FOR NOW! */
4340 rcItem.left = LVIR_BOUNDS;
4341 if (LISTVIEW_GetItemRect(hwnd, nItem, &rcItem) != FALSE)
4343 if (rcItem.left < infoPtr->rcList.left)
4345 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4349 if (uView == LVS_LIST)
4351 nScrollPosWidth = infoPtr->nItemWidth;
4352 rcItem.left += infoPtr->rcList.left;
4354 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4356 nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
4357 rcItem.left += infoPtr->rcList.left;
4360 /* When in LVS_REPORT view, the scroll position should
4362 if (nScrollPosWidth != 0)
4364 if (rcItem.left % nScrollPosWidth == 0)
4366 scrollInfo.nPos += rcItem.left / nScrollPosWidth;
4370 scrollInfo.nPos += rcItem.left / nScrollPosWidth - 1;
4373 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
4377 else if (rcItem.right > infoPtr->rcList.right)
4379 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4383 if (uView == LVS_LIST)
4385 rcItem.right -= infoPtr->rcList.right;
4386 nScrollPosWidth = infoPtr->nItemWidth;
4388 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4390 rcItem.right -= infoPtr->rcList.right;
4391 nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
4394 /* When in LVS_REPORT view, the scroll position should
4396 if (nScrollPosWidth != 0)
4398 if (rcItem.right % nScrollPosWidth == 0)
4400 scrollInfo.nPos += rcItem.right / nScrollPosWidth;
4404 scrollInfo.nPos += rcItem.right / nScrollPosWidth + 1;
4407 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
4412 if (rcItem.top < infoPtr->rcList.top)
4416 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4418 if (uView == LVS_REPORT)
4420 rcItem.top -= infoPtr->rcList.top;
4421 nScrollPosHeight = infoPtr->nItemHeight;
4423 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
4425 nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
4426 rcItem.top += infoPtr->rcList.top;
4429 if (rcItem.top % nScrollPosHeight == 0)
4431 scrollInfo.nPos += rcItem.top / nScrollPosHeight;
4435 scrollInfo.nPos += rcItem.top / nScrollPosHeight - 1;
4438 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
4441 else if (rcItem.bottom > infoPtr->rcList.bottom)
4445 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4447 if (uView == LVS_REPORT)
4449 rcItem.bottom -= infoPtr->rcList.bottom;
4450 nScrollPosHeight = infoPtr->nItemHeight;
4452 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
4454 nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
4455 rcItem.bottom -= infoPtr->rcList.bottom;
4458 if (rcItem.bottom % nScrollPosHeight == 0)
4460 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight;
4464 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight + 1;
4467 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
4473 InvalidateRect(hwnd,NULL,TRUE);
4479 * Retrieves the nearest item, given a position and a direction.
4482 * [I] HWND : window handle
4483 * [I] POINT : start position
4484 * [I] UINT : direction
4487 * Item index if successdful, -1 otherwise.
4489 static INT LISTVIEW_GetNearestItem(HWND hwnd, POINT pt, UINT vkDirection)
4491 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4492 LVHITTESTINFO lvHitTestInfo;
4496 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
4498 ZeroMemory(&lvHitTestInfo, sizeof(LVHITTESTINFO));
4499 LISTVIEW_GetOrigin(hwnd, &lvHitTestInfo.pt);
4500 lvHitTestInfo.pt.x += pt.x;
4501 lvHitTestInfo.pt.y += pt.y;
4505 if (vkDirection == VK_DOWN)
4507 lvHitTestInfo.pt.y += infoPtr->nItemHeight;
4509 else if (vkDirection == VK_UP)
4511 lvHitTestInfo.pt.y -= infoPtr->nItemHeight;
4513 else if (vkDirection == VK_LEFT)
4515 lvHitTestInfo.pt.x -= infoPtr->nItemWidth;
4517 else if (vkDirection == VK_RIGHT)
4519 lvHitTestInfo.pt.x += infoPtr->nItemWidth;
4522 if (PtInRect(&rcView, lvHitTestInfo.pt) == FALSE)
4528 nItem = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo, TRUE);
4532 while (nItem == -1);
4540 * Searches for an item with specific characteristics.
4543 * [I] HWND : window handle
4544 * [I] INT : base item index
4545 * [I] LPLVFINDINFO : item information to look for
4548 * SUCCESS : index of item
4551 static LRESULT LISTVIEW_FindItem(HWND hwnd, INT nStart,
4552 LPLVFINDINFO lpFindInfo)
4554 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4556 CHAR szDispText[DISP_TEXT_SIZE];
4560 INT nLast = GETITEMCOUNT(infoPtr);
4562 if ((nItem >= -1) && (lpFindInfo != NULL))
4564 ZeroMemory(&lvItem, sizeof(LVITEMA));
4566 if (lpFindInfo->flags & LVFI_PARAM)
4568 lvItem.mask |= LVIF_PARAM;
4571 if (lpFindInfo->flags & LVFI_STRING)
4573 lvItem.mask |= LVIF_TEXT;
4574 lvItem.pszText = szDispText;
4575 lvItem.cchTextMax = DISP_TEXT_SIZE;
4578 if (lpFindInfo->flags & LVFI_PARTIAL)
4580 lvItem.mask |= LVIF_TEXT;
4581 lvItem.pszText = szDispText;
4582 lvItem.cchTextMax = DISP_TEXT_SIZE;
4585 if (lpFindInfo->flags & LVFI_WRAP)
4590 if (lpFindInfo->flags & LVFI_NEARESTXY)
4592 ptItem.x = lpFindInfo->pt.x;
4593 ptItem.y = lpFindInfo->pt.y;
4598 while (nItem < nLast)
4600 if (lpFindInfo->flags & LVFI_NEARESTXY)
4602 nItem = LISTVIEW_GetNearestItem(hwnd, ptItem,
4603 lpFindInfo->vkDirection);
4606 /* get position of the new item index */
4607 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) == FALSE)
4618 lvItem.iItem = nItem;
4619 lvItem.iSubItem = 0;
4620 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
4622 if (lvItem.mask & LVIF_TEXT)
4624 if (lpFindInfo->flags & LVFI_PARTIAL)
4626 if (strstr(lvItem.pszText, lpFindInfo->psz) == NULL)
4631 if (strcmp(lvItem.pszText, lpFindInfo->psz) != 0)
4636 if (lvItem.mask & LVIF_PARAM)
4638 if (lpFindInfo->lParam != lvItem.lParam)
4664 * Retrieves the background color of the listview control.
4667 * [I] HWND : window handle
4670 * COLORREF associated with the background.
4672 static LRESULT LISTVIEW_GetBkColor(HWND hwnd)
4674 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4676 return infoPtr->clrBk;
4681 * Retrieves the background image of the listview control.
4684 * [I] HWND : window handle
4685 * [O] LPLVMKBIMAGE : background image attributes
4691 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
4693 /* FIXME (listview, "empty stub!\n"); */
4699 * Retrieves the callback mask.
4702 * [I] HWND : window handle
4707 static UINT LISTVIEW_GetCallbackMask(HWND hwnd)
4709 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4711 return infoPtr->uCallbackMask;
4716 * Retrieves column attributes.
4719 * [I] HWND : window handle
4720 * [I] INT : column index
4721 * [IO] LPLVCOLUMNA : column information
4727 static LRESULT LISTVIEW_GetColumnA(HWND hwnd, INT nItem, LPLVCOLUMNA lpColumn)
4729 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4731 BOOL bResult = FALSE;
4733 if (lpColumn != NULL)
4735 /* initialize memory */
4736 ZeroMemory(&hdi, sizeof(HDITEMA));
4738 if (lpColumn->mask & LVCF_FMT)
4740 hdi.mask |= HDI_FORMAT;
4743 if (lpColumn->mask & LVCF_WIDTH)
4745 hdi.mask |= HDI_WIDTH;
4748 if (lpColumn->mask & LVCF_TEXT)
4750 hdi.mask |= HDI_TEXT;
4751 hdi.cchTextMax = lpColumn->cchTextMax;
4752 hdi.pszText = lpColumn->pszText;
4755 if (lpColumn->mask & LVCF_IMAGE)
4757 hdi.mask |= HDI_IMAGE;
4760 if (lpColumn->mask & LVCF_ORDER)
4762 hdi.mask |= HDI_ORDER;
4765 bResult = Header_GetItemA(infoPtr->hwndHeader, nItem, &hdi);
4766 if (bResult != FALSE)
4768 if (lpColumn->mask & LVCF_FMT)
4772 if (hdi.fmt & HDF_LEFT)
4774 lpColumn->fmt |= LVCFMT_LEFT;
4776 else if (hdi.fmt & HDF_RIGHT)
4778 lpColumn->fmt |= LVCFMT_RIGHT;
4780 else if (hdi.fmt & HDF_CENTER)
4782 lpColumn->fmt |= LVCFMT_CENTER;
4785 if (hdi.fmt & HDF_IMAGE)
4787 lpColumn->fmt |= LVCFMT_COL_HAS_IMAGES;
4790 if (hdi.fmt & HDF_BITMAP_ON_RIGHT)
4792 lpColumn->fmt |= LVCFMT_BITMAP_ON_RIGHT;
4796 if (lpColumn->mask & LVCF_WIDTH)
4798 lpColumn->cx = hdi.cxy;
4801 if (lpColumn->mask & LVCF_IMAGE)
4803 lpColumn->iImage = hdi.iImage;
4806 if (lpColumn->mask & LVCF_ORDER)
4808 lpColumn->iOrder = hdi.iOrder;
4816 /* LISTVIEW_GetColumnW */
4819 static LRESULT LISTVIEW_GetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
4821 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
4828 for (i = 0; i < iCount; i++)
4836 * Retrieves the column width.
4839 * [I] HWND : window handle
4840 * [I] int : column index
4843 * SUCCESS : column width
4846 static LRESULT LISTVIEW_GetColumnWidth(HWND hwnd, INT nColumn)
4848 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4849 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4850 INT nColumnWidth = 0;
4853 if (uView == LVS_LIST)
4855 nColumnWidth = infoPtr->nItemWidth;
4857 else if (uView == LVS_REPORT)
4859 /* get column width from header */
4860 ZeroMemory(&hdi, sizeof(HDITEMA));
4861 hdi.mask = HDI_WIDTH;
4862 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdi) != FALSE)
4864 nColumnWidth = hdi.cxy;
4868 return nColumnWidth;
4873 * In list or report display mode, retrieves the number of items that can fit
4874 * vertically in the visible area. In icon or small icon display mode,
4875 * retrieves the total number of visible items.
4878 * [I] HWND : window handle
4881 * Number of fully visible items.
4883 static LRESULT LISTVIEW_GetCountPerPage(HWND hwnd)
4885 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4886 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4889 if (uView == LVS_LIST)
4891 if (infoPtr->rcList.right > infoPtr->nItemWidth)
4893 nItemCount = LISTVIEW_GetCountPerRow(hwnd) *
4894 LISTVIEW_GetCountPerColumn(hwnd);
4897 else if (uView == LVS_REPORT)
4899 nItemCount = LISTVIEW_GetCountPerColumn(hwnd);
4903 nItemCount = GETITEMCOUNT(infoPtr);
4909 /* LISTVIEW_GetEditControl */
4913 * Retrieves the extended listview style.
4916 * [I] HWND : window handle
4919 * SUCCESS : previous style
4922 static LRESULT LISTVIEW_GetExtendedListViewStyle(HWND hwnd)
4924 LISTVIEW_INFO *infoPtr;
4926 /* make sure we can get the listview info */
4927 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
4930 return (infoPtr->dwExStyle);
4935 * Retrieves the handle to the header control.
4938 * [I] HWND : window handle
4943 static LRESULT LISTVIEW_GetHeader(HWND hwnd)
4945 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4947 return infoPtr->hwndHeader;
4950 /* LISTVIEW_GetHotCursor */
4954 * Returns the time that the mouse cursor must hover over an item
4955 * before it is selected.
4958 * [I] HWND : window handle
4961 * Returns the previously set hover time or (DWORD)-1 to indicate that the
4962 * hover time is set to the default hover time.
4964 static LRESULT LISTVIEW_GetHoverTime(HWND hwnd)
4966 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4968 return infoPtr->dwHoverTime;
4973 * Retrieves an image list handle.
4976 * [I] HWND : window handle
4977 * [I] INT : image list identifier
4980 * SUCCESS : image list handle
4983 static LRESULT LISTVIEW_GetImageList(HWND hwnd, INT nImageList)
4985 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4986 HIMAGELIST himl = NULL;
4991 himl = infoPtr->himlNormal;
4994 himl = infoPtr->himlSmall;
4997 himl = infoPtr->himlState;
5001 return (LRESULT)himl;
5004 /* LISTVIEW_GetISearchString */
5008 * Retrieves item attributes.
5011 * [I] HWND : window handle
5012 * [IO] LPLVITEMA : item info
5013 * [I] internal : if true then we will use tricks that avoid copies
5014 * but are not compatible with the regular interface
5020 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem, BOOL internal)
5022 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5023 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
5024 NMLVDISPINFOA dispInfo;
5025 LISTVIEW_SUBITEM *lpSubItem;
5026 LISTVIEW_ITEM *lpItem;
5030 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5031 /* In the following:
5032 * lpLVItem describes the information requested by the user
5033 * lpItem/lpSubItem is what we have
5034 * dispInfo is a structure we use to request the missing
5035 * information from the application
5038 TRACE("(hwnd=%x, lpLVItem=%p)\n", hwnd, lpLVItem);
5040 if ((lpLVItem == NULL) ||
5041 (lpLVItem->iItem < 0) ||
5042 (lpLVItem->iItem >= GETITEMCOUNT(infoPtr))
5046 if (lStyle & LVS_OWNERDATA)
5048 if (lpLVItem->mask & ~LVIF_STATE)
5050 dispInfo.hdr.hwndFrom = hwnd;
5051 dispInfo.hdr.idFrom = lCtrlId;
5052 dispInfo.hdr.code = LVN_GETDISPINFOA;
5053 memcpy(&dispInfo.item,lpLVItem,sizeof(LVITEMA));
5055 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
5056 memcpy(lpLVItem,&dispInfo.item,sizeof(LVITEMA));
5059 if ((lpLVItem->mask & LVIF_STATE)&&(lpLVItem->iSubItem == 0))
5061 lpLVItem->state = 0;
5062 if (infoPtr->nFocusedItem == lpLVItem->iItem)
5063 lpLVItem->state |= LVIS_FOCUSED;
5064 if (LISTVIEW_IsSelected(hwnd,lpLVItem->iItem))
5065 lpLVItem->state |= LVIS_SELECTED;
5072 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
5073 if (hdpaSubItems == NULL)
5076 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
5080 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
5081 if (lpLVItem->iSubItem == 0)
5083 piImage=&lpItem->iImage;
5084 ppszText=&lpItem->pszText;
5085 if ((infoPtr->uCallbackMask != 0) && (lpLVItem->mask & LVIF_STATE))
5087 dispInfo.item.mask |= LVIF_STATE;
5088 dispInfo.item.stateMask = infoPtr->uCallbackMask;
5093 lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem);
5094 if (lpSubItem != NULL)
5096 piImage=&lpSubItem->iImage;
5097 ppszText=&lpSubItem->pszText;
5106 if ((lpLVItem->mask & LVIF_IMAGE) &&
5107 ((piImage==NULL) || (*piImage == I_IMAGECALLBACK)))
5109 dispInfo.item.mask |= LVIF_IMAGE;
5112 if ((lpLVItem->mask & LVIF_TEXT) &&
5113 ((ppszText==NULL) || (*ppszText == LPSTR_TEXTCALLBACKA)))
5115 dispInfo.item.mask |= LVIF_TEXT;
5116 dispInfo.item.pszText = lpLVItem->pszText;
5117 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
5120 if (dispInfo.item.mask != 0)
5122 /* We don't have all the requested info, query the application */
5123 dispInfo.hdr.hwndFrom = hwnd;
5124 dispInfo.hdr.idFrom = lCtrlId;
5125 dispInfo.hdr.code = LVN_GETDISPINFOA;
5126 dispInfo.item.iItem = lpLVItem->iItem;
5127 dispInfo.item.iSubItem = lpLVItem->iSubItem;
5128 dispInfo.item.lParam = lpItem->lParam;
5129 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
5132 if (dispInfo.item.mask & LVIF_IMAGE)
5134 lpLVItem->iImage = dispInfo.item.iImage;
5136 else if (lpLVItem->mask & LVIF_IMAGE)
5138 lpLVItem->iImage = *piImage;
5141 if (dispInfo.item.mask & LVIF_PARAM)
5143 lpLVItem->lParam = dispInfo.item.lParam;
5145 else if (lpLVItem->mask & LVIF_PARAM)
5147 lpLVItem->lParam = lpItem->lParam;
5150 if (dispInfo.item.mask & LVIF_TEXT)
5152 if ((dispInfo.item.mask & LVIF_DI_SETITEM) && (ppszText != NULL))
5154 Str_SetPtrA(ppszText, dispInfo.item.pszText);
5156 /* If lpLVItem->pszText==dispInfo.item.pszText a copy is unnecessary, but */
5157 /* some apps give a new pointer in ListView_Notify so we can't be sure. */
5158 if (lpLVItem->pszText!=dispInfo.item.pszText) {
5159 lstrcpynA(lpLVItem->pszText, dispInfo.item.pszText, lpLVItem->cchTextMax);
5162 else if (lpLVItem->mask & LVIF_TEXT)
5166 lpLVItem->pszText=*ppszText;
5168 lstrcpynA(lpLVItem->pszText, *ppszText, lpLVItem->cchTextMax);
5172 if (lpLVItem->iSubItem == 0)
5174 if (dispInfo.item.mask & LVIF_STATE)
5176 lpLVItem->state = lpItem->state;
5177 lpLVItem->state &= ~dispInfo.item.stateMask;
5178 lpLVItem->state |= (dispInfo.item.state & dispInfo.item.stateMask);
5180 lpLVItem->state &= ~LVIS_SELECTED;
5181 if ((dispInfo.item.stateMask & LVIS_SELECTED) &&
5182 (LISTVIEW_IsSelected(hwnd,dispInfo.item.iItem)))
5183 lpLVItem->state |= LVIS_SELECTED;
5185 else if (lpLVItem->mask & LVIF_STATE)
5187 lpLVItem->state = lpItem->state & lpLVItem->stateMask;
5189 lpLVItem->state &= ~LVIS_SELECTED;
5190 if ((lpLVItem->stateMask & LVIS_SELECTED) &&
5191 (LISTVIEW_IsSelected(hwnd,lpLVItem->iItem)))
5192 lpLVItem->state |= LVIS_SELECTED;
5195 if (lpLVItem->mask & LVIF_PARAM)
5197 lpLVItem->lParam = lpItem->lParam;
5200 if (lpLVItem->mask & LVIF_INDENT)
5202 lpLVItem->iIndent = lpItem->iIndent;
5209 /* LISTVIEW_GetItemW */
5210 /* LISTVIEW_GetHotCursor */
5214 * Retrieves the index of the hot item.
5217 * [I] HWND : window handle
5220 * SUCCESS : hot item index
5221 * FAILURE : -1 (no hot item)
5223 static LRESULT LISTVIEW_GetHotItem(HWND hwnd)
5225 LISTVIEW_INFO *infoPtr;
5227 /* make sure we can get the listview info */
5228 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5231 return (infoPtr->nHotItem);
5234 /* LISTVIEW_GetHoverTime */
5238 * Retrieves the number of items in the listview control.
5241 * [I] HWND : window handle
5246 static LRESULT LISTVIEW_GetItemCount(HWND hwnd)
5248 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5250 return GETITEMCOUNT(infoPtr);
5255 * Retrieves the position (upper-left) of the listview control item.
5258 * [I] HWND : window handle
5259 * [I] INT : item index
5260 * [O] LPPOINT : coordinate information
5266 static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem,
5267 LPPOINT lpptPosition)
5269 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5270 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5271 BOOL bResult = FALSE;
5273 LISTVIEW_ITEM *lpItem;
5274 INT nCountPerColumn;
5277 TRACE("(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd, nItem,
5280 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
5281 (lpptPosition != NULL))
5283 if (uView == LVS_LIST)
5286 nItem = nItem - ListView_GetTopIndex(hwnd);
5287 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
5290 nRow = nItem % nCountPerColumn;
5293 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
5294 lpptPosition->y = 0;
5298 lpptPosition->x = (nItem / nCountPerColumn -1) * infoPtr->nItemWidth;
5299 lpptPosition->y = (nRow + nCountPerColumn) * infoPtr->nItemHeight;
5304 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
5305 lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight;
5308 else if (uView == LVS_REPORT)
5311 lpptPosition->x = REPORT_MARGINX;
5312 lpptPosition->y = ((nItem - ListView_GetTopIndex(hwnd)) *
5313 infoPtr->nItemHeight) + infoPtr->rcList.top;
5317 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
5318 if (hdpaSubItems != NULL)
5320 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
5324 lpptPosition->x = lpItem->ptPosition.x;
5325 lpptPosition->y = lpItem->ptPosition.y;
5335 * Retrieves the bounding rectangle for a listview control item.
5338 * [I] HWND : window handle
5339 * [I] INT : item index
5340 * [IO] LPRECT : bounding rectangle coordinates
5346 static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc)
5348 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5349 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5350 BOOL bResult = FALSE;
5361 TRACE("(hwnd=%x, nItem=%d, lprc=%p)\n", hwnd, nItem, lprc);
5363 if (uView & LVS_REPORT)
5365 ZeroMemory(&lvItem, sizeof(LVITEMA));
5366 lvItem.mask = LVIF_INDENT;
5367 lvItem.iItem = nItem;
5368 lvItem.iSubItem = 0;
5369 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
5372 if (lvItem.iIndent>0 && infoPtr->iconSize.cx > 0)
5374 nIndent = infoPtr->iconSize.cx * lvItem.iIndent;
5382 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL))
5384 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) != FALSE)
5389 if (uView == LVS_ICON)
5391 if (infoPtr->himlNormal != NULL)
5393 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5396 lprc->left = ptItem.x + ptOrigin.x;
5397 lprc->top = ptItem.y + ptOrigin.y;
5398 lprc->right = lprc->left + infoPtr->iconSize.cx;
5399 lprc->bottom = (lprc->top + infoPtr->iconSize.cy +
5400 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
5404 else if (uView == LVS_SMALLICON)
5406 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5409 lprc->left = ptItem.x + ptOrigin.x;
5410 lprc->top = ptItem.y + ptOrigin.y;
5411 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5413 if (infoPtr->himlState != NULL)
5414 lprc->left += infoPtr->iconSize.cx;
5416 if (infoPtr->himlSmall != NULL)
5417 lprc->right = lprc->left + infoPtr->iconSize.cx;
5419 lprc->right = lprc->left;
5425 lprc->left = ptItem.x;
5426 if (uView & LVS_REPORT)
5427 lprc->left += nIndent;
5428 lprc->top = ptItem.y;
5429 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5431 if (infoPtr->himlState != NULL)
5433 lprc->left += infoPtr->iconSize.cx;
5436 if (infoPtr->himlSmall != NULL)
5438 lprc->right = lprc->left + infoPtr->iconSize.cx;
5442 lprc->right = lprc->left;
5448 if (uView == LVS_ICON)
5450 if (infoPtr->himlNormal != NULL)
5452 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5455 lprc->left = ptItem.x + ptOrigin.x;
5456 lprc->top = (ptItem.y + ptOrigin.y + infoPtr->iconSize.cy +
5457 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
5458 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5459 if (infoPtr->iconSpacing.cx - nLabelWidth > 1)
5461 lprc->left += (infoPtr->iconSpacing.cx - nLabelWidth) / 2;
5462 lprc->right = lprc->left + nLabelWidth;
5467 lprc->right = lprc->left + infoPtr->iconSpacing.cx - 1;
5471 hOldFont = SelectObject(hdc, infoPtr->hFont);
5472 GetTextMetricsA(hdc, &tm);
5473 lprc->bottom = lprc->top + tm.tmHeight + HEIGHT_PADDING;
5474 SelectObject(hdc, hOldFont);
5475 ReleaseDC(hwnd, hdc);
5479 else if (uView == LVS_SMALLICON)
5481 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5484 nLeftPos = lprc->left = ptItem.x + ptOrigin.x;
5485 lprc->top = ptItem.y + ptOrigin.y;
5486 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5488 if (infoPtr->himlState != NULL)
5490 lprc->left += infoPtr->iconSize.cx;
5493 if (infoPtr->himlSmall != NULL)
5495 lprc->left += infoPtr->iconSize.cx;
5498 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5499 nLabelWidth += TRAILING_PADDING;
5500 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5502 lprc->right = lprc->left + nLabelWidth;
5506 lprc->right = nLeftPos + infoPtr->nItemWidth;
5513 if (uView & LVS_REPORT)
5514 nLeftPos = lprc->left = ptItem.x + nIndent;
5516 nLeftPos = lprc->left = ptItem.x;
5517 lprc->top = ptItem.y;
5518 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5520 if (infoPtr->himlState != NULL)
5522 lprc->left += infoPtr->iconSize.cx;
5525 if (infoPtr->himlSmall != NULL)
5527 lprc->left += infoPtr->iconSize.cx;
5530 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5531 nLabelWidth += TRAILING_PADDING;
5532 if (infoPtr->himlSmall)
5533 nLabelWidth += IMAGE_PADDING;
5534 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5536 lprc->right = lprc->left + nLabelWidth;
5540 lprc->right = nLeftPos + infoPtr->nItemWidth;
5546 if (uView == LVS_ICON)
5548 if (infoPtr->himlNormal != NULL)
5550 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5553 lprc->left = ptItem.x + ptOrigin.x;
5554 lprc->top = ptItem.y + ptOrigin.y;
5555 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
5556 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
5560 else if (uView == LVS_SMALLICON)
5562 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5565 lprc->left = ptItem.x + ptOrigin.x;
5566 lprc->right = lprc->left;
5567 lprc->top = ptItem.y + ptOrigin.y;
5568 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5569 if (infoPtr->himlState != NULL)
5570 lprc->right += infoPtr->iconSize.cx;
5571 if (infoPtr->himlSmall != NULL)
5572 lprc->right += infoPtr->iconSize.cx;
5574 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5575 nLabelWidth += TRAILING_PADDING;
5576 if (infoPtr->himlSmall)
5577 nLabelWidth += IMAGE_PADDING;
5578 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
5580 lprc->right += nLabelWidth;
5584 lprc->right = lprc->left + infoPtr->nItemWidth;
5591 lprc->left = ptItem.x;
5592 if (!(infoPtr->dwExStyle&LVS_EX_FULLROWSELECT) && uView&LVS_REPORT)
5593 lprc->left += nIndent;
5594 lprc->right = lprc->left;
5595 lprc->top = ptItem.y;
5596 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5598 if (infoPtr->dwExStyle & LVS_EX_FULLROWSELECT)
5601 int nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
5602 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
5604 lprc->right = max(lprc->left, br.right - REPORT_MARGINX);
5608 if (infoPtr->himlState != NULL)
5610 lprc->right += infoPtr->iconSize.cx;
5613 if (infoPtr->himlSmall != NULL)
5615 lprc->right += infoPtr->iconSize.cx;
5618 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5619 nLabelWidth += TRAILING_PADDING;
5620 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
5622 lprc->right += nLabelWidth;
5626 lprc->right = lprc->left + infoPtr->nItemWidth;
5632 case LVIR_SELECTBOUNDS:
5633 if (uView == LVS_ICON)
5635 if (infoPtr->himlNormal != NULL)
5637 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5640 lprc->left = ptItem.x + ptOrigin.x;
5641 lprc->top = ptItem.y + ptOrigin.y;
5642 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
5643 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
5647 else if (uView == LVS_SMALLICON)
5649 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5652 nLeftPos= lprc->left = ptItem.x + ptOrigin.x;
5653 lprc->top = ptItem.y + ptOrigin.y;
5654 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5656 if (infoPtr->himlState != NULL)
5658 lprc->left += infoPtr->iconSize.cx;
5661 lprc->right = lprc->left;
5663 if (infoPtr->himlSmall != NULL)
5665 lprc->right += infoPtr->iconSize.cx;
5668 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5669 nLabelWidth += TRAILING_PADDING;
5670 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5672 lprc->right += nLabelWidth;
5676 lprc->right = nLeftPos + infoPtr->nItemWidth;
5683 if (!(infoPtr->dwExStyle&LVS_EX_FULLROWSELECT) && (uView&LVS_REPORT))
5684 nLeftPos = lprc->left = ptItem.x + nIndent;
5686 nLeftPos = lprc->left = ptItem.x;
5687 lprc->top = ptItem.y;
5688 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5690 if (infoPtr->himlState != NULL)
5692 lprc->left += infoPtr->iconSize.cx;
5695 lprc->right = lprc->left;
5697 if (infoPtr->dwExStyle & LVS_EX_FULLROWSELECT)
5700 int nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
5701 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
5703 lprc->right = max(lprc->left, br.right - REPORT_MARGINX);
5707 if (infoPtr->himlSmall != NULL)
5709 lprc->right += infoPtr->iconSize.cx;
5712 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5713 nLabelWidth += TRAILING_PADDING;
5714 if (infoPtr->himlSmall)
5715 nLabelWidth += IMAGE_PADDING;
5716 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5718 lprc->right += nLabelWidth;
5722 lprc->right = nLeftPos + infoPtr->nItemWidth;
5735 * Retrieves the width of a label.
5738 * [I] HWND : window handle
5741 * SUCCESS : string width (in pixels)
5744 static INT LISTVIEW_GetLabelWidth(HWND hwnd, INT nItem)
5746 CHAR szDispText[DISP_TEXT_SIZE];
5747 INT nLabelWidth = 0;
5750 TRACE("(hwnd=%x, nItem=%d)\n", hwnd, nItem);
5752 ZeroMemory(&lvItem, sizeof(LVITEMA));
5753 lvItem.mask = LVIF_TEXT;
5754 lvItem.iItem = nItem;
5755 lvItem.cchTextMax = DISP_TEXT_SIZE;
5756 lvItem.pszText = szDispText;
5757 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
5759 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
5767 * Retrieves the spacing between listview control items.
5770 * [I] HWND : window handle
5771 * [I] BOOL : flag for small or large icon
5774 * Horizontal + vertical spacing
5776 static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall)
5778 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5781 if (bSmall == FALSE)
5783 lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
5787 /* TODO: need to store width of smallicon item */
5788 lResult = MAKELONG(0, infoPtr->nItemHeight);
5796 * Retrieves the state of a listview control item.
5799 * [I] HWND : window handle
5800 * [I] INT : item index
5801 * [I] UINT : state mask
5804 * State specified by the mask.
5806 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask)
5808 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5812 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5814 ZeroMemory(&lvItem, sizeof(LVITEMA));
5815 lvItem.iItem = nItem;
5816 lvItem.stateMask = uMask;
5817 lvItem.mask = LVIF_STATE;
5818 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
5820 uState = lvItem.state;
5829 * Retrieves the text of a listview control item or subitem.
5832 * [I] HWND : window handle
5833 * [I] INT : item index
5834 * [IO] LPLVITEMA : item information
5837 * SUCCESS : string length
5840 static LRESULT LISTVIEW_GetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5842 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5845 if (lpLVItem != NULL)
5847 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5849 lpLVItem->mask = LVIF_TEXT;
5850 lpLVItem->iItem = nItem;
5851 if (LISTVIEW_GetItemA(hwnd, lpLVItem, FALSE) != FALSE)
5853 nLength = lstrlenA(lpLVItem->pszText);
5863 * Searches for an item based on properties + relationships.
5866 * [I] HWND : window handle
5867 * [I] INT : item index
5868 * [I] INT : relationship flag
5871 * SUCCESS : item index
5874 static LRESULT LISTVIEW_GetNextItem(HWND hwnd, INT nItem, UINT uFlags)
5876 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5877 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5879 LVFINDINFO lvFindInfo;
5880 INT nCountPerColumn;
5883 if ((nItem >= -1) && (nItem < GETITEMCOUNT(infoPtr)))
5885 ZeroMemory(&lvFindInfo, sizeof(LVFINDINFO));
5887 if (uFlags & LVNI_CUT)
5890 if (uFlags & LVNI_DROPHILITED)
5891 uMask |= LVIS_DROPHILITED;
5893 if (uFlags & LVNI_FOCUSED)
5894 uMask |= LVIS_FOCUSED;
5896 if (uFlags & LVNI_SELECTED)
5897 uMask |= LVIS_SELECTED;
5899 if (uFlags & LVNI_ABOVE)
5901 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
5906 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5912 lvFindInfo.flags = LVFI_NEARESTXY;
5913 lvFindInfo.vkDirection = VK_UP;
5914 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5915 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5917 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5922 else if (uFlags & LVNI_BELOW)
5924 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
5926 while (nItem < GETITEMCOUNT(infoPtr))
5929 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5935 lvFindInfo.flags = LVFI_NEARESTXY;
5936 lvFindInfo.vkDirection = VK_DOWN;
5937 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5938 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5940 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5945 else if (uFlags & LVNI_TOLEFT)
5947 if (uView == LVS_LIST)
5949 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
5950 while (nItem - nCountPerColumn >= 0)
5952 nItem -= nCountPerColumn;
5953 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5957 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
5959 lvFindInfo.flags = LVFI_NEARESTXY;
5960 lvFindInfo.vkDirection = VK_LEFT;
5961 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5962 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5964 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5969 else if (uFlags & LVNI_TORIGHT)
5971 if (uView == LVS_LIST)
5973 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
5974 while (nItem + nCountPerColumn < GETITEMCOUNT(infoPtr))
5976 nItem += nCountPerColumn;
5977 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5981 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
5983 lvFindInfo.flags = LVFI_NEARESTXY;
5984 lvFindInfo.vkDirection = VK_RIGHT;
5985 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5986 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5988 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5997 /* search by index */
5998 for (i = nItem; i < GETITEMCOUNT(infoPtr); i++)
6000 if ((ListView_GetItemState(hwnd, i, uMask) & uMask) == uMask)
6009 /* LISTVIEW_GetNumberOfWorkAreas */
6013 * Retrieves the origin coordinates when in icon or small icon display mode.
6016 * [I] HWND : window handle
6017 * [O] LPPOINT : coordinate information
6023 static LRESULT LISTVIEW_GetOrigin(HWND hwnd, LPPOINT lpptOrigin)
6025 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6026 UINT uView = lStyle & LVS_TYPEMASK;
6027 BOOL bResult = FALSE;
6029 TRACE("(hwnd=%x, lpptOrigin=%p)\n", hwnd, lpptOrigin);
6031 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
6033 SCROLLINFO scrollInfo;
6034 ZeroMemory(lpptOrigin, sizeof(POINT));
6035 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
6036 scrollInfo.cbSize = sizeof(SCROLLINFO);
6038 if (lStyle & WS_HSCROLL)
6040 scrollInfo.fMask = SIF_POS;
6041 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
6043 lpptOrigin->x = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
6047 if (lStyle & WS_VSCROLL)
6049 scrollInfo.fMask = SIF_POS;
6050 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
6052 lpptOrigin->y = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
6064 * Retrieves the number of items that are marked as selected.
6067 * [I] HWND : window handle
6070 * Number of items selected.
6072 static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd)
6075 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6076 INT nSelectedCount = 0;
6079 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
6081 if (ListView_GetItemState(hwnd, i, LVIS_SELECTED) & LVIS_SELECTED)
6087 return nSelectedCount;
6092 * Retrieves item index that marks the start of a multiple selection.
6095 * [I] HWND : window handle
6098 * Index number or -1 if there is no selection mark.
6100 static LRESULT LISTVIEW_GetSelectionMark(HWND hwnd)
6102 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6104 return infoPtr->nSelectionMark;
6109 * Retrieves the width of a string.
6112 * [I] HWND : window handle
6115 * SUCCESS : string width (in pixels)
6118 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText)
6120 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6121 HFONT hFont, hOldFont;
6125 ZeroMemory(&stringSize, sizeof(SIZE));
6126 if (lpszText != NULL && lpszText != (LPCSTR)-1)
6128 hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
6130 hOldFont = SelectObject(hdc, hFont);
6131 GetTextExtentPointA(hdc, lpszText, lstrlenA(lpszText), &stringSize);
6132 SelectObject(hdc, hOldFont);
6133 ReleaseDC(hwnd, hdc);
6136 return stringSize.cx;
6141 * Retrieves the text backgound color.
6144 * [I] HWND : window handle
6147 * COLORREF associated with the the background.
6149 static LRESULT LISTVIEW_GetTextBkColor(HWND hwnd)
6151 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
6153 return infoPtr->clrTextBk;
6158 * Retrieves the text color.
6161 * [I] HWND : window handle
6164 * COLORREF associated with the text.
6166 static LRESULT LISTVIEW_GetTextColor(HWND hwnd)
6168 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
6170 return infoPtr->clrText;
6175 * Determines which section of the item was selected (if any).
6178 * [I] HWND : window handle
6179 * [IO] LPLVHITTESTINFO : hit test information
6180 * [I] subitem : fill out iSubItem.
6183 * SUCCESS : item index
6186 static INT LISTVIEW_HitTestItem(
6187 HWND hwnd, LPLVHITTESTINFO lpHitTestInfo, BOOL subitem
6189 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6191 INT i,topindex,bottomindex;
6192 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6193 UINT uView = lStyle & LVS_TYPEMASK;
6196 TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpHitTestInfo->pt.x,
6197 lpHitTestInfo->pt.y);
6199 topindex = ListView_GetTopIndex(hwnd);
6200 if (uView == LVS_REPORT)
6202 bottomindex = topindex + LISTVIEW_GetCountPerColumn(hwnd) + 1;
6203 bottomindex = min(bottomindex,GETITEMCOUNT(infoPtr));
6207 bottomindex = GETITEMCOUNT(infoPtr);
6210 for (i = topindex; i < bottomindex; i++)
6212 rcItem.left = LVIR_BOUNDS;
6213 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
6215 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
6217 rcItem.left = LVIR_ICON;
6218 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
6220 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
6222 lpHitTestInfo->flags = LVHT_ONITEMICON;
6223 lpHitTestInfo->iItem = i;
6224 if (subitem) lpHitTestInfo->iSubItem = 0;
6229 rcItem.left = LVIR_LABEL;
6230 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
6232 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
6234 lpHitTestInfo->flags = LVHT_ONITEMLABEL;
6235 lpHitTestInfo->iItem = i;
6236 if (subitem) lpHitTestInfo->iSubItem = 0;
6241 lpHitTestInfo->flags = LVHT_ONITEMSTATEICON;
6242 lpHitTestInfo->iItem = i;
6243 if (subitem) lpHitTestInfo->iSubItem = 0;
6249 lpHitTestInfo->flags = LVHT_NOWHERE;
6256 * Determines which listview item is located at the specified position.
6259 * [I] HWND : window handle
6260 * [IO} LPLVHITTESTINFO : hit test information
6263 * SUCCESS : item index
6266 static LRESULT LISTVIEW_HitTest(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
6268 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6271 lpHitTestInfo->flags = 0;
6273 if (infoPtr->rcList.left > lpHitTestInfo->pt.x)
6275 lpHitTestInfo->flags = LVHT_TOLEFT;
6277 else if (infoPtr->rcList.right < lpHitTestInfo->pt.x)
6279 lpHitTestInfo->flags = LVHT_TORIGHT;
6281 if (infoPtr->rcList.top > lpHitTestInfo->pt.y)
6283 lpHitTestInfo->flags |= LVHT_ABOVE;
6285 else if (infoPtr->rcList.bottom < lpHitTestInfo->pt.y)
6287 lpHitTestInfo->flags |= LVHT_BELOW;
6290 if (lpHitTestInfo->flags == 0)
6292 /* NOTE (mm 20001022): We must not allow iSubItem to be touched, for
6293 * an app might pass only a structure with space up to iItem!
6294 * (MS Office 97 does that for instance in the file open dialog)
6296 nItem = LISTVIEW_HitTestItem(hwnd, lpHitTestInfo, FALSE);
6304 * Inserts a new column.
6307 * [I] HWND : window handle
6308 * [I] INT : column index
6309 * [I] LPLVCOLUMNA : column information
6312 * SUCCESS : new column index
6315 static LRESULT LISTVIEW_InsertColumnA(HWND hwnd, INT nColumn,
6316 LPLVCOLUMNA lpColumn)
6318 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6320 INT nNewColumn = -1;
6322 TRACE("(hwnd=%x, nColumn=%d, lpColumn=%p)\n",hwnd, nColumn,
6325 if (lpColumn != NULL)
6327 /* initialize memory */
6328 ZeroMemory(&hdi, sizeof(HDITEMA));
6330 if (lpColumn->mask & LVCF_FMT)
6332 /* format member is valid */
6333 hdi.mask |= HDI_FORMAT;
6335 /* set text alignment (leftmost column must be left-aligned) */
6338 hdi.fmt |= HDF_LEFT;
6342 if (lpColumn->fmt & LVCFMT_LEFT)
6344 hdi.fmt |= HDF_LEFT;
6346 else if (lpColumn->fmt & LVCFMT_RIGHT)
6348 hdi.fmt |= HDF_RIGHT;
6350 else if (lpColumn->fmt & LVCFMT_CENTER)
6352 hdi.fmt |= HDF_CENTER;
6356 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
6358 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
6362 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
6367 if (lpColumn->fmt & LVCFMT_IMAGE)
6369 hdi.fmt |= HDF_IMAGE;
6370 hdi.iImage = I_IMAGECALLBACK;
6374 if (lpColumn->mask & LVCF_WIDTH)
6376 hdi.mask |= HDI_WIDTH;
6377 hdi.cxy = lpColumn->cx;
6380 if (lpColumn->mask & LVCF_TEXT)
6382 hdi.mask |= HDI_TEXT | HDI_FORMAT;
6383 hdi.pszText = lpColumn->pszText;
6384 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
6385 hdi.fmt |= HDF_STRING;
6388 if (lpColumn->mask & LVCF_IMAGE)
6390 hdi.mask |= HDI_IMAGE;
6391 hdi.iImage = lpColumn->iImage;
6394 if (lpColumn->mask & LVCF_ORDER)
6396 hdi.mask |= HDI_ORDER;
6397 hdi.iOrder = lpColumn->iOrder;
6400 /* insert item in header control */
6401 nNewColumn = SendMessageA(infoPtr->hwndHeader, HDM_INSERTITEMA,
6402 (WPARAM)nColumn, (LPARAM)&hdi);
6404 /* Need to reset the item width when inserting a new column */
6405 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6407 LISTVIEW_UpdateScroll(hwnd);
6408 InvalidateRect(hwnd, NULL, FALSE);
6414 static LRESULT LISTVIEW_InsertColumnW(HWND hwnd, INT nColumn,
6415 LPLVCOLUMNW lpColumn)
6420 memcpy(&lvca,lpColumn,sizeof(lvca));
6421 if (lpColumn->mask & LVCF_TEXT)
6422 lvca.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpColumn->pszText);
6423 lres = LISTVIEW_InsertColumnA(hwnd,nColumn,&lvca);
6424 if (lpColumn->mask & LVCF_TEXT)
6425 HeapFree(GetProcessHeap(),0,lvca.pszText);
6429 /* LISTVIEW_InsertCompare: callback routine for comparing pszText members of the LV_ITEMS
6430 in a LISTVIEW on insert. Passed to DPA_Sort in LISTVIEW_InsertItem.
6431 This function should only be used for inserting items into a sorted list (LVM_INSERTITEM)
6432 and not during the processing of a LVM_SORTITEMS message. Applications should provide
6433 their own sort proc. when sending LVM_SORTITEMS.
6436 (remarks on LVITEM: LVM_INSERTITEM will insert the new item in the proper sort postion...
6438 LVS_SORTXXX must be specified,
6439 LVS_OWNERDRAW is not set,
6440 <item>.pszText is not LPSTR_TEXTCALLBACK.
6442 (LVS_SORT* flags): "For the LVS_SORTASCENDING... styles, item indices
6443 are sorted based on item text..."
6445 static INT WINAPI LISTVIEW_InsertCompare( LPVOID first, LPVOID second, LPARAM lParam)
6447 HDPA hdpa_first = (HDPA) first;
6448 HDPA hdpa_second = (HDPA) second;
6449 LISTVIEW_ITEM* lv_first = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_first, 0 );
6450 LISTVIEW_ITEM* lv_second = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_second, 0 );
6451 LONG lStyle = GetWindowLongA((HWND) lParam, GWL_STYLE);
6452 INT cmpv = lstrcmpA( lv_first->pszText, lv_second->pszText );
6453 /* if we're sorting descending, negate the return value */
6454 return (lStyle & LVS_SORTDESCENDING) ? -cmpv : cmpv;
6459 * Inserts a new item in the listview control.
6462 * [I] HWND : window handle
6463 * [I] LPLVITEMA : item information
6466 * SUCCESS : new item index
6469 static LRESULT LISTVIEW_InsertItemA(HWND hwnd, LPLVITEMA lpLVItem)
6471 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6472 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6473 UINT uView = lStyle & LVS_TYPEMASK;
6474 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
6479 LISTVIEW_ITEM *lpItem = NULL;
6481 TRACE("(hwnd=%x,lpLVItem=%p)\n", hwnd, lpLVItem);
6483 if (lStyle & LVS_OWNERDATA)
6485 nItem = infoPtr->hdpaItems->nItemCount;
6486 infoPtr->hdpaItems->nItemCount ++;
6490 if (lpLVItem != NULL)
6492 /* make sure it's not a subitem; cannot insert a subitem */
6493 if (lpLVItem->iSubItem == 0)
6495 lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM));
6498 ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
6499 if (LISTVIEW_InitItem(hwnd, lpItem, lpLVItem) != FALSE)
6501 /* insert item in listview control data structure */
6502 hdpaSubItems = DPA_Create(8);
6503 if (hdpaSubItems != NULL)
6505 nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem);
6508 if ( ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
6509 && !(lStyle & LVS_OWNERDRAWFIXED)
6510 && (LPSTR_TEXTCALLBACKA != lpLVItem->pszText) )
6512 /* Insert the item in the proper sort order based on the pszText
6513 member. See comments for LISTVIEW_InsertCompare() for greater detail */
6514 nItem = DPA_InsertPtr( infoPtr->hdpaItems,
6515 GETITEMCOUNT( infoPtr ) + 1, hdpaSubItems );
6516 DPA_Sort( infoPtr->hdpaItems, LISTVIEW_InsertCompare, hwnd );
6517 nItem = DPA_GetPtrIndex( infoPtr->hdpaItems, hdpaSubItems );
6521 nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpLVItem->iItem,
6526 LISTVIEW_ShiftSelections(hwnd,nItem,1);
6528 /* manage item focus */
6529 if (lpLVItem->mask & LVIF_STATE)
6531 lpItem->state &= ~(LVIS_FOCUSED|LVIS_SELECTED);
6532 if (lpLVItem->stateMask & LVIS_SELECTED)
6534 LISTVIEW_SetSelection(hwnd, nItem);
6536 else if (lpLVItem->stateMask & LVIS_FOCUSED)
6538 LISTVIEW_SetItemFocus(hwnd, nItem);
6542 /* send LVN_INSERTITEM notification */
6543 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
6544 nmlv.hdr.hwndFrom = hwnd;
6545 nmlv.hdr.idFrom = lCtrlId;
6546 nmlv.hdr.code = LVN_INSERTITEM;
6548 nmlv.lParam = lpItem->lParam;;
6549 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
6551 if ((uView == LVS_SMALLICON) || (uView == LVS_LIST))
6553 nItemWidth = LISTVIEW_CalculateWidth(hwnd, lpLVItem->iItem);
6554 if (nItemWidth > infoPtr->nItemWidth)
6556 infoPtr->nItemWidth = nItemWidth;
6560 /* align items (set position of each item) */
6561 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
6563 if (lStyle & LVS_ALIGNLEFT)
6565 LISTVIEW_AlignLeft(hwnd);
6569 LISTVIEW_AlignTop(hwnd);
6573 LISTVIEW_UpdateScroll(hwnd);
6574 /* refresh client area */
6575 InvalidateRect(hwnd, NULL, FALSE);
6584 /* free memory if unsuccessful */
6585 if ((nItem == -1) && (lpItem != NULL))
6587 COMCTL32_Free(lpItem);
6593 static LRESULT LISTVIEW_InsertItemW(HWND hwnd, LPLVITEMW lpLVItem) {
6597 memcpy(&lvia,lpLVItem,sizeof(LVITEMA));
6598 if (lvia.mask & LVIF_TEXT) {
6599 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKW)
6600 lvia.pszText = LPSTR_TEXTCALLBACKA;
6602 lvia.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpLVItem->pszText);
6604 lres = LISTVIEW_InsertItemA(hwnd, &lvia);
6605 if (lvia.mask & LVIF_TEXT) {
6606 if (lpLVItem->pszText != LPSTR_TEXTCALLBACKW)
6607 HeapFree(GetProcessHeap(),0,lvia.pszText);
6612 /* LISTVIEW_InsertItemW */
6616 * Redraws a range of items.
6619 * [I] HWND : window handle
6620 * [I] INT : first item
6621 * [I] INT : last item
6627 static LRESULT LISTVIEW_RedrawItems(HWND hwnd, INT nFirst, INT nLast)
6629 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6630 BOOL bResult = FALSE;
6633 if (nFirst <= nLast)
6635 if ((nFirst >= 0) && (nFirst < GETITEMCOUNT(infoPtr)))
6637 if ((nLast >= 0) && (nLast < GETITEMCOUNT(infoPtr)))
6640 for (i = nFirst; i <= nLast; i++)
6642 rcItem.left = LVIR_BOUNDS;
6643 LISTVIEW_GetItemRect(hwnd, i, &rcItem);
6644 InvalidateRect(hwnd, &rcItem, TRUE);
6653 /* LISTVIEW_Scroll */
6657 * Sets the background color.
6660 * [I] HWND : window handle
6661 * [I] COLORREF : background color
6667 static LRESULT LISTVIEW_SetBkColor(HWND hwnd, COLORREF clrBk)
6669 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6671 infoPtr->clrBk = clrBk;
6672 InvalidateRect(hwnd, NULL, TRUE);
6677 /* LISTVIEW_SetBkImage */
6681 * Sets the callback mask. This mask will be used when the parent
6682 * window stores state information (some or all).
6685 * [I] HWND : window handle
6686 * [I] UINT : state mask
6692 static BOOL LISTVIEW_SetCallbackMask(HWND hwnd, UINT uMask)
6694 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6696 infoPtr->uCallbackMask = uMask;
6703 * Sets the attributes of a header item.
6706 * [I] HWND : window handle
6707 * [I] INT : column index
6708 * [I] LPLVCOLUMNA : column attributes
6714 static LRESULT LISTVIEW_SetColumnA(HWND hwnd, INT nColumn,
6715 LPLVCOLUMNA lpColumn)
6717 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6718 BOOL bResult = FALSE;
6719 HDITEMA hdi, hdiget;
6721 if ((lpColumn != NULL) && (nColumn >= 0) &&
6722 (nColumn < Header_GetItemCount(infoPtr->hwndHeader)))
6724 /* initialize memory */
6725 ZeroMemory(&hdi, sizeof(HDITEMA));
6727 if (lpColumn->mask & LVCF_FMT)
6729 /* format member is valid */
6730 hdi.mask |= HDI_FORMAT;
6732 /* get current format first */
6733 hdiget.mask = HDI_FORMAT;
6734 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdiget))
6735 /* preserve HDF_STRING if present */
6736 hdi.fmt = hdiget.fmt & HDF_STRING;
6738 /* set text alignment (leftmost column must be left-aligned) */
6741 hdi.fmt |= HDF_LEFT;
6745 if (lpColumn->fmt & LVCFMT_LEFT)
6747 hdi.fmt |= HDF_LEFT;
6749 else if (lpColumn->fmt & LVCFMT_RIGHT)
6751 hdi.fmt |= HDF_RIGHT;
6753 else if (lpColumn->fmt & LVCFMT_CENTER)
6755 hdi.fmt |= HDF_CENTER;
6759 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
6761 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
6764 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
6766 hdi.fmt |= HDF_IMAGE;
6769 if (lpColumn->fmt & LVCFMT_IMAGE)
6771 hdi.fmt |= HDF_IMAGE;
6772 hdi.iImage = I_IMAGECALLBACK;
6776 if (lpColumn->mask & LVCF_WIDTH)
6778 hdi.mask |= HDI_WIDTH;
6779 hdi.cxy = lpColumn->cx;
6782 if (lpColumn->mask & LVCF_TEXT)
6784 hdi.mask |= HDI_TEXT | HDI_FORMAT;
6785 hdi.pszText = lpColumn->pszText;
6786 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
6787 hdi.fmt |= HDF_STRING;
6790 if (lpColumn->mask & LVCF_IMAGE)
6792 hdi.mask |= HDI_IMAGE;
6793 hdi.iImage = lpColumn->iImage;
6796 if (lpColumn->mask & LVCF_ORDER)
6798 hdi.mask |= HDI_ORDER;
6799 hdi.iOrder = lpColumn->iOrder;
6802 /* set header item attributes */
6803 bResult = Header_SetItemA(infoPtr->hwndHeader, nColumn, &hdi);
6809 /* LISTVIEW_SetColumnW */
6813 * Sets the column order array
6816 * [I] HWND : window handle
6817 * [I] INT : number of elements in column order array
6818 * [I] INT : pointer to column order array
6824 static LRESULT LISTVIEW_SetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
6826 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
6828 FIXME("iCount %d lpiArray %p\n", iCount, lpiArray);
6839 * Sets the width of a column
6842 * [I] HWND : window handle
6843 * [I] INT : column index
6844 * [I] INT : column width
6850 static LRESULT LISTVIEW_SetColumnWidth(HWND hwnd, INT iCol, INT cx)
6852 LISTVIEW_INFO *infoPtr;
6855 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6856 UINT uView = lStyle & LVS_TYPEMASK;
6861 CHAR text_buffer[DISP_TEXT_SIZE];
6862 INT header_item_count;
6867 /* make sure we can get the listview info */
6868 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
6871 if (!infoPtr->hwndHeader) /* make sure we have a header */
6874 /* set column width only if in report or list mode */
6875 if ((uView != LVS_REPORT) && (uView != LVS_LIST))
6878 /* take care of invalid cx values */
6879 if((uView == LVS_REPORT) && (cx < -2))
6880 cx = LVSCW_AUTOSIZE;
6881 else if (uView == LVS_LIST && (cx < 1))
6884 /* resize all columns if in LVS_LIST mode */
6885 if(uView == LVS_LIST) {
6886 infoPtr->nItemWidth = cx;
6887 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
6891 /* autosize based on listview items width */
6892 if(cx == LVSCW_AUTOSIZE)
6894 /* set the width of the header to the width of the widest item */
6895 for(item_index = 0; item_index < GETITEMCOUNT(infoPtr); item_index++)
6897 if(cx < LISTVIEW_GetLabelWidth(hwnd, item_index))
6898 cx = LISTVIEW_GetLabelWidth(hwnd, item_index);
6900 } /* autosize based on listview header width */
6901 else if(cx == LVSCW_AUTOSIZE_USEHEADER)
6903 header_item_count = Header_GetItemCount(infoPtr->hwndHeader);
6905 /* if iCol is the last column make it fill the remainder of the controls width */
6906 if(iCol == (header_item_count - 1)) {
6907 /* get the width of every item except the current one */
6908 hdi.mask = HDI_WIDTH;
6911 for(item_index = 0; item_index < (header_item_count - 1); item_index++) {
6912 Header_GetItemA(infoPtr->hwndHeader, item_index, (LPARAM)(&hdi));
6916 /* retrieve the layout of the header */
6917 GetWindowRect(infoPtr->hwndHeader, &rcHeader);
6919 cx = (rcHeader.right - rcHeader.left) - cx;
6923 /* retrieve header font */
6924 header_font = SendMessageA(infoPtr->hwndHeader, WM_GETFONT, 0L, 0L);
6926 /* retrieve header text */
6927 hdi.mask = HDI_TEXT;
6928 hdi.cchTextMax = sizeof(text_buffer);
6929 hdi.pszText = text_buffer;
6931 Header_GetItemA(infoPtr->hwndHeader, iCol, (LPARAM)(&hdi));
6933 /* determine the width of the text in the header */
6935 old_font = SelectObject(hdc, header_font); /* select the font into hdc */
6937 GetTextExtentPoint32A(hdc, text_buffer, strlen(text_buffer), &size);
6939 SelectObject(hdc, old_font); /* restore the old font */
6940 ReleaseDC(hwnd, hdc);
6942 /* set the width of this column to the width of the text */
6947 /* call header to update the column change */
6948 hdi.mask = HDI_WIDTH;
6951 lret = Header_SetItemA(infoPtr->hwndHeader, (WPARAM)iCol, (LPARAM)&hdi);
6953 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
6960 * Sets the extended listview style.
6963 * [I] HWND : window handle
6968 * SUCCESS : previous style
6971 static LRESULT LISTVIEW_SetExtendedListViewStyle(HWND hwnd, DWORD dwMask, DWORD dwStyle)
6973 LISTVIEW_INFO *infoPtr;
6976 /* make sure we can get the listview info */
6977 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
6980 /* store previous style */
6981 dwOldStyle = infoPtr->dwExStyle;
6985 infoPtr->dwExStyle = (dwOldStyle & ~dwMask) | (dwStyle & dwMask);
6987 infoPtr->dwExStyle = dwStyle;
6989 return (dwOldStyle);
6992 /* LISTVIEW_SetHotCursor */
6996 * Sets the hot item index.
6999 * [I] HWND : window handle
7003 * SUCCESS : previous hot item index
7004 * FAILURE : -1 (no hot item)
7006 static LRESULT LISTVIEW_SetHotItem(HWND hwnd, INT iIndex)
7008 LISTVIEW_INFO *infoPtr;
7011 /* make sure we can get the listview info */
7012 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
7015 /* store previous index */
7016 iOldIndex = infoPtr->nHotItem;
7019 infoPtr->nHotItem = iIndex;
7026 * Sets the amount of time the cursor must hover over an item before it is selected.
7029 * [I] HWND : window handle
7030 * [I] DWORD : dwHoverTime, if -1 the hover time is set to the default
7033 * Returns the previous hover time
7035 static LRESULT LISTVIEW_SetHoverTime(HWND hwnd, DWORD dwHoverTime)
7037 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7038 DWORD oldHoverTime = infoPtr->dwHoverTime;
7040 infoPtr->dwHoverTime = dwHoverTime;
7042 return oldHoverTime;
7045 /* LISTVIEW_SetIconSpacing */
7052 * [I] HWND : window handle
7053 * [I] INT : image list type
7054 * [I] HIMAGELIST : image list handle
7057 * SUCCESS : old image list
7060 static LRESULT LISTVIEW_SetImageList(HWND hwnd, INT nType, HIMAGELIST himl)
7062 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7063 HIMAGELIST himlOld = 0;
7068 himlOld = infoPtr->himlNormal;
7069 infoPtr->himlNormal = himl;
7073 himlOld = infoPtr->himlSmall;
7074 infoPtr->himlSmall = himl;
7078 himlOld = infoPtr->himlState;
7079 infoPtr->himlState = himl;
7080 ImageList_SetBkColor(infoPtr->himlState, CLR_NONE);
7084 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7086 return (LRESULT)himlOld;
7092 * Sets the attributes of an item.
7095 * [I] HWND : window handle
7096 * [I] LPLVITEM : item information
7102 static LRESULT LISTVIEW_SetItemA(HWND hwnd, LPLVITEMA lpLVItem)
7104 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7105 BOOL bResult = FALSE;
7107 if (lpLVItem != NULL)
7109 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
7111 if (lpLVItem->iSubItem == 0)
7113 bResult = LISTVIEW_SetItem(hwnd, lpLVItem);
7117 bResult = LISTVIEW_SetSubItem(hwnd, lpLVItem);
7126 /* LISTVIEW_SetItemW */
7130 * Preallocates memory.
7133 * [I] HWND : window handle
7134 * [I] INT : item count (projected number of items)
7135 * [I] DWORD : update flags
7141 static BOOL LISTVIEW_SetItemCount(HWND hwnd, INT nItems, DWORD dwFlags)
7143 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
7145 if (GetWindowLongA(hwnd, GWL_STYLE) & LVS_OWNERDATA)
7147 int precount,topvisible;
7148 TRACE("LVS_OWNERDATA is set!\n");
7151 * Internally remove all the selections.
7155 LISTVIEW_SELECTION *selection;
7156 selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,0);
7158 LISTVIEW_RemoveSelectionRange(hwnd,selection->lower,
7161 while (infoPtr->hdpaSelectionRanges->nItemCount>0);
7163 precount = infoPtr->hdpaItems->nItemCount;
7164 topvisible = ListView_GetTopIndex(hwnd) +
7165 LISTVIEW_GetCountPerColumn(hwnd) + 1;
7167 infoPtr->hdpaItems->nItemCount = nItems;
7169 LISTVIEW_UpdateSize(hwnd);
7170 LISTVIEW_UpdateScroll(hwnd);
7171 if (min(precount,infoPtr->hdpaItems->nItemCount)<topvisible)
7172 InvalidateRect(hwnd, NULL, TRUE);
7177 return LISTVIEW_DeleteAllItems (hwnd);
7179 if (nItems > GETITEMCOUNT(infoPtr))
7182 FIXME("append items\n");
7185 else if (nItems < GETITEMCOUNT(infoPtr))
7188 while(nItems < GETITEMCOUNT(infoPtr)) {
7189 LISTVIEW_DeleteItem(hwnd, GETITEMCOUNT(infoPtr) - 1);
7199 * Sets the position of an item.
7202 * [I] HWND : window handle
7203 * [I] INT : item index
7204 * [I] LONG : x coordinate
7205 * [I] LONG : y coordinate
7211 static BOOL LISTVIEW_SetItemPosition(HWND hwnd, INT nItem,
7212 LONG nPosX, LONG nPosY)
7214 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
7215 UINT lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7216 UINT uView = lStyle & LVS_TYPEMASK;
7217 LISTVIEW_ITEM *lpItem;
7219 BOOL bResult = FALSE;
7221 TRACE("(hwnd=%x,nItem=%d,X=%ld,Y=%ld)\n", hwnd, nItem, nPosX, nPosY);
7223 if (lStyle & LVS_OWNERDATA)
7226 if ((nItem >= 0) || (nItem < GETITEMCOUNT(infoPtr)))
7228 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
7230 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
7231 if (hdpaSubItems != NULL)
7233 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
7237 lpItem->ptPosition.x = nPosX;
7238 lpItem->ptPosition.y = nPosY;
7249 * Sets the state of one or many items.
7252 * [I] HWND : window handle
7253 * [I]INT : item index
7254 * [I] LPLVITEM : item or subitem info
7260 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
7262 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7263 BOOL bResult = FALSE;
7270 ZeroMemory(&lvItem, sizeof(LVITEMA));
7271 lvItem.mask = LVIF_STATE;
7272 lvItem.state = lpLVItem->state;
7273 lvItem.stateMask = lpLVItem->stateMask ;
7275 /* apply to all items */
7276 for (i = 0; i< GETITEMCOUNT(infoPtr); i++)
7279 if (ListView_SetItemA(hwnd, &lvItem) == FALSE)
7287 ZeroMemory(&lvItem, sizeof(LVITEMA));
7288 lvItem.mask = LVIF_STATE;
7289 lvItem.state = lpLVItem->state;
7290 lvItem.stateMask = lpLVItem->stateMask;
7291 lvItem.iItem = nItem;
7292 bResult = ListView_SetItemA(hwnd, &lvItem);
7300 * Sets the text of an item or subitem.
7303 * [I] HWND : window handle
7304 * [I] INT : item index
7305 * [I] LPLVITEMA : item or subitem info
7311 static BOOL LISTVIEW_SetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
7313 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7314 BOOL bResult = FALSE;
7317 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
7319 ZeroMemory(&lvItem, sizeof(LVITEMA));
7320 lvItem.mask = LVIF_TEXT;
7321 lvItem.pszText = lpLVItem->pszText;
7322 lvItem.iItem = nItem;
7323 lvItem.iSubItem = lpLVItem->iSubItem;
7324 bResult = ListView_SetItemA(hwnd, &lvItem);
7330 /* LISTVIEW_SetItemTextW */
7334 * Set item index that marks the start of a multiple selection.
7337 * [I] HWND : window handle
7341 * Index number or -1 if there is no selection mark.
7343 static LRESULT LISTVIEW_SetSelectionMark(HWND hwnd, INT nIndex)
7345 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7346 INT nOldIndex = infoPtr->nSelectionMark;
7348 infoPtr->nSelectionMark = nIndex;
7355 * Sets the text background color.
7358 * [I] HWND : window handle
7359 * [I] COLORREF : text background color
7365 static LRESULT LISTVIEW_SetTextBkColor(HWND hwnd, COLORREF clrTextBk)
7367 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7369 infoPtr->clrTextBk = clrTextBk;
7370 InvalidateRect(hwnd, NULL, TRUE);
7377 * Sets the text foreground color.
7380 * [I] HWND : window handle
7381 * [I] COLORREF : text color
7387 static LRESULT LISTVIEW_SetTextColor (HWND hwnd, COLORREF clrText)
7389 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7391 infoPtr->clrText = clrText;
7392 InvalidateRect(hwnd, NULL, TRUE);
7397 /* LISTVIEW_SetToolTips */
7398 /* LISTVIEW_SetUnicodeFormat */
7399 /* LISTVIEW_SetWorkAreas */
7403 * Callback internally used by LISTVIEW_SortItems()
7406 * [I] LPVOID : first LISTVIEW_ITEM to compare
7407 * [I] LPVOID : second LISTVIEW_ITEM to compare
7408 * [I] LPARAM : HWND of control
7411 * if first comes before second : negative
7412 * if first comes after second : positive
7413 * if first and second are equivalent : zero
7415 static INT WINAPI LISTVIEW_CallBackCompare(
7420 /* Forward the call to the client defined callback */
7422 HWND hwnd = (HWND)lParam;
7423 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7424 HDPA hdpa_first = (HDPA) first;
7425 HDPA hdpa_second = (HDPA) second;
7426 LISTVIEW_ITEM* lv_first = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_first, 0 );
7427 LISTVIEW_ITEM* lv_second = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_second, 0 );
7429 rv = (infoPtr->pfnCompare)( lv_first->lParam , lv_second->lParam, infoPtr->lParamSort );
7436 * Sorts the listview items.
7439 * [I] HWND : window handle
7440 * [I] WPARAM : application-defined value
7441 * [I] LPARAM : pointer to comparision callback
7447 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam)
7449 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7451 UINT lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7453 if (lStyle & LVS_OWNERDATA)
7456 if (!infoPtr || !infoPtr->hdpaItems)
7459 nCount = GETITEMCOUNT(infoPtr);
7460 /* if there are 0 or 1 items, there is no need to sort */
7463 infoPtr->pfnCompare = (PFNLVCOMPARE)lParam;
7464 infoPtr->lParamSort = (LPARAM)wParam;
7466 DPA_Sort(infoPtr->hdpaItems, LISTVIEW_CallBackCompare, hwnd);
7469 /* align the items */
7470 LISTVIEW_AlignTop(hwnd);
7472 /* refresh the display */
7473 InvalidateRect(hwnd, NULL, TRUE);
7478 /* LISTVIEW_SubItemHitTest */
7482 * Updates an items or rearranges the listview control.
7485 * [I] HWND : window handle
7486 * [I] INT : item index
7492 static LRESULT LISTVIEW_Update(HWND hwnd, INT nItem)
7494 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7495 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7496 BOOL bResult = FALSE;
7499 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
7503 /* rearrange with default alignment style */
7504 if ((lStyle & LVS_AUTOARRANGE) && (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
7505 ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON)))
7507 ListView_Arrange(hwnd, 0);
7511 /* get item bounding rectangle */
7512 rc.left = LVIR_BOUNDS;
7513 ListView_GetItemRect(hwnd, nItem, &rc);
7514 InvalidateRect(hwnd, &rc, TRUE);
7523 * Creates the listview control.
7526 * [I] HWND : window handle
7531 static LRESULT LISTVIEW_Create(HWND hwnd, WPARAM wParam, LPARAM lParam)
7533 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7534 LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam;
7535 UINT uView = lpcs->style & LVS_TYPEMASK;
7538 /* initialize info pointer */
7539 ZeroMemory(infoPtr, sizeof(LISTVIEW_INFO));
7541 /* determine the type of structures to use */
7542 infoPtr->notifyFormat = SendMessageA(GetParent(hwnd), WM_NOTIFYFORMAT,
7543 (WPARAM)hwnd, (LPARAM)NF_QUERY);
7544 if (infoPtr->notifyFormat != NFR_ANSI)
7546 FIXME("ANSI notify format is NOT used\n");
7549 /* initialize color information */
7550 infoPtr->clrBk = GetSysColor(COLOR_WINDOW);
7551 infoPtr->clrText = GetSysColor(COLOR_WINDOWTEXT);
7552 infoPtr->clrTextBk = CLR_DEFAULT;
7554 /* set default values */
7555 infoPtr->uCallbackMask = 0;
7556 infoPtr->nFocusedItem = -1;
7557 infoPtr->nSelectionMark = -1;
7558 infoPtr->nHotItem = -1;
7559 infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING);
7560 infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING);
7561 ZeroMemory(&infoPtr->rcList, sizeof(RECT));
7562 infoPtr->hwndEdit = 0;
7563 infoPtr->pedititem = NULL;
7564 infoPtr->nEditLabelItem = -1;
7566 /* get default font (icon title) */
7567 SystemParametersInfoA(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
7568 infoPtr->hDefaultFont = CreateFontIndirectA(&logFont);
7569 infoPtr->hFont = infoPtr->hDefaultFont;
7572 infoPtr->hwndHeader = CreateWindowA(WC_HEADERA, (LPCSTR)NULL,
7573 WS_CHILD | HDS_HORZ | HDS_BUTTONS,
7574 0, 0, 0, 0, hwnd, (HMENU)0,
7575 lpcs->hInstance, NULL);
7577 /* set header font */
7578 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont,
7581 if (uView == LVS_ICON)
7583 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
7584 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
7586 else if (uView == LVS_REPORT)
7588 if (!(LVS_NOCOLUMNHEADER & lpcs->style))
7590 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
7594 /* set HDS_HIDDEN flag to hide the header bar */
7595 SetWindowLongA(infoPtr->hwndHeader, GWL_STYLE,
7596 GetWindowLongA(infoPtr->hwndHeader, GWL_STYLE) | HDS_HIDDEN);
7600 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7601 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7605 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7606 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7609 /* display unsupported listview window styles */
7610 LISTVIEW_UnsupportedStyles(lpcs->style);
7612 /* allocate memory for the data structure */
7613 infoPtr->hdpaItems = DPA_Create(10);
7615 /* allocate memory for the selection ranges */
7616 infoPtr->hdpaSelectionRanges = DPA_Create(10);
7618 /* initialize size of items */
7619 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7620 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7622 /* initialize the hover time to -1(indicating the default system hover time) */
7623 infoPtr->dwHoverTime = -1;
7630 * Erases the background of the listview control.
7633 * [I] HWND : window handle
7634 * [I] WPARAM : device context handle
7635 * [I] LPARAM : not used
7641 static LRESULT LISTVIEW_EraseBackground(HWND hwnd, WPARAM wParam,
7644 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7647 if (infoPtr->clrBk == CLR_NONE)
7649 bResult = SendMessageA(GetParent(hwnd), WM_ERASEBKGND, wParam, lParam);
7654 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
7655 GetClientRect(hwnd, &rc);
7656 FillRect((HDC)wParam, &rc, hBrush);
7657 DeleteObject(hBrush);
7665 static void LISTVIEW_FillBackground(HWND hwnd, HDC hdc, LPRECT rc)
7667 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7669 if (infoPtr->clrBk != CLR_NONE)
7671 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
7672 FillRect(hdc, rc, hBrush);
7673 DeleteObject(hBrush);
7679 * Retrieves the listview control font.
7682 * [I] HWND : window handle
7687 static LRESULT LISTVIEW_GetFont(HWND hwnd)
7689 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7691 return infoPtr->hFont;
7696 * Performs vertical scrolling.
7699 * [I] HWND : window handle
7700 * [I] INT : scroll code
7701 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
7703 * [I] HWND : scrollbar control window handle
7708 static LRESULT LISTVIEW_VScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
7711 SCROLLINFO scrollInfo;
7713 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7714 SendMessageA(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
7716 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
7717 scrollInfo.cbSize = sizeof(SCROLLINFO);
7718 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
7720 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
7722 INT nOldScrollPos = scrollInfo.nPos;
7723 switch (nScrollCode)
7726 if (scrollInfo.nPos > scrollInfo.nMin)
7733 if (scrollInfo.nPos < scrollInfo.nMax)
7740 if (scrollInfo.nPos > scrollInfo.nMin)
7742 if (scrollInfo.nPos >= scrollInfo.nPage)
7744 scrollInfo.nPos -= scrollInfo.nPage;
7748 scrollInfo.nPos = scrollInfo.nMin;
7754 if (scrollInfo.nPos < scrollInfo.nMax)
7756 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
7758 scrollInfo.nPos += scrollInfo.nPage;
7762 scrollInfo.nPos = scrollInfo.nMax;
7768 scrollInfo.nPos = nCurrentPos;
7769 if (scrollInfo.nPos > scrollInfo.nMax)
7770 scrollInfo.nPos=scrollInfo.nMax;
7772 if (scrollInfo.nPos < scrollInfo.nMin)
7773 scrollInfo.nPos=scrollInfo.nMin;
7778 if (nOldScrollPos != scrollInfo.nPos)
7780 scrollInfo.fMask = SIF_POS;
7781 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
7782 InvalidateRect(hwnd, NULL, TRUE);
7791 * Performs horizontal scrolling.
7794 * [I] HWND : window handle
7795 * [I] INT : scroll code
7796 * [I] SHORT : current scroll position if scroll code is SB_THUMBPOSITION
7798 * [I] HWND : scrollbar control window handle
7803 static LRESULT LISTVIEW_HScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
7806 SCROLLINFO scrollInfo;
7808 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7809 SendMessageA(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
7812 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
7813 scrollInfo.cbSize = sizeof(SCROLLINFO);
7814 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
7816 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
7818 INT nOldScrollPos = scrollInfo.nPos;
7820 switch (nScrollCode)
7823 if (scrollInfo.nPos > scrollInfo.nMin)
7830 if (scrollInfo.nPos < scrollInfo.nMax)
7837 if (scrollInfo.nPos > scrollInfo.nMin)
7839 if (scrollInfo.nPos >= scrollInfo.nPage)
7841 scrollInfo.nPos -= scrollInfo.nPage;
7845 scrollInfo.nPos = scrollInfo.nMin;
7851 if (scrollInfo.nPos < scrollInfo.nMax)
7853 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
7855 scrollInfo.nPos += scrollInfo.nPage;
7859 scrollInfo.nPos = scrollInfo.nMax;
7865 scrollInfo.nPos = nCurrentPos;
7867 if (scrollInfo.nPos > scrollInfo.nMax)
7868 scrollInfo.nPos=scrollInfo.nMax;
7870 if (scrollInfo.nPos < scrollInfo.nMin)
7871 scrollInfo.nPos=scrollInfo.nMin;
7875 if (nOldScrollPos != scrollInfo.nPos)
7877 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
7878 scrollInfo.fMask = SIF_POS;
7879 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
7880 if(uView == LVS_REPORT)
7882 scrollInfo.fMask = SIF_POS;
7883 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
7884 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
7886 InvalidateRect(hwnd, NULL, TRUE);
7893 static LRESULT LISTVIEW_MouseWheel(HWND hwnd, INT wheelDelta)
7895 INT gcWheelDelta = 0;
7896 UINT pulScrollLines = 3;
7897 SCROLLINFO scrollInfo;
7899 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
7901 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
7902 gcWheelDelta -= wheelDelta;
7904 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
7905 scrollInfo.cbSize = sizeof(SCROLLINFO);
7906 scrollInfo.fMask = SIF_POS | SIF_RANGE;
7913 * listview should be scrolled by a multiple of 37 dependently on its dimension or its visible item number
7914 * should be fixed in the future.
7916 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
7917 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + (gcWheelDelta < 0) ? 37 : -37, 0);
7921 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
7923 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
7925 int cLineScroll = min(LISTVIEW_GetCountPerColumn(hwnd), pulScrollLines);
7926 cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
7927 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + cLineScroll, 0);
7933 LISTVIEW_HScroll(hwnd, (gcWheelDelta < 0) ? SB_LINELEFT : SB_LINERIGHT, 0, 0);
7944 * [I] HWND : window handle
7945 * [I] INT : virtual key
7946 * [I] LONG : key data
7951 static LRESULT LISTVIEW_KeyDown(HWND hwnd, INT nVirtualKey, LONG lKeyData)
7953 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7954 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
7955 HWND hwndParent = GetParent(hwnd);
7956 NMLVKEYDOWN nmKeyDown;
7959 BOOL bRedraw = FALSE;
7960 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7961 UINT uView = lStyle & LVS_TYPEMASK;
7963 /* send LVN_KEYDOWN notification */
7964 ZeroMemory(&nmKeyDown, sizeof(NMLVKEYDOWN));
7965 nmKeyDown.hdr.hwndFrom = hwnd;
7966 nmKeyDown.hdr.idFrom = nCtrlId;
7967 nmKeyDown.hdr.code = LVN_KEYDOWN;
7968 nmKeyDown.wVKey = nVirtualKey;
7969 nmKeyDown.flags = 0;
7970 SendMessageA(hwndParent, WM_NOTIFY, (WPARAM)nCtrlId, (LPARAM)&nmKeyDown);
7973 nmh.hwndFrom = hwnd;
7974 nmh.idFrom = nCtrlId;
7976 switch (nVirtualKey)
7979 if ((GETITEMCOUNT(infoPtr) > 0) && (infoPtr->nFocusedItem != -1))
7981 /* send NM_RETURN notification */
7982 nmh.code = NM_RETURN;
7983 ListView_Notify(hwndParent, nCtrlId, &nmh);
7985 /* send LVN_ITEMACTIVATE notification */
7986 nmh.code = LVN_ITEMACTIVATE;
7987 ListView_Notify(hwndParent, nCtrlId, &nmh);
7992 if (GETITEMCOUNT(infoPtr) > 0)
7999 if (GETITEMCOUNT(infoPtr) > 0)
8001 nItem = GETITEMCOUNT(infoPtr) - 1;
8006 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TOLEFT);
8010 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_ABOVE);
8014 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TORIGHT);
8018 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_BELOW);
8022 if (uView == LVS_REPORT)
8024 nItem = infoPtr->nFocusedItem - LISTVIEW_GetCountPerColumn(hwnd);
8028 nItem = infoPtr->nFocusedItem - LISTVIEW_GetCountPerColumn(hwnd)
8029 * LISTVIEW_GetCountPerRow(hwnd);
8031 if(nItem < 0) nItem = 0;
8035 if (uView == LVS_REPORT)
8037 nItem = infoPtr->nFocusedItem + LISTVIEW_GetCountPerColumn(hwnd);
8041 nItem = infoPtr->nFocusedItem + LISTVIEW_GetCountPerColumn(hwnd)
8042 * LISTVIEW_GetCountPerRow(hwnd);
8044 if(nItem >= GETITEMCOUNT(infoPtr)) nItem = GETITEMCOUNT(infoPtr) - 1;
8048 if ((nItem != -1) && (nItem != infoPtr->nFocusedItem))
8050 bRedraw = LISTVIEW_KeySelection(hwnd, nItem);
8051 if (bRedraw != FALSE)
8053 /* refresh client area */
8066 * [I] HWND : window handle
8071 static LRESULT LISTVIEW_KillFocus(HWND hwnd)
8073 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
8074 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8078 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8079 UINT uView = lStyle & LVS_TYPEMASK;
8081 TRACE("(hwnd=%x)\n", hwnd);
8083 /* send NM_KILLFOCUS notification */
8084 nmh.hwndFrom = hwnd;
8085 nmh.idFrom = nCtrlId;
8086 nmh.code = NM_KILLFOCUS;
8087 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8089 /* set window focus flag */
8090 infoPtr->bFocus = FALSE;
8092 /* NEED drawing optimization ; redraw the selected items */
8093 if (uView & LVS_REPORT)
8095 nTop = LISTVIEW_GetTopIndex(hwnd);
8097 LISTVIEW_GetCountPerColumn(hwnd) + 1;
8102 nBottom = GETITEMCOUNT(infoPtr);
8104 for (i = nTop; i<nBottom; i++)
8106 if (LISTVIEW_IsSelected(hwnd,i))
8108 rcItem.left = LVIR_BOUNDS;
8109 LISTVIEW_GetItemRect(hwnd, i, &rcItem);
8110 InvalidateRect(hwnd, &rcItem, FALSE);
8119 * Processes double click messages (left mouse button).
8122 * [I] HWND : window handle
8123 * [I] WORD : key flag
8124 * [I] WORD : x coordinate
8125 * [I] WORD : y coordinate
8130 static LRESULT LISTVIEW_LButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
8133 LONG nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8134 LVHITTESTINFO htInfo;
8139 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8141 htInfo.pt.x = wPosX;
8142 htInfo.pt.y = wPosY;
8144 /* send NM_DBLCLK notification */
8145 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
8146 nmlv.hdr.hwndFrom = hwnd;
8147 nmlv.hdr.idFrom = nCtrlId;
8148 nmlv.hdr.code = NM_DBLCLK;
8149 ret = LISTVIEW_HitTestItem(hwnd, &htInfo, TRUE);
8152 nmlv.iItem = htInfo.iItem;
8153 nmlv.iSubItem = htInfo.iSubItem;
8160 nmlv.ptAction.x = wPosX;
8161 nmlv.ptAction.y = wPosY;
8162 ListView_LVNotify(GetParent(hwnd), nCtrlId, &nmlv);
8165 /* To send the LVN_ITEMACTIVATE, it must be on an Item */
8168 /* send LVN_ITEMACTIVATE notification */
8169 nmh.hwndFrom = hwnd;
8170 nmh.idFrom = nCtrlId;
8171 nmh.code = LVN_ITEMACTIVATE;
8172 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8180 * Processes mouse down messages (left mouse button).
8183 * [I] HWND : window handle
8184 * [I] WORD : key flag
8185 * [I] WORD : x coordinate
8186 * [I] WORD : y coordinate
8191 static LRESULT LISTVIEW_LButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
8194 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8195 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8196 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8197 static BOOL bGroupSelect = TRUE;
8202 TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd, wKey, wPosX,
8205 /* send NM_RELEASEDCAPTURE notification */
8206 nmh.hwndFrom = hwnd;
8207 nmh.idFrom = nCtrlId;
8208 nmh.code = NM_RELEASEDCAPTURE;
8209 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8211 if (infoPtr->bFocus == FALSE)
8216 /* set left button down flag */
8217 infoPtr->bLButtonDown = TRUE;
8219 ptPosition.x = wPosX;
8220 ptPosition.y = wPosY;
8221 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
8222 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
8224 if (lStyle & LVS_SINGLESEL)
8226 if ((ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
8227 && infoPtr->nEditLabelItem == -1)
8229 infoPtr->nEditLabelItem = nItem;
8233 LISTVIEW_SetSelection(hwnd, nItem);
8238 if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
8240 if (bGroupSelect != FALSE)
8242 LISTVIEW_AddGroupSelection(hwnd, nItem);
8246 LISTVIEW_AddSelection(hwnd, nItem);
8249 else if (wKey & MK_CONTROL)
8251 bGroupSelect = LISTVIEW_ToggleSelection(hwnd, nItem);
8253 else if (wKey & MK_SHIFT)
8255 LISTVIEW_SetGroupSelection(hwnd, nItem);
8260 (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED);
8262 /* set selection (clears other pre-existing selections) */
8263 LISTVIEW_SetSelection(hwnd, nItem);
8265 if (was_selected && infoPtr->nEditLabelItem == -1)
8267 infoPtr->nEditLabelItem = nItem;
8274 /* remove all selections */
8275 LISTVIEW_RemoveAllSelections(hwnd);
8278 /* redraw if we could have possibly selected something */
8279 if(!GETITEMCOUNT(infoPtr)) InvalidateRect(hwnd, NULL, TRUE);
8286 * Processes mouse up messages (left mouse button).
8289 * [I] HWND : window handle
8290 * [I] WORD : key flag
8291 * [I] WORD : x coordinate
8292 * [I] WORD : y coordinate
8297 static LRESULT LISTVIEW_LButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
8300 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8302 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8304 if (infoPtr->bLButtonDown != FALSE)
8306 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8308 LVHITTESTINFO lvHitTestInfo;
8311 lvHitTestInfo.pt.x = wPosX;
8312 lvHitTestInfo.pt.y = wPosY;
8314 /* send NM_CLICK notification */
8315 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
8316 nmlv.hdr.hwndFrom = hwnd;
8317 nmlv.hdr.idFrom = nCtrlId;
8318 nmlv.hdr.code = NM_CLICK;
8319 ret = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo, TRUE);
8322 nmlv.iItem = lvHitTestInfo.iItem;
8323 nmlv.iSubItem = lvHitTestInfo.iSubItem;
8330 nmlv.ptAction.x = wPosX;
8331 nmlv.ptAction.y = wPosY;
8332 ListView_LVNotify(GetParent(hwnd), nCtrlId, &nmlv);
8335 /* set left button flag */
8336 infoPtr->bLButtonDown = FALSE;
8338 if(infoPtr->nEditLabelItem != -1)
8340 if(lvHitTestInfo.iItem == infoPtr->nEditLabelItem)
8342 LISTVIEW_EditLabelA(hwnd, lvHitTestInfo.iItem);
8344 infoPtr->nEditLabelItem = -1;
8353 * Creates the listview control (called before WM_CREATE).
8356 * [I] HWND : window handle
8357 * [I] WPARAM : unhandled
8358 * [I] LPARAM : widow creation info
8363 static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
8365 LISTVIEW_INFO *infoPtr;
8367 TRACE("(hwnd=%x,wParam=%x,lParam=%lx)\n", hwnd, wParam, lParam);
8369 /* allocate memory for info structure */
8370 infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc(sizeof(LISTVIEW_INFO));
8371 SetWindowLongA(hwnd, 0, (LONG)infoPtr);
8372 if (infoPtr == NULL)
8374 ERR("could not allocate info memory!\n");
8378 if ((LISTVIEW_INFO *)GetWindowLongA(hwnd, 0) != infoPtr)
8380 ERR("pointer assignment error!\n");
8384 return DefWindowProcA(hwnd, WM_NCCREATE, wParam, lParam);
8389 * Destroys the listview control (called after WM_DESTROY).
8392 * [I] HWND : window handle
8397 static LRESULT LISTVIEW_NCDestroy(HWND hwnd)
8399 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8401 TRACE("(hwnd=%x)\n", hwnd);
8403 /* delete all items */
8404 LISTVIEW_DeleteAllItems(hwnd);
8406 /* destroy data structure */
8407 DPA_Destroy(infoPtr->hdpaItems);
8408 DPA_Destroy(infoPtr->hdpaSelectionRanges);
8411 infoPtr->hFont = (HFONT)0;
8412 if (infoPtr->hDefaultFont)
8414 DeleteObject(infoPtr->hDefaultFont);
8417 /* free listview info pointer*/
8418 COMCTL32_Free(infoPtr);
8420 SetWindowLongA(hwnd, 0, 0);
8426 * Handles notifications from children.
8429 * [I] HWND : window handle
8430 * [I] INT : control identifier
8431 * [I] LPNMHDR : notification information
8436 static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh)
8438 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8440 if (lpnmh->hwndFrom == infoPtr->hwndHeader)
8442 /* handle notification from header control */
8443 if (lpnmh->code == HDN_ENDTRACKA)
8445 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8446 InvalidateRect(hwnd, NULL, TRUE);
8448 else if(lpnmh->code == HDN_ITEMCLICKA)
8450 /* Handle sorting by Header Column */
8452 LPNMHEADERA pnmHeader = (LPNMHEADERA) lpnmh;
8453 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
8455 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
8456 nmlv.hdr.hwndFrom = hwnd;
8457 nmlv.hdr.idFrom = lCtrlId;
8458 nmlv.hdr.code = LVN_COLUMNCLICK;
8460 nmlv.iSubItem = pnmHeader->iItem;
8462 ListView_LVNotify(GetParent(hwnd),lCtrlId, &nmlv);
8465 else if(lpnmh->code == NM_RELEASEDCAPTURE)
8467 /* Idealy this should be done in HDN_ENDTRACKA
8468 * but since SetItemBounds in Header.c is called after
8469 * the notification is sent, it is neccessary to handle the
8470 * update of the scroll bar here (Header.c works fine as it is,
8471 * no need to disturb it)
8473 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8474 LISTVIEW_UpdateScroll(hwnd);
8475 InvalidateRect(hwnd, NULL, TRUE);
8485 * Determines the type of structure to use.
8488 * [I] HWND : window handle of the sender
8489 * [I] HWND : listview window handle
8490 * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
8495 static LRESULT LISTVIEW_NotifyFormat(HWND hwndFrom, HWND hwnd, INT nCommand)
8497 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8499 if (nCommand == NF_REQUERY)
8501 /* determine the type of structure to use */
8502 infoPtr->notifyFormat = SendMessageA(hwndFrom, WM_NOTIFYFORMAT,
8503 (WPARAM)hwnd, (LPARAM)NF_QUERY);
8504 if (infoPtr->notifyFormat == NFR_UNICODE)
8506 FIXME("NO support for unicode structures");
8515 * Paints/Repaints the listview control.
8518 * [I] HWND : window handle
8519 * [I] HDC : device context handle
8524 static LRESULT LISTVIEW_Paint(HWND hwnd, HDC hdc)
8528 TRACE("(hwnd=%x,hdc=%x)\n", hwnd, hdc);
8532 hdc = BeginPaint(hwnd, &ps);
8533 LISTVIEW_Refresh(hwnd, hdc);
8534 EndPaint(hwnd, &ps);
8538 LISTVIEW_Refresh(hwnd, hdc);
8546 * Processes double click messages (right mouse button).
8549 * [I] HWND : window handle
8550 * [I] WORD : key flag
8551 * [I] WORD : x coordinate
8552 * [I] WORD : y coordinate
8557 static LRESULT LISTVIEW_RButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
8560 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8563 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8565 /* send NM_RELEASEDCAPTURE notification */
8566 nmh.hwndFrom = hwnd;
8567 nmh.idFrom = nCtrlId;
8568 nmh.code = NM_RELEASEDCAPTURE;
8569 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8571 /* send NM_RDBLCLK notification */
8572 nmh.code = NM_RDBLCLK;
8573 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8580 * Processes mouse down messages (right mouse button).
8583 * [I] HWND : window handle
8584 * [I] WORD : key flag
8585 * [I] WORD : x coordinate
8586 * [I] WORD : y coordinate
8591 static LRESULT LISTVIEW_RButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
8594 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8595 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8600 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8602 /* send NM_RELEASEDCAPTURE notification */
8603 nmh.hwndFrom = hwnd;
8604 nmh.idFrom = nCtrlId;
8605 nmh.code = NM_RELEASEDCAPTURE;
8606 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8608 /* make sure the listview control window has the focus */
8609 if (infoPtr->bFocus == FALSE)
8614 /* set right button down flag */
8615 infoPtr->bRButtonDown = TRUE;
8617 /* determine the index of the selected item */
8618 ptPosition.x = wPosX;
8619 ptPosition.y = wPosY;
8620 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
8621 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
8623 if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)))
8625 LISTVIEW_SetSelection(hwnd, nItem);
8630 LISTVIEW_RemoveAllSelections(hwnd);
8638 * Processes mouse up messages (right mouse button).
8641 * [I] HWND : window handle
8642 * [I] WORD : key flag
8643 * [I] WORD : x coordinate
8644 * [I] WORD : y coordinate
8649 static LRESULT LISTVIEW_RButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
8652 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8653 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8655 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8657 if (infoPtr->bRButtonDown != FALSE)
8660 LVHITTESTINFO lvHitTestInfo;
8664 lvHitTestInfo.pt.x = wPosX;
8665 lvHitTestInfo.pt.y = wPosY;
8667 /* Send NM_RClICK notification */
8668 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
8669 nmlv.hdr.hwndFrom = hwnd;
8670 nmlv.hdr.idFrom = nCtrlId;
8671 nmlv.hdr.code = NM_RCLICK;
8672 ret = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo, TRUE);
8675 nmlv.iItem = lvHitTestInfo.iItem;
8676 nmlv.iSubItem = lvHitTestInfo.iSubItem;
8683 nmlv.ptAction.x = wPosX;
8684 nmlv.ptAction.y = wPosY;
8685 ListView_LVNotify(GetParent(hwnd), nCtrlId, &nmlv);
8690 /* set button flag */
8691 infoPtr->bRButtonDown = FALSE;
8693 /* Change to screen coordinate for WM_CONTEXTMENU */
8694 ClientToScreen(hwnd, &pt);
8696 /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
8697 SendMessageA( hwnd, WM_CONTEXTMENU, (WPARAM) hwnd, MAKELPARAM(pt.x, pt.y));
8708 * [I] HWND : window handle
8709 * [I] HWND : window handle of previously focused window
8714 static LRESULT LISTVIEW_SetFocus(HWND hwnd, HWND hwndLoseFocus)
8716 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8717 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8720 TRACE("(hwnd=%x, hwndLoseFocus=%x)\n", hwnd, hwndLoseFocus);
8722 /* send NM_SETFOCUS notification */
8723 nmh.hwndFrom = hwnd;
8724 nmh.idFrom = nCtrlId;
8725 nmh.code = NM_SETFOCUS;
8726 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8728 /* set window focus flag */
8729 infoPtr->bFocus = TRUE;
8741 * [I] HWND : window handle
8742 * [I] HFONT : font handle
8743 * [I] WORD : redraw flag
8748 static LRESULT LISTVIEW_SetFont(HWND hwnd, HFONT hFont, WORD fRedraw)
8750 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8751 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
8753 TRACE("(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd, hFont, fRedraw);
8757 infoPtr->hFont = infoPtr->hDefaultFont;
8761 infoPtr->hFont = hFont;
8764 if (uView == LVS_REPORT)
8766 /* set header font */
8767 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont,
8768 MAKELPARAM(fRedraw, 0));
8771 /* invalidate listview control client area */
8772 InvalidateRect(hwnd, NULL, TRUE);
8774 if (fRedraw != FALSE)
8784 * Message handling for WM_SETREDRAW.
8785 * For the Listview, it invalidates the entire window (the doc specifies otherwise)
8788 * [I] HWND : window handle
8789 * [I] bRedraw: state of redraw flag
8792 * DefWinProc return value
8794 static LRESULT LISTVIEW_SetRedraw(HWND hwnd, BOOL bRedraw)
8797 lResult = DefWindowProcA(hwnd, WM_SETREDRAW, bRedraw, 0);
8800 RedrawWindow(hwnd, NULL, 0,
8801 RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN | RDW_ERASENOW);
8808 * Resizes the listview control. This function processes WM_SIZE
8809 * messages. At this time, the width and height are not used.
8812 * [I] HWND : window handle
8813 * [I] WORD : new width
8814 * [I] WORD : new height
8819 static LRESULT LISTVIEW_Size(HWND hwnd, int Width, int Height)
8821 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8822 UINT uView = lStyle & LVS_TYPEMASK;
8824 TRACE("(hwnd=%x, width=%d, height=%d)\n",hwnd, Width, Height);
8826 LISTVIEW_UpdateSize(hwnd);
8828 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
8830 if (lStyle & LVS_ALIGNLEFT)
8832 LISTVIEW_AlignLeft(hwnd);
8836 LISTVIEW_AlignTop(hwnd);
8840 LISTVIEW_UpdateScroll(hwnd);
8842 /* invalidate client area + erase background */
8843 InvalidateRect(hwnd, NULL, TRUE);
8850 * Sets the size information.
8853 * [I] HWND : window handle
8858 static VOID LISTVIEW_UpdateSize(HWND hwnd)
8860 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8861 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8862 UINT uView = lStyle & LVS_TYPEMASK;
8865 GetClientRect(hwnd, &rcList);
8866 infoPtr->rcList.left = 0;
8867 infoPtr->rcList.right = max(rcList.right - rcList.left, 1);
8868 infoPtr->rcList.top = 0;
8869 infoPtr->rcList.bottom = max(rcList.bottom - rcList.top, 1);
8871 if (uView == LVS_LIST)
8873 if ((lStyle & WS_HSCROLL) == 0)
8875 INT nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
8876 if (infoPtr->rcList.bottom > nHScrollHeight)
8878 infoPtr->rcList.bottom -= nHScrollHeight;
8882 else if (uView == LVS_REPORT)
8889 Header_Layout(infoPtr->hwndHeader, &hl);
8891 SetWindowPos(wp.hwnd, wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
8893 if (!(LVS_NOCOLUMNHEADER & lStyle))
8895 infoPtr->rcList.top = max(wp.cy, 0);
8902 * Processes WM_STYLECHANGED messages.
8905 * [I] HWND : window handle
8906 * [I] WPARAM : window style type (normal or extended)
8907 * [I] LPSTYLESTRUCT : window style information
8912 static INT LISTVIEW_StyleChanged(HWND hwnd, WPARAM wStyleType,
8915 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8916 UINT uNewView = lpss->styleNew & LVS_TYPEMASK;
8917 UINT uOldView = lpss->styleOld & LVS_TYPEMASK;
8918 RECT rcList = infoPtr->rcList;
8920 TRACE("(hwnd=%x, styletype=%x, stylestruct=%p)\n",
8921 hwnd, wStyleType, lpss);
8923 if (wStyleType == GWL_STYLE)
8925 if (uOldView == LVS_REPORT)
8927 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
8930 if ((lpss->styleOld & WS_HSCROLL) != 0)
8932 ShowScrollBar(hwnd, SB_HORZ, FALSE);
8935 if ((lpss->styleOld & WS_VSCROLL) != 0)
8937 ShowScrollBar(hwnd, SB_VERT, FALSE);
8940 if (uNewView == LVS_ICON)
8942 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
8943 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
8944 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8945 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8946 if (lpss->styleNew & LVS_ALIGNLEFT)
8948 LISTVIEW_AlignLeft(hwnd);
8952 LISTVIEW_AlignTop(hwnd);
8955 else if (uNewView == LVS_REPORT)
8962 Header_Layout(infoPtr->hwndHeader, &hl);
8963 SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, wp.cy,
8965 if (!(LVS_NOCOLUMNHEADER & lpss->styleNew))
8966 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
8968 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
8969 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
8970 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8971 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8973 else if (uNewView == LVS_LIST)
8975 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
8976 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
8977 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8978 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8982 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
8983 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
8984 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8985 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8986 if (lpss->styleNew & LVS_ALIGNLEFT)
8988 LISTVIEW_AlignLeft(hwnd);
8992 LISTVIEW_AlignTop(hwnd);
8996 /* update the size of the client area */
8997 LISTVIEW_UpdateSize(hwnd);
8999 /* add scrollbars if needed */
9000 LISTVIEW_UpdateScroll(hwnd);
9002 /* invalidate client area + erase background */
9003 InvalidateRect(hwnd, NULL, TRUE);
9005 /* print the list of unsupported window styles */
9006 LISTVIEW_UnsupportedStyles(lpss->styleNew);
9009 /* If they change the view and we have an active edit control
9010 we will need to kill the control since the redraw will
9011 misplace the edit control.
9013 if (infoPtr->hwndEdit &&
9014 ((uNewView & (LVS_ICON|LVS_LIST|LVS_SMALLICON)) !=
9015 ((LVS_ICON|LVS_LIST|LVS_SMALLICON) & uOldView)))
9017 SendMessageA(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
9025 * Window procedure of the listview control.
9028 static LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
9031 TRACE("hwnd=%x uMsg=%x wParam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam);
9032 if (!GetWindowLongA(hwnd, 0) && (uMsg != WM_NCCREATE))
9033 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
9036 case LVM_APPROXIMATEVIEWRECT:
9037 return LISTVIEW_ApproximateViewRect(hwnd, (INT)wParam,
9038 LOWORD(lParam), HIWORD(lParam));
9040 return LISTVIEW_Arrange(hwnd, (INT)wParam);
9042 /* case LVM_CREATEDRAGIMAGE: */
9044 case LVM_DELETEALLITEMS:
9045 return LISTVIEW_DeleteAllItems(hwnd);
9047 case LVM_DELETECOLUMN:
9048 return LISTVIEW_DeleteColumn(hwnd, (INT)wParam);
9050 case LVM_DELETEITEM:
9051 return LISTVIEW_DeleteItem(hwnd, (INT)wParam);
9053 case LVM_EDITLABELW:
9054 case LVM_EDITLABELA:
9055 return LISTVIEW_EditLabelA(hwnd, (INT)wParam);
9057 case LVM_ENSUREVISIBLE:
9058 return LISTVIEW_EnsureVisible(hwnd, (INT)wParam, (BOOL)lParam);
9061 return LISTVIEW_FindItem(hwnd, (INT)wParam, (LPLVFINDINFO)lParam);
9063 case LVM_GETBKCOLOR:
9064 return LISTVIEW_GetBkColor(hwnd);
9066 /* case LVM_GETBKIMAGE: */
9068 case LVM_GETCALLBACKMASK:
9069 return LISTVIEW_GetCallbackMask(hwnd);
9071 case LVM_GETCOLUMNA:
9072 return LISTVIEW_GetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
9074 /* case LVM_GETCOLUMNW: */
9076 case LVM_GETCOLUMNORDERARRAY:
9077 return LISTVIEW_GetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
9079 case LVM_GETCOLUMNWIDTH:
9080 return LISTVIEW_GetColumnWidth(hwnd, (INT)wParam);
9082 case LVM_GETCOUNTPERPAGE:
9083 return LISTVIEW_GetCountPerPage(hwnd);
9085 case LVM_GETEDITCONTROL:
9086 return LISTVIEW_GetEditControl(hwnd);
9088 case LVM_GETEXTENDEDLISTVIEWSTYLE:
9089 return LISTVIEW_GetExtendedListViewStyle(hwnd);
9092 return LISTVIEW_GetHeader(hwnd);
9094 /* case LVM_GETHOTCURSOR: */
9096 case LVM_GETHOTITEM:
9097 return LISTVIEW_GetHotItem(hwnd);
9099 case LVM_GETHOVERTIME:
9100 return LISTVIEW_GetHoverTime(hwnd);
9102 case LVM_GETIMAGELIST:
9103 return LISTVIEW_GetImageList(hwnd, (INT)wParam);
9105 /* case LVM_GETISEARCHSTRING: */
9108 return LISTVIEW_GetItemA(hwnd, (LPLVITEMA)lParam, FALSE);
9110 /* case LVM_GETITEMW: */
9112 case LVM_GETITEMCOUNT:
9113 return LISTVIEW_GetItemCount(hwnd);
9115 case LVM_GETITEMPOSITION:
9116 return LISTVIEW_GetItemPosition(hwnd, (INT)wParam, (LPPOINT)lParam);
9118 case LVM_GETITEMRECT:
9119 return LISTVIEW_GetItemRect(hwnd, (INT)wParam, (LPRECT)lParam);
9121 case LVM_GETITEMSPACING:
9122 return LISTVIEW_GetItemSpacing(hwnd, (BOOL)wParam);
9124 case LVM_GETITEMSTATE:
9125 return LISTVIEW_GetItemState(hwnd, (INT)wParam, (UINT)lParam);
9127 case LVM_GETITEMTEXTA:
9128 LISTVIEW_GetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
9131 /* case LVM_GETITEMTEXTW: */
9133 case LVM_GETNEXTITEM:
9134 return LISTVIEW_GetNextItem(hwnd, (INT)wParam, LOWORD(lParam));
9136 /* case LVM_GETNUMBEROFWORKAREAS: */
9139 return LISTVIEW_GetOrigin(hwnd, (LPPOINT)lParam);
9141 case LVM_GETSELECTEDCOUNT:
9142 return LISTVIEW_GetSelectedCount(hwnd);
9144 case LVM_GETSELECTIONMARK:
9145 return LISTVIEW_GetSelectionMark(hwnd);
9147 case LVM_GETSTRINGWIDTHA:
9148 return LISTVIEW_GetStringWidthA (hwnd, (LPCSTR)lParam);
9150 /* case LVM_GETSTRINGWIDTHW: */
9151 /* case LVM_GETSUBITEMRECT: */
9153 case LVM_GETTEXTBKCOLOR:
9154 return LISTVIEW_GetTextBkColor(hwnd);
9156 case LVM_GETTEXTCOLOR:
9157 return LISTVIEW_GetTextColor(hwnd);
9159 /* case LVM_GETTOOLTIPS: */
9161 case LVM_GETTOPINDEX:
9162 return LISTVIEW_GetTopIndex(hwnd);
9164 /* case LVM_GETUNICODEFORMAT: */
9166 case LVM_GETVIEWRECT:
9167 return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam);
9169 /* case LVM_GETWORKAREAS: */
9172 return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam);
9174 case LVM_INSERTCOLUMNA:
9175 return LISTVIEW_InsertColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
9177 case LVM_INSERTCOLUMNW:
9178 return LISTVIEW_InsertColumnW(hwnd, (INT)wParam, (LPLVCOLUMNW)lParam);
9180 case LVM_INSERTITEMA:
9181 return LISTVIEW_InsertItemA(hwnd, (LPLVITEMA)lParam);
9183 case LVM_INSERTITEMW:
9184 return LISTVIEW_InsertItemW(hwnd, (LPLVITEMW)lParam);
9186 case LVM_REDRAWITEMS:
9187 return LISTVIEW_RedrawItems(hwnd, (INT)wParam, (INT)lParam);
9189 /* case LVM_SCROLL: */
9190 /* return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); */
9192 case LVM_SETBKCOLOR:
9193 return LISTVIEW_SetBkColor(hwnd, (COLORREF)lParam);
9195 /* case LVM_SETBKIMAGE: */
9197 case LVM_SETCALLBACKMASK:
9198 return LISTVIEW_SetCallbackMask(hwnd, (UINT)wParam);
9200 case LVM_SETCOLUMNA:
9201 return LISTVIEW_SetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
9203 case LVM_SETCOLUMNW:
9204 FIXME("Unimplemented msg LVM_SETCOLUMNW\n");
9207 case LVM_SETCOLUMNORDERARRAY:
9208 return LISTVIEW_SetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
9210 case LVM_SETCOLUMNWIDTH:
9211 return LISTVIEW_SetColumnWidth(hwnd, (INT)wParam, SLOWORD(lParam));
9213 case LVM_SETEXTENDEDLISTVIEWSTYLE:
9214 return LISTVIEW_SetExtendedListViewStyle(hwnd, (DWORD)wParam, (DWORD)lParam);
9216 /* case LVM_SETHOTCURSOR: */
9218 case LVM_SETHOTITEM:
9219 return LISTVIEW_SetHotItem(hwnd, (INT)wParam);
9221 case LVM_SETHOVERTIME:
9222 return LISTVIEW_SetHoverTime(hwnd, (DWORD)wParam);
9224 /* case LVM_SETICONSPACING: */
9226 case LVM_SETIMAGELIST:
9227 return LISTVIEW_SetImageList(hwnd, (INT)wParam, (HIMAGELIST)lParam);
9230 return LISTVIEW_SetItemA(hwnd, (LPLVITEMA)lParam);
9232 /* case LVM_SETITEMW: */
9234 case LVM_SETITEMCOUNT:
9235 return LISTVIEW_SetItemCount(hwnd, (INT)wParam, (DWORD)lParam);
9237 case LVM_SETITEMPOSITION:
9238 return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, (INT)LOWORD(lParam),
9239 (INT)HIWORD(lParam));
9241 case LVM_SETITEMPOSITION32:
9242 return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, ((POINT*)lParam)->x,
9243 ((POINT*)lParam)->y);
9245 case LVM_SETITEMSTATE:
9246 return LISTVIEW_SetItemState(hwnd, (INT)wParam, (LPLVITEMA)lParam);
9248 case LVM_SETITEMTEXTA:
9249 return LISTVIEW_SetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
9251 /* case LVM_SETITEMTEXTW: */
9253 case LVM_SETSELECTIONMARK:
9254 return LISTVIEW_SetSelectionMark(hwnd, (INT)lParam);
9256 case LVM_SETTEXTBKCOLOR:
9257 return LISTVIEW_SetTextBkColor(hwnd, (COLORREF)lParam);
9259 case LVM_SETTEXTCOLOR:
9260 return LISTVIEW_SetTextColor(hwnd, (COLORREF)lParam);
9262 /* case LVM_SETTOOLTIPS: */
9263 /* case LVM_SETUNICODEFORMAT: */
9264 /* case LVM_SETWORKAREAS: */
9267 return LISTVIEW_SortItems(hwnd, wParam, lParam);
9269 /* case LVM_SUBITEMHITTEST: */
9272 return LISTVIEW_Update(hwnd, (INT)wParam);
9276 return LISTVIEW_ProcessLetterKeys( hwnd, wParam, lParam );
9279 return LISTVIEW_Command(hwnd, wParam, lParam);
9282 return LISTVIEW_Create(hwnd, wParam, lParam);
9285 return LISTVIEW_EraseBackground(hwnd, wParam, lParam);
9288 return DLGC_WANTCHARS | DLGC_WANTARROWS;
9291 return LISTVIEW_GetFont(hwnd);
9294 return LISTVIEW_HScroll(hwnd, (INT)LOWORD(wParam),
9295 (INT)HIWORD(wParam), (HWND)lParam);
9298 return LISTVIEW_KeyDown(hwnd, (INT)wParam, (LONG)lParam);
9301 return LISTVIEW_KillFocus(hwnd);
9303 case WM_LBUTTONDBLCLK:
9304 return LISTVIEW_LButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
9307 case WM_LBUTTONDOWN:
9308 return LISTVIEW_LButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
9311 return LISTVIEW_LButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
9314 return LISTVIEW_MouseMove (hwnd, wParam, lParam);
9317 return LISTVIEW_MouseHover(hwnd, wParam, lParam);
9320 return LISTVIEW_NCCreate(hwnd, wParam, lParam);
9323 return LISTVIEW_NCDestroy(hwnd);
9326 return LISTVIEW_Notify(hwnd, (INT)wParam, (LPNMHDR)lParam);
9328 case WM_NOTIFYFORMAT:
9329 return LISTVIEW_NotifyFormat(hwnd, (HWND)wParam, (INT)lParam);
9332 return LISTVIEW_Paint(hwnd, (HDC)wParam);
9334 case WM_RBUTTONDBLCLK:
9335 return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
9338 case WM_RBUTTONDOWN:
9339 return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
9343 return LISTVIEW_RButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
9347 return LISTVIEW_SetFocus(hwnd, (HWND)wParam);
9350 return LISTVIEW_SetFont(hwnd, (HFONT)wParam, (WORD)lParam);
9353 return LISTVIEW_SetRedraw(hwnd, (BOOL)wParam);
9356 return LISTVIEW_Size(hwnd, (int)SLOWORD(lParam), (int)SHIWORD(lParam));
9358 case WM_STYLECHANGED:
9359 return LISTVIEW_StyleChanged(hwnd, wParam, (LPSTYLESTRUCT)lParam);
9361 /* case WM_TIMER: */
9364 return LISTVIEW_VScroll(hwnd, (INT)LOWORD(wParam),
9365 (INT)HIWORD(wParam), (HWND)lParam);
9368 if (wParam & (MK_SHIFT | MK_CONTROL))
9369 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
9370 return LISTVIEW_MouseWheel(hwnd, (short int)HIWORD(wParam));/* case WM_WINDOWPOSCHANGED: */
9372 /* case WM_WININICHANGE: */
9375 if (uMsg >= WM_USER)
9377 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam,
9381 /* call default window procedure */
9382 return DefWindowProcA(hwnd, uMsg, wParam, lParam);
9390 * Registers the window class.
9398 VOID LISTVIEW_Register(void)
9402 ZeroMemory(&wndClass, sizeof(WNDCLASSA));
9403 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
9404 wndClass.lpfnWndProc = (WNDPROC)LISTVIEW_WindowProc;
9405 wndClass.cbClsExtra = 0;
9406 wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *);
9407 wndClass.hCursor = LoadCursorA(0, IDC_ARROWA);
9408 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
9409 wndClass.lpszClassName = WC_LISTVIEWA;
9410 RegisterClassA(&wndClass);
9415 * Unregisters the window class.
9423 VOID LISTVIEW_Unregister(void)
9425 UnregisterClassA(WC_LISTVIEWA, (HINSTANCE)NULL);
9430 * Handle any WM_COMMAND messages
9436 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam)
9438 switch (HIWORD(wParam))
9443 * Adjust the edit window size
9446 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
9447 HDC hdc = GetDC(infoPtr->hwndEdit);
9448 HFONT hFont, hOldFont = 0;
9453 len = GetWindowTextA(infoPtr->hwndEdit, buffer, 1023);
9454 GetWindowRect(infoPtr->hwndEdit, &rect);
9456 /* Select font to get the right dimension of the string */
9457 hFont = SendMessageA(infoPtr->hwndEdit, WM_GETFONT, 0, 0);
9460 hOldFont = SelectObject(hdc, hFont);
9463 if (GetTextExtentPoint32A(hdc, buffer, strlen(buffer), &sz))
9465 TEXTMETRICA textMetric;
9467 /* Add Extra spacing for the next character */
9468 GetTextMetricsA(hdc, &textMetric);
9469 sz.cx += (textMetric.tmMaxCharWidth * 2);
9477 rect.bottom - rect.top,
9478 SWP_DRAWFRAME|SWP_NOMOVE);
9482 SelectObject(hdc, hOldFont);
9485 ReleaseDC(hwnd, hdc);
9491 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
9500 * Subclassed edit control windproc function
9506 LRESULT CALLBACK EditLblWndProc(HWND hwnd, UINT uMsg,
9507 WPARAM wParam, LPARAM lParam)
9509 BOOL cancel = FALSE;
9510 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(GetParent(hwnd), 0);
9511 EDITLABEL_ITEM *einfo = infoPtr->pedititem;
9512 static BOOL bIgnoreKillFocus = FALSE;
9516 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
9519 if(bIgnoreKillFocus)
9527 WNDPROC editProc = einfo->EditWndProc;
9528 SetWindowLongA(hwnd, GWL_WNDPROC, (LONG)editProc);
9529 COMCTL32_Free(einfo);
9530 infoPtr->pedititem = NULL;
9531 return CallWindowProcA(editProc, hwnd, uMsg, wParam, lParam);
9535 if (VK_ESCAPE == (INT)wParam)
9541 else if (VK_RETURN == (INT)wParam)
9545 return CallWindowProcA(einfo->EditWndProc, hwnd,
9546 uMsg, wParam, lParam);
9549 if (einfo->EditLblCb)
9551 char *buffer = NULL;
9556 int len = 1 + GetWindowTextLengthA(hwnd);
9560 if (NULL != (buffer = (char *)COMCTL32_Alloc(len*sizeof(char))))
9562 GetWindowTextA(hwnd, buffer, len);
9566 /* Processing LVN_ENDLABELEDIT message could kill the focus */
9567 /* eg. Using a messagebox */
9568 bIgnoreKillFocus = TRUE;
9569 einfo->EditLblCb(GetParent(hwnd), buffer, einfo->param);
9572 COMCTL32_Free(buffer);
9574 einfo->EditLblCb = NULL;
9575 bIgnoreKillFocus = FALSE;
9578 SendMessageA(hwnd, WM_CLOSE, 0, 0);
9585 * Creates a subclassed edit cotrol
9591 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
9592 INT width, INT height, HWND parent, HINSTANCE hinst,
9593 EditlblCallback EditLblCb, DWORD param)
9599 TEXTMETRICA textMetric;
9600 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(parent, 0);
9602 if (NULL == (infoPtr->pedititem = COMCTL32_Alloc(sizeof(EDITLABEL_ITEM))))
9605 style |= WS_CHILDWINDOW|WS_CLIPSIBLINGS|ES_LEFT|WS_BORDER;
9606 hdc = GetDC(parent);
9608 /* Select the font to get appropriate metric dimensions */
9609 if(infoPtr->hFont != 0)
9611 hOldFont = SelectObject(hdc, infoPtr->hFont);
9614 /*Get String Lenght in pixels */
9615 GetTextExtentPoint32A(hdc, text, strlen(text), &sz);
9617 /*Add Extra spacing for the next character */
9618 GetTextMetricsA(hdc, &textMetric);
9619 sz.cx += (textMetric.tmMaxCharWidth * 2);
9621 if(infoPtr->hFont != 0)
9623 SelectObject(hdc, hOldFont);
9626 ReleaseDC(parent, hdc);
9627 if (!(hedit = CreateWindowA("Edit", text, style, x, y, sz.cx, height,
9628 parent, 0, hinst, 0)))
9630 COMCTL32_Free(infoPtr->pedititem);
9634 infoPtr->pedititem->param = param;
9635 infoPtr->pedititem->EditLblCb = EditLblCb;
9636 infoPtr->pedititem->EditWndProc = (WNDPROC)SetWindowLongA(hedit,
9637 GWL_WNDPROC, (LONG) EditLblWndProc);
9639 SendMessageA(hedit, WM_SETFONT, infoPtr->hFont, FALSE);