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)
2552 LISTVIEW_AddSelectionRange(hwnd,lpLVItem->iItem,lpLVItem->iItem);
2554 LISTVIEW_RemoveSelectionRange(hwnd,lpLVItem->iItem,
2558 nmlv.hdr.code = LVN_ITEMCHANGED;
2560 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2562 rcItem.left = LVIR_BOUNDS;
2563 LISTVIEW_GetItemRect(hwnd, lpLVItem->iItem, &rcItem);
2564 InvalidateRect(hwnd, &rcItem, TRUE);
2572 if (lpLVItem != NULL)
2574 if (lpLVItem->iSubItem == 0)
2576 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
2577 if (hdpaSubItems != NULL && hdpaSubItems != (HDPA)-1)
2579 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem);
2582 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2583 nmlv.hdr.hwndFrom = hwnd;
2584 nmlv.hdr.idFrom = lCtrlId;
2585 nmlv.hdr.code = LVN_ITEMCHANGING;
2586 nmlv.lParam = lpItem->lParam;
2587 uChanged = LISTVIEW_GetItemChanges(lpItem, lpLVItem);
2590 if (uChanged & LVIF_STATE)
2592 nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask;
2593 nmlv.uOldState = lpItem->state & lpLVItem->stateMask;
2595 if (nmlv.uNewState & LVIS_SELECTED)
2598 * This is redundant if called through SetSelection
2600 * however is required if the used directly calls SetItem
2601 * to set the selection.
2603 if (lStyle & LVS_SINGLESEL)
2605 LISTVIEW_RemoveAllSelections(hwnd);
2608 LISTVIEW_AddSelectionRange(hwnd,lpLVItem->iItem,
2611 else if (lpLVItem->stateMask & LVIS_SELECTED)
2613 LISTVIEW_RemoveSelectionRange(hwnd,lpLVItem->iItem,
2616 if (nmlv.uNewState & LVIS_FOCUSED)
2619 * This is a fun hoop to jump to try to catch if
2620 * the user is calling us directly to call focus or if
2621 * this function is being called as a result of a
2622 * SetItemFocus call.
2624 if (infoPtr->nFocusedItem >= 0)
2625 LISTVIEW_SetItemFocus(hwnd, lpLVItem->iItem);
2629 nmlv.uChanged = uChanged;
2630 nmlv.iItem = lpLVItem->iItem;
2631 nmlv.lParam = lpItem->lParam;
2632 /* send LVN_ITEMCHANGING notification */
2633 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2635 /* copy information */
2636 bResult = LISTVIEW_InitItem(hwnd, lpItem, lpLVItem);
2638 /* if LVS_LIST or LVS_SMALLICON, update the width of the items
2639 based on the width of the items text */
2640 if((uView == LVS_LIST) || (uView == LVS_SMALLICON))
2642 item_width = LISTVIEW_GetStringWidthA(hwnd, lpItem->pszText);
2644 if(item_width > infoPtr->nItemWidth)
2645 infoPtr->nItemWidth = item_width;
2648 /* send LVN_ITEMCHANGED notification */
2649 nmlv.hdr.code = LVN_ITEMCHANGED;
2650 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2659 rcItem.left = LVIR_BOUNDS;
2660 LISTVIEW_GetItemRect(hwnd, lpLVItem->iItem, &rcItem);
2661 InvalidateRect(hwnd, &rcItem, TRUE);
2673 * Sets subitem attributes.
2676 * [I] HWND : window handle
2677 * [I] LPLVITEM : new subitem atttributes
2683 static BOOL LISTVIEW_SetSubItem(HWND hwnd, LPLVITEMA lpLVItem)
2685 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2686 BOOL bResult = FALSE;
2688 LISTVIEW_SUBITEM *lpSubItem;
2689 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2692 if (lStyle & LVS_OWNERDATA)
2695 if (lpLVItem != NULL)
2697 if (lpLVItem->iSubItem > 0)
2699 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
2700 if (hdpaSubItems != NULL)
2702 /* set subitem only if column is present */
2703 if (Header_GetItemCount(infoPtr->hwndHeader) > lpLVItem->iSubItem)
2705 lpSubItem = LISTVIEW_GetSubItem(hdpaSubItems, lpLVItem->iSubItem);
2706 if (lpSubItem != NULL)
2708 bResult = LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem);
2712 bResult = LISTVIEW_AddSubItem(hwnd, lpLVItem);
2715 rcItem.left = LVIR_BOUNDS;
2716 LISTVIEW_GetItemRect(hwnd, lpLVItem->iItem, &rcItem);
2717 InvalidateRect(hwnd, &rcItem, FALSE);
2728 * Retrieves the index of the item at coordinate (0, 0) of the client area.
2731 * [I] HWND : window handle
2736 static INT LISTVIEW_GetTopIndex(HWND hwnd)
2738 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2739 UINT uView = lStyle & LVS_TYPEMASK;
2741 SCROLLINFO scrollInfo;
2743 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2744 scrollInfo.cbSize = sizeof(SCROLLINFO);
2745 scrollInfo.fMask = SIF_POS;
2747 if (uView == LVS_LIST)
2749 if (lStyle & WS_HSCROLL)
2751 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2753 nItem = scrollInfo.nPos * LISTVIEW_GetCountPerColumn(hwnd);
2757 else if (uView == LVS_REPORT)
2759 if (lStyle & WS_VSCROLL)
2761 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
2763 nItem = scrollInfo.nPos;
2776 * [I] HWND : window handle
2777 * [I] HDC : device context handle
2778 * [I] INT : item index
2779 * [I] INT : subitem index
2780 * [I] RECT * : clipping rectangle
2785 static VOID LISTVIEW_DrawSubItem(HWND hwnd, HDC hdc, INT nItem, INT nSubItem,
2786 RECT rcItem, BOOL Selected)
2788 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2789 CHAR szDispText[DISP_TEXT_SIZE];
2791 UINT textoutOptions = ETO_CLIPPED | ETO_OPAQUE;
2794 TRACE("(hwnd=%x, hdc=%x, nItem=%d, nSubItem=%d)\n", hwnd, hdc,
2797 /* get information needed for drawing the item */
2798 ZeroMemory(&lvItem, sizeof(LVITEMA));
2799 lvItem.mask = LVIF_TEXT;
2800 lvItem.iItem = nItem;
2801 lvItem.iSubItem = nSubItem;
2802 lvItem.cchTextMax = DISP_TEXT_SIZE;
2803 lvItem.pszText = szDispText;
2804 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
2806 /* redraw the background of the item */
2808 if(infoPtr->nColumnCount == (nSubItem + 1))
2809 rcTemp.right = infoPtr->rcList.right;
2811 rcTemp.right+=WIDTH_PADDING;
2813 LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
2815 /* set item colors */
2816 if (ListView_GetItemState(hwnd,nItem,LVIS_SELECTED) && Selected)
2818 if (infoPtr->bFocus)
2820 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
2821 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2825 SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
2826 SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
2831 if ( (infoPtr->clrTextBk == CLR_DEFAULT) || (infoPtr->clrTextBk == CLR_NONE) )
2833 SetBkMode(hdc, TRANSPARENT);
2834 textoutOptions &= ~ETO_OPAQUE;
2838 SetBkMode(hdc, OPAQUE);
2839 SetBkColor(hdc, infoPtr->clrTextBk);
2842 SetTextColor(hdc, infoPtr->clrText);
2845 ExtTextOutA(hdc, rcItem.left, rcItem.top, textoutOptions,
2846 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
2850 /* fill in the gap */
2852 if (nSubItem < Header_GetItemCount(infoPtr->hwndHeader)-1)
2854 CopyRect(&rec,&rcItem);
2855 rec.left = rec.right;
2856 rec.right = rec.left+REPORT_MARGINX;
2857 ExtTextOutA(hdc, rec.left , rec.top, textoutOptions,
2858 &rec, NULL, 0, NULL);
2860 CopyRect(&rec,&rcItem);
2861 rec.right = rec.left;
2862 rec.left = rec.left - REPORT_MARGINX;
2863 ExtTextOutA(hdc, rec.left , rec.top, textoutOptions,
2864 &rec, NULL, 0, NULL);
2874 * [I] HWND : window handle
2875 * [I] HDC : device context handle
2876 * [I] INT : item index
2877 * [I] RECT * : clipping rectangle
2882 static VOID LISTVIEW_DrawItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem, BOOL FullSelect, RECT* SuggestedFocus)
2884 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2885 CHAR szDispText[DISP_TEXT_SIZE];
2890 DWORD dwTextColor,dwTextX;
2891 BOOL bImage = FALSE;
2893 UINT textoutOptions = ETO_OPAQUE | ETO_CLIPPED;
2896 TRACE("(hwnd=%x, hdc=%x, nItem=%d)\n", hwnd, hdc, nItem);
2899 /* get information needed for drawing the item */
2900 ZeroMemory(&lvItem, sizeof(LVITEMA));
2901 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_INDENT;
2902 lvItem.stateMask = LVIS_SELECTED | LVIS_STATEIMAGEMASK;
2903 lvItem.iItem = nItem;
2904 lvItem.iSubItem = 0;
2905 lvItem.cchTextMax = DISP_TEXT_SIZE;
2906 lvItem.pszText = szDispText;
2907 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
2909 /* redraw the background of the item */
2911 if(infoPtr->nColumnCount == (nItem + 1))
2912 rcTemp.right = infoPtr->rcList.right;
2914 rcTemp.right+=WIDTH_PADDING;
2916 LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
2919 if (lvItem.iIndent>0 && infoPtr->iconSize.cx > 0)
2921 rcItem.left += infoPtr->iconSize.cx * lvItem.iIndent;
2924 SuggestedFocus->left += infoPtr->iconSize.cx * lvItem.iIndent;
2928 if (infoPtr->himlState != NULL)
2930 UINT uStateImage = (lvItem.state & LVIS_STATEIMAGEMASK) >> 12;
2931 if (uStateImage > 0)
2933 ImageList_Draw(infoPtr->himlState, uStateImage - 1, hdc, rcItem.left,
2934 rcItem.top, ILD_NORMAL);
2937 rcItem.left += infoPtr->iconSize.cx;
2939 SuggestedFocus->left += infoPtr->iconSize.cx;
2944 if (infoPtr->himlSmall != NULL)
2946 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE) &&
2949 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
2950 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
2951 rcItem.top, ILD_SELECTED);
2953 else if (lvItem.iImage>=0)
2955 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
2956 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
2957 rcItem.top, ILD_NORMAL);
2960 rcItem.left += infoPtr->iconSize.cx;
2963 SuggestedFocus->left += infoPtr->iconSize.cx;
2967 /* Don't bother painting item being edited */
2968 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED && !FullSelect)
2971 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
2973 /* set item colors */
2974 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
2975 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2976 /* set raster mode */
2977 nMixMode = SetROP2(hdc, R2_XORPEN);
2979 else if ((GetWindowLongA(hwnd, GWL_STYLE) & LVS_SHOWSELALWAYS) &&
2980 (lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus == FALSE))
2982 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
2983 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
2984 /* set raster mode */
2985 nMixMode = SetROP2(hdc, R2_COPYPEN);
2989 /* set item colors */
2990 if ( (infoPtr->clrTextBk == CLR_DEFAULT) || (infoPtr->clrTextBk == CLR_NONE) )
2992 dwBkColor = GetBkColor(hdc);
2993 iBkMode = SetBkMode(hdc, TRANSPARENT);
2994 textoutOptions &= ~ETO_OPAQUE;
2998 dwBkColor = SetBkColor(hdc, infoPtr->clrTextBk);
2999 iBkMode = SetBkMode(hdc, OPAQUE);
3002 dwTextColor = SetTextColor(hdc, infoPtr->clrText);
3003 /* set raster mode */
3004 nMixMode = SetROP2(hdc, R2_COPYPEN);
3007 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
3008 if (rcItem.left + nLabelWidth < rcItem.right)
3011 rcItem.right = rcItem.left + nLabelWidth + TRAILING_PADDING;
3013 rcItem.right += IMAGE_PADDING;
3017 dwTextX = rcItem.left + 1;
3019 dwTextX += IMAGE_PADDING;
3022 ExtTextOutA(hdc, dwTextX, rcItem.top, textoutOptions,
3023 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
3025 if ((FullSelect)&&(Header_GetItemCount(infoPtr->hwndHeader) > 1))
3027 /* fill in the gap */
3029 CopyRect(&rec,&rcItem);
3030 rec.left = rec.right;
3031 rec.right = rec.left+REPORT_MARGINX;
3032 ExtTextOutA(hdc, rec.left , rec.top, textoutOptions,
3033 &rec, NULL, 0, NULL);
3037 CopyRect(SuggestedFocus,&rcItem);
3041 SetROP2(hdc, R2_COPYPEN);
3042 SetBkColor(hdc, dwBkColor);
3043 SetTextColor(hdc, dwTextColor);
3045 SetBkMode(hdc, iBkMode);
3051 * Draws an item when in large icon display mode.
3054 * [I] HWND : window handle
3055 * [I] HDC : device context handle
3056 * [I] LISTVIEW_ITEM * : item
3057 * [I] INT : item index
3058 * [I] RECT * : clipping rectangle
3063 static VOID LISTVIEW_DrawLargeItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem,
3064 RECT *SuggestedFocus)
3066 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3067 CHAR szDispText[DISP_TEXT_SIZE];
3068 INT nDrawPosX = rcItem.left;
3069 INT nLabelWidth, rcWidth;
3072 UINT textoutOptions = ETO_CLIPPED | ETO_OPAQUE;
3075 TRACE("(hwnd=%x, hdc=%x, nItem=%d, left=%d, top=%d, right=%d, \
3076 bottom=%d)\n", hwnd, hdc, nItem, rcItem.left, rcItem.top, rcItem.right,
3079 /* get information needed for drawing the item */
3080 ZeroMemory(&lvItem, sizeof(LVITEMA));
3081 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
3082 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
3083 lvItem.iItem = nItem;
3084 lvItem.iSubItem = 0;
3085 lvItem.cchTextMax = DISP_TEXT_SIZE;
3086 lvItem.pszText = szDispText;
3087 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
3089 /* redraw the background of the item */
3091 if(infoPtr->nColumnCount == (nItem + 1))
3092 rcTemp.right = infoPtr->rcList.right;
3094 rcTemp.right+=WIDTH_PADDING;
3096 LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
3098 if (lvItem.state & LVIS_SELECTED)
3100 /* set item colors */
3101 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
3102 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
3103 /* set raster mode */
3104 SetROP2(hdc, R2_XORPEN);
3108 /* set item colors */
3109 if ( (infoPtr->clrTextBk == CLR_DEFAULT) || (infoPtr->clrTextBk == CLR_NONE) )
3111 SetBkMode(hdc, TRANSPARENT);
3112 textoutOptions &= ~ETO_OPAQUE;
3116 SetBkMode(hdc, OPAQUE);
3117 SetBkColor(hdc, infoPtr->clrTextBk);
3120 SetTextColor(hdc, infoPtr->clrText);
3121 /* set raster mode */
3122 SetROP2(hdc, R2_COPYPEN);
3125 if (infoPtr->himlNormal != NULL)
3127 rcItem.top += ICON_TOP_PADDING;
3128 nDrawPosX += (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
3129 if ((lvItem.state & LVIS_SELECTED) && (lvItem.iImage>=0))
3131 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
3132 rcItem.top, ILD_SELECTED);
3134 else if (lvItem.iImage>=0)
3136 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
3137 rcItem.top, ILD_NORMAL);
3141 /* Don't bother painting item being edited */
3142 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED)
3145 InflateRect(&rcItem, -(2*CAPTION_BORDER), 0);
3146 rcItem.top += infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
3147 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
3148 GetTextMetricsA(hdc, &tm);
3150 /* append an ellipse ('...') if the caption won't fit in the rect */
3151 rcWidth = max(0, rcItem.right - rcItem.left);
3152 if (nLabelWidth > rcWidth)
3154 INT i, len, eos, nCharsFit;
3155 /* give or take a couple, how many average sized chars would fit? */
3156 nCharsFit = tm.tmAveCharWidth > 0 ? (rcWidth/tm.tmAveCharWidth)+2 : 0;
3157 /* place the ellipse accordingly, without overrunning the buffer */
3158 len = strlen(szDispText);
3159 eos = min((nCharsFit > 1 && nCharsFit < len) ? nCharsFit+3 : len+2,
3160 sizeof(szDispText)-1);
3162 nLabelWidth = ListView_GetStringWidthA(hwnd, szDispText);
3163 while ((nLabelWidth > rcWidth) && (eos > 3))
3165 for (i = 1; i < 4; i++)
3166 szDispText[eos-i] = '.';
3167 /* shift the ellipse one char to the left for each iteration */
3168 szDispText[eos--] = '\0';
3169 nLabelWidth = ListView_GetStringWidthA(hwnd, szDispText);
3173 InflateRect(&rcItem, 2*CAPTION_BORDER, 0);
3174 nDrawPosX = infoPtr->iconSpacing.cx - 2*CAPTION_BORDER - nLabelWidth;
3177 rcItem.left += nDrawPosX / 2;
3178 rcItem.right = rcItem.left + nLabelWidth + 2*CAPTION_BORDER;
3183 rcItem.right = rcItem.left + infoPtr->iconSpacing.cx - 1;
3187 rcItem.bottom = rcItem.top + tm.tmHeight + HEIGHT_PADDING;
3189 ExtTextOutA(hdc, rcItem.left + CAPTION_BORDER, rcItem.top, textoutOptions,
3190 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
3193 CopyRect(SuggestedFocus,&rcItem);
3198 * Draws listview items when in report display mode.
3201 * [I] HWND : window handle
3202 * [I] HDC : device context handle
3207 static VOID LISTVIEW_RefreshReport(HWND hwnd, HDC hdc, DWORD cdmode)
3209 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
3210 SCROLLINFO scrollInfo;
3211 INT nDrawPosY = infoPtr->rcList.top;
3213 RECT rcItem, rcTemp;
3218 DWORD cditemmode = CDRF_DODEFAULT;
3219 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3221 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
3222 scrollInfo.cbSize = sizeof(SCROLLINFO);
3223 scrollInfo.fMask = SIF_POS;
3225 nItem = ListView_GetTopIndex(hwnd);
3227 /* add 1 for displaying a partial item at the bottom */
3228 nLast = nItem + LISTVIEW_GetCountPerColumn(hwnd) + 1;
3229 nLast = min(nLast, GETITEMCOUNT(infoPtr));
3231 /* send cache hint notification */
3232 if (GetWindowLongA(hwnd,GWL_STYLE) & LVS_OWNERDATA)
3236 nmlv.hdr.hwndFrom = hwnd;
3237 nmlv.hdr.idFrom = GetWindowLongA(hwnd,GWL_ID);
3238 nmlv.hdr.code = LVN_ODCACHEHINT;
3242 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)nmlv.hdr.idFrom,
3246 nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
3247 infoPtr->nColumnCount = nColumnCount; /* update nColumnCount */
3248 FullSelected = infoPtr->dwExStyle & LVS_EX_FULLROWSELECT;
3250 /* clear the background of any part of the control that doesn't contain items */
3251 SubtractRect(&rcTemp, &infoPtr->rcList, &infoPtr->rcView);
3252 LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
3254 /* nothing to draw */
3255 if(GETITEMCOUNT(infoPtr) == 0)
3258 for (; nItem < nLast; nItem++)
3260 RECT SuggestedFocusRect;
3263 if (lStyle & LVS_OWNERDRAWFIXED)
3265 UINT uID = GetWindowLongA( hwnd, GWL_ID);
3270 TRACE("Owner Drawn\n");
3271 dis.CtlType = ODT_LISTVIEW;
3274 dis.itemAction = ODA_DRAWENTIRE;
3277 if (LISTVIEW_IsSelected(hwnd,nItem)) dis.itemState|=ODS_SELECTED;
3278 if (nItem==infoPtr->nFocusedItem) dis.itemState|=ODS_FOCUS;
3280 dis.hwndItem = hwnd;
3283 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
3286 dis.rcItem.right = max(dis.rcItem.left, br.right);
3287 dis.rcItem.top = nDrawPosY;
3288 dis.rcItem.bottom = dis.rcItem.top + infoPtr->nItemHeight;
3290 ZeroMemory(&item,sizeof(LVITEMA));
3292 item.mask = LVIF_PARAM;
3293 ListView_GetItemA(hwnd,&item);
3295 dis.itemData = item.lParam;
3297 if (SendMessageA(GetParent(hwnd),WM_DRAWITEM,(WPARAM)uID,(LPARAM)&dis))
3299 nDrawPosY += infoPtr->nItemHeight;
3308 Header_GetItemRect(infoPtr->hwndHeader, 0, &ir);
3309 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
3311 ir.left += REPORT_MARGINX;
3312 ir.right = max(ir.left, br.right - REPORT_MARGINX);
3314 ir.bottom = ir.top + infoPtr->nItemHeight;
3316 CopyRect(&SuggestedFocusRect,&ir);
3319 for (j = 0; j < nColumnCount; j++)
3321 if (cdmode & CDRF_NOTIFYITEMDRAW)
3322 cditemmode = LISTVIEW_SendCustomDrawItemNotify (hwnd, hdc, nItem, j,
3324 if (cditemmode & CDRF_SKIPDEFAULT)
3327 Header_GetItemRect(infoPtr->hwndHeader, j, &rcItem);
3329 rcItem.left += REPORT_MARGINX;
3330 rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX);
3331 rcItem.top = nDrawPosY;
3332 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
3334 /* Offset the Scroll Bar Pos */
3335 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
3337 rcItem.left -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
3338 rcItem.right -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
3343 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem, FullSelected,
3344 &SuggestedFocusRect);
3348 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, j, rcItem,
3352 if (cditemmode & CDRF_NOTIFYPOSTPAINT)
3353 LISTVIEW_SendCustomDrawItemNotify(hwnd, hdc, nItem, 0,
3354 CDDS_ITEMPOSTPAINT);
3359 if (LISTVIEW_GetItemState(hwnd,nItem,LVIS_FOCUSED) && infoPtr->bFocus)
3362 if (FullSelected && LISTVIEW_GetItemState(hwnd,nItem,LVIS_SELECTED))
3363 rop = SetROP2(hdc, R2_XORPEN);
3365 Rectangle(hdc, SuggestedFocusRect.left, SuggestedFocusRect.top,
3366 SuggestedFocusRect.right,SuggestedFocusRect.bottom);
3369 SetROP2(hdc, R2_COPYPEN);
3371 nDrawPosY += infoPtr->nItemHeight;
3377 * Retrieves the number of items that can fit vertically in the client area.
3380 * [I] HWND : window handle
3383 * Number of items per row.
3385 static INT LISTVIEW_GetCountPerRow(HWND hwnd)
3387 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
3388 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3389 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
3390 INT nCountPerRow = 1;
3394 if (uView == LVS_REPORT)
3400 nCountPerRow = nListWidth / infoPtr->nItemWidth;
3401 if (nCountPerRow == 0)
3408 return nCountPerRow;
3413 * Retrieves the number of items that can fit horizontally in the client
3417 * [I] HWND : window handle
3420 * Number of items per column.
3422 static INT LISTVIEW_GetCountPerColumn(HWND hwnd)
3424 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
3425 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
3426 INT nCountPerColumn = 1;
3428 if (nListHeight > 0)
3430 nCountPerColumn = nListHeight / infoPtr->nItemHeight;
3431 if (nCountPerColumn == 0)
3433 nCountPerColumn = 1;
3437 return nCountPerColumn;
3442 * Retrieves the number of columns needed to display all the items when in
3443 * list display mode.
3446 * [I] HWND : window handle
3449 * Number of columns.
3451 static INT LISTVIEW_GetColumnCount(HWND hwnd)
3453 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3454 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3455 INT nColumnCount = 0;
3457 if ((lStyle & LVS_TYPEMASK) == LVS_LIST)
3459 if (infoPtr->rcList.right % infoPtr->nItemWidth == 0)
3461 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth;
3465 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth + 1;
3469 return nColumnCount;
3475 * Draws listview items when in list display mode.
3478 * [I] HWND : window handle
3479 * [I] HDC : device context handle
3484 static VOID LISTVIEW_RefreshList(HWND hwnd, HDC hdc, DWORD cdmode)
3486 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3487 RECT rcItem, FocusRect, rcTemp;
3491 INT nCountPerColumn;
3492 INT nItemWidth = infoPtr->nItemWidth;
3493 INT nItemHeight = infoPtr->nItemHeight;
3494 DWORD cditemmode = CDRF_DODEFAULT;
3496 /* get number of fully visible columns */
3497 nColumnCount = LISTVIEW_GetColumnCount(hwnd);
3498 infoPtr->nColumnCount = nColumnCount;
3499 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
3500 nItem = ListView_GetTopIndex(hwnd);
3502 /* paint the background of the control that doesn't contain any items */
3503 SubtractRect(&rcTemp, &infoPtr->rcList, &infoPtr->rcView);
3504 LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
3506 /* nothing to draw, return here */
3507 if(GETITEMCOUNT(infoPtr) == 0)
3510 for (i = 0; i < nColumnCount; i++)
3512 for (j = 0; j < nCountPerColumn; j++, nItem++)
3514 if (nItem >= GETITEMCOUNT(infoPtr))
3517 if (cdmode & CDRF_NOTIFYITEMDRAW)
3518 cditemmode = LISTVIEW_SendCustomDrawItemNotify (hwnd, hdc, nItem, 0,
3520 if (cditemmode & CDRF_SKIPDEFAULT)
3523 rcItem.top = j * nItemHeight;
3524 rcItem.left = i * nItemWidth;
3525 rcItem.bottom = rcItem.top + nItemHeight;
3526 rcItem.right = rcItem.left + nItemWidth;
3527 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem, FALSE, &FocusRect);
3531 if (LISTVIEW_GetItemState(hwnd,nItem,LVIS_FOCUSED) && infoPtr->bFocus)
3532 Rectangle(hdc, FocusRect.left, FocusRect.top,
3533 FocusRect.right,FocusRect.bottom);
3535 if (cditemmode & CDRF_NOTIFYPOSTPAINT)
3536 LISTVIEW_SendCustomDrawItemNotify(hwnd, hdc, nItem, 0,
3537 CDDS_ITEMPOSTPAINT);
3545 * Draws listview items when in icon or small icon display mode.
3548 * [I] HWND : window handle
3549 * [I] HDC : device context handle
3554 static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc, BOOL bSmall, DWORD cdmode)
3556 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3559 RECT rcItem, SuggestedFocus, rcTemp;
3561 DWORD cditemmode = CDRF_DODEFAULT;
3563 infoPtr->nColumnCount = 1; /* set this to an arbitrary value to prevent */
3564 /* DrawItem from erasing the incorrect background area */
3566 /* paint the background of the control that doesn't contain any items */
3567 SubtractRect(&rcTemp, &infoPtr->rcList, &infoPtr->rcView);
3568 LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
3570 /* nothing to draw, return here */
3571 if(GETITEMCOUNT(infoPtr) == 0)
3574 LISTVIEW_GetOrigin(hwnd, &ptOrigin);
3575 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
3577 if (cdmode & CDRF_NOTIFYITEMDRAW)
3578 cditemmode = LISTVIEW_SendCustomDrawItemNotify (hwnd, hdc, i, 0,
3580 if (cditemmode & CDRF_SKIPDEFAULT)
3583 LISTVIEW_GetItemPosition(hwnd, i, &ptPosition);
3584 ptPosition.x += ptOrigin.x;
3585 ptPosition.y += ptOrigin.y;
3587 if (ptPosition.y + infoPtr->nItemHeight > infoPtr->rcList.top)
3589 if (ptPosition.x + infoPtr->nItemWidth > infoPtr->rcList.left)
3591 if (ptPosition.y < infoPtr->rcList.bottom)
3593 if (ptPosition.x < infoPtr->rcList.right)
3595 rcItem.top = ptPosition.y;
3596 rcItem.left = ptPosition.x;
3597 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
3598 rcItem.right = rcItem.left + infoPtr->nItemWidth;
3599 if (bSmall == FALSE)
3601 LISTVIEW_DrawLargeItem(hwnd, hdc, i, rcItem, &SuggestedFocus);
3605 LISTVIEW_DrawItem(hwnd, hdc, i, rcItem, FALSE, &SuggestedFocus);
3610 if (LISTVIEW_GetItemState(hwnd,i,LVIS_FOCUSED) &&
3612 Rectangle(hdc, SuggestedFocus.left, SuggestedFocus.top,
3613 SuggestedFocus.right,SuggestedFocus.bottom);
3618 if (cditemmode & CDRF_NOTIFYPOSTPAINT)
3619 LISTVIEW_SendCustomDrawItemNotify(hwnd, hdc, i, 0,
3620 CDDS_ITEMPOSTPAINT);
3626 * Draws listview items.
3629 * [I] HWND : window handle
3630 * [I] HDC : device context handle
3635 static VOID LISTVIEW_Refresh(HWND hwnd, HDC hdc)
3637 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3638 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3644 GetClientRect(hwnd, &rect);
3645 cdmode = LISTVIEW_SendCustomDrawNotify(hwnd,CDDS_PREPAINT,hdc,rect);
3647 if (cdmode == CDRF_SKIPDEFAULT) return;
3650 hOldFont = SelectObject(hdc, infoPtr->hFont);
3652 /* select the dotted pen (for drawing the focus box) */
3653 hPen = CreatePen(PS_ALTERNATE, 1, 0);
3654 hOldPen = SelectObject(hdc, hPen);
3656 /* select transparent brush (for drawing the focus box) */
3657 SelectObject(hdc, GetStockObject(NULL_BRUSH));
3659 if (uView == LVS_LIST)
3661 LISTVIEW_RefreshList(hwnd, hdc, cdmode);
3663 else if (uView == LVS_REPORT)
3665 LISTVIEW_RefreshReport(hwnd, hdc, cdmode);
3667 else if (uView == LVS_SMALLICON)
3669 LISTVIEW_RefreshIcon(hwnd, hdc, TRUE, cdmode);
3671 else if (uView == LVS_ICON)
3673 LISTVIEW_RefreshIcon(hwnd, hdc, FALSE, cdmode);
3676 /* unselect objects */
3677 SelectObject(hdc, hOldFont);
3678 SelectObject(hdc, hOldPen);
3683 if (cdmode & CDRF_NOTIFYPOSTPAINT)
3684 LISTVIEW_SendCustomDrawNotify(hwnd, CDDS_POSTPAINT, hdc, rect);
3690 * Calculates the approximate width and height of a given number of items.
3693 * [I] HWND : window handle
3694 * [I] INT : number of items
3699 * Returns a DWORD. The width in the low word and the height in high word.
3701 static LRESULT LISTVIEW_ApproximateViewRect(HWND hwnd, INT nItemCount,
3702 WORD wWidth, WORD wHeight)
3704 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3705 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3706 INT nItemCountPerColumn = 1;
3707 INT nColumnCount = 0;
3708 DWORD dwViewRect = 0;
3710 if (nItemCount == -1)
3712 nItemCount = GETITEMCOUNT(infoPtr);
3715 if (uView == LVS_LIST)
3717 if (wHeight == 0xFFFF)
3719 /* use current height */
3720 wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
3723 if (wHeight < infoPtr->nItemHeight)
3725 wHeight = infoPtr->nItemHeight;
3730 if (infoPtr->nItemHeight > 0)
3732 nItemCountPerColumn = wHeight / infoPtr->nItemHeight;
3733 if (nItemCountPerColumn == 0)
3735 nItemCountPerColumn = 1;
3738 if (nItemCount % nItemCountPerColumn != 0)
3740 nColumnCount = nItemCount / nItemCountPerColumn;
3744 nColumnCount = nItemCount / nItemCountPerColumn + 1;
3749 /* Microsoft padding magic */
3750 wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2;
3751 wWidth = nColumnCount * infoPtr->nItemWidth + 2;
3753 dwViewRect = MAKELONG(wWidth, wHeight);
3755 else if (uView == LVS_REPORT)
3759 else if (uView == LVS_SMALLICON)
3763 else if (uView == LVS_ICON)
3773 * Arranges listview items in icon display mode.
3776 * [I] HWND : window handle
3777 * [I] INT : alignment code
3783 static LRESULT LISTVIEW_Arrange(HWND hwnd, INT nAlignCode)
3785 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3786 BOOL bResult = FALSE;
3788 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
3801 case LVA_SNAPTOGRID:
3810 /* << LISTVIEW_CreateDragImage >> */
3815 * Removes all listview items and subitems.
3818 * [I] HWND : window handle
3824 static LRESULT LISTVIEW_DeleteAllItems(HWND hwnd)
3826 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3827 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
3828 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3829 UINT uView = lStyle & LVS_TYPEMASK;
3830 LISTVIEW_ITEM *lpItem;
3831 LISTVIEW_SUBITEM *lpSubItem;
3834 BOOL bResult = FALSE;
3839 TRACE("(hwnd=%x,)\n", hwnd);
3840 LISTVIEW_RemoveAllSelections(hwnd);
3842 if (lStyle & LVS_OWNERDATA)
3844 infoPtr->hdpaItems->nItemCount = 0;
3845 InvalidateRect(hwnd, NULL, TRUE);
3849 if (GETITEMCOUNT(infoPtr) > 0)
3851 /* initialize memory */
3852 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
3854 /* send LVN_DELETEALLITEMS notification */
3855 nmlv.hdr.hwndFrom = hwnd;
3856 nmlv.hdr.idFrom = lCtrlId;
3857 nmlv.hdr.code = LVN_DELETEALLITEMS;
3860 /* verify if subsequent LVN_DELETEITEM notifications should be
3862 bSuppress = ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
3864 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
3866 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
3867 if (hdpaSubItems != NULL)
3869 for (j = 1; j < hdpaSubItems->nItemCount; j++)
3871 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, j);
3872 if (lpSubItem != NULL)
3874 /* free subitem string */
3875 if ((lpSubItem->pszText != NULL) &&
3876 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
3878 COMCTL32_Free(lpSubItem->pszText);
3882 COMCTL32_Free(lpSubItem);
3886 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3889 if (bSuppress == FALSE)
3891 /* send LVN_DELETEITEM notification */
3892 nmlv.hdr.code = LVN_DELETEITEM;
3894 nmlv.lParam = lpItem->lParam;
3895 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
3898 /* free item string */
3899 if ((lpItem->pszText != NULL) &&
3900 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
3902 COMCTL32_Free(lpItem->pszText);
3906 COMCTL32_Free(lpItem);
3909 DPA_Destroy(hdpaSubItems);
3913 /* reinitialize listview memory */
3914 bResult = DPA_DeleteAllPtrs(infoPtr->hdpaItems);
3916 /* align items (set position of each item) */
3917 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
3919 if (lStyle & LVS_ALIGNLEFT)
3921 LISTVIEW_AlignLeft(hwnd);
3925 LISTVIEW_AlignTop(hwnd);
3929 LISTVIEW_UpdateScroll(hwnd);
3931 /* invalidate client area (optimization needed) */
3932 InvalidateRect(hwnd, NULL, TRUE);
3940 * Removes a column from the listview control.
3943 * [I] HWND : window handle
3944 * [I] INT : column index
3950 static LRESULT LISTVIEW_DeleteColumn(HWND hwnd, INT nColumn)
3952 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3953 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3954 UINT uOwnerData = GetWindowLongA(hwnd, GWL_STYLE) & LVS_OWNERDATA;
3955 BOOL bResult = FALSE;
3957 if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) != FALSE)
3960 bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
3962 /* Need to reset the item width when deleting a column */
3963 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
3965 /* reset scroll parameters */
3966 if (uView == LVS_REPORT)
3968 /* update scrollbar(s) */
3969 LISTVIEW_UpdateScroll(hwnd);
3971 /* refresh client area */
3972 InvalidateRect(hwnd, NULL, FALSE);
3981 * Removes an item from the listview control.
3984 * [I] HWND : window handle
3985 * [I] INT : item index
3991 static LRESULT LISTVIEW_DeleteItem(HWND hwnd, INT nItem)
3993 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3994 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3995 UINT uView = lStyle & LVS_TYPEMASK;
3996 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
3998 BOOL bResult = FALSE;
4000 LISTVIEW_ITEM *lpItem;
4001 LISTVIEW_SUBITEM *lpSubItem;
4005 TRACE("(hwnd=%x,nItem=%d)\n", hwnd, nItem);
4007 /* remove it from the selection range */
4008 ZeroMemory(&item,sizeof(LVITEMA));
4009 item.stateMask = LVIS_SELECTED;
4010 LISTVIEW_SetItemState(hwnd,nItem,&item);
4012 LISTVIEW_ShiftSelections(hwnd,nItem,-1);
4014 if (lStyle & LVS_OWNERDATA)
4016 infoPtr->hdpaItems->nItemCount --;
4017 InvalidateRect(hwnd, NULL, TRUE);
4021 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4023 /* initialize memory */
4024 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
4026 hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem);
4027 if (hdpaSubItems != NULL)
4029 for (i = 1; i < hdpaSubItems->nItemCount; i++)
4031 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
4032 if (lpSubItem != NULL)
4034 /* free item string */
4035 if ((lpSubItem->pszText != NULL) &&
4036 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
4038 COMCTL32_Free(lpSubItem->pszText);
4042 COMCTL32_Free(lpSubItem);
4046 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
4049 /* send LVN_DELETEITEM notification */
4050 nmlv.hdr.hwndFrom = hwnd;
4051 nmlv.hdr.idFrom = lCtrlId;
4052 nmlv.hdr.code = LVN_DELETEITEM;
4054 nmlv.lParam = lpItem->lParam;
4055 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId,
4058 /* free item string */
4059 if ((lpItem->pszText != NULL) &&
4060 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
4062 COMCTL32_Free(lpItem->pszText);
4066 COMCTL32_Free(lpItem);
4069 bResult = DPA_Destroy(hdpaSubItems);
4072 /* align items (set position of each item) */
4073 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4075 if (lStyle & LVS_ALIGNLEFT)
4077 LISTVIEW_AlignLeft(hwnd);
4081 LISTVIEW_AlignTop(hwnd);
4085 /* If this item had focus change focus to next or previous item */
4086 if (GETITEMCOUNT(infoPtr) > 0)
4088 int sItem = nItem < GETITEMCOUNT(infoPtr) ? nItem : nItem - 1;
4089 if (infoPtr->nFocusedItem == nItem)
4090 LISTVIEW_SetItemFocus(hwnd, sItem);
4093 infoPtr->nFocusedItem = -1;
4095 LISTVIEW_UpdateScroll(hwnd);
4097 /* refresh client area */
4098 InvalidateRect(hwnd, NULL, TRUE);
4107 * Return edit control handle of current edit label
4110 * [I] HWND : window handle
4116 static LRESULT LISTVIEW_GetEditControl(HWND hwnd)
4118 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4119 return infoPtr->hwndEdit;
4125 * Callback implementation for editlabel control
4128 * [I] HWND : window handle
4129 * [I] LPSTR : modified text
4130 * [I] DWORD : item index
4137 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem)
4139 NMLVDISPINFOA dispInfo;
4140 LISTVIEW_ITEM *lpItem;
4141 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
4142 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4143 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4145 BOOL bUpdateItemText;
4146 LISTVIEW_ITEM lvItemRef;
4149 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
4151 if (!(lStyle & LVS_OWNERDATA))
4153 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
4156 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
4161 ZeroMemory(&lvItemRef,sizeof(LISTVIEW_ITEM));
4162 ZeroMemory(&item,sizeof(LVITEMA));
4165 item.mask = LVIF_PARAM | LVIF_STATE;
4166 ListView_GetItemA(hwnd,&item);
4167 lvItemRef.state = item.state;
4168 lvItemRef.iImage = item.iImage;
4169 lvItemRef.lParam = item.lParam;
4170 lpItem = &lvItemRef;
4173 dispInfo.hdr.hwndFrom = hwnd;
4174 dispInfo.hdr.idFrom = nCtrlId;
4175 dispInfo.hdr.code = LVN_ENDLABELEDITA;
4176 dispInfo.item.mask = 0;
4177 dispInfo.item.iItem = nItem;
4178 dispInfo.item.state = lpItem->state;
4179 dispInfo.item.stateMask = 0;
4180 dispInfo.item.pszText = pszText;
4181 dispInfo.item.cchTextMax = pszText ? strlen(pszText) : 0;
4182 dispInfo.item.iImage = lpItem->iImage;
4183 dispInfo.item.lParam = lpItem->lParam;
4184 infoPtr->hwndEdit = 0;
4186 bUpdateItemText = ListView_Notify(GetParent(hwnd), nCtrlId, &dispInfo);
4188 /* Do we need to update the Item Text */
4191 if ((lpItem->pszText != LPSTR_TEXTCALLBACKA)&&(!(lStyle & LVS_OWNERDATA)))
4193 Str_SetPtrA(&lpItem->pszText, pszText);
4202 * Begin in place editing of specified list view item
4205 * [I] HWND : window handle
4206 * [I] INT : item index
4213 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem)
4215 NMLVDISPINFOA dispInfo;
4217 LISTVIEW_ITEM *lpItem;
4219 HINSTANCE hinst = GetWindowLongA(hwnd, GWL_HINSTANCE);
4220 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
4221 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4223 CHAR szDispText[DISP_TEXT_SIZE];
4224 LVITEMA lvItem,item;
4225 LISTVIEW_ITEM lvItemRef;
4226 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4228 if (~GetWindowLongA(hwnd, GWL_STYLE) & LVS_EDITLABELS)
4231 /* Is the EditBox still there, if so remove it */
4232 if(infoPtr->hwndEdit != 0)
4237 LISTVIEW_SetSelection(hwnd, nItem);
4238 LISTVIEW_SetItemFocus(hwnd, nItem);
4240 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
4241 if (!(lStyle & LVS_OWNERDATA))
4243 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
4246 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
4251 ZeroMemory(&lvItemRef,sizeof(LISTVIEW_ITEM));
4252 ZeroMemory(&item,sizeof(LVITEMA));
4255 item.mask = LVIF_PARAM | LVIF_STATE;
4256 ListView_GetItemA(hwnd,&item);
4257 lvItemRef.iImage = item.iImage;
4258 lvItemRef.state = item.state;
4259 lvItemRef.lParam = item.lParam;
4260 lpItem = &lvItemRef;
4263 /* get information needed for drawing the item */
4264 ZeroMemory(&lvItem, sizeof(LVITEMA));
4265 lvItem.mask = LVIF_TEXT;
4266 lvItem.iItem = nItem;
4267 lvItem.iSubItem = 0;
4268 lvItem.cchTextMax = DISP_TEXT_SIZE;
4269 lvItem.pszText = szDispText;
4270 ListView_GetItemA(hwnd, &lvItem);
4272 dispInfo.hdr.hwndFrom = hwnd;
4273 dispInfo.hdr.idFrom = nCtrlId;
4274 dispInfo.hdr.code = LVN_BEGINLABELEDITA;
4275 dispInfo.item.mask = 0;
4276 dispInfo.item.iItem = nItem;
4277 dispInfo.item.state = lpItem->state;
4278 dispInfo.item.stateMask = 0;
4279 dispInfo.item.pszText = lvItem.pszText;
4280 dispInfo.item.cchTextMax = strlen(lvItem.pszText);
4281 dispInfo.item.iImage = lpItem->iImage;
4282 dispInfo.item.lParam = lpItem->lParam;
4284 if (ListView_LVNotify(GetParent(hwnd), nCtrlId, &dispInfo))
4287 rect.left = LVIR_LABEL;
4288 if (!LISTVIEW_GetItemRect(hwnd, nItem, &rect))
4291 if (!(hedit = CreateEditLabel(szDispText , WS_VISIBLE,
4292 rect.left-2, rect.top-1, 0,
4293 rect.bottom - rect.top+2,
4294 hwnd, hinst, LISTVIEW_EndEditLabel, nItem)))
4297 infoPtr->hwndEdit = hedit;
4299 SendMessageA(hedit, EM_SETSEL, 0, -1);
4307 * Ensures the specified item is visible, scrolling into view if necessary.
4310 * [I] HWND : window handle
4311 * [I] INT : item index
4312 * [I] BOOL : partially or entirely visible
4318 static BOOL LISTVIEW_EnsureVisible(HWND hwnd, INT nItem, BOOL bPartial)
4320 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4321 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4322 INT nScrollPosHeight = 0;
4323 INT nScrollPosWidth = 0;
4324 SCROLLINFO scrollInfo;
4326 BOOL bRedraw = FALSE;
4328 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
4329 scrollInfo.cbSize = sizeof(SCROLLINFO);
4330 scrollInfo.fMask = SIF_POS;
4332 /* ALWAYS bPartial == FALSE, FOR NOW! */
4334 rcItem.left = LVIR_BOUNDS;
4335 if (LISTVIEW_GetItemRect(hwnd, nItem, &rcItem) != FALSE)
4337 if (rcItem.left < infoPtr->rcList.left)
4339 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4343 if (uView == LVS_LIST)
4345 nScrollPosWidth = infoPtr->nItemWidth;
4346 rcItem.left += infoPtr->rcList.left;
4348 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4350 nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
4351 rcItem.left += infoPtr->rcList.left;
4354 /* When in LVS_REPORT view, the scroll position should
4356 if (nScrollPosWidth != 0)
4358 if (rcItem.left % nScrollPosWidth == 0)
4360 scrollInfo.nPos += rcItem.left / nScrollPosWidth;
4364 scrollInfo.nPos += rcItem.left / nScrollPosWidth - 1;
4367 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
4371 else if (rcItem.right > infoPtr->rcList.right)
4373 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4377 if (uView == LVS_LIST)
4379 rcItem.right -= infoPtr->rcList.right;
4380 nScrollPosWidth = infoPtr->nItemWidth;
4382 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4384 rcItem.right -= infoPtr->rcList.right;
4385 nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
4388 /* When in LVS_REPORT view, the scroll position should
4390 if (nScrollPosWidth != 0)
4392 if (rcItem.right % nScrollPosWidth == 0)
4394 scrollInfo.nPos += rcItem.right / nScrollPosWidth;
4398 scrollInfo.nPos += rcItem.right / nScrollPosWidth + 1;
4401 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
4406 if (rcItem.top < infoPtr->rcList.top)
4410 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4412 if (uView == LVS_REPORT)
4414 rcItem.top -= infoPtr->rcList.top;
4415 nScrollPosHeight = infoPtr->nItemHeight;
4417 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
4419 nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
4420 rcItem.top += infoPtr->rcList.top;
4423 if (rcItem.top % nScrollPosHeight == 0)
4425 scrollInfo.nPos += rcItem.top / nScrollPosHeight;
4429 scrollInfo.nPos += rcItem.top / nScrollPosHeight - 1;
4432 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
4435 else if (rcItem.bottom > infoPtr->rcList.bottom)
4439 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4441 if (uView == LVS_REPORT)
4443 rcItem.bottom -= infoPtr->rcList.bottom;
4444 nScrollPosHeight = infoPtr->nItemHeight;
4446 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
4448 nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
4449 rcItem.bottom -= infoPtr->rcList.bottom;
4452 if (rcItem.bottom % nScrollPosHeight == 0)
4454 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight;
4458 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight + 1;
4461 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
4467 InvalidateRect(hwnd,NULL,TRUE);
4473 * Retrieves the nearest item, given a position and a direction.
4476 * [I] HWND : window handle
4477 * [I] POINT : start position
4478 * [I] UINT : direction
4481 * Item index if successdful, -1 otherwise.
4483 static INT LISTVIEW_GetNearestItem(HWND hwnd, POINT pt, UINT vkDirection)
4485 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4486 LVHITTESTINFO lvHitTestInfo;
4490 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
4492 ZeroMemory(&lvHitTestInfo, sizeof(LVHITTESTINFO));
4493 LISTVIEW_GetOrigin(hwnd, &lvHitTestInfo.pt);
4494 lvHitTestInfo.pt.x += pt.x;
4495 lvHitTestInfo.pt.y += pt.y;
4499 if (vkDirection == VK_DOWN)
4501 lvHitTestInfo.pt.y += infoPtr->nItemHeight;
4503 else if (vkDirection == VK_UP)
4505 lvHitTestInfo.pt.y -= infoPtr->nItemHeight;
4507 else if (vkDirection == VK_LEFT)
4509 lvHitTestInfo.pt.x -= infoPtr->nItemWidth;
4511 else if (vkDirection == VK_RIGHT)
4513 lvHitTestInfo.pt.x += infoPtr->nItemWidth;
4516 if (PtInRect(&rcView, lvHitTestInfo.pt) == FALSE)
4522 nItem = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo, TRUE);
4526 while (nItem == -1);
4534 * Searches for an item with specific characteristics.
4537 * [I] HWND : window handle
4538 * [I] INT : base item index
4539 * [I] LPLVFINDINFO : item information to look for
4542 * SUCCESS : index of item
4545 static LRESULT LISTVIEW_FindItem(HWND hwnd, INT nStart,
4546 LPLVFINDINFO lpFindInfo)
4548 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4550 CHAR szDispText[DISP_TEXT_SIZE];
4554 INT nLast = GETITEMCOUNT(infoPtr);
4556 if ((nItem >= -1) && (lpFindInfo != NULL))
4558 ZeroMemory(&lvItem, sizeof(LVITEMA));
4560 if (lpFindInfo->flags & LVFI_PARAM)
4562 lvItem.mask |= LVIF_PARAM;
4565 if (lpFindInfo->flags & LVFI_STRING)
4567 lvItem.mask |= LVIF_TEXT;
4568 lvItem.pszText = szDispText;
4569 lvItem.cchTextMax = DISP_TEXT_SIZE;
4572 if (lpFindInfo->flags & LVFI_PARTIAL)
4574 lvItem.mask |= LVIF_TEXT;
4575 lvItem.pszText = szDispText;
4576 lvItem.cchTextMax = DISP_TEXT_SIZE;
4579 if (lpFindInfo->flags & LVFI_WRAP)
4584 if (lpFindInfo->flags & LVFI_NEARESTXY)
4586 ptItem.x = lpFindInfo->pt.x;
4587 ptItem.y = lpFindInfo->pt.y;
4592 while (nItem < nLast)
4594 if (lpFindInfo->flags & LVFI_NEARESTXY)
4596 nItem = LISTVIEW_GetNearestItem(hwnd, ptItem,
4597 lpFindInfo->vkDirection);
4600 /* get position of the new item index */
4601 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) == FALSE)
4612 lvItem.iItem = nItem;
4613 lvItem.iSubItem = 0;
4614 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
4616 if (lvItem.mask & LVIF_TEXT)
4618 if (lpFindInfo->flags & LVFI_PARTIAL)
4620 if (strstr(lvItem.pszText, lpFindInfo->psz) == NULL)
4625 if (strcmp(lvItem.pszText, lpFindInfo->psz) != 0)
4630 if (lvItem.mask & LVIF_PARAM)
4632 if (lpFindInfo->lParam != lvItem.lParam)
4658 * Retrieves the background color of the listview control.
4661 * [I] HWND : window handle
4664 * COLORREF associated with the background.
4666 static LRESULT LISTVIEW_GetBkColor(HWND hwnd)
4668 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4670 return infoPtr->clrBk;
4675 * Retrieves the background image of the listview control.
4678 * [I] HWND : window handle
4679 * [O] LPLVMKBIMAGE : background image attributes
4685 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
4687 /* FIXME (listview, "empty stub!\n"); */
4693 * Retrieves the callback mask.
4696 * [I] HWND : window handle
4701 static UINT LISTVIEW_GetCallbackMask(HWND hwnd)
4703 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4705 return infoPtr->uCallbackMask;
4710 * Retrieves column attributes.
4713 * [I] HWND : window handle
4714 * [I] INT : column index
4715 * [IO] LPLVCOLUMNA : column information
4721 static LRESULT LISTVIEW_GetColumnA(HWND hwnd, INT nItem, LPLVCOLUMNA lpColumn)
4723 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4725 BOOL bResult = FALSE;
4727 if (lpColumn != NULL)
4729 /* initialize memory */
4730 ZeroMemory(&hdi, sizeof(HDITEMA));
4732 if (lpColumn->mask & LVCF_FMT)
4734 hdi.mask |= HDI_FORMAT;
4737 if (lpColumn->mask & LVCF_WIDTH)
4739 hdi.mask |= HDI_WIDTH;
4742 if (lpColumn->mask & LVCF_TEXT)
4744 hdi.mask |= HDI_TEXT;
4745 hdi.cchTextMax = lpColumn->cchTextMax;
4746 hdi.pszText = lpColumn->pszText;
4749 if (lpColumn->mask & LVCF_IMAGE)
4751 hdi.mask |= HDI_IMAGE;
4754 if (lpColumn->mask & LVCF_ORDER)
4756 hdi.mask |= HDI_ORDER;
4759 bResult = Header_GetItemA(infoPtr->hwndHeader, nItem, &hdi);
4760 if (bResult != FALSE)
4762 if (lpColumn->mask & LVCF_FMT)
4766 if (hdi.fmt & HDF_LEFT)
4768 lpColumn->fmt |= LVCFMT_LEFT;
4770 else if (hdi.fmt & HDF_RIGHT)
4772 lpColumn->fmt |= LVCFMT_RIGHT;
4774 else if (hdi.fmt & HDF_CENTER)
4776 lpColumn->fmt |= LVCFMT_CENTER;
4779 if (hdi.fmt & HDF_IMAGE)
4781 lpColumn->fmt |= LVCFMT_COL_HAS_IMAGES;
4784 if (hdi.fmt & HDF_BITMAP_ON_RIGHT)
4786 lpColumn->fmt |= LVCFMT_BITMAP_ON_RIGHT;
4790 if (lpColumn->mask & LVCF_WIDTH)
4792 lpColumn->cx = hdi.cxy;
4795 if (lpColumn->mask & LVCF_IMAGE)
4797 lpColumn->iImage = hdi.iImage;
4800 if (lpColumn->mask & LVCF_ORDER)
4802 lpColumn->iOrder = hdi.iOrder;
4810 /* LISTVIEW_GetColumnW */
4813 static LRESULT LISTVIEW_GetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
4815 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
4822 for (i = 0; i < iCount; i++)
4830 * Retrieves the column width.
4833 * [I] HWND : window handle
4834 * [I] int : column index
4837 * SUCCESS : column width
4840 static LRESULT LISTVIEW_GetColumnWidth(HWND hwnd, INT nColumn)
4842 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4843 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4844 INT nColumnWidth = 0;
4847 if (uView == LVS_LIST)
4849 nColumnWidth = infoPtr->nItemWidth;
4851 else if (uView == LVS_REPORT)
4853 /* get column width from header */
4854 ZeroMemory(&hdi, sizeof(HDITEMA));
4855 hdi.mask = HDI_WIDTH;
4856 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdi) != FALSE)
4858 nColumnWidth = hdi.cxy;
4862 return nColumnWidth;
4867 * In list or report display mode, retrieves the number of items that can fit
4868 * vertically in the visible area. In icon or small icon display mode,
4869 * retrieves the total number of visible items.
4872 * [I] HWND : window handle
4875 * Number of fully visible items.
4877 static LRESULT LISTVIEW_GetCountPerPage(HWND hwnd)
4879 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4880 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4883 if (uView == LVS_LIST)
4885 if (infoPtr->rcList.right > infoPtr->nItemWidth)
4887 nItemCount = LISTVIEW_GetCountPerRow(hwnd) *
4888 LISTVIEW_GetCountPerColumn(hwnd);
4891 else if (uView == LVS_REPORT)
4893 nItemCount = LISTVIEW_GetCountPerColumn(hwnd);
4897 nItemCount = GETITEMCOUNT(infoPtr);
4903 /* LISTVIEW_GetEditControl */
4907 * Retrieves the extended listview style.
4910 * [I] HWND : window handle
4913 * SUCCESS : previous style
4916 static LRESULT LISTVIEW_GetExtendedListViewStyle(HWND hwnd)
4918 LISTVIEW_INFO *infoPtr;
4920 /* make sure we can get the listview info */
4921 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
4924 return (infoPtr->dwExStyle);
4929 * Retrieves the handle to the header control.
4932 * [I] HWND : window handle
4937 static LRESULT LISTVIEW_GetHeader(HWND hwnd)
4939 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4941 return infoPtr->hwndHeader;
4944 /* LISTVIEW_GetHotCursor */
4948 * Returns the time that the mouse cursor must hover over an item
4949 * before it is selected.
4952 * [I] HWND : window handle
4955 * Returns the previously set hover time or (DWORD)-1 to indicate that the
4956 * hover time is set to the default hover time.
4958 static LRESULT LISTVIEW_GetHoverTime(HWND hwnd)
4960 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4962 return infoPtr->dwHoverTime;
4967 * Retrieves an image list handle.
4970 * [I] HWND : window handle
4971 * [I] INT : image list identifier
4974 * SUCCESS : image list handle
4977 static LRESULT LISTVIEW_GetImageList(HWND hwnd, INT nImageList)
4979 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4980 HIMAGELIST himl = NULL;
4985 himl = infoPtr->himlNormal;
4988 himl = infoPtr->himlSmall;
4991 himl = infoPtr->himlState;
4995 return (LRESULT)himl;
4998 /* LISTVIEW_GetISearchString */
5002 * Retrieves item attributes.
5005 * [I] HWND : window handle
5006 * [IO] LPLVITEMA : item info
5007 * [I] internal : if true then we will use tricks that avoid copies
5008 * but are not compatible with the regular interface
5014 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem, BOOL internal)
5016 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5017 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
5018 NMLVDISPINFOA dispInfo;
5019 LISTVIEW_SUBITEM *lpSubItem;
5020 LISTVIEW_ITEM *lpItem;
5024 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5025 /* In the following:
5026 * lpLVItem describes the information requested by the user
5027 * lpItem/lpSubItem is what we have
5028 * dispInfo is a structure we use to request the missing
5029 * information from the application
5032 TRACE("(hwnd=%x, lpLVItem=%p)\n", hwnd, lpLVItem);
5034 if ((lpLVItem == NULL) ||
5035 (lpLVItem->iItem < 0) ||
5036 (lpLVItem->iItem >= GETITEMCOUNT(infoPtr))
5040 if (lStyle & LVS_OWNERDATA)
5042 if (lpLVItem->mask & ~LVIF_STATE)
5044 dispInfo.hdr.hwndFrom = hwnd;
5045 dispInfo.hdr.idFrom = lCtrlId;
5046 dispInfo.hdr.code = LVN_GETDISPINFOA;
5047 memcpy(&dispInfo.item,lpLVItem,sizeof(LVITEMA));
5049 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
5050 memcpy(lpLVItem,&dispInfo.item,sizeof(LVITEMA));
5053 if ((lpLVItem->mask & LVIF_STATE)&&(lpLVItem->iSubItem == 0))
5055 lpLVItem->state = 0;
5056 if (infoPtr->nFocusedItem == lpLVItem->iItem)
5057 lpLVItem->state |= LVIS_FOCUSED;
5058 if (LISTVIEW_IsSelected(hwnd,lpLVItem->iItem))
5059 lpLVItem->state |= LVIS_SELECTED;
5066 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
5067 if (hdpaSubItems == NULL)
5070 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
5074 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
5075 if (lpLVItem->iSubItem == 0)
5077 piImage=&lpItem->iImage;
5078 ppszText=&lpItem->pszText;
5079 if ((infoPtr->uCallbackMask != 0) && (lpLVItem->mask & LVIF_STATE))
5081 dispInfo.item.mask |= LVIF_STATE;
5082 dispInfo.item.stateMask = infoPtr->uCallbackMask;
5087 lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem);
5088 if (lpSubItem != NULL)
5090 piImage=&lpSubItem->iImage;
5091 ppszText=&lpSubItem->pszText;
5100 if ((lpLVItem->mask & LVIF_IMAGE) &&
5101 ((piImage==NULL) || (*piImage == I_IMAGECALLBACK)))
5103 dispInfo.item.mask |= LVIF_IMAGE;
5106 if ((lpLVItem->mask & LVIF_TEXT) &&
5107 ((ppszText==NULL) || (*ppszText == LPSTR_TEXTCALLBACKA)))
5109 dispInfo.item.mask |= LVIF_TEXT;
5110 dispInfo.item.pszText = lpLVItem->pszText;
5111 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
5114 if (dispInfo.item.mask != 0)
5116 /* We don't have all the requested info, query the application */
5117 dispInfo.hdr.hwndFrom = hwnd;
5118 dispInfo.hdr.idFrom = lCtrlId;
5119 dispInfo.hdr.code = LVN_GETDISPINFOA;
5120 dispInfo.item.iItem = lpLVItem->iItem;
5121 dispInfo.item.iSubItem = lpLVItem->iSubItem;
5122 dispInfo.item.lParam = lpItem->lParam;
5123 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
5126 if (dispInfo.item.mask & LVIF_IMAGE)
5128 lpLVItem->iImage = dispInfo.item.iImage;
5130 else if (lpLVItem->mask & LVIF_IMAGE)
5132 lpLVItem->iImage = *piImage;
5135 if (dispInfo.item.mask & LVIF_PARAM)
5137 lpLVItem->lParam = dispInfo.item.lParam;
5139 else if (lpLVItem->mask & LVIF_PARAM)
5141 lpLVItem->lParam = lpItem->lParam;
5144 if (dispInfo.item.mask & LVIF_TEXT)
5146 if ((dispInfo.item.mask & LVIF_DI_SETITEM) && (ppszText != NULL))
5148 Str_SetPtrA(ppszText, dispInfo.item.pszText);
5150 /* If lpLVItem->pszText==dispInfo.item.pszText a copy is unnecessary, but */
5151 /* some apps give a new pointer in ListView_Notify so we can't be sure. */
5152 if (lpLVItem->pszText!=dispInfo.item.pszText) {
5153 lstrcpynA(lpLVItem->pszText, dispInfo.item.pszText, lpLVItem->cchTextMax);
5156 else if (lpLVItem->mask & LVIF_TEXT)
5160 lpLVItem->pszText=*ppszText;
5162 lstrcpynA(lpLVItem->pszText, *ppszText, lpLVItem->cchTextMax);
5166 if (lpLVItem->iSubItem == 0)
5168 if (dispInfo.item.mask & LVIF_STATE)
5170 lpLVItem->state = lpItem->state;
5171 lpLVItem->state &= ~dispInfo.item.stateMask;
5172 lpLVItem->state |= (dispInfo.item.state & dispInfo.item.stateMask);
5174 lpLVItem->state &= ~LVIS_SELECTED;
5175 if ((dispInfo.item.stateMask & LVIS_SELECTED) &&
5176 (LISTVIEW_IsSelected(hwnd,dispInfo.item.iItem)))
5177 lpLVItem->state |= LVIS_SELECTED;
5179 else if (lpLVItem->mask & LVIF_STATE)
5181 lpLVItem->state = lpItem->state & lpLVItem->stateMask;
5183 lpLVItem->state &= ~LVIS_SELECTED;
5184 if ((lpLVItem->stateMask & LVIS_SELECTED) &&
5185 (LISTVIEW_IsSelected(hwnd,lpLVItem->iItem)))
5186 lpLVItem->state |= LVIS_SELECTED;
5189 if (lpLVItem->mask & LVIF_PARAM)
5191 lpLVItem->lParam = lpItem->lParam;
5194 if (lpLVItem->mask & LVIF_INDENT)
5196 lpLVItem->iIndent = lpItem->iIndent;
5203 /* LISTVIEW_GetItemW */
5204 /* LISTVIEW_GetHotCursor */
5208 * Retrieves the index of the hot item.
5211 * [I] HWND : window handle
5214 * SUCCESS : hot item index
5215 * FAILURE : -1 (no hot item)
5217 static LRESULT LISTVIEW_GetHotItem(HWND hwnd)
5219 LISTVIEW_INFO *infoPtr;
5221 /* make sure we can get the listview info */
5222 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5225 return (infoPtr->nHotItem);
5228 /* LISTVIEW_GetHoverTime */
5232 * Retrieves the number of items in the listview control.
5235 * [I] HWND : window handle
5240 static LRESULT LISTVIEW_GetItemCount(HWND hwnd)
5242 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5244 return GETITEMCOUNT(infoPtr);
5249 * Retrieves the position (upper-left) of the listview control item.
5252 * [I] HWND : window handle
5253 * [I] INT : item index
5254 * [O] LPPOINT : coordinate information
5260 static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem,
5261 LPPOINT lpptPosition)
5263 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5264 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5265 BOOL bResult = FALSE;
5267 LISTVIEW_ITEM *lpItem;
5268 INT nCountPerColumn;
5271 TRACE("(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd, nItem,
5274 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
5275 (lpptPosition != NULL))
5277 if (uView == LVS_LIST)
5280 nItem = nItem - ListView_GetTopIndex(hwnd);
5281 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
5284 nRow = nItem % nCountPerColumn;
5287 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
5288 lpptPosition->y = 0;
5292 lpptPosition->x = (nItem / nCountPerColumn -1) * infoPtr->nItemWidth;
5293 lpptPosition->y = (nRow + nCountPerColumn) * infoPtr->nItemHeight;
5298 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
5299 lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight;
5302 else if (uView == LVS_REPORT)
5305 lpptPosition->x = REPORT_MARGINX;
5306 lpptPosition->y = ((nItem - ListView_GetTopIndex(hwnd)) *
5307 infoPtr->nItemHeight) + infoPtr->rcList.top;
5311 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
5312 if (hdpaSubItems != NULL)
5314 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
5318 lpptPosition->x = lpItem->ptPosition.x;
5319 lpptPosition->y = lpItem->ptPosition.y;
5329 * Retrieves the bounding rectangle for a listview control item.
5332 * [I] HWND : window handle
5333 * [I] INT : item index
5334 * [IO] LPRECT : bounding rectangle coordinates
5340 static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc)
5342 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5343 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5344 BOOL bResult = FALSE;
5355 TRACE("(hwnd=%x, nItem=%d, lprc=%p)\n", hwnd, nItem, lprc);
5357 if (uView & LVS_REPORT)
5359 ZeroMemory(&lvItem, sizeof(LVITEMA));
5360 lvItem.mask = LVIF_INDENT;
5361 lvItem.iItem = nItem;
5362 lvItem.iSubItem = 0;
5363 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
5366 if (lvItem.iIndent>0 && infoPtr->iconSize.cx > 0)
5368 nIndent = infoPtr->iconSize.cx * lvItem.iIndent;
5376 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL))
5378 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) != FALSE)
5383 if (uView == LVS_ICON)
5385 if (infoPtr->himlNormal != NULL)
5387 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5390 lprc->left = ptItem.x + ptOrigin.x;
5391 lprc->top = ptItem.y + ptOrigin.y;
5392 lprc->right = lprc->left + infoPtr->iconSize.cx;
5393 lprc->bottom = (lprc->top + infoPtr->iconSize.cy +
5394 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
5398 else if (uView == LVS_SMALLICON)
5400 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5403 lprc->left = ptItem.x + ptOrigin.x;
5404 lprc->top = ptItem.y + ptOrigin.y;
5405 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5407 if (infoPtr->himlState != NULL)
5408 lprc->left += infoPtr->iconSize.cx;
5410 if (infoPtr->himlSmall != NULL)
5411 lprc->right = lprc->left + infoPtr->iconSize.cx;
5413 lprc->right = lprc->left;
5419 lprc->left = ptItem.x;
5420 if (uView & LVS_REPORT)
5421 lprc->left += nIndent;
5422 lprc->top = ptItem.y;
5423 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5425 if (infoPtr->himlState != NULL)
5427 lprc->left += infoPtr->iconSize.cx;
5430 if (infoPtr->himlSmall != NULL)
5432 lprc->right = lprc->left + infoPtr->iconSize.cx;
5436 lprc->right = lprc->left;
5442 if (uView == LVS_ICON)
5444 if (infoPtr->himlNormal != NULL)
5446 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5449 lprc->left = ptItem.x + ptOrigin.x;
5450 lprc->top = (ptItem.y + ptOrigin.y + infoPtr->iconSize.cy +
5451 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
5452 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5453 if (infoPtr->iconSpacing.cx - nLabelWidth > 1)
5455 lprc->left += (infoPtr->iconSpacing.cx - nLabelWidth) / 2;
5456 lprc->right = lprc->left + nLabelWidth;
5461 lprc->right = lprc->left + infoPtr->iconSpacing.cx - 1;
5465 hOldFont = SelectObject(hdc, infoPtr->hFont);
5466 GetTextMetricsA(hdc, &tm);
5467 lprc->bottom = lprc->top + tm.tmHeight + HEIGHT_PADDING;
5468 SelectObject(hdc, hOldFont);
5469 ReleaseDC(hwnd, hdc);
5473 else if (uView == LVS_SMALLICON)
5475 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5478 nLeftPos = lprc->left = ptItem.x + ptOrigin.x;
5479 lprc->top = ptItem.y + ptOrigin.y;
5480 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5482 if (infoPtr->himlState != NULL)
5484 lprc->left += infoPtr->iconSize.cx;
5487 if (infoPtr->himlSmall != NULL)
5489 lprc->left += infoPtr->iconSize.cx;
5492 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5493 nLabelWidth += TRAILING_PADDING;
5494 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5496 lprc->right = lprc->left + nLabelWidth;
5500 lprc->right = nLeftPos + infoPtr->nItemWidth;
5507 if (uView & LVS_REPORT)
5508 nLeftPos = lprc->left = ptItem.x + nIndent;
5510 nLeftPos = lprc->left = ptItem.x;
5511 lprc->top = ptItem.y;
5512 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5514 if (infoPtr->himlState != NULL)
5516 lprc->left += infoPtr->iconSize.cx;
5519 if (infoPtr->himlSmall != NULL)
5521 lprc->left += infoPtr->iconSize.cx;
5524 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5525 nLabelWidth += TRAILING_PADDING;
5526 if (infoPtr->himlSmall)
5527 nLabelWidth += IMAGE_PADDING;
5528 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5530 lprc->right = lprc->left + nLabelWidth;
5534 lprc->right = nLeftPos + infoPtr->nItemWidth;
5540 if (uView == LVS_ICON)
5542 if (infoPtr->himlNormal != NULL)
5544 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5547 lprc->left = ptItem.x + ptOrigin.x;
5548 lprc->top = ptItem.y + ptOrigin.y;
5549 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
5550 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
5554 else if (uView == LVS_SMALLICON)
5556 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5559 lprc->left = ptItem.x + ptOrigin.x;
5560 lprc->right = lprc->left;
5561 lprc->top = ptItem.y + ptOrigin.y;
5562 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5563 if (infoPtr->himlState != NULL)
5564 lprc->right += infoPtr->iconSize.cx;
5565 if (infoPtr->himlSmall != NULL)
5566 lprc->right += infoPtr->iconSize.cx;
5568 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5569 nLabelWidth += TRAILING_PADDING;
5570 if (infoPtr->himlSmall)
5571 nLabelWidth += IMAGE_PADDING;
5572 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
5574 lprc->right += nLabelWidth;
5578 lprc->right = lprc->left + infoPtr->nItemWidth;
5585 lprc->left = ptItem.x;
5586 if (!(infoPtr->dwExStyle&LVS_EX_FULLROWSELECT) && uView&LVS_REPORT)
5587 lprc->left += nIndent;
5588 lprc->right = lprc->left;
5589 lprc->top = ptItem.y;
5590 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5592 if (infoPtr->dwExStyle & LVS_EX_FULLROWSELECT)
5595 int nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
5596 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
5598 lprc->right = max(lprc->left, br.right - REPORT_MARGINX);
5602 if (infoPtr->himlState != NULL)
5604 lprc->right += infoPtr->iconSize.cx;
5607 if (infoPtr->himlSmall != NULL)
5609 lprc->right += infoPtr->iconSize.cx;
5612 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5613 nLabelWidth += TRAILING_PADDING;
5614 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
5616 lprc->right += nLabelWidth;
5620 lprc->right = lprc->left + infoPtr->nItemWidth;
5626 case LVIR_SELECTBOUNDS:
5627 if (uView == LVS_ICON)
5629 if (infoPtr->himlNormal != NULL)
5631 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5634 lprc->left = ptItem.x + ptOrigin.x;
5635 lprc->top = ptItem.y + ptOrigin.y;
5636 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
5637 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
5641 else if (uView == LVS_SMALLICON)
5643 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5646 nLeftPos= lprc->left = ptItem.x + ptOrigin.x;
5647 lprc->top = ptItem.y + ptOrigin.y;
5648 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5650 if (infoPtr->himlState != NULL)
5652 lprc->left += infoPtr->iconSize.cx;
5655 lprc->right = lprc->left;
5657 if (infoPtr->himlSmall != NULL)
5659 lprc->right += infoPtr->iconSize.cx;
5662 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5663 nLabelWidth += TRAILING_PADDING;
5664 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5666 lprc->right += nLabelWidth;
5670 lprc->right = nLeftPos + infoPtr->nItemWidth;
5677 if (!(infoPtr->dwExStyle&LVS_EX_FULLROWSELECT) && (uView&LVS_REPORT))
5678 nLeftPos = lprc->left = ptItem.x + nIndent;
5680 nLeftPos = lprc->left = ptItem.x;
5681 lprc->top = ptItem.y;
5682 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5684 if (infoPtr->himlState != NULL)
5686 lprc->left += infoPtr->iconSize.cx;
5689 lprc->right = lprc->left;
5691 if (infoPtr->dwExStyle & LVS_EX_FULLROWSELECT)
5694 int nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
5695 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
5697 lprc->right = max(lprc->left, br.right - REPORT_MARGINX);
5701 if (infoPtr->himlSmall != NULL)
5703 lprc->right += infoPtr->iconSize.cx;
5706 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5707 nLabelWidth += TRAILING_PADDING;
5708 if (infoPtr->himlSmall)
5709 nLabelWidth += IMAGE_PADDING;
5710 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5712 lprc->right += nLabelWidth;
5716 lprc->right = nLeftPos + infoPtr->nItemWidth;
5729 * Retrieves the width of a label.
5732 * [I] HWND : window handle
5735 * SUCCESS : string width (in pixels)
5738 static INT LISTVIEW_GetLabelWidth(HWND hwnd, INT nItem)
5740 CHAR szDispText[DISP_TEXT_SIZE];
5741 INT nLabelWidth = 0;
5744 TRACE("(hwnd=%x, nItem=%d)\n", hwnd, nItem);
5746 ZeroMemory(&lvItem, sizeof(LVITEMA));
5747 lvItem.mask = LVIF_TEXT;
5748 lvItem.iItem = nItem;
5749 lvItem.cchTextMax = DISP_TEXT_SIZE;
5750 lvItem.pszText = szDispText;
5751 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
5753 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
5761 * Retrieves the spacing between listview control items.
5764 * [I] HWND : window handle
5765 * [I] BOOL : flag for small or large icon
5768 * Horizontal + vertical spacing
5770 static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall)
5772 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5775 if (bSmall == FALSE)
5777 lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
5781 /* TODO: need to store width of smallicon item */
5782 lResult = MAKELONG(0, infoPtr->nItemHeight);
5790 * Retrieves the state of a listview control item.
5793 * [I] HWND : window handle
5794 * [I] INT : item index
5795 * [I] UINT : state mask
5798 * State specified by the mask.
5800 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask)
5802 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5806 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5808 ZeroMemory(&lvItem, sizeof(LVITEMA));
5809 lvItem.iItem = nItem;
5810 lvItem.stateMask = uMask;
5811 lvItem.mask = LVIF_STATE;
5812 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
5814 uState = lvItem.state;
5823 * Retrieves the text of a listview control item or subitem.
5826 * [I] HWND : window handle
5827 * [I] INT : item index
5828 * [IO] LPLVITEMA : item information
5831 * SUCCESS : string length
5834 static LRESULT LISTVIEW_GetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5836 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5839 if (lpLVItem != NULL)
5841 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5843 lpLVItem->mask = LVIF_TEXT;
5844 lpLVItem->iItem = nItem;
5845 if (LISTVIEW_GetItemA(hwnd, lpLVItem, FALSE) != FALSE)
5847 nLength = lstrlenA(lpLVItem->pszText);
5857 * Searches for an item based on properties + relationships.
5860 * [I] HWND : window handle
5861 * [I] INT : item index
5862 * [I] INT : relationship flag
5865 * SUCCESS : item index
5868 static LRESULT LISTVIEW_GetNextItem(HWND hwnd, INT nItem, UINT uFlags)
5870 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5871 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5873 LVFINDINFO lvFindInfo;
5874 INT nCountPerColumn;
5877 if ((nItem >= -1) && (nItem < GETITEMCOUNT(infoPtr)))
5879 ZeroMemory(&lvFindInfo, sizeof(LVFINDINFO));
5881 if (uFlags & LVNI_CUT)
5884 if (uFlags & LVNI_DROPHILITED)
5885 uMask |= LVIS_DROPHILITED;
5887 if (uFlags & LVNI_FOCUSED)
5888 uMask |= LVIS_FOCUSED;
5890 if (uFlags & LVNI_SELECTED)
5891 uMask |= LVIS_SELECTED;
5893 if (uFlags & LVNI_ABOVE)
5895 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
5900 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5906 lvFindInfo.flags = LVFI_NEARESTXY;
5907 lvFindInfo.vkDirection = VK_UP;
5908 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5909 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5911 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5916 else if (uFlags & LVNI_BELOW)
5918 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
5920 while (nItem < GETITEMCOUNT(infoPtr))
5923 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5929 lvFindInfo.flags = LVFI_NEARESTXY;
5930 lvFindInfo.vkDirection = VK_DOWN;
5931 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5932 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5934 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5939 else if (uFlags & LVNI_TOLEFT)
5941 if (uView == LVS_LIST)
5943 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
5944 while (nItem - nCountPerColumn >= 0)
5946 nItem -= nCountPerColumn;
5947 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5951 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
5953 lvFindInfo.flags = LVFI_NEARESTXY;
5954 lvFindInfo.vkDirection = VK_LEFT;
5955 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5956 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5958 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5963 else if (uFlags & LVNI_TORIGHT)
5965 if (uView == LVS_LIST)
5967 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
5968 while (nItem + nCountPerColumn < GETITEMCOUNT(infoPtr))
5970 nItem += nCountPerColumn;
5971 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5975 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
5977 lvFindInfo.flags = LVFI_NEARESTXY;
5978 lvFindInfo.vkDirection = VK_RIGHT;
5979 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5980 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5982 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5991 /* search by index */
5992 for (i = nItem; i < GETITEMCOUNT(infoPtr); i++)
5994 if ((ListView_GetItemState(hwnd, i, uMask) & uMask) == uMask)
6003 /* LISTVIEW_GetNumberOfWorkAreas */
6007 * Retrieves the origin coordinates when in icon or small icon display mode.
6010 * [I] HWND : window handle
6011 * [O] LPPOINT : coordinate information
6017 static LRESULT LISTVIEW_GetOrigin(HWND hwnd, LPPOINT lpptOrigin)
6019 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6020 UINT uView = lStyle & LVS_TYPEMASK;
6021 BOOL bResult = FALSE;
6023 TRACE("(hwnd=%x, lpptOrigin=%p)\n", hwnd, lpptOrigin);
6025 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
6027 SCROLLINFO scrollInfo;
6028 ZeroMemory(lpptOrigin, sizeof(POINT));
6029 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
6030 scrollInfo.cbSize = sizeof(SCROLLINFO);
6032 if (lStyle & WS_HSCROLL)
6034 scrollInfo.fMask = SIF_POS;
6035 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
6037 lpptOrigin->x = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
6041 if (lStyle & WS_VSCROLL)
6043 scrollInfo.fMask = SIF_POS;
6044 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
6046 lpptOrigin->y = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
6058 * Retrieves the number of items that are marked as selected.
6061 * [I] HWND : window handle
6064 * Number of items selected.
6066 static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd)
6069 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6070 INT nSelectedCount = 0;
6073 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
6075 if (ListView_GetItemState(hwnd, i, LVIS_SELECTED) & LVIS_SELECTED)
6081 return nSelectedCount;
6086 * Retrieves item index that marks the start of a multiple selection.
6089 * [I] HWND : window handle
6092 * Index number or -1 if there is no selection mark.
6094 static LRESULT LISTVIEW_GetSelectionMark(HWND hwnd)
6096 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6098 return infoPtr->nSelectionMark;
6103 * Retrieves the width of a string.
6106 * [I] HWND : window handle
6109 * SUCCESS : string width (in pixels)
6112 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText)
6114 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6115 HFONT hFont, hOldFont;
6119 ZeroMemory(&stringSize, sizeof(SIZE));
6120 if (lpszText != NULL && lpszText != (LPCSTR)-1)
6122 hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
6124 hOldFont = SelectObject(hdc, hFont);
6125 GetTextExtentPointA(hdc, lpszText, lstrlenA(lpszText), &stringSize);
6126 SelectObject(hdc, hOldFont);
6127 ReleaseDC(hwnd, hdc);
6130 return stringSize.cx;
6135 * Retrieves the text backgound color.
6138 * [I] HWND : window handle
6141 * COLORREF associated with the the background.
6143 static LRESULT LISTVIEW_GetTextBkColor(HWND hwnd)
6145 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
6147 return infoPtr->clrTextBk;
6152 * Retrieves the text color.
6155 * [I] HWND : window handle
6158 * COLORREF associated with the text.
6160 static LRESULT LISTVIEW_GetTextColor(HWND hwnd)
6162 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
6164 return infoPtr->clrText;
6169 * Determines which section of the item was selected (if any).
6172 * [I] HWND : window handle
6173 * [IO] LPLVHITTESTINFO : hit test information
6174 * [I] subitem : fill out iSubItem.
6177 * SUCCESS : item index
6180 static INT LISTVIEW_HitTestItem(
6181 HWND hwnd, LPLVHITTESTINFO lpHitTestInfo, BOOL subitem
6183 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6185 INT i,topindex,bottomindex;
6186 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6187 UINT uView = lStyle & LVS_TYPEMASK;
6190 TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpHitTestInfo->pt.x,
6191 lpHitTestInfo->pt.y);
6193 topindex = ListView_GetTopIndex(hwnd);
6194 if (uView == LVS_REPORT)
6196 bottomindex = topindex + LISTVIEW_GetCountPerColumn(hwnd) + 1;
6197 bottomindex = min(bottomindex,GETITEMCOUNT(infoPtr));
6201 bottomindex = GETITEMCOUNT(infoPtr);
6204 for (i = topindex; i < bottomindex; i++)
6206 rcItem.left = LVIR_BOUNDS;
6207 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
6209 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
6211 rcItem.left = LVIR_ICON;
6212 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
6214 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
6216 lpHitTestInfo->flags = LVHT_ONITEMICON;
6217 lpHitTestInfo->iItem = i;
6218 if (subitem) lpHitTestInfo->iSubItem = 0;
6223 rcItem.left = LVIR_LABEL;
6224 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
6226 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
6228 lpHitTestInfo->flags = LVHT_ONITEMLABEL;
6229 lpHitTestInfo->iItem = i;
6230 if (subitem) lpHitTestInfo->iSubItem = 0;
6235 lpHitTestInfo->flags = LVHT_ONITEMSTATEICON;
6236 lpHitTestInfo->iItem = i;
6237 if (subitem) lpHitTestInfo->iSubItem = 0;
6243 lpHitTestInfo->flags = LVHT_NOWHERE;
6250 * Determines which listview item is located at the specified position.
6253 * [I] HWND : window handle
6254 * [IO} LPLVHITTESTINFO : hit test information
6257 * SUCCESS : item index
6260 static LRESULT LISTVIEW_HitTest(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
6262 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6265 lpHitTestInfo->flags = 0;
6267 if (infoPtr->rcList.left > lpHitTestInfo->pt.x)
6269 lpHitTestInfo->flags = LVHT_TOLEFT;
6271 else if (infoPtr->rcList.right < lpHitTestInfo->pt.x)
6273 lpHitTestInfo->flags = LVHT_TORIGHT;
6275 if (infoPtr->rcList.top > lpHitTestInfo->pt.y)
6277 lpHitTestInfo->flags |= LVHT_ABOVE;
6279 else if (infoPtr->rcList.bottom < lpHitTestInfo->pt.y)
6281 lpHitTestInfo->flags |= LVHT_BELOW;
6284 if (lpHitTestInfo->flags == 0)
6286 /* NOTE (mm 20001022): We must not allow iSubItem to be touched, for
6287 * an app might pass only a structure with space up to iItem!
6288 * (MS Office 97 does that for instance in the file open dialog)
6290 nItem = LISTVIEW_HitTestItem(hwnd, lpHitTestInfo, FALSE);
6298 * Inserts a new column.
6301 * [I] HWND : window handle
6302 * [I] INT : column index
6303 * [I] LPLVCOLUMNA : column information
6306 * SUCCESS : new column index
6309 static LRESULT LISTVIEW_InsertColumnA(HWND hwnd, INT nColumn,
6310 LPLVCOLUMNA lpColumn)
6312 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6314 INT nNewColumn = -1;
6316 TRACE("(hwnd=%x, nColumn=%d, lpColumn=%p)\n",hwnd, nColumn,
6319 if (lpColumn != NULL)
6321 /* initialize memory */
6322 ZeroMemory(&hdi, sizeof(HDITEMA));
6324 if (lpColumn->mask & LVCF_FMT)
6326 /* format member is valid */
6327 hdi.mask |= HDI_FORMAT;
6329 /* set text alignment (leftmost column must be left-aligned) */
6332 hdi.fmt |= HDF_LEFT;
6336 if (lpColumn->fmt & LVCFMT_LEFT)
6338 hdi.fmt |= HDF_LEFT;
6340 else if (lpColumn->fmt & LVCFMT_RIGHT)
6342 hdi.fmt |= HDF_RIGHT;
6344 else if (lpColumn->fmt & LVCFMT_CENTER)
6346 hdi.fmt |= HDF_CENTER;
6350 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
6352 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
6356 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
6361 if (lpColumn->fmt & LVCFMT_IMAGE)
6363 hdi.fmt |= HDF_IMAGE;
6364 hdi.iImage = I_IMAGECALLBACK;
6368 if (lpColumn->mask & LVCF_WIDTH)
6370 hdi.mask |= HDI_WIDTH;
6371 hdi.cxy = lpColumn->cx;
6374 if (lpColumn->mask & LVCF_TEXT)
6376 hdi.mask |= HDI_TEXT | HDI_FORMAT;
6377 hdi.pszText = lpColumn->pszText;
6378 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
6379 hdi.fmt |= HDF_STRING;
6382 if (lpColumn->mask & LVCF_IMAGE)
6384 hdi.mask |= HDI_IMAGE;
6385 hdi.iImage = lpColumn->iImage;
6388 if (lpColumn->mask & LVCF_ORDER)
6390 hdi.mask |= HDI_ORDER;
6391 hdi.iOrder = lpColumn->iOrder;
6394 /* insert item in header control */
6395 nNewColumn = SendMessageA(infoPtr->hwndHeader, HDM_INSERTITEMA,
6396 (WPARAM)nColumn, (LPARAM)&hdi);
6398 /* Need to reset the item width when inserting a new column */
6399 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6401 LISTVIEW_UpdateScroll(hwnd);
6402 InvalidateRect(hwnd, NULL, FALSE);
6408 static LRESULT LISTVIEW_InsertColumnW(HWND hwnd, INT nColumn,
6409 LPLVCOLUMNW lpColumn)
6414 memcpy(&lvca,lpColumn,sizeof(lvca));
6415 if (lpColumn->mask & LVCF_TEXT)
6416 lvca.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpColumn->pszText);
6417 lres = LISTVIEW_InsertColumnA(hwnd,nColumn,&lvca);
6418 if (lpColumn->mask & LVCF_TEXT)
6419 HeapFree(GetProcessHeap(),0,lvca.pszText);
6423 /* LISTVIEW_InsertCompare: callback routine for comparing pszText members of the LV_ITEMS
6424 in a LISTVIEW on insert. Passed to DPA_Sort in LISTVIEW_InsertItem.
6425 This function should only be used for inserting items into a sorted list (LVM_INSERTITEM)
6426 and not during the processing of a LVM_SORTITEMS message. Applications should provide
6427 their own sort proc. when sending LVM_SORTITEMS.
6430 (remarks on LVITEM: LVM_INSERTITEM will insert the new item in the proper sort postion...
6432 LVS_SORTXXX must be specified,
6433 LVS_OWNERDRAW is not set,
6434 <item>.pszText is not LPSTR_TEXTCALLBACK.
6436 (LVS_SORT* flags): "For the LVS_SORTASCENDING... styles, item indices
6437 are sorted based on item text..."
6439 static INT WINAPI LISTVIEW_InsertCompare( LPVOID first, LPVOID second, LPARAM lParam)
6441 HDPA hdpa_first = (HDPA) first;
6442 HDPA hdpa_second = (HDPA) second;
6443 LISTVIEW_ITEM* lv_first = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_first, 0 );
6444 LISTVIEW_ITEM* lv_second = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_second, 0 );
6445 LONG lStyle = GetWindowLongA((HWND) lParam, GWL_STYLE);
6446 INT cmpv = lstrcmpA( lv_first->pszText, lv_second->pszText );
6447 /* if we're sorting descending, negate the return value */
6448 return (lStyle & LVS_SORTDESCENDING) ? -cmpv : cmpv;
6453 * Inserts a new item in the listview control.
6456 * [I] HWND : window handle
6457 * [I] LPLVITEMA : item information
6460 * SUCCESS : new item index
6463 static LRESULT LISTVIEW_InsertItemA(HWND hwnd, LPLVITEMA lpLVItem)
6465 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6466 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6467 UINT uView = lStyle & LVS_TYPEMASK;
6468 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
6473 LISTVIEW_ITEM *lpItem = NULL;
6475 TRACE("(hwnd=%x,lpLVItem=%p)\n", hwnd, lpLVItem);
6477 if (lStyle & LVS_OWNERDATA)
6479 nItem = infoPtr->hdpaItems->nItemCount;
6480 infoPtr->hdpaItems->nItemCount ++;
6484 if (lpLVItem != NULL)
6486 /* make sure it's not a subitem; cannot insert a subitem */
6487 if (lpLVItem->iSubItem == 0)
6489 lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM));
6492 ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
6493 if (LISTVIEW_InitItem(hwnd, lpItem, lpLVItem) != FALSE)
6495 /* insert item in listview control data structure */
6496 hdpaSubItems = DPA_Create(8);
6497 if (hdpaSubItems != NULL)
6499 nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem);
6502 if ( ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
6503 && !(lStyle & LVS_OWNERDRAWFIXED)
6504 && (LPSTR_TEXTCALLBACKA != lpLVItem->pszText) )
6506 /* Insert the item in the proper sort order based on the pszText
6507 member. See comments for LISTVIEW_InsertCompare() for greater detail */
6508 nItem = DPA_InsertPtr( infoPtr->hdpaItems,
6509 GETITEMCOUNT( infoPtr ) + 1, hdpaSubItems );
6510 DPA_Sort( infoPtr->hdpaItems, LISTVIEW_InsertCompare, hwnd );
6511 nItem = DPA_GetPtrIndex( infoPtr->hdpaItems, hdpaSubItems );
6515 nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpLVItem->iItem,
6520 LISTVIEW_ShiftSelections(hwnd,nItem,1);
6522 /* manage item focus */
6523 if (lpLVItem->mask & LVIF_STATE)
6525 lpItem->state &= ~(LVIS_FOCUSED|LVIS_SELECTED);
6526 if (lpLVItem->stateMask & LVIS_SELECTED)
6528 LISTVIEW_SetSelection(hwnd, nItem);
6530 else if (lpLVItem->stateMask & LVIS_FOCUSED)
6532 LISTVIEW_SetItemFocus(hwnd, nItem);
6536 /* send LVN_INSERTITEM notification */
6537 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
6538 nmlv.hdr.hwndFrom = hwnd;
6539 nmlv.hdr.idFrom = lCtrlId;
6540 nmlv.hdr.code = LVN_INSERTITEM;
6542 nmlv.lParam = lpItem->lParam;;
6543 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
6545 if ((uView == LVS_SMALLICON) || (uView == LVS_LIST))
6547 nItemWidth = LISTVIEW_CalculateWidth(hwnd, lpLVItem->iItem);
6548 if (nItemWidth > infoPtr->nItemWidth)
6550 infoPtr->nItemWidth = nItemWidth;
6554 /* align items (set position of each item) */
6555 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
6557 if (lStyle & LVS_ALIGNLEFT)
6559 LISTVIEW_AlignLeft(hwnd);
6563 LISTVIEW_AlignTop(hwnd);
6567 LISTVIEW_UpdateScroll(hwnd);
6568 /* refresh client area */
6569 InvalidateRect(hwnd, NULL, FALSE);
6578 /* free memory if unsuccessful */
6579 if ((nItem == -1) && (lpItem != NULL))
6581 COMCTL32_Free(lpItem);
6587 static LRESULT LISTVIEW_InsertItemW(HWND hwnd, LPLVITEMW lpLVItem) {
6591 memcpy(&lvia,lpLVItem,sizeof(LVITEMA));
6592 if (lvia.mask & LVIF_TEXT) {
6593 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKW)
6594 lvia.pszText = LPSTR_TEXTCALLBACKA;
6596 lvia.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpLVItem->pszText);
6598 lres = LISTVIEW_InsertItemA(hwnd, &lvia);
6599 if (lvia.mask & LVIF_TEXT) {
6600 if (lpLVItem->pszText != LPSTR_TEXTCALLBACKW)
6601 HeapFree(GetProcessHeap(),0,lvia.pszText);
6606 /* LISTVIEW_InsertItemW */
6610 * Redraws a range of items.
6613 * [I] HWND : window handle
6614 * [I] INT : first item
6615 * [I] INT : last item
6621 static LRESULT LISTVIEW_RedrawItems(HWND hwnd, INT nFirst, INT nLast)
6623 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6624 BOOL bResult = FALSE;
6627 if (nFirst <= nLast)
6629 if ((nFirst >= 0) && (nFirst < GETITEMCOUNT(infoPtr)))
6631 if ((nLast >= 0) && (nLast < GETITEMCOUNT(infoPtr)))
6634 for (i = nFirst; i <= nLast; i++)
6636 rcItem.left = LVIR_BOUNDS;
6637 LISTVIEW_GetItemRect(hwnd, i, &rcItem);
6638 InvalidateRect(hwnd, &rcItem, TRUE);
6647 /* LISTVIEW_Scroll */
6651 * Sets the background color.
6654 * [I] HWND : window handle
6655 * [I] COLORREF : background color
6661 static LRESULT LISTVIEW_SetBkColor(HWND hwnd, COLORREF clrBk)
6663 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6665 infoPtr->clrBk = clrBk;
6666 InvalidateRect(hwnd, NULL, TRUE);
6671 /* LISTVIEW_SetBkImage */
6675 * Sets the callback mask. This mask will be used when the parent
6676 * window stores state information (some or all).
6679 * [I] HWND : window handle
6680 * [I] UINT : state mask
6686 static BOOL LISTVIEW_SetCallbackMask(HWND hwnd, UINT uMask)
6688 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6690 infoPtr->uCallbackMask = uMask;
6697 * Sets the attributes of a header item.
6700 * [I] HWND : window handle
6701 * [I] INT : column index
6702 * [I] LPLVCOLUMNA : column attributes
6708 static LRESULT LISTVIEW_SetColumnA(HWND hwnd, INT nColumn,
6709 LPLVCOLUMNA lpColumn)
6711 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6712 BOOL bResult = FALSE;
6713 HDITEMA hdi, hdiget;
6715 if ((lpColumn != NULL) && (nColumn >= 0) &&
6716 (nColumn < Header_GetItemCount(infoPtr->hwndHeader)))
6718 /* initialize memory */
6719 ZeroMemory(&hdi, sizeof(HDITEMA));
6721 if (lpColumn->mask & LVCF_FMT)
6723 /* format member is valid */
6724 hdi.mask |= HDI_FORMAT;
6726 /* get current format first */
6727 hdiget.mask = HDI_FORMAT;
6728 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdiget))
6729 /* preserve HDF_STRING if present */
6730 hdi.fmt = hdiget.fmt & HDF_STRING;
6732 /* set text alignment (leftmost column must be left-aligned) */
6735 hdi.fmt |= HDF_LEFT;
6739 if (lpColumn->fmt & LVCFMT_LEFT)
6741 hdi.fmt |= HDF_LEFT;
6743 else if (lpColumn->fmt & LVCFMT_RIGHT)
6745 hdi.fmt |= HDF_RIGHT;
6747 else if (lpColumn->fmt & LVCFMT_CENTER)
6749 hdi.fmt |= HDF_CENTER;
6753 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
6755 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
6758 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
6760 hdi.fmt |= HDF_IMAGE;
6763 if (lpColumn->fmt & LVCFMT_IMAGE)
6765 hdi.fmt |= HDF_IMAGE;
6766 hdi.iImage = I_IMAGECALLBACK;
6770 if (lpColumn->mask & LVCF_WIDTH)
6772 hdi.mask |= HDI_WIDTH;
6773 hdi.cxy = lpColumn->cx;
6776 if (lpColumn->mask & LVCF_TEXT)
6778 hdi.mask |= HDI_TEXT | HDI_FORMAT;
6779 hdi.pszText = lpColumn->pszText;
6780 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
6781 hdi.fmt |= HDF_STRING;
6784 if (lpColumn->mask & LVCF_IMAGE)
6786 hdi.mask |= HDI_IMAGE;
6787 hdi.iImage = lpColumn->iImage;
6790 if (lpColumn->mask & LVCF_ORDER)
6792 hdi.mask |= HDI_ORDER;
6793 hdi.iOrder = lpColumn->iOrder;
6796 /* set header item attributes */
6797 bResult = Header_SetItemA(infoPtr->hwndHeader, nColumn, &hdi);
6803 /* LISTVIEW_SetColumnW */
6807 * Sets the column order array
6810 * [I] HWND : window handle
6811 * [I] INT : number of elements in column order array
6812 * [I] INT : pointer to column order array
6818 static LRESULT LISTVIEW_SetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
6820 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
6822 FIXME("iCount %d lpiArray %p\n", iCount, lpiArray);
6833 * Sets the width of a column
6836 * [I] HWND : window handle
6837 * [I] INT : column index
6838 * [I] INT : column width
6844 static LRESULT LISTVIEW_SetColumnWidth(HWND hwnd, INT iCol, INT cx)
6846 LISTVIEW_INFO *infoPtr;
6849 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6850 UINT uView = lStyle & LVS_TYPEMASK;
6855 CHAR text_buffer[DISP_TEXT_SIZE];
6856 INT header_item_count;
6861 /* make sure we can get the listview info */
6862 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
6865 if (!infoPtr->hwndHeader) /* make sure we have a header */
6868 /* set column width only if in report or list mode */
6869 if ((uView != LVS_REPORT) && (uView != LVS_LIST))
6872 /* take care of invalid cx values */
6873 if((uView == LVS_REPORT) && (cx < -2))
6874 cx = LVSCW_AUTOSIZE;
6875 else if (uView == LVS_LIST && (cx < 1))
6878 /* resize all columns if in LVS_LIST mode */
6879 if(uView == LVS_LIST) {
6880 infoPtr->nItemWidth = cx;
6881 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
6885 /* autosize based on listview items width */
6886 if(cx == LVSCW_AUTOSIZE)
6888 /* set the width of the header to the width of the widest item */
6889 for(item_index = 0; item_index < GETITEMCOUNT(infoPtr); item_index++)
6891 if(cx < LISTVIEW_GetLabelWidth(hwnd, item_index))
6892 cx = LISTVIEW_GetLabelWidth(hwnd, item_index);
6894 } /* autosize based on listview header width */
6895 else if(cx == LVSCW_AUTOSIZE_USEHEADER)
6897 header_item_count = Header_GetItemCount(infoPtr->hwndHeader);
6899 /* if iCol is the last column make it fill the remainder of the controls width */
6900 if(iCol == (header_item_count - 1)) {
6901 /* get the width of every item except the current one */
6902 hdi.mask = HDI_WIDTH;
6905 for(item_index = 0; item_index < (header_item_count - 1); item_index++) {
6906 Header_GetItemA(infoPtr->hwndHeader, item_index, (LPARAM)(&hdi));
6910 /* retrieve the layout of the header */
6911 GetWindowRect(infoPtr->hwndHeader, &rcHeader);
6913 cx = (rcHeader.right - rcHeader.left) - cx;
6917 /* retrieve header font */
6918 header_font = SendMessageA(infoPtr->hwndHeader, WM_GETFONT, 0L, 0L);
6920 /* retrieve header text */
6921 hdi.mask = HDI_TEXT;
6922 hdi.cchTextMax = sizeof(text_buffer);
6923 hdi.pszText = text_buffer;
6925 Header_GetItemA(infoPtr->hwndHeader, iCol, (LPARAM)(&hdi));
6927 /* determine the width of the text in the header */
6929 old_font = SelectObject(hdc, header_font); /* select the font into hdc */
6931 GetTextExtentPoint32A(hdc, text_buffer, strlen(text_buffer), &size);
6933 SelectObject(hdc, old_font); /* restore the old font */
6934 ReleaseDC(hwnd, hdc);
6936 /* set the width of this column to the width of the text */
6941 /* call header to update the column change */
6942 hdi.mask = HDI_WIDTH;
6945 lret = Header_SetItemA(infoPtr->hwndHeader, (WPARAM)iCol, (LPARAM)&hdi);
6947 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
6954 * Sets the extended listview style.
6957 * [I] HWND : window handle
6962 * SUCCESS : previous style
6965 static LRESULT LISTVIEW_SetExtendedListViewStyle(HWND hwnd, DWORD dwMask, DWORD dwStyle)
6967 LISTVIEW_INFO *infoPtr;
6970 /* make sure we can get the listview info */
6971 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
6974 /* store previous style */
6975 dwOldStyle = infoPtr->dwExStyle;
6979 infoPtr->dwExStyle = (dwOldStyle & ~dwMask) | (dwStyle & dwMask);
6981 infoPtr->dwExStyle = dwStyle;
6983 return (dwOldStyle);
6986 /* LISTVIEW_SetHotCursor */
6990 * Sets the hot item index.
6993 * [I] HWND : window handle
6997 * SUCCESS : previous hot item index
6998 * FAILURE : -1 (no hot item)
7000 static LRESULT LISTVIEW_SetHotItem(HWND hwnd, INT iIndex)
7002 LISTVIEW_INFO *infoPtr;
7005 /* make sure we can get the listview info */
7006 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
7009 /* store previous index */
7010 iOldIndex = infoPtr->nHotItem;
7013 infoPtr->nHotItem = iIndex;
7020 * Sets the amount of time the cursor must hover over an item before it is selected.
7023 * [I] HWND : window handle
7024 * [I] DWORD : dwHoverTime, if -1 the hover time is set to the default
7027 * Returns the previous hover time
7029 static LRESULT LISTVIEW_SetHoverTime(HWND hwnd, DWORD dwHoverTime)
7031 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7032 DWORD oldHoverTime = infoPtr->dwHoverTime;
7034 infoPtr->dwHoverTime = dwHoverTime;
7036 return oldHoverTime;
7039 /* LISTVIEW_SetIconSpacing */
7046 * [I] HWND : window handle
7047 * [I] INT : image list type
7048 * [I] HIMAGELIST : image list handle
7051 * SUCCESS : old image list
7054 static LRESULT LISTVIEW_SetImageList(HWND hwnd, INT nType, HIMAGELIST himl)
7056 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7057 HIMAGELIST himlOld = 0;
7062 himlOld = infoPtr->himlNormal;
7063 infoPtr->himlNormal = himl;
7067 himlOld = infoPtr->himlSmall;
7068 infoPtr->himlSmall = himl;
7072 himlOld = infoPtr->himlState;
7073 infoPtr->himlState = himl;
7074 ImageList_SetBkColor(infoPtr->himlState, CLR_NONE);
7078 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7080 return (LRESULT)himlOld;
7086 * Sets the attributes of an item.
7089 * [I] HWND : window handle
7090 * [I] LPLVITEM : item information
7096 static LRESULT LISTVIEW_SetItemA(HWND hwnd, LPLVITEMA lpLVItem)
7098 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7099 BOOL bResult = FALSE;
7101 if (lpLVItem != NULL)
7103 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
7105 if (lpLVItem->iSubItem == 0)
7107 bResult = LISTVIEW_SetItem(hwnd, lpLVItem);
7111 bResult = LISTVIEW_SetSubItem(hwnd, lpLVItem);
7120 /* LISTVIEW_SetItemW */
7124 * Preallocates memory.
7127 * [I] HWND : window handle
7128 * [I] INT : item count (projected number of items)
7129 * [I] DWORD : update flags
7135 static BOOL LISTVIEW_SetItemCount(HWND hwnd, INT nItems, DWORD dwFlags)
7137 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
7139 if (GetWindowLongA(hwnd, GWL_STYLE) & LVS_OWNERDATA)
7141 int precount,topvisible;
7142 TRACE("LVS_OWNERDATA is set!\n");
7145 * Internally remove all the selections.
7149 LISTVIEW_SELECTION *selection;
7150 selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,0);
7152 LISTVIEW_RemoveSelectionRange(hwnd,selection->lower,
7155 while (infoPtr->hdpaSelectionRanges->nItemCount>0);
7157 precount = infoPtr->hdpaItems->nItemCount;
7158 topvisible = ListView_GetTopIndex(hwnd) +
7159 LISTVIEW_GetCountPerColumn(hwnd) + 1;
7161 infoPtr->hdpaItems->nItemCount = nItems;
7163 LISTVIEW_UpdateSize(hwnd);
7164 LISTVIEW_UpdateScroll(hwnd);
7165 if (min(precount,infoPtr->hdpaItems->nItemCount)<topvisible)
7166 InvalidateRect(hwnd, NULL, TRUE);
7171 return LISTVIEW_DeleteAllItems (hwnd);
7173 if (nItems > GETITEMCOUNT(infoPtr))
7176 FIXME("append items\n");
7179 else if (nItems < GETITEMCOUNT(infoPtr))
7182 while(nItems < GETITEMCOUNT(infoPtr)) {
7183 LISTVIEW_DeleteItem(hwnd, GETITEMCOUNT(infoPtr) - 1);
7193 * Sets the position of an item.
7196 * [I] HWND : window handle
7197 * [I] INT : item index
7198 * [I] LONG : x coordinate
7199 * [I] LONG : y coordinate
7205 static BOOL LISTVIEW_SetItemPosition(HWND hwnd, INT nItem,
7206 LONG nPosX, LONG nPosY)
7208 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
7209 UINT lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7210 UINT uView = lStyle & LVS_TYPEMASK;
7211 LISTVIEW_ITEM *lpItem;
7213 BOOL bResult = FALSE;
7215 TRACE("(hwnd=%x,nItem=%d,X=%ld,Y=%ld)\n", hwnd, nItem, nPosX, nPosY);
7217 if (lStyle & LVS_OWNERDATA)
7220 if ((nItem >= 0) || (nItem < GETITEMCOUNT(infoPtr)))
7222 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
7224 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
7225 if (hdpaSubItems != NULL)
7227 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
7231 lpItem->ptPosition.x = nPosX;
7232 lpItem->ptPosition.y = nPosY;
7243 * Sets the state of one or many items.
7246 * [I] HWND : window handle
7247 * [I]INT : item index
7248 * [I] LPLVITEM : item or subitem info
7254 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
7256 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7257 BOOL bResult = FALSE;
7264 ZeroMemory(&lvItem, sizeof(LVITEMA));
7265 lvItem.mask = LVIF_STATE;
7266 lvItem.state = lpLVItem->state;
7267 lvItem.stateMask = lpLVItem->stateMask ;
7269 /* apply to all items */
7270 for (i = 0; i< GETITEMCOUNT(infoPtr); i++)
7273 if (ListView_SetItemA(hwnd, &lvItem) == FALSE)
7281 ZeroMemory(&lvItem, sizeof(LVITEMA));
7282 lvItem.mask = LVIF_STATE;
7283 lvItem.state = lpLVItem->state;
7284 lvItem.stateMask = lpLVItem->stateMask;
7285 lvItem.iItem = nItem;
7286 bResult = ListView_SetItemA(hwnd, &lvItem);
7294 * Sets the text of an item or subitem.
7297 * [I] HWND : window handle
7298 * [I] INT : item index
7299 * [I] LPLVITEMA : item or subitem info
7305 static BOOL LISTVIEW_SetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
7307 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7308 BOOL bResult = FALSE;
7311 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
7313 ZeroMemory(&lvItem, sizeof(LVITEMA));
7314 lvItem.mask = LVIF_TEXT;
7315 lvItem.pszText = lpLVItem->pszText;
7316 lvItem.iItem = nItem;
7317 lvItem.iSubItem = lpLVItem->iSubItem;
7318 bResult = ListView_SetItemA(hwnd, &lvItem);
7324 /* LISTVIEW_SetItemTextW */
7328 * Set item index that marks the start of a multiple selection.
7331 * [I] HWND : window handle
7335 * Index number or -1 if there is no selection mark.
7337 static LRESULT LISTVIEW_SetSelectionMark(HWND hwnd, INT nIndex)
7339 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7340 INT nOldIndex = infoPtr->nSelectionMark;
7342 infoPtr->nSelectionMark = nIndex;
7349 * Sets the text background color.
7352 * [I] HWND : window handle
7353 * [I] COLORREF : text background color
7359 static LRESULT LISTVIEW_SetTextBkColor(HWND hwnd, COLORREF clrTextBk)
7361 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7363 infoPtr->clrTextBk = clrTextBk;
7364 InvalidateRect(hwnd, NULL, TRUE);
7371 * Sets the text foreground color.
7374 * [I] HWND : window handle
7375 * [I] COLORREF : text color
7381 static LRESULT LISTVIEW_SetTextColor (HWND hwnd, COLORREF clrText)
7383 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7385 infoPtr->clrText = clrText;
7386 InvalidateRect(hwnd, NULL, TRUE);
7391 /* LISTVIEW_SetToolTips */
7392 /* LISTVIEW_SetUnicodeFormat */
7393 /* LISTVIEW_SetWorkAreas */
7397 * Callback internally used by LISTVIEW_SortItems()
7400 * [I] LPVOID : first LISTVIEW_ITEM to compare
7401 * [I] LPVOID : second LISTVIEW_ITEM to compare
7402 * [I] LPARAM : HWND of control
7405 * if first comes before second : negative
7406 * if first comes after second : positive
7407 * if first and second are equivalent : zero
7409 static INT WINAPI LISTVIEW_CallBackCompare(
7414 /* Forward the call to the client defined callback */
7416 HWND hwnd = (HWND)lParam;
7417 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7418 HDPA hdpa_first = (HDPA) first;
7419 HDPA hdpa_second = (HDPA) second;
7420 LISTVIEW_ITEM* lv_first = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_first, 0 );
7421 LISTVIEW_ITEM* lv_second = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_second, 0 );
7423 rv = (infoPtr->pfnCompare)( lv_first->lParam , lv_second->lParam, infoPtr->lParamSort );
7430 * Sorts the listview items.
7433 * [I] HWND : window handle
7434 * [I] WPARAM : application-defined value
7435 * [I] LPARAM : pointer to comparision callback
7441 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam)
7443 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7445 UINT lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7447 if (lStyle & LVS_OWNERDATA)
7450 if (!infoPtr || !infoPtr->hdpaItems)
7453 nCount = GETITEMCOUNT(infoPtr);
7454 /* if there are 0 or 1 items, there is no need to sort */
7457 infoPtr->pfnCompare = (PFNLVCOMPARE)lParam;
7458 infoPtr->lParamSort = (LPARAM)wParam;
7460 DPA_Sort(infoPtr->hdpaItems, LISTVIEW_CallBackCompare, hwnd);
7463 /* align the items */
7464 LISTVIEW_AlignTop(hwnd);
7466 /* refresh the display */
7467 InvalidateRect(hwnd, NULL, TRUE);
7472 /* LISTVIEW_SubItemHitTest */
7476 * Updates an items or rearranges the listview control.
7479 * [I] HWND : window handle
7480 * [I] INT : item index
7486 static LRESULT LISTVIEW_Update(HWND hwnd, INT nItem)
7488 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7489 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7490 BOOL bResult = FALSE;
7493 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
7497 /* rearrange with default alignment style */
7498 if ((lStyle & LVS_AUTOARRANGE) && (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
7499 ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON)))
7501 ListView_Arrange(hwnd, 0);
7505 /* get item bounding rectangle */
7506 rc.left = LVIR_BOUNDS;
7507 ListView_GetItemRect(hwnd, nItem, &rc);
7508 InvalidateRect(hwnd, &rc, TRUE);
7517 * Creates the listview control.
7520 * [I] HWND : window handle
7525 static LRESULT LISTVIEW_Create(HWND hwnd, WPARAM wParam, LPARAM lParam)
7527 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7528 LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam;
7529 UINT uView = lpcs->style & LVS_TYPEMASK;
7532 /* initialize info pointer */
7533 ZeroMemory(infoPtr, sizeof(LISTVIEW_INFO));
7535 /* determine the type of structures to use */
7536 infoPtr->notifyFormat = SendMessageA(GetParent(hwnd), WM_NOTIFYFORMAT,
7537 (WPARAM)hwnd, (LPARAM)NF_QUERY);
7538 if (infoPtr->notifyFormat != NFR_ANSI)
7540 FIXME("ANSI notify format is NOT used\n");
7543 /* initialize color information */
7544 infoPtr->clrBk = GetSysColor(COLOR_WINDOW);
7545 infoPtr->clrText = GetSysColor(COLOR_WINDOWTEXT);
7546 infoPtr->clrTextBk = CLR_DEFAULT;
7548 /* set default values */
7549 infoPtr->uCallbackMask = 0;
7550 infoPtr->nFocusedItem = -1;
7551 infoPtr->nSelectionMark = -1;
7552 infoPtr->nHotItem = -1;
7553 infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING);
7554 infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING);
7555 ZeroMemory(&infoPtr->rcList, sizeof(RECT));
7556 infoPtr->hwndEdit = 0;
7557 infoPtr->pedititem = NULL;
7558 infoPtr->nEditLabelItem = -1;
7560 /* get default font (icon title) */
7561 SystemParametersInfoA(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
7562 infoPtr->hDefaultFont = CreateFontIndirectA(&logFont);
7563 infoPtr->hFont = infoPtr->hDefaultFont;
7566 infoPtr->hwndHeader = CreateWindowA(WC_HEADERA, (LPCSTR)NULL,
7567 WS_CHILD | HDS_HORZ | HDS_BUTTONS,
7568 0, 0, 0, 0, hwnd, (HMENU)0,
7569 lpcs->hInstance, NULL);
7571 /* set header font */
7572 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont,
7575 if (uView == LVS_ICON)
7577 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
7578 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
7580 else if (uView == LVS_REPORT)
7582 if (!(LVS_NOCOLUMNHEADER & lpcs->style))
7584 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
7588 /* set HDS_HIDDEN flag to hide the header bar */
7589 SetWindowLongA(infoPtr->hwndHeader, GWL_STYLE,
7590 GetWindowLongA(infoPtr->hwndHeader, GWL_STYLE) | HDS_HIDDEN);
7594 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7595 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7599 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7600 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7603 /* display unsupported listview window styles */
7604 LISTVIEW_UnsupportedStyles(lpcs->style);
7606 /* allocate memory for the data structure */
7607 infoPtr->hdpaItems = DPA_Create(10);
7609 /* allocate memory for the selection ranges */
7610 infoPtr->hdpaSelectionRanges = DPA_Create(10);
7612 /* initialize size of items */
7613 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7614 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7616 /* initialize the hover time to -1(indicating the default system hover time) */
7617 infoPtr->dwHoverTime = -1;
7624 * Erases the background of the listview control.
7627 * [I] HWND : window handle
7628 * [I] WPARAM : device context handle
7629 * [I] LPARAM : not used
7635 static LRESULT LISTVIEW_EraseBackground(HWND hwnd, WPARAM wParam,
7638 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7641 if (infoPtr->clrBk == CLR_NONE)
7643 bResult = SendMessageA(GetParent(hwnd), WM_ERASEBKGND, wParam, lParam);
7648 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
7649 GetClientRect(hwnd, &rc);
7650 FillRect((HDC)wParam, &rc, hBrush);
7651 DeleteObject(hBrush);
7659 static void LISTVIEW_FillBackground(HWND hwnd, HDC hdc, LPRECT rc)
7661 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7663 if (infoPtr->clrBk != CLR_NONE)
7665 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
7666 FillRect(hdc, rc, hBrush);
7667 DeleteObject(hBrush);
7673 * Retrieves the listview control font.
7676 * [I] HWND : window handle
7681 static LRESULT LISTVIEW_GetFont(HWND hwnd)
7683 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7685 return infoPtr->hFont;
7690 * Performs vertical scrolling.
7693 * [I] HWND : window handle
7694 * [I] INT : scroll code
7695 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
7697 * [I] HWND : scrollbar control window handle
7702 static LRESULT LISTVIEW_VScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
7705 SCROLLINFO scrollInfo;
7707 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7708 SendMessageA(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
7710 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
7711 scrollInfo.cbSize = sizeof(SCROLLINFO);
7712 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
7714 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
7716 INT nOldScrollPos = scrollInfo.nPos;
7717 switch (nScrollCode)
7720 if (scrollInfo.nPos > scrollInfo.nMin)
7727 if (scrollInfo.nPos < scrollInfo.nMax)
7734 if (scrollInfo.nPos > scrollInfo.nMin)
7736 if (scrollInfo.nPos >= scrollInfo.nPage)
7738 scrollInfo.nPos -= scrollInfo.nPage;
7742 scrollInfo.nPos = scrollInfo.nMin;
7748 if (scrollInfo.nPos < scrollInfo.nMax)
7750 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
7752 scrollInfo.nPos += scrollInfo.nPage;
7756 scrollInfo.nPos = scrollInfo.nMax;
7762 scrollInfo.nPos = nCurrentPos;
7763 if (scrollInfo.nPos > scrollInfo.nMax)
7764 scrollInfo.nPos=scrollInfo.nMax;
7766 if (scrollInfo.nPos < scrollInfo.nMin)
7767 scrollInfo.nPos=scrollInfo.nMin;
7772 if (nOldScrollPos != scrollInfo.nPos)
7774 scrollInfo.fMask = SIF_POS;
7775 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
7776 InvalidateRect(hwnd, NULL, TRUE);
7785 * Performs horizontal scrolling.
7788 * [I] HWND : window handle
7789 * [I] INT : scroll code
7790 * [I] SHORT : current scroll position if scroll code is SB_THUMBPOSITION
7792 * [I] HWND : scrollbar control window handle
7797 static LRESULT LISTVIEW_HScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
7800 SCROLLINFO scrollInfo;
7802 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7803 SendMessageA(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
7806 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
7807 scrollInfo.cbSize = sizeof(SCROLLINFO);
7808 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
7810 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
7812 INT nOldScrollPos = scrollInfo.nPos;
7814 switch (nScrollCode)
7817 if (scrollInfo.nPos > scrollInfo.nMin)
7824 if (scrollInfo.nPos < scrollInfo.nMax)
7831 if (scrollInfo.nPos > scrollInfo.nMin)
7833 if (scrollInfo.nPos >= scrollInfo.nPage)
7835 scrollInfo.nPos -= scrollInfo.nPage;
7839 scrollInfo.nPos = scrollInfo.nMin;
7845 if (scrollInfo.nPos < scrollInfo.nMax)
7847 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
7849 scrollInfo.nPos += scrollInfo.nPage;
7853 scrollInfo.nPos = scrollInfo.nMax;
7859 scrollInfo.nPos = nCurrentPos;
7861 if (scrollInfo.nPos > scrollInfo.nMax)
7862 scrollInfo.nPos=scrollInfo.nMax;
7864 if (scrollInfo.nPos < scrollInfo.nMin)
7865 scrollInfo.nPos=scrollInfo.nMin;
7869 if (nOldScrollPos != scrollInfo.nPos)
7871 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
7872 scrollInfo.fMask = SIF_POS;
7873 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
7874 if(uView == LVS_REPORT)
7876 scrollInfo.fMask = SIF_POS;
7877 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
7878 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
7880 InvalidateRect(hwnd, NULL, TRUE);
7887 static LRESULT LISTVIEW_MouseWheel(HWND hwnd, INT wheelDelta)
7889 INT gcWheelDelta = 0;
7890 UINT pulScrollLines = 3;
7891 SCROLLINFO scrollInfo;
7893 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
7895 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
7896 gcWheelDelta -= wheelDelta;
7898 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
7899 scrollInfo.cbSize = sizeof(SCROLLINFO);
7900 scrollInfo.fMask = SIF_POS | SIF_RANGE;
7907 * listview should be scrolled by a multiple of 37 dependently on its dimension or its visible item number
7908 * should be fixed in the future.
7910 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
7911 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + (gcWheelDelta < 0) ? 37 : -37, 0);
7915 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
7917 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
7919 int cLineScroll = min(LISTVIEW_GetCountPerColumn(hwnd), pulScrollLines);
7920 cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
7921 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + cLineScroll, 0);
7927 LISTVIEW_HScroll(hwnd, (gcWheelDelta < 0) ? SB_LINELEFT : SB_LINERIGHT, 0, 0);
7938 * [I] HWND : window handle
7939 * [I] INT : virtual key
7940 * [I] LONG : key data
7945 static LRESULT LISTVIEW_KeyDown(HWND hwnd, INT nVirtualKey, LONG lKeyData)
7947 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7948 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
7949 HWND hwndParent = GetParent(hwnd);
7950 NMLVKEYDOWN nmKeyDown;
7953 BOOL bRedraw = FALSE;
7954 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7955 UINT uView = lStyle & LVS_TYPEMASK;
7957 /* send LVN_KEYDOWN notification */
7958 ZeroMemory(&nmKeyDown, sizeof(NMLVKEYDOWN));
7959 nmKeyDown.hdr.hwndFrom = hwnd;
7960 nmKeyDown.hdr.idFrom = nCtrlId;
7961 nmKeyDown.hdr.code = LVN_KEYDOWN;
7962 nmKeyDown.wVKey = nVirtualKey;
7963 nmKeyDown.flags = 0;
7964 SendMessageA(hwndParent, WM_NOTIFY, (WPARAM)nCtrlId, (LPARAM)&nmKeyDown);
7967 nmh.hwndFrom = hwnd;
7968 nmh.idFrom = nCtrlId;
7970 switch (nVirtualKey)
7973 if ((GETITEMCOUNT(infoPtr) > 0) && (infoPtr->nFocusedItem != -1))
7975 /* send NM_RETURN notification */
7976 nmh.code = NM_RETURN;
7977 ListView_Notify(hwndParent, nCtrlId, &nmh);
7979 /* send LVN_ITEMACTIVATE notification */
7980 nmh.code = LVN_ITEMACTIVATE;
7981 ListView_Notify(hwndParent, nCtrlId, &nmh);
7986 if (GETITEMCOUNT(infoPtr) > 0)
7993 if (GETITEMCOUNT(infoPtr) > 0)
7995 nItem = GETITEMCOUNT(infoPtr) - 1;
8000 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TOLEFT);
8004 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_ABOVE);
8008 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TORIGHT);
8012 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_BELOW);
8016 if (uView == LVS_REPORT)
8018 nItem = infoPtr->nFocusedItem - LISTVIEW_GetCountPerColumn(hwnd);
8022 nItem = infoPtr->nFocusedItem - LISTVIEW_GetCountPerColumn(hwnd)
8023 * LISTVIEW_GetCountPerRow(hwnd);
8025 if(nItem < 0) nItem = 0;
8029 if (uView == LVS_REPORT)
8031 nItem = infoPtr->nFocusedItem + LISTVIEW_GetCountPerColumn(hwnd);
8035 nItem = infoPtr->nFocusedItem + LISTVIEW_GetCountPerColumn(hwnd)
8036 * LISTVIEW_GetCountPerRow(hwnd);
8038 if(nItem >= GETITEMCOUNT(infoPtr)) nItem = GETITEMCOUNT(infoPtr) - 1;
8042 if ((nItem != -1) && (nItem != infoPtr->nFocusedItem))
8044 bRedraw = LISTVIEW_KeySelection(hwnd, nItem);
8045 if (bRedraw != FALSE)
8047 /* refresh client area */
8060 * [I] HWND : window handle
8065 static LRESULT LISTVIEW_KillFocus(HWND hwnd)
8067 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
8068 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8072 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8073 UINT uView = lStyle & LVS_TYPEMASK;
8075 TRACE("(hwnd=%x)\n", hwnd);
8077 /* send NM_KILLFOCUS notification */
8078 nmh.hwndFrom = hwnd;
8079 nmh.idFrom = nCtrlId;
8080 nmh.code = NM_KILLFOCUS;
8081 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8083 /* set window focus flag */
8084 infoPtr->bFocus = FALSE;
8086 /* NEED drawing optimization ; redraw the selected items */
8087 if (uView & LVS_REPORT)
8089 nTop = LISTVIEW_GetTopIndex(hwnd);
8091 LISTVIEW_GetCountPerColumn(hwnd) + 1;
8096 nBottom = GETITEMCOUNT(infoPtr);
8098 for (i = nTop; i<nBottom; i++)
8100 if (LISTVIEW_IsSelected(hwnd,i))
8102 rcItem.left = LVIR_BOUNDS;
8103 LISTVIEW_GetItemRect(hwnd, i, &rcItem);
8104 InvalidateRect(hwnd, &rcItem, FALSE);
8113 * Processes double click messages (left mouse button).
8116 * [I] HWND : window handle
8117 * [I] WORD : key flag
8118 * [I] WORD : x coordinate
8119 * [I] WORD : y coordinate
8124 static LRESULT LISTVIEW_LButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
8127 LONG nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8128 LVHITTESTINFO htInfo;
8133 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8135 htInfo.pt.x = wPosX;
8136 htInfo.pt.y = wPosY;
8138 /* send NM_DBLCLK notification */
8139 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
8140 nmlv.hdr.hwndFrom = hwnd;
8141 nmlv.hdr.idFrom = nCtrlId;
8142 nmlv.hdr.code = NM_DBLCLK;
8143 ret = LISTVIEW_HitTestItem(hwnd, &htInfo, TRUE);
8146 nmlv.iItem = htInfo.iItem;
8147 nmlv.iSubItem = htInfo.iSubItem;
8154 nmlv.ptAction.x = wPosX;
8155 nmlv.ptAction.y = wPosY;
8156 ListView_LVNotify(GetParent(hwnd), nCtrlId, &nmlv);
8159 /* To send the LVN_ITEMACTIVATE, it must be on an Item */
8162 /* send LVN_ITEMACTIVATE notification */
8163 nmh.hwndFrom = hwnd;
8164 nmh.idFrom = nCtrlId;
8165 nmh.code = LVN_ITEMACTIVATE;
8166 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8174 * Processes mouse down messages (left mouse button).
8177 * [I] HWND : window handle
8178 * [I] WORD : key flag
8179 * [I] WORD : x coordinate
8180 * [I] WORD : y coordinate
8185 static LRESULT LISTVIEW_LButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
8188 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8189 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8190 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8191 static BOOL bGroupSelect = TRUE;
8196 TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd, wKey, wPosX,
8199 /* send NM_RELEASEDCAPTURE notification */
8200 nmh.hwndFrom = hwnd;
8201 nmh.idFrom = nCtrlId;
8202 nmh.code = NM_RELEASEDCAPTURE;
8203 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8205 if (infoPtr->bFocus == FALSE)
8210 /* set left button down flag */
8211 infoPtr->bLButtonDown = TRUE;
8213 ptPosition.x = wPosX;
8214 ptPosition.y = wPosY;
8215 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
8216 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
8218 if (lStyle & LVS_SINGLESEL)
8220 if ((ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
8221 && infoPtr->nEditLabelItem == -1)
8223 infoPtr->nEditLabelItem = nItem;
8227 LISTVIEW_SetSelection(hwnd, nItem);
8232 if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
8234 if (bGroupSelect != FALSE)
8236 LISTVIEW_AddGroupSelection(hwnd, nItem);
8240 LISTVIEW_AddSelection(hwnd, nItem);
8243 else if (wKey & MK_CONTROL)
8245 bGroupSelect = LISTVIEW_ToggleSelection(hwnd, nItem);
8247 else if (wKey & MK_SHIFT)
8249 LISTVIEW_SetGroupSelection(hwnd, nItem);
8254 (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED);
8256 /* set selection (clears other pre-existing selections) */
8257 LISTVIEW_SetSelection(hwnd, nItem);
8259 if (was_selected && infoPtr->nEditLabelItem == -1)
8261 infoPtr->nEditLabelItem = nItem;
8268 /* remove all selections */
8269 LISTVIEW_RemoveAllSelections(hwnd);
8272 /* redraw if we could have possibly selected something */
8273 if(!GETITEMCOUNT(infoPtr)) InvalidateRect(hwnd, NULL, TRUE);
8280 * Processes mouse up messages (left mouse button).
8283 * [I] HWND : window handle
8284 * [I] WORD : key flag
8285 * [I] WORD : x coordinate
8286 * [I] WORD : y coordinate
8291 static LRESULT LISTVIEW_LButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
8294 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8296 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8298 if (infoPtr->bLButtonDown != FALSE)
8300 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8302 LVHITTESTINFO lvHitTestInfo;
8305 lvHitTestInfo.pt.x = wPosX;
8306 lvHitTestInfo.pt.y = wPosY;
8308 /* send NM_CLICK notification */
8309 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
8310 nmlv.hdr.hwndFrom = hwnd;
8311 nmlv.hdr.idFrom = nCtrlId;
8312 nmlv.hdr.code = NM_CLICK;
8313 ret = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo, TRUE);
8316 nmlv.iItem = lvHitTestInfo.iItem;
8317 nmlv.iSubItem = lvHitTestInfo.iSubItem;
8324 nmlv.ptAction.x = wPosX;
8325 nmlv.ptAction.y = wPosY;
8326 ListView_LVNotify(GetParent(hwnd), nCtrlId, &nmlv);
8329 /* set left button flag */
8330 infoPtr->bLButtonDown = FALSE;
8332 if(infoPtr->nEditLabelItem != -1)
8334 if(lvHitTestInfo.iItem == infoPtr->nEditLabelItem)
8336 LISTVIEW_EditLabelA(hwnd, lvHitTestInfo.iItem);
8338 infoPtr->nEditLabelItem = -1;
8347 * Creates the listview control (called before WM_CREATE).
8350 * [I] HWND : window handle
8351 * [I] WPARAM : unhandled
8352 * [I] LPARAM : widow creation info
8357 static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
8359 LISTVIEW_INFO *infoPtr;
8361 TRACE("(hwnd=%x,wParam=%x,lParam=%lx)\n", hwnd, wParam, lParam);
8363 /* allocate memory for info structure */
8364 infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc(sizeof(LISTVIEW_INFO));
8365 SetWindowLongA(hwnd, 0, (LONG)infoPtr);
8366 if (infoPtr == NULL)
8368 ERR("could not allocate info memory!\n");
8372 if ((LISTVIEW_INFO *)GetWindowLongA(hwnd, 0) != infoPtr)
8374 ERR("pointer assignment error!\n");
8378 return DefWindowProcA(hwnd, WM_NCCREATE, wParam, lParam);
8383 * Destroys the listview control (called after WM_DESTROY).
8386 * [I] HWND : window handle
8391 static LRESULT LISTVIEW_NCDestroy(HWND hwnd)
8393 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8395 TRACE("(hwnd=%x)\n", hwnd);
8397 /* delete all items */
8398 LISTVIEW_DeleteAllItems(hwnd);
8400 /* destroy data structure */
8401 DPA_Destroy(infoPtr->hdpaItems);
8402 DPA_Destroy(infoPtr->hdpaSelectionRanges);
8405 infoPtr->hFont = (HFONT)0;
8406 if (infoPtr->hDefaultFont)
8408 DeleteObject(infoPtr->hDefaultFont);
8411 /* free listview info pointer*/
8412 COMCTL32_Free(infoPtr);
8414 SetWindowLongA(hwnd, 0, 0);
8420 * Handles notifications from children.
8423 * [I] HWND : window handle
8424 * [I] INT : control identifier
8425 * [I] LPNMHDR : notification information
8430 static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh)
8432 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8434 if (lpnmh->hwndFrom == infoPtr->hwndHeader)
8436 /* handle notification from header control */
8437 if (lpnmh->code == HDN_ENDTRACKA)
8439 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8440 InvalidateRect(hwnd, NULL, TRUE);
8442 else if(lpnmh->code == HDN_ITEMCLICKA)
8444 /* Handle sorting by Header Column */
8446 LPNMHEADERA pnmHeader = (LPNMHEADERA) lpnmh;
8447 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
8449 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
8450 nmlv.hdr.hwndFrom = hwnd;
8451 nmlv.hdr.idFrom = lCtrlId;
8452 nmlv.hdr.code = LVN_COLUMNCLICK;
8454 nmlv.iSubItem = pnmHeader->iItem;
8456 ListView_LVNotify(GetParent(hwnd),lCtrlId, &nmlv);
8459 else if(lpnmh->code == NM_RELEASEDCAPTURE)
8461 /* Idealy this should be done in HDN_ENDTRACKA
8462 * but since SetItemBounds in Header.c is called after
8463 * the notification is sent, it is neccessary to handle the
8464 * update of the scroll bar here (Header.c works fine as it is,
8465 * no need to disturb it)
8467 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8468 LISTVIEW_UpdateScroll(hwnd);
8469 InvalidateRect(hwnd, NULL, TRUE);
8479 * Determines the type of structure to use.
8482 * [I] HWND : window handle of the sender
8483 * [I] HWND : listview window handle
8484 * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
8489 static LRESULT LISTVIEW_NotifyFormat(HWND hwndFrom, HWND hwnd, INT nCommand)
8491 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8493 if (nCommand == NF_REQUERY)
8495 /* determine the type of structure to use */
8496 infoPtr->notifyFormat = SendMessageA(hwndFrom, WM_NOTIFYFORMAT,
8497 (WPARAM)hwnd, (LPARAM)NF_QUERY);
8498 if (infoPtr->notifyFormat == NFR_UNICODE)
8500 FIXME("NO support for unicode structures");
8509 * Paints/Repaints the listview control.
8512 * [I] HWND : window handle
8513 * [I] HDC : device context handle
8518 static LRESULT LISTVIEW_Paint(HWND hwnd, HDC hdc)
8522 TRACE("(hwnd=%x,hdc=%x)\n", hwnd, hdc);
8526 hdc = BeginPaint(hwnd, &ps);
8527 LISTVIEW_Refresh(hwnd, hdc);
8528 EndPaint(hwnd, &ps);
8532 LISTVIEW_Refresh(hwnd, hdc);
8540 * Processes double click messages (right mouse button).
8543 * [I] HWND : window handle
8544 * [I] WORD : key flag
8545 * [I] WORD : x coordinate
8546 * [I] WORD : y coordinate
8551 static LRESULT LISTVIEW_RButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
8554 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8557 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8559 /* send NM_RELEASEDCAPTURE notification */
8560 nmh.hwndFrom = hwnd;
8561 nmh.idFrom = nCtrlId;
8562 nmh.code = NM_RELEASEDCAPTURE;
8563 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8565 /* send NM_RDBLCLK notification */
8566 nmh.code = NM_RDBLCLK;
8567 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8574 * Processes mouse down messages (right mouse button).
8577 * [I] HWND : window handle
8578 * [I] WORD : key flag
8579 * [I] WORD : x coordinate
8580 * [I] WORD : y coordinate
8585 static LRESULT LISTVIEW_RButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
8588 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8589 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8594 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8596 /* send NM_RELEASEDCAPTURE notification */
8597 nmh.hwndFrom = hwnd;
8598 nmh.idFrom = nCtrlId;
8599 nmh.code = NM_RELEASEDCAPTURE;
8600 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8602 /* make sure the listview control window has the focus */
8603 if (infoPtr->bFocus == FALSE)
8608 /* set right button down flag */
8609 infoPtr->bRButtonDown = TRUE;
8611 /* determine the index of the selected item */
8612 ptPosition.x = wPosX;
8613 ptPosition.y = wPosY;
8614 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
8615 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
8617 if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)))
8619 LISTVIEW_SetSelection(hwnd, nItem);
8624 LISTVIEW_RemoveAllSelections(hwnd);
8632 * Processes mouse up messages (right mouse button).
8635 * [I] HWND : window handle
8636 * [I] WORD : key flag
8637 * [I] WORD : x coordinate
8638 * [I] WORD : y coordinate
8643 static LRESULT LISTVIEW_RButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
8646 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8647 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8649 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8651 if (infoPtr->bRButtonDown != FALSE)
8654 LVHITTESTINFO lvHitTestInfo;
8658 lvHitTestInfo.pt.x = wPosX;
8659 lvHitTestInfo.pt.y = wPosY;
8661 /* Send NM_RClICK notification */
8662 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
8663 nmlv.hdr.hwndFrom = hwnd;
8664 nmlv.hdr.idFrom = nCtrlId;
8665 nmlv.hdr.code = NM_RCLICK;
8666 ret = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo, TRUE);
8669 nmlv.iItem = lvHitTestInfo.iItem;
8670 nmlv.iSubItem = lvHitTestInfo.iSubItem;
8677 nmlv.ptAction.x = wPosX;
8678 nmlv.ptAction.y = wPosY;
8679 ListView_LVNotify(GetParent(hwnd), nCtrlId, &nmlv);
8684 /* set button flag */
8685 infoPtr->bRButtonDown = FALSE;
8687 /* Change to screen coordinate for WM_CONTEXTMENU */
8688 ClientToScreen(hwnd, &pt);
8690 /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
8691 SendMessageA( hwnd, WM_CONTEXTMENU, (WPARAM) hwnd, MAKELPARAM(pt.x, pt.y));
8702 * [I] HWND : window handle
8703 * [I] HWND : window handle of previously focused window
8708 static LRESULT LISTVIEW_SetFocus(HWND hwnd, HWND hwndLoseFocus)
8710 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8711 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8714 TRACE("(hwnd=%x, hwndLoseFocus=%x)\n", hwnd, hwndLoseFocus);
8716 /* send NM_SETFOCUS notification */
8717 nmh.hwndFrom = hwnd;
8718 nmh.idFrom = nCtrlId;
8719 nmh.code = NM_SETFOCUS;
8720 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8722 /* set window focus flag */
8723 infoPtr->bFocus = TRUE;
8735 * [I] HWND : window handle
8736 * [I] HFONT : font handle
8737 * [I] WORD : redraw flag
8742 static LRESULT LISTVIEW_SetFont(HWND hwnd, HFONT hFont, WORD fRedraw)
8744 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8745 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
8747 TRACE("(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd, hFont, fRedraw);
8751 infoPtr->hFont = infoPtr->hDefaultFont;
8755 infoPtr->hFont = hFont;
8758 if (uView == LVS_REPORT)
8760 /* set header font */
8761 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont,
8762 MAKELPARAM(fRedraw, 0));
8765 /* invalidate listview control client area */
8766 InvalidateRect(hwnd, NULL, TRUE);
8768 if (fRedraw != FALSE)
8778 * Message handling for WM_SETREDRAW.
8779 * For the Listview, it invalidates the entire window (the doc specifies otherwise)
8782 * [I] HWND : window handle
8783 * [I] bRedraw: state of redraw flag
8786 * DefWinProc return value
8788 static LRESULT LISTVIEW_SetRedraw(HWND hwnd, BOOL bRedraw)
8791 lResult = DefWindowProcA(hwnd, WM_SETREDRAW, bRedraw, 0);
8794 RedrawWindow(hwnd, NULL, 0,
8795 RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN | RDW_ERASENOW);
8802 * Resizes the listview control. This function processes WM_SIZE
8803 * messages. At this time, the width and height are not used.
8806 * [I] HWND : window handle
8807 * [I] WORD : new width
8808 * [I] WORD : new height
8813 static LRESULT LISTVIEW_Size(HWND hwnd, int Width, int Height)
8815 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8816 UINT uView = lStyle & LVS_TYPEMASK;
8818 TRACE("(hwnd=%x, width=%d, height=%d)\n",hwnd, Width, Height);
8820 LISTVIEW_UpdateSize(hwnd);
8822 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
8824 if (lStyle & LVS_ALIGNLEFT)
8826 LISTVIEW_AlignLeft(hwnd);
8830 LISTVIEW_AlignTop(hwnd);
8834 LISTVIEW_UpdateScroll(hwnd);
8836 /* invalidate client area + erase background */
8837 InvalidateRect(hwnd, NULL, TRUE);
8844 * Sets the size information.
8847 * [I] HWND : window handle
8852 static VOID LISTVIEW_UpdateSize(HWND hwnd)
8854 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8855 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8856 UINT uView = lStyle & LVS_TYPEMASK;
8859 GetClientRect(hwnd, &rcList);
8860 infoPtr->rcList.left = 0;
8861 infoPtr->rcList.right = max(rcList.right - rcList.left, 1);
8862 infoPtr->rcList.top = 0;
8863 infoPtr->rcList.bottom = max(rcList.bottom - rcList.top, 1);
8865 if (uView == LVS_LIST)
8867 if ((lStyle & WS_HSCROLL) == 0)
8869 INT nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
8870 if (infoPtr->rcList.bottom > nHScrollHeight)
8872 infoPtr->rcList.bottom -= nHScrollHeight;
8876 else if (uView == LVS_REPORT)
8883 Header_Layout(infoPtr->hwndHeader, &hl);
8885 SetWindowPos(wp.hwnd, wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
8887 if (!(LVS_NOCOLUMNHEADER & lStyle))
8889 infoPtr->rcList.top = max(wp.cy, 0);
8896 * Processes WM_STYLECHANGED messages.
8899 * [I] HWND : window handle
8900 * [I] WPARAM : window style type (normal or extended)
8901 * [I] LPSTYLESTRUCT : window style information
8906 static INT LISTVIEW_StyleChanged(HWND hwnd, WPARAM wStyleType,
8909 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8910 UINT uNewView = lpss->styleNew & LVS_TYPEMASK;
8911 UINT uOldView = lpss->styleOld & LVS_TYPEMASK;
8912 RECT rcList = infoPtr->rcList;
8914 TRACE("(hwnd=%x, styletype=%x, stylestruct=%p)\n",
8915 hwnd, wStyleType, lpss);
8917 if (wStyleType == GWL_STYLE)
8919 if (uOldView == LVS_REPORT)
8921 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
8924 if ((lpss->styleOld & WS_HSCROLL) != 0)
8926 ShowScrollBar(hwnd, SB_HORZ, FALSE);
8929 if ((lpss->styleOld & WS_VSCROLL) != 0)
8931 ShowScrollBar(hwnd, SB_VERT, FALSE);
8934 if (uNewView == LVS_ICON)
8936 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
8937 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
8938 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8939 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8940 if (lpss->styleNew & LVS_ALIGNLEFT)
8942 LISTVIEW_AlignLeft(hwnd);
8946 LISTVIEW_AlignTop(hwnd);
8949 else if (uNewView == LVS_REPORT)
8956 Header_Layout(infoPtr->hwndHeader, &hl);
8957 SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, wp.cy,
8959 if (!(LVS_NOCOLUMNHEADER & lpss->styleNew))
8960 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
8962 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
8963 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
8964 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8965 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8967 else if (uNewView == LVS_LIST)
8969 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
8970 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
8971 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8972 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8976 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
8977 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
8978 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8979 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8980 if (lpss->styleNew & LVS_ALIGNLEFT)
8982 LISTVIEW_AlignLeft(hwnd);
8986 LISTVIEW_AlignTop(hwnd);
8990 /* update the size of the client area */
8991 LISTVIEW_UpdateSize(hwnd);
8993 /* add scrollbars if needed */
8994 LISTVIEW_UpdateScroll(hwnd);
8996 /* invalidate client area + erase background */
8997 InvalidateRect(hwnd, NULL, TRUE);
8999 /* print the list of unsupported window styles */
9000 LISTVIEW_UnsupportedStyles(lpss->styleNew);
9003 /* If they change the view and we have an active edit control
9004 we will need to kill the control since the redraw will
9005 misplace the edit control.
9007 if (infoPtr->hwndEdit &&
9008 ((uNewView & (LVS_ICON|LVS_LIST|LVS_SMALLICON)) !=
9009 ((LVS_ICON|LVS_LIST|LVS_SMALLICON) & uOldView)))
9011 SendMessageA(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
9019 * Window procedure of the listview control.
9022 static LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
9025 TRACE("hwnd=%x uMsg=%x wParam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam);
9026 if (!GetWindowLongA(hwnd, 0) && (uMsg != WM_NCCREATE))
9027 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
9030 case LVM_APPROXIMATEVIEWRECT:
9031 return LISTVIEW_ApproximateViewRect(hwnd, (INT)wParam,
9032 LOWORD(lParam), HIWORD(lParam));
9034 return LISTVIEW_Arrange(hwnd, (INT)wParam);
9036 /* case LVM_CREATEDRAGIMAGE: */
9038 case LVM_DELETEALLITEMS:
9039 return LISTVIEW_DeleteAllItems(hwnd);
9041 case LVM_DELETECOLUMN:
9042 return LISTVIEW_DeleteColumn(hwnd, (INT)wParam);
9044 case LVM_DELETEITEM:
9045 return LISTVIEW_DeleteItem(hwnd, (INT)wParam);
9047 case LVM_EDITLABELW:
9048 case LVM_EDITLABELA:
9049 return LISTVIEW_EditLabelA(hwnd, (INT)wParam);
9051 case LVM_ENSUREVISIBLE:
9052 return LISTVIEW_EnsureVisible(hwnd, (INT)wParam, (BOOL)lParam);
9055 return LISTVIEW_FindItem(hwnd, (INT)wParam, (LPLVFINDINFO)lParam);
9057 case LVM_GETBKCOLOR:
9058 return LISTVIEW_GetBkColor(hwnd);
9060 /* case LVM_GETBKIMAGE: */
9062 case LVM_GETCALLBACKMASK:
9063 return LISTVIEW_GetCallbackMask(hwnd);
9065 case LVM_GETCOLUMNA:
9066 return LISTVIEW_GetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
9068 /* case LVM_GETCOLUMNW: */
9070 case LVM_GETCOLUMNORDERARRAY:
9071 return LISTVIEW_GetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
9073 case LVM_GETCOLUMNWIDTH:
9074 return LISTVIEW_GetColumnWidth(hwnd, (INT)wParam);
9076 case LVM_GETCOUNTPERPAGE:
9077 return LISTVIEW_GetCountPerPage(hwnd);
9079 case LVM_GETEDITCONTROL:
9080 return LISTVIEW_GetEditControl(hwnd);
9082 case LVM_GETEXTENDEDLISTVIEWSTYLE:
9083 return LISTVIEW_GetExtendedListViewStyle(hwnd);
9086 return LISTVIEW_GetHeader(hwnd);
9088 /* case LVM_GETHOTCURSOR: */
9090 case LVM_GETHOTITEM:
9091 return LISTVIEW_GetHotItem(hwnd);
9093 case LVM_GETHOVERTIME:
9094 return LISTVIEW_GetHoverTime(hwnd);
9096 case LVM_GETIMAGELIST:
9097 return LISTVIEW_GetImageList(hwnd, (INT)wParam);
9099 /* case LVM_GETISEARCHSTRING: */
9102 return LISTVIEW_GetItemA(hwnd, (LPLVITEMA)lParam, FALSE);
9104 /* case LVM_GETITEMW: */
9106 case LVM_GETITEMCOUNT:
9107 return LISTVIEW_GetItemCount(hwnd);
9109 case LVM_GETITEMPOSITION:
9110 return LISTVIEW_GetItemPosition(hwnd, (INT)wParam, (LPPOINT)lParam);
9112 case LVM_GETITEMRECT:
9113 return LISTVIEW_GetItemRect(hwnd, (INT)wParam, (LPRECT)lParam);
9115 case LVM_GETITEMSPACING:
9116 return LISTVIEW_GetItemSpacing(hwnd, (BOOL)wParam);
9118 case LVM_GETITEMSTATE:
9119 return LISTVIEW_GetItemState(hwnd, (INT)wParam, (UINT)lParam);
9121 case LVM_GETITEMTEXTA:
9122 LISTVIEW_GetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
9125 /* case LVM_GETITEMTEXTW: */
9127 case LVM_GETNEXTITEM:
9128 return LISTVIEW_GetNextItem(hwnd, (INT)wParam, LOWORD(lParam));
9130 /* case LVM_GETNUMBEROFWORKAREAS: */
9133 return LISTVIEW_GetOrigin(hwnd, (LPPOINT)lParam);
9135 case LVM_GETSELECTEDCOUNT:
9136 return LISTVIEW_GetSelectedCount(hwnd);
9138 case LVM_GETSELECTIONMARK:
9139 return LISTVIEW_GetSelectionMark(hwnd);
9141 case LVM_GETSTRINGWIDTHA:
9142 return LISTVIEW_GetStringWidthA (hwnd, (LPCSTR)lParam);
9144 /* case LVM_GETSTRINGWIDTHW: */
9145 /* case LVM_GETSUBITEMRECT: */
9147 case LVM_GETTEXTBKCOLOR:
9148 return LISTVIEW_GetTextBkColor(hwnd);
9150 case LVM_GETTEXTCOLOR:
9151 return LISTVIEW_GetTextColor(hwnd);
9153 /* case LVM_GETTOOLTIPS: */
9155 case LVM_GETTOPINDEX:
9156 return LISTVIEW_GetTopIndex(hwnd);
9158 /* case LVM_GETUNICODEFORMAT: */
9160 case LVM_GETVIEWRECT:
9161 return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam);
9163 /* case LVM_GETWORKAREAS: */
9166 return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam);
9168 case LVM_INSERTCOLUMNA:
9169 return LISTVIEW_InsertColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
9171 case LVM_INSERTCOLUMNW:
9172 return LISTVIEW_InsertColumnW(hwnd, (INT)wParam, (LPLVCOLUMNW)lParam);
9174 case LVM_INSERTITEMA:
9175 return LISTVIEW_InsertItemA(hwnd, (LPLVITEMA)lParam);
9177 case LVM_INSERTITEMW:
9178 return LISTVIEW_InsertItemW(hwnd, (LPLVITEMW)lParam);
9180 case LVM_REDRAWITEMS:
9181 return LISTVIEW_RedrawItems(hwnd, (INT)wParam, (INT)lParam);
9183 /* case LVM_SCROLL: */
9184 /* return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); */
9186 case LVM_SETBKCOLOR:
9187 return LISTVIEW_SetBkColor(hwnd, (COLORREF)lParam);
9189 /* case LVM_SETBKIMAGE: */
9191 case LVM_SETCALLBACKMASK:
9192 return LISTVIEW_SetCallbackMask(hwnd, (UINT)wParam);
9194 case LVM_SETCOLUMNA:
9195 return LISTVIEW_SetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
9197 case LVM_SETCOLUMNW:
9198 FIXME("Unimplemented msg LVM_SETCOLUMNW\n");
9201 case LVM_SETCOLUMNORDERARRAY:
9202 return LISTVIEW_SetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
9204 case LVM_SETCOLUMNWIDTH:
9205 return LISTVIEW_SetColumnWidth(hwnd, (INT)wParam, SLOWORD(lParam));
9207 case LVM_SETEXTENDEDLISTVIEWSTYLE:
9208 return LISTVIEW_SetExtendedListViewStyle(hwnd, (DWORD)wParam, (DWORD)lParam);
9210 /* case LVM_SETHOTCURSOR: */
9212 case LVM_SETHOTITEM:
9213 return LISTVIEW_SetHotItem(hwnd, (INT)wParam);
9215 case LVM_SETHOVERTIME:
9216 return LISTVIEW_SetHoverTime(hwnd, (DWORD)wParam);
9218 /* case LVM_SETICONSPACING: */
9220 case LVM_SETIMAGELIST:
9221 return LISTVIEW_SetImageList(hwnd, (INT)wParam, (HIMAGELIST)lParam);
9224 return LISTVIEW_SetItemA(hwnd, (LPLVITEMA)lParam);
9226 /* case LVM_SETITEMW: */
9228 case LVM_SETITEMCOUNT:
9229 return LISTVIEW_SetItemCount(hwnd, (INT)wParam, (DWORD)lParam);
9231 case LVM_SETITEMPOSITION:
9232 return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, (INT)LOWORD(lParam),
9233 (INT)HIWORD(lParam));
9235 case LVM_SETITEMPOSITION32:
9236 return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, ((POINT*)lParam)->x,
9237 ((POINT*)lParam)->y);
9239 case LVM_SETITEMSTATE:
9240 return LISTVIEW_SetItemState(hwnd, (INT)wParam, (LPLVITEMA)lParam);
9242 case LVM_SETITEMTEXTA:
9243 return LISTVIEW_SetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
9245 /* case LVM_SETITEMTEXTW: */
9247 case LVM_SETSELECTIONMARK:
9248 return LISTVIEW_SetSelectionMark(hwnd, (INT)lParam);
9250 case LVM_SETTEXTBKCOLOR:
9251 return LISTVIEW_SetTextBkColor(hwnd, (COLORREF)lParam);
9253 case LVM_SETTEXTCOLOR:
9254 return LISTVIEW_SetTextColor(hwnd, (COLORREF)lParam);
9256 /* case LVM_SETTOOLTIPS: */
9257 /* case LVM_SETUNICODEFORMAT: */
9258 /* case LVM_SETWORKAREAS: */
9261 return LISTVIEW_SortItems(hwnd, wParam, lParam);
9263 /* case LVM_SUBITEMHITTEST: */
9266 return LISTVIEW_Update(hwnd, (INT)wParam);
9270 return LISTVIEW_ProcessLetterKeys( hwnd, wParam, lParam );
9273 return LISTVIEW_Command(hwnd, wParam, lParam);
9276 return LISTVIEW_Create(hwnd, wParam, lParam);
9279 return LISTVIEW_EraseBackground(hwnd, wParam, lParam);
9282 return DLGC_WANTCHARS | DLGC_WANTARROWS;
9285 return LISTVIEW_GetFont(hwnd);
9288 return LISTVIEW_HScroll(hwnd, (INT)LOWORD(wParam),
9289 (INT)HIWORD(wParam), (HWND)lParam);
9292 return LISTVIEW_KeyDown(hwnd, (INT)wParam, (LONG)lParam);
9295 return LISTVIEW_KillFocus(hwnd);
9297 case WM_LBUTTONDBLCLK:
9298 return LISTVIEW_LButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
9301 case WM_LBUTTONDOWN:
9302 return LISTVIEW_LButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
9305 return LISTVIEW_LButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
9308 return LISTVIEW_MouseMove (hwnd, wParam, lParam);
9311 return LISTVIEW_MouseHover(hwnd, wParam, lParam);
9314 return LISTVIEW_NCCreate(hwnd, wParam, lParam);
9317 return LISTVIEW_NCDestroy(hwnd);
9320 return LISTVIEW_Notify(hwnd, (INT)wParam, (LPNMHDR)lParam);
9322 case WM_NOTIFYFORMAT:
9323 return LISTVIEW_NotifyFormat(hwnd, (HWND)wParam, (INT)lParam);
9326 return LISTVIEW_Paint(hwnd, (HDC)wParam);
9328 case WM_RBUTTONDBLCLK:
9329 return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
9332 case WM_RBUTTONDOWN:
9333 return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
9337 return LISTVIEW_RButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
9341 return LISTVIEW_SetFocus(hwnd, (HWND)wParam);
9344 return LISTVIEW_SetFont(hwnd, (HFONT)wParam, (WORD)lParam);
9347 return LISTVIEW_SetRedraw(hwnd, (BOOL)wParam);
9350 return LISTVIEW_Size(hwnd, (int)SLOWORD(lParam), (int)SHIWORD(lParam));
9352 case WM_STYLECHANGED:
9353 return LISTVIEW_StyleChanged(hwnd, wParam, (LPSTYLESTRUCT)lParam);
9355 /* case WM_TIMER: */
9358 return LISTVIEW_VScroll(hwnd, (INT)LOWORD(wParam),
9359 (INT)HIWORD(wParam), (HWND)lParam);
9362 if (wParam & (MK_SHIFT | MK_CONTROL))
9363 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
9364 return LISTVIEW_MouseWheel(hwnd, (short int)HIWORD(wParam));/* case WM_WINDOWPOSCHANGED: */
9366 /* case WM_WININICHANGE: */
9369 if (uMsg >= WM_USER)
9371 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam,
9375 /* call default window procedure */
9376 return DefWindowProcA(hwnd, uMsg, wParam, lParam);
9384 * Registers the window class.
9392 VOID LISTVIEW_Register(void)
9396 ZeroMemory(&wndClass, sizeof(WNDCLASSA));
9397 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
9398 wndClass.lpfnWndProc = (WNDPROC)LISTVIEW_WindowProc;
9399 wndClass.cbClsExtra = 0;
9400 wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *);
9401 wndClass.hCursor = LoadCursorA(0, IDC_ARROWA);
9402 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
9403 wndClass.lpszClassName = WC_LISTVIEWA;
9404 RegisterClassA(&wndClass);
9409 * Unregisters the window class.
9417 VOID LISTVIEW_Unregister(void)
9419 UnregisterClassA(WC_LISTVIEWA, (HINSTANCE)NULL);
9424 * Handle any WM_COMMAND messages
9430 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam)
9432 switch (HIWORD(wParam))
9437 * Adjust the edit window size
9440 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
9441 HDC hdc = GetDC(infoPtr->hwndEdit);
9442 HFONT hFont, hOldFont = 0;
9447 len = GetWindowTextA(infoPtr->hwndEdit, buffer, 1023);
9448 GetWindowRect(infoPtr->hwndEdit, &rect);
9450 /* Select font to get the right dimension of the string */
9451 hFont = SendMessageA(infoPtr->hwndEdit, WM_GETFONT, 0, 0);
9454 hOldFont = SelectObject(hdc, hFont);
9457 if (GetTextExtentPoint32A(hdc, buffer, strlen(buffer), &sz))
9459 TEXTMETRICA textMetric;
9461 /* Add Extra spacing for the next character */
9462 GetTextMetricsA(hdc, &textMetric);
9463 sz.cx += (textMetric.tmMaxCharWidth * 2);
9471 rect.bottom - rect.top,
9472 SWP_DRAWFRAME|SWP_NOMOVE);
9476 SelectObject(hdc, hOldFont);
9479 ReleaseDC(hwnd, hdc);
9485 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
9494 * Subclassed edit control windproc function
9500 LRESULT CALLBACK EditLblWndProc(HWND hwnd, UINT uMsg,
9501 WPARAM wParam, LPARAM lParam)
9503 BOOL cancel = FALSE;
9504 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(GetParent(hwnd), 0);
9505 EDITLABEL_ITEM *einfo = infoPtr->pedititem;
9506 static BOOL bIgnoreKillFocus = FALSE;
9510 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
9513 if(bIgnoreKillFocus)
9521 WNDPROC editProc = einfo->EditWndProc;
9522 SetWindowLongA(hwnd, GWL_WNDPROC, (LONG)editProc);
9523 COMCTL32_Free(einfo);
9524 infoPtr->pedititem = NULL;
9525 return CallWindowProcA(editProc, hwnd, uMsg, wParam, lParam);
9529 if (VK_ESCAPE == (INT)wParam)
9535 else if (VK_RETURN == (INT)wParam)
9539 return CallWindowProcA(einfo->EditWndProc, hwnd,
9540 uMsg, wParam, lParam);
9543 if (einfo->EditLblCb)
9545 char *buffer = NULL;
9550 int len = 1 + GetWindowTextLengthA(hwnd);
9554 if (NULL != (buffer = (char *)COMCTL32_Alloc(len*sizeof(char))))
9556 GetWindowTextA(hwnd, buffer, len);
9560 /* Processing LVN_ENDLABELEDIT message could kill the focus */
9561 /* eg. Using a messagebox */
9562 bIgnoreKillFocus = TRUE;
9563 einfo->EditLblCb(GetParent(hwnd), buffer, einfo->param);
9566 COMCTL32_Free(buffer);
9568 einfo->EditLblCb = NULL;
9569 bIgnoreKillFocus = FALSE;
9572 SendMessageA(hwnd, WM_CLOSE, 0, 0);
9579 * Creates a subclassed edit cotrol
9585 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
9586 INT width, INT height, HWND parent, HINSTANCE hinst,
9587 EditlblCallback EditLblCb, DWORD param)
9593 TEXTMETRICA textMetric;
9594 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(parent, 0);
9596 if (NULL == (infoPtr->pedititem = COMCTL32_Alloc(sizeof(EDITLABEL_ITEM))))
9599 style |= WS_CHILDWINDOW|WS_CLIPSIBLINGS|ES_LEFT|WS_BORDER;
9600 hdc = GetDC(parent);
9602 /* Select the font to get appropriate metric dimensions */
9603 if(infoPtr->hFont != 0)
9605 hOldFont = SelectObject(hdc, infoPtr->hFont);
9608 /*Get String Lenght in pixels */
9609 GetTextExtentPoint32A(hdc, text, strlen(text), &sz);
9611 /*Add Extra spacing for the next character */
9612 GetTextMetricsA(hdc, &textMetric);
9613 sz.cx += (textMetric.tmMaxCharWidth * 2);
9615 if(infoPtr->hFont != 0)
9617 SelectObject(hdc, hOldFont);
9620 ReleaseDC(parent, hdc);
9621 if (!(hedit = CreateWindowA("Edit", text, style, x, y, sz.cx, height,
9622 parent, 0, hinst, 0)))
9624 COMCTL32_Free(infoPtr->pedititem);
9628 infoPtr->pedititem->param = param;
9629 infoPtr->pedititem->EditLblCb = EditLblCb;
9630 infoPtr->pedititem->EditWndProc = (WNDPROC)SetWindowLongA(hedit,
9631 GWL_WNDPROC, (LONG) EditLblWndProc);
9633 SendMessageA(hedit, WM_SETFONT, infoPtr->hFont, FALSE);