4 * Copyright 1998, 1999 Eric Kohl
5 * Copyright 1999 Luc Tourangeau
6 * Copyright 2000 Jason Mawdsley
9 * Listview control implementation.
12 * 1. No horizontal scrolling when header is larger than the client area.
13 * 2. Drawing optimizations.
14 * 3. Hot item handling.
17 * LISTVIEW_Notify : most notifications from children (editbox and header)
20 * LISTVIEW_SetItemCount : not completed
23 * LISTVIEW_SetItemW : no unicode support
24 * LISTVIEW_InsertItemW : no unicode support
25 * LISTVIEW_InsertColumnW : no unicode support
26 * LISTVIEW_GetColumnW : no unicode support
27 * LISTVIEW_SetColumnW : no unicode support
29 * Advanced functionality:
30 * LISTVIEW_GetNumberOfWorkAreas : not implemented
31 * LISTVIEW_GetHotCursor : not implemented
32 * LISTVIEW_GetISearchString : not implemented
33 * LISTVIEW_GetBkImage : not implemented
34 * LISTVIEW_GetColumnOrderArray : simple hack only
35 * LISTVIEW_SetColumnOrderArray : simple hack only
36 * LISTVIEW_Arrange : empty stub
37 * LISTVIEW_ApproximateViewRect : incomplete
38 * LISTVIEW_Scroll : not implemented
39 * LISTVIEW_RedrawItems : empty stub
40 * LISTVIEW_Update : not completed
49 #include "debugtools.h"
51 DEFAULT_DEBUG_CHANNEL(listview);
53 /* Some definitions for inline edit control */
54 typedef BOOL (*EditlblCallback)(HWND, LPSTR, DWORD);
56 typedef struct tagEDITLABEL_ITEM
60 EditlblCallback EditLblCb;
63 typedef struct tagLISTVIEW_SUBITEM
71 typedef struct tagLISTVIEW_ITEM
82 typedef struct tagLISTVIEW_SELECTION
88 typedef struct tagLISTVIEW_INFO
93 HIMAGELIST himlNormal;
99 HDPA hdpaSelectionRanges;
114 DWORD dwExStyle; /* extended listview style */
116 PFNLVCOMPARE pfnCompare;
120 EDITLABEL_ITEM *pedititem;
122 INT nColumnCount; /* the number of columns in this control */
124 WPARAM charCode; /* Added */
125 CHAR szSearchParam[ MAX_PATH ]; /* Added */
126 DWORD timeSinceLastKeyPress; /* Added */
127 INT nSearchParamLength; /* Added */
134 /* maximum size of a label */
135 #define DISP_TEXT_SIZE 512
137 /* padding for items in list and small icon display modes */
138 #define WIDTH_PADDING 12
140 /* padding for items in list, report and small icon display modes */
141 #define HEIGHT_PADDING 1
143 /* offset of items in report display mode */
144 #define REPORT_MARGINX 2
146 /* padding for icon in large icon display mode */
147 #define ICON_TOP_PADDING 2
148 #define ICON_BOTTOM_PADDING 2
150 /* padding for label in large icon display mode */
151 #define LABEL_VERT_OFFSET 2
153 /* default label width for items in list and small icon display modes */
154 #define DEFAULT_LABEL_WIDTH 40
156 /* default column width for items in list display mode */
157 #define DEFAULT_COLUMN_WIDTH 96
159 /* Increment size of the horizontal scroll bar */
160 #define LISTVIEW_SCROLL_DIV_SIZE 10
162 /* Padding betwen image and label */
163 #define IMAGE_PADDING 2
165 /* Padding behind the label */
166 #define TRAILING_PADDING 5
168 /* Border for the icon caption */
169 #define CAPTION_BORDER 2
173 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
174 #define ListView_LVNotify(hwnd,lCtrlId,plvnm) \
175 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMLISTVIEW)(plvnm))
176 #define ListView_Notify(hwnd,lCtrlId,pnmh) \
177 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMHDR)(pnmh))
178 /* retrieve the number of items in the listview */
179 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
181 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
182 INT width, INT height, HWND parent, HINSTANCE hinst,
183 EditlblCallback EditLblCb, DWORD param);
186 * forward declarations
188 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem, BOOL internal);
189 static INT LISTVIEW_HitTestItem(HWND, LPLVHITTESTINFO);
190 static INT LISTVIEW_GetCountPerRow(HWND);
191 static INT LISTVIEW_GetCountPerColumn(HWND);
192 static VOID LISTVIEW_AlignLeft(HWND);
193 static VOID LISTVIEW_AlignTop(HWND);
194 static VOID LISTVIEW_AddGroupSelection(HWND, INT);
195 static VOID LISTVIEW_AddSelection(HWND, INT);
196 static BOOL LISTVIEW_AddSubItem(HWND, LPLVITEMA);
197 static INT LISTVIEW_FindInsertPosition(HDPA, INT);
198 static INT LISTVIEW_GetItemHeight(HWND);
199 static BOOL LISTVIEW_GetItemPosition(HWND, INT, LPPOINT);
200 static LRESULT LISTVIEW_GetItemRect(HWND, INT, LPRECT);
201 static INT LISTVIEW_GetItemWidth(HWND);
202 static INT LISTVIEW_GetLabelWidth(HWND, INT);
203 static LRESULT LISTVIEW_GetOrigin(HWND, LPPOINT);
204 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem);
205 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA, INT);
206 static LRESULT LISTVIEW_GetViewRect(HWND, LPRECT);
207 static BOOL LISTVIEW_InitItem(HWND, LISTVIEW_ITEM *, LPLVITEMA);
208 static BOOL LISTVIEW_InitSubItem(HWND, LISTVIEW_SUBITEM *, LPLVITEMA);
209 static LRESULT LISTVIEW_MouseSelection(HWND, POINT);
210 static BOOL LISTVIEW_RemoveColumn(HDPA, INT);
211 static BOOL LISTVIEW_RemoveSubItem(HDPA, INT);
212 static VOID LISTVIEW_SetGroupSelection(HWND, INT);
213 static BOOL LISTVIEW_SetItem(HWND, LPLVITEMA);
214 static BOOL LISTVIEW_SetItemFocus(HWND, INT);
215 static BOOL LISTVIEW_SetItemPosition(HWND, INT, INT, INT);
216 static VOID LISTVIEW_UpdateScroll(HWND);
217 static VOID LISTVIEW_SetSelection(HWND, INT);
218 static VOID LISTVIEW_UpdateSize(HWND);
219 static BOOL LISTVIEW_SetSubItem(HWND, LPLVITEMA);
220 static LRESULT LISTVIEW_SetViewRect(HWND, LPRECT);
221 static BOOL LISTVIEW_ToggleSelection(HWND, INT);
222 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle);
223 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem);
224 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem);
225 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam);
226 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam);
227 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText);
228 static INT LISTVIEW_ProcessLetterKeys( HWND hwnd, WPARAM charCode, LPARAM keyData );
229 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem);
230 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask);
231 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem);
232 static BOOL LISTVIEW_IsSelected(HWND hwnd, INT nItem);
233 static VOID LISTVIEW_RemoveSelectionRange(HWND hwnd, INT lItem, INT uItem);
235 /******** Defines that LISTVIEW_ProcessLetterKeys uses ****************/
236 #define KEY_DELAY 900
237 #define LISTVIEW_InitLvItemStruct(item,idx,TEXT) \
238 ZeroMemory(&(item), sizeof(LVITEMA)); \
239 (item).mask = LVIF_TEXT; \
240 (item).iItem = (idx); \
241 (item).iSubItem = 0; \
242 (item).pszText = (TEXT); \
243 (item).cchTextMax = MAX_PATH
246 LISTVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
249 LISTVIEW_INFO *infoPtr;
250 NMLVCUSTOMDRAW nmcdhdr;
253 TRACE("drawstage:%lx hdc:%x\n", dwDrawStage, hdc);
255 infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
257 nmcd= & nmcdhdr.nmcd;
258 nmcd->hdr.hwndFrom = hwnd;
259 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
260 nmcd->hdr.code = NM_CUSTOMDRAW;
261 nmcd->dwDrawStage= dwDrawStage;
263 nmcd->rc.left = rc.left;
264 nmcd->rc.right = rc.right;
265 nmcd->rc.bottom = rc.bottom;
266 nmcd->rc.top = rc.top;
267 nmcd->dwItemSpec = 0;
268 nmcd->uItemState = 0;
269 nmcd->lItemlParam= 0;
270 nmcdhdr.clrText = infoPtr->clrText;
271 nmcdhdr.clrTextBk= infoPtr->clrBk;
273 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
274 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
278 LISTVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
279 UINT iItem, UINT iSubItem,
282 LISTVIEW_INFO *infoPtr;
283 NMLVCUSTOMDRAW nmcdhdr;
285 DWORD dwDrawStage,dwItemSpec;
291 infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
293 ZeroMemory(&item,sizeof(LVITEMA));
295 item.mask = LVIF_PARAM;
296 ListView_GetItemA(hwnd,&item);
298 dwDrawStage=CDDS_ITEM | uItemDrawState;
302 if (LISTVIEW_IsSelected(hwnd,iItem)) uItemState|=CDIS_SELECTED;
303 if (iItem==infoPtr->nFocusedItem) uItemState|=CDIS_FOCUS;
304 if (iItem==infoPtr->nHotItem) uItemState|=CDIS_HOT;
306 itemRect.left = LVIR_BOUNDS;
307 LISTVIEW_GetItemRect(hwnd, iItem, &itemRect);
309 nmcd= & nmcdhdr.nmcd;
310 nmcd->hdr.hwndFrom = hwnd;
311 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
312 nmcd->hdr.code = NM_CUSTOMDRAW;
313 nmcd->dwDrawStage= dwDrawStage;
315 nmcd->rc.left = itemRect.left;
316 nmcd->rc.right = itemRect.right;
317 nmcd->rc.bottom = itemRect.bottom;
318 nmcd->rc.top = itemRect.top;
319 nmcd->dwItemSpec = dwItemSpec;
320 nmcd->uItemState = uItemState;
321 nmcd->lItemlParam= item.lParam;
322 nmcdhdr.clrText = infoPtr->clrText;
323 nmcdhdr.clrTextBk= infoPtr->clrBk;
324 nmcdhdr.iSubItem =iSubItem;
326 TRACE("drawstage:%lx hdc:%x item:%lx, itemstate:%x, lItemlParam:%lx\n",
327 nmcd->dwDrawStage, nmcd->hdc, nmcd->dwItemSpec,
328 nmcd->uItemState, nmcd->lItemlParam);
330 retval=SendMessageA (GetParent (hwnd), WM_NOTIFY,
331 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
333 infoPtr->clrText=nmcdhdr.clrText;
334 infoPtr->clrBk =nmcdhdr.clrTextBk;
335 return (BOOL) retval;
339 /*************************************************************************
341 * Processes keyboard messages generated by pressing the letter keys on the keyboard.
342 * Assumes the list is sorted alphabetically, without regard to case.
345 * [I] HWND: handle to the window
346 * [I] WPARAM: the character code, the actual character
347 * [I] LPARAM: key data
357 static INT LISTVIEW_ProcessLetterKeys( HWND hwnd, WPARAM charCode, LPARAM keyData )
359 LISTVIEW_INFO *infoPtr = NULL;
364 BOOL bFoundMatchingFiles = FALSE;
366 CHAR TEXT[ MAX_PATH ];
367 CHAR szCharCode[ 2 ];
368 DWORD timeSinceLastKeyPress = 0;
370 szCharCode[0] = charCode;
373 /* simple parameter checking */
374 if ( !hwnd || !charCode || !keyData )
377 infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
382 /* only allow the valid WM_CHARs through */
383 if ( isalnum( charCode ) || charCode == '.' || charCode == '`' || charCode == '!'
384 || charCode == '@' || charCode == '#' || charCode == '$' || charCode == '%'
385 || charCode == '^' || charCode == '&' || charCode == '*' || charCode == '('
386 || charCode == ')' || charCode == '-' || charCode == '_' || charCode == '+'
387 || charCode == '=' || charCode == '\\'|| charCode == ']' || charCode == '}'
388 || charCode == '[' || charCode == '{' || charCode == '/' || charCode == '?'
389 || charCode == '>' || charCode == '<' || charCode == ',' || charCode == '~')
391 timeSinceLastKeyPress = GetTickCount();
393 nSize = GETITEMCOUNT( infoPtr );
394 /* if there are 0 items, there is no where to go */
398 * If the last charCode equals the current charCode then look
399 * to the next element in list to see if it matches the previous
402 if ( infoPtr->charCode == charCode )
404 if ( timeSinceLastKeyPress - infoPtr->timeSinceLastKeyPress < KEY_DELAY )
405 { /* append new character to search string */
406 strcat( infoPtr->szSearchParam, szCharCode );
407 infoPtr->nSearchParamLength++;
409 /* loop from start of list view */
410 for( idx = infoPtr->nFocusedItem; idx < nSize; idx++ )
412 LISTVIEW_InitLvItemStruct( item, idx, TEXT );
413 ListView_GetItemA( hwnd, &item );
416 if ( strncasecmp( item.pszText, infoPtr->szSearchParam,
417 infoPtr->nSearchParamLength ) == 0 )
424 else if ( infoPtr->timeSinceLastKeyPress > timeSinceLastKeyPress )
425 { /* The DWORD went over it's boundery?? Ergo assuming too slow??. */
426 for ( idx = 0; idx < nSize; idx++ )
428 LISTVIEW_InitLvItemStruct( item, idx, TEXT );
429 ListView_GetItemA( hwnd, &item );
431 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
437 strcpy( infoPtr->szSearchParam, szCharCode );
438 infoPtr->nSearchParamLength = 1;
441 { /* Save szCharCode for use in later searches */
442 strcpy( infoPtr->szSearchParam, szCharCode );
443 infoPtr->nSearchParamLength = 1;
445 LISTVIEW_InitLvItemStruct( item, infoPtr->nFocusedItem + 1, TEXT );
446 ListView_GetItemA( hwnd, &item );
448 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
449 nItem = infoPtr->nFocusedItem + 1;
452 * Ok so there are no more folders that match
453 * now we look for files.
455 for ( idx = infoPtr->nFocusedItem + 1; idx < nSize; idx ++ )
457 LISTVIEW_InitLvItemStruct( item, idx, TEXT );
458 ListView_GetItemA( hwnd, &item );
460 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
463 bFoundMatchingFiles = TRUE;
467 if ( !bFoundMatchingFiles )
468 { /* go back to first instance */
469 for ( idx = 0; idx < nSize; idx ++ )
471 LISTVIEW_InitLvItemStruct( item,idx, TEXT );
472 ListView_GetItemA( hwnd, &item );
474 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
483 } /*END: if ( infoPtr->charCode == charCode )*/
485 else /* different keypressed */
487 /* could be that they are spelling the file/directory for us */
488 if ( timeSinceLastKeyPress - infoPtr->timeSinceLastKeyPress > KEY_DELAY )
490 * Too slow, move to the first instance of the
493 for ( idx = 0; idx < nSize; idx++ )
495 LISTVIEW_InitLvItemStruct( item,idx, TEXT );
496 ListView_GetItemA( hwnd, &item );
498 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
504 strcpy( infoPtr->szSearchParam, szCharCode );
505 infoPtr->nSearchParamLength = 1;
507 else if ( infoPtr->timeSinceLastKeyPress > timeSinceLastKeyPress )
508 { /* The DWORD went over it's boundery?? Ergo assuming too slow??. */
509 for ( idx = 0; idx < nSize; idx++ )
511 LISTVIEW_InitLvItemStruct( item,idx, TEXT );
512 ListView_GetItemA( hwnd, &item );
514 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
520 strcpy( infoPtr->szSearchParam, szCharCode );
521 infoPtr->nSearchParamLength = 1;
523 else /* Search for the string the user is typing */
525 /* append new character to search string */
526 strcat( infoPtr->szSearchParam, szCharCode );
527 infoPtr->nSearchParamLength++;
529 /* loop from start of list view */
530 for( idx = 0; idx < nSize; idx++ )
532 LISTVIEW_InitLvItemStruct( item, idx, TEXT );
533 ListView_GetItemA( hwnd, &item );
536 if ( strncasecmp( item.pszText, infoPtr->szSearchParam,
537 infoPtr->nSearchParamLength ) == 0 )
549 bRedraw = LISTVIEW_KeySelection(hwnd, nItem );
550 if (bRedraw != FALSE)
552 /* refresh client area */
553 InvalidateRect(hwnd, NULL, TRUE);
557 /* Store the WM_CHAR for next time */
558 infoPtr->charCode = charCode;
561 infoPtr->timeSinceLastKeyPress = timeSinceLastKeyPress;
567 /*************************************************************************
568 * LISTVIEW_UpdateHeaderSize [Internal]
570 * Function to resize the header control
573 * hwnd [I] handle to a window
574 * nNewScrollPos [I] Scroll Pos to Set
581 static VOID LISTVIEW_UpdateHeaderSize(HWND hwnd, INT nNewScrollPos)
583 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
587 GetWindowRect(infoPtr->hwndHeader, &winRect);
588 point[0].x = winRect.left;
589 point[0].y = winRect.top;
590 point[1].x = winRect.right;
591 point[1].y = winRect.bottom;
593 MapWindowPoints(HWND_DESKTOP, hwnd, point, 2);
594 point[0].x = -(nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
595 point[1].x += (nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
597 SetWindowPos(infoPtr->hwndHeader,0,
598 point[0].x,point[0].y,point[1].x,point[1].y,
599 SWP_NOZORDER | SWP_NOACTIVATE);
604 * Update the scrollbars. This functions should be called whenever
605 * the content, size or view changes.
608 * [I] HWND : window handle
613 static VOID LISTVIEW_UpdateScroll(HWND hwnd)
615 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
616 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
617 UINT uView = lStyle & LVS_TYPEMASK;
618 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
619 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
620 SCROLLINFO scrollInfo;
622 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
623 scrollInfo.cbSize = sizeof(SCROLLINFO);
625 if (uView == LVS_LIST)
627 /* update horizontal scrollbar */
629 INT nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
630 INT nCountPerRow = LISTVIEW_GetCountPerRow(hwnd);
631 INT nNumOfItems = GETITEMCOUNT(infoPtr);
633 scrollInfo.nMax = nNumOfItems / nCountPerColumn;
634 if((nNumOfItems % nCountPerColumn) == 0)
638 scrollInfo.nPos = ListView_GetTopIndex(hwnd) / nCountPerColumn;
639 scrollInfo.nPage = nCountPerRow;
640 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
641 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
642 ShowScrollBar(hwnd, SB_VERT, FALSE);
644 else if (uView == LVS_REPORT)
646 /* update vertical scrollbar */
648 scrollInfo.nMax = GETITEMCOUNT(infoPtr) - 1;
649 scrollInfo.nPos = ListView_GetTopIndex(hwnd);
650 scrollInfo.nPage = LISTVIEW_GetCountPerColumn(hwnd);
651 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
652 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
654 /* update horizontal scrollbar */
655 nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
656 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE
657 || GETITEMCOUNT(infoPtr) == 0)
662 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE ;
663 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
664 scrollInfo.nMax = max(infoPtr->nItemWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
665 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
667 /* Update the Header Control */
668 scrollInfo.fMask = SIF_POS;
669 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
670 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
677 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
679 INT nViewWidth = rcView.right - rcView.left;
680 INT nViewHeight = rcView.bottom - rcView.top;
682 /* Update Horizontal Scrollbar */
683 scrollInfo.fMask = SIF_POS;
684 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE
685 || GETITEMCOUNT(infoPtr) == 0)
689 scrollInfo.nMax = max(nViewWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
691 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
692 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
693 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
695 /* Update Vertical Scrollbar */
696 nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
697 scrollInfo.fMask = SIF_POS;
698 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) == FALSE
699 || GETITEMCOUNT(infoPtr) == 0)
703 scrollInfo.nMax = max(nViewHeight / LISTVIEW_SCROLL_DIV_SIZE,0)-1;
705 scrollInfo.nPage = nListHeight / LISTVIEW_SCROLL_DIV_SIZE;
706 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
707 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
714 * Prints a message for unsupported window styles.
715 * A kind of TODO list for window styles.
718 * [I] LONG : window style
723 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle)
725 if ((LVS_TYPEMASK & lStyle) == LVS_EDITLABELS)
727 FIXME(" LVS_EDITLABELS\n");
730 if ((LVS_TYPEMASK & lStyle) == LVS_NOLABELWRAP)
732 FIXME(" LVS_NOLABELWRAP\n");
735 if ((LVS_TYPEMASK & lStyle) == LVS_NOSCROLL)
737 FIXME(" LVS_NOSCROLL\n");
740 if ((LVS_TYPEMASK & lStyle) == LVS_NOSORTHEADER)
742 FIXME(" LVS_NOSORTHEADER\n");
745 if ((LVS_TYPEMASK & lStyle) == LVS_OWNERDRAWFIXED)
747 FIXME(" LVS_OWNERDRAWFIXED\n");
750 if ((LVS_TYPEMASK & lStyle) == LVS_SHAREIMAGELISTS)
752 FIXME(" LVS_SHAREIMAGELISTS\n");
755 if ((LVS_TYPEMASK & lStyle) == LVS_SORTASCENDING)
757 FIXME(" LVS_SORTASCENDING\n");
760 if ((LVS_TYPEMASK & lStyle) == LVS_SORTDESCENDING)
762 FIXME(" LVS_SORTDESCENDING\n");
768 * Aligns the items with the top edge of the window.
771 * [I] HWND : window handle
776 static VOID LISTVIEW_AlignTop(HWND hwnd)
778 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
779 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
780 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
785 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
787 ZeroMemory(&ptItem, sizeof(POINT));
788 ZeroMemory(&rcView, sizeof(RECT));
790 if (nListWidth > infoPtr->nItemWidth)
792 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
794 if (ptItem.x + infoPtr->nItemWidth > nListWidth)
797 ptItem.y += infoPtr->nItemHeight;
800 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
801 ptItem.x += infoPtr->nItemWidth;
802 rcView.right = max(rcView.right, ptItem.x);
805 rcView.bottom = ptItem.y + infoPtr->nItemHeight;
809 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
811 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
812 ptItem.y += infoPtr->nItemHeight;
815 rcView.right = infoPtr->nItemWidth;
816 rcView.bottom = ptItem.y;
819 LISTVIEW_SetViewRect(hwnd, &rcView);
825 * Aligns the items with the left edge of the window.
828 * [I] HWND : window handle
833 static VOID LISTVIEW_AlignLeft(HWND hwnd)
835 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
836 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
837 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
842 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
844 ZeroMemory(&ptItem, sizeof(POINT));
845 ZeroMemory(&rcView, sizeof(RECT));
847 if (nListHeight > infoPtr->nItemHeight)
849 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
851 if (ptItem.y + infoPtr->nItemHeight > nListHeight)
854 ptItem.x += infoPtr->nItemWidth;
857 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
858 ptItem.y += infoPtr->nItemHeight;
859 rcView.bottom = max(rcView.bottom, ptItem.y);
862 rcView.right = ptItem.x + infoPtr->nItemWidth;
866 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
868 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
869 ptItem.x += infoPtr->nItemWidth;
872 rcView.bottom = infoPtr->nItemHeight;
873 rcView.right = ptItem.x;
876 LISTVIEW_SetViewRect(hwnd, &rcView);
882 * Set the bounding rectangle of all the items.
885 * [I] HWND : window handle
886 * [I] LPRECT : bounding rectangle
892 static LRESULT LISTVIEW_SetViewRect(HWND hwnd, LPRECT lprcView)
894 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
895 BOOL bResult = FALSE;
897 TRACE("(hwnd=%x, left=%d, top=%d, right=%d, bottom=%d)\n", hwnd,
898 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
900 if (lprcView != NULL)
903 infoPtr->rcView.left = lprcView->left;
904 infoPtr->rcView.top = lprcView->top;
905 infoPtr->rcView.right = lprcView->right;
906 infoPtr->rcView.bottom = lprcView->bottom;
914 * Retrieves the bounding rectangle of all the items.
917 * [I] HWND : window handle
918 * [O] LPRECT : bounding rectangle
924 static LRESULT LISTVIEW_GetViewRect(HWND hwnd, LPRECT lprcView)
926 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
927 BOOL bResult = FALSE;
930 TRACE("(hwnd=%x, lprcView=%p)\n", hwnd, lprcView);
932 if (lprcView != NULL)
934 bResult = LISTVIEW_GetOrigin(hwnd, &ptOrigin);
935 if (bResult != FALSE)
937 lprcView->left = infoPtr->rcView.left + ptOrigin.x;
938 lprcView->top = infoPtr->rcView.top + ptOrigin.y;
939 lprcView->right = infoPtr->rcView.right + ptOrigin.x;
940 lprcView->bottom = infoPtr->rcView.bottom + ptOrigin.y;
943 TRACE("(left=%d, top=%d, right=%d, bottom=%d)\n",
944 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
952 * Retrieves the subitem pointer associated with the subitem index.
955 * [I] HDPA : DPA handle for a specific item
956 * [I] INT : index of subitem
959 * SUCCESS : subitem pointer
962 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems,
965 LISTVIEW_SUBITEM *lpSubItem;
968 for (i = 1; i < hdpaSubItems->nItemCount; i++)
970 lpSubItem = (LISTVIEW_SUBITEM *) DPA_GetPtr(hdpaSubItems, i);
971 if (lpSubItem != NULL)
973 if (lpSubItem->iSubItem == nSubItem)
985 * Calculates the width of an item.
988 * [I] HWND : window handle
989 * [I] LONG : window style
992 * Returns item width.
994 static INT LISTVIEW_GetItemWidth(HWND hwnd)
996 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
997 LONG style = GetWindowLongA(hwnd, GWL_STYLE);
998 UINT uView = style & LVS_TYPEMASK;
999 INT nHeaderItemCount;
1005 TRACE("(hwnd=%x)\n", hwnd);
1007 if (uView == LVS_ICON)
1009 nItemWidth = infoPtr->iconSpacing.cx;
1011 else if (uView == LVS_REPORT && (!(LVS_NOCOLUMNHEADER & style)) )
1013 /* calculate width of header */
1014 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
1015 for (i = 0; i < nHeaderItemCount; i++)
1017 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
1019 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
1025 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
1027 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, i);
1028 nItemWidth = max(nItemWidth, nLabelWidth);
1031 /* default label size */
1032 if (GETITEMCOUNT(infoPtr) == 0)
1034 nItemWidth = DEFAULT_COLUMN_WIDTH;
1038 if (nItemWidth == 0)
1040 nItemWidth = DEFAULT_LABEL_WIDTH;
1045 nItemWidth += WIDTH_PADDING;
1047 if (infoPtr->himlSmall != NULL)
1049 nItemWidth += infoPtr->iconSize.cx;
1052 if (infoPtr->himlState != NULL)
1054 nItemWidth += infoPtr->iconSize.cx;
1061 /* nItemWidth Cannot be Zero */
1069 * Calculates the width of a specific item.
1072 * [I] HWND : window handle
1073 * [I] LPSTR : string
1076 * Returns the width of an item width a specified string.
1078 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem)
1080 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1081 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
1082 INT nHeaderItemCount;
1087 TRACE("(hwnd=%x)\n", hwnd);
1089 if (uView == LVS_ICON)
1091 nItemWidth = infoPtr->iconSpacing.cx;
1093 else if (uView == LVS_REPORT)
1095 /* calculate width of header */
1096 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
1097 for (i = 0; i < nHeaderItemCount; i++)
1099 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
1101 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
1107 /* get width of string */
1108 nItemWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
1110 /* default label size */
1111 if (GETITEMCOUNT(infoPtr) == 0)
1113 nItemWidth = DEFAULT_COLUMN_WIDTH;
1117 if (nItemWidth == 0)
1119 nItemWidth = DEFAULT_LABEL_WIDTH;
1124 nItemWidth += WIDTH_PADDING;
1126 if (infoPtr->himlSmall != NULL)
1128 nItemWidth += infoPtr->iconSize.cx;
1131 if (infoPtr->himlState != NULL)
1133 nItemWidth += infoPtr->iconSize.cx;
1144 * Calculates the height of an item.
1147 * [I] HWND : window handle
1148 * [I] LONG : window style
1151 * Returns item height.
1153 static INT LISTVIEW_GetItemHeight(HWND hwnd)
1155 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1156 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
1157 INT nItemHeight = 0;
1159 if (uView == LVS_ICON)
1161 nItemHeight = infoPtr->iconSpacing.cy;
1166 HDC hdc = GetDC(hwnd);
1167 HFONT hOldFont = SelectObject(hdc, infoPtr->hFont);
1168 GetTextMetricsA(hdc, &tm);
1170 if(infoPtr->himlState || infoPtr->himlSmall)
1171 nItemHeight = max(tm.tmHeight, infoPtr->iconSize.cy) + HEIGHT_PADDING;
1173 nItemHeight = tm.tmHeight;
1175 SelectObject(hdc, hOldFont);
1176 ReleaseDC(hwnd, hdc);
1183 static void LISTVIEW_PrintSelectionRanges(hwnd)
1185 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1186 LISTVIEW_SELECTION *selection;
1187 INT topSelection = infoPtr->hdpaSelectionRanges->nItemCount;
1190 TRACE("Selections are:\n");
1191 for (i = 0; i < topSelection; i++)
1193 selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,i);
1194 TRACE(" %lu - %lu\n",selection->lower,selection->upper);
1200 * A compare function for selection ranges
1203 * [I] LPVOID : Item 1;
1204 * [I] LPVOID : Item 2;
1205 * [I] LPARAM : flags
1208 * >0 : if Item 1 > Item 2
1209 * <0 : if Item 2 > Item 1
1210 * 0 : if Item 1 == Item 2
1212 static INT CALLBACK LISTVIEW_CompareSelectionRanges(LPVOID range1, LPVOID range2,
1215 int l1 = ((LISTVIEW_SELECTION*)(range1))->lower;
1216 int l2 = ((LISTVIEW_SELECTION*)(range2))->lower;
1217 int u1 = ((LISTVIEW_SELECTION*)(range1))->upper;
1218 int u2 = ((LISTVIEW_SELECTION*)(range2))->upper;
1232 * Adds a selection range.
1235 * [I] HWND : window handle
1236 * [I] INT : lower item index
1237 * [I] INT : upper item index
1242 static VOID LISTVIEW_AddSelectionRange(HWND hwnd, INT lItem, INT uItem)
1244 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1245 LISTVIEW_SELECTION *selection;
1246 INT topSelection = infoPtr->hdpaSelectionRanges->nItemCount;
1247 BOOL lowerzero=FALSE;
1249 selection = (LISTVIEW_SELECTION *)COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION));
1250 selection->lower = lItem;
1251 selection->upper = uItem;
1253 TRACE("Add range %i - %i\n",lItem,uItem);
1256 LISTVIEW_SELECTION *checkselection,*checkselection2;
1257 INT index,mergeindex;
1259 /* find overlapping selections */
1260 /* we want to catch adjacent ranges so expand our range by 1 */
1263 if (selection->lower == 0)
1268 index = DPA_Search(infoPtr->hdpaSelectionRanges, selection, 0,
1269 LISTVIEW_CompareSelectionRanges,
1271 selection->upper --;
1275 selection->lower ++;
1279 checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,index);
1280 TRACE("Merge with index %i (%lu - %lu)\n",index,checkselection->lower,
1281 checkselection->upper);
1283 checkselection->lower = min(selection->lower,checkselection->lower);
1284 checkselection->upper = max(selection->upper,checkselection->upper);
1286 TRACE("New range (%lu - %lu)\n", checkselection->lower,
1287 checkselection->upper);
1289 COMCTL32_Free(selection);
1291 /* merge now common selection ranges in the lower group*/
1294 checkselection->upper ++;
1295 if (checkselection->lower == 0)
1298 checkselection->lower --;
1300 TRACE("search lower range (%lu - %lu)\n", checkselection->lower,
1301 checkselection->upper);
1303 /* not sorted yet */
1304 mergeindex = DPA_Search(infoPtr->hdpaSelectionRanges, checkselection, 0,
1305 LISTVIEW_CompareSelectionRanges, 0,
1308 checkselection->upper --;
1312 checkselection->lower ++;
1314 if (mergeindex >=0 && mergeindex != index)
1316 TRACE("Merge with index %i\n",mergeindex);
1317 checkselection2 = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
1319 checkselection->lower = min(checkselection->lower,
1320 checkselection2->lower);
1321 checkselection->upper = max(checkselection->upper,
1322 checkselection2->upper);
1323 COMCTL32_Free(checkselection2);
1324 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,mergeindex);
1328 while (mergeindex > -1 && mergeindex <index);
1330 /* merge now common selection ranges in the upper group*/
1333 checkselection->upper ++;
1334 if (checkselection->lower == 0)
1337 checkselection->lower --;
1339 TRACE("search upper range %i (%lu - %lu)\n",index,
1340 checkselection->lower, checkselection->upper);
1342 /* not sorted yet */
1343 mergeindex = DPA_Search(infoPtr->hdpaSelectionRanges, checkselection,
1345 LISTVIEW_CompareSelectionRanges, 0,
1348 checkselection->upper --;
1352 checkselection->lower ++;
1354 if (mergeindex >=0 && mergeindex !=index)
1356 TRACE("Merge with index %i\n",mergeindex);
1357 checkselection2 = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
1359 checkselection->lower = min(checkselection->lower,
1360 checkselection2->lower);
1361 checkselection->upper = max(checkselection->upper,
1362 checkselection2->upper);
1363 COMCTL32_Free(checkselection2);
1364 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,mergeindex);
1367 while (mergeindex > -1);
1372 index = DPA_Search(infoPtr->hdpaSelectionRanges, selection, 0,
1373 LISTVIEW_CompareSelectionRanges, 0,
1376 TRACE("Insert before index %i\n",index);
1379 DPA_InsertPtr(infoPtr->hdpaSelectionRanges,index,selection);
1384 DPA_InsertPtr(infoPtr->hdpaSelectionRanges,0,selection);
1389 DPA_Sort(infoPtr->hdpaSelectionRanges,LISTVIEW_CompareSelectionRanges,0);
1390 LISTVIEW_PrintSelectionRanges(hwnd);
1395 * check if a specified index is selected.
1398 * [I] HWND : window handle
1399 * [I] INT : item index
1404 static BOOL LISTVIEW_IsSelected(HWND hwnd, INT nItem)
1406 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1407 LISTVIEW_SELECTION selection;
1410 selection.upper = nItem;
1411 selection.lower = nItem;
1413 index = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, 0,
1414 LISTVIEW_CompareSelectionRanges,
1424 * Removes all selection ranges
1427 * HWND: window handle
1433 static LRESULT LISTVIEW_RemoveAllSelections(HWND hwnd)
1435 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1436 LISTVIEW_SELECTION *selection;
1440 TRACE("(0x%x)\n",hwnd);
1442 ZeroMemory(&item,sizeof(LVITEMA));
1443 item.stateMask = LVIS_SELECTED;
1447 selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,0);
1450 TRACE("Removing %lu to %lu\n",selection->lower, selection->upper);
1451 for (i = selection->lower; i<=selection->upper; i++)
1452 LISTVIEW_SetItemState(hwnd,i,&item);
1453 LISTVIEW_RemoveSelectionRange(hwnd,selection->lower,selection->upper);
1456 while (infoPtr->hdpaSelectionRanges->nItemCount>0);
1464 * Removes a range selections.
1467 * [I] HWND : window handle
1468 * [I] INT : lower item index
1469 * [I] INT : upper item index
1474 static VOID LISTVIEW_RemoveSelectionRange(HWND hwnd, INT lItem, INT uItem)
1476 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1477 LISTVIEW_SELECTION removeselection,*checkselection;
1480 removeselection.lower = lItem;
1481 removeselection.upper = uItem;
1483 TRACE("Remove range %lu - %lu\n",removeselection.lower,removeselection.upper);
1484 LISTVIEW_PrintSelectionRanges(hwnd);
1486 index = DPA_Search(infoPtr->hdpaSelectionRanges, &removeselection, 0,
1487 LISTVIEW_CompareSelectionRanges,
1494 checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
1497 TRACE("Matches range index %i (%lu-%lu)\n",index,checkselection->lower,
1498 checkselection->upper);
1501 if ((checkselection->upper == removeselection.upper) &&
1502 (checkselection->lower == removeselection.lower))
1504 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,index);
1507 /* case 2: engulf */
1508 else if (((checkselection->upper < removeselection.upper) &&
1509 (checkselection->lower > removeselection.lower))||
1510 ((checkselection->upper <= removeselection.upper) &&
1511 (checkselection->lower > removeselection.lower)) ||
1512 ((checkselection->upper < removeselection.upper) &&
1513 (checkselection->lower >= removeselection.lower)))
1516 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,index);
1517 /* do it again because others may also get caught */
1519 LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
1521 /* case 3: overlap upper */
1522 else if ((checkselection->upper < removeselection.upper) &&
1523 (checkselection->lower < removeselection.lower))
1525 checkselection->upper = removeselection.lower - 1;
1527 LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
1529 /* case 4: overlap lower */
1530 else if ((checkselection->upper > removeselection.upper) &&
1531 (checkselection->lower > removeselection.lower))
1533 checkselection->lower = removeselection.upper + 1;
1535 LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
1537 /* case 5: fully internal */
1538 else if (checkselection->upper == removeselection.upper)
1539 checkselection->upper = removeselection.lower - 1;
1540 else if (checkselection->lower == removeselection.lower)
1541 checkselection->lower = removeselection.upper + 1;
1544 /* bisect the range */
1545 LISTVIEW_SELECTION *newselection;
1547 newselection = (LISTVIEW_SELECTION *)
1548 COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION));
1549 newselection -> lower = checkselection->lower;
1550 newselection -> upper = removeselection.lower - 1;
1551 checkselection -> lower = removeselection.upper + 1;
1552 DPA_InsertPtr(infoPtr->hdpaSelectionRanges,index,newselection);
1554 DPA_Sort(infoPtr->hdpaSelectionRanges,LISTVIEW_CompareSelectionRanges,0);
1556 LISTVIEW_PrintSelectionRanges(hwnd);
1561 * shifts all selection indexs starting with the indesx specified
1562 * in the direction specified.
1565 * [I] HWND : window handle
1566 * [I] INT : item index
1567 * [I] INT : amount and direction of shift
1572 static VOID LISTVIEW_ShiftSelections(HWND hwnd, INT nItem, INT direction)
1574 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1575 LISTVIEW_SELECTION selection,*checkselection;
1578 TRACE("Shifting %iu, %i steps\n",nItem,direction);
1580 selection.upper = nItem;
1581 selection.lower = nItem;
1583 index = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, 0,
1584 LISTVIEW_CompareSelectionRanges,
1585 0,DPAS_SORTED|DPAS_INSERTAFTER);
1587 while ((index < infoPtr->hdpaSelectionRanges->nItemCount)&&(index != -1))
1589 checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,index);
1590 if ((checkselection->lower >= nItem)&&
1591 (checkselection->lower + direction >= 0))
1592 checkselection->lower += direction;
1593 if ((checkselection->upper >= nItem)&&
1594 (checkselection->upper + direction >=0))
1595 checkselection->upper += direction;
1603 * Adds a block of selections.
1606 * [I] HWND : window handle
1607 * [I] INT : item index
1612 static VOID LISTVIEW_AddGroupSelection(HWND hwnd, INT nItem)
1614 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1615 INT nFirst = min(infoPtr->nSelectionMark, nItem);
1616 INT nLast = max(infoPtr->nSelectionMark, nItem);
1620 ZeroMemory(&item,sizeof(LVITEMA));
1621 item.stateMask = LVIS_SELECTED;
1622 item.state = LVIS_SELECTED;
1624 for (i = nFirst; i <= nLast; i++);
1626 LISTVIEW_SetItemState(hwnd,i,&item);
1629 LISTVIEW_SetItemFocus(hwnd, nItem);
1630 infoPtr->nSelectionMark = nItem;
1636 * Adds a single selection.
1639 * [I] HWND : window handle
1640 * [I] INT : item index
1645 static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem)
1647 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1650 ZeroMemory(&item,sizeof(LVITEMA));
1651 item.state = LVIS_SELECTED;
1652 item.stateMask = LVIS_SELECTED;
1654 LISTVIEW_SetItemState(hwnd,nItem,&item);
1656 LISTVIEW_SetItemFocus(hwnd, nItem);
1657 infoPtr->nSelectionMark = nItem;
1662 * Selects or unselects an item.
1665 * [I] HWND : window handle
1666 * [I] INT : item index
1672 static BOOL LISTVIEW_ToggleSelection(HWND hwnd, INT nItem)
1674 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1678 ZeroMemory(&item,sizeof(LVITEMA));
1679 item.stateMask = LVIS_SELECTED;
1681 if (LISTVIEW_IsSelected(hwnd,nItem))
1684 LISTVIEW_SetItemState(hwnd,nItem,&item);
1689 item.state = LVIS_SELECTED;
1690 LISTVIEW_SetItemState(hwnd,nItem,&item);
1694 LISTVIEW_SetItemFocus(hwnd, nItem);
1695 infoPtr->nSelectionMark = nItem;
1702 * Selects items based on view coordinates.
1705 * [I] HWND : window handle
1706 * [I] RECT : selection rectangle
1711 static VOID LISTVIEW_SetSelectionRect(HWND hwnd, RECT rcSelRect)
1713 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1718 ZeroMemory(&item,sizeof(LVITEMA));
1719 item.stateMask = LVIS_SELECTED;
1721 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
1723 LISTVIEW_GetItemPosition(hwnd, i, &ptItem);
1725 if (PtInRect(&rcSelRect, ptItem) != FALSE)
1727 item.state = LVIS_SELECTED;
1728 LISTVIEW_SetItemState(hwnd,i,&item);
1733 LISTVIEW_SetItemState(hwnd,i,&item);
1740 * Sets a single group selection.
1743 * [I] HWND : window handle
1744 * [I] INT : item index
1749 static VOID LISTVIEW_SetGroupSelection(HWND hwnd, INT nItem)
1751 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1752 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
1755 ZeroMemory(&item,sizeof(LVITEMA));
1756 item.stateMask = LVIS_SELECTED;
1758 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
1761 INT nFirst = min(infoPtr->nSelectionMark, nItem);
1762 INT nLast = max(infoPtr->nSelectionMark, nItem);
1764 for (i = 0; i <= GETITEMCOUNT(infoPtr); i++)
1766 if ((i < nFirst) || (i > nLast))
1769 LISTVIEW_SetItemState(hwnd,i,&item);
1773 item.state = LVIS_SELECTED;
1774 LISTVIEW_SetItemState(hwnd,i,&item);
1783 LISTVIEW_GetItemPosition(hwnd, nItem, &ptItem);
1784 LISTVIEW_GetItemPosition(hwnd, infoPtr->nSelectionMark, &ptSelMark);
1785 rcSel.left = min(ptSelMark.x, ptItem.x);
1786 rcSel.top = min(ptSelMark.y, ptItem.y);
1787 rcSel.right = max(ptSelMark.x, ptItem.x) + infoPtr->nItemWidth;
1788 rcSel.bottom = max(ptSelMark.y, ptItem.y) + infoPtr->nItemHeight;
1789 LISTVIEW_SetSelectionRect(hwnd, rcSel);
1792 LISTVIEW_SetItemFocus(hwnd, nItem);
1797 * Manages the item focus.
1800 * [I] HWND : window handle
1801 * [I] INT : item index
1804 * TRUE : focused item changed
1805 * FALSE : focused item has NOT changed
1807 static BOOL LISTVIEW_SetItemFocus(HWND hwnd, INT nItem)
1809 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1810 BOOL bResult = FALSE;
1813 if (infoPtr->nFocusedItem != nItem)
1815 if (infoPtr->nFocusedItem >= 0)
1817 INT oldFocus = infoPtr->nFocusedItem;
1819 infoPtr->nFocusedItem = -1;
1820 ZeroMemory(&lvItem, sizeof(LVITEMA));
1821 lvItem.stateMask = LVIS_FOCUSED;
1822 ListView_SetItemState(hwnd, oldFocus, &lvItem);
1826 lvItem.state = LVIS_FOCUSED;
1827 lvItem.stateMask = LVIS_FOCUSED;
1828 ListView_SetItemState(hwnd, nItem, &lvItem);
1830 infoPtr->nFocusedItem = nItem;
1831 ListView_EnsureVisible(hwnd, nItem, FALSE);
1839 * Sets a single selection.
1842 * [I] HWND : window handle
1843 * [I] INT : item index
1848 static VOID LISTVIEW_SetSelection(HWND hwnd, INT nItem)
1850 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1853 ZeroMemory(&lvItem, sizeof(LVITEMA));
1854 lvItem.stateMask = LVIS_FOCUSED;
1855 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
1857 LISTVIEW_RemoveAllSelections(hwnd);
1859 lvItem.state = LVIS_FOCUSED|LVIS_SELECTED;
1860 lvItem.stateMask = LVIS_FOCUSED|LVIS_SELECTED;
1861 ListView_SetItemState(hwnd, nItem, &lvItem);
1863 infoPtr->nFocusedItem = nItem;
1864 infoPtr->nSelectionMark = nItem;
1869 * Set selection(s) with keyboard.
1872 * [I] HWND : window handle
1873 * [I] INT : item index
1876 * SUCCESS : TRUE (needs to be repainted)
1877 * FAILURE : FALSE (nothing has changed)
1879 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem)
1881 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1882 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1883 WORD wShift = HIWORD(GetKeyState(VK_SHIFT));
1884 WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL));
1885 BOOL bResult = FALSE;
1887 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
1889 if (lStyle & LVS_SINGLESEL)
1892 LISTVIEW_SetSelection(hwnd, nItem);
1893 ListView_EnsureVisible(hwnd, nItem, FALSE);
1900 LISTVIEW_SetGroupSelection(hwnd, nItem);
1904 bResult = LISTVIEW_SetItemFocus(hwnd, nItem);
1909 LISTVIEW_SetSelection(hwnd, nItem);
1910 ListView_EnsureVisible(hwnd, nItem, FALSE);
1920 * Called when the mouse is being actively tracked and has hovered for a specified
1924 * [I] HWND : window handle
1925 * [I] wParam : key indicator
1926 * [I] lParam : mouse position
1929 * 0 if the message was processed, non-zero if there was an error
1932 * LVS_EX_TRACKSELECT: An item is automatically selected when the cursor remains
1933 * over the item for a certain period of time.
1936 static LRESULT LISTVIEW_MouseHover(hwnd, wParam, lParam)
1938 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1941 pt.x = (INT)LOWORD(lParam);
1942 pt.y = (INT)HIWORD(lParam);
1944 if(infoPtr->dwExStyle & LVS_EX_TRACKSELECT) {
1945 /* select the item under the cursor */
1946 LISTVIEW_MouseSelection(hwnd, pt);
1954 * Called whenever WM_MOUSEMOVE is recieved.
1957 * [I] HWND : window handle
1958 * [I] wParam : key indicators
1959 * [I] lParam : cursor position
1962 * 0 if the message is processed, non-zero if there was an error
1964 static LRESULT LISTVIEW_MouseMove(HWND hwnd, WPARAM wParam, LPARAM lParam)
1966 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1967 TRACKMOUSEEVENT trackinfo;
1969 /* see if we are supposed to be tracking mouse hovering */
1970 if(infoPtr->dwExStyle & LVS_EX_TRACKSELECT) {
1971 /* fill in the trackinfo struct */
1972 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
1973 trackinfo.dwFlags = TME_QUERY;
1974 trackinfo.hwndTrack = hwnd;
1975 trackinfo.dwHoverTime = infoPtr->dwHoverTime;
1977 /* see if we are already tracking this hwnd */
1978 _TrackMouseEvent(&trackinfo);
1980 if(!(trackinfo.dwFlags & TME_HOVER)) {
1981 trackinfo.dwFlags = TME_HOVER;
1983 /* call TRACKMOUSEEVENT so we recieve WM_MOUSEHOVER messages */
1984 _TrackMouseEvent(&trackinfo);
1993 * Selects an item based on coordinates.
1996 * [I] HWND : window handle
1997 * [I] POINT : mouse click ccordinates
2000 * SUCCESS : item index
2003 static LRESULT LISTVIEW_MouseSelection(HWND hwnd, POINT pt)
2005 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2007 INT i,topindex,bottomindex;
2008 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2009 UINT uView = lStyle & LVS_TYPEMASK;
2011 topindex = ListView_GetTopIndex(hwnd);
2012 if (uView == LVS_REPORT)
2014 bottomindex = topindex + LISTVIEW_GetCountPerColumn(hwnd) + 1;
2015 bottomindex = min(bottomindex,GETITEMCOUNT(infoPtr));
2019 bottomindex = GETITEMCOUNT(infoPtr);
2022 for (i = topindex; i < bottomindex; i++)
2024 rcItem.left = LVIR_SELECTBOUNDS;
2025 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) == TRUE)
2027 if (PtInRect(&rcItem, pt) != FALSE)
2042 * [IO] HDPA : dynamic pointer array handle
2043 * [I] INT : column index (subitem index)
2049 static BOOL LISTVIEW_RemoveColumn(HDPA hdpaItems, INT nSubItem)
2051 BOOL bResult = TRUE;
2055 for (i = 0; i < hdpaItems->nItemCount; i++)
2057 hdpaSubItems = (HDPA)DPA_GetPtr(hdpaItems, i);
2058 if (hdpaSubItems != NULL)
2060 if (LISTVIEW_RemoveSubItem(hdpaSubItems, nSubItem) == FALSE)
2072 * Removes a subitem at a given position.
2075 * [IO] HDPA : dynamic pointer array handle
2076 * [I] INT : subitem index
2082 static BOOL LISTVIEW_RemoveSubItem(HDPA hdpaSubItems, INT nSubItem)
2084 LISTVIEW_SUBITEM *lpSubItem;
2087 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2089 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2090 if (lpSubItem != NULL)
2092 if (lpSubItem->iSubItem == nSubItem)
2095 if ((lpSubItem->pszText != NULL) &&
2096 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2098 COMCTL32_Free(lpSubItem->pszText);
2102 COMCTL32_Free(lpSubItem);
2104 /* free dpa memory */
2105 if (DPA_DeletePtr(hdpaSubItems, i) == NULL)
2110 else if (lpSubItem->iSubItem > nSubItem)
2122 * Compares the item information.
2125 * [I] LISTVIEW_ITEM *: destination item
2126 * [I] LPLVITEM : source item
2129 * SUCCCESS : TRUE (EQUAL)
2130 * FAILURE : FALSE (NOT EQUAL)
2132 static UINT LISTVIEW_GetItemChanges(LISTVIEW_ITEM *lpItem, LPLVITEMA lpLVItem)
2136 if ((lpItem != NULL) && (lpLVItem != NULL))
2138 if (lpLVItem->mask & LVIF_STATE)
2140 if ((lpItem->state & lpLVItem->stateMask) !=
2141 (lpLVItem->state & lpLVItem->stateMask))
2143 uChanged |= LVIF_STATE;
2147 if (lpLVItem->mask & LVIF_IMAGE)
2149 if (lpItem->iImage != lpLVItem->iImage)
2151 uChanged |= LVIF_IMAGE;
2155 if (lpLVItem->mask & LVIF_PARAM)
2157 if (lpItem->lParam != lpLVItem->lParam)
2159 uChanged |= LVIF_PARAM;
2163 if (lpLVItem->mask & LVIF_INDENT)
2165 if (lpItem->iIndent != lpLVItem->iIndent)
2167 uChanged |= LVIF_INDENT;
2171 if (lpLVItem->mask & LVIF_TEXT)
2173 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
2175 if (lpItem->pszText != LPSTR_TEXTCALLBACKA)
2177 uChanged |= LVIF_TEXT;
2182 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
2184 uChanged |= LVIF_TEXT;
2188 if (lpLVItem->pszText)
2190 if (lpItem->pszText)
2192 if (strcmp(lpLVItem->pszText, lpItem->pszText) != 0)
2194 uChanged |= LVIF_TEXT;
2199 uChanged |= LVIF_TEXT;
2204 if (lpItem->pszText)
2206 uChanged |= LVIF_TEXT;
2218 * Initializes item attributes.
2221 * [I] HWND : window handle
2222 * [O] LISTVIEW_ITEM *: destination item
2223 * [I] LPLVITEM : source item
2229 static BOOL LISTVIEW_InitItem(HWND hwnd, LISTVIEW_ITEM *lpItem,
2232 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2233 BOOL bResult = FALSE;
2235 if ((lpItem != NULL) && (lpLVItem != NULL))
2239 if (lpLVItem->mask & LVIF_STATE)
2241 lpItem->state &= ~lpLVItem->stateMask;
2242 lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
2245 if (lpLVItem->mask & LVIF_IMAGE)
2247 lpItem->iImage = lpLVItem->iImage;
2250 if (lpLVItem->mask & LVIF_PARAM)
2252 lpItem->lParam = lpLVItem->lParam;
2255 if (lpLVItem->mask & LVIF_INDENT)
2257 lpItem->iIndent = lpLVItem->iIndent;
2260 if (lpLVItem->mask & LVIF_TEXT)
2262 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
2264 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
2269 if ((lpItem->pszText != NULL) &&
2270 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2272 COMCTL32_Free(lpItem->pszText);
2275 lpItem->pszText = LPSTR_TEXTCALLBACKA;
2279 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
2281 lpItem->pszText = NULL;
2284 bResult = Str_SetPtrA(&lpItem->pszText, lpLVItem->pszText);
2294 * Initializes subitem attributes.
2296 * NOTE: The documentation specifies that the operation fails if the user
2297 * tries to set the indent of a subitem.
2300 * [I] HWND : window handle
2301 * [O] LISTVIEW_SUBITEM *: destination subitem
2302 * [I] LPLVITEM : source subitem
2308 static BOOL LISTVIEW_InitSubItem(HWND hwnd, LISTVIEW_SUBITEM *lpSubItem,
2311 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2312 BOOL bResult = FALSE;
2314 if ((lpSubItem != NULL) && (lpLVItem != NULL))
2316 if (!(lpLVItem->mask & LVIF_INDENT))
2320 lpSubItem->iSubItem = lpLVItem->iSubItem;
2322 if (lpLVItem->mask & LVIF_IMAGE)
2324 lpSubItem->iImage = lpLVItem->iImage;
2327 if (lpLVItem->mask & LVIF_TEXT)
2329 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
2331 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
2336 if ((lpSubItem->pszText != NULL) &&
2337 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2339 COMCTL32_Free(lpSubItem->pszText);
2342 lpSubItem->pszText = LPSTR_TEXTCALLBACKA;
2346 if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
2348 lpSubItem->pszText = NULL;
2351 bResult = Str_SetPtrA(&lpSubItem->pszText, lpLVItem->pszText);
2362 * Adds a subitem at a given position (column index).
2365 * [I] HWND : window handle
2366 * [I] LPLVITEM : new subitem atttributes
2372 static BOOL LISTVIEW_AddSubItem(HWND hwnd, LPLVITEMA lpLVItem)
2374 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2375 LISTVIEW_SUBITEM *lpSubItem = NULL;
2376 BOOL bResult = FALSE;
2378 INT nPosition, nItem;
2379 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2381 if (lStyle & LVS_OWNERDATA)
2384 if (lpLVItem != NULL)
2386 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
2387 if (hdpaSubItems != NULL)
2389 lpSubItem = (LISTVIEW_SUBITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM));
2390 if (lpSubItem != NULL)
2392 ZeroMemory(lpSubItem, sizeof(LISTVIEW_SUBITEM));
2393 if (LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem) != FALSE)
2395 nPosition = LISTVIEW_FindInsertPosition(hdpaSubItems,
2396 lpSubItem->iSubItem);
2397 nItem = DPA_InsertPtr(hdpaSubItems, nPosition, lpSubItem);
2407 /* cleanup if unsuccessful */
2408 if ((bResult == FALSE) && (lpSubItem != NULL))
2410 COMCTL32_Free(lpSubItem);
2418 * Finds the dpa insert position (array index).
2421 * [I] HWND : window handle
2422 * [I] INT : subitem index
2428 static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem)
2430 LISTVIEW_SUBITEM *lpSubItem;
2433 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2435 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2436 if (lpSubItem != NULL)
2438 if (lpSubItem->iSubItem > nSubItem)
2445 return hdpaSubItems->nItemCount;
2450 * Retrieves a listview subitem at a given position (column index).
2453 * [I] HWND : window handle
2454 * [I] INT : subitem index
2460 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem)
2462 LISTVIEW_SUBITEM *lpSubItem;
2465 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2467 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2468 if (lpSubItem != NULL)
2470 if (lpSubItem->iSubItem == nSubItem)
2474 else if (lpSubItem->iSubItem > nSubItem)
2486 * Sets item attributes.
2489 * [I] HWND : window handle
2490 * [I] LPLVITEM : new item atttributes
2496 static BOOL LISTVIEW_SetItem(HWND hwnd, LPLVITEMA lpLVItem)
2498 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2499 BOOL bResult = FALSE;
2501 LISTVIEW_ITEM *lpItem;
2503 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2504 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2506 UINT uView = lStyle & LVS_TYPEMASK;
2510 if (lStyle & LVS_OWNERDATA)
2512 if ((lpLVItem->iSubItem == 0)&&(lpLVItem->mask == LVIF_STATE))
2516 ZeroMemory(&itm,sizeof(LVITEMA));
2517 itm.mask = LVIF_STATE | LVIF_PARAM;
2518 itm.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
2519 itm.iItem = lpLVItem->iItem;
2521 ListView_GetItemA(hwnd,&itm);
2524 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2525 nmlv.hdr.hwndFrom = hwnd;
2526 nmlv.hdr.idFrom = lCtrlId;
2527 nmlv.hdr.code = LVN_ITEMCHANGING;
2528 nmlv.uNewState = lpLVItem->state;
2529 nmlv.uOldState = itm.state;
2530 nmlv.uChanged = LVIF_STATE;
2531 nmlv.lParam = itm.lParam;
2532 nmlv.iItem = lpLVItem->iItem;
2534 if ((itm.state & lpLVItem->stateMask) !=
2535 (lpLVItem->state & lpLVItem->stateMask))
2537 /* send LVN_ITEMCHANGING notification */
2538 if (!ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv))
2540 if (lpLVItem->stateMask & LVIS_FOCUSED)
2542 if (lpLVItem->state & LVIS_FOCUSED)
2543 infoPtr->nFocusedItem = lpLVItem->iItem;
2544 else if (infoPtr->nFocusedItem == lpLVItem->iItem)
2545 infoPtr->nFocusedItem = -1;
2547 if (lpLVItem->stateMask & LVIS_SELECTED)
2549 if (lpLVItem->state & LVIS_SELECTED)
2550 LISTVIEW_AddSelectionRange(hwnd,lpLVItem->iItem,lpLVItem->iItem);
2552 LISTVIEW_RemoveSelectionRange(hwnd,lpLVItem->iItem,
2556 nmlv.hdr.code = LVN_ITEMCHANGED;
2558 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2560 rcItem.left = LVIR_BOUNDS;
2561 LISTVIEW_GetItemRect(hwnd, lpLVItem->iItem, &rcItem);
2562 InvalidateRect(hwnd, &rcItem, TRUE);
2570 if (lpLVItem != NULL)
2572 if (lpLVItem->iSubItem == 0)
2574 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
2575 if (hdpaSubItems != NULL && hdpaSubItems != (HDPA)-1)
2577 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem);
2580 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2581 nmlv.hdr.hwndFrom = hwnd;
2582 nmlv.hdr.idFrom = lCtrlId;
2583 nmlv.hdr.code = LVN_ITEMCHANGING;
2584 nmlv.lParam = lpItem->lParam;
2585 uChanged = LISTVIEW_GetItemChanges(lpItem, lpLVItem);
2588 if (uChanged & LVIF_STATE)
2590 nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask;
2591 nmlv.uOldState = lpItem->state & lpLVItem->stateMask;
2593 if (nmlv.uNewState & LVIS_SELECTED)
2596 * This is redundant if called through SetSelection
2598 * however is required if the used directly calls SetItem
2599 * to set the selection.
2601 if (lStyle & LVS_SINGLESEL)
2603 LISTVIEW_RemoveAllSelections(hwnd);
2606 LISTVIEW_AddSelectionRange(hwnd,lpLVItem->iItem,
2609 else if (lpLVItem->stateMask & LVIS_SELECTED)
2611 LISTVIEW_RemoveSelectionRange(hwnd,lpLVItem->iItem,
2614 if (nmlv.uNewState & LVIS_FOCUSED)
2617 * This is a fun hoop to jump to try to catch if
2618 * the user is calling us directly to call focus or if
2619 * this function is being called as a result of a
2620 * SetItemFocus call.
2622 if (infoPtr->nFocusedItem >= 0)
2623 LISTVIEW_SetItemFocus(hwnd, lpLVItem->iItem);
2627 nmlv.uChanged = uChanged;
2628 nmlv.iItem = lpLVItem->iItem;
2629 nmlv.lParam = lpItem->lParam;
2630 /* send LVN_ITEMCHANGING notification */
2631 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2633 /* copy information */
2634 bResult = LISTVIEW_InitItem(hwnd, lpItem, lpLVItem);
2636 /* if LVS_LIST or LVS_SMALLICON, update the width of the items
2637 based on the width of the items text */
2638 if((uView == LVS_LIST) || (uView == LVS_SMALLICON))
2640 item_width = LISTVIEW_GetStringWidthA(hwnd, lpItem->pszText);
2642 if(item_width > infoPtr->nItemWidth)
2643 infoPtr->nItemWidth = item_width;
2646 /* send LVN_ITEMCHANGED notification */
2647 nmlv.hdr.code = LVN_ITEMCHANGED;
2648 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2657 rcItem.left = LVIR_BOUNDS;
2658 LISTVIEW_GetItemRect(hwnd, lpLVItem->iItem, &rcItem);
2659 InvalidateRect(hwnd, &rcItem, TRUE);
2671 * Sets subitem attributes.
2674 * [I] HWND : window handle
2675 * [I] LPLVITEM : new subitem atttributes
2681 static BOOL LISTVIEW_SetSubItem(HWND hwnd, LPLVITEMA lpLVItem)
2683 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2684 BOOL bResult = FALSE;
2686 LISTVIEW_SUBITEM *lpSubItem;
2687 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2690 if (lStyle & LVS_OWNERDATA)
2693 if (lpLVItem != NULL)
2695 if (lpLVItem->iSubItem > 0)
2697 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
2698 if (hdpaSubItems != NULL)
2700 /* set subitem only if column is present */
2701 if (Header_GetItemCount(infoPtr->hwndHeader) > lpLVItem->iSubItem)
2703 lpSubItem = LISTVIEW_GetSubItem(hdpaSubItems, lpLVItem->iSubItem);
2704 if (lpSubItem != NULL)
2706 bResult = LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem);
2710 bResult = LISTVIEW_AddSubItem(hwnd, lpLVItem);
2713 rcItem.left = LVIR_BOUNDS;
2714 LISTVIEW_GetItemRect(hwnd, lpLVItem->iItem, &rcItem);
2715 InvalidateRect(hwnd, &rcItem, FALSE);
2726 * Retrieves the index of the item at coordinate (0, 0) of the client area.
2729 * [I] HWND : window handle
2734 static INT LISTVIEW_GetTopIndex(HWND hwnd)
2736 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2737 UINT uView = lStyle & LVS_TYPEMASK;
2739 SCROLLINFO scrollInfo;
2741 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2742 scrollInfo.cbSize = sizeof(SCROLLINFO);
2743 scrollInfo.fMask = SIF_POS;
2745 if (uView == LVS_LIST)
2747 if (lStyle & WS_HSCROLL)
2749 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2751 nItem = scrollInfo.nPos * LISTVIEW_GetCountPerColumn(hwnd);
2755 else if (uView == LVS_REPORT)
2757 if (lStyle & WS_VSCROLL)
2759 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
2761 nItem = scrollInfo.nPos;
2774 * [I] HWND : window handle
2775 * [I] HDC : device context handle
2776 * [I] INT : item index
2777 * [I] INT : subitem index
2778 * [I] RECT * : clipping rectangle
2783 static VOID LISTVIEW_DrawSubItem(HWND hwnd, HDC hdc, INT nItem, INT nSubItem,
2784 RECT rcItem, BOOL Selected)
2786 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2787 CHAR szDispText[DISP_TEXT_SIZE];
2789 UINT textoutOptions = ETO_CLIPPED | ETO_OPAQUE;
2793 TRACE("(hwnd=%x, hdc=%x, nItem=%d, nSubItem=%d)\n", hwnd, hdc,
2796 /* get information needed for drawing the item */
2797 ZeroMemory(&lvItem, sizeof(LVITEMA));
2798 lvItem.mask = LVIF_TEXT;
2799 lvItem.iItem = nItem;
2800 lvItem.iSubItem = nSubItem;
2801 lvItem.cchTextMax = DISP_TEXT_SIZE;
2802 lvItem.pszText = szDispText;
2803 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
2805 /* redraw the background of the item */
2806 hBrush = CreateSolidBrush(infoPtr->clrBk);
2808 if(infoPtr->nColumnCount == (nSubItem + 1))
2809 rcTemp.right = infoPtr->rcList.right;
2811 rcTemp.right+=WIDTH_PADDING;
2813 FillRect(hdc, &rcTemp, hBrush);
2814 DeleteObject(hBrush);
2816 /* set item colors */
2817 if (ListView_GetItemState(hwnd,nItem,LVIS_SELECTED)
2818 &&(infoPtr->bFocus != FALSE) && Selected)
2820 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
2821 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2825 if ( (infoPtr->clrTextBk == CLR_DEFAULT) || (infoPtr->clrTextBk == CLR_NONE) )
2827 SetBkMode(hdc, TRANSPARENT);
2828 textoutOptions &= ~ETO_OPAQUE;
2832 SetBkMode(hdc, OPAQUE);
2833 SetBkColor(hdc, infoPtr->clrTextBk);
2836 SetTextColor(hdc, infoPtr->clrText);
2839 ExtTextOutA(hdc, rcItem.left, rcItem.top, textoutOptions,
2840 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
2844 /* fill in the gap */
2846 if (nSubItem < Header_GetItemCount(infoPtr->hwndHeader)-1)
2848 CopyRect(&rec,&rcItem);
2849 rec.left = rec.right;
2850 rec.right = rec.left+REPORT_MARGINX;
2851 ExtTextOutA(hdc, rec.left , rec.top, textoutOptions,
2852 &rec, NULL, 0, NULL);
2854 CopyRect(&rec,&rcItem);
2855 rec.right = rec.left;
2856 rec.left = rec.left - REPORT_MARGINX;
2857 ExtTextOutA(hdc, rec.left , rec.top, textoutOptions,
2858 &rec, NULL, 0, NULL);
2868 * [I] HWND : window handle
2869 * [I] HDC : device context handle
2870 * [I] INT : item index
2871 * [I] RECT * : clipping rectangle
2876 static VOID LISTVIEW_DrawItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem, BOOL FullSelect, RECT* SuggestedFocus)
2878 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2879 CHAR szDispText[DISP_TEXT_SIZE];
2884 DWORD dwTextColor,dwTextX;
2885 BOOL bImage = FALSE;
2887 UINT textoutOptions = ETO_OPAQUE | ETO_CLIPPED;
2891 TRACE("(hwnd=%x, hdc=%x, nItem=%d)\n", hwnd, hdc, nItem);
2894 /* get information needed for drawing the item */
2895 ZeroMemory(&lvItem, sizeof(LVITEMA));
2896 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_INDENT;
2897 lvItem.stateMask = LVIS_SELECTED | LVIS_STATEIMAGEMASK;
2898 lvItem.iItem = nItem;
2899 lvItem.iSubItem = 0;
2900 lvItem.cchTextMax = DISP_TEXT_SIZE;
2901 lvItem.pszText = szDispText;
2902 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
2904 /* redraw the background of the item */
2905 hBrush = CreateSolidBrush(infoPtr->clrBk);
2907 if(infoPtr->nColumnCount == (nItem + 1))
2908 rcTemp.right = infoPtr->rcList.right;
2910 rcTemp.right+=WIDTH_PADDING;
2912 FillRect(hdc, &rcTemp, hBrush);
2913 DeleteObject(hBrush);
2916 if (lvItem.iIndent>0 && infoPtr->iconSize.cx > 0)
2918 rcItem.left += infoPtr->iconSize.cx * lvItem.iIndent;
2921 SuggestedFocus->left += infoPtr->iconSize.cx * lvItem.iIndent;
2925 if (infoPtr->himlState != NULL)
2927 UINT uStateImage = (lvItem.state & LVIS_STATEIMAGEMASK) >> 12;
2928 if (uStateImage > 0)
2930 ImageList_Draw(infoPtr->himlState, uStateImage - 1, hdc, rcItem.left,
2931 rcItem.top, ILD_NORMAL);
2934 rcItem.left += infoPtr->iconSize.cx;
2936 SuggestedFocus->left += infoPtr->iconSize.cx;
2941 if (infoPtr->himlSmall != NULL)
2943 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE) &&
2946 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
2947 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
2948 rcItem.top, ILD_SELECTED);
2950 else if (lvItem.iImage>=0)
2952 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
2953 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
2954 rcItem.top, ILD_NORMAL);
2957 rcItem.left += infoPtr->iconSize.cx;
2960 SuggestedFocus->left += infoPtr->iconSize.cx;
2964 /* Don't bother painting item being edited */
2965 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED && !FullSelect)
2968 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
2970 /* set item colors */
2971 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
2972 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2973 /* set raster mode */
2974 nMixMode = SetROP2(hdc, R2_XORPEN);
2976 else if ((GetWindowLongA(hwnd, GWL_STYLE) & LVS_SHOWSELALWAYS) &&
2977 (lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus == FALSE))
2979 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
2980 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
2981 /* set raster mode */
2982 nMixMode = SetROP2(hdc, R2_COPYPEN);
2986 /* set item colors */
2987 if ( (infoPtr->clrTextBk == CLR_DEFAULT) || (infoPtr->clrTextBk == CLR_NONE) )
2989 dwBkColor = GetBkColor(hdc);
2990 iBkMode = SetBkMode(hdc, TRANSPARENT);
2991 textoutOptions &= ~ETO_OPAQUE;
2995 dwBkColor = SetBkColor(hdc, infoPtr->clrTextBk);
2996 iBkMode = SetBkMode(hdc, OPAQUE);
2999 dwTextColor = SetTextColor(hdc, infoPtr->clrText);
3000 /* set raster mode */
3001 nMixMode = SetROP2(hdc, R2_COPYPEN);
3004 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
3005 if (rcItem.left + nLabelWidth < rcItem.right)
3008 rcItem.right = rcItem.left + nLabelWidth + TRAILING_PADDING;
3010 rcItem.right += IMAGE_PADDING;
3014 dwTextX = rcItem.left + 1;
3016 dwTextX += IMAGE_PADDING;
3018 ExtTextOutA(hdc, dwTextX, rcItem.top, textoutOptions,
3019 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
3021 if ((FullSelect)&&(Header_GetItemCount(infoPtr->hwndHeader) > 1))
3023 /* fill in the gap */
3025 CopyRect(&rec,&rcItem);
3026 rec.left = rec.right;
3027 rec.right = rec.left+REPORT_MARGINX;
3028 ExtTextOutA(hdc, rec.left , rec.top, textoutOptions,
3029 &rec, NULL, 0, NULL);
3033 CopyRect(SuggestedFocus,&rcItem);
3037 SetROP2(hdc, R2_COPYPEN);
3038 SetBkColor(hdc, dwBkColor);
3039 SetTextColor(hdc, dwTextColor);
3041 SetBkMode(hdc, iBkMode);
3047 * Draws an item when in large icon display mode.
3050 * [I] HWND : window handle
3051 * [I] HDC : device context handle
3052 * [I] LISTVIEW_ITEM * : item
3053 * [I] INT : item index
3054 * [I] RECT * : clipping rectangle
3059 static VOID LISTVIEW_DrawLargeItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem,
3060 RECT *SuggestedFocus)
3062 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3063 CHAR szDispText[DISP_TEXT_SIZE];
3064 INT nDrawPosX = rcItem.left;
3065 INT nLabelWidth, rcWidth;
3068 UINT textoutOptions = ETO_CLIPPED | ETO_OPAQUE;
3072 TRACE("(hwnd=%x, hdc=%x, nItem=%d, left=%d, top=%d, right=%d, \
3073 bottom=%d)\n", hwnd, hdc, nItem, rcItem.left, rcItem.top, rcItem.right,
3076 /* get information needed for drawing the item */
3077 ZeroMemory(&lvItem, sizeof(LVITEMA));
3078 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
3079 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
3080 lvItem.iItem = nItem;
3081 lvItem.iSubItem = 0;
3082 lvItem.cchTextMax = DISP_TEXT_SIZE;
3083 lvItem.pszText = szDispText;
3084 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
3086 /* redraw the background of the item */
3087 hBrush = CreateSolidBrush(infoPtr->clrBk);
3088 if(infoPtr->nColumnCount == (nItem + 1))
3089 rcTemp.right = infoPtr->rcList.right;
3091 rcTemp.right+=WIDTH_PADDING;
3093 FillRect(hdc, &rcTemp, hBrush);
3094 DeleteObject(hBrush);
3096 if (lvItem.state & LVIS_SELECTED)
3098 /* set item colors */
3099 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
3100 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
3101 /* set raster mode */
3102 SetROP2(hdc, R2_XORPEN);
3106 /* set item colors */
3107 if ( (infoPtr->clrTextBk == CLR_DEFAULT) || (infoPtr->clrTextBk == CLR_NONE) )
3109 SetBkMode(hdc, TRANSPARENT);
3110 textoutOptions &= ~ETO_OPAQUE;
3114 SetBkMode(hdc, OPAQUE);
3115 SetBkColor(hdc, infoPtr->clrTextBk);
3118 SetTextColor(hdc, infoPtr->clrText);
3119 /* set raster mode */
3120 SetROP2(hdc, R2_COPYPEN);
3123 if (infoPtr->himlNormal != NULL)
3125 rcItem.top += ICON_TOP_PADDING;
3126 nDrawPosX += (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
3127 if ((lvItem.state & LVIS_SELECTED) && (lvItem.iImage>=0))
3129 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
3130 rcItem.top, ILD_SELECTED);
3132 else if (lvItem.iImage>=0)
3134 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
3135 rcItem.top, ILD_NORMAL);
3139 /* Don't bother painting item being edited */
3140 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED)
3143 InflateRect(&rcItem, -(2*CAPTION_BORDER), 0);
3144 rcItem.top += infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
3145 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
3146 GetTextMetricsA(hdc, &tm);
3148 /* append an ellipse ('...') if the caption won't fit in the rect */
3149 rcWidth = max(0, rcItem.right - rcItem.left);
3150 if (nLabelWidth > rcWidth)
3152 INT i, len, eos, nCharsFit;
3153 /* give or take a couple, how many average sized chars would fit? */
3154 nCharsFit = tm.tmAveCharWidth > 0 ? (rcWidth/tm.tmAveCharWidth)+2 : 0;
3155 /* place the ellipse accordingly, without overrunning the buffer */
3156 len = strlen(szDispText);
3157 eos = min((nCharsFit > 1 && nCharsFit < len) ? nCharsFit+3 : len+2,
3158 sizeof(szDispText)-1);
3160 nLabelWidth = ListView_GetStringWidthA(hwnd, szDispText);
3161 while ((nLabelWidth > rcWidth) && (eos > 3))
3163 for (i = 1; i < 4; i++)
3164 szDispText[eos-i] = '.';
3165 /* shift the ellipse one char to the left for each iteration */
3166 szDispText[eos--] = '\0';
3167 nLabelWidth = ListView_GetStringWidthA(hwnd, szDispText);
3171 InflateRect(&rcItem, 2*CAPTION_BORDER, 0);
3172 nDrawPosX = infoPtr->iconSpacing.cx - 2*CAPTION_BORDER - nLabelWidth;
3175 rcItem.left += nDrawPosX / 2;
3176 rcItem.right = rcItem.left + nLabelWidth + 2*CAPTION_BORDER;
3181 rcItem.right = rcItem.left + infoPtr->iconSpacing.cx - 1;
3185 rcItem.bottom = rcItem.top + tm.tmHeight + HEIGHT_PADDING;
3187 ExtTextOutA(hdc, rcItem.left + CAPTION_BORDER, rcItem.top, textoutOptions,
3188 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
3191 CopyRect(SuggestedFocus,&rcItem);
3196 * Draws listview items when in report display mode.
3199 * [I] HWND : window handle
3200 * [I] HDC : device context handle
3205 static VOID LISTVIEW_RefreshReport(HWND hwnd, HDC hdc, DWORD cdmode)
3207 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
3208 SCROLLINFO scrollInfo;
3209 INT nDrawPosY = infoPtr->rcList.top;
3211 RECT rcItem, rcTemp;
3216 DWORD cditemmode = CDRF_DODEFAULT;
3217 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3220 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
3221 scrollInfo.cbSize = sizeof(SCROLLINFO);
3222 scrollInfo.fMask = SIF_POS;
3224 nItem = ListView_GetTopIndex(hwnd);
3226 /* add 1 for displaying a partial item at the bottom */
3227 nLast = nItem + LISTVIEW_GetCountPerColumn(hwnd) + 1;
3228 nLast = min(nLast, GETITEMCOUNT(infoPtr));
3230 /* send cache hint notification */
3231 if (GetWindowLongA(hwnd,GWL_STYLE) & LVS_OWNERDATA)
3235 nmlv.hdr.hwndFrom = hwnd;
3236 nmlv.hdr.idFrom = GetWindowLongA(hwnd,GWL_ID);
3237 nmlv.hdr.code = LVN_ODCACHEHINT;
3241 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)nmlv.hdr.idFrom,
3245 nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
3246 infoPtr->nColumnCount = nColumnCount; /* update nColumnCount */
3247 FullSelected = infoPtr->dwExStyle & LVS_EX_FULLROWSELECT;
3249 /* clear the background of any part of the control that doesn't contain items */
3250 SubtractRect(&rcTemp, &infoPtr->rcList, &infoPtr->rcView);
3251 hBrush = CreateSolidBrush(infoPtr->clrBk);
3252 FillRect(hdc, &infoPtr->rcList, hBrush);
3253 DeleteObject(hBrush);
3255 /* nothing to draw */
3256 if(GETITEMCOUNT(infoPtr) == 0)
3259 for (; nItem < nLast; nItem++)
3261 RECT SuggestedFocusRect;
3264 if (lStyle & LVS_OWNERDRAWFIXED)
3266 UINT uID = GetWindowLongA( hwnd, GWL_ID);
3271 TRACE("Owner Drawn\n");
3272 dis.CtlType = ODT_LISTVIEW;
3275 dis.itemAction = ODA_DRAWENTIRE;
3278 if (LISTVIEW_IsSelected(hwnd,nItem)) dis.itemState|=ODS_SELECTED;
3279 if (nItem==infoPtr->nFocusedItem) dis.itemState|=ODS_FOCUS;
3281 dis.hwndItem = hwnd;
3284 Header_GetItemRect(infoPtr->hwndHeader, 0, &dis.rcItem);
3285 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
3288 dis.rcItem.right = max(dis.rcItem.left, br.right);
3289 dis.rcItem.top = nDrawPosY;
3290 dis.rcItem.bottom = dis.rcItem.top + infoPtr->nItemHeight;
3292 ZeroMemory(&item,sizeof(LVITEMA));
3294 item.mask = LVIF_PARAM;
3295 ListView_GetItemA(hwnd,&item);
3297 dis.itemData = item.lParam;
3299 if (SendMessageA(GetParent(hwnd),WM_DRAWITEM,(WPARAM)uID,(LPARAM)&dis))
3301 nDrawPosY += infoPtr->nItemHeight;
3310 Header_GetItemRect(infoPtr->hwndHeader, 0, &ir);
3311 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
3313 ir.left += REPORT_MARGINX;
3314 ir.right = max(ir.left, br.right - REPORT_MARGINX);
3316 ir.bottom = ir.top + infoPtr->nItemHeight;
3318 CopyRect(&SuggestedFocusRect,&ir);
3321 for (j = 0; j < nColumnCount; j++)
3323 if (cdmode & CDRF_NOTIFYITEMDRAW)
3324 cditemmode = LISTVIEW_SendCustomDrawItemNotify (hwnd, hdc, nItem, j,
3326 if (cditemmode & CDRF_SKIPDEFAULT)
3329 Header_GetItemRect(infoPtr->hwndHeader, j, &rcItem);
3331 rcItem.left += REPORT_MARGINX;
3332 rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX);
3333 rcItem.top = nDrawPosY;
3334 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
3336 /* Offset the Scroll Bar Pos */
3337 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
3339 rcItem.left -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
3340 rcItem.right -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
3345 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem, FullSelected,
3346 &SuggestedFocusRect);
3350 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, j, rcItem,
3354 if (cditemmode & CDRF_NOTIFYPOSTPAINT)
3355 LISTVIEW_SendCustomDrawItemNotify(hwnd, hdc, nItem, 0,
3356 CDDS_ITEMPOSTPAINT);
3361 if (LISTVIEW_GetItemState(hwnd,nItem,LVIS_FOCUSED) && infoPtr->bFocus)
3364 if (FullSelected && LISTVIEW_GetItemState(hwnd,nItem,LVIS_SELECTED))
3365 rop = SetROP2(hdc, R2_XORPEN);
3367 Rectangle(hdc, SuggestedFocusRect.left, SuggestedFocusRect.top,
3368 SuggestedFocusRect.right,SuggestedFocusRect.bottom);
3371 SetROP2(hdc, R2_COPYPEN);
3373 nDrawPosY += infoPtr->nItemHeight;
3379 * Retrieves the number of items that can fit vertically in the client area.
3382 * [I] HWND : window handle
3385 * Number of items per row.
3387 static INT LISTVIEW_GetCountPerRow(HWND hwnd)
3389 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
3390 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3391 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
3392 INT nCountPerRow = 1;
3396 if (uView == LVS_REPORT)
3402 nCountPerRow = nListWidth / infoPtr->nItemWidth;
3403 if (nCountPerRow == 0)
3410 return nCountPerRow;
3415 * Retrieves the number of items that can fit horizontally in the client
3419 * [I] HWND : window handle
3422 * Number of items per column.
3424 static INT LISTVIEW_GetCountPerColumn(HWND hwnd)
3426 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
3427 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
3428 INT nCountPerColumn = 1;
3430 if (nListHeight > 0)
3432 nCountPerColumn = nListHeight / infoPtr->nItemHeight;
3433 if (nCountPerColumn == 0)
3435 nCountPerColumn = 1;
3439 return nCountPerColumn;
3444 * Retrieves the number of columns needed to display all the items when in
3445 * list display mode.
3448 * [I] HWND : window handle
3451 * Number of columns.
3453 static INT LISTVIEW_GetColumnCount(HWND hwnd)
3455 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3456 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3457 INT nColumnCount = 0;
3459 if ((lStyle & LVS_TYPEMASK) == LVS_LIST)
3461 if (infoPtr->rcList.right % infoPtr->nItemWidth == 0)
3463 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth;
3467 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth + 1;
3471 return nColumnCount;
3477 * Draws listview items when in list display mode.
3480 * [I] HWND : window handle
3481 * [I] HDC : device context handle
3486 static VOID LISTVIEW_RefreshList(HWND hwnd, HDC hdc, DWORD cdmode)
3488 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3489 RECT rcItem, FocusRect, rcTemp;
3493 INT nCountPerColumn;
3494 INT nItemWidth = infoPtr->nItemWidth;
3495 INT nItemHeight = infoPtr->nItemHeight;
3496 DWORD cditemmode = CDRF_DODEFAULT;
3499 /* get number of fully visible columns */
3500 nColumnCount = LISTVIEW_GetColumnCount(hwnd);
3501 infoPtr->nColumnCount = nColumnCount;
3502 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
3503 nItem = ListView_GetTopIndex(hwnd);
3505 /* paint the background of the control that doesn't contain any items */
3506 SubtractRect(&rcTemp, &infoPtr->rcList, &infoPtr->rcView);
3507 hBrush = CreateSolidBrush(infoPtr->clrBk);
3508 FillRect(hdc, &infoPtr->rcList, hBrush);
3509 DeleteObject(hBrush);
3511 /* nothing to draw, return here */
3512 if(GETITEMCOUNT(infoPtr) == 0)
3515 for (i = 0; i < nColumnCount; i++)
3517 for (j = 0; j < nCountPerColumn; j++, nItem++)
3519 if (nItem >= GETITEMCOUNT(infoPtr))
3522 if (cdmode & CDRF_NOTIFYITEMDRAW)
3523 cditemmode = LISTVIEW_SendCustomDrawItemNotify (hwnd, hdc, nItem, 0,
3525 if (cditemmode & CDRF_SKIPDEFAULT)
3528 rcItem.top = j * nItemHeight;
3529 rcItem.left = i * nItemWidth;
3530 rcItem.bottom = rcItem.top + nItemHeight;
3531 rcItem.right = rcItem.left + nItemWidth;
3532 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem, FALSE, &FocusRect);
3536 if (LISTVIEW_GetItemState(hwnd,nItem,LVIS_FOCUSED) && infoPtr->bFocus)
3537 Rectangle(hdc, FocusRect.left, FocusRect.top,
3538 FocusRect.right,FocusRect.bottom);
3540 if (cditemmode & CDRF_NOTIFYPOSTPAINT)
3541 LISTVIEW_SendCustomDrawItemNotify(hwnd, hdc, nItem, 0,
3542 CDDS_ITEMPOSTPAINT);
3550 * Draws listview items when in icon or small icon display mode.
3553 * [I] HWND : window handle
3554 * [I] HDC : device context handle
3559 static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc, BOOL bSmall, DWORD cdmode)
3561 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3564 RECT rcItem, SuggestedFocus, rcTemp;
3567 DWORD cditemmode = CDRF_DODEFAULT;
3569 infoPtr->nColumnCount = 1; /* set this to an arbitrary value to prevent */
3570 /* DrawItem from erasing the incorrect background area */
3572 /* paint the background of the control that doesn't contain any items */
3573 SubtractRect(&rcTemp, &infoPtr->rcList, &infoPtr->rcView);
3574 hBrush = CreateSolidBrush(infoPtr->clrBk);
3575 FillRect(hdc, &infoPtr->rcList, hBrush);
3576 DeleteObject(hBrush);
3578 /* nothing to draw, return here */
3579 if(GETITEMCOUNT(infoPtr) == 0)
3582 LISTVIEW_GetOrigin(hwnd, &ptOrigin);
3583 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
3585 if (cdmode & CDRF_NOTIFYITEMDRAW)
3586 cditemmode = LISTVIEW_SendCustomDrawItemNotify (hwnd, hdc, i, 0,
3588 if (cditemmode & CDRF_SKIPDEFAULT)
3591 LISTVIEW_GetItemPosition(hwnd, i, &ptPosition);
3592 ptPosition.x += ptOrigin.x;
3593 ptPosition.y += ptOrigin.y;
3595 if (ptPosition.y + infoPtr->nItemHeight > infoPtr->rcList.top)
3597 if (ptPosition.x + infoPtr->nItemWidth > infoPtr->rcList.left)
3599 if (ptPosition.y < infoPtr->rcList.bottom)
3601 if (ptPosition.x < infoPtr->rcList.right)
3603 rcItem.top = ptPosition.y;
3604 rcItem.left = ptPosition.x;
3605 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
3606 rcItem.right = rcItem.left + infoPtr->nItemWidth;
3607 if (bSmall == FALSE)
3609 LISTVIEW_DrawLargeItem(hwnd, hdc, i, rcItem, &SuggestedFocus);
3613 LISTVIEW_DrawItem(hwnd, hdc, i, rcItem, FALSE, &SuggestedFocus);
3618 if (LISTVIEW_GetItemState(hwnd,i,LVIS_FOCUSED) &&
3620 Rectangle(hdc, SuggestedFocus.left, SuggestedFocus.top,
3621 SuggestedFocus.right,SuggestedFocus.bottom);
3626 if (cditemmode & CDRF_NOTIFYPOSTPAINT)
3627 LISTVIEW_SendCustomDrawItemNotify(hwnd, hdc, i, 0,
3628 CDDS_ITEMPOSTPAINT);
3634 * Draws listview items.
3637 * [I] HWND : window handle
3638 * [I] HDC : device context handle
3643 static VOID LISTVIEW_Refresh(HWND hwnd, HDC hdc)
3645 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3646 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3652 GetClientRect(hwnd, &rect);
3653 cdmode = LISTVIEW_SendCustomDrawNotify(hwnd,CDDS_PREPAINT,hdc,rect);
3655 if (cdmode == CDRF_SKIPDEFAULT) return;
3658 hOldFont = SelectObject(hdc, infoPtr->hFont);
3660 /* select the dotted pen (for drawing the focus box) */
3661 hPen = CreatePen(PS_DOT, 1, 0);
3662 hOldPen = SelectObject(hdc, hPen);
3664 /* select transparent brush (for drawing the focus box) */
3665 SelectObject(hdc, GetStockObject(NULL_BRUSH));
3667 if (uView == LVS_LIST)
3669 LISTVIEW_RefreshList(hwnd, hdc, cdmode);
3671 else if (uView == LVS_REPORT)
3673 LISTVIEW_RefreshReport(hwnd, hdc, cdmode);
3675 else if (uView == LVS_SMALLICON)
3677 LISTVIEW_RefreshIcon(hwnd, hdc, TRUE, cdmode);
3679 else if (uView == LVS_ICON)
3681 LISTVIEW_RefreshIcon(hwnd, hdc, FALSE, cdmode);
3684 /* unselect objects */
3685 SelectObject(hdc, hOldFont);
3686 SelectObject(hdc, hOldPen);
3691 if (cdmode & CDRF_NOTIFYPOSTPAINT)
3692 LISTVIEW_SendCustomDrawNotify(hwnd, CDDS_POSTPAINT, hdc, rect);
3698 * Calculates the approximate width and height of a given number of items.
3701 * [I] HWND : window handle
3702 * [I] INT : number of items
3707 * Returns a DWORD. The width in the low word and the height in high word.
3709 static LRESULT LISTVIEW_ApproximateViewRect(HWND hwnd, INT nItemCount,
3710 WORD wWidth, WORD wHeight)
3712 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3713 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3714 INT nItemCountPerColumn = 1;
3715 INT nColumnCount = 0;
3716 DWORD dwViewRect = 0;
3718 if (nItemCount == -1)
3720 nItemCount = GETITEMCOUNT(infoPtr);
3723 if (uView == LVS_LIST)
3725 if (wHeight == 0xFFFF)
3727 /* use current height */
3728 wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
3731 if (wHeight < infoPtr->nItemHeight)
3733 wHeight = infoPtr->nItemHeight;
3738 if (infoPtr->nItemHeight > 0)
3740 nItemCountPerColumn = wHeight / infoPtr->nItemHeight;
3741 if (nItemCountPerColumn == 0)
3743 nItemCountPerColumn = 1;
3746 if (nItemCount % nItemCountPerColumn != 0)
3748 nColumnCount = nItemCount / nItemCountPerColumn;
3752 nColumnCount = nItemCount / nItemCountPerColumn + 1;
3757 /* Microsoft padding magic */
3758 wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2;
3759 wWidth = nColumnCount * infoPtr->nItemWidth + 2;
3761 dwViewRect = MAKELONG(wWidth, wHeight);
3763 else if (uView == LVS_REPORT)
3767 else if (uView == LVS_SMALLICON)
3771 else if (uView == LVS_ICON)
3781 * Arranges listview items in icon display mode.
3784 * [I] HWND : window handle
3785 * [I] INT : alignment code
3791 static LRESULT LISTVIEW_Arrange(HWND hwnd, INT nAlignCode)
3793 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3794 BOOL bResult = FALSE;
3796 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
3809 case LVA_SNAPTOGRID:
3818 /* << LISTVIEW_CreateDragImage >> */
3823 * Removes all listview items and subitems.
3826 * [I] HWND : window handle
3832 static LRESULT LISTVIEW_DeleteAllItems(HWND hwnd)
3834 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3835 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
3836 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3837 UINT uView = lStyle & LVS_TYPEMASK;
3838 LISTVIEW_ITEM *lpItem;
3839 LISTVIEW_SUBITEM *lpSubItem;
3842 BOOL bResult = FALSE;
3847 TRACE("(hwnd=%x,)\n", hwnd);
3848 LISTVIEW_RemoveAllSelections(hwnd);
3850 if (lStyle & LVS_OWNERDATA)
3852 infoPtr->hdpaItems->nItemCount = 0;
3853 InvalidateRect(hwnd, NULL, TRUE);
3857 if (GETITEMCOUNT(infoPtr) > 0)
3859 /* initialize memory */
3860 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
3862 /* send LVN_DELETEALLITEMS notification */
3863 nmlv.hdr.hwndFrom = hwnd;
3864 nmlv.hdr.idFrom = lCtrlId;
3865 nmlv.hdr.code = LVN_DELETEALLITEMS;
3868 /* verify if subsequent LVN_DELETEITEM notifications should be
3870 bSuppress = ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
3872 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
3874 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
3875 if (hdpaSubItems != NULL)
3877 for (j = 1; j < hdpaSubItems->nItemCount; j++)
3879 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, j);
3880 if (lpSubItem != NULL)
3882 /* free subitem string */
3883 if ((lpSubItem->pszText != NULL) &&
3884 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
3886 COMCTL32_Free(lpSubItem->pszText);
3890 COMCTL32_Free(lpSubItem);
3894 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3897 if (bSuppress == FALSE)
3899 /* send LVN_DELETEITEM notification */
3900 nmlv.hdr.code = LVN_DELETEITEM;
3902 nmlv.lParam = lpItem->lParam;
3903 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
3906 /* free item string */
3907 if ((lpItem->pszText != NULL) &&
3908 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
3910 COMCTL32_Free(lpItem->pszText);
3914 COMCTL32_Free(lpItem);
3917 DPA_Destroy(hdpaSubItems);
3921 /* reinitialize listview memory */
3922 bResult = DPA_DeleteAllPtrs(infoPtr->hdpaItems);
3924 /* align items (set position of each item) */
3925 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
3927 if (lStyle & LVS_ALIGNLEFT)
3929 LISTVIEW_AlignLeft(hwnd);
3933 LISTVIEW_AlignTop(hwnd);
3937 LISTVIEW_UpdateScroll(hwnd);
3939 /* invalidate client area (optimization needed) */
3940 InvalidateRect(hwnd, NULL, TRUE);
3948 * Removes a column from the listview control.
3951 * [I] HWND : window handle
3952 * [I] INT : column index
3958 static LRESULT LISTVIEW_DeleteColumn(HWND hwnd, INT nColumn)
3960 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3961 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3962 BOOL bResult = FALSE;
3964 if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) != FALSE)
3966 bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
3968 /* Need to reset the item width when deleting a column */
3969 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
3971 /* reset scroll parameters */
3972 if (uView == LVS_REPORT)
3974 /* update scrollbar(s) */
3975 LISTVIEW_UpdateScroll(hwnd);
3977 /* refresh client area */
3978 InvalidateRect(hwnd, NULL, FALSE);
3987 * Removes an item from the listview control.
3990 * [I] HWND : window handle
3991 * [I] INT : item index
3997 static LRESULT LISTVIEW_DeleteItem(HWND hwnd, INT nItem)
3999 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4000 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4001 UINT uView = lStyle & LVS_TYPEMASK;
4002 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
4004 BOOL bResult = FALSE;
4006 LISTVIEW_ITEM *lpItem;
4007 LISTVIEW_SUBITEM *lpSubItem;
4011 TRACE("(hwnd=%x,nItem=%d)\n", hwnd, nItem);
4013 /* remove it from the selection range */
4014 ZeroMemory(&item,sizeof(LVITEMA));
4015 item.stateMask = LVIS_SELECTED;
4016 LISTVIEW_SetItemState(hwnd,nItem,&item);
4018 LISTVIEW_ShiftSelections(hwnd,nItem,-1);
4020 if (lStyle & LVS_OWNERDATA)
4022 infoPtr->hdpaItems->nItemCount --;
4023 InvalidateRect(hwnd, NULL, TRUE);
4027 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4029 /* initialize memory */
4030 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
4032 hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem);
4033 if (hdpaSubItems != NULL)
4035 for (i = 1; i < hdpaSubItems->nItemCount; i++)
4037 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
4038 if (lpSubItem != NULL)
4040 /* free item string */
4041 if ((lpSubItem->pszText != NULL) &&
4042 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
4044 COMCTL32_Free(lpSubItem->pszText);
4048 COMCTL32_Free(lpSubItem);
4052 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
4055 /* send LVN_DELETEITEM notification */
4056 nmlv.hdr.hwndFrom = hwnd;
4057 nmlv.hdr.idFrom = lCtrlId;
4058 nmlv.hdr.code = LVN_DELETEITEM;
4060 nmlv.lParam = lpItem->lParam;
4061 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId,
4064 /* free item string */
4065 if ((lpItem->pszText != NULL) &&
4066 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
4068 COMCTL32_Free(lpItem->pszText);
4072 COMCTL32_Free(lpItem);
4075 bResult = DPA_Destroy(hdpaSubItems);
4078 /* align items (set position of each item) */
4079 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4081 if (lStyle & LVS_ALIGNLEFT)
4083 LISTVIEW_AlignLeft(hwnd);
4087 LISTVIEW_AlignTop(hwnd);
4091 /* If this item had focus change focus to next or previous item */
4092 if (GETITEMCOUNT(infoPtr) > 0)
4094 int sItem = nItem < GETITEMCOUNT(infoPtr) ? nItem : nItem - 1;
4095 if (infoPtr->nFocusedItem == nItem)
4096 LISTVIEW_SetItemFocus(hwnd, sItem);
4099 infoPtr->nFocusedItem = -1;
4101 LISTVIEW_UpdateScroll(hwnd);
4103 /* refresh client area */
4104 InvalidateRect(hwnd, NULL, TRUE);
4113 * Return edit control handle of current edit label
4116 * [I] HWND : window handle
4122 static LRESULT LISTVIEW_GetEditControl(hwnd)
4124 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4125 return infoPtr->hwndEdit;
4131 * Callback implementation for editlabel control
4134 * [I] HWND : window handle
4135 * [I] LPSTR : modified text
4136 * [I] DWORD : item index
4143 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem)
4145 NMLVDISPINFOA dispInfo;
4146 LISTVIEW_ITEM *lpItem;
4147 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
4148 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4149 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4151 BOOL bUpdateItemText;
4152 LISTVIEW_ITEM lvItemRef;
4155 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
4157 if (!(lStyle & LVS_OWNERDATA))
4159 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
4162 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
4167 ZeroMemory(&lvItemRef,sizeof(LISTVIEW_ITEM));
4168 ZeroMemory(&item,sizeof(LVITEMA));
4171 item.mask = LVIF_PARAM | LVIF_STATE;
4172 ListView_GetItemA(hwnd,&item);
4173 lvItemRef.state = item.state;
4174 lvItemRef.iImage = item.iImage;
4175 lvItemRef.lParam = item.lParam;
4176 lpItem = &lvItemRef;
4179 dispInfo.hdr.hwndFrom = hwnd;
4180 dispInfo.hdr.idFrom = nCtrlId;
4181 dispInfo.hdr.code = LVN_ENDLABELEDITA;
4182 dispInfo.item.mask = 0;
4183 dispInfo.item.iItem = nItem;
4184 dispInfo.item.state = lpItem->state;
4185 dispInfo.item.stateMask = 0;
4186 dispInfo.item.pszText = pszText;
4187 dispInfo.item.cchTextMax = pszText ? strlen(pszText) : 0;
4188 dispInfo.item.iImage = lpItem->iImage;
4189 dispInfo.item.lParam = lpItem->lParam;
4190 infoPtr->hwndEdit = 0;
4192 bUpdateItemText = ListView_Notify(GetParent(hwnd), nCtrlId, &dispInfo);
4194 /* Do we need to update the Item Text */
4197 if ((lpItem->pszText != LPSTR_TEXTCALLBACKA)&&(!(lStyle & LVS_OWNERDATA)))
4199 Str_SetPtrA(&lpItem->pszText, pszText);
4208 * Begin in place editing of specified list view item
4211 * [I] HWND : window handle
4212 * [I] INT : item index
4219 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem)
4221 NMLVDISPINFOA dispInfo;
4223 LISTVIEW_ITEM *lpItem;
4225 HINSTANCE hinst = GetWindowLongA(hwnd, GWL_HINSTANCE);
4226 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
4227 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4229 CHAR szDispText[DISP_TEXT_SIZE];
4230 LVITEMA lvItem,item;
4231 LISTVIEW_ITEM lvItemRef;
4232 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4234 if (~GetWindowLongA(hwnd, GWL_STYLE) & LVS_EDITLABELS)
4237 /* Is the EditBox still there, if so remove it */
4238 if(infoPtr->hwndEdit != 0)
4243 LISTVIEW_SetSelection(hwnd, nItem);
4244 LISTVIEW_SetItemFocus(hwnd, nItem);
4246 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
4247 if (!(lStyle & LVS_OWNERDATA))
4249 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
4252 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
4257 ZeroMemory(&lvItemRef,sizeof(LISTVIEW_ITEM));
4258 ZeroMemory(&item,sizeof(LVITEMA));
4261 item.mask = LVIF_PARAM | LVIF_STATE;
4262 ListView_GetItemA(hwnd,&item);
4263 lvItemRef.iImage = item.iImage;
4264 lvItemRef.state = item.state;
4265 lvItemRef.lParam = item.lParam;
4266 lpItem = &lvItemRef;
4269 /* get information needed for drawing the item */
4270 ZeroMemory(&lvItem, sizeof(LVITEMA));
4271 lvItem.mask = LVIF_TEXT;
4272 lvItem.iItem = nItem;
4273 lvItem.iSubItem = 0;
4274 lvItem.cchTextMax = DISP_TEXT_SIZE;
4275 lvItem.pszText = szDispText;
4276 ListView_GetItemA(hwnd, &lvItem);
4278 dispInfo.hdr.hwndFrom = hwnd;
4279 dispInfo.hdr.idFrom = nCtrlId;
4280 dispInfo.hdr.code = LVN_BEGINLABELEDITA;
4281 dispInfo.item.mask = 0;
4282 dispInfo.item.iItem = nItem;
4283 dispInfo.item.state = lpItem->state;
4284 dispInfo.item.stateMask = 0;
4285 dispInfo.item.pszText = lvItem.pszText;
4286 dispInfo.item.cchTextMax = strlen(lvItem.pszText);
4287 dispInfo.item.iImage = lpItem->iImage;
4288 dispInfo.item.lParam = lpItem->lParam;
4290 if (ListView_LVNotify(GetParent(hwnd), nCtrlId, &dispInfo))
4293 rect.left = LVIR_LABEL;
4294 if (!LISTVIEW_GetItemRect(hwnd, nItem, &rect))
4297 if (!(hedit = CreateEditLabel(szDispText , WS_VISIBLE,
4298 rect.left-2, rect.top-1, 0,
4299 rect.bottom - rect.top+2,
4300 hwnd, hinst, LISTVIEW_EndEditLabel, nItem)))
4303 infoPtr->hwndEdit = hedit;
4305 SendMessageA(hedit, EM_SETSEL, 0, -1);
4313 * Ensures the specified item is visible, scrolling into view if necessary.
4316 * [I] HWND : window handle
4317 * [I] INT : item index
4318 * [I] BOOL : partially or entirely visible
4324 static BOOL LISTVIEW_EnsureVisible(HWND hwnd, INT nItem, BOOL bPartial)
4326 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4327 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4328 INT nScrollPosHeight = 0;
4329 INT nScrollPosWidth = 0;
4330 SCROLLINFO scrollInfo;
4332 BOOL bRedraw = FALSE;
4334 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
4335 scrollInfo.cbSize = sizeof(SCROLLINFO);
4336 scrollInfo.fMask = SIF_POS;
4338 /* ALWAYS bPartial == FALSE, FOR NOW! */
4340 rcItem.left = LVIR_BOUNDS;
4341 if (LISTVIEW_GetItemRect(hwnd, nItem, &rcItem) != FALSE)
4343 if (rcItem.left < infoPtr->rcList.left)
4345 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4349 if (uView == LVS_LIST)
4351 nScrollPosWidth = infoPtr->nItemWidth;
4352 rcItem.left += infoPtr->rcList.left;
4354 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4356 nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
4357 rcItem.left += infoPtr->rcList.left;
4360 /* When in LVS_REPORT view, the scroll position should
4362 if (nScrollPosWidth != 0)
4364 if (rcItem.left % nScrollPosWidth == 0)
4366 scrollInfo.nPos += rcItem.left / nScrollPosWidth;
4370 scrollInfo.nPos += rcItem.left / nScrollPosWidth - 1;
4373 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
4377 else if (rcItem.right > infoPtr->rcList.right)
4379 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4383 if (uView == LVS_LIST)
4385 rcItem.right -= infoPtr->rcList.right;
4386 nScrollPosWidth = infoPtr->nItemWidth;
4388 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4390 rcItem.right -= infoPtr->rcList.right;
4391 nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
4394 /* When in LVS_REPORT view, the scroll position should
4396 if (nScrollPosWidth != 0)
4398 if (rcItem.right % nScrollPosWidth == 0)
4400 scrollInfo.nPos += rcItem.right / nScrollPosWidth;
4404 scrollInfo.nPos += rcItem.right / nScrollPosWidth + 1;
4407 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
4412 if (rcItem.top < infoPtr->rcList.top)
4416 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4418 if (uView == LVS_REPORT)
4420 rcItem.top -= infoPtr->rcList.top;
4421 nScrollPosHeight = infoPtr->nItemHeight;
4423 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
4425 nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
4426 rcItem.top += infoPtr->rcList.top;
4429 if (rcItem.top % nScrollPosHeight == 0)
4431 scrollInfo.nPos += rcItem.top / nScrollPosHeight;
4435 scrollInfo.nPos += rcItem.top / nScrollPosHeight - 1;
4438 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
4441 else if (rcItem.bottom > infoPtr->rcList.bottom)
4445 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4447 if (uView == LVS_REPORT)
4449 rcItem.bottom -= infoPtr->rcList.bottom;
4450 nScrollPosHeight = infoPtr->nItemHeight;
4452 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
4454 nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
4455 rcItem.bottom -= infoPtr->rcList.bottom;
4458 if (rcItem.bottom % nScrollPosHeight == 0)
4460 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight;
4464 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight + 1;
4467 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
4473 InvalidateRect(hwnd,NULL,TRUE);
4479 * Retrieves the nearest item, given a position and a direction.
4482 * [I] HWND : window handle
4483 * [I] POINT : start position
4484 * [I] UINT : direction
4487 * Item index if successdful, -1 otherwise.
4489 static INT LISTVIEW_GetNearestItem(HWND hwnd, POINT pt, UINT vkDirection)
4491 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4492 LVHITTESTINFO lvHitTestInfo;
4496 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
4498 ZeroMemory(&lvHitTestInfo, sizeof(LVHITTESTINFO));
4499 LISTVIEW_GetOrigin(hwnd, &lvHitTestInfo.pt);
4500 lvHitTestInfo.pt.x += pt.x;
4501 lvHitTestInfo.pt.y += pt.y;
4505 if (vkDirection == VK_DOWN)
4507 lvHitTestInfo.pt.y += infoPtr->nItemHeight;
4509 else if (vkDirection == VK_UP)
4511 lvHitTestInfo.pt.y -= infoPtr->nItemHeight;
4513 else if (vkDirection == VK_LEFT)
4515 lvHitTestInfo.pt.x -= infoPtr->nItemWidth;
4517 else if (vkDirection == VK_RIGHT)
4519 lvHitTestInfo.pt.x += infoPtr->nItemWidth;
4522 if (PtInRect(&rcView, lvHitTestInfo.pt) == FALSE)
4528 nItem = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo);
4532 while (nItem == -1);
4540 * Searches for an item with specific characteristics.
4543 * [I] HWND : window handle
4544 * [I] INT : base item index
4545 * [I] LPLVFINDINFO : item information to look for
4548 * SUCCESS : index of item
4551 static LRESULT LISTVIEW_FindItem(HWND hwnd, INT nStart,
4552 LPLVFINDINFO lpFindInfo)
4554 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4556 CHAR szDispText[DISP_TEXT_SIZE];
4560 INT nLast = GETITEMCOUNT(infoPtr);
4562 if ((nItem >= -1) && (lpFindInfo != NULL))
4564 ZeroMemory(&lvItem, sizeof(LVITEMA));
4566 if (lpFindInfo->flags & LVFI_PARAM)
4568 lvItem.mask |= LVIF_PARAM;
4571 if (lpFindInfo->flags & LVFI_STRING)
4573 lvItem.mask |= LVIF_TEXT;
4574 lvItem.pszText = szDispText;
4575 lvItem.cchTextMax = DISP_TEXT_SIZE;
4578 if (lpFindInfo->flags & LVFI_PARTIAL)
4580 lvItem.mask |= LVIF_TEXT;
4581 lvItem.pszText = szDispText;
4582 lvItem.cchTextMax = DISP_TEXT_SIZE;
4585 if (lpFindInfo->flags & LVFI_WRAP)
4590 if (lpFindInfo->flags & LVFI_NEARESTXY)
4592 ptItem.x = lpFindInfo->pt.x;
4593 ptItem.y = lpFindInfo->pt.y;
4598 while (nItem < nLast)
4600 if (lpFindInfo->flags & LVFI_NEARESTXY)
4602 nItem = LISTVIEW_GetNearestItem(hwnd, ptItem,
4603 lpFindInfo->vkDirection);
4606 /* get position of the new item index */
4607 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) == FALSE)
4618 lvItem.iItem = nItem;
4619 lvItem.iSubItem = 0;
4620 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
4622 if (lvItem.mask & LVIF_TEXT)
4624 if (lpFindInfo->flags & LVFI_PARTIAL)
4626 if (strstr(lvItem.pszText, lpFindInfo->psz) == NULL)
4631 if (strcmp(lvItem.pszText, lpFindInfo->psz) != 0)
4636 if (lvItem.mask & LVIF_PARAM)
4638 if (lpFindInfo->lParam != lvItem.lParam)
4664 * Retrieves the background color of the listview control.
4667 * [I] HWND : window handle
4670 * COLORREF associated with the background.
4672 static LRESULT LISTVIEW_GetBkColor(HWND hwnd)
4674 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4676 return infoPtr->clrBk;
4681 * Retrieves the background image of the listview control.
4684 * [I] HWND : window handle
4685 * [O] LPLVMKBIMAGE : background image attributes
4691 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
4693 /* FIXME (listview, "empty stub!\n"); */
4699 * Retrieves the callback mask.
4702 * [I] HWND : window handle
4707 static UINT LISTVIEW_GetCallbackMask(HWND hwnd)
4709 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4711 return infoPtr->uCallbackMask;
4716 * Retrieves column attributes.
4719 * [I] HWND : window handle
4720 * [I] INT : column index
4721 * [IO] LPLVCOLUMNA : column information
4727 static LRESULT LISTVIEW_GetColumnA(HWND hwnd, INT nItem, LPLVCOLUMNA lpColumn)
4729 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4731 BOOL bResult = FALSE;
4733 if (lpColumn != NULL)
4735 /* initialize memory */
4736 ZeroMemory(&hdi, sizeof(HDITEMA));
4738 if (lpColumn->mask & LVCF_FMT)
4740 hdi.mask |= HDI_FORMAT;
4743 if (lpColumn->mask & LVCF_WIDTH)
4745 hdi.mask |= HDI_WIDTH;
4748 if (lpColumn->mask & LVCF_TEXT)
4750 hdi.mask |= HDI_TEXT;
4751 hdi.cchTextMax = lpColumn->cchTextMax;
4752 hdi.pszText = lpColumn->pszText;
4755 if (lpColumn->mask & LVCF_IMAGE)
4757 hdi.mask |= HDI_IMAGE;
4760 if (lpColumn->mask & LVCF_ORDER)
4762 hdi.mask |= HDI_ORDER;
4765 bResult = Header_GetItemA(infoPtr->hwndHeader, nItem, &hdi);
4766 if (bResult != FALSE)
4768 if (lpColumn->mask & LVCF_FMT)
4772 if (hdi.fmt & HDF_LEFT)
4774 lpColumn->fmt |= LVCFMT_LEFT;
4776 else if (hdi.fmt & HDF_RIGHT)
4778 lpColumn->fmt |= LVCFMT_RIGHT;
4780 else if (hdi.fmt & HDF_CENTER)
4782 lpColumn->fmt |= LVCFMT_CENTER;
4785 if (hdi.fmt & HDF_IMAGE)
4787 lpColumn->fmt |= LVCFMT_COL_HAS_IMAGES;
4790 if (hdi.fmt & HDF_BITMAP_ON_RIGHT)
4792 lpColumn->fmt |= LVCFMT_BITMAP_ON_RIGHT;
4796 if (lpColumn->mask & LVCF_WIDTH)
4798 lpColumn->cx = hdi.cxy;
4801 if (lpColumn->mask & LVCF_IMAGE)
4803 lpColumn->iImage = hdi.iImage;
4806 if (lpColumn->mask & LVCF_ORDER)
4808 lpColumn->iOrder = hdi.iOrder;
4816 /* LISTVIEW_GetColumnW */
4819 static LRESULT LISTVIEW_GetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
4821 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
4828 for (i = 0; i < iCount; i++)
4836 * Retrieves the column width.
4839 * [I] HWND : window handle
4840 * [I] int : column index
4843 * SUCCESS : column width
4846 static LRESULT LISTVIEW_GetColumnWidth(HWND hwnd, INT nColumn)
4848 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4849 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4850 INT nColumnWidth = 0;
4853 if (uView == LVS_LIST)
4855 nColumnWidth = infoPtr->nItemWidth;
4857 else if (uView == LVS_REPORT)
4859 /* get column width from header */
4860 ZeroMemory(&hdi, sizeof(HDITEMA));
4861 hdi.mask = HDI_WIDTH;
4862 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdi) != FALSE)
4864 nColumnWidth = hdi.cxy;
4868 return nColumnWidth;
4873 * In list or report display mode, retrieves the number of items that can fit
4874 * vertically in the visible area. In icon or small icon display mode,
4875 * retrieves the total number of visible items.
4878 * [I] HWND : window handle
4881 * Number of fully visible items.
4883 static LRESULT LISTVIEW_GetCountPerPage(HWND hwnd)
4885 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4886 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4889 if (uView == LVS_LIST)
4891 if (infoPtr->rcList.right > infoPtr->nItemWidth)
4893 nItemCount = LISTVIEW_GetCountPerRow(hwnd) *
4894 LISTVIEW_GetCountPerColumn(hwnd);
4897 else if (uView == LVS_REPORT)
4899 nItemCount = LISTVIEW_GetCountPerColumn(hwnd);
4903 nItemCount = GETITEMCOUNT(infoPtr);
4909 /* LISTVIEW_GetEditControl */
4913 * Retrieves the extended listview style.
4916 * [I] HWND : window handle
4919 * SUCCESS : previous style
4922 static LRESULT LISTVIEW_GetExtendedListViewStyle(HWND hwnd)
4924 LISTVIEW_INFO *infoPtr;
4926 /* make sure we can get the listview info */
4927 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
4930 return (infoPtr->dwExStyle);
4935 * Retrieves the handle to the header control.
4938 * [I] HWND : window handle
4943 static LRESULT LISTVIEW_GetHeader(HWND hwnd)
4945 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4947 return infoPtr->hwndHeader;
4950 /* LISTVIEW_GetHotCursor */
4954 * Returns the time that the mouse cursor must hover over an item
4955 * before it is selected.
4958 * [I] HWND : window handle
4961 * Returns the previously set hover time or (DWORD)-1 to indicate that the
4962 * hover time is set to the default hover time.
4964 static LRESULT LISTVIEW_GetHoverTime(HWND hwnd)
4966 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4968 return infoPtr->dwHoverTime;
4973 * Retrieves an image list handle.
4976 * [I] HWND : window handle
4977 * [I] INT : image list identifier
4980 * SUCCESS : image list handle
4983 static LRESULT LISTVIEW_GetImageList(HWND hwnd, INT nImageList)
4985 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4986 HIMAGELIST himl = NULL;
4991 himl = infoPtr->himlNormal;
4994 himl = infoPtr->himlSmall;
4997 himl = infoPtr->himlState;
5001 return (LRESULT)himl;
5004 /* LISTVIEW_GetISearchString */
5008 * Retrieves item attributes.
5011 * [I] HWND : window handle
5012 * [IO] LPLVITEMA : item info
5013 * [I] internal : if true then we will use tricks that avoid copies
5014 * but are not compatible with the regular interface
5020 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem, BOOL internal)
5022 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5023 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
5024 NMLVDISPINFOA dispInfo;
5025 LISTVIEW_SUBITEM *lpSubItem;
5026 LISTVIEW_ITEM *lpItem;
5030 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5031 /* In the following:
5032 * lpLVItem describes the information requested by the user
5033 * lpItem/lpSubItem is what we have
5034 * dispInfo is a structure we use to request the missing
5035 * information from the application
5038 TRACE("(hwnd=%x, lpLVItem=%p)\n", hwnd, lpLVItem);
5040 if ((lpLVItem == NULL) ||
5041 (lpLVItem->iItem < 0) ||
5042 (lpLVItem->iItem >= GETITEMCOUNT(infoPtr))
5046 if (lStyle & LVS_OWNERDATA)
5048 if (lpLVItem->mask & ~LVIF_STATE)
5050 dispInfo.hdr.hwndFrom = hwnd;
5051 dispInfo.hdr.idFrom = lCtrlId;
5052 dispInfo.hdr.code = LVN_GETDISPINFOA;
5053 memcpy(&dispInfo.item,lpLVItem,sizeof(LVITEMA));
5055 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
5056 memcpy(lpLVItem,&dispInfo.item,sizeof(LVITEMA));
5059 if ((lpLVItem->mask & LVIF_STATE)&&(lpLVItem->iSubItem == 0))
5061 lpLVItem->state = 0;
5062 if (infoPtr->nFocusedItem == lpLVItem->iItem)
5063 lpLVItem->state |= LVIS_FOCUSED;
5064 if (LISTVIEW_IsSelected(hwnd,lpLVItem->iItem))
5065 lpLVItem->state |= LVIS_SELECTED;
5072 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
5073 if (hdpaSubItems == NULL)
5076 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
5080 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
5081 if (lpLVItem->iSubItem == 0)
5083 piImage=&lpItem->iImage;
5084 ppszText=&lpItem->pszText;
5085 if ((infoPtr->uCallbackMask != 0) && (lpLVItem->mask & LVIF_STATE))
5087 dispInfo.item.mask |= LVIF_STATE;
5088 dispInfo.item.stateMask = infoPtr->uCallbackMask;
5093 lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem);
5094 if (lpSubItem != NULL)
5096 piImage=&lpSubItem->iImage;
5097 ppszText=&lpSubItem->pszText;
5106 if ((lpLVItem->mask & LVIF_IMAGE) &&
5107 ((piImage==NULL) || (*piImage == I_IMAGECALLBACK)))
5109 dispInfo.item.mask |= LVIF_IMAGE;
5112 if ((lpLVItem->mask & LVIF_TEXT) &&
5113 ((ppszText==NULL) || (*ppszText == LPSTR_TEXTCALLBACKA)))
5115 dispInfo.item.mask |= LVIF_TEXT;
5116 dispInfo.item.pszText = lpLVItem->pszText;
5117 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
5120 if (dispInfo.item.mask != 0)
5122 /* We don't have all the requested info, query the application */
5123 dispInfo.hdr.hwndFrom = hwnd;
5124 dispInfo.hdr.idFrom = lCtrlId;
5125 dispInfo.hdr.code = LVN_GETDISPINFOA;
5126 dispInfo.item.iItem = lpLVItem->iItem;
5127 dispInfo.item.iSubItem = lpLVItem->iSubItem;
5128 dispInfo.item.lParam = lpItem->lParam;
5129 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
5132 if (dispInfo.item.mask & LVIF_IMAGE)
5134 lpLVItem->iImage = dispInfo.item.iImage;
5136 else if (lpLVItem->mask & LVIF_IMAGE)
5138 lpLVItem->iImage = *piImage;
5141 if (dispInfo.item.mask & LVIF_PARAM)
5143 lpLVItem->lParam = dispInfo.item.lParam;
5145 else if (lpLVItem->mask & LVIF_PARAM)
5147 lpLVItem->lParam = lpItem->lParam;
5150 if (dispInfo.item.mask & LVIF_TEXT)
5152 if ((dispInfo.item.mask & LVIF_DI_SETITEM) && (ppszText != NULL))
5154 Str_SetPtrA(ppszText, dispInfo.item.pszText);
5156 /* If lpLVItem->pszText==dispInfo.item.pszText a copy is unnecessary, but */
5157 /* some apps give a new pointer in ListView_Notify so we can't be sure. */
5158 if (lpLVItem->pszText!=dispInfo.item.pszText) {
5159 lstrcpynA(lpLVItem->pszText, dispInfo.item.pszText, lpLVItem->cchTextMax);
5162 else if (lpLVItem->mask & LVIF_TEXT)
5166 lpLVItem->pszText=*ppszText;
5168 lstrcpynA(lpLVItem->pszText, *ppszText, lpLVItem->cchTextMax);
5172 if (lpLVItem->iSubItem == 0)
5174 if (dispInfo.item.mask & LVIF_STATE)
5176 lpLVItem->state = lpItem->state;
5177 lpLVItem->state &= ~dispInfo.item.stateMask;
5178 lpLVItem->state |= (dispInfo.item.state & dispInfo.item.stateMask);
5180 lpLVItem->state &= ~LVIS_SELECTED;
5181 if ((dispInfo.item.stateMask & LVIS_SELECTED) &&
5182 (LISTVIEW_IsSelected(hwnd,dispInfo.item.iItem)))
5183 lpLVItem->state |= LVIS_SELECTED;
5185 else if (lpLVItem->mask & LVIF_STATE)
5187 lpLVItem->state = lpItem->state & lpLVItem->stateMask;
5189 lpLVItem->state &= ~LVIS_SELECTED;
5190 if ((lpLVItem->stateMask & LVIS_SELECTED) &&
5191 (LISTVIEW_IsSelected(hwnd,lpLVItem->iItem)))
5192 lpLVItem->state |= LVIS_SELECTED;
5195 if (lpLVItem->mask & LVIF_PARAM)
5197 lpLVItem->lParam = lpItem->lParam;
5200 if (lpLVItem->mask & LVIF_INDENT)
5202 lpLVItem->iIndent = lpItem->iIndent;
5209 /* LISTVIEW_GetItemW */
5210 /* LISTVIEW_GetHotCursor */
5214 * Retrieves the index of the hot item.
5217 * [I] HWND : window handle
5220 * SUCCESS : hot item index
5221 * FAILURE : -1 (no hot item)
5223 static LRESULT LISTVIEW_GetHotItem(HWND hwnd)
5225 LISTVIEW_INFO *infoPtr;
5227 /* make sure we can get the listview info */
5228 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5231 return (infoPtr->nHotItem);
5234 /* LISTVIEW_GetHoverTime */
5238 * Retrieves the number of items in the listview control.
5241 * [I] HWND : window handle
5246 static LRESULT LISTVIEW_GetItemCount(HWND hwnd)
5248 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5250 return GETITEMCOUNT(infoPtr);
5255 * Retrieves the position (upper-left) of the listview control item.
5258 * [I] HWND : window handle
5259 * [I] INT : item index
5260 * [O] LPPOINT : coordinate information
5266 static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem,
5267 LPPOINT lpptPosition)
5269 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5270 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5271 BOOL bResult = FALSE;
5273 LISTVIEW_ITEM *lpItem;
5274 INT nCountPerColumn;
5277 TRACE("(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd, nItem,
5280 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
5281 (lpptPosition != NULL))
5283 if (uView == LVS_LIST)
5286 nItem = nItem - ListView_GetTopIndex(hwnd);
5287 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
5290 nRow = nItem % nCountPerColumn;
5293 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
5294 lpptPosition->y = 0;
5298 lpptPosition->x = (nItem / nCountPerColumn -1) * infoPtr->nItemWidth;
5299 lpptPosition->y = (nRow + nCountPerColumn) * infoPtr->nItemHeight;
5304 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
5305 lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight;
5308 else if (uView == LVS_REPORT)
5311 lpptPosition->x = REPORT_MARGINX;
5312 lpptPosition->y = ((nItem - ListView_GetTopIndex(hwnd)) *
5313 infoPtr->nItemHeight) + infoPtr->rcList.top;
5317 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
5318 if (hdpaSubItems != NULL)
5320 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
5324 lpptPosition->x = lpItem->ptPosition.x;
5325 lpptPosition->y = lpItem->ptPosition.y;
5335 * Retrieves the bounding rectangle for a listview control item.
5338 * [I] HWND : window handle
5339 * [I] INT : item index
5340 * [IO] LPRECT : bounding rectangle coordinates
5346 static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc)
5348 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5349 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5350 BOOL bResult = FALSE;
5361 TRACE("(hwnd=%x, nItem=%d, lprc=%p)\n", hwnd, nItem, lprc);
5363 if (uView & LVS_REPORT)
5365 ZeroMemory(&lvItem, sizeof(LVITEMA));
5366 lvItem.mask = LVIF_INDENT;
5367 lvItem.iItem = nItem;
5368 lvItem.iSubItem = 0;
5369 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
5372 if (lvItem.iIndent>0 && infoPtr->iconSize.cx > 0)
5374 nIndent = infoPtr->iconSize.cx * lvItem.iIndent;
5382 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL))
5384 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) != FALSE)
5389 if (uView == LVS_ICON)
5391 if (infoPtr->himlNormal != NULL)
5393 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5396 lprc->left = ptItem.x + ptOrigin.x;
5397 lprc->top = ptItem.y + ptOrigin.y;
5398 lprc->right = lprc->left + infoPtr->iconSize.cx;
5399 lprc->bottom = (lprc->top + infoPtr->iconSize.cy +
5400 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
5404 else if (uView == LVS_SMALLICON)
5406 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5409 lprc->left = ptItem.x + ptOrigin.x;
5410 lprc->top = ptItem.y + ptOrigin.y;
5411 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5413 if (infoPtr->himlState != NULL)
5414 lprc->left += infoPtr->iconSize.cx;
5416 if (infoPtr->himlSmall != NULL)
5417 lprc->right = lprc->left + infoPtr->iconSize.cx;
5419 lprc->right = lprc->left;
5425 lprc->left = ptItem.x;
5426 if (uView & LVS_REPORT)
5427 lprc->left += nIndent;
5428 lprc->top = ptItem.y;
5429 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5431 if (infoPtr->himlState != NULL)
5433 lprc->left += infoPtr->iconSize.cx;
5436 if (infoPtr->himlSmall != NULL)
5438 lprc->right = lprc->left + infoPtr->iconSize.cx;
5442 lprc->right = lprc->left;
5448 if (uView == LVS_ICON)
5450 if (infoPtr->himlNormal != NULL)
5452 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5455 lprc->left = ptItem.x + ptOrigin.x;
5456 lprc->top = (ptItem.y + ptOrigin.y + infoPtr->iconSize.cy +
5457 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
5458 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5459 if (infoPtr->iconSpacing.cx - nLabelWidth > 1)
5461 lprc->left += (infoPtr->iconSpacing.cx - nLabelWidth) / 2;
5462 lprc->right = lprc->left + nLabelWidth;
5467 lprc->right = lprc->left + infoPtr->iconSpacing.cx - 1;
5471 hOldFont = SelectObject(hdc, infoPtr->hFont);
5472 GetTextMetricsA(hdc, &tm);
5473 lprc->bottom = lprc->top + tm.tmHeight + HEIGHT_PADDING;
5474 SelectObject(hdc, hOldFont);
5475 ReleaseDC(hwnd, hdc);
5479 else if (uView == LVS_SMALLICON)
5481 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5484 nLeftPos = lprc->left = ptItem.x + ptOrigin.x;
5485 lprc->top = ptItem.y + ptOrigin.y;
5486 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5488 if (infoPtr->himlState != NULL)
5490 lprc->left += infoPtr->iconSize.cx;
5493 if (infoPtr->himlSmall != NULL)
5495 lprc->left += infoPtr->iconSize.cx;
5498 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5499 nLabelWidth += TRAILING_PADDING;
5500 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5502 lprc->right = lprc->left + nLabelWidth;
5506 lprc->right = nLeftPos + infoPtr->nItemWidth;
5513 if (uView & LVS_REPORT)
5514 nLeftPos = lprc->left = ptItem.x + nIndent;
5516 nLeftPos = lprc->left = ptItem.x;
5517 lprc->top = ptItem.y;
5518 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5520 if (infoPtr->himlState != NULL)
5522 lprc->left += infoPtr->iconSize.cx;
5525 if (infoPtr->himlSmall != NULL)
5527 lprc->left += infoPtr->iconSize.cx;
5530 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5531 nLabelWidth += TRAILING_PADDING;
5532 if (infoPtr->himlSmall)
5533 nLabelWidth += IMAGE_PADDING;
5534 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5536 lprc->right = lprc->left + nLabelWidth;
5540 lprc->right = nLeftPos + infoPtr->nItemWidth;
5546 if (uView == LVS_ICON)
5548 if (infoPtr->himlNormal != NULL)
5550 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5553 lprc->left = ptItem.x + ptOrigin.x;
5554 lprc->top = ptItem.y + ptOrigin.y;
5555 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
5556 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
5560 else if (uView == LVS_SMALLICON)
5562 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5565 lprc->left = ptItem.x + ptOrigin.x;
5566 lprc->right = lprc->left;
5567 lprc->top = ptItem.y + ptOrigin.y;
5568 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5569 if (infoPtr->himlState != NULL)
5570 lprc->right += infoPtr->iconSize.cx;
5571 if (infoPtr->himlSmall != NULL)
5572 lprc->right += infoPtr->iconSize.cx;
5574 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5575 nLabelWidth += TRAILING_PADDING;
5576 if (infoPtr->himlSmall)
5577 nLabelWidth += IMAGE_PADDING;
5578 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
5580 lprc->right += nLabelWidth;
5584 lprc->right = lprc->left + infoPtr->nItemWidth;
5591 lprc->left = ptItem.x;
5592 if (!(infoPtr->dwExStyle&LVS_EX_FULLROWSELECT) && uView&LVS_REPORT)
5593 lprc->left += nIndent;
5594 lprc->right = lprc->left;
5595 lprc->top = ptItem.y;
5596 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5598 if (infoPtr->dwExStyle & LVS_EX_FULLROWSELECT)
5601 int nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
5602 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
5604 lprc->right = max(lprc->left, br.right - REPORT_MARGINX);
5608 if (infoPtr->himlState != NULL)
5610 lprc->right += infoPtr->iconSize.cx;
5613 if (infoPtr->himlSmall != NULL)
5615 lprc->right += infoPtr->iconSize.cx;
5618 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5619 nLabelWidth += TRAILING_PADDING;
5620 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
5622 lprc->right += nLabelWidth;
5626 lprc->right = lprc->left + infoPtr->nItemWidth;
5632 case LVIR_SELECTBOUNDS:
5633 if (uView == LVS_ICON)
5635 if (infoPtr->himlNormal != NULL)
5637 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5640 lprc->left = ptItem.x + ptOrigin.x;
5641 lprc->top = ptItem.y + ptOrigin.y;
5642 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
5643 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
5647 else if (uView == LVS_SMALLICON)
5649 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5652 nLeftPos= lprc->left = ptItem.x + ptOrigin.x;
5653 lprc->top = ptItem.y + ptOrigin.y;
5654 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5656 if (infoPtr->himlState != NULL)
5658 lprc->left += infoPtr->iconSize.cx;
5661 lprc->right = lprc->left;
5663 if (infoPtr->himlSmall != NULL)
5665 lprc->right += infoPtr->iconSize.cx;
5668 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5669 nLabelWidth += TRAILING_PADDING;
5670 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5672 lprc->right += nLabelWidth;
5676 lprc->right = nLeftPos + infoPtr->nItemWidth;
5683 if (!(infoPtr->dwExStyle&LVS_EX_FULLROWSELECT) && (uView&LVS_REPORT))
5684 nLeftPos = lprc->left = ptItem.x + nIndent;
5686 nLeftPos = lprc->left = ptItem.x;
5687 lprc->top = ptItem.y;
5688 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5690 if (infoPtr->himlState != NULL)
5692 lprc->left += infoPtr->iconSize.cx;
5695 lprc->right = lprc->left;
5697 if (infoPtr->dwExStyle & LVS_EX_FULLROWSELECT)
5700 int nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
5701 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
5703 lprc->right = max(lprc->left, br.right - REPORT_MARGINX);
5707 if (infoPtr->himlSmall != NULL)
5709 lprc->right += infoPtr->iconSize.cx;
5712 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5713 nLabelWidth += TRAILING_PADDING;
5714 if (infoPtr->himlSmall)
5715 nLabelWidth += IMAGE_PADDING;
5716 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5718 lprc->right += nLabelWidth;
5722 lprc->right = nLeftPos + infoPtr->nItemWidth;
5735 * Retrieves the width of a label.
5738 * [I] HWND : window handle
5741 * SUCCESS : string width (in pixels)
5744 static INT LISTVIEW_GetLabelWidth(HWND hwnd, INT nItem)
5746 CHAR szDispText[DISP_TEXT_SIZE];
5747 INT nLabelWidth = 0;
5750 TRACE("(hwnd=%x, nItem=%d)\n", hwnd, nItem);
5752 ZeroMemory(&lvItem, sizeof(LVITEMA));
5753 lvItem.mask = LVIF_TEXT;
5754 lvItem.iItem = nItem;
5755 lvItem.cchTextMax = DISP_TEXT_SIZE;
5756 lvItem.pszText = szDispText;
5757 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
5759 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
5767 * Retrieves the spacing between listview control items.
5770 * [I] HWND : window handle
5771 * [I] BOOL : flag for small or large icon
5774 * Horizontal + vertical spacing
5776 static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall)
5778 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5781 if (bSmall == FALSE)
5783 lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
5787 /* TODO: need to store width of smallicon item */
5788 lResult = MAKELONG(0, infoPtr->nItemHeight);
5796 * Retrieves the state of a listview control item.
5799 * [I] HWND : window handle
5800 * [I] INT : item index
5801 * [I] UINT : state mask
5804 * State specified by the mask.
5806 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask)
5808 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5812 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5814 ZeroMemory(&lvItem, sizeof(LVITEMA));
5815 lvItem.iItem = nItem;
5816 lvItem.stateMask = uMask;
5817 lvItem.mask = LVIF_STATE;
5818 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
5820 uState = lvItem.state;
5829 * Retrieves the text of a listview control item or subitem.
5832 * [I] HWND : window handle
5833 * [I] INT : item index
5834 * [IO] LPLVITEMA : item information
5837 * SUCCESS : string length
5840 static LRESULT LISTVIEW_GetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5842 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5845 if (lpLVItem != NULL)
5847 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5849 lpLVItem->mask = LVIF_TEXT;
5850 lpLVItem->iItem = nItem;
5851 if (LISTVIEW_GetItemA(hwnd, lpLVItem, FALSE) != FALSE)
5853 nLength = lstrlenA(lpLVItem->pszText);
5863 * Searches for an item based on properties + relationships.
5866 * [I] HWND : window handle
5867 * [I] INT : item index
5868 * [I] INT : relationship flag
5871 * SUCCESS : item index
5874 static LRESULT LISTVIEW_GetNextItem(HWND hwnd, INT nItem, UINT uFlags)
5876 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5877 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5879 LVFINDINFO lvFindInfo;
5880 INT nCountPerColumn;
5883 if ((nItem >= -1) && (nItem < GETITEMCOUNT(infoPtr)))
5885 ZeroMemory(&lvFindInfo, sizeof(LVFINDINFO));
5887 if (uFlags & LVNI_CUT)
5890 if (uFlags & LVNI_DROPHILITED)
5891 uMask |= LVIS_DROPHILITED;
5893 if (uFlags & LVNI_FOCUSED)
5894 uMask |= LVIS_FOCUSED;
5896 if (uFlags & LVNI_SELECTED)
5897 uMask |= LVIS_SELECTED;
5899 if (uFlags & LVNI_ABOVE)
5901 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
5906 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5912 lvFindInfo.flags = LVFI_NEARESTXY;
5913 lvFindInfo.vkDirection = VK_UP;
5914 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5915 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5917 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5922 else if (uFlags & LVNI_BELOW)
5924 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
5926 while (nItem < GETITEMCOUNT(infoPtr))
5929 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5935 lvFindInfo.flags = LVFI_NEARESTXY;
5936 lvFindInfo.vkDirection = VK_DOWN;
5937 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5938 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5940 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5945 else if (uFlags & LVNI_TOLEFT)
5947 if (uView == LVS_LIST)
5949 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
5950 while (nItem - nCountPerColumn >= 0)
5952 nItem -= nCountPerColumn;
5953 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5957 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
5959 lvFindInfo.flags = LVFI_NEARESTXY;
5960 lvFindInfo.vkDirection = VK_LEFT;
5961 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5962 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5964 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5969 else if (uFlags & LVNI_TORIGHT)
5971 if (uView == LVS_LIST)
5973 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
5974 while (nItem + nCountPerColumn < GETITEMCOUNT(infoPtr))
5976 nItem += nCountPerColumn;
5977 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5981 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
5983 lvFindInfo.flags = LVFI_NEARESTXY;
5984 lvFindInfo.vkDirection = VK_RIGHT;
5985 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5986 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5988 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5997 /* search by index */
5998 for (i = nItem; i < GETITEMCOUNT(infoPtr); i++)
6000 if ((ListView_GetItemState(hwnd, i, uMask) & uMask) == uMask)
6009 /* LISTVIEW_GetNumberOfWorkAreas */
6013 * Retrieves the origin coordinates when in icon or small icon display mode.
6016 * [I] HWND : window handle
6017 * [O] LPPOINT : coordinate information
6023 static LRESULT LISTVIEW_GetOrigin(HWND hwnd, LPPOINT lpptOrigin)
6025 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6026 UINT uView = lStyle & LVS_TYPEMASK;
6027 BOOL bResult = FALSE;
6029 TRACE("(hwnd=%x, lpptOrigin=%p)\n", hwnd, lpptOrigin);
6031 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
6033 SCROLLINFO scrollInfo;
6034 ZeroMemory(lpptOrigin, sizeof(POINT));
6035 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
6036 scrollInfo.cbSize = sizeof(SCROLLINFO);
6038 if (lStyle & WS_HSCROLL)
6040 scrollInfo.fMask = SIF_POS;
6041 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
6043 lpptOrigin->x = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
6047 if (lStyle & WS_VSCROLL)
6049 scrollInfo.fMask = SIF_POS;
6050 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
6052 lpptOrigin->y = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
6064 * Retrieves the number of items that are marked as selected.
6067 * [I] HWND : window handle
6070 * Number of items selected.
6072 static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd)
6075 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6076 INT nSelectedCount = 0;
6079 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
6081 if (ListView_GetItemState(hwnd, i, LVIS_SELECTED) & LVIS_SELECTED)
6087 return nSelectedCount;
6092 * Retrieves item index that marks the start of a multiple selection.
6095 * [I] HWND : window handle
6098 * Index number or -1 if there is no selection mark.
6100 static LRESULT LISTVIEW_GetSelectionMark(HWND hwnd)
6102 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6104 return infoPtr->nSelectionMark;
6109 * Retrieves the width of a string.
6112 * [I] HWND : window handle
6115 * SUCCESS : string width (in pixels)
6118 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText)
6120 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6121 HFONT hFont, hOldFont;
6125 ZeroMemory(&stringSize, sizeof(SIZE));
6126 if (lpszText != NULL && lpszText != (LPCSTR)-1)
6128 hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
6130 hOldFont = SelectObject(hdc, hFont);
6131 GetTextExtentPointA(hdc, lpszText, lstrlenA(lpszText), &stringSize);
6132 SelectObject(hdc, hOldFont);
6133 ReleaseDC(hwnd, hdc);
6136 return stringSize.cx;
6141 * Retrieves the text backgound color.
6144 * [I] HWND : window handle
6147 * COLORREF associated with the the background.
6149 static LRESULT LISTVIEW_GetTextBkColor(HWND hwnd)
6151 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
6153 return infoPtr->clrTextBk;
6158 * Retrieves the text color.
6161 * [I] HWND : window handle
6164 * COLORREF associated with the text.
6166 static LRESULT LISTVIEW_GetTextColor(HWND hwnd)
6168 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
6170 return infoPtr->clrText;
6175 * Determines which section of the item was selected (if any).
6178 * [I] HWND : window handle
6179 * [IO] LPLVHITTESTINFO : hit test information
6182 * SUCCESS : item index
6185 static INT LISTVIEW_HitTestItem(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
6187 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6189 INT i,topindex,bottomindex;
6190 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6191 UINT uView = lStyle & LVS_TYPEMASK;
6194 TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpHitTestInfo->pt.x,
6195 lpHitTestInfo->pt.y);
6197 topindex = ListView_GetTopIndex(hwnd);
6198 if (uView == LVS_REPORT)
6200 bottomindex = topindex + LISTVIEW_GetCountPerColumn(hwnd) + 1;
6201 bottomindex = min(bottomindex,GETITEMCOUNT(infoPtr));
6205 bottomindex = GETITEMCOUNT(infoPtr);
6208 for (i = topindex; i < bottomindex; i++)
6210 rcItem.left = LVIR_BOUNDS;
6211 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
6213 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
6215 rcItem.left = LVIR_ICON;
6216 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
6218 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
6220 lpHitTestInfo->flags = LVHT_ONITEMICON;
6221 lpHitTestInfo->iItem = i;
6222 lpHitTestInfo->iSubItem = 0;
6227 rcItem.left = LVIR_LABEL;
6228 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
6230 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
6232 lpHitTestInfo->flags = LVHT_ONITEMLABEL;
6233 lpHitTestInfo->iItem = i;
6234 lpHitTestInfo->iSubItem = 0;
6239 lpHitTestInfo->flags = LVHT_ONITEMSTATEICON;
6240 lpHitTestInfo->iItem = i;
6241 lpHitTestInfo->iSubItem = 0;
6247 lpHitTestInfo->flags = LVHT_NOWHERE;
6254 * Determines which listview item is located at the specified position.
6257 * [I] HWND : window handle
6258 * [IO} LPLVHITTESTINFO : hit test information
6261 * SUCCESS : item index
6264 static LRESULT LISTVIEW_HitTest(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
6266 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6269 lpHitTestInfo->flags = 0;
6271 if (infoPtr->rcList.left > lpHitTestInfo->pt.x)
6273 lpHitTestInfo->flags = LVHT_TOLEFT;
6275 else if (infoPtr->rcList.right < lpHitTestInfo->pt.x)
6277 lpHitTestInfo->flags = LVHT_TORIGHT;
6279 if (infoPtr->rcList.top > lpHitTestInfo->pt.y)
6281 lpHitTestInfo->flags |= LVHT_ABOVE;
6283 else if (infoPtr->rcList.bottom < lpHitTestInfo->pt.y)
6285 lpHitTestInfo->flags |= LVHT_BELOW;
6288 if (lpHitTestInfo->flags == 0)
6290 nItem = LISTVIEW_HitTestItem(hwnd, lpHitTestInfo);
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 InvalidateRect(hwnd, &rc, FALSE);
6642 /* LISTVIEW_Scroll */
6646 * Sets the background color.
6649 * [I] HWND : window handle
6650 * [I] COLORREF : background color
6656 static LRESULT LISTVIEW_SetBkColor(HWND hwnd, COLORREF clrBk)
6658 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6660 infoPtr->clrBk = clrBk;
6661 InvalidateRect(hwnd, NULL, TRUE);
6666 /* LISTVIEW_SetBkImage */
6670 * Sets the callback mask. This mask will be used when the parent
6671 * window stores state information (some or all).
6674 * [I] HWND : window handle
6675 * [I] UINT : state mask
6681 static BOOL LISTVIEW_SetCallbackMask(HWND hwnd, UINT uMask)
6683 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6685 infoPtr->uCallbackMask = uMask;
6692 * Sets the attributes of a header item.
6695 * [I] HWND : window handle
6696 * [I] INT : column index
6697 * [I] LPLVCOLUMNA : column attributes
6703 static LRESULT LISTVIEW_SetColumnA(HWND hwnd, INT nColumn,
6704 LPLVCOLUMNA lpColumn)
6706 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6707 BOOL bResult = FALSE;
6708 HDITEMA hdi, hdiget;
6710 if ((lpColumn != NULL) && (nColumn >= 0) &&
6711 (nColumn < Header_GetItemCount(infoPtr->hwndHeader)))
6713 /* initialize memory */
6714 ZeroMemory(&hdi, sizeof(HDITEMA));
6716 if (lpColumn->mask & LVCF_FMT)
6718 /* format member is valid */
6719 hdi.mask |= HDI_FORMAT;
6721 /* get current format first */
6722 hdiget.mask = HDI_FORMAT;
6723 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdiget))
6724 /* preserve HDF_STRING if present */
6725 hdi.fmt = hdiget.fmt & HDF_STRING;
6727 /* set text alignment (leftmost column must be left-aligned) */
6730 hdi.fmt |= HDF_LEFT;
6734 if (lpColumn->fmt & LVCFMT_LEFT)
6736 hdi.fmt |= HDF_LEFT;
6738 else if (lpColumn->fmt & LVCFMT_RIGHT)
6740 hdi.fmt |= HDF_RIGHT;
6742 else if (lpColumn->fmt & LVCFMT_CENTER)
6744 hdi.fmt |= HDF_CENTER;
6748 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
6750 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
6753 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
6755 hdi.fmt |= HDF_IMAGE;
6758 if (lpColumn->fmt & LVCFMT_IMAGE)
6760 hdi.fmt |= HDF_IMAGE;
6761 hdi.iImage = I_IMAGECALLBACK;
6765 if (lpColumn->mask & LVCF_WIDTH)
6767 hdi.mask |= HDI_WIDTH;
6768 hdi.cxy = lpColumn->cx;
6771 if (lpColumn->mask & LVCF_TEXT)
6773 hdi.mask |= HDI_TEXT | HDI_FORMAT;
6774 hdi.pszText = lpColumn->pszText;
6775 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
6776 hdi.fmt |= HDF_STRING;
6779 if (lpColumn->mask & LVCF_IMAGE)
6781 hdi.mask |= HDI_IMAGE;
6782 hdi.iImage = lpColumn->iImage;
6785 if (lpColumn->mask & LVCF_ORDER)
6787 hdi.mask |= HDI_ORDER;
6788 hdi.iOrder = lpColumn->iOrder;
6791 /* set header item attributes */
6792 bResult = Header_SetItemA(infoPtr->hwndHeader, nColumn, &hdi);
6798 /* LISTVIEW_SetColumnW */
6802 * Sets the column order array
6805 * [I] HWND : window handle
6806 * [I] INT : number of elements in column order array
6807 * [I] INT : pointer to column order array
6813 static LRESULT LISTVIEW_SetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
6815 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
6817 FIXME("iCount %d lpiArray %p\n", iCount, lpiArray);
6828 * Sets the width of a column
6831 * [I] HWND : window handle
6832 * [I] INT : column index
6833 * [I] INT : column width
6839 static LRESULT LISTVIEW_SetColumnWidth(HWND hwnd, INT iCol, INT cx)
6841 LISTVIEW_INFO *infoPtr;
6844 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6845 UINT uView = lStyle & LVS_TYPEMASK;
6850 CHAR text_buffer[DISP_TEXT_SIZE];
6851 INT header_item_count;
6856 /* make sure we can get the listview info */
6857 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
6860 if (!infoPtr->hwndHeader) /* make sure we have a header */
6863 /* set column width only if in report or list mode */
6864 if ((uView != LVS_REPORT) && (uView != LVS_LIST))
6867 /* take care of invalid cx values */
6868 if((uView == LVS_REPORT) && (cx < -2))
6869 cx = LVSCW_AUTOSIZE;
6870 else if (uView == LVS_LIST && (cx < 1))
6873 /* resize all columns if in LVS_LIST mode */
6874 if(uView == LVS_LIST) {
6875 infoPtr->nItemWidth = cx;
6876 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
6880 /* autosize based on listview items width */
6881 if(cx == LVSCW_AUTOSIZE)
6883 /* set the width of the header to the width of the widest item */
6884 for(item_index = 0; item_index < GETITEMCOUNT(infoPtr); item_index++)
6886 if(cx < LISTVIEW_GetLabelWidth(hwnd, item_index))
6887 cx = LISTVIEW_GetLabelWidth(hwnd, item_index);
6889 } /* autosize based on listview header width */
6890 else if(cx == LVSCW_AUTOSIZE_USEHEADER)
6892 header_item_count = Header_GetItemCount(infoPtr->hwndHeader);
6894 /* if iCol is the last column make it fill the remainder of the controls width */
6895 if(iCol == (header_item_count - 1)) {
6896 /* get the width of every item except the current one */
6897 hdi.mask = HDI_WIDTH;
6900 for(item_index = 0; item_index < (header_item_count - 1); item_index++) {
6901 Header_GetItemA(infoPtr->hwndHeader, item_index, (LPARAM)(&hdi));
6905 /* retrieve the layout of the header */
6906 GetWindowRect(infoPtr->hwndHeader, &rcHeader);
6908 cx = (rcHeader.right - rcHeader.left) - cx;
6912 /* retrieve header font */
6913 header_font = SendMessageA(infoPtr->hwndHeader, WM_GETFONT, 0L, 0L);
6915 /* retrieve header text */
6916 hdi.mask = HDI_TEXT;
6917 hdi.cchTextMax = sizeof(text_buffer);
6918 hdi.pszText = text_buffer;
6920 Header_GetItemA(infoPtr->hwndHeader, iCol, (LPARAM)(&hdi));
6922 /* determine the width of the text in the header */
6924 old_font = SelectObject(hdc, header_font); /* select the font into hdc */
6926 GetTextExtentPoint32A(hdc, text_buffer, strlen(text_buffer), &size);
6928 SelectObject(hdc, old_font); /* restore the old font */
6929 ReleaseDC(hwnd, hdc);
6931 /* set the width of this column to the width of the text */
6936 /* call header to update the column change */
6937 hdi.mask = HDI_WIDTH;
6940 lret = Header_SetItemA(infoPtr->hwndHeader, (WPARAM)iCol, (LPARAM)&hdi);
6942 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
6949 * Sets the extended listview style.
6952 * [I] HWND : window handle
6957 * SUCCESS : previous style
6960 static LRESULT LISTVIEW_SetExtendedListViewStyle(HWND hwnd, DWORD dwMask, DWORD dwStyle)
6962 LISTVIEW_INFO *infoPtr;
6965 /* make sure we can get the listview info */
6966 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
6969 /* store previous style */
6970 dwOldStyle = infoPtr->dwExStyle;
6974 infoPtr->dwExStyle = (dwOldStyle & ~dwMask) | (dwStyle & dwMask);
6976 infoPtr->dwExStyle = dwStyle;
6978 return (dwOldStyle);
6981 /* LISTVIEW_SetHotCursor */
6985 * Sets the hot item index.
6988 * [I] HWND : window handle
6992 * SUCCESS : previous hot item index
6993 * FAILURE : -1 (no hot item)
6995 static LRESULT LISTVIEW_SetHotItem(HWND hwnd, INT iIndex)
6997 LISTVIEW_INFO *infoPtr;
7000 /* make sure we can get the listview info */
7001 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
7004 /* store previous index */
7005 iOldIndex = infoPtr->nHotItem;
7008 infoPtr->nHotItem = iIndex;
7015 * Sets the amount of time the cursor must hover over an item before it is selected.
7018 * [I] HWND : window handle
7019 * [I] DWORD : dwHoverTime, if -1 the hover time is set to the default
7022 * Returns the previous hover time
7024 static LRESULT LISTVIEW_SetHoverTime(HWND hwnd, DWORD dwHoverTime)
7026 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7027 DWORD oldHoverTime = infoPtr->dwHoverTime;
7029 infoPtr->dwHoverTime = dwHoverTime;
7031 return oldHoverTime;
7034 /* LISTVIEW_SetIconSpacing */
7041 * [I] HWND : window handle
7042 * [I] INT : image list type
7043 * [I] HIMAGELIST : image list handle
7046 * SUCCESS : old image list
7049 static LRESULT LISTVIEW_SetImageList(HWND hwnd, INT nType, HIMAGELIST himl)
7051 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7052 HIMAGELIST himlTemp = 0;
7057 himlTemp = infoPtr->himlNormal;
7058 infoPtr->himlNormal = himl;
7059 return (LRESULT)himlTemp;
7062 himlTemp = infoPtr->himlSmall;
7063 infoPtr->himlSmall = himl;
7064 return (LRESULT)himlTemp;
7067 himlTemp = infoPtr->himlState;
7068 infoPtr->himlState = himl;
7069 ImageList_SetBkColor(infoPtr->himlState, CLR_NONE);
7070 return (LRESULT)himlTemp;
7073 return (LRESULT)NULL;
7079 * Sets the attributes of an item.
7082 * [I] HWND : window handle
7083 * [I] LPLVITEM : item information
7089 static LRESULT LISTVIEW_SetItemA(HWND hwnd, LPLVITEMA lpLVItem)
7091 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7092 BOOL bResult = FALSE;
7094 if (lpLVItem != NULL)
7096 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
7098 if (lpLVItem->iSubItem == 0)
7100 bResult = LISTVIEW_SetItem(hwnd, lpLVItem);
7104 bResult = LISTVIEW_SetSubItem(hwnd, lpLVItem);
7113 /* LISTVIEW_SetItemW */
7117 * Preallocates memory.
7120 * [I] HWND : window handle
7121 * [I] INT : item count (projected number of items)
7122 * [I] DWORD : update flags
7128 static BOOL LISTVIEW_SetItemCount(HWND hwnd, INT nItems, DWORD dwFlags)
7130 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
7132 FIXME("(%d %08lx)stub!\n", nItems, dwFlags);
7134 if (GetWindowLongA(hwnd, GWL_STYLE) & LVS_OWNERDATA)
7136 int precount,topvisible;
7137 TRACE("LVS_OWNERDATA is set!\n");
7140 * Internally remove all the selections.
7144 LISTVIEW_SELECTION *selection;
7145 selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,0);
7147 LISTVIEW_RemoveSelectionRange(hwnd,selection->lower,
7150 while (infoPtr->hdpaSelectionRanges->nItemCount>0);
7152 precount = infoPtr->hdpaItems->nItemCount;
7153 topvisible = ListView_GetTopIndex(hwnd) +
7154 LISTVIEW_GetCountPerColumn(hwnd) + 1;
7156 infoPtr->hdpaItems->nItemCount = nItems;
7158 LISTVIEW_UpdateSize(hwnd);
7159 LISTVIEW_UpdateScroll(hwnd);
7160 if (min(precount,infoPtr->hdpaItems->nItemCount)<topvisible)
7161 InvalidateRect(hwnd, NULL, TRUE);
7166 return LISTVIEW_DeleteAllItems (hwnd);
7168 if (nItems > GETITEMCOUNT(infoPtr))
7171 FIXME("append items\n");
7174 else if (nItems < GETITEMCOUNT(infoPtr))
7177 while(nItems < GETITEMCOUNT(infoPtr)) {
7178 LISTVIEW_DeleteItem(hwnd, GETITEMCOUNT(infoPtr) - 1);
7188 * Sets the position of an item.
7191 * [I] HWND : window handle
7192 * [I] INT : item index
7193 * [I] INT : x coordinate
7194 * [I] INT : y coordinate
7200 static BOOL LISTVIEW_SetItemPosition(HWND hwnd, INT nItem,
7201 INT nPosX, INT nPosY)
7203 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
7204 UINT lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7205 UINT uView = lStyle & LVS_TYPEMASK;
7206 LISTVIEW_ITEM *lpItem;
7208 BOOL bResult = FALSE;
7210 TRACE("(hwnd=%x,nItem=%d,X=%d,Y=%d)\n", hwnd, nItem, nPosX, nPosY);
7212 if (lStyle & LVS_OWNERDATA)
7215 if ((nItem >= 0) || (nItem < GETITEMCOUNT(infoPtr)))
7217 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
7219 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
7220 if (hdpaSubItems != NULL)
7222 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
7226 lpItem->ptPosition.x = nPosX;
7227 lpItem->ptPosition.y = nPosY;
7236 /* LISTVIEW_SetItemPosition32 */
7240 * Sets the state of one or many items.
7243 * [I] HWND : window handle
7244 * [I]INT : item index
7245 * [I] LPLVITEM : item or subitem info
7251 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
7253 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7254 BOOL bResult = FALSE;
7261 ZeroMemory(&lvItem, sizeof(LVITEMA));
7262 lvItem.mask = LVIF_STATE;
7263 lvItem.state = lpLVItem->state;
7264 lvItem.stateMask = lpLVItem->stateMask ;
7266 /* apply to all items */
7267 for (i = 0; i< GETITEMCOUNT(infoPtr); i++)
7270 if (ListView_SetItemA(hwnd, &lvItem) == FALSE)
7278 ZeroMemory(&lvItem, sizeof(LVITEMA));
7279 lvItem.mask = LVIF_STATE;
7280 lvItem.state = lpLVItem->state;
7281 lvItem.stateMask = lpLVItem->stateMask;
7282 lvItem.iItem = nItem;
7283 bResult = ListView_SetItemA(hwnd, &lvItem);
7291 * Sets the text of an item or subitem.
7294 * [I] HWND : window handle
7295 * [I] INT : item index
7296 * [I] LPLVITEMA : item or subitem info
7302 static BOOL LISTVIEW_SetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
7304 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7305 BOOL bResult = FALSE;
7308 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
7310 ZeroMemory(&lvItem, sizeof(LVITEMA));
7311 lvItem.mask = LVIF_TEXT;
7312 lvItem.pszText = lpLVItem->pszText;
7313 lvItem.iItem = nItem;
7314 lvItem.iSubItem = lpLVItem->iSubItem;
7315 bResult = ListView_SetItemA(hwnd, &lvItem);
7321 /* LISTVIEW_SetItemTextW */
7325 * Set item index that marks the start of a multiple selection.
7328 * [I] HWND : window handle
7332 * Index number or -1 if there is no selection mark.
7334 static LRESULT LISTVIEW_SetSelectionMark(HWND hwnd, INT nIndex)
7336 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7337 INT nOldIndex = infoPtr->nSelectionMark;
7339 infoPtr->nSelectionMark = nIndex;
7346 * Sets the text background color.
7349 * [I] HWND : window handle
7350 * [I] COLORREF : text background color
7356 static LRESULT LISTVIEW_SetTextBkColor(HWND hwnd, COLORREF clrTextBk)
7358 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7360 infoPtr->clrTextBk = clrTextBk;
7361 InvalidateRect(hwnd, NULL, TRUE);
7368 * Sets the text foreground color.
7371 * [I] HWND : window handle
7372 * [I] COLORREF : text color
7378 static LRESULT LISTVIEW_SetTextColor (HWND hwnd, COLORREF clrText)
7380 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7382 infoPtr->clrText = clrText;
7383 InvalidateRect(hwnd, NULL, TRUE);
7388 /* LISTVIEW_SetToolTips */
7389 /* LISTVIEW_SetUnicodeFormat */
7390 /* LISTVIEW_SetWorkAreas */
7394 * Callback internally used by LISTVIEW_SortItems()
7397 * [I] LPVOID : first LISTVIEW_ITEM to compare
7398 * [I] LPVOID : second LISTVIEW_ITEM to compare
7399 * [I] LPARAM : HWND of control
7402 * if first comes before second : negative
7403 * if first comes after second : positive
7404 * if first and second are equivalent : zero
7406 static INT WINAPI LISTVIEW_CallBackCompare(
7411 /* Forward the call to the client defined callback */
7413 HWND hwnd = (HWND)lParam;
7414 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7415 HDPA hdpa_first = (HDPA) first;
7416 HDPA hdpa_second = (HDPA) second;
7417 LISTVIEW_ITEM* lv_first = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_first, 0 );
7418 LISTVIEW_ITEM* lv_second = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_second, 0 );
7420 rv = (infoPtr->pfnCompare)( lv_first->lParam , lv_second->lParam, infoPtr->lParamSort );
7427 * Sorts the listview items.
7430 * [I] HWND : window handle
7431 * [I] WPARAM : application-defined value
7432 * [I] LPARAM : pointer to comparision callback
7438 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam)
7440 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7442 UINT lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7444 if (lStyle & LVS_OWNERDATA)
7447 if (!infoPtr || !infoPtr->hdpaItems)
7450 nCount = GETITEMCOUNT(infoPtr);
7451 /* if there are 0 or 1 items, there is no need to sort */
7454 infoPtr->pfnCompare = (PFNLVCOMPARE)lParam;
7455 infoPtr->lParamSort = (LPARAM)wParam;
7457 DPA_Sort(infoPtr->hdpaItems, LISTVIEW_CallBackCompare, hwnd);
7463 /* LISTVIEW_SubItemHitTest */
7467 * Updates an items or rearranges the listview control.
7470 * [I] HWND : window handle
7471 * [I] INT : item index
7477 static LRESULT LISTVIEW_Update(HWND hwnd, INT nItem)
7479 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7480 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7481 BOOL bResult = FALSE;
7484 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
7488 /* rearrange with default alignment style */
7489 if ((lStyle & LVS_AUTOARRANGE) && (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
7490 ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON)))
7492 ListView_Arrange(hwnd, 0);
7496 /* get item bounding rectangle */
7497 rc.left = LVIR_BOUNDS;
7498 ListView_GetItemRect(hwnd, nItem, &rc);
7499 InvalidateRect(hwnd, &rc, TRUE);
7508 * Creates the listview control.
7511 * [I] HWND : window handle
7516 static LRESULT LISTVIEW_Create(HWND hwnd, WPARAM wParam, LPARAM lParam)
7518 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7519 LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam;
7520 UINT uView = lpcs->style & LVS_TYPEMASK;
7523 /* initialize info pointer */
7524 ZeroMemory(infoPtr, sizeof(LISTVIEW_INFO));
7526 /* determine the type of structures to use */
7527 infoPtr->notifyFormat = SendMessageA(GetParent(hwnd), WM_NOTIFYFORMAT,
7528 (WPARAM)hwnd, (LPARAM)NF_QUERY);
7529 if (infoPtr->notifyFormat != NFR_ANSI)
7531 FIXME("ANSI notify format is NOT used\n");
7534 /* initialize color information */
7535 infoPtr->clrBk = GetSysColor(COLOR_WINDOW);
7536 infoPtr->clrText = GetSysColor(COLOR_WINDOWTEXT);
7537 infoPtr->clrTextBk = CLR_DEFAULT;
7539 /* set default values */
7540 infoPtr->uCallbackMask = 0;
7541 infoPtr->nFocusedItem = -1;
7542 infoPtr->nSelectionMark = -1;
7543 infoPtr->nHotItem = -1;
7544 infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING);
7545 infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING);
7546 ZeroMemory(&infoPtr->rcList, sizeof(RECT));
7547 infoPtr->hwndEdit = 0;
7548 infoPtr->pedititem = NULL;
7549 infoPtr->nEditLabelItem = -1;
7551 /* get default font (icon title) */
7552 SystemParametersInfoA(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
7553 infoPtr->hDefaultFont = CreateFontIndirectA(&logFont);
7554 infoPtr->hFont = infoPtr->hDefaultFont;
7557 infoPtr->hwndHeader = CreateWindowA(WC_HEADERA, (LPCSTR)NULL,
7558 WS_CHILD | HDS_HORZ | HDS_BUTTONS,
7559 0, 0, 0, 0, hwnd, (HMENU)0,
7560 lpcs->hInstance, NULL);
7562 /* set header font */
7563 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont,
7566 if (uView == LVS_ICON)
7568 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
7569 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
7571 else if (uView == LVS_REPORT)
7573 if (!(LVS_NOCOLUMNHEADER & lpcs->style))
7575 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
7579 /* resize our header to nothing */
7583 memset(&zeroRect,0,sizeof(RECT));
7587 Header_Layout(infoPtr->hwndHeader,&hd);
7591 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7592 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7596 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7597 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7600 /* display unsupported listview window styles */
7601 LISTVIEW_UnsupportedStyles(lpcs->style);
7603 /* allocate memory for the data structure */
7604 infoPtr->hdpaItems = DPA_Create(10);
7606 /* allocate memory for the selection ranges */
7607 infoPtr->hdpaSelectionRanges = DPA_Create(10);
7609 /* initialize size of items */
7610 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7611 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7613 /* initialize the hover time to -1(indicating the default system hover time) */
7614 infoPtr->dwHoverTime = -1;
7621 * Erases the background of the listview control.
7624 * [I] HWND : window handle
7625 * [I] WPARAM : device context handle
7626 * [I] LPARAM : not used
7632 static LRESULT LISTVIEW_EraseBackground(HWND hwnd, WPARAM wParam,
7635 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7638 if (infoPtr->clrBk == CLR_NONE)
7640 bResult = SendMessageA(GetParent(hwnd), WM_ERASEBKGND, wParam, lParam);
7645 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
7646 GetClientRect(hwnd, &rc);
7647 FillRect((HDC)wParam, &rc, hBrush);
7648 DeleteObject(hBrush);
7657 * Retrieves the listview control font.
7660 * [I] HWND : window handle
7665 static LRESULT LISTVIEW_GetFont(HWND hwnd)
7667 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7669 return infoPtr->hFont;
7674 * Performs vertical scrolling.
7677 * [I] HWND : window handle
7678 * [I] INT : scroll code
7679 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
7681 * [I] HWND : scrollbar control window handle
7686 static LRESULT LISTVIEW_VScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
7689 SCROLLINFO scrollInfo;
7691 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
7692 scrollInfo.cbSize = sizeof(SCROLLINFO);
7693 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
7695 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
7697 INT nOldScrollPos = scrollInfo.nPos;
7698 switch (nScrollCode)
7701 if (scrollInfo.nPos > scrollInfo.nMin)
7708 if (scrollInfo.nPos < scrollInfo.nMax)
7715 if (scrollInfo.nPos > scrollInfo.nMin)
7717 if (scrollInfo.nPos >= scrollInfo.nPage)
7719 scrollInfo.nPos -= scrollInfo.nPage;
7723 scrollInfo.nPos = scrollInfo.nMin;
7729 if (scrollInfo.nPos < scrollInfo.nMax)
7731 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
7733 scrollInfo.nPos += scrollInfo.nPage;
7737 scrollInfo.nPos = scrollInfo.nMax;
7743 scrollInfo.nPos = nCurrentPos;
7744 if (scrollInfo.nPos > scrollInfo.nMax)
7745 scrollInfo.nPos=scrollInfo.nMax;
7747 if (scrollInfo.nPos < scrollInfo.nMin)
7748 scrollInfo.nPos=scrollInfo.nMin;
7753 if (nOldScrollPos != scrollInfo.nPos)
7755 scrollInfo.fMask = SIF_POS;
7756 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
7757 InvalidateRect(hwnd, NULL, TRUE);
7766 * Performs horizontal scrolling.
7769 * [I] HWND : window handle
7770 * [I] INT : scroll code
7771 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
7773 * [I] HWND : scrollbar control window handle
7778 static LRESULT LISTVIEW_HScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
7781 SCROLLINFO scrollInfo;
7783 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
7784 scrollInfo.cbSize = sizeof(SCROLLINFO);
7785 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
7787 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
7789 INT nOldScrollPos = scrollInfo.nPos;
7791 switch (nScrollCode)
7794 if (scrollInfo.nPos > scrollInfo.nMin)
7801 if (scrollInfo.nPos < scrollInfo.nMax)
7808 if (scrollInfo.nPos > scrollInfo.nMin)
7810 if (scrollInfo.nPos >= scrollInfo.nPage)
7812 scrollInfo.nPos -= scrollInfo.nPage;
7816 scrollInfo.nPos = scrollInfo.nMin;
7822 if (scrollInfo.nPos < scrollInfo.nMax)
7824 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
7826 scrollInfo.nPos += scrollInfo.nPage;
7830 scrollInfo.nPos = scrollInfo.nMax;
7836 scrollInfo.nPos = nCurrentPos;
7838 if (scrollInfo.nPos > scrollInfo.nMax)
7839 scrollInfo.nPos=scrollInfo.nMax;
7841 if (scrollInfo.nPos < scrollInfo.nMin)
7842 scrollInfo.nPos=scrollInfo.nMin;
7846 if (nOldScrollPos != scrollInfo.nPos)
7848 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
7849 scrollInfo.fMask = SIF_POS;
7850 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
7851 if(uView == LVS_REPORT)
7853 scrollInfo.fMask = SIF_POS;
7854 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
7855 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
7857 InvalidateRect(hwnd, NULL, TRUE);
7864 static LRESULT LISTVIEW_MouseWheel(HWND hwnd, INT wheelDelta)
7866 INT gcWheelDelta = 0;
7867 UINT pulScrollLines = 3;
7868 SCROLLINFO scrollInfo;
7870 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
7872 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
7873 gcWheelDelta -= wheelDelta;
7875 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
7876 scrollInfo.cbSize = sizeof(SCROLLINFO);
7877 scrollInfo.fMask = SIF_POS | SIF_RANGE;
7884 * listview should be scrolled by a multiple of 37 dependently on its dimension or its visible item number
7885 * should be fixed in the future.
7887 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
7888 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + (gcWheelDelta < 0) ? 37 : -37, 0);
7892 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
7894 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
7896 int cLineScroll = min(LISTVIEW_GetCountPerColumn(hwnd), pulScrollLines);
7897 cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
7898 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + cLineScroll, 0);
7904 LISTVIEW_HScroll(hwnd, (gcWheelDelta < 0) ? SB_LINELEFT : SB_LINERIGHT, 0, 0);
7915 * [I] HWND : window handle
7916 * [I] INT : virtual key
7917 * [I] LONG : key data
7922 static LRESULT LISTVIEW_KeyDown(HWND hwnd, INT nVirtualKey, LONG lKeyData)
7924 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7925 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
7926 HWND hwndParent = GetParent(hwnd);
7927 NMLVKEYDOWN nmKeyDown;
7930 BOOL bRedraw = FALSE;
7932 /* send LVN_KEYDOWN notification */
7933 ZeroMemory(&nmKeyDown, sizeof(NMLVKEYDOWN));
7934 nmKeyDown.hdr.hwndFrom = hwnd;
7935 nmKeyDown.hdr.idFrom = nCtrlId;
7936 nmKeyDown.hdr.code = LVN_KEYDOWN;
7937 nmKeyDown.wVKey = nVirtualKey;
7938 nmKeyDown.flags = 0;
7939 SendMessageA(hwndParent, WM_NOTIFY, (WPARAM)nCtrlId, (LPARAM)&nmKeyDown);
7942 nmh.hwndFrom = hwnd;
7943 nmh.idFrom = nCtrlId;
7945 switch (nVirtualKey)
7948 if ((GETITEMCOUNT(infoPtr) > 0) && (infoPtr->nFocusedItem != -1))
7950 /* send NM_RETURN notification */
7951 nmh.code = NM_RETURN;
7952 ListView_Notify(hwndParent, nCtrlId, &nmh);
7954 /* send LVN_ITEMACTIVATE notification */
7955 nmh.code = LVN_ITEMACTIVATE;
7956 ListView_Notify(hwndParent, nCtrlId, &nmh);
7961 if (GETITEMCOUNT(infoPtr) > 0)
7968 if (GETITEMCOUNT(infoPtr) > 0)
7970 nItem = GETITEMCOUNT(infoPtr) - 1;
7975 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TOLEFT);
7979 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_ABOVE);
7983 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TORIGHT);
7987 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_BELOW);
7999 if ((nItem != -1) && (nItem != infoPtr->nFocusedItem))
8001 bRedraw = LISTVIEW_KeySelection(hwnd, nItem);
8002 if (bRedraw != FALSE)
8004 /* refresh client area */
8017 * [I] HWND : window handle
8022 static LRESULT LISTVIEW_KillFocus(HWND hwnd)
8024 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
8025 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8029 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8030 UINT uView = lStyle & LVS_TYPEMASK;
8032 TRACE("(hwnd=%x)\n", hwnd);
8034 /* send NM_KILLFOCUS notification */
8035 nmh.hwndFrom = hwnd;
8036 nmh.idFrom = nCtrlId;
8037 nmh.code = NM_KILLFOCUS;
8038 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8040 /* set window focus flag */
8041 infoPtr->bFocus = FALSE;
8043 /* NEED drawing optimization ; redraw the selected items */
8044 if (uView & LVS_REPORT)
8046 nTop = LISTVIEW_GetTopIndex(hwnd);
8048 LISTVIEW_GetCountPerColumn(hwnd) + 1;
8053 nBottom = GETITEMCOUNT(infoPtr);
8055 for (i = nTop; i<nBottom; i++)
8057 if (LISTVIEW_IsSelected(hwnd,i))
8059 rcItem.left = LVIR_BOUNDS;
8060 LISTVIEW_GetItemRect(hwnd, i, &rcItem);
8061 InvalidateRect(hwnd, &rcItem, FALSE);
8070 * Processes double click messages (left mouse button).
8073 * [I] HWND : window handle
8074 * [I] WORD : key flag
8075 * [I] WORD : x coordinate
8076 * [I] WORD : y coordinate
8081 static LRESULT LISTVIEW_LButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
8084 LONG nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8085 LVHITTESTINFO htInfo;
8090 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8092 htInfo.pt.x = wPosX;
8093 htInfo.pt.y = wPosY;
8095 /* send NM_DBLCLK notification */
8096 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
8097 nmlv.hdr.hwndFrom = hwnd;
8098 nmlv.hdr.idFrom = nCtrlId;
8099 nmlv.hdr.code = NM_DBLCLK;
8100 ret = LISTVIEW_HitTestItem(hwnd, &htInfo);
8103 nmlv.iItem = htInfo.iItem;
8104 nmlv.iSubItem = htInfo.iSubItem;
8111 nmlv.ptAction.x = wPosX;
8112 nmlv.ptAction.y = wPosY;
8113 ListView_LVNotify(GetParent(hwnd), nCtrlId, &nmlv);
8116 /* To send the LVN_ITEMACTIVATE, it must be on an Item */
8119 /* send LVN_ITEMACTIVATE notification */
8120 nmh.hwndFrom = hwnd;
8121 nmh.idFrom = nCtrlId;
8122 nmh.code = LVN_ITEMACTIVATE;
8123 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8131 * Processes mouse down messages (left mouse button).
8134 * [I] HWND : window handle
8135 * [I] WORD : key flag
8136 * [I] WORD : x coordinate
8137 * [I] WORD : y coordinate
8142 static LRESULT LISTVIEW_LButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
8145 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8146 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8147 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8148 static BOOL bGroupSelect = TRUE;
8153 TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd, wKey, wPosX,
8156 /* send NM_RELEASEDCAPTURE notification */
8157 nmh.hwndFrom = hwnd;
8158 nmh.idFrom = nCtrlId;
8159 nmh.code = NM_RELEASEDCAPTURE;
8160 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8162 if (infoPtr->bFocus == FALSE)
8167 /* set left button down flag */
8168 infoPtr->bLButtonDown = TRUE;
8170 ptPosition.x = wPosX;
8171 ptPosition.y = wPosY;
8172 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
8173 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
8175 if (lStyle & LVS_SINGLESEL)
8177 if ((ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
8178 && infoPtr->nEditLabelItem == -1)
8180 infoPtr->nEditLabelItem = nItem;
8184 LISTVIEW_SetSelection(hwnd, nItem);
8189 if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
8191 if (bGroupSelect != FALSE)
8193 LISTVIEW_AddGroupSelection(hwnd, nItem);
8197 LISTVIEW_AddSelection(hwnd, nItem);
8200 else if (wKey & MK_CONTROL)
8202 bGroupSelect = LISTVIEW_ToggleSelection(hwnd, nItem);
8204 else if (wKey & MK_SHIFT)
8206 LISTVIEW_SetGroupSelection(hwnd, nItem);
8211 (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED);
8213 /* set selection (clears other pre-existing selections) */
8214 LISTVIEW_SetSelection(hwnd, nItem);
8216 if (was_selected && infoPtr->nEditLabelItem == -1)
8218 infoPtr->nEditLabelItem = nItem;
8225 /* remove all selections */
8226 LISTVIEW_RemoveAllSelections(hwnd);
8229 /* redraw if we could have possibly selected something */
8230 if(!GETITEMCOUNT(infoPtr)) InvalidateRect(hwnd, NULL, TRUE);
8237 * Processes mouse up messages (left mouse button).
8240 * [I] HWND : window handle
8241 * [I] WORD : key flag
8242 * [I] WORD : x coordinate
8243 * [I] WORD : y coordinate
8248 static LRESULT LISTVIEW_LButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
8251 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8253 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8255 if (infoPtr->bLButtonDown != FALSE)
8257 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8259 LVHITTESTINFO lvHitTestInfo;
8262 lvHitTestInfo.pt.x = wPosX;
8263 lvHitTestInfo.pt.y = wPosY;
8265 /* send NM_CLICK notification */
8266 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
8267 nmlv.hdr.hwndFrom = hwnd;
8268 nmlv.hdr.idFrom = nCtrlId;
8269 nmlv.hdr.code = NM_CLICK;
8270 ret = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo);
8273 nmlv.iItem = lvHitTestInfo.iItem;
8274 nmlv.iSubItem = lvHitTestInfo.iSubItem;
8281 nmlv.ptAction.x = wPosX;
8282 nmlv.ptAction.y = wPosY;
8283 ListView_LVNotify(GetParent(hwnd), nCtrlId, &nmlv);
8286 /* set left button flag */
8287 infoPtr->bLButtonDown = FALSE;
8289 if(infoPtr->nEditLabelItem != -1)
8291 if(lvHitTestInfo.iItem == infoPtr->nEditLabelItem)
8293 LISTVIEW_EditLabelA(hwnd, lvHitTestInfo.iItem);
8295 infoPtr->nEditLabelItem = -1;
8304 * Creates the listview control (called before WM_CREATE).
8307 * [I] HWND : window handle
8308 * [I] WPARAM : unhandled
8309 * [I] LPARAM : widow creation info
8314 static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
8316 LISTVIEW_INFO *infoPtr;
8318 TRACE("(hwnd=%x,wParam=%x,lParam=%lx)\n", hwnd, wParam, lParam);
8320 /* allocate memory for info structure */
8321 infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc(sizeof(LISTVIEW_INFO));
8322 SetWindowLongA(hwnd, 0, (LONG)infoPtr);
8323 if (infoPtr == NULL)
8325 ERR("could not allocate info memory!\n");
8329 if ((LISTVIEW_INFO *)GetWindowLongA(hwnd, 0) != infoPtr)
8331 ERR("pointer assignment error!\n");
8335 return DefWindowProcA(hwnd, WM_NCCREATE, wParam, lParam);
8340 * Destroys the listview control (called after WM_DESTROY).
8343 * [I] HWND : window handle
8348 static LRESULT LISTVIEW_NCDestroy(HWND hwnd)
8350 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8352 TRACE("(hwnd=%x)\n", hwnd);
8354 /* delete all items */
8355 LISTVIEW_DeleteAllItems(hwnd);
8357 /* destroy data structure */
8358 DPA_Destroy(infoPtr->hdpaItems);
8359 DPA_Destroy(infoPtr->hdpaSelectionRanges);
8362 infoPtr->hFont = (HFONT)0;
8363 if (infoPtr->hDefaultFont)
8365 DeleteObject(infoPtr->hDefaultFont);
8368 /* free listview info pointer*/
8369 COMCTL32_Free(infoPtr);
8371 SetWindowLongA(hwnd, 0, 0);
8377 * Handles notifications from children.
8380 * [I] HWND : window handle
8381 * [I] INT : control identifier
8382 * [I] LPNMHDR : notification information
8387 static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh)
8389 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8391 if (lpnmh->hwndFrom == infoPtr->hwndHeader)
8393 /* handle notification from header control */
8394 if (lpnmh->code == HDN_ENDTRACKA)
8396 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8397 InvalidateRect(hwnd, NULL, TRUE);
8399 else if(lpnmh->code == HDN_ITEMCLICKA)
8401 /* Handle sorting by Header Column */
8403 LPNMHEADERA pnmHeader = (LPNMHEADERA) lpnmh;
8404 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
8406 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
8407 nmlv.hdr.hwndFrom = hwnd;
8408 nmlv.hdr.idFrom = lCtrlId;
8409 nmlv.hdr.code = LVN_COLUMNCLICK;
8411 nmlv.iSubItem = pnmHeader->iItem;
8413 ListView_LVNotify(GetParent(hwnd),lCtrlId, &nmlv);
8416 else if(lpnmh->code == NM_RELEASEDCAPTURE)
8418 /* Idealy this should be done in HDN_ENDTRACKA
8419 * but since SetItemBounds in Header.c is called after
8420 * the notification is sent, it is neccessary to handle the
8421 * update of the scroll bar here (Header.c works fine as it is,
8422 * no need to disturb it)
8424 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8425 LISTVIEW_UpdateScroll(hwnd);
8426 InvalidateRect(hwnd, NULL, TRUE);
8436 * Determines the type of structure to use.
8439 * [I] HWND : window handle of the sender
8440 * [I] HWND : listview window handle
8441 * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
8446 static LRESULT LISTVIEW_NotifyFormat(HWND hwndFrom, HWND hwnd, INT nCommand)
8448 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8450 if (nCommand == NF_REQUERY)
8452 /* determine the type of structure to use */
8453 infoPtr->notifyFormat = SendMessageA(hwndFrom, WM_NOTIFYFORMAT,
8454 (WPARAM)hwnd, (LPARAM)NF_QUERY);
8455 if (infoPtr->notifyFormat == NFR_UNICODE)
8457 FIXME("NO support for unicode structures");
8466 * Paints/Repaints the listview control.
8469 * [I] HWND : window handle
8470 * [I] HDC : device context handle
8475 static LRESULT LISTVIEW_Paint(HWND hwnd, HDC hdc)
8479 TRACE("(hwnd=%x,hdc=%x)\n", hwnd, hdc);
8483 hdc = BeginPaint(hwnd, &ps);
8484 LISTVIEW_Refresh(hwnd, hdc);
8485 EndPaint(hwnd, &ps);
8489 LISTVIEW_Refresh(hwnd, hdc);
8497 * Processes double click messages (right mouse button).
8500 * [I] HWND : window handle
8501 * [I] WORD : key flag
8502 * [I] WORD : x coordinate
8503 * [I] WORD : y coordinate
8508 static LRESULT LISTVIEW_RButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
8511 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8514 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8516 /* send NM_RELEASEDCAPTURE notification */
8517 nmh.hwndFrom = hwnd;
8518 nmh.idFrom = nCtrlId;
8519 nmh.code = NM_RELEASEDCAPTURE;
8520 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8522 /* send NM_RDBLCLK notification */
8523 nmh.code = NM_RDBLCLK;
8524 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8531 * Processes mouse down messages (right mouse button).
8534 * [I] HWND : window handle
8535 * [I] WORD : key flag
8536 * [I] WORD : x coordinate
8537 * [I] WORD : y coordinate
8542 static LRESULT LISTVIEW_RButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
8545 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8546 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8551 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8553 /* send NM_RELEASEDCAPTURE notification */
8554 nmh.hwndFrom = hwnd;
8555 nmh.idFrom = nCtrlId;
8556 nmh.code = NM_RELEASEDCAPTURE;
8557 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8559 /* make sure the listview control window has the focus */
8560 if (infoPtr->bFocus == FALSE)
8565 /* set right button down flag */
8566 infoPtr->bRButtonDown = TRUE;
8568 /* determine the index of the selected item */
8569 ptPosition.x = wPosX;
8570 ptPosition.y = wPosY;
8571 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
8572 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
8574 if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)))
8576 LISTVIEW_SetSelection(hwnd, nItem);
8581 LISTVIEW_RemoveAllSelections(hwnd);
8589 * Processes mouse up messages (right mouse button).
8592 * [I] HWND : window handle
8593 * [I] WORD : key flag
8594 * [I] WORD : x coordinate
8595 * [I] WORD : y coordinate
8600 static LRESULT LISTVIEW_RButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
8603 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8604 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8606 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8608 if (infoPtr->bRButtonDown != FALSE)
8611 LVHITTESTINFO lvHitTestInfo;
8615 lvHitTestInfo.pt.x = wPosX;
8616 lvHitTestInfo.pt.y = wPosY;
8618 /* Send NM_RClICK notification */
8619 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
8620 nmlv.hdr.hwndFrom = hwnd;
8621 nmlv.hdr.idFrom = nCtrlId;
8622 nmlv.hdr.code = NM_RCLICK;
8623 ret = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo);
8626 nmlv.iItem = lvHitTestInfo.iItem;
8627 nmlv.iSubItem = lvHitTestInfo.iSubItem;
8634 nmlv.iItem = lvHitTestInfo.iItem;
8635 nmlv.iSubItem = lvHitTestInfo.iSubItem;
8636 nmlv.ptAction.x = wPosX;
8637 nmlv.ptAction.y = wPosY;
8638 ListView_LVNotify(GetParent(hwnd), nCtrlId, &nmlv);
8643 /* set button flag */
8644 infoPtr->bRButtonDown = FALSE;
8646 /* Change to screen coordinate for WM_CONTEXTMENU */
8647 ClientToScreen(hwnd, &pt);
8649 /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
8650 SendMessageA( hwnd, WM_CONTEXTMENU, (WPARAM) hwnd, MAKELPARAM(pt.x, pt.y));
8661 * [I] HWND : window handle
8662 * [I] HWND : window handle of previously focused window
8667 static LRESULT LISTVIEW_SetFocus(HWND hwnd, HWND hwndLoseFocus)
8669 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8670 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8673 TRACE("(hwnd=%x, hwndLoseFocus=%x)\n", hwnd, hwndLoseFocus);
8675 /* send NM_SETFOCUS notification */
8676 nmh.hwndFrom = hwnd;
8677 nmh.idFrom = nCtrlId;
8678 nmh.code = NM_SETFOCUS;
8679 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8681 /* set window focus flag */
8682 infoPtr->bFocus = TRUE;
8694 * [I] HWND : window handle
8695 * [I] HFONT : font handle
8696 * [I] WORD : redraw flag
8701 static LRESULT LISTVIEW_SetFont(HWND hwnd, HFONT hFont, WORD fRedraw)
8703 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8704 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
8706 TRACE("(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd, hFont, fRedraw);
8710 infoPtr->hFont = infoPtr->hDefaultFont;
8714 infoPtr->hFont = hFont;
8717 if (uView == LVS_REPORT)
8719 /* set header font */
8720 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont,
8721 MAKELPARAM(fRedraw, 0));
8724 /* invalidate listview control client area */
8725 InvalidateRect(hwnd, NULL, TRUE);
8727 if (fRedraw != FALSE)
8737 * Message handling for WM_SETREDRAW.
8738 * For the Listview, it invalidates the entire window (the doc specifies otherwise)
8741 * [I] HWND : window handle
8742 * [I] bRedraw: state of redraw flag
8745 * DefWinProc return value
8747 static LRESULT LISTVIEW_SetRedraw(HWND hwnd, BOOL bRedraw)
8750 lResult = DefWindowProcA(hwnd, WM_SETREDRAW, bRedraw, 0);
8753 RedrawWindow(hwnd, NULL, 0,
8754 RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN | RDW_ERASENOW);
8761 * Resizes the listview control. This function processes WM_SIZE
8762 * messages. At this time, the width and height are not used.
8765 * [I] HWND : window handle
8766 * [I] WORD : new width
8767 * [I] WORD : new height
8772 static LRESULT LISTVIEW_Size(HWND hwnd, int Width, int Height)
8774 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8775 UINT uView = lStyle & LVS_TYPEMASK;
8777 TRACE("(hwnd=%x, width=%d, height=%d)\n",hwnd, Width, Height);
8779 LISTVIEW_UpdateSize(hwnd);
8781 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
8783 if (lStyle & LVS_ALIGNLEFT)
8785 LISTVIEW_AlignLeft(hwnd);
8789 LISTVIEW_AlignTop(hwnd);
8793 LISTVIEW_UpdateScroll(hwnd);
8795 /* invalidate client area + erase background */
8796 InvalidateRect(hwnd, NULL, TRUE);
8803 * Sets the size information.
8806 * [I] HWND : window handle
8811 static VOID LISTVIEW_UpdateSize(HWND hwnd)
8813 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8814 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8815 UINT uView = lStyle & LVS_TYPEMASK;
8818 GetClientRect(hwnd, &rcList);
8819 infoPtr->rcList.left = 0;
8820 infoPtr->rcList.right = max(rcList.right - rcList.left, 1);
8821 infoPtr->rcList.top = 0;
8822 infoPtr->rcList.bottom = max(rcList.bottom - rcList.top, 1);
8824 if (uView == LVS_LIST)
8826 if ((lStyle & WS_HSCROLL) == 0)
8828 INT nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
8829 if (infoPtr->rcList.bottom > nHScrollHeight)
8831 infoPtr->rcList.bottom -= nHScrollHeight;
8835 else if ((uView == LVS_REPORT)&&(!(LVS_NOCOLUMNHEADER & lStyle)))
8842 Header_Layout(infoPtr->hwndHeader, &hl);
8844 SetWindowPos(wp.hwnd, wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
8846 if (!(LVS_NOCOLUMNHEADER & lStyle))
8848 infoPtr->rcList.top = max(wp.cy, 0);
8855 * Processes WM_STYLECHANGED messages.
8858 * [I] HWND : window handle
8859 * [I] WPARAM : window style type (normal or extended)
8860 * [I] LPSTYLESTRUCT : window style information
8865 static INT LISTVIEW_StyleChanged(HWND hwnd, WPARAM wStyleType,
8868 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8869 UINT uNewView = lpss->styleNew & LVS_TYPEMASK;
8870 UINT uOldView = lpss->styleOld & LVS_TYPEMASK;
8871 RECT rcList = infoPtr->rcList;
8873 TRACE("(hwnd=%x, styletype=%x, stylestruct=%p)\n",
8874 hwnd, wStyleType, lpss);
8876 if (wStyleType == GWL_STYLE)
8878 if (uOldView == LVS_REPORT)
8880 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
8883 if ((lpss->styleOld & WS_HSCROLL) != 0)
8885 ShowScrollBar(hwnd, SB_HORZ, FALSE);
8888 if ((lpss->styleOld & WS_VSCROLL) != 0)
8890 ShowScrollBar(hwnd, SB_VERT, FALSE);
8893 if (uNewView == LVS_ICON)
8895 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
8896 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
8897 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8898 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8899 if (lpss->styleNew & LVS_ALIGNLEFT)
8901 LISTVIEW_AlignLeft(hwnd);
8905 LISTVIEW_AlignTop(hwnd);
8908 else if (uNewView == LVS_REPORT)
8913 if (!(LVS_NOCOLUMNHEADER & lpss->styleNew))
8917 Header_Layout(infoPtr->hwndHeader, &hl);
8918 SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, wp.cy,
8920 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
8925 ZeroMemory(&zeroRect,sizeof(RECT));
8929 Header_Layout(infoPtr->hwndHeader, &hl);
8932 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
8933 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
8934 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8935 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8937 else if (uNewView == LVS_LIST)
8939 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
8940 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
8941 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8942 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8946 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
8947 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
8948 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8949 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8950 if (lpss->styleNew & LVS_ALIGNLEFT)
8952 LISTVIEW_AlignLeft(hwnd);
8956 LISTVIEW_AlignTop(hwnd);
8960 /* update the size of the client area */
8961 LISTVIEW_UpdateSize(hwnd);
8963 /* add scrollbars if needed */
8964 LISTVIEW_UpdateScroll(hwnd);
8966 /* invalidate client area + erase background */
8967 InvalidateRect(hwnd, NULL, TRUE);
8969 /* print the list of unsupported window styles */
8970 LISTVIEW_UnsupportedStyles(lpss->styleNew);
8973 /* If they change the view and we have an active edit control
8974 we will need to kill the control since the redraw will
8975 misplace the edit control.
8977 if (infoPtr->hwndEdit &&
8978 ((uNewView & (LVS_ICON|LVS_LIST|LVS_SMALLICON)) !=
8979 ((LVS_ICON|LVS_LIST|LVS_SMALLICON) & uOldView)))
8981 SendMessageA(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
8989 * Window procedure of the listview control.
8992 static LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
8995 TRACE("hwnd=%x uMsg=%x wParam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam);
8996 if (!GetWindowLongA(hwnd, 0) && (uMsg != WM_NCCREATE))
8997 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
9000 case LVM_APPROXIMATEVIEWRECT:
9001 return LISTVIEW_ApproximateViewRect(hwnd, (INT)wParam,
9002 LOWORD(lParam), HIWORD(lParam));
9004 return LISTVIEW_Arrange(hwnd, (INT)wParam);
9006 /* case LVM_CREATEDRAGIMAGE: */
9008 case LVM_DELETEALLITEMS:
9009 return LISTVIEW_DeleteAllItems(hwnd);
9011 case LVM_DELETECOLUMN:
9012 return LISTVIEW_DeleteColumn(hwnd, (INT)wParam);
9014 case LVM_DELETEITEM:
9015 return LISTVIEW_DeleteItem(hwnd, (INT)wParam);
9017 case LVM_EDITLABELW:
9018 case LVM_EDITLABELA:
9019 return LISTVIEW_EditLabelA(hwnd, (INT)wParam);
9021 case LVM_ENSUREVISIBLE:
9022 return LISTVIEW_EnsureVisible(hwnd, (INT)wParam, (BOOL)lParam);
9025 return LISTVIEW_FindItem(hwnd, (INT)wParam, (LPLVFINDINFO)lParam);
9027 case LVM_GETBKCOLOR:
9028 return LISTVIEW_GetBkColor(hwnd);
9030 /* case LVM_GETBKIMAGE: */
9032 case LVM_GETCALLBACKMASK:
9033 return LISTVIEW_GetCallbackMask(hwnd);
9035 case LVM_GETCOLUMNA:
9036 return LISTVIEW_GetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
9038 /* case LVM_GETCOLUMNW: */
9040 case LVM_GETCOLUMNORDERARRAY:
9041 return LISTVIEW_GetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
9043 case LVM_GETCOLUMNWIDTH:
9044 return LISTVIEW_GetColumnWidth(hwnd, (INT)wParam);
9046 case LVM_GETCOUNTPERPAGE:
9047 return LISTVIEW_GetCountPerPage(hwnd);
9049 case LVM_GETEDITCONTROL:
9050 return LISTVIEW_GetEditControl(hwnd);
9052 case LVM_GETEXTENDEDLISTVIEWSTYLE:
9053 return LISTVIEW_GetExtendedListViewStyle(hwnd);
9056 return LISTVIEW_GetHeader(hwnd);
9058 /* case LVM_GETHOTCURSOR: */
9060 case LVM_GETHOTITEM:
9061 return LISTVIEW_GetHotItem(hwnd);
9063 case LVM_GETHOVERTIME:
9064 return LISTVIEW_GetHoverTime(hwnd);
9066 case LVM_GETIMAGELIST:
9067 return LISTVIEW_GetImageList(hwnd, (INT)wParam);
9069 /* case LVM_GETISEARCHSTRING: */
9072 return LISTVIEW_GetItemA(hwnd, (LPLVITEMA)lParam, FALSE);
9074 /* case LVM_GETITEMW: */
9076 case LVM_GETITEMCOUNT:
9077 return LISTVIEW_GetItemCount(hwnd);
9079 case LVM_GETITEMPOSITION:
9080 return LISTVIEW_GetItemPosition(hwnd, (INT)wParam, (LPPOINT)lParam);
9082 case LVM_GETITEMRECT:
9083 return LISTVIEW_GetItemRect(hwnd, (INT)wParam, (LPRECT)lParam);
9085 case LVM_GETITEMSPACING:
9086 return LISTVIEW_GetItemSpacing(hwnd, (BOOL)wParam);
9088 case LVM_GETITEMSTATE:
9089 return LISTVIEW_GetItemState(hwnd, (INT)wParam, (UINT)lParam);
9091 case LVM_GETITEMTEXTA:
9092 LISTVIEW_GetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
9095 /* case LVM_GETITEMTEXTW: */
9097 case LVM_GETNEXTITEM:
9098 return LISTVIEW_GetNextItem(hwnd, (INT)wParam, LOWORD(lParam));
9100 /* case LVM_GETNUMBEROFWORKAREAS: */
9103 return LISTVIEW_GetOrigin(hwnd, (LPPOINT)lParam);
9105 case LVM_GETSELECTEDCOUNT:
9106 return LISTVIEW_GetSelectedCount(hwnd);
9108 case LVM_GETSELECTIONMARK:
9109 return LISTVIEW_GetSelectionMark(hwnd);
9111 case LVM_GETSTRINGWIDTHA:
9112 return LISTVIEW_GetStringWidthA (hwnd, (LPCSTR)lParam);
9114 /* case LVM_GETSTRINGWIDTHW: */
9115 /* case LVM_GETSUBITEMRECT: */
9117 case LVM_GETTEXTBKCOLOR:
9118 return LISTVIEW_GetTextBkColor(hwnd);
9120 case LVM_GETTEXTCOLOR:
9121 return LISTVIEW_GetTextColor(hwnd);
9123 /* case LVM_GETTOOLTIPS: */
9125 case LVM_GETTOPINDEX:
9126 return LISTVIEW_GetTopIndex(hwnd);
9128 /* case LVM_GETUNICODEFORMAT: */
9130 case LVM_GETVIEWRECT:
9131 return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam);
9133 /* case LVM_GETWORKAREAS: */
9136 return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam);
9138 case LVM_INSERTCOLUMNA:
9139 return LISTVIEW_InsertColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
9141 case LVM_INSERTCOLUMNW:
9142 return LISTVIEW_InsertColumnW(hwnd, (INT)wParam, (LPLVCOLUMNW)lParam);
9144 case LVM_INSERTITEMA:
9145 return LISTVIEW_InsertItemA(hwnd, (LPLVITEMA)lParam);
9147 case LVM_INSERTITEMW:
9148 return LISTVIEW_InsertItemW(hwnd, (LPLVITEMW)lParam);
9150 case LVM_REDRAWITEMS:
9151 return LISTVIEW_RedrawItems(hwnd, (INT)wParam, (INT)lParam);
9153 /* case LVM_SCROLL: */
9154 /* return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); */
9156 case LVM_SETBKCOLOR:
9157 return LISTVIEW_SetBkColor(hwnd, (COLORREF)lParam);
9159 /* case LVM_SETBKIMAGE: */
9161 case LVM_SETCALLBACKMASK:
9162 return LISTVIEW_SetCallbackMask(hwnd, (UINT)wParam);
9164 case LVM_SETCOLUMNA:
9165 return LISTVIEW_SetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
9167 case LVM_SETCOLUMNW:
9168 FIXME("Unimplemented msg LVM_SETCOLUMNW\n");
9171 case LVM_SETCOLUMNORDERARRAY:
9172 return LISTVIEW_SetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
9174 case LVM_SETCOLUMNWIDTH:
9175 return LISTVIEW_SetColumnWidth(hwnd, (INT)wParam, SLOWORD(lParam));
9177 case LVM_SETEXTENDEDLISTVIEWSTYLE:
9178 return LISTVIEW_SetExtendedListViewStyle(hwnd, (DWORD)wParam, (DWORD)lParam);
9180 /* case LVM_SETHOTCURSOR: */
9182 case LVM_SETHOTITEM:
9183 return LISTVIEW_SetHotItem(hwnd, (INT)wParam);
9185 case LVM_SETHOVERTIME:
9186 return LISTVIEW_SetHoverTime(hwnd, (DWORD)wParam);
9188 /* case LVM_SETICONSPACING: */
9190 case LVM_SETIMAGELIST:
9191 return LISTVIEW_SetImageList(hwnd, (INT)wParam, (HIMAGELIST)lParam);
9194 return LISTVIEW_SetItemA(hwnd, (LPLVITEMA)lParam);
9196 /* case LVM_SETITEMW: */
9198 case LVM_SETITEMCOUNT:
9199 return LISTVIEW_SetItemCount(hwnd, (INT)wParam, (DWORD)lParam);
9201 case LVM_SETITEMPOSITION:
9202 return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, (INT)LOWORD(lParam),
9203 (INT)HIWORD(lParam));
9205 /* case LVM_SETITEMPOSITION32: */
9207 case LVM_SETITEMSTATE:
9208 return LISTVIEW_SetItemState(hwnd, (INT)wParam, (LPLVITEMA)lParam);
9210 case LVM_SETITEMTEXTA:
9211 return LISTVIEW_SetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
9213 /* case LVM_SETITEMTEXTW: */
9215 case LVM_SETSELECTIONMARK:
9216 return LISTVIEW_SetSelectionMark(hwnd, (INT)lParam);
9218 case LVM_SETTEXTBKCOLOR:
9219 return LISTVIEW_SetTextBkColor(hwnd, (COLORREF)lParam);
9221 case LVM_SETTEXTCOLOR:
9222 return LISTVIEW_SetTextColor(hwnd, (COLORREF)lParam);
9224 /* case LVM_SETTOOLTIPS: */
9225 /* case LVM_SETUNICODEFORMAT: */
9226 /* case LVM_SETWORKAREAS: */
9229 return LISTVIEW_SortItems(hwnd, wParam, lParam);
9231 /* case LVM_SUBITEMHITTEST: */
9234 return LISTVIEW_Update(hwnd, (INT)wParam);
9238 return LISTVIEW_ProcessLetterKeys( hwnd, wParam, lParam );
9241 return LISTVIEW_Command(hwnd, wParam, lParam);
9244 return LISTVIEW_Create(hwnd, wParam, lParam);
9247 return LISTVIEW_EraseBackground(hwnd, wParam, lParam);
9250 return DLGC_WANTCHARS | DLGC_WANTARROWS;
9253 return LISTVIEW_GetFont(hwnd);
9256 return LISTVIEW_HScroll(hwnd, (INT)LOWORD(wParam),
9257 (INT)HIWORD(wParam), (HWND)lParam);
9260 return LISTVIEW_KeyDown(hwnd, (INT)wParam, (LONG)lParam);
9263 return LISTVIEW_KillFocus(hwnd);
9265 case WM_LBUTTONDBLCLK:
9266 return LISTVIEW_LButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
9269 case WM_LBUTTONDOWN:
9270 return LISTVIEW_LButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
9273 return LISTVIEW_LButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
9276 return LISTVIEW_MouseMove (hwnd, wParam, lParam);
9279 return LISTVIEW_MouseHover(hwnd, wParam, lParam);
9282 return LISTVIEW_NCCreate(hwnd, wParam, lParam);
9285 return LISTVIEW_NCDestroy(hwnd);
9288 return LISTVIEW_Notify(hwnd, (INT)wParam, (LPNMHDR)lParam);
9290 case WM_NOTIFYFORMAT:
9291 return LISTVIEW_NotifyFormat(hwnd, (HWND)wParam, (INT)lParam);
9294 return LISTVIEW_Paint(hwnd, (HDC)wParam);
9296 case WM_RBUTTONDBLCLK:
9297 return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
9300 case WM_RBUTTONDOWN:
9301 return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
9305 return LISTVIEW_RButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
9309 return LISTVIEW_SetFocus(hwnd, (HWND)wParam);
9312 return LISTVIEW_SetFont(hwnd, (HFONT)wParam, (WORD)lParam);
9315 return LISTVIEW_SetRedraw(hwnd, (BOOL)wParam);
9318 return LISTVIEW_Size(hwnd, (int)SLOWORD(lParam), (int)SHIWORD(lParam));
9320 case WM_STYLECHANGED:
9321 return LISTVIEW_StyleChanged(hwnd, wParam, (LPSTYLESTRUCT)lParam);
9323 /* case WM_TIMER: */
9326 return LISTVIEW_VScroll(hwnd, (INT)LOWORD(wParam),
9327 (INT)HIWORD(wParam), (HWND)lParam);
9330 if (wParam & (MK_SHIFT | MK_CONTROL))
9331 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
9332 return LISTVIEW_MouseWheel(hwnd, (short int)HIWORD(wParam));/* case WM_WINDOWPOSCHANGED: */
9334 /* case WM_WININICHANGE: */
9337 if (uMsg >= WM_USER)
9339 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam,
9343 /* call default window procedure */
9344 return DefWindowProcA(hwnd, uMsg, wParam, lParam);
9352 * Registers the window class.
9360 VOID LISTVIEW_Register(void)
9364 ZeroMemory(&wndClass, sizeof(WNDCLASSA));
9365 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
9366 wndClass.lpfnWndProc = (WNDPROC)LISTVIEW_WindowProc;
9367 wndClass.cbClsExtra = 0;
9368 wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *);
9369 wndClass.hCursor = LoadCursorA(0, IDC_ARROWA);
9370 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
9371 wndClass.lpszClassName = WC_LISTVIEWA;
9372 RegisterClassA(&wndClass);
9377 * Unregisters the window class.
9385 VOID LISTVIEW_Unregister(void)
9387 UnregisterClassA(WC_LISTVIEWA, (HINSTANCE)NULL);
9392 * Handle any WM_COMMAND messages
9398 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam)
9400 switch (HIWORD(wParam))
9405 * Adjust the edit window size
9408 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
9409 HDC hdc = GetDC(infoPtr->hwndEdit);
9410 HFONT hFont, hOldFont = 0;
9415 len = GetWindowTextA(infoPtr->hwndEdit, buffer, 1023);
9416 GetWindowRect(infoPtr->hwndEdit, &rect);
9418 /* Select font to get the right dimension of the string */
9419 hFont = SendMessageA(infoPtr->hwndEdit, WM_GETFONT, 0, 0);
9422 hOldFont = SelectObject(hdc, hFont);
9425 if (GetTextExtentPoint32A(hdc, buffer, strlen(buffer), &sz))
9427 TEXTMETRICA textMetric;
9429 /* Add Extra spacing for the next character */
9430 GetTextMetricsA(hdc, &textMetric);
9431 sz.cx += (textMetric.tmMaxCharWidth * 2);
9439 rect.bottom - rect.top,
9440 SWP_DRAWFRAME|SWP_NOMOVE);
9444 SelectObject(hdc, hOldFont);
9447 ReleaseDC(hwnd, hdc);
9453 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
9462 * Subclassed edit control windproc function
9468 LRESULT CALLBACK EditLblWndProc(HWND hwnd, UINT uMsg,
9469 WPARAM wParam, LPARAM lParam)
9471 BOOL cancel = FALSE;
9472 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(GetParent(hwnd), 0);
9473 EDITLABEL_ITEM *einfo = infoPtr->pedititem;
9474 static BOOL bIgnoreKillFocus = FALSE;
9478 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
9481 if(bIgnoreKillFocus)
9489 WNDPROC editProc = einfo->EditWndProc;
9490 SetWindowLongA(hwnd, GWL_WNDPROC, (LONG)editProc);
9491 COMCTL32_Free(einfo);
9492 infoPtr->pedititem = NULL;
9493 return CallWindowProcA(editProc, hwnd, uMsg, wParam, lParam);
9497 if (VK_ESCAPE == (INT)wParam)
9503 else if (VK_RETURN == (INT)wParam)
9507 return CallWindowProcA(einfo->EditWndProc, hwnd,
9508 uMsg, wParam, lParam);
9511 if (einfo->EditLblCb)
9513 char *buffer = NULL;
9518 int len = 1 + GetWindowTextLengthA(hwnd);
9522 if (NULL != (buffer = (char *)COMCTL32_Alloc(len*sizeof(char))))
9524 GetWindowTextA(hwnd, buffer, len);
9528 /* Processing LVN_ENDLABELEDIT message could kill the focus */
9529 /* eg. Using a messagebox */
9530 bIgnoreKillFocus = TRUE;
9531 einfo->EditLblCb(GetParent(hwnd), buffer, einfo->param);
9534 COMCTL32_Free(buffer);
9536 einfo->EditLblCb = NULL;
9537 bIgnoreKillFocus = FALSE;
9540 SendMessageA(hwnd, WM_CLOSE, 0, 0);
9547 * Creates a subclassed edit cotrol
9553 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
9554 INT width, INT height, HWND parent, HINSTANCE hinst,
9555 EditlblCallback EditLblCb, DWORD param)
9561 TEXTMETRICA textMetric;
9562 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(parent, 0);
9564 if (NULL == (infoPtr->pedititem = COMCTL32_Alloc(sizeof(EDITLABEL_ITEM))))
9567 style |= WS_CHILDWINDOW|WS_CLIPSIBLINGS|ES_LEFT|WS_BORDER;
9568 hdc = GetDC(parent);
9570 /* Select the font to get appropriate metric dimensions */
9571 if(infoPtr->hFont != 0)
9573 hOldFont = SelectObject(hdc, infoPtr->hFont);
9576 /*Get String Lenght in pixels */
9577 GetTextExtentPoint32A(hdc, text, strlen(text), &sz);
9579 /*Add Extra spacing for the next character */
9580 GetTextMetricsA(hdc, &textMetric);
9581 sz.cx += (textMetric.tmMaxCharWidth * 2);
9583 if(infoPtr->hFont != 0)
9585 SelectObject(hdc, hOldFont);
9588 ReleaseDC(parent, hdc);
9589 if (!(hedit = CreateWindowA("Edit", text, style, x, y, sz.cx, height,
9590 parent, 0, hinst, 0)))
9592 COMCTL32_Free(infoPtr->pedititem);
9596 infoPtr->pedititem->param = param;
9597 infoPtr->pedititem->EditLblCb = EditLblCb;
9598 infoPtr->pedititem->EditWndProc = (WNDPROC)SetWindowLongA(hedit,
9599 GWL_WNDPROC, (LONG) EditLblWndProc);
9601 SendMessageA(hedit, WM_SETFONT, infoPtr->hFont, FALSE);