Fix ListView_GetItemRect() macro.
[wine/hacks.git] / dlls / comctl32 / listview.c
blob9fa569b28b32c21987c8cd9021b454ac0036d954
1 /*
2 * Listview control
4 * Copyright 1998, 1999 Eric Kohl
5 * Copyright 1999 Luc Tourangeau
6 * Copyright 2000 Jason Mawdsley
8 * NOTES
9 * Listview control implementation.
11 * TODO:
12 * 1. No horizontal scrolling when header is larger than the client area.
13 * 2. Drawing optimizations.
14 * 3. Hot item handling.
16 * Notifications:
17 * LISTVIEW_Notify : most notifications from children (editbox and header)
19 * Data structure:
20 * LISTVIEW_SetItemCount : not completed for non OWNERDATA
22 * Unicode:
23 * LISTVIEW_SetItemW : no unicode support
24 * LISTVIEW_InsertItemW : no unicode support
25 * LISTVIEW_InsertColumnW : no unicode support
26 * LISTVIEW_GetColumnW : no unicode support
27 * LISTVIEW_SetColumnW : no unicode support
29 * Advanced functionality:
30 * LISTVIEW_GetNumberOfWorkAreas : not implemented
31 * LISTVIEW_GetHotCursor : not implemented
32 * LISTVIEW_GetISearchString : not implemented
33 * LISTVIEW_GetBkImage : not implemented
34 * LISTVIEW_SetBkImage : not implemented
35 * LISTVIEW_GetColumnOrderArray : simple hack only
36 * LISTVIEW_SetColumnOrderArray : simple hack only
37 * LISTVIEW_Arrange : empty stub
38 * LISTVIEW_ApproximateViewRect : incomplete
39 * LISTVIEW_Scroll : not implemented
40 * LISTVIEW_Update : not completed
43 #include <ctype.h>
44 #include <string.h>
45 #include <stdlib.h>
47 #include "winbase.h"
48 #include "heap.h"
49 #include "commctrl.h"
50 #include "debugtools.h"
52 DEFAULT_DEBUG_CHANNEL(listview);
54 /* Some definitions for inline edit control */
55 typedef BOOL (*EditlblCallback)(HWND, LPSTR, DWORD);
57 typedef struct tagEDITLABEL_ITEM
59 WNDPROC EditWndProc;
60 DWORD param;
61 EditlblCallback EditLblCb;
62 } EDITLABEL_ITEM;
64 typedef struct tagLISTVIEW_SUBITEM
66 LPSTR pszText;
67 INT iImage;
68 INT iSubItem;
70 } LISTVIEW_SUBITEM;
72 typedef struct tagLISTVIEW_ITEM
74 UINT state;
75 LPSTR pszText;
76 INT iImage;
77 LPARAM lParam;
78 INT iIndent;
79 POINT ptPosition;
81 } LISTVIEW_ITEM;
83 typedef struct tagLISTVIEW_SELECTION
85 DWORD lower;
86 DWORD upper;
87 } LISTVIEW_SELECTION;
89 typedef struct tagLISTVIEW_INFO
91 COLORREF clrBk;
92 COLORREF clrText;
93 COLORREF clrTextBk;
94 HIMAGELIST himlNormal;
95 HIMAGELIST himlSmall;
96 HIMAGELIST himlState;
97 BOOL bLButtonDown;
98 BOOL bRButtonDown;
99 INT nFocusedItem;
100 HDPA hdpaSelectionRanges;
101 INT nItemHeight;
102 INT nItemWidth;
103 INT nSelectionMark;
104 INT nHotItem;
105 SHORT notifyFormat;
106 RECT rcList;
107 RECT rcView;
108 SIZE iconSize;
109 SIZE iconSpacing;
110 UINT uCallbackMask;
111 HWND hwndHeader;
112 HFONT hDefaultFont;
113 HFONT hFont;
114 BOOL bFocus;
115 DWORD dwExStyle; /* extended listview style */
116 HDPA hdpaItems;
117 PFNLVCOMPARE pfnCompare;
118 LPARAM lParamSort;
119 HWND hwndEdit;
120 INT nEditLabelItem;
121 EDITLABEL_ITEM *pedititem;
122 DWORD dwHoverTime;
123 INT nColumnCount; /* the number of columns in this control */
125 WPARAM charCode; /* Added */
126 CHAR szSearchParam[ MAX_PATH ]; /* Added */
127 DWORD timeSinceLastKeyPress; /* Added */
128 INT nSearchParamLength; /* Added */
129 } LISTVIEW_INFO;
132 * constants
135 /* maximum size of a label */
136 #define DISP_TEXT_SIZE 512
138 /* padding for items in list and small icon display modes */
139 #define WIDTH_PADDING 12
141 /* padding for items in list, report and small icon display modes */
142 #define HEIGHT_PADDING 1
144 /* offset of items in report display mode */
145 #define REPORT_MARGINX 2
147 /* padding for icon in large icon display mode */
148 #define ICON_TOP_PADDING 2
149 #define ICON_BOTTOM_PADDING 2
151 /* padding for label in large icon display mode */
152 #define LABEL_VERT_OFFSET 2
154 /* default label width for items in list and small icon display modes */
155 #define DEFAULT_LABEL_WIDTH 40
157 /* default column width for items in list display mode */
158 #define DEFAULT_COLUMN_WIDTH 96
160 /* Increment size of the horizontal scroll bar */
161 #define LISTVIEW_SCROLL_DIV_SIZE 10
163 /* Padding betwen image and label */
164 #define IMAGE_PADDING 2
166 /* Padding behind the label */
167 #define TRAILING_PADDING 5
169 /* Border for the icon caption */
170 #define CAPTION_BORDER 2
172 * macros
174 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
175 #define ListView_LVNotify(hwnd,lCtrlId,plvnm) \
176 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMLISTVIEW)(plvnm))
177 #define ListView_Notify(hwnd,lCtrlId,pnmh) \
178 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMHDR)(pnmh))
179 /* retrieve the number of items in the listview */
180 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
182 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
183 INT width, INT height, HWND parent, HINSTANCE hinst,
184 EditlblCallback EditLblCb, DWORD param);
187 * forward declarations
189 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem, BOOL internal);
190 static INT LISTVIEW_HitTestItem(HWND, LPLVHITTESTINFO, BOOL);
191 static INT LISTVIEW_GetCountPerRow(HWND);
192 static INT LISTVIEW_GetCountPerColumn(HWND);
193 static VOID LISTVIEW_AlignLeft(HWND);
194 static VOID LISTVIEW_AlignTop(HWND);
195 static VOID LISTVIEW_AddGroupSelection(HWND, INT);
196 static VOID LISTVIEW_AddSelection(HWND, INT);
197 static BOOL LISTVIEW_AddSubItem(HWND, LPLVITEMA);
198 static INT LISTVIEW_FindInsertPosition(HDPA, INT);
199 static INT LISTVIEW_GetItemHeight(HWND);
200 static BOOL LISTVIEW_GetItemPosition(HWND, INT, LPPOINT);
201 static LRESULT LISTVIEW_GetItemRect(HWND, INT, LPRECT);
202 static INT LISTVIEW_GetItemWidth(HWND);
203 static INT LISTVIEW_GetLabelWidth(HWND, INT);
204 static LRESULT LISTVIEW_GetOrigin(HWND, LPPOINT);
205 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem);
206 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA, INT);
207 static LRESULT LISTVIEW_GetViewRect(HWND, LPRECT);
208 static BOOL LISTVIEW_InitItem(HWND, LISTVIEW_ITEM *, LPLVITEMA);
209 static BOOL LISTVIEW_InitSubItem(HWND, LISTVIEW_SUBITEM *, LPLVITEMA);
210 static LRESULT LISTVIEW_MouseSelection(HWND, POINT);
211 static BOOL LISTVIEW_RemoveColumn(HDPA, INT);
212 static BOOL LISTVIEW_RemoveSubItem(HDPA, INT);
213 static VOID LISTVIEW_SetGroupSelection(HWND, INT);
214 static BOOL LISTVIEW_SetItem(HWND, LPLVITEMA);
215 static BOOL LISTVIEW_SetItemFocus(HWND, INT);
216 static BOOL LISTVIEW_SetItemPosition(HWND, INT, LONG, LONG);
217 static VOID LISTVIEW_UpdateScroll(HWND);
218 static VOID LISTVIEW_SetSelection(HWND, INT);
219 static VOID LISTVIEW_UpdateSize(HWND);
220 static BOOL LISTVIEW_SetSubItem(HWND, LPLVITEMA);
221 static LRESULT LISTVIEW_SetViewRect(HWND, LPRECT);
222 static BOOL LISTVIEW_ToggleSelection(HWND, INT);
223 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle);
224 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem);
225 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem);
226 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam);
227 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam);
228 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText);
229 static INT LISTVIEW_ProcessLetterKeys( HWND hwnd, WPARAM charCode, LPARAM keyData );
230 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem);
231 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask);
232 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem);
233 static BOOL LISTVIEW_IsSelected(HWND hwnd, INT nItem);
234 static VOID LISTVIEW_RemoveSelectionRange(HWND hwnd, INT lItem, INT uItem);
235 static void LISTVIEW_FillBackground(HWND hwnd, HDC hdc, LPRECT rc);
237 /******** Defines that LISTVIEW_ProcessLetterKeys uses ****************/
238 #define KEY_DELAY 900
239 #define LISTVIEW_InitLvItemStruct(item,idx,TEXT) \
240 ZeroMemory(&(item), sizeof(LVITEMA)); \
241 (item).mask = LVIF_TEXT; \
242 (item).iItem = (idx); \
243 (item).iSubItem = 0; \
244 (item).pszText = (TEXT); \
245 (item).cchTextMax = MAX_PATH
247 static BOOL
248 LISTVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
249 RECT rc)
251 LISTVIEW_INFO *infoPtr;
252 NMLVCUSTOMDRAW nmcdhdr;
253 LPNMCUSTOMDRAW nmcd;
255 TRACE("drawstage:%lx hdc:%x\n", dwDrawStage, hdc);
257 infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
259 nmcd= & nmcdhdr.nmcd;
260 nmcd->hdr.hwndFrom = hwnd;
261 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
262 nmcd->hdr.code = NM_CUSTOMDRAW;
263 nmcd->dwDrawStage= dwDrawStage;
264 nmcd->hdc = hdc;
265 nmcd->rc.left = rc.left;
266 nmcd->rc.right = rc.right;
267 nmcd->rc.bottom = rc.bottom;
268 nmcd->rc.top = rc.top;
269 nmcd->dwItemSpec = 0;
270 nmcd->uItemState = 0;
271 nmcd->lItemlParam= 0;
272 nmcdhdr.clrText = infoPtr->clrText;
273 nmcdhdr.clrTextBk= infoPtr->clrBk;
275 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
276 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
279 static BOOL
280 LISTVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
281 UINT iItem, UINT iSubItem,
282 UINT uItemDrawState)
284 LISTVIEW_INFO *infoPtr;
285 NMLVCUSTOMDRAW nmcdhdr;
286 LPNMCUSTOMDRAW nmcd;
287 DWORD dwDrawStage,dwItemSpec;
288 UINT uItemState;
289 INT retval;
290 RECT itemRect;
291 LVITEMA item;
293 infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
295 ZeroMemory(&item,sizeof(LVITEMA));
296 item.iItem = iItem;
297 item.mask = LVIF_PARAM;
298 ListView_GetItemA(hwnd,&item);
300 dwDrawStage=CDDS_ITEM | uItemDrawState;
301 dwItemSpec=iItem;
302 uItemState=0;
304 if (LISTVIEW_IsSelected(hwnd,iItem)) uItemState|=CDIS_SELECTED;
305 if (iItem==infoPtr->nFocusedItem) uItemState|=CDIS_FOCUS;
306 if (iItem==infoPtr->nHotItem) uItemState|=CDIS_HOT;
308 itemRect.left = LVIR_BOUNDS;
309 LISTVIEW_GetItemRect(hwnd, iItem, &itemRect);
311 nmcd= & nmcdhdr.nmcd;
312 nmcd->hdr.hwndFrom = hwnd;
313 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
314 nmcd->hdr.code = NM_CUSTOMDRAW;
315 nmcd->dwDrawStage= dwDrawStage;
316 nmcd->hdc = hdc;
317 nmcd->rc.left = itemRect.left;
318 nmcd->rc.right = itemRect.right;
319 nmcd->rc.bottom = itemRect.bottom;
320 nmcd->rc.top = itemRect.top;
321 nmcd->dwItemSpec = dwItemSpec;
322 nmcd->uItemState = uItemState;
323 nmcd->lItemlParam= item.lParam;
324 nmcdhdr.clrText = infoPtr->clrText;
325 nmcdhdr.clrTextBk= infoPtr->clrBk;
326 nmcdhdr.iSubItem =iSubItem;
328 TRACE("drawstage:%lx hdc:%x item:%lx, itemstate:%x, lItemlParam:%lx\n",
329 nmcd->dwDrawStage, nmcd->hdc, nmcd->dwItemSpec,
330 nmcd->uItemState, nmcd->lItemlParam);
332 retval=SendMessageA (GetParent (hwnd), WM_NOTIFY,
333 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
335 infoPtr->clrText=nmcdhdr.clrText;
336 infoPtr->clrBk =nmcdhdr.clrTextBk;
337 return (BOOL) retval;
341 /*************************************************************************
342 * DESCRIPTION:
343 * Processes keyboard messages generated by pressing the letter keys on the keyboard.
344 * Assumes the list is sorted alphabetically, without regard to case.
346 * PARAMETERS:
347 * [I] HWND: handle to the window
348 * [I] WPARAM: the character code, the actual character
349 * [I] LPARAM: key data
352 * RETURN:
353 * Zero.
355 * TODO:
359 static INT LISTVIEW_ProcessLetterKeys( HWND hwnd, WPARAM charCode, LPARAM keyData )
361 LISTVIEW_INFO *infoPtr = NULL;
362 INT nItem = -1;
363 BOOL bRedraw;
364 INT nSize = 0;
365 INT idx = 0;
366 BOOL bFoundMatchingFiles = FALSE;
367 LVITEMA item;
368 CHAR TEXT[ MAX_PATH ];
369 CHAR szCharCode[ 2 ];
370 DWORD timeSinceLastKeyPress = 0;
372 szCharCode[0] = charCode;
373 szCharCode[1] = 0;
375 /* simple parameter checking */
376 if ( !hwnd || !charCode || !keyData )
377 return 0;
379 infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
381 if ( !infoPtr )
382 return 0;
384 /* only allow the valid WM_CHARs through */
385 if ( isalnum( charCode ) || charCode == '.' || charCode == '`' || charCode == '!'
386 || charCode == '@' || charCode == '#' || charCode == '$' || charCode == '%'
387 || charCode == '^' || charCode == '&' || charCode == '*' || charCode == '('
388 || charCode == ')' || charCode == '-' || charCode == '_' || charCode == '+'
389 || charCode == '=' || charCode == '\\'|| charCode == ']' || charCode == '}'
390 || charCode == '[' || charCode == '{' || charCode == '/' || charCode == '?'
391 || charCode == '>' || charCode == '<' || charCode == ',' || charCode == '~')
393 timeSinceLastKeyPress = GetTickCount();
395 nSize = GETITEMCOUNT( infoPtr );
396 /* if there are 0 items, there is no where to go */
397 if ( nSize == 0 )
398 return 0;
400 * If the last charCode equals the current charCode then look
401 * to the next element in list to see if it matches the previous
402 * charCode.
404 if ( infoPtr->charCode == charCode )
406 if ( timeSinceLastKeyPress - infoPtr->timeSinceLastKeyPress < KEY_DELAY )
407 { /* append new character to search string */
408 strcat( infoPtr->szSearchParam, szCharCode );
409 infoPtr->nSearchParamLength++;
411 /* loop from start of list view */
412 for( idx = infoPtr->nFocusedItem; idx < nSize; idx++ )
413 { /* get item */
414 LISTVIEW_InitLvItemStruct( item, idx, TEXT );
415 ListView_GetItemA( hwnd, &item );
417 /* compare items */
418 if ( strncasecmp( item.pszText, infoPtr->szSearchParam,
419 infoPtr->nSearchParamLength ) == 0 )
421 nItem = idx;
422 break;
426 else if ( infoPtr->timeSinceLastKeyPress > timeSinceLastKeyPress )
427 { /* The DWORD went over it's boundary?? Ergo assuming too slow??. */
428 for ( idx = 0; idx < nSize; idx++ )
430 LISTVIEW_InitLvItemStruct( item, idx, TEXT );
431 ListView_GetItemA( hwnd, &item );
433 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
435 nItem = idx;
436 break;
439 strcpy( infoPtr->szSearchParam, szCharCode );
440 infoPtr->nSearchParamLength = 1;
442 else
443 { /* Save szCharCode for use in later searches */
444 strcpy( infoPtr->szSearchParam, szCharCode );
445 infoPtr->nSearchParamLength = 1;
447 LISTVIEW_InitLvItemStruct( item, infoPtr->nFocusedItem + 1, TEXT );
448 ListView_GetItemA( hwnd, &item );
450 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
451 nItem = infoPtr->nFocusedItem + 1;
452 else
453 { /*
454 * Ok so there are no more folders that match
455 * now we look for files.
457 for ( idx = infoPtr->nFocusedItem + 1; idx < nSize; idx ++ )
459 LISTVIEW_InitLvItemStruct( item, idx, TEXT );
460 ListView_GetItemA( hwnd, &item );
462 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
464 nItem = idx;
465 bFoundMatchingFiles = TRUE;
466 break;
469 if ( !bFoundMatchingFiles )
470 { /* go back to first instance */
471 for ( idx = 0; idx < nSize; idx ++ )
473 LISTVIEW_InitLvItemStruct( item,idx, TEXT );
474 ListView_GetItemA( hwnd, &item );
476 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
478 nItem = idx;
479 break;
485 } /*END: if ( infoPtr->charCode == charCode )*/
487 else /* different keypressed */
489 /* could be that they are spelling the file/directory for us */
490 if ( timeSinceLastKeyPress - infoPtr->timeSinceLastKeyPress > KEY_DELAY )
491 { /*
492 * Too slow, move to the first instance of the
493 * charCode.
495 for ( idx = 0; idx < nSize; idx++ )
497 LISTVIEW_InitLvItemStruct( item,idx, TEXT );
498 ListView_GetItemA( hwnd, &item );
500 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
502 nItem = idx;
503 break;
506 strcpy( infoPtr->szSearchParam, szCharCode );
507 infoPtr->nSearchParamLength = 1;
509 else if ( infoPtr->timeSinceLastKeyPress > timeSinceLastKeyPress )
510 { /* The DWORD went over it's boundery?? Ergo assuming too slow??. */
511 for ( idx = 0; idx < nSize; idx++ )
513 LISTVIEW_InitLvItemStruct( item,idx, TEXT );
514 ListView_GetItemA( hwnd, &item );
516 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
518 nItem = idx;
519 break;
522 strcpy( infoPtr->szSearchParam, szCharCode );
523 infoPtr->nSearchParamLength = 1;
525 else /* Search for the string the user is typing */
527 /* append new character to search string */
528 strcat( infoPtr->szSearchParam, szCharCode );
529 infoPtr->nSearchParamLength++;
531 /* loop from start of list view */
532 for( idx = 0; idx < nSize; idx++ )
533 { /* get item */
534 LISTVIEW_InitLvItemStruct( item, idx, TEXT );
535 ListView_GetItemA( hwnd, &item );
537 /* compare items */
538 if ( strncasecmp( item.pszText, infoPtr->szSearchParam,
539 infoPtr->nSearchParamLength ) == 0 )
541 nItem = idx;
542 break;
546 }/*END: else */
548 else
549 return 0;
551 bRedraw = LISTVIEW_KeySelection(hwnd, nItem );
552 if (bRedraw != FALSE)
554 /* refresh client area */
555 InvalidateRect(hwnd, NULL, TRUE);
556 UpdateWindow(hwnd);
559 /* Store the WM_CHAR for next time */
560 infoPtr->charCode = charCode;
562 /* Store time */
563 infoPtr->timeSinceLastKeyPress = timeSinceLastKeyPress;
565 return 0;
569 /*************************************************************************
570 * LISTVIEW_UpdateHeaderSize [Internal]
572 * Function to resize the header control
574 * PARAMS
575 * hwnd [I] handle to a window
576 * nNewScrollPos [I] Scroll Pos to Set
578 * RETURNS
579 * nothing
581 * NOTES
583 static VOID LISTVIEW_UpdateHeaderSize(HWND hwnd, INT nNewScrollPos)
585 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
586 RECT winRect;
587 POINT point[2];
589 GetWindowRect(infoPtr->hwndHeader, &winRect);
590 point[0].x = winRect.left;
591 point[0].y = winRect.top;
592 point[1].x = winRect.right;
593 point[1].y = winRect.bottom;
595 MapWindowPoints(HWND_DESKTOP, hwnd, point, 2);
596 point[0].x = -(nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
597 point[1].x += (nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
599 SetWindowPos(infoPtr->hwndHeader,0,
600 point[0].x,point[0].y,point[1].x,point[1].y,
601 SWP_NOZORDER | SWP_NOACTIVATE);
604 /***
605 * DESCRIPTION:
606 * Update the scrollbars. This functions should be called whenever
607 * the content, size or view changes.
609 * PARAMETER(S):
610 * [I] HWND : window handle
612 * RETURN:
613 * None
615 static VOID LISTVIEW_UpdateScroll(HWND hwnd)
617 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
618 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
619 UINT uView = lStyle & LVS_TYPEMASK;
620 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
621 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
622 SCROLLINFO scrollInfo;
624 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
625 scrollInfo.cbSize = sizeof(SCROLLINFO);
627 if (uView == LVS_LIST)
629 /* update horizontal scrollbar */
631 INT nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
632 INT nCountPerRow = LISTVIEW_GetCountPerRow(hwnd);
633 INT nNumOfItems = GETITEMCOUNT(infoPtr);
635 scrollInfo.nMax = nNumOfItems / nCountPerColumn;
636 if((nNumOfItems % nCountPerColumn) == 0)
638 scrollInfo.nMax--;
640 scrollInfo.nPos = ListView_GetTopIndex(hwnd) / nCountPerColumn;
641 scrollInfo.nPage = nCountPerRow;
642 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
643 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
644 ShowScrollBar(hwnd, SB_VERT, FALSE);
646 else if (uView == LVS_REPORT)
648 /* update vertical scrollbar */
649 scrollInfo.nMin = 0;
650 scrollInfo.nMax = GETITEMCOUNT(infoPtr) - 1;
651 scrollInfo.nPos = ListView_GetTopIndex(hwnd);
652 scrollInfo.nPage = LISTVIEW_GetCountPerColumn(hwnd);
653 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
654 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
656 /* update horizontal scrollbar */
657 nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
658 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE
659 || GETITEMCOUNT(infoPtr) == 0)
661 scrollInfo.nPos = 0;
663 scrollInfo.nMin = 0;
664 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE ;
665 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
666 scrollInfo.nMax = max(infoPtr->nItemWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
667 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
669 /* Update the Header Control */
670 scrollInfo.fMask = SIF_POS;
671 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
672 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
675 else
677 RECT rcView;
679 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
681 INT nViewWidth = rcView.right - rcView.left;
682 INT nViewHeight = rcView.bottom - rcView.top;
684 /* Update Horizontal Scrollbar */
685 scrollInfo.fMask = SIF_POS;
686 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE
687 || GETITEMCOUNT(infoPtr) == 0)
689 scrollInfo.nPos = 0;
691 scrollInfo.nMax = max(nViewWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
692 scrollInfo.nMin = 0;
693 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
694 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
695 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
697 /* Update Vertical Scrollbar */
698 nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
699 scrollInfo.fMask = SIF_POS;
700 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) == FALSE
701 || GETITEMCOUNT(infoPtr) == 0)
703 scrollInfo.nPos = 0;
705 scrollInfo.nMax = max(nViewHeight / LISTVIEW_SCROLL_DIV_SIZE,0)-1;
706 scrollInfo.nMin = 0;
707 scrollInfo.nPage = nListHeight / LISTVIEW_SCROLL_DIV_SIZE;
708 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
709 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
714 /***
715 * DESCRIPTION:
716 * Prints a message for unsupported window styles.
717 * A kind of TODO list for window styles.
719 * PARAMETER(S):
720 * [I] LONG : window style
722 * RETURN:
723 * None
725 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle)
727 if ((LVS_TYPEMASK & lStyle) == LVS_EDITLABELS)
729 FIXME(" LVS_EDITLABELS\n");
732 if ((LVS_TYPEMASK & lStyle) == LVS_NOLABELWRAP)
734 FIXME(" LVS_NOLABELWRAP\n");
737 if ((LVS_TYPEMASK & lStyle) == LVS_NOSCROLL)
739 FIXME(" LVS_NOSCROLL\n");
742 if ((LVS_TYPEMASK & lStyle) == LVS_NOSORTHEADER)
744 FIXME(" LVS_NOSORTHEADER\n");
747 if ((LVS_TYPEMASK & lStyle) == LVS_OWNERDRAWFIXED)
749 FIXME(" LVS_OWNERDRAWFIXED\n");
752 if ((LVS_TYPEMASK & lStyle) == LVS_SHAREIMAGELISTS)
754 FIXME(" LVS_SHAREIMAGELISTS\n");
757 if ((LVS_TYPEMASK & lStyle) == LVS_SORTASCENDING)
759 FIXME(" LVS_SORTASCENDING\n");
762 if ((LVS_TYPEMASK & lStyle) == LVS_SORTDESCENDING)
764 FIXME(" LVS_SORTDESCENDING\n");
768 /***
769 * DESCRIPTION:
770 * Aligns the items with the top edge of the window.
772 * PARAMETER(S):
773 * [I] HWND : window handle
775 * RETURN:
776 * None
778 static VOID LISTVIEW_AlignTop(HWND hwnd)
780 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
781 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
782 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
783 POINT ptItem;
784 RECT rcView;
785 INT i;
787 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
789 ZeroMemory(&ptItem, sizeof(POINT));
790 ZeroMemory(&rcView, sizeof(RECT));
792 if (nListWidth > infoPtr->nItemWidth)
794 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
796 if (ptItem.x + infoPtr->nItemWidth > nListWidth)
798 ptItem.x = 0;
799 ptItem.y += infoPtr->nItemHeight;
802 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
803 ptItem.x += infoPtr->nItemWidth;
804 rcView.right = max(rcView.right, ptItem.x);
807 rcView.bottom = ptItem.y + infoPtr->nItemHeight;
809 else
811 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
813 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
814 ptItem.y += infoPtr->nItemHeight;
817 rcView.right = infoPtr->nItemWidth;
818 rcView.bottom = ptItem.y;
821 LISTVIEW_SetViewRect(hwnd, &rcView);
825 /***
826 * DESCRIPTION:
827 * Aligns the items with the left edge of the window.
829 * PARAMETER(S):
830 * [I] HWND : window handle
832 * RETURN:
833 * None
835 static VOID LISTVIEW_AlignLeft(HWND hwnd)
837 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
838 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
839 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
840 POINT ptItem;
841 RECT rcView;
842 INT i;
844 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
846 ZeroMemory(&ptItem, sizeof(POINT));
847 ZeroMemory(&rcView, sizeof(RECT));
849 if (nListHeight > infoPtr->nItemHeight)
851 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
853 if (ptItem.y + infoPtr->nItemHeight > nListHeight)
855 ptItem.y = 0;
856 ptItem.x += infoPtr->nItemWidth;
859 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
860 ptItem.y += infoPtr->nItemHeight;
861 rcView.bottom = max(rcView.bottom, ptItem.y);
864 rcView.right = ptItem.x + infoPtr->nItemWidth;
866 else
868 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
870 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
871 ptItem.x += infoPtr->nItemWidth;
874 rcView.bottom = infoPtr->nItemHeight;
875 rcView.right = ptItem.x;
878 LISTVIEW_SetViewRect(hwnd, &rcView);
882 /***
883 * DESCRIPTION:
884 * Set the bounding rectangle of all the items.
886 * PARAMETER(S):
887 * [I] HWND : window handle
888 * [I] LPRECT : bounding rectangle
890 * RETURN:
891 * SUCCESS : TRUE
892 * FAILURE : FALSE
894 static LRESULT LISTVIEW_SetViewRect(HWND hwnd, LPRECT lprcView)
896 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
897 BOOL bResult = FALSE;
899 TRACE("(hwnd=%x, left=%d, top=%d, right=%d, bottom=%d)\n", hwnd,
900 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
902 if (lprcView != NULL)
904 bResult = TRUE;
905 infoPtr->rcView.left = lprcView->left;
906 infoPtr->rcView.top = lprcView->top;
907 infoPtr->rcView.right = lprcView->right;
908 infoPtr->rcView.bottom = lprcView->bottom;
911 return bResult;
914 /***
915 * DESCRIPTION:
916 * Retrieves the bounding rectangle of all the items.
918 * PARAMETER(S):
919 * [I] HWND : window handle
920 * [O] LPRECT : bounding rectangle
922 * RETURN:
923 * SUCCESS : TRUE
924 * FAILURE : FALSE
926 static LRESULT LISTVIEW_GetViewRect(HWND hwnd, LPRECT lprcView)
928 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
929 BOOL bResult = FALSE;
930 POINT ptOrigin;
932 TRACE("(hwnd=%x, lprcView=%p)\n", hwnd, lprcView);
934 if (lprcView != NULL)
936 bResult = LISTVIEW_GetOrigin(hwnd, &ptOrigin);
937 if (bResult != FALSE)
939 lprcView->left = infoPtr->rcView.left + ptOrigin.x;
940 lprcView->top = infoPtr->rcView.top + ptOrigin.y;
941 lprcView->right = infoPtr->rcView.right + ptOrigin.x;
942 lprcView->bottom = infoPtr->rcView.bottom + ptOrigin.y;
945 TRACE("(left=%d, top=%d, right=%d, bottom=%d)\n",
946 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
949 return bResult;
952 /***
953 * DESCRIPTION:
954 * Retrieves the subitem pointer associated with the subitem index.
956 * PARAMETER(S):
957 * [I] HDPA : DPA handle for a specific item
958 * [I] INT : index of subitem
960 * RETURN:
961 * SUCCESS : subitem pointer
962 * FAILURE : NULL
964 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems,
965 INT nSubItem)
967 LISTVIEW_SUBITEM *lpSubItem;
968 INT i;
970 for (i = 1; i < hdpaSubItems->nItemCount; i++)
972 lpSubItem = (LISTVIEW_SUBITEM *) DPA_GetPtr(hdpaSubItems, i);
973 if (lpSubItem != NULL)
975 if (lpSubItem->iSubItem == nSubItem)
977 return lpSubItem;
982 return NULL;
985 /***
986 * DESCRIPTION:
987 * Calculates the width of an item.
989 * PARAMETER(S):
990 * [I] HWND : window handle
991 * [I] LONG : window style
993 * RETURN:
994 * Returns item width.
996 static INT LISTVIEW_GetItemWidth(HWND hwnd)
998 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
999 LONG style = GetWindowLongA(hwnd, GWL_STYLE);
1000 UINT uView = style & LVS_TYPEMASK;
1001 INT nHeaderItemCount;
1002 RECT rcHeaderItem;
1003 INT nItemWidth = 0;
1004 INT nLabelWidth;
1005 INT i;
1007 TRACE("(hwnd=%x)\n", hwnd);
1009 if (uView == LVS_ICON)
1011 nItemWidth = infoPtr->iconSpacing.cx;
1013 else if (uView == LVS_REPORT)
1015 /* calculate width of header */
1016 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
1017 for (i = 0; i < nHeaderItemCount; i++)
1019 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
1021 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
1025 else
1027 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
1029 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, i);
1030 nItemWidth = max(nItemWidth, nLabelWidth);
1033 /* default label size */
1034 if (GETITEMCOUNT(infoPtr) == 0)
1036 nItemWidth = DEFAULT_COLUMN_WIDTH;
1038 else
1040 if (nItemWidth == 0)
1042 nItemWidth = DEFAULT_LABEL_WIDTH;
1044 else
1046 /* add padding */
1047 nItemWidth += WIDTH_PADDING;
1049 if (infoPtr->himlSmall != NULL)
1051 nItemWidth += infoPtr->iconSize.cx;
1054 if (infoPtr->himlState != NULL)
1056 nItemWidth += infoPtr->iconSize.cx;
1061 if(nItemWidth == 0)
1063 /* nItemWidth Cannot be Zero */
1064 nItemWidth = 1;
1066 return nItemWidth;
1069 /***
1070 * DESCRIPTION:
1071 * Calculates the width of a specific item.
1073 * PARAMETER(S):
1074 * [I] HWND : window handle
1075 * [I] LPSTR : string
1077 * RETURN:
1078 * Returns the width of an item width a specified string.
1080 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem)
1082 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1083 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
1084 INT nHeaderItemCount;
1085 RECT rcHeaderItem;
1086 INT nItemWidth = 0;
1087 INT i;
1089 TRACE("(hwnd=%x)\n", hwnd);
1091 if (uView == LVS_ICON)
1093 nItemWidth = infoPtr->iconSpacing.cx;
1095 else if (uView == LVS_REPORT)
1097 /* calculate width of header */
1098 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
1099 for (i = 0; i < nHeaderItemCount; i++)
1101 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
1103 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
1107 else
1109 /* get width of string */
1110 nItemWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
1112 /* default label size */
1113 if (GETITEMCOUNT(infoPtr) == 0)
1115 nItemWidth = DEFAULT_COLUMN_WIDTH;
1117 else
1119 if (nItemWidth == 0)
1121 nItemWidth = DEFAULT_LABEL_WIDTH;
1123 else
1125 /* add padding */
1126 nItemWidth += WIDTH_PADDING;
1128 if (infoPtr->himlSmall != NULL)
1130 nItemWidth += infoPtr->iconSize.cx;
1133 if (infoPtr->himlState != NULL)
1135 nItemWidth += infoPtr->iconSize.cx;
1141 return nItemWidth;
1144 /***
1145 * DESCRIPTION:
1146 * Calculates the height of an item.
1148 * PARAMETER(S):
1149 * [I] HWND : window handle
1150 * [I] LONG : window style
1152 * RETURN:
1153 * Returns item height.
1155 static INT LISTVIEW_GetItemHeight(HWND hwnd)
1157 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1158 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
1159 INT nItemHeight = 0;
1161 if (uView == LVS_ICON)
1163 nItemHeight = infoPtr->iconSpacing.cy;
1165 else
1167 TEXTMETRICA tm;
1168 HDC hdc = GetDC(hwnd);
1169 HFONT hOldFont = SelectObject(hdc, infoPtr->hFont);
1170 GetTextMetricsA(hdc, &tm);
1172 if(infoPtr->himlState || infoPtr->himlSmall)
1173 nItemHeight = max(tm.tmHeight, infoPtr->iconSize.cy) + HEIGHT_PADDING;
1174 else
1175 nItemHeight = tm.tmHeight;
1177 SelectObject(hdc, hOldFont);
1178 ReleaseDC(hwnd, hdc);
1181 return nItemHeight;
1185 static void LISTVIEW_PrintSelectionRanges(HWND hwnd)
1187 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1188 LISTVIEW_SELECTION *selection;
1189 INT topSelection = infoPtr->hdpaSelectionRanges->nItemCount;
1190 INT i;
1192 TRACE("Selections are:\n");
1193 for (i = 0; i < topSelection; i++)
1195 selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,i);
1196 TRACE(" %lu - %lu\n",selection->lower,selection->upper);
1200 /***
1201 * DESCRIPTION:
1202 * A compare function for selection ranges
1204 *PARAMETER(S)
1205 * [I] LPVOID : Item 1;
1206 * [I] LPVOID : Item 2;
1207 * [I] LPARAM : flags
1209 *RETURNS:
1210 * >0 : if Item 1 > Item 2
1211 * <0 : if Item 2 > Item 1
1212 * 0 : if Item 1 == Item 2
1214 static INT CALLBACK LISTVIEW_CompareSelectionRanges(LPVOID range1, LPVOID range2,
1215 LPARAM flags)
1217 int l1 = ((LISTVIEW_SELECTION*)(range1))->lower;
1218 int l2 = ((LISTVIEW_SELECTION*)(range2))->lower;
1219 int u1 = ((LISTVIEW_SELECTION*)(range1))->upper;
1220 int u2 = ((LISTVIEW_SELECTION*)(range2))->upper;
1221 int rc=0;
1223 if (u1 < l2)
1224 rc= -1;
1226 if (u2 < l1)
1227 rc= 1;
1229 return rc;
1233 * DESCRIPTION:
1234 * Adds a selection range.
1236 * PARAMETER(S):
1237 * [I] HWND : window handle
1238 * [I] INT : lower item index
1239 * [I] INT : upper item index
1241 * RETURN:
1242 * None
1244 static VOID LISTVIEW_AddSelectionRange(HWND hwnd, INT lItem, INT uItem)
1246 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1247 LISTVIEW_SELECTION *selection;
1248 INT topSelection = infoPtr->hdpaSelectionRanges->nItemCount;
1249 BOOL lowerzero=FALSE;
1251 selection = (LISTVIEW_SELECTION *)COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION));
1252 selection->lower = lItem;
1253 selection->upper = uItem;
1255 TRACE("Add range %i - %i\n",lItem,uItem);
1256 if (topSelection)
1258 LISTVIEW_SELECTION *checkselection,*checkselection2;
1259 INT index,mergeindex;
1261 /* find overlapping selections */
1262 /* we want to catch adjacent ranges so expand our range by 1 */
1264 selection->upper++;
1265 if (selection->lower == 0)
1266 lowerzero = TRUE;
1267 else
1268 selection->lower--;
1270 index = DPA_Search(infoPtr->hdpaSelectionRanges, selection, 0,
1271 LISTVIEW_CompareSelectionRanges,
1272 0,0);
1273 selection->upper --;
1274 if (lowerzero)
1275 lowerzero=FALSE;
1276 else
1277 selection->lower ++;
1279 if (index >=0)
1281 checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,index);
1282 TRACE("Merge with index %i (%lu - %lu)\n",index,checkselection->lower,
1283 checkselection->upper);
1285 checkselection->lower = min(selection->lower,checkselection->lower);
1286 checkselection->upper = max(selection->upper,checkselection->upper);
1288 TRACE("New range (%lu - %lu)\n", checkselection->lower,
1289 checkselection->upper);
1291 COMCTL32_Free(selection);
1293 /* merge now common selection ranges in the lower group*/
1296 checkselection->upper ++;
1297 if (checkselection->lower == 0)
1298 lowerzero = TRUE;
1299 else
1300 checkselection->lower --;
1302 TRACE("search lower range (%lu - %lu)\n", checkselection->lower,
1303 checkselection->upper);
1305 /* not sorted yet */
1306 mergeindex = DPA_Search(infoPtr->hdpaSelectionRanges, checkselection, 0,
1307 LISTVIEW_CompareSelectionRanges, 0,
1310 checkselection->upper --;
1311 if (lowerzero)
1312 lowerzero = FALSE;
1313 else
1314 checkselection->lower ++;
1316 if (mergeindex >=0 && mergeindex != index)
1318 TRACE("Merge with index %i\n",mergeindex);
1319 checkselection2 = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
1320 mergeindex);
1321 checkselection->lower = min(checkselection->lower,
1322 checkselection2->lower);
1323 checkselection->upper = max(checkselection->upper,
1324 checkselection2->upper);
1325 COMCTL32_Free(checkselection2);
1326 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,mergeindex);
1327 index --;
1330 while (mergeindex > -1 && mergeindex <index);
1332 /* merge now common selection ranges in the upper group*/
1335 checkselection->upper ++;
1336 if (checkselection->lower == 0)
1337 lowerzero = TRUE;
1338 else
1339 checkselection->lower --;
1341 TRACE("search upper range %i (%lu - %lu)\n",index,
1342 checkselection->lower, checkselection->upper);
1344 /* not sorted yet */
1345 mergeindex = DPA_Search(infoPtr->hdpaSelectionRanges, checkselection,
1346 index+1,
1347 LISTVIEW_CompareSelectionRanges, 0,
1350 checkselection->upper --;
1351 if (lowerzero)
1352 lowerzero = FALSE;
1353 else
1354 checkselection->lower ++;
1356 if (mergeindex >=0 && mergeindex !=index)
1358 TRACE("Merge with index %i\n",mergeindex);
1359 checkselection2 = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
1360 mergeindex);
1361 checkselection->lower = min(checkselection->lower,
1362 checkselection2->lower);
1363 checkselection->upper = max(checkselection->upper,
1364 checkselection2->upper);
1365 COMCTL32_Free(checkselection2);
1366 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,mergeindex);
1369 while (mergeindex > -1);
1371 else
1374 index = DPA_Search(infoPtr->hdpaSelectionRanges, selection, 0,
1375 LISTVIEW_CompareSelectionRanges, 0,
1376 DPAS_INSERTAFTER);
1378 TRACE("Insert before index %i\n",index);
1379 if (index == -1)
1380 index = 0;
1381 DPA_InsertPtr(infoPtr->hdpaSelectionRanges,index,selection);
1384 else
1386 DPA_InsertPtr(infoPtr->hdpaSelectionRanges,0,selection);
1389 * Incase of error
1391 DPA_Sort(infoPtr->hdpaSelectionRanges,LISTVIEW_CompareSelectionRanges,0);
1392 LISTVIEW_PrintSelectionRanges(hwnd);
1396 * DESCRIPTION:
1397 * check if a specified index is selected.
1399 * PARAMETER(S):
1400 * [I] HWND : window handle
1401 * [I] INT : item index
1403 * RETURN:
1404 * None
1406 static BOOL LISTVIEW_IsSelected(HWND hwnd, INT nItem)
1408 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1409 LISTVIEW_SELECTION selection;
1410 INT index;
1412 selection.upper = nItem;
1413 selection.lower = nItem;
1415 index = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, 0,
1416 LISTVIEW_CompareSelectionRanges,
1417 0,DPAS_SORTED);
1418 if (index != -1)
1419 return TRUE;
1420 else
1421 return FALSE;
1424 /***
1425 * DESCRIPTION:
1426 * Removes all selection ranges
1428 * Parameters(s):
1429 * HWND: window handle
1431 * RETURNS:
1432 * SUCCESS : TRUE
1433 * FAILURE : TRUE
1435 static LRESULT LISTVIEW_RemoveAllSelections(HWND hwnd)
1437 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1438 LISTVIEW_SELECTION *selection;
1439 INT i;
1440 LVITEMA item;
1442 TRACE("(0x%x)\n",hwnd);
1444 ZeroMemory(&item,sizeof(LVITEMA));
1445 item.stateMask = LVIS_SELECTED;
1449 selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,0);
1450 if (selection)
1452 TRACE("Removing %lu to %lu\n",selection->lower, selection->upper);
1453 for (i = selection->lower; i<=selection->upper; i++)
1454 LISTVIEW_SetItemState(hwnd,i,&item);
1455 LISTVIEW_RemoveSelectionRange(hwnd,selection->lower,selection->upper);
1458 while (infoPtr->hdpaSelectionRanges->nItemCount>0);
1460 TRACE("done\n");
1461 return TRUE;
1465 * DESCRIPTION:
1466 * Removes a range selections.
1468 * PARAMETER(S):
1469 * [I] HWND : window handle
1470 * [I] INT : lower item index
1471 * [I] INT : upper item index
1473 * RETURN:
1474 * None
1476 static VOID LISTVIEW_RemoveSelectionRange(HWND hwnd, INT lItem, INT uItem)
1478 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1479 LISTVIEW_SELECTION removeselection,*checkselection;
1480 INT index;
1482 removeselection.lower = lItem;
1483 removeselection.upper = uItem;
1485 TRACE("Remove range %lu - %lu\n",removeselection.lower,removeselection.upper);
1486 LISTVIEW_PrintSelectionRanges(hwnd);
1488 index = DPA_Search(infoPtr->hdpaSelectionRanges, &removeselection, 0,
1489 LISTVIEW_CompareSelectionRanges,
1490 0,0);
1492 if (index == -1)
1493 return;
1496 checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
1497 index);
1499 TRACE("Matches range index %i (%lu-%lu)\n",index,checkselection->lower,
1500 checkselection->upper);
1502 /* case 1: Same */
1503 if ((checkselection->upper == removeselection.upper) &&
1504 (checkselection->lower == removeselection.lower))
1506 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,index);
1507 TRACE("Case 1\n");
1509 /* case 2: engulf */
1510 else if (((checkselection->upper < removeselection.upper) &&
1511 (checkselection->lower > removeselection.lower))||
1512 ((checkselection->upper <= removeselection.upper) &&
1513 (checkselection->lower > removeselection.lower)) ||
1514 ((checkselection->upper < removeselection.upper) &&
1515 (checkselection->lower >= removeselection.lower)))
1518 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,index);
1519 /* do it again because others may also get caught */
1520 TRACE("Case 2\n");
1521 LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
1523 /* case 3: overlap upper */
1524 else if ((checkselection->upper < removeselection.upper) &&
1525 (checkselection->lower < removeselection.lower))
1527 checkselection->upper = removeselection.lower - 1;
1528 TRACE("Case 3\n");
1529 LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
1531 /* case 4: overlap lower */
1532 else if ((checkselection->upper > removeselection.upper) &&
1533 (checkselection->lower > removeselection.lower))
1535 checkselection->lower = removeselection.upper + 1;
1536 TRACE("Case 4\n");
1537 LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
1539 /* case 5: fully internal */
1540 else if (checkselection->upper == removeselection.upper)
1541 checkselection->upper = removeselection.lower - 1;
1542 else if (checkselection->lower == removeselection.lower)
1543 checkselection->lower = removeselection.upper + 1;
1544 else
1546 /* bisect the range */
1547 LISTVIEW_SELECTION *newselection;
1549 newselection = (LISTVIEW_SELECTION *)
1550 COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION));
1551 newselection -> lower = checkselection->lower;
1552 newselection -> upper = removeselection.lower - 1;
1553 checkselection -> lower = removeselection.upper + 1;
1554 DPA_InsertPtr(infoPtr->hdpaSelectionRanges,index,newselection);
1555 TRACE("Case 5\n");
1556 DPA_Sort(infoPtr->hdpaSelectionRanges,LISTVIEW_CompareSelectionRanges,0);
1558 LISTVIEW_PrintSelectionRanges(hwnd);
1562 * DESCRIPTION:
1563 * shifts all selection indexs starting with the indesx specified
1564 * in the direction specified.
1566 * PARAMETER(S):
1567 * [I] HWND : window handle
1568 * [I] INT : item index
1569 * [I] INT : amount and direction of shift
1571 * RETURN:
1572 * None
1574 static VOID LISTVIEW_ShiftSelections(HWND hwnd, INT nItem, INT direction)
1576 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1577 LISTVIEW_SELECTION selection,*checkselection;
1578 INT index;
1580 TRACE("Shifting %iu, %i steps\n",nItem,direction);
1582 selection.upper = nItem;
1583 selection.lower = nItem;
1585 index = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, 0,
1586 LISTVIEW_CompareSelectionRanges,
1587 0,DPAS_SORTED|DPAS_INSERTAFTER);
1589 while ((index < infoPtr->hdpaSelectionRanges->nItemCount)&&(index != -1))
1591 checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,index);
1592 if ((checkselection->lower >= nItem)&&
1593 (checkselection->lower + direction >= 0))
1594 checkselection->lower += direction;
1595 if ((checkselection->upper >= nItem)&&
1596 (checkselection->upper + direction >=0))
1597 checkselection->upper += direction;
1598 index ++;
1604 * DESCRIPTION:
1605 * Adds a block of selections.
1607 * PARAMETER(S):
1608 * [I] HWND : window handle
1609 * [I] INT : item index
1611 * RETURN:
1612 * None
1614 static VOID LISTVIEW_AddGroupSelection(HWND hwnd, INT nItem)
1616 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1617 INT nFirst = min(infoPtr->nSelectionMark, nItem);
1618 INT nLast = max(infoPtr->nSelectionMark, nItem);
1619 INT i;
1620 LVITEMA item;
1622 ZeroMemory(&item,sizeof(LVITEMA));
1623 item.stateMask = LVIS_SELECTED;
1624 item.state = LVIS_SELECTED;
1626 for (i = nFirst; i <= nLast; i++);
1628 LISTVIEW_SetItemState(hwnd,i,&item);
1631 LISTVIEW_SetItemFocus(hwnd, nItem);
1632 infoPtr->nSelectionMark = nItem;
1636 /***
1637 * DESCRIPTION:
1638 * Adds a single selection.
1640 * PARAMETER(S):
1641 * [I] HWND : window handle
1642 * [I] INT : item index
1644 * RETURN:
1645 * None
1647 static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem)
1649 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1650 LVITEMA item;
1652 ZeroMemory(&item,sizeof(LVITEMA));
1653 item.state = LVIS_SELECTED;
1654 item.stateMask = LVIS_SELECTED;
1656 LISTVIEW_SetItemState(hwnd,nItem,&item);
1658 LISTVIEW_SetItemFocus(hwnd, nItem);
1659 infoPtr->nSelectionMark = nItem;
1662 /***
1663 * DESCRIPTION:
1664 * Selects or unselects an item.
1666 * PARAMETER(S):
1667 * [I] HWND : window handle
1668 * [I] INT : item index
1670 * RETURN:
1671 * SELECT: TRUE
1672 * UNSELECT : FALSE
1674 static BOOL LISTVIEW_ToggleSelection(HWND hwnd, INT nItem)
1676 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1677 BOOL bResult;
1678 LVITEMA item;
1680 ZeroMemory(&item,sizeof(LVITEMA));
1681 item.stateMask = LVIS_SELECTED;
1683 if (LISTVIEW_IsSelected(hwnd,nItem))
1686 LISTVIEW_SetItemState(hwnd,nItem,&item);
1687 bResult = FALSE;
1689 else
1691 item.state = LVIS_SELECTED;
1692 LISTVIEW_SetItemState(hwnd,nItem,&item);
1693 bResult = TRUE;
1696 LISTVIEW_SetItemFocus(hwnd, nItem);
1697 infoPtr->nSelectionMark = nItem;
1699 return bResult;
1702 /***
1703 * DESCRIPTION:
1704 * Selects items based on view coordinates.
1706 * PARAMETER(S):
1707 * [I] HWND : window handle
1708 * [I] RECT : selection rectangle
1710 * RETURN:
1711 * None
1713 static VOID LISTVIEW_SetSelectionRect(HWND hwnd, RECT rcSelRect)
1715 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1716 POINT ptItem;
1717 INT i;
1718 LVITEMA item;
1720 ZeroMemory(&item,sizeof(LVITEMA));
1721 item.stateMask = LVIS_SELECTED;
1723 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
1725 LISTVIEW_GetItemPosition(hwnd, i, &ptItem);
1727 if (PtInRect(&rcSelRect, ptItem) != FALSE)
1729 item.state = LVIS_SELECTED;
1730 LISTVIEW_SetItemState(hwnd,i,&item);
1732 else
1734 item.state = 0;
1735 LISTVIEW_SetItemState(hwnd,i,&item);
1740 /***
1741 * DESCRIPTION:
1742 * Sets a single group selection.
1744 * PARAMETER(S):
1745 * [I] HWND : window handle
1746 * [I] INT : item index
1748 * RETURN:
1749 * None
1751 static VOID LISTVIEW_SetGroupSelection(HWND hwnd, INT nItem)
1753 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1754 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
1755 LVITEMA item;
1757 ZeroMemory(&item,sizeof(LVITEMA));
1758 item.stateMask = LVIS_SELECTED;
1760 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
1762 INT i;
1763 INT nFirst = min(infoPtr->nSelectionMark, nItem);
1764 INT nLast = max(infoPtr->nSelectionMark, nItem);
1766 for (i = 0; i <= GETITEMCOUNT(infoPtr); i++)
1768 if ((i < nFirst) || (i > nLast))
1770 item.state = 0;
1771 LISTVIEW_SetItemState(hwnd,i,&item);
1773 else
1775 item.state = LVIS_SELECTED;
1776 LISTVIEW_SetItemState(hwnd,i,&item);
1780 else
1782 POINT ptItem;
1783 POINT ptSelMark;
1784 RECT rcSel;
1785 LISTVIEW_GetItemPosition(hwnd, nItem, &ptItem);
1786 LISTVIEW_GetItemPosition(hwnd, infoPtr->nSelectionMark, &ptSelMark);
1787 rcSel.left = min(ptSelMark.x, ptItem.x);
1788 rcSel.top = min(ptSelMark.y, ptItem.y);
1789 rcSel.right = max(ptSelMark.x, ptItem.x) + infoPtr->nItemWidth;
1790 rcSel.bottom = max(ptSelMark.y, ptItem.y) + infoPtr->nItemHeight;
1791 LISTVIEW_SetSelectionRect(hwnd, rcSel);
1794 LISTVIEW_SetItemFocus(hwnd, nItem);
1797 /***
1798 * DESCRIPTION:
1799 * Manages the item focus.
1801 * PARAMETER(S):
1802 * [I] HWND : window handle
1803 * [I] INT : item index
1805 * RETURN:
1806 * TRUE : focused item changed
1807 * FALSE : focused item has NOT changed
1809 static BOOL LISTVIEW_SetItemFocus(HWND hwnd, INT nItem)
1811 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1812 BOOL bResult = FALSE;
1813 LVITEMA lvItem;
1815 if (infoPtr->nFocusedItem != nItem)
1817 if (infoPtr->nFocusedItem >= 0)
1819 INT oldFocus = infoPtr->nFocusedItem;
1820 bResult = TRUE;
1821 infoPtr->nFocusedItem = -1;
1822 ZeroMemory(&lvItem, sizeof(LVITEMA));
1823 lvItem.stateMask = LVIS_FOCUSED;
1824 ListView_SetItemState(hwnd, oldFocus, &lvItem);
1828 lvItem.state = LVIS_FOCUSED;
1829 lvItem.stateMask = LVIS_FOCUSED;
1830 ListView_SetItemState(hwnd, nItem, &lvItem);
1832 infoPtr->nFocusedItem = nItem;
1833 ListView_EnsureVisible(hwnd, nItem, FALSE);
1836 return bResult;
1839 /***
1840 * DESCRIPTION:
1841 * Sets a single selection.
1843 * PARAMETER(S):
1844 * [I] HWND : window handle
1845 * [I] INT : item index
1847 * RETURN:
1848 * None
1850 static VOID LISTVIEW_SetSelection(HWND hwnd, INT nItem)
1852 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1853 LVITEMA lvItem;
1855 ZeroMemory(&lvItem, sizeof(LVITEMA));
1856 lvItem.stateMask = LVIS_FOCUSED;
1857 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
1859 LISTVIEW_RemoveAllSelections(hwnd);
1861 lvItem.state = LVIS_FOCUSED|LVIS_SELECTED;
1862 lvItem.stateMask = LVIS_FOCUSED|LVIS_SELECTED;
1863 ListView_SetItemState(hwnd, nItem, &lvItem);
1865 infoPtr->nFocusedItem = nItem;
1866 infoPtr->nSelectionMark = nItem;
1869 /***
1870 * DESCRIPTION:
1871 * Set selection(s) with keyboard.
1873 * PARAMETER(S):
1874 * [I] HWND : window handle
1875 * [I] INT : item index
1877 * RETURN:
1878 * SUCCESS : TRUE (needs to be repainted)
1879 * FAILURE : FALSE (nothing has changed)
1881 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem)
1883 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1884 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1885 WORD wShift = HIWORD(GetKeyState(VK_SHIFT));
1886 WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL));
1887 BOOL bResult = FALSE;
1889 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
1891 if (lStyle & LVS_SINGLESEL)
1893 bResult = TRUE;
1894 LISTVIEW_SetSelection(hwnd, nItem);
1895 ListView_EnsureVisible(hwnd, nItem, FALSE);
1897 else
1899 if (wShift)
1901 bResult = TRUE;
1902 LISTVIEW_SetGroupSelection(hwnd, nItem);
1904 else if (wCtrl)
1906 bResult = LISTVIEW_SetItemFocus(hwnd, nItem);
1908 else
1910 bResult = TRUE;
1911 LISTVIEW_SetSelection(hwnd, nItem);
1912 ListView_EnsureVisible(hwnd, nItem, FALSE);
1917 return bResult;
1920 /***
1921 * DESCRIPTION:
1922 * Called when the mouse is being actively tracked and has hovered for a specified
1923 * amount of time
1925 * PARAMETER(S):
1926 * [I] HWND : window handle
1927 * [I] wParam : key indicator
1928 * [I] lParam : mouse position
1930 * RETURN:
1931 * 0 if the message was processed, non-zero if there was an error
1933 * INFO:
1934 * LVS_EX_TRACKSELECT: An item is automatically selected when the cursor remains
1935 * over the item for a certain period of time.
1938 static LRESULT LISTVIEW_MouseHover(HWND hwnd, WPARAM wParam, LPARAM lParam)
1940 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1941 POINT pt;
1943 pt.x = (INT)LOWORD(lParam);
1944 pt.y = (INT)HIWORD(lParam);
1946 if(infoPtr->dwExStyle & LVS_EX_TRACKSELECT) {
1947 /* select the item under the cursor */
1948 LISTVIEW_MouseSelection(hwnd, pt);
1951 return 0;
1954 /***
1955 * DESCRIPTION:
1956 * Called whenever WM_MOUSEMOVE is recieved.
1958 * PARAMETER(S):
1959 * [I] HWND : window handle
1960 * [I] wParam : key indicators
1961 * [I] lParam : cursor position
1963 * RETURN:
1964 * 0 if the message is processed, non-zero if there was an error
1966 static LRESULT LISTVIEW_MouseMove(HWND hwnd, WPARAM wParam, LPARAM lParam)
1968 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1969 TRACKMOUSEEVENT trackinfo;
1971 /* see if we are supposed to be tracking mouse hovering */
1972 if(infoPtr->dwExStyle & LVS_EX_TRACKSELECT) {
1973 /* fill in the trackinfo struct */
1974 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
1975 trackinfo.dwFlags = TME_QUERY;
1976 trackinfo.hwndTrack = hwnd;
1977 trackinfo.dwHoverTime = infoPtr->dwHoverTime;
1979 /* see if we are already tracking this hwnd */
1980 _TrackMouseEvent(&trackinfo);
1982 if(!(trackinfo.dwFlags & TME_HOVER)) {
1983 trackinfo.dwFlags = TME_HOVER;
1985 /* call TRACKMOUSEEVENT so we recieve WM_MOUSEHOVER messages */
1986 _TrackMouseEvent(&trackinfo);
1990 return 0;
1993 /***
1994 * DESCRIPTION:
1995 * Selects an item based on coordinates.
1997 * PARAMETER(S):
1998 * [I] HWND : window handle
1999 * [I] POINT : mouse click ccordinates
2001 * RETURN:
2002 * SUCCESS : item index
2003 * FAILURE : -1
2005 static LRESULT LISTVIEW_MouseSelection(HWND hwnd, POINT pt)
2007 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2008 RECT rcItem;
2009 INT i,topindex,bottomindex;
2010 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2011 UINT uView = lStyle & LVS_TYPEMASK;
2013 topindex = ListView_GetTopIndex(hwnd);
2014 if (uView == LVS_REPORT)
2016 bottomindex = topindex + LISTVIEW_GetCountPerColumn(hwnd) + 1;
2017 bottomindex = min(bottomindex,GETITEMCOUNT(infoPtr));
2019 else
2021 bottomindex = GETITEMCOUNT(infoPtr);
2024 for (i = topindex; i < bottomindex; i++)
2026 rcItem.left = LVIR_SELECTBOUNDS;
2027 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) == TRUE)
2029 if (PtInRect(&rcItem, pt) != FALSE)
2031 return i;
2036 return -1;
2039 /***
2040 * DESCRIPTION:
2041 * Removes a column.
2043 * PARAMETER(S):
2044 * [IO] HDPA : dynamic pointer array handle
2045 * [I] INT : column index (subitem index)
2047 * RETURN:
2048 * SUCCCESS : TRUE
2049 * FAILURE : FALSE
2051 static BOOL LISTVIEW_RemoveColumn(HDPA hdpaItems, INT nSubItem)
2053 BOOL bResult = TRUE;
2054 HDPA hdpaSubItems;
2055 INT i;
2057 for (i = 0; i < hdpaItems->nItemCount; i++)
2059 hdpaSubItems = (HDPA)DPA_GetPtr(hdpaItems, i);
2060 if (hdpaSubItems != NULL)
2062 if (LISTVIEW_RemoveSubItem(hdpaSubItems, nSubItem) == FALSE)
2064 bResult = FALSE;
2069 return bResult;
2072 /***
2073 * DESCRIPTION:
2074 * Removes a subitem at a given position.
2076 * PARAMETER(S):
2077 * [IO] HDPA : dynamic pointer array handle
2078 * [I] INT : subitem index
2080 * RETURN:
2081 * SUCCCESS : TRUE
2082 * FAILURE : FALSE
2084 static BOOL LISTVIEW_RemoveSubItem(HDPA hdpaSubItems, INT nSubItem)
2086 LISTVIEW_SUBITEM *lpSubItem;
2087 INT i;
2089 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2091 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2092 if (lpSubItem != NULL)
2094 if (lpSubItem->iSubItem == nSubItem)
2096 /* free string */
2097 if ((lpSubItem->pszText != NULL) &&
2098 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2100 COMCTL32_Free(lpSubItem->pszText);
2103 /* free item */
2104 COMCTL32_Free(lpSubItem);
2106 /* free dpa memory */
2107 if (DPA_DeletePtr(hdpaSubItems, i) == NULL)
2109 return FALSE;
2112 else if (lpSubItem->iSubItem > nSubItem)
2114 return TRUE;
2119 return TRUE;
2122 /***
2123 * DESCRIPTION:
2124 * Compares the item information.
2126 * PARAMETER(S):
2127 * [I] LISTVIEW_ITEM *: destination item
2128 * [I] LPLVITEM : source item
2130 * RETURN:
2131 * SUCCCESS : TRUE (EQUAL)
2132 * FAILURE : FALSE (NOT EQUAL)
2134 static UINT LISTVIEW_GetItemChanges(LISTVIEW_ITEM *lpItem, LPLVITEMA lpLVItem)
2136 UINT uChanged = 0;
2138 if ((lpItem != NULL) && (lpLVItem != NULL))
2140 if (lpLVItem->mask & LVIF_STATE)
2142 if ((lpItem->state & lpLVItem->stateMask) !=
2143 (lpLVItem->state & lpLVItem->stateMask))
2145 uChanged |= LVIF_STATE;
2149 if (lpLVItem->mask & LVIF_IMAGE)
2151 if (lpItem->iImage != lpLVItem->iImage)
2153 uChanged |= LVIF_IMAGE;
2157 if (lpLVItem->mask & LVIF_PARAM)
2159 if (lpItem->lParam != lpLVItem->lParam)
2161 uChanged |= LVIF_PARAM;
2165 if (lpLVItem->mask & LVIF_INDENT)
2167 if (lpItem->iIndent != lpLVItem->iIndent)
2169 uChanged |= LVIF_INDENT;
2173 if (lpLVItem->mask & LVIF_TEXT)
2175 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
2177 if (lpItem->pszText != LPSTR_TEXTCALLBACKA)
2179 uChanged |= LVIF_TEXT;
2182 else
2184 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
2186 uChanged |= LVIF_TEXT;
2188 else
2190 if (lpLVItem->pszText)
2192 if (lpItem->pszText)
2194 if (strcmp(lpLVItem->pszText, lpItem->pszText) != 0)
2196 uChanged |= LVIF_TEXT;
2199 else
2201 uChanged |= LVIF_TEXT;
2204 else
2206 if (lpItem->pszText)
2208 uChanged |= LVIF_TEXT;
2215 return uChanged;
2218 /***
2219 * DESCRIPTION:
2220 * Initializes item attributes.
2222 * PARAMETER(S):
2223 * [I] HWND : window handle
2224 * [O] LISTVIEW_ITEM *: destination item
2225 * [I] LPLVITEM : source item
2227 * RETURN:
2228 * SUCCCESS : TRUE
2229 * FAILURE : FALSE
2231 static BOOL LISTVIEW_InitItem(HWND hwnd, LISTVIEW_ITEM *lpItem,
2232 LPLVITEMA lpLVItem)
2234 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2235 BOOL bResult = FALSE;
2237 if ((lpItem != NULL) && (lpLVItem != NULL))
2239 bResult = TRUE;
2241 if (lpLVItem->mask & LVIF_STATE)
2243 lpItem->state &= ~lpLVItem->stateMask;
2244 lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
2247 if (lpLVItem->mask & LVIF_IMAGE)
2249 lpItem->iImage = lpLVItem->iImage;
2252 if (lpLVItem->mask & LVIF_PARAM)
2254 lpItem->lParam = lpLVItem->lParam;
2257 if (lpLVItem->mask & LVIF_INDENT)
2259 lpItem->iIndent = lpLVItem->iIndent;
2262 if (lpLVItem->mask & LVIF_TEXT)
2264 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
2266 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
2268 return FALSE;
2271 if ((lpItem->pszText != NULL) &&
2272 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2274 COMCTL32_Free(lpItem->pszText);
2277 lpItem->pszText = LPSTR_TEXTCALLBACKA;
2279 else
2281 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
2283 lpItem->pszText = NULL;
2286 bResult = Str_SetPtrA(&lpItem->pszText, lpLVItem->pszText);
2291 return bResult;
2294 /***
2295 * DESCRIPTION:
2296 * Initializes subitem attributes.
2298 * NOTE: The documentation specifies that the operation fails if the user
2299 * tries to set the indent of a subitem.
2301 * PARAMETER(S):
2302 * [I] HWND : window handle
2303 * [O] LISTVIEW_SUBITEM *: destination subitem
2304 * [I] LPLVITEM : source subitem
2306 * RETURN:
2307 * SUCCCESS : TRUE
2308 * FAILURE : FALSE
2310 static BOOL LISTVIEW_InitSubItem(HWND hwnd, LISTVIEW_SUBITEM *lpSubItem,
2311 LPLVITEMA lpLVItem)
2313 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2314 BOOL bResult = FALSE;
2316 if ((lpSubItem != NULL) && (lpLVItem != NULL))
2318 if (!(lpLVItem->mask & LVIF_INDENT))
2320 bResult = TRUE;
2322 lpSubItem->iSubItem = lpLVItem->iSubItem;
2324 if (lpLVItem->mask & LVIF_IMAGE)
2326 lpSubItem->iImage = lpLVItem->iImage;
2329 if (lpLVItem->mask & LVIF_TEXT)
2331 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
2333 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
2335 return FALSE;
2338 if ((lpSubItem->pszText != NULL) &&
2339 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2341 COMCTL32_Free(lpSubItem->pszText);
2344 lpSubItem->pszText = LPSTR_TEXTCALLBACKA;
2346 else
2348 if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
2350 lpSubItem->pszText = NULL;
2353 bResult = Str_SetPtrA(&lpSubItem->pszText, lpLVItem->pszText);
2359 return bResult;
2362 /***
2363 * DESCRIPTION:
2364 * Adds a subitem at a given position (column index).
2366 * PARAMETER(S):
2367 * [I] HWND : window handle
2368 * [I] LPLVITEM : new subitem atttributes
2370 * RETURN:
2371 * SUCCESS : TRUE
2372 * FAILURE : FALSE
2374 static BOOL LISTVIEW_AddSubItem(HWND hwnd, LPLVITEMA lpLVItem)
2376 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2377 LISTVIEW_SUBITEM *lpSubItem = NULL;
2378 BOOL bResult = FALSE;
2379 HDPA hdpaSubItems;
2380 INT nPosition, nItem;
2381 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2383 if (lStyle & LVS_OWNERDATA)
2384 return FALSE;
2386 if (lpLVItem != NULL)
2388 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
2389 if (hdpaSubItems != NULL)
2391 lpSubItem = (LISTVIEW_SUBITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM));
2392 if (lpSubItem != NULL)
2394 ZeroMemory(lpSubItem, sizeof(LISTVIEW_SUBITEM));
2395 if (LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem) != FALSE)
2397 nPosition = LISTVIEW_FindInsertPosition(hdpaSubItems,
2398 lpSubItem->iSubItem);
2399 nItem = DPA_InsertPtr(hdpaSubItems, nPosition, lpSubItem);
2400 if (nItem != -1)
2402 bResult = TRUE;
2409 /* cleanup if unsuccessful */
2410 if ((bResult == FALSE) && (lpSubItem != NULL))
2412 COMCTL32_Free(lpSubItem);
2415 return bResult;
2418 /***
2419 * DESCRIPTION:
2420 * Finds the dpa insert position (array index).
2422 * PARAMETER(S):
2423 * [I] HWND : window handle
2424 * [I] INT : subitem index
2426 * RETURN:
2427 * SUCCESS : TRUE
2428 * FAILURE : FALSE
2430 static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem)
2432 LISTVIEW_SUBITEM *lpSubItem;
2433 INT i;
2435 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2437 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2438 if (lpSubItem != NULL)
2440 if (lpSubItem->iSubItem > nSubItem)
2442 return i;
2447 return hdpaSubItems->nItemCount;
2450 /***
2451 * DESCRIPTION:
2452 * Retrieves a listview subitem at a given position (column index).
2454 * PARAMETER(S):
2455 * [I] HWND : window handle
2456 * [I] INT : subitem index
2458 * RETURN:
2459 * SUCCESS : TRUE
2460 * FAILURE : FALSE
2462 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem)
2464 LISTVIEW_SUBITEM *lpSubItem;
2465 INT i;
2467 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2469 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2470 if (lpSubItem != NULL)
2472 if (lpSubItem->iSubItem == nSubItem)
2474 return lpSubItem;
2476 else if (lpSubItem->iSubItem > nSubItem)
2478 return NULL;
2483 return NULL;
2486 /***
2487 * DESCRIPTION:
2488 * Sets item attributes.
2490 * PARAMETER(S):
2491 * [I] HWND : window handle
2492 * [I] LPLVITEM : new item atttributes
2494 * RETURN:
2495 * SUCCESS : TRUE
2496 * FAILURE : FALSE
2498 static BOOL LISTVIEW_SetItem(HWND hwnd, LPLVITEMA lpLVItem)
2500 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2501 BOOL bResult = FALSE;
2502 HDPA hdpaSubItems;
2503 LISTVIEW_ITEM *lpItem;
2504 NMLISTVIEW nmlv;
2505 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2506 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2507 UINT uChanged;
2508 UINT uView = lStyle & LVS_TYPEMASK;
2509 INT item_width;
2510 RECT rcItem;
2512 if (lStyle & LVS_OWNERDATA)
2514 if ((lpLVItem->iSubItem == 0)&&(lpLVItem->mask == LVIF_STATE))
2516 LVITEMA itm;
2518 ZeroMemory(&itm,sizeof(LVITEMA));
2519 itm.mask = LVIF_STATE | LVIF_PARAM;
2520 itm.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
2521 itm.iItem = lpLVItem->iItem;
2522 itm.iSubItem = 0;
2523 ListView_GetItemA(hwnd,&itm);
2526 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2527 nmlv.hdr.hwndFrom = hwnd;
2528 nmlv.hdr.idFrom = lCtrlId;
2529 nmlv.hdr.code = LVN_ITEMCHANGING;
2530 nmlv.uNewState = lpLVItem->state;
2531 nmlv.uOldState = itm.state;
2532 nmlv.uChanged = LVIF_STATE;
2533 nmlv.lParam = itm.lParam;
2534 nmlv.iItem = lpLVItem->iItem;
2536 if ((itm.state & lpLVItem->stateMask) !=
2537 (lpLVItem->state & lpLVItem->stateMask))
2539 /* send LVN_ITEMCHANGING notification */
2540 if (!ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv))
2542 if (lpLVItem->stateMask & LVIS_FOCUSED)
2544 if (lpLVItem->state & LVIS_FOCUSED)
2545 infoPtr->nFocusedItem = lpLVItem->iItem;
2546 else if (infoPtr->nFocusedItem == lpLVItem->iItem)
2547 infoPtr->nFocusedItem = -1;
2549 if (lpLVItem->stateMask & LVIS_SELECTED)
2551 if (lpLVItem->state & LVIS_SELECTED)
2553 if (lStyle & LVS_SINGLESEL)
2555 LISTVIEW_RemoveAllSelections(hwnd);
2557 LISTVIEW_AddSelectionRange(hwnd,lpLVItem->iItem,lpLVItem->iItem);
2559 else
2560 LISTVIEW_RemoveSelectionRange(hwnd,lpLVItem->iItem,
2561 lpLVItem->iItem);
2564 nmlv.hdr.code = LVN_ITEMCHANGED;
2566 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2568 rcItem.left = LVIR_BOUNDS;
2569 LISTVIEW_GetItemRect(hwnd, lpLVItem->iItem, &rcItem);
2570 InvalidateRect(hwnd, &rcItem, TRUE);
2573 return TRUE;
2575 return FALSE;
2578 if (lpLVItem != NULL)
2580 if (lpLVItem->iSubItem == 0)
2582 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
2583 if (hdpaSubItems != NULL && hdpaSubItems != (HDPA)-1)
2585 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem);
2586 if (lpItem != NULL)
2588 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2589 nmlv.hdr.hwndFrom = hwnd;
2590 nmlv.hdr.idFrom = lCtrlId;
2591 nmlv.hdr.code = LVN_ITEMCHANGING;
2592 nmlv.lParam = lpItem->lParam;
2593 uChanged = LISTVIEW_GetItemChanges(lpItem, lpLVItem);
2594 if (uChanged != 0)
2596 if (uChanged & LVIF_STATE)
2598 nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask;
2599 nmlv.uOldState = lpItem->state & lpLVItem->stateMask;
2601 if (nmlv.uNewState & LVIS_SELECTED)
2604 * This is redundant if called through SetSelection
2606 * however is required if the used directly calls SetItem
2607 * to set the selection.
2609 if (lStyle & LVS_SINGLESEL)
2611 LISTVIEW_RemoveAllSelections(hwnd);
2614 LISTVIEW_AddSelectionRange(hwnd,lpLVItem->iItem,
2615 lpLVItem->iItem);
2617 else if (lpLVItem->stateMask & LVIS_SELECTED)
2619 LISTVIEW_RemoveSelectionRange(hwnd,lpLVItem->iItem,
2620 lpLVItem->iItem);
2622 if (nmlv.uNewState & LVIS_FOCUSED)
2625 * This is a fun hoop to jump to try to catch if
2626 * the user is calling us directly to call focus or if
2627 * this function is being called as a result of a
2628 * SetItemFocus call.
2630 if (infoPtr->nFocusedItem >= 0)
2631 LISTVIEW_SetItemFocus(hwnd, lpLVItem->iItem);
2635 nmlv.uChanged = uChanged;
2636 nmlv.iItem = lpLVItem->iItem;
2637 nmlv.lParam = lpItem->lParam;
2638 /* send LVN_ITEMCHANGING notification */
2639 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2641 /* copy information */
2642 bResult = LISTVIEW_InitItem(hwnd, lpItem, lpLVItem);
2644 /* if LVS_LIST or LVS_SMALLICON, update the width of the items
2645 based on the width of the items text */
2646 if((uView == LVS_LIST) || (uView == LVS_SMALLICON))
2648 item_width = LISTVIEW_GetStringWidthA(hwnd, lpItem->pszText);
2650 if(item_width > infoPtr->nItemWidth)
2651 infoPtr->nItemWidth = item_width;
2654 /* send LVN_ITEMCHANGED notification */
2655 nmlv.hdr.code = LVN_ITEMCHANGED;
2656 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2658 else
2660 bResult = TRUE;
2663 if (uChanged)
2665 rcItem.left = LVIR_BOUNDS;
2666 LISTVIEW_GetItemRect(hwnd, lpLVItem->iItem, &rcItem);
2667 InvalidateRect(hwnd, &rcItem, TRUE);
2674 return bResult;
2677 /***
2678 * DESCRIPTION:
2679 * Sets subitem attributes.
2681 * PARAMETER(S):
2682 * [I] HWND : window handle
2683 * [I] LPLVITEM : new subitem atttributes
2685 * RETURN:
2686 * SUCCESS : TRUE
2687 * FAILURE : FALSE
2689 static BOOL LISTVIEW_SetSubItem(HWND hwnd, LPLVITEMA lpLVItem)
2691 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2692 BOOL bResult = FALSE;
2693 HDPA hdpaSubItems;
2694 LISTVIEW_SUBITEM *lpSubItem;
2695 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2696 RECT rcItem;
2698 if (lStyle & LVS_OWNERDATA)
2699 return FALSE;
2701 if (lpLVItem != NULL)
2703 if (lpLVItem->iSubItem > 0)
2705 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
2706 if (hdpaSubItems != NULL)
2708 /* set subitem only if column is present */
2709 if (Header_GetItemCount(infoPtr->hwndHeader) > lpLVItem->iSubItem)
2711 lpSubItem = LISTVIEW_GetSubItem(hdpaSubItems, lpLVItem->iSubItem);
2712 if (lpSubItem != NULL)
2714 bResult = LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem);
2716 else
2718 bResult = LISTVIEW_AddSubItem(hwnd, lpLVItem);
2721 rcItem.left = LVIR_BOUNDS;
2722 LISTVIEW_GetItemRect(hwnd, lpLVItem->iItem, &rcItem);
2723 InvalidateRect(hwnd, &rcItem, FALSE);
2729 return bResult;
2732 /***
2733 * DESCRIPTION:
2734 * Retrieves the index of the item at coordinate (0, 0) of the client area.
2736 * PARAMETER(S):
2737 * [I] HWND : window handle
2739 * RETURN:
2740 * item index
2742 static INT LISTVIEW_GetTopIndex(HWND hwnd)
2744 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2745 UINT uView = lStyle & LVS_TYPEMASK;
2746 INT nItem = 0;
2747 SCROLLINFO scrollInfo;
2749 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2750 scrollInfo.cbSize = sizeof(SCROLLINFO);
2751 scrollInfo.fMask = SIF_POS;
2753 if (uView == LVS_LIST)
2755 if (lStyle & WS_HSCROLL)
2757 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2759 nItem = scrollInfo.nPos * LISTVIEW_GetCountPerColumn(hwnd);
2763 else if (uView == LVS_REPORT)
2765 if (lStyle & WS_VSCROLL)
2767 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
2769 nItem = scrollInfo.nPos;
2774 return nItem;
2777 /***
2778 * DESCRIPTION:
2779 * Draws a subitem.
2781 * PARAMETER(S):
2782 * [I] HWND : window handle
2783 * [I] HDC : device context handle
2784 * [I] INT : item index
2785 * [I] INT : subitem index
2786 * [I] RECT * : clipping rectangle
2788 * RETURN:
2789 * None
2791 static VOID LISTVIEW_DrawSubItem(HWND hwnd, HDC hdc, INT nItem, INT nSubItem,
2792 RECT rcItem, BOOL Selected)
2794 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2795 CHAR szDispText[DISP_TEXT_SIZE];
2796 LVITEMA lvItem;
2797 UINT textoutOptions = ETO_CLIPPED | ETO_OPAQUE;
2798 RECT rcTemp;
2800 TRACE("(hwnd=%x, hdc=%x, nItem=%d, nSubItem=%d)\n", hwnd, hdc,
2801 nItem, nSubItem);
2803 /* get information needed for drawing the item */
2804 ZeroMemory(&lvItem, sizeof(LVITEMA));
2805 lvItem.mask = LVIF_TEXT;
2806 lvItem.iItem = nItem;
2807 lvItem.iSubItem = nSubItem;
2808 lvItem.cchTextMax = DISP_TEXT_SIZE;
2809 lvItem.pszText = szDispText;
2810 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
2812 /* redraw the background of the item */
2813 rcTemp = rcItem;
2814 if(infoPtr->nColumnCount == (nSubItem + 1))
2815 rcTemp.right = infoPtr->rcList.right;
2816 else
2817 rcTemp.right+=WIDTH_PADDING;
2819 LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
2821 /* set item colors */
2822 if (ListView_GetItemState(hwnd,nItem,LVIS_SELECTED) && Selected)
2824 if (infoPtr->bFocus)
2826 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
2827 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2829 else
2831 SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
2832 SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
2835 else
2837 if ( (infoPtr->clrTextBk == CLR_DEFAULT) || (infoPtr->clrTextBk == CLR_NONE) )
2839 SetBkMode(hdc, TRANSPARENT);
2840 textoutOptions &= ~ETO_OPAQUE;
2842 else
2844 SetBkMode(hdc, OPAQUE);
2845 SetBkColor(hdc, infoPtr->clrTextBk);
2848 SetTextColor(hdc, infoPtr->clrText);
2851 ExtTextOutA(hdc, rcItem.left, rcItem.top, textoutOptions,
2852 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
2854 if (Selected)
2856 /* fill in the gap */
2857 RECT rec;
2858 if (nSubItem < Header_GetItemCount(infoPtr->hwndHeader)-1)
2860 CopyRect(&rec,&rcItem);
2861 rec.left = rec.right;
2862 rec.right = rec.left+REPORT_MARGINX;
2863 ExtTextOutA(hdc, rec.left , rec.top, textoutOptions,
2864 &rec, NULL, 0, NULL);
2866 CopyRect(&rec,&rcItem);
2867 rec.right = rec.left;
2868 rec.left = rec.left - REPORT_MARGINX;
2869 ExtTextOutA(hdc, rec.left , rec.top, textoutOptions,
2870 &rec, NULL, 0, NULL);
2875 /***
2876 * DESCRIPTION:
2877 * Draws an item.
2879 * PARAMETER(S):
2880 * [I] HWND : window handle
2881 * [I] HDC : device context handle
2882 * [I] INT : item index
2883 * [I] RECT * : clipping rectangle
2885 * RETURN:
2886 * None
2888 static VOID LISTVIEW_DrawItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem, BOOL FullSelect, RECT* SuggestedFocus)
2890 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2891 CHAR szDispText[DISP_TEXT_SIZE];
2892 INT nLabelWidth;
2893 LVITEMA lvItem;
2894 INT nMixMode;
2895 DWORD dwBkColor;
2896 DWORD dwTextColor,dwTextX;
2897 BOOL bImage = FALSE;
2898 INT iBkMode = -1;
2899 UINT textoutOptions = ETO_OPAQUE | ETO_CLIPPED;
2900 RECT rcTemp;
2902 TRACE("(hwnd=%x, hdc=%x, nItem=%d)\n", hwnd, hdc, nItem);
2905 /* get information needed for drawing the item */
2906 ZeroMemory(&lvItem, sizeof(LVITEMA));
2907 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_INDENT;
2908 lvItem.stateMask = LVIS_SELECTED | LVIS_STATEIMAGEMASK;
2909 lvItem.iItem = nItem;
2910 lvItem.iSubItem = 0;
2911 lvItem.cchTextMax = DISP_TEXT_SIZE;
2912 lvItem.pszText = szDispText;
2913 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
2915 /* redraw the background of the item */
2916 rcTemp = rcItem;
2917 if(infoPtr->nColumnCount == (nItem + 1))
2918 rcTemp.right = infoPtr->rcList.right;
2919 else
2920 rcTemp.right+=WIDTH_PADDING;
2922 LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
2924 /* do indent */
2925 if (lvItem.iIndent>0 && infoPtr->iconSize.cx > 0)
2927 rcItem.left += infoPtr->iconSize.cx * lvItem.iIndent;
2929 if (SuggestedFocus)
2930 SuggestedFocus->left += infoPtr->iconSize.cx * lvItem.iIndent;
2933 /* state icons */
2934 if (infoPtr->himlState != NULL)
2936 UINT uStateImage = (lvItem.state & LVIS_STATEIMAGEMASK) >> 12;
2937 if (uStateImage > 0)
2939 ImageList_Draw(infoPtr->himlState, uStateImage - 1, hdc, rcItem.left,
2940 rcItem.top, ILD_NORMAL);
2943 rcItem.left += infoPtr->iconSize.cx;
2944 if (SuggestedFocus)
2945 SuggestedFocus->left += infoPtr->iconSize.cx;
2946 bImage = TRUE;
2949 /* small icons */
2950 if (infoPtr->himlSmall != NULL)
2952 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE) &&
2953 (lvItem.iImage>=0))
2955 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
2956 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
2957 rcItem.top, ILD_SELECTED);
2959 else if (lvItem.iImage>=0)
2961 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
2962 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
2963 rcItem.top, ILD_NORMAL);
2966 rcItem.left += infoPtr->iconSize.cx;
2968 if (SuggestedFocus)
2969 SuggestedFocus->left += infoPtr->iconSize.cx;
2970 bImage = TRUE;
2973 /* Don't bother painting item being edited */
2974 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED && !FullSelect)
2975 return;
2977 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
2979 /* set item colors */
2980 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
2981 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2982 /* set raster mode */
2983 nMixMode = SetROP2(hdc, R2_XORPEN);
2985 else if ((GetWindowLongA(hwnd, GWL_STYLE) & LVS_SHOWSELALWAYS) &&
2986 (lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus == FALSE))
2988 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
2989 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
2990 /* set raster mode */
2991 nMixMode = SetROP2(hdc, R2_COPYPEN);
2993 else
2995 /* set item colors */
2996 if ( (infoPtr->clrTextBk == CLR_DEFAULT) || (infoPtr->clrTextBk == CLR_NONE) )
2998 dwBkColor = GetBkColor(hdc);
2999 iBkMode = SetBkMode(hdc, TRANSPARENT);
3000 textoutOptions &= ~ETO_OPAQUE;
3002 else
3004 dwBkColor = SetBkColor(hdc, infoPtr->clrTextBk);
3005 iBkMode = SetBkMode(hdc, OPAQUE);
3008 dwTextColor = SetTextColor(hdc, infoPtr->clrText);
3009 /* set raster mode */
3010 nMixMode = SetROP2(hdc, R2_COPYPEN);
3013 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
3014 if (rcItem.left + nLabelWidth < rcItem.right)
3016 if (!FullSelect)
3017 rcItem.right = rcItem.left + nLabelWidth + TRAILING_PADDING;
3018 if (bImage)
3019 rcItem.right += IMAGE_PADDING;
3022 /* draw label */
3023 dwTextX = rcItem.left + 1;
3024 if (bImage)
3025 dwTextX += IMAGE_PADDING;
3027 if (lvItem.pszText)
3028 ExtTextOutA(hdc, dwTextX, rcItem.top, textoutOptions,
3029 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
3031 if ((FullSelect)&&(Header_GetItemCount(infoPtr->hwndHeader) > 1))
3033 /* fill in the gap */
3034 RECT rec;
3035 CopyRect(&rec,&rcItem);
3036 rec.left = rec.right;
3037 rec.right = rec.left+REPORT_MARGINX;
3038 ExtTextOutA(hdc, rec.left , rec.top, textoutOptions,
3039 &rec, NULL, 0, NULL);
3042 if (!FullSelect)
3043 CopyRect(SuggestedFocus,&rcItem);
3045 if (nMixMode != 0)
3047 SetROP2(hdc, R2_COPYPEN);
3048 SetBkColor(hdc, dwBkColor);
3049 SetTextColor(hdc, dwTextColor);
3050 if (iBkMode != -1)
3051 SetBkMode(hdc, iBkMode);
3055 /***
3056 * DESCRIPTION:
3057 * Draws an item when in large icon display mode.
3059 * PARAMETER(S):
3060 * [I] HWND : window handle
3061 * [I] HDC : device context handle
3062 * [I] LISTVIEW_ITEM * : item
3063 * [I] INT : item index
3064 * [I] RECT * : clipping rectangle
3066 * RETURN:
3067 * None
3069 static VOID LISTVIEW_DrawLargeItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem,
3070 RECT *SuggestedFocus)
3072 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3073 CHAR szDispText[DISP_TEXT_SIZE];
3074 INT nDrawPosX = rcItem.left;
3075 INT nLabelWidth, rcWidth;
3076 TEXTMETRICA tm;
3077 LVITEMA lvItem;
3078 UINT textoutOptions = ETO_CLIPPED | ETO_OPAQUE;
3079 RECT rcTemp;
3081 TRACE("(hwnd=%x, hdc=%x, nItem=%d, left=%d, top=%d, right=%d, \
3082 bottom=%d)\n", hwnd, hdc, nItem, rcItem.left, rcItem.top, rcItem.right,
3083 rcItem.bottom);
3085 /* get information needed for drawing the item */
3086 ZeroMemory(&lvItem, sizeof(LVITEMA));
3087 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
3088 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
3089 lvItem.iItem = nItem;
3090 lvItem.iSubItem = 0;
3091 lvItem.cchTextMax = DISP_TEXT_SIZE;
3092 lvItem.pszText = szDispText;
3093 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
3095 /* redraw the background of the item */
3096 rcTemp = rcItem;
3097 if(infoPtr->nColumnCount == (nItem + 1))
3098 rcTemp.right = infoPtr->rcList.right;
3099 else
3100 rcTemp.right+=WIDTH_PADDING;
3102 LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
3104 if (lvItem.state & LVIS_SELECTED)
3106 /* set item colors */
3107 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
3108 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
3109 /* set raster mode */
3110 SetROP2(hdc, R2_XORPEN);
3112 else
3114 /* set item colors */
3115 if ( (infoPtr->clrTextBk == CLR_DEFAULT) || (infoPtr->clrTextBk == CLR_NONE) )
3117 SetBkMode(hdc, TRANSPARENT);
3118 textoutOptions &= ~ETO_OPAQUE;
3120 else
3122 SetBkMode(hdc, OPAQUE);
3123 SetBkColor(hdc, infoPtr->clrTextBk);
3126 SetTextColor(hdc, infoPtr->clrText);
3127 /* set raster mode */
3128 SetROP2(hdc, R2_COPYPEN);
3131 if (infoPtr->himlNormal != NULL)
3133 rcItem.top += ICON_TOP_PADDING;
3134 nDrawPosX += (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
3135 if ((lvItem.state & LVIS_SELECTED) && (lvItem.iImage>=0))
3137 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
3138 rcItem.top, ILD_SELECTED);
3140 else if (lvItem.iImage>=0)
3142 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
3143 rcItem.top, ILD_NORMAL);
3147 /* Don't bother painting item being edited */
3148 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED)
3149 return;
3151 InflateRect(&rcItem, -(2*CAPTION_BORDER), 0);
3152 rcItem.top += infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
3153 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
3154 GetTextMetricsA(hdc, &tm);
3156 /* append an ellipse ('...') if the caption won't fit in the rect */
3157 rcWidth = max(0, rcItem.right - rcItem.left);
3158 if (nLabelWidth > rcWidth)
3160 INT i, len, eos, nCharsFit;
3161 /* give or take a couple, how many average sized chars would fit? */
3162 nCharsFit = tm.tmAveCharWidth > 0 ? (rcWidth/tm.tmAveCharWidth)+2 : 0;
3163 /* place the ellipse accordingly, without overrunning the buffer */
3164 len = strlen(szDispText);
3165 eos = min((nCharsFit > 1 && nCharsFit < len) ? nCharsFit+3 : len+2,
3166 sizeof(szDispText)-1);
3168 nLabelWidth = ListView_GetStringWidthA(hwnd, szDispText);
3169 while ((nLabelWidth > rcWidth) && (eos > 3))
3171 for (i = 1; i < 4; i++)
3172 szDispText[eos-i] = '.';
3173 /* shift the ellipse one char to the left for each iteration */
3174 szDispText[eos--] = '\0';
3175 nLabelWidth = ListView_GetStringWidthA(hwnd, szDispText);
3179 InflateRect(&rcItem, 2*CAPTION_BORDER, 0);
3180 nDrawPosX = infoPtr->iconSpacing.cx - 2*CAPTION_BORDER - nLabelWidth;
3181 if (nDrawPosX > 1)
3183 rcItem.left += nDrawPosX / 2;
3184 rcItem.right = rcItem.left + nLabelWidth + 2*CAPTION_BORDER;
3186 else
3188 rcItem.left += 1;
3189 rcItem.right = rcItem.left + infoPtr->iconSpacing.cx - 1;
3192 /* draw label */
3193 rcItem.bottom = rcItem.top + tm.tmHeight + HEIGHT_PADDING;
3195 ExtTextOutA(hdc, rcItem.left + CAPTION_BORDER, rcItem.top, textoutOptions,
3196 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
3199 CopyRect(SuggestedFocus,&rcItem);
3202 /***
3203 * DESCRIPTION:
3204 * Draws listview items when in report display mode.
3206 * PARAMETER(S):
3207 * [I] HWND : window handle
3208 * [I] HDC : device context handle
3210 * RETURN:
3211 * None
3213 static VOID LISTVIEW_RefreshReport(HWND hwnd, HDC hdc, DWORD cdmode)
3215 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
3216 SCROLLINFO scrollInfo;
3217 INT nDrawPosY = infoPtr->rcList.top;
3218 INT nColumnCount;
3219 RECT rcItem, rcTemp;
3220 INT j;
3221 INT nItem;
3222 INT nLast;
3223 BOOL FullSelected;
3224 DWORD cditemmode = CDRF_DODEFAULT;
3225 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3226 INT scrollOffset;
3228 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
3229 scrollInfo.cbSize = sizeof(SCROLLINFO);
3230 scrollInfo.fMask = SIF_POS;
3232 nItem = ListView_GetTopIndex(hwnd);
3234 /* add 1 for displaying a partial item at the bottom */
3235 nLast = nItem + LISTVIEW_GetCountPerColumn(hwnd) + 1;
3236 nLast = min(nLast, GETITEMCOUNT(infoPtr));
3238 /* send cache hint notification */
3239 if (GetWindowLongA(hwnd,GWL_STYLE) & LVS_OWNERDATA)
3241 NMLVCACHEHINT nmlv;
3243 nmlv.hdr.hwndFrom = hwnd;
3244 nmlv.hdr.idFrom = GetWindowLongA(hwnd,GWL_ID);
3245 nmlv.hdr.code = LVN_ODCACHEHINT;
3246 nmlv.iFrom = nItem;
3247 nmlv.iTo = nLast;
3249 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)nmlv.hdr.idFrom,
3250 (LPARAM)&nmlv);
3253 nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
3254 infoPtr->nColumnCount = nColumnCount; /* update nColumnCount */
3255 FullSelected = infoPtr->dwExStyle & LVS_EX_FULLROWSELECT;
3257 /* clear the background of any part of the control that doesn't contain items */
3258 SubtractRect(&rcTemp, &infoPtr->rcList, &infoPtr->rcView);
3259 LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
3261 /* nothing to draw */
3262 if(GETITEMCOUNT(infoPtr) == 0)
3263 return;
3265 /* Get scroll bar info once before loop */
3266 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
3267 scrollOffset = scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
3269 for (; nItem < nLast; nItem++)
3271 RECT SuggestedFocusRect;
3273 /* Do Owner Draw */
3274 if (lStyle & LVS_OWNERDRAWFIXED)
3276 UINT uID = GetWindowLongA( hwnd, GWL_ID);
3277 DRAWITEMSTRUCT dis;
3278 LVITEMA item;
3279 RECT br;
3281 TRACE("Owner Drawn\n");
3282 dis.CtlType = ODT_LISTVIEW;
3283 dis.CtlID = uID;
3284 dis.itemID = nItem;
3285 dis.itemAction = ODA_DRAWENTIRE;
3286 dis.itemState = 0;
3288 if (LISTVIEW_IsSelected(hwnd,nItem)) dis.itemState|=ODS_SELECTED;
3289 if (nItem==infoPtr->nFocusedItem) dis.itemState|=ODS_FOCUS;
3291 dis.hwndItem = hwnd;
3292 dis.hDC = hdc;
3294 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
3296 dis.rcItem.left = -scrollOffset;
3297 dis.rcItem.right = max(dis.rcItem.left, br.right - scrollOffset);
3298 dis.rcItem.top = nDrawPosY;
3299 dis.rcItem.bottom = dis.rcItem.top + infoPtr->nItemHeight;
3301 ZeroMemory(&item,sizeof(LVITEMA));
3302 item.iItem = nItem;
3303 item.mask = LVIF_PARAM;
3304 ListView_GetItemA(hwnd,&item);
3306 dis.itemData = item.lParam;
3308 if (SendMessageA(GetParent(hwnd),WM_DRAWITEM,(WPARAM)uID,(LPARAM)&dis))
3310 nDrawPosY += infoPtr->nItemHeight;
3311 continue;
3315 if (FullSelected)
3317 RECT ir,br;
3319 Header_GetItemRect(infoPtr->hwndHeader, 0, &ir);
3320 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
3322 ir.left += REPORT_MARGINX;
3323 ir.right = max(ir.left, br.right - REPORT_MARGINX);
3324 ir.top = nDrawPosY;
3325 ir.bottom = ir.top + infoPtr->nItemHeight;
3327 CopyRect(&SuggestedFocusRect,&ir);
3330 for (j = 0; j < nColumnCount; j++)
3332 if (cdmode & CDRF_NOTIFYITEMDRAW)
3333 cditemmode = LISTVIEW_SendCustomDrawItemNotify (hwnd, hdc, nItem, j,
3334 CDDS_ITEMPREPAINT);
3335 if (cditemmode & CDRF_SKIPDEFAULT)
3336 continue;
3338 Header_GetItemRect(infoPtr->hwndHeader, j, &rcItem);
3340 rcItem.left += REPORT_MARGINX;
3341 rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX);
3342 rcItem.top = nDrawPosY;
3343 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
3345 /* Offset the Scroll Bar Pos */
3346 rcItem.left -= scrollOffset;
3347 rcItem.right -= scrollOffset;
3349 if (j == 0)
3351 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem, FullSelected,
3352 &SuggestedFocusRect);
3354 else
3356 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, j, rcItem,
3357 FullSelected);
3360 if (cditemmode & CDRF_NOTIFYPOSTPAINT)
3361 LISTVIEW_SendCustomDrawItemNotify(hwnd, hdc, nItem, 0,
3362 CDDS_ITEMPOSTPAINT);
3365 * Draw Focus Rect
3367 if (LISTVIEW_GetItemState(hwnd,nItem,LVIS_FOCUSED) && infoPtr->bFocus)
3369 BOOL rop=FALSE;
3370 if (FullSelected && LISTVIEW_GetItemState(hwnd,nItem,LVIS_SELECTED))
3371 rop = SetROP2(hdc, R2_XORPEN);
3373 Rectangle(hdc, SuggestedFocusRect.left, SuggestedFocusRect.top,
3374 SuggestedFocusRect.right,SuggestedFocusRect.bottom);
3376 if (rop)
3377 SetROP2(hdc, R2_COPYPEN);
3379 nDrawPosY += infoPtr->nItemHeight;
3383 /***
3384 * DESCRIPTION:
3385 * Retrieves the number of items that can fit vertically in the client area.
3387 * PARAMETER(S):
3388 * [I] HWND : window handle
3390 * RETURN:
3391 * Number of items per row.
3393 static INT LISTVIEW_GetCountPerRow(HWND hwnd)
3395 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
3396 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3397 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
3398 INT nCountPerRow = 1;
3400 if (nListWidth > 0)
3402 if (uView == LVS_REPORT)
3404 nCountPerRow = 1;
3406 else
3408 nCountPerRow = nListWidth / infoPtr->nItemWidth;
3409 if (nCountPerRow == 0)
3411 nCountPerRow = 1;
3416 return nCountPerRow;
3419 /***
3420 * DESCRIPTION:
3421 * Retrieves the number of items that can fit horizontally in the client
3422 * area.
3424 * PARAMETER(S):
3425 * [I] HWND : window handle
3427 * RETURN:
3428 * Number of items per column.
3430 static INT LISTVIEW_GetCountPerColumn(HWND hwnd)
3432 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
3433 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
3434 INT nCountPerColumn = 1;
3436 if (nListHeight > 0)
3438 nCountPerColumn = nListHeight / infoPtr->nItemHeight;
3439 if (nCountPerColumn == 0)
3441 nCountPerColumn = 1;
3445 return nCountPerColumn;
3448 /***
3449 * DESCRIPTION:
3450 * Retrieves the number of columns needed to display all the items when in
3451 * list display mode.
3453 * PARAMETER(S):
3454 * [I] HWND : window handle
3456 * RETURN:
3457 * Number of columns.
3459 static INT LISTVIEW_GetColumnCount(HWND hwnd)
3461 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3462 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3463 INT nColumnCount = 0;
3465 if ((lStyle & LVS_TYPEMASK) == LVS_LIST)
3467 if (infoPtr->rcList.right % infoPtr->nItemWidth == 0)
3469 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth;
3471 else
3473 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth + 1;
3477 return nColumnCount;
3481 /***
3482 * DESCRIPTION:
3483 * Draws listview items when in list display mode.
3485 * PARAMETER(S):
3486 * [I] HWND : window handle
3487 * [I] HDC : device context handle
3489 * RETURN:
3490 * None
3492 static VOID LISTVIEW_RefreshList(HWND hwnd, HDC hdc, DWORD cdmode)
3494 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3495 RECT rcItem, FocusRect, rcTemp;
3496 INT i, j;
3497 INT nItem;
3498 INT nColumnCount;
3499 INT nCountPerColumn;
3500 INT nItemWidth = infoPtr->nItemWidth;
3501 INT nItemHeight = infoPtr->nItemHeight;
3502 DWORD cditemmode = CDRF_DODEFAULT;
3504 /* get number of fully visible columns */
3505 nColumnCount = LISTVIEW_GetColumnCount(hwnd);
3506 infoPtr->nColumnCount = nColumnCount;
3507 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
3508 nItem = ListView_GetTopIndex(hwnd);
3510 /* paint the background of the control that doesn't contain any items */
3511 SubtractRect(&rcTemp, &infoPtr->rcList, &infoPtr->rcView);
3512 LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
3514 /* nothing to draw, return here */
3515 if(GETITEMCOUNT(infoPtr) == 0)
3516 return;
3518 for (i = 0; i < nColumnCount; i++)
3520 for (j = 0; j < nCountPerColumn; j++, nItem++)
3522 if (nItem >= GETITEMCOUNT(infoPtr))
3523 return;
3525 if (cdmode & CDRF_NOTIFYITEMDRAW)
3526 cditemmode = LISTVIEW_SendCustomDrawItemNotify (hwnd, hdc, nItem, 0,
3527 CDDS_ITEMPREPAINT);
3528 if (cditemmode & CDRF_SKIPDEFAULT)
3529 continue;
3531 rcItem.top = j * nItemHeight;
3532 rcItem.left = i * nItemWidth;
3533 rcItem.bottom = rcItem.top + nItemHeight;
3534 rcItem.right = rcItem.left + nItemWidth;
3535 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem, FALSE, &FocusRect);
3537 * Draw Focus Rect
3539 if (LISTVIEW_GetItemState(hwnd,nItem,LVIS_FOCUSED) && infoPtr->bFocus)
3540 Rectangle(hdc, FocusRect.left, FocusRect.top,
3541 FocusRect.right,FocusRect.bottom);
3543 if (cditemmode & CDRF_NOTIFYPOSTPAINT)
3544 LISTVIEW_SendCustomDrawItemNotify(hwnd, hdc, nItem, 0,
3545 CDDS_ITEMPOSTPAINT);
3551 /***
3552 * DESCRIPTION:
3553 * Draws listview items when in icon or small icon display mode.
3555 * PARAMETER(S):
3556 * [I] HWND : window handle
3557 * [I] HDC : device context handle
3559 * RETURN:
3560 * None
3562 static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc, BOOL bSmall, DWORD cdmode)
3564 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3565 POINT ptPosition;
3566 POINT ptOrigin;
3567 RECT rcItem, SuggestedFocus, rcTemp;
3568 INT i;
3569 DWORD cditemmode = CDRF_DODEFAULT;
3571 infoPtr->nColumnCount = 1; /* set this to an arbitrary value to prevent */
3572 /* DrawItem from erasing the incorrect background area */
3574 /* paint the background of the control that doesn't contain any items */
3575 SubtractRect(&rcTemp, &infoPtr->rcList, &infoPtr->rcView);
3576 LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
3578 /* nothing to draw, return here */
3579 if(GETITEMCOUNT(infoPtr) == 0)
3580 return;
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,
3587 CDDS_ITEMPREPAINT);
3588 if (cditemmode & CDRF_SKIPDEFAULT)
3589 continue;
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);
3611 else
3613 LISTVIEW_DrawItem(hwnd, hdc, i, rcItem, FALSE, &SuggestedFocus);
3616 * Draw Focus Rect
3618 if (LISTVIEW_GetItemState(hwnd,i,LVIS_FOCUSED) &&
3619 infoPtr->bFocus)
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);
3632 /***
3633 * DESCRIPTION:
3634 * Draws listview items.
3636 * PARAMETER(S):
3637 * [I] HWND : window handle
3638 * [I] HDC : device context handle
3640 * RETURN:
3641 * NoneX
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;
3647 HFONT hOldFont;
3648 HPEN hPen, hOldPen;
3649 DWORD cdmode;
3650 RECT rect;
3652 GetClientRect(hwnd, &rect);
3653 cdmode = LISTVIEW_SendCustomDrawNotify(hwnd,CDDS_PREPAINT,hdc,rect);
3655 if (cdmode == CDRF_SKIPDEFAULT) return;
3657 /* select font */
3658 hOldFont = SelectObject(hdc, infoPtr->hFont);
3660 /* select the dotted pen (for drawing the focus box) */
3661 hPen = CreatePen(PS_ALTERNATE, 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);
3688 /* delete pen */
3689 DeleteObject(hPen);
3691 if (cdmode & CDRF_NOTIFYPOSTPAINT)
3692 LISTVIEW_SendCustomDrawNotify(hwnd, CDDS_POSTPAINT, hdc, rect);
3696 /***
3697 * DESCRIPTION:
3698 * Calculates the approximate width and height of a given number of items.
3700 * PARAMETER(S):
3701 * [I] HWND : window handle
3702 * [I] INT : number of items
3703 * [I] INT : width
3704 * [I] INT : height
3706 * RETURN:
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;
3736 if (nItemCount > 0)
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;
3750 else
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)
3765 /* TO DO */
3767 else if (uView == LVS_SMALLICON)
3769 /* TO DO */
3771 else if (uView == LVS_ICON)
3773 /* TO DO */
3776 return dwViewRect;
3779 /***
3780 * DESCRIPTION:
3781 * Arranges listview items in icon display mode.
3783 * PARAMETER(S):
3784 * [I] HWND : window handle
3785 * [I] INT : alignment code
3787 * RETURN:
3788 * SUCCESS : TRUE
3789 * FAILURE : FALSE
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))
3798 switch (nAlignCode)
3800 case LVA_ALIGNLEFT:
3801 /* TO DO */
3802 break;
3803 case LVA_ALIGNTOP:
3804 /* TO DO */
3805 break;
3806 case LVA_DEFAULT:
3807 /* TO DO */
3808 break;
3809 case LVA_SNAPTOGRID:
3810 /* TO DO */
3811 break;
3815 return bResult;
3818 /* << LISTVIEW_CreateDragImage >> */
3821 /***
3822 * DESCRIPTION:
3823 * Removes all listview items and subitems.
3825 * PARAMETER(S):
3826 * [I] HWND : window handle
3828 * RETURN:
3829 * SUCCESS : TRUE
3830 * FAILURE : FALSE
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;
3840 NMLISTVIEW nmlv;
3841 BOOL bSuppress;
3842 BOOL bResult = FALSE;
3843 INT i;
3844 INT j;
3845 HDPA hdpaSubItems;
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);
3854 return 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;
3866 nmlv.iItem = -1;
3868 /* verify if subsequent LVN_DELETEITEM notifications should be
3869 suppressed */
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);
3889 /* free subitem */
3890 COMCTL32_Free(lpSubItem);
3894 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3895 if (lpItem != NULL)
3897 if (bSuppress == FALSE)
3899 /* send LVN_DELETEITEM notification */
3900 nmlv.hdr.code = LVN_DELETEITEM;
3901 nmlv.iItem = i;
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);
3913 /* free item */
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);
3931 else
3933 LISTVIEW_AlignTop(hwnd);
3937 LISTVIEW_UpdateScroll(hwnd);
3939 /* invalidate client area (optimization needed) */
3940 InvalidateRect(hwnd, NULL, TRUE);
3943 return bResult;
3946 /***
3947 * DESCRIPTION:
3948 * Removes a column from the listview control.
3950 * PARAMETER(S):
3951 * [I] HWND : window handle
3952 * [I] INT : column index
3954 * RETURN:
3955 * SUCCESS : TRUE
3956 * FAILURE : FALSE
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 UINT uOwnerData = GetWindowLongA(hwnd, GWL_STYLE) & LVS_OWNERDATA;
3963 BOOL bResult = FALSE;
3965 if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) != FALSE)
3967 if (!uOwnerData)
3968 bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
3970 /* Need to reset the item width when deleting a column */
3971 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
3973 /* reset scroll parameters */
3974 if (uView == LVS_REPORT)
3976 /* update scrollbar(s) */
3977 LISTVIEW_UpdateScroll(hwnd);
3979 /* refresh client area */
3980 InvalidateRect(hwnd, NULL, FALSE);
3984 return bResult;
3987 /***
3988 * DESCRIPTION:
3989 * Removes an item from the listview control.
3991 * PARAMETER(S):
3992 * [I] HWND : window handle
3993 * [I] INT : item index
3995 * RETURN:
3996 * SUCCESS : TRUE
3997 * FAILURE : FALSE
3999 static LRESULT LISTVIEW_DeleteItem(HWND hwnd, INT nItem)
4001 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4002 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4003 UINT uView = lStyle & LVS_TYPEMASK;
4004 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
4005 NMLISTVIEW nmlv;
4006 BOOL bResult = FALSE;
4007 HDPA hdpaSubItems;
4008 LISTVIEW_ITEM *lpItem;
4009 LISTVIEW_SUBITEM *lpSubItem;
4010 INT i;
4011 LVITEMA item;
4013 TRACE("(hwnd=%x,nItem=%d)\n", hwnd, nItem);
4015 /* remove it from the selection range */
4016 ZeroMemory(&item,sizeof(LVITEMA));
4017 item.stateMask = LVIS_SELECTED;
4018 LISTVIEW_SetItemState(hwnd,nItem,&item);
4020 LISTVIEW_ShiftSelections(hwnd,nItem,-1);
4022 if (lStyle & LVS_OWNERDATA)
4024 infoPtr->hdpaItems->nItemCount --;
4025 InvalidateRect(hwnd, NULL, TRUE);
4026 return TRUE;
4029 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4031 /* initialize memory */
4032 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
4034 hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem);
4035 if (hdpaSubItems != NULL)
4037 for (i = 1; i < hdpaSubItems->nItemCount; i++)
4039 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
4040 if (lpSubItem != NULL)
4042 /* free item string */
4043 if ((lpSubItem->pszText != NULL) &&
4044 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
4046 COMCTL32_Free(lpSubItem->pszText);
4049 /* free item */
4050 COMCTL32_Free(lpSubItem);
4054 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
4055 if (lpItem != NULL)
4057 /* send LVN_DELETEITEM notification */
4058 nmlv.hdr.hwndFrom = hwnd;
4059 nmlv.hdr.idFrom = lCtrlId;
4060 nmlv.hdr.code = LVN_DELETEITEM;
4061 nmlv.iItem = nItem;
4062 nmlv.lParam = lpItem->lParam;
4063 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId,
4064 (LPARAM)&nmlv);
4066 /* free item string */
4067 if ((lpItem->pszText != NULL) &&
4068 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
4070 COMCTL32_Free(lpItem->pszText);
4073 /* free item */
4074 COMCTL32_Free(lpItem);
4077 bResult = DPA_Destroy(hdpaSubItems);
4080 /* align items (set position of each item) */
4081 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4083 if (lStyle & LVS_ALIGNLEFT)
4085 LISTVIEW_AlignLeft(hwnd);
4087 else
4089 LISTVIEW_AlignTop(hwnd);
4093 /* If this item had focus change focus to next or previous item */
4094 if (GETITEMCOUNT(infoPtr) > 0)
4096 int sItem = nItem < GETITEMCOUNT(infoPtr) ? nItem : nItem - 1;
4097 if (infoPtr->nFocusedItem == nItem)
4098 LISTVIEW_SetItemFocus(hwnd, sItem);
4100 else
4101 infoPtr->nFocusedItem = -1;
4103 LISTVIEW_UpdateScroll(hwnd);
4105 /* refresh client area */
4106 InvalidateRect(hwnd, NULL, TRUE);
4109 return bResult;
4113 /***
4114 * DESCRIPTION:
4115 * Return edit control handle of current edit label
4117 * PARAMETER(S):
4118 * [I] HWND : window handle
4120 * RETURN:
4121 * SUCCESS : HWND
4122 * FAILURE : 0
4124 static LRESULT LISTVIEW_GetEditControl(HWND hwnd)
4126 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4127 return infoPtr->hwndEdit;
4131 /***
4132 * DESCRIPTION:
4133 * Callback implementation for editlabel control
4135 * PARAMETER(S):
4136 * [I] HWND : window handle
4137 * [I] LPSTR : modified text
4138 * [I] DWORD : item index
4140 * RETURN:
4141 * SUCCESS : TRUE
4142 * FAILURE : FALSE
4145 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem)
4147 NMLVDISPINFOA dispInfo;
4148 LISTVIEW_ITEM *lpItem;
4149 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
4150 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4151 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4152 HDPA hdpaSubItems;
4153 BOOL bUpdateItemText;
4154 LISTVIEW_ITEM lvItemRef;
4155 LVITEMA item;
4157 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
4159 if (!(lStyle & LVS_OWNERDATA))
4161 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
4162 return FALSE;
4164 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
4165 return FALSE;
4167 else
4169 ZeroMemory(&lvItemRef,sizeof(LISTVIEW_ITEM));
4170 ZeroMemory(&item,sizeof(LVITEMA));
4171 item.iItem = nItem;
4172 item.iSubItem = 0;
4173 item.mask = LVIF_PARAM | LVIF_STATE;
4174 ListView_GetItemA(hwnd,&item);
4175 lvItemRef.state = item.state;
4176 lvItemRef.iImage = item.iImage;
4177 lvItemRef.lParam = item.lParam;
4178 lpItem = &lvItemRef;
4181 dispInfo.hdr.hwndFrom = hwnd;
4182 dispInfo.hdr.idFrom = nCtrlId;
4183 dispInfo.hdr.code = LVN_ENDLABELEDITA;
4184 dispInfo.item.mask = 0;
4185 dispInfo.item.iItem = nItem;
4186 dispInfo.item.state = lpItem->state;
4187 dispInfo.item.stateMask = 0;
4188 dispInfo.item.pszText = pszText;
4189 dispInfo.item.cchTextMax = pszText ? strlen(pszText) : 0;
4190 dispInfo.item.iImage = lpItem->iImage;
4191 dispInfo.item.lParam = lpItem->lParam;
4192 infoPtr->hwndEdit = 0;
4194 bUpdateItemText = ListView_Notify(GetParent(hwnd), nCtrlId, &dispInfo);
4196 /* Do we need to update the Item Text */
4197 if(bUpdateItemText)
4199 if ((lpItem->pszText != LPSTR_TEXTCALLBACKA)&&(!(lStyle & LVS_OWNERDATA)))
4201 Str_SetPtrA(&lpItem->pszText, pszText);
4205 return TRUE;
4208 /***
4209 * DESCRIPTION:
4210 * Begin in place editing of specified list view item
4212 * PARAMETER(S):
4213 * [I] HWND : window handle
4214 * [I] INT : item index
4216 * RETURN:
4217 * SUCCESS : TRUE
4218 * FAILURE : FALSE
4221 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem)
4223 NMLVDISPINFOA dispInfo;
4224 RECT rect;
4225 LISTVIEW_ITEM *lpItem;
4226 HWND hedit;
4227 HINSTANCE hinst = GetWindowLongA(hwnd, GWL_HINSTANCE);
4228 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
4229 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4230 HDPA hdpaSubItems;
4231 CHAR szDispText[DISP_TEXT_SIZE];
4232 LVITEMA lvItem,item;
4233 LISTVIEW_ITEM lvItemRef;
4234 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4236 if (~GetWindowLongA(hwnd, GWL_STYLE) & LVS_EDITLABELS)
4237 return FALSE;
4239 /* Is the EditBox still there, if so remove it */
4240 if(infoPtr->hwndEdit != 0)
4242 SetFocus(hwnd);
4245 LISTVIEW_SetSelection(hwnd, nItem);
4246 LISTVIEW_SetItemFocus(hwnd, nItem);
4248 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
4249 if (!(lStyle & LVS_OWNERDATA))
4251 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
4252 return 0;
4254 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
4255 return 0;
4257 else
4259 ZeroMemory(&lvItemRef,sizeof(LISTVIEW_ITEM));
4260 ZeroMemory(&item,sizeof(LVITEMA));
4261 item.iItem = nItem;
4262 item.iSubItem = 0;
4263 item.mask = LVIF_PARAM | LVIF_STATE;
4264 ListView_GetItemA(hwnd,&item);
4265 lvItemRef.iImage = item.iImage;
4266 lvItemRef.state = item.state;
4267 lvItemRef.lParam = item.lParam;
4268 lpItem = &lvItemRef;
4271 /* get information needed for drawing the item */
4272 ZeroMemory(&lvItem, sizeof(LVITEMA));
4273 lvItem.mask = LVIF_TEXT;
4274 lvItem.iItem = nItem;
4275 lvItem.iSubItem = 0;
4276 lvItem.cchTextMax = DISP_TEXT_SIZE;
4277 lvItem.pszText = szDispText;
4278 ListView_GetItemA(hwnd, &lvItem);
4280 dispInfo.hdr.hwndFrom = hwnd;
4281 dispInfo.hdr.idFrom = nCtrlId;
4282 dispInfo.hdr.code = LVN_BEGINLABELEDITA;
4283 dispInfo.item.mask = 0;
4284 dispInfo.item.iItem = nItem;
4285 dispInfo.item.state = lpItem->state;
4286 dispInfo.item.stateMask = 0;
4287 dispInfo.item.pszText = lvItem.pszText;
4288 dispInfo.item.cchTextMax = strlen(lvItem.pszText);
4289 dispInfo.item.iImage = lpItem->iImage;
4290 dispInfo.item.lParam = lpItem->lParam;
4292 if (ListView_LVNotify(GetParent(hwnd), nCtrlId, &dispInfo))
4293 return 0;
4295 rect.left = LVIR_LABEL;
4296 if (!LISTVIEW_GetItemRect(hwnd, nItem, &rect))
4297 return 0;
4299 if (!(hedit = CreateEditLabel(szDispText , WS_VISIBLE,
4300 rect.left-2, rect.top-1, 0,
4301 rect.bottom - rect.top+2,
4302 hwnd, hinst, LISTVIEW_EndEditLabel, nItem)))
4303 return 0;
4305 infoPtr->hwndEdit = hedit;
4306 SetFocus(hedit);
4307 SendMessageA(hedit, EM_SETSEL, 0, -1);
4309 return hedit;
4313 /***
4314 * DESCRIPTION:
4315 * Ensures the specified item is visible, scrolling into view if necessary.
4317 * PARAMETER(S):
4318 * [I] HWND : window handle
4319 * [I] INT : item index
4320 * [I] BOOL : partially or entirely visible
4322 * RETURN:
4323 * SUCCESS : TRUE
4324 * FAILURE : FALSE
4326 static BOOL LISTVIEW_EnsureVisible(HWND hwnd, INT nItem, BOOL bPartial)
4328 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4329 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4330 INT nScrollPosHeight = 0;
4331 INT nScrollPosWidth = 0;
4332 SCROLLINFO scrollInfo;
4333 RECT rcItem;
4334 BOOL bRedraw = FALSE;
4336 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
4337 scrollInfo.cbSize = sizeof(SCROLLINFO);
4338 scrollInfo.fMask = SIF_POS;
4340 /* ALWAYS bPartial == FALSE, FOR NOW! */
4342 rcItem.left = LVIR_BOUNDS;
4343 if (LISTVIEW_GetItemRect(hwnd, nItem, &rcItem) != FALSE)
4345 if (rcItem.left < infoPtr->rcList.left)
4347 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4349 /* scroll left */
4350 bRedraw = TRUE;
4351 if (uView == LVS_LIST)
4353 nScrollPosWidth = infoPtr->nItemWidth;
4354 rcItem.left += infoPtr->rcList.left;
4356 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4358 nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
4359 rcItem.left += infoPtr->rcList.left;
4362 /* When in LVS_REPORT view, the scroll position should
4363 not be updated. */
4364 if (nScrollPosWidth != 0)
4366 if (rcItem.left % nScrollPosWidth == 0)
4368 scrollInfo.nPos += rcItem.left / nScrollPosWidth;
4370 else
4372 scrollInfo.nPos += rcItem.left / nScrollPosWidth - 1;
4375 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
4379 else if (rcItem.right > infoPtr->rcList.right)
4381 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4383 /* scroll right */
4384 bRedraw = TRUE;
4385 if (uView == LVS_LIST)
4387 rcItem.right -= infoPtr->rcList.right;
4388 nScrollPosWidth = infoPtr->nItemWidth;
4390 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4392 rcItem.right -= infoPtr->rcList.right;
4393 nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
4396 /* When in LVS_REPORT view, the scroll position should
4397 not be updated. */
4398 if (nScrollPosWidth != 0)
4400 if (rcItem.right % nScrollPosWidth == 0)
4402 scrollInfo.nPos += rcItem.right / nScrollPosWidth;
4404 else
4406 scrollInfo.nPos += rcItem.right / nScrollPosWidth + 1;
4409 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
4414 if (rcItem.top < infoPtr->rcList.top)
4416 /* scroll up */
4417 bRedraw = TRUE;
4418 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4420 if (uView == LVS_REPORT)
4422 rcItem.top -= infoPtr->rcList.top;
4423 nScrollPosHeight = infoPtr->nItemHeight;
4425 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
4427 nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
4428 rcItem.top += infoPtr->rcList.top;
4431 if (rcItem.top % nScrollPosHeight == 0)
4433 scrollInfo.nPos += rcItem.top / nScrollPosHeight;
4435 else
4437 scrollInfo.nPos += rcItem.top / nScrollPosHeight - 1;
4440 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
4443 else if (rcItem.bottom > infoPtr->rcList.bottom)
4445 /* scroll down */
4446 bRedraw = TRUE;
4447 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4449 if (uView == LVS_REPORT)
4451 rcItem.bottom -= infoPtr->rcList.bottom;
4452 nScrollPosHeight = infoPtr->nItemHeight;
4454 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
4456 nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
4457 rcItem.bottom -= infoPtr->rcList.bottom;
4460 if (rcItem.bottom % nScrollPosHeight == 0)
4462 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight;
4464 else
4466 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight + 1;
4469 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
4474 if(bRedraw)
4475 InvalidateRect(hwnd,NULL,TRUE);
4476 return TRUE;
4479 /***
4480 * DESCRIPTION:
4481 * Retrieves the nearest item, given a position and a direction.
4483 * PARAMETER(S):
4484 * [I] HWND : window handle
4485 * [I] POINT : start position
4486 * [I] UINT : direction
4488 * RETURN:
4489 * Item index if successdful, -1 otherwise.
4491 static INT LISTVIEW_GetNearestItem(HWND hwnd, POINT pt, UINT vkDirection)
4493 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4494 LVHITTESTINFO lvHitTestInfo;
4495 INT nItem = -1;
4496 RECT rcView;
4498 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
4500 ZeroMemory(&lvHitTestInfo, sizeof(LVHITTESTINFO));
4501 LISTVIEW_GetOrigin(hwnd, &lvHitTestInfo.pt);
4502 lvHitTestInfo.pt.x += pt.x;
4503 lvHitTestInfo.pt.y += pt.y;
4507 if (vkDirection == VK_DOWN)
4509 lvHitTestInfo.pt.y += infoPtr->nItemHeight;
4511 else if (vkDirection == VK_UP)
4513 lvHitTestInfo.pt.y -= infoPtr->nItemHeight;
4515 else if (vkDirection == VK_LEFT)
4517 lvHitTestInfo.pt.x -= infoPtr->nItemWidth;
4519 else if (vkDirection == VK_RIGHT)
4521 lvHitTestInfo.pt.x += infoPtr->nItemWidth;
4524 if (PtInRect(&rcView, lvHitTestInfo.pt) == FALSE)
4526 return -1;
4528 else
4530 nItem = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo, TRUE);
4534 while (nItem == -1);
4537 return nItem;
4540 /***
4541 * DESCRIPTION:
4542 * Searches for an item with specific characteristics.
4544 * PARAMETER(S):
4545 * [I] HWND : window handle
4546 * [I] INT : base item index
4547 * [I] LPLVFINDINFO : item information to look for
4549 * RETURN:
4550 * SUCCESS : index of item
4551 * FAILURE : -1
4553 static LRESULT LISTVIEW_FindItem(HWND hwnd, INT nStart,
4554 LPLVFINDINFO lpFindInfo)
4556 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4557 POINT ptItem;
4558 CHAR szDispText[DISP_TEXT_SIZE];
4559 LVITEMA lvItem;
4560 BOOL bWrap = FALSE;
4561 INT nItem = nStart;
4562 INT nLast = GETITEMCOUNT(infoPtr);
4564 if ((nItem >= -1) && (lpFindInfo != NULL))
4566 ZeroMemory(&lvItem, sizeof(LVITEMA));
4568 if (lpFindInfo->flags & LVFI_PARAM)
4570 lvItem.mask |= LVIF_PARAM;
4573 if (lpFindInfo->flags & LVFI_STRING)
4575 lvItem.mask |= LVIF_TEXT;
4576 lvItem.pszText = szDispText;
4577 lvItem.cchTextMax = DISP_TEXT_SIZE;
4580 if (lpFindInfo->flags & LVFI_PARTIAL)
4582 lvItem.mask |= LVIF_TEXT;
4583 lvItem.pszText = szDispText;
4584 lvItem.cchTextMax = DISP_TEXT_SIZE;
4587 if (lpFindInfo->flags & LVFI_WRAP)
4589 bWrap = TRUE;
4592 if (lpFindInfo->flags & LVFI_NEARESTXY)
4594 ptItem.x = lpFindInfo->pt.x;
4595 ptItem.y = lpFindInfo->pt.y;
4598 while (1)
4600 while (nItem < nLast)
4602 if (lpFindInfo->flags & LVFI_NEARESTXY)
4604 nItem = LISTVIEW_GetNearestItem(hwnd, ptItem,
4605 lpFindInfo->vkDirection);
4606 if (nItem != -1)
4608 /* get position of the new item index */
4609 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) == FALSE)
4610 return -1;
4612 else
4613 return -1;
4615 else
4617 nItem++;
4620 lvItem.iItem = nItem;
4621 lvItem.iSubItem = 0;
4622 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
4624 if (lvItem.mask & LVIF_TEXT)
4626 if (lpFindInfo->flags & LVFI_PARTIAL)
4628 if (strstr(lvItem.pszText, lpFindInfo->psz) == NULL)
4629 continue;
4631 else
4633 if (strcmp(lvItem.pszText, lpFindInfo->psz) != 0)
4634 continue;
4638 if (lvItem.mask & LVIF_PARAM)
4640 if (lpFindInfo->lParam != lvItem.lParam)
4641 continue;
4644 return nItem;
4648 if (bWrap != FALSE)
4650 nItem = -1;
4651 nLast = nStart + 1;
4652 bWrap = FALSE;
4654 else
4656 return -1;
4661 return -1;
4664 /***
4665 * DESCRIPTION:
4666 * Retrieves the background color of the listview control.
4668 * PARAMETER(S):
4669 * [I] HWND : window handle
4671 * RETURN:
4672 * COLORREF associated with the background.
4674 static LRESULT LISTVIEW_GetBkColor(HWND hwnd)
4676 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4678 return infoPtr->clrBk;
4681 /***
4682 * DESCRIPTION:
4683 * Retrieves the background image of the listview control.
4685 * PARAMETER(S):
4686 * [I] HWND : window handle
4687 * [O] LPLVMKBIMAGE : background image attributes
4689 * RETURN:
4690 * SUCCESS : TRUE
4691 * FAILURE : FALSE
4693 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
4694 /* { */
4695 /* FIXME (listview, "empty stub!\n"); */
4696 /* return FALSE; */
4697 /* } */
4699 /***
4700 * DESCRIPTION:
4701 * Retrieves the callback mask.
4703 * PARAMETER(S):
4704 * [I] HWND : window handle
4706 * RETURN:
4707 * Value of mask
4709 static UINT LISTVIEW_GetCallbackMask(HWND hwnd)
4711 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4713 return infoPtr->uCallbackMask;
4716 /***
4717 * DESCRIPTION:
4718 * Retrieves column attributes.
4720 * PARAMETER(S):
4721 * [I] HWND : window handle
4722 * [I] INT : column index
4723 * [IO] LPLVCOLUMNA : column information
4725 * RETURN:
4726 * SUCCESS : TRUE
4727 * FAILURE : FALSE
4729 static LRESULT LISTVIEW_GetColumnA(HWND hwnd, INT nItem, LPLVCOLUMNA lpColumn)
4731 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4732 HDITEMA hdi;
4733 BOOL bResult = FALSE;
4735 if (lpColumn != NULL)
4737 /* initialize memory */
4738 ZeroMemory(&hdi, sizeof(HDITEMA));
4740 if (lpColumn->mask & LVCF_FMT)
4742 hdi.mask |= HDI_FORMAT;
4745 if (lpColumn->mask & LVCF_WIDTH)
4747 hdi.mask |= HDI_WIDTH;
4750 if (lpColumn->mask & LVCF_TEXT)
4752 hdi.mask |= HDI_TEXT;
4753 hdi.cchTextMax = lpColumn->cchTextMax;
4754 hdi.pszText = lpColumn->pszText;
4757 if (lpColumn->mask & LVCF_IMAGE)
4759 hdi.mask |= HDI_IMAGE;
4762 if (lpColumn->mask & LVCF_ORDER)
4764 hdi.mask |= HDI_ORDER;
4767 bResult = Header_GetItemA(infoPtr->hwndHeader, nItem, &hdi);
4768 if (bResult != FALSE)
4770 if (lpColumn->mask & LVCF_FMT)
4772 lpColumn->fmt = 0;
4774 if (hdi.fmt & HDF_LEFT)
4776 lpColumn->fmt |= LVCFMT_LEFT;
4778 else if (hdi.fmt & HDF_RIGHT)
4780 lpColumn->fmt |= LVCFMT_RIGHT;
4782 else if (hdi.fmt & HDF_CENTER)
4784 lpColumn->fmt |= LVCFMT_CENTER;
4787 if (hdi.fmt & HDF_IMAGE)
4789 lpColumn->fmt |= LVCFMT_COL_HAS_IMAGES;
4792 if (hdi.fmt & HDF_BITMAP_ON_RIGHT)
4794 lpColumn->fmt |= LVCFMT_BITMAP_ON_RIGHT;
4798 if (lpColumn->mask & LVCF_WIDTH)
4800 lpColumn->cx = hdi.cxy;
4803 if (lpColumn->mask & LVCF_IMAGE)
4805 lpColumn->iImage = hdi.iImage;
4808 if (lpColumn->mask & LVCF_ORDER)
4810 lpColumn->iOrder = hdi.iOrder;
4815 return bResult;
4818 /* LISTVIEW_GetColumnW */
4821 static LRESULT LISTVIEW_GetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
4823 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
4824 INT i;
4826 if (!lpiArray)
4827 return FALSE;
4829 /* little hack */
4830 for (i = 0; i < iCount; i++)
4831 lpiArray[i] = i;
4833 return TRUE;
4836 /***
4837 * DESCRIPTION:
4838 * Retrieves the column width.
4840 * PARAMETER(S):
4841 * [I] HWND : window handle
4842 * [I] int : column index
4844 * RETURN:
4845 * SUCCESS : column width
4846 * FAILURE : zero
4848 static LRESULT LISTVIEW_GetColumnWidth(HWND hwnd, INT nColumn)
4850 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4851 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4852 INT nColumnWidth = 0;
4853 HDITEMA hdi;
4855 if (uView == LVS_LIST)
4857 nColumnWidth = infoPtr->nItemWidth;
4859 else if (uView == LVS_REPORT)
4861 /* get column width from header */
4862 ZeroMemory(&hdi, sizeof(HDITEMA));
4863 hdi.mask = HDI_WIDTH;
4864 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdi) != FALSE)
4866 nColumnWidth = hdi.cxy;
4870 return nColumnWidth;
4873 /***
4874 * DESCRIPTION:
4875 * In list or report display mode, retrieves the number of items that can fit
4876 * vertically in the visible area. In icon or small icon display mode,
4877 * retrieves the total number of visible items.
4879 * PARAMETER(S):
4880 * [I] HWND : window handle
4882 * RETURN:
4883 * Number of fully visible items.
4885 static LRESULT LISTVIEW_GetCountPerPage(HWND hwnd)
4887 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4888 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4889 INT nItemCount = 0;
4891 if (uView == LVS_LIST)
4893 if (infoPtr->rcList.right > infoPtr->nItemWidth)
4895 nItemCount = LISTVIEW_GetCountPerRow(hwnd) *
4896 LISTVIEW_GetCountPerColumn(hwnd);
4899 else if (uView == LVS_REPORT)
4901 nItemCount = LISTVIEW_GetCountPerColumn(hwnd);
4903 else
4905 nItemCount = GETITEMCOUNT(infoPtr);
4908 return nItemCount;
4911 /* LISTVIEW_GetEditControl */
4913 /***
4914 * DESCRIPTION:
4915 * Retrieves the extended listview style.
4917 * PARAMETERS:
4918 * [I] HWND : window handle
4920 * RETURN:
4921 * SUCCESS : previous style
4922 * FAILURE : 0
4924 static LRESULT LISTVIEW_GetExtendedListViewStyle(HWND hwnd)
4926 LISTVIEW_INFO *infoPtr;
4928 /* make sure we can get the listview info */
4929 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
4930 return (0);
4932 return (infoPtr->dwExStyle);
4935 /***
4936 * DESCRIPTION:
4937 * Retrieves the handle to the header control.
4939 * PARAMETER(S):
4940 * [I] HWND : window handle
4942 * RETURN:
4943 * Header handle.
4945 static LRESULT LISTVIEW_GetHeader(HWND hwnd)
4947 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4949 return infoPtr->hwndHeader;
4952 /* LISTVIEW_GetHotCursor */
4954 /***
4955 * DESCRIPTION:
4956 * Returns the time that the mouse cursor must hover over an item
4957 * before it is selected.
4959 * PARAMETER(S):
4960 * [I] HWND : window handle
4962 * RETURN:
4963 * Returns the previously set hover time or (DWORD)-1 to indicate that the
4964 * hover time is set to the default hover time.
4966 static LRESULT LISTVIEW_GetHoverTime(HWND hwnd)
4968 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4970 return infoPtr->dwHoverTime;
4973 /***
4974 * DESCRIPTION:
4975 * Retrieves an image list handle.
4977 * PARAMETER(S):
4978 * [I] HWND : window handle
4979 * [I] INT : image list identifier
4981 * RETURN:
4982 * SUCCESS : image list handle
4983 * FAILURE : NULL
4985 static LRESULT LISTVIEW_GetImageList(HWND hwnd, INT nImageList)
4987 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4988 HIMAGELIST himl = NULL;
4990 switch (nImageList)
4992 case LVSIL_NORMAL:
4993 himl = infoPtr->himlNormal;
4994 break;
4995 case LVSIL_SMALL:
4996 himl = infoPtr->himlSmall;
4997 break;
4998 case LVSIL_STATE:
4999 himl = infoPtr->himlState;
5000 break;
5003 return (LRESULT)himl;
5006 /* LISTVIEW_GetISearchString */
5008 /***
5009 * DESCRIPTION:
5010 * Retrieves item attributes.
5012 * PARAMETER(S):
5013 * [I] HWND : window handle
5014 * [IO] LPLVITEMA : item info
5015 * [I] internal : if true then we will use tricks that avoid copies
5016 * but are not compatible with the regular interface
5018 * RETURN:
5019 * SUCCESS : TRUE
5020 * FAILURE : FALSE
5022 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem, BOOL internal)
5024 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5025 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
5026 NMLVDISPINFOA dispInfo;
5027 LISTVIEW_SUBITEM *lpSubItem;
5028 LISTVIEW_ITEM *lpItem;
5029 INT* piImage;
5030 LPSTR* ppszText;
5031 HDPA hdpaSubItems;
5032 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5033 /* In the following:
5034 * lpLVItem describes the information requested by the user
5035 * lpItem/lpSubItem is what we have
5036 * dispInfo is a structure we use to request the missing
5037 * information from the application
5040 TRACE("(hwnd=%x, lpLVItem=%p)\n", hwnd, lpLVItem);
5042 if ((lpLVItem == NULL) ||
5043 (lpLVItem->iItem < 0) ||
5044 (lpLVItem->iItem >= GETITEMCOUNT(infoPtr))
5046 return FALSE;
5048 if (lStyle & LVS_OWNERDATA)
5050 if (lpLVItem->mask & ~LVIF_STATE)
5052 dispInfo.hdr.hwndFrom = hwnd;
5053 dispInfo.hdr.idFrom = lCtrlId;
5054 dispInfo.hdr.code = LVN_GETDISPINFOA;
5055 memcpy(&dispInfo.item,lpLVItem,sizeof(LVITEMA));
5057 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
5058 memcpy(lpLVItem,&dispInfo.item,sizeof(LVITEMA));
5061 if ((lpLVItem->mask & LVIF_STATE)&&(lpLVItem->iSubItem == 0))
5063 lpLVItem->state = 0;
5064 if (infoPtr->nFocusedItem == lpLVItem->iItem)
5065 lpLVItem->state |= LVIS_FOCUSED;
5066 if (LISTVIEW_IsSelected(hwnd,lpLVItem->iItem))
5067 lpLVItem->state |= LVIS_SELECTED;
5070 return TRUE;
5074 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
5075 if (hdpaSubItems == NULL)
5076 return FALSE;
5078 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
5079 if (lpItem == NULL)
5080 return FALSE;
5082 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
5083 if (lpLVItem->iSubItem == 0)
5085 piImage=&lpItem->iImage;
5086 ppszText=&lpItem->pszText;
5087 if ((infoPtr->uCallbackMask != 0) && (lpLVItem->mask & LVIF_STATE))
5089 dispInfo.item.mask |= LVIF_STATE;
5090 dispInfo.item.stateMask = infoPtr->uCallbackMask;
5093 else
5095 lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem);
5096 if (lpSubItem != NULL)
5098 piImage=&lpSubItem->iImage;
5099 ppszText=&lpSubItem->pszText;
5101 else
5103 piImage=NULL;
5104 ppszText=NULL;
5108 if ((lpLVItem->mask & LVIF_IMAGE) &&
5109 ((piImage==NULL) || (*piImage == I_IMAGECALLBACK)))
5111 dispInfo.item.mask |= LVIF_IMAGE;
5114 if ((lpLVItem->mask & LVIF_TEXT) &&
5115 ((ppszText==NULL) || (*ppszText == LPSTR_TEXTCALLBACKA)))
5117 dispInfo.item.mask |= LVIF_TEXT;
5118 dispInfo.item.pszText = lpLVItem->pszText;
5119 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
5122 if (dispInfo.item.mask != 0)
5124 /* We don't have all the requested info, query the application */
5125 dispInfo.hdr.hwndFrom = hwnd;
5126 dispInfo.hdr.idFrom = lCtrlId;
5127 dispInfo.hdr.code = LVN_GETDISPINFOA;
5128 dispInfo.item.iItem = lpLVItem->iItem;
5129 dispInfo.item.iSubItem = lpLVItem->iSubItem;
5130 dispInfo.item.lParam = lpItem->lParam;
5131 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
5134 if (dispInfo.item.mask & LVIF_IMAGE)
5136 lpLVItem->iImage = dispInfo.item.iImage;
5138 else if (lpLVItem->mask & LVIF_IMAGE)
5140 lpLVItem->iImage = *piImage;
5143 if (dispInfo.item.mask & LVIF_PARAM)
5145 lpLVItem->lParam = dispInfo.item.lParam;
5147 else if (lpLVItem->mask & LVIF_PARAM)
5149 lpLVItem->lParam = lpItem->lParam;
5152 if (dispInfo.item.mask & LVIF_TEXT)
5154 if ((dispInfo.item.mask & LVIF_DI_SETITEM) && (ppszText != NULL))
5156 Str_SetPtrA(ppszText, dispInfo.item.pszText);
5158 /* If lpLVItem->pszText==dispInfo.item.pszText a copy is unnecessary, but */
5159 /* some apps give a new pointer in ListView_Notify so we can't be sure. */
5160 if (lpLVItem->pszText!=dispInfo.item.pszText) {
5161 lstrcpynA(lpLVItem->pszText, dispInfo.item.pszText, lpLVItem->cchTextMax);
5164 else if (lpLVItem->mask & LVIF_TEXT)
5166 if (internal==TRUE)
5168 lpLVItem->pszText=*ppszText;
5169 } else {
5170 lstrcpynA(lpLVItem->pszText, *ppszText, lpLVItem->cchTextMax);
5174 if (lpLVItem->iSubItem == 0)
5176 if (dispInfo.item.mask & LVIF_STATE)
5178 lpLVItem->state = lpItem->state;
5179 lpLVItem->state &= ~dispInfo.item.stateMask;
5180 lpLVItem->state |= (dispInfo.item.state & dispInfo.item.stateMask);
5182 lpLVItem->state &= ~LVIS_SELECTED;
5183 if ((dispInfo.item.stateMask & LVIS_SELECTED) &&
5184 (LISTVIEW_IsSelected(hwnd,dispInfo.item.iItem)))
5185 lpLVItem->state |= LVIS_SELECTED;
5187 else if (lpLVItem->mask & LVIF_STATE)
5189 lpLVItem->state = lpItem->state & lpLVItem->stateMask;
5191 lpLVItem->state &= ~LVIS_SELECTED;
5192 if ((lpLVItem->stateMask & LVIS_SELECTED) &&
5193 (LISTVIEW_IsSelected(hwnd,lpLVItem->iItem)))
5194 lpLVItem->state |= LVIS_SELECTED;
5197 if (lpLVItem->mask & LVIF_PARAM)
5199 lpLVItem->lParam = lpItem->lParam;
5202 if (lpLVItem->mask & LVIF_INDENT)
5204 lpLVItem->iIndent = lpItem->iIndent;
5208 return TRUE;
5211 /* LISTVIEW_GetItemW */
5212 /* LISTVIEW_GetHotCursor */
5214 /***
5215 * DESCRIPTION:
5216 * Retrieves the index of the hot item.
5218 * PARAMETERS:
5219 * [I] HWND : window handle
5221 * RETURN:
5222 * SUCCESS : hot item index
5223 * FAILURE : -1 (no hot item)
5225 static LRESULT LISTVIEW_GetHotItem(HWND hwnd)
5227 LISTVIEW_INFO *infoPtr;
5229 /* make sure we can get the listview info */
5230 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5231 return (-1);
5233 return (infoPtr->nHotItem);
5236 /* LISTVIEW_GetHoverTime */
5238 /***
5239 * DESCRIPTION:
5240 * Retrieves the number of items in the listview control.
5242 * PARAMETER(S):
5243 * [I] HWND : window handle
5245 * RETURN:
5246 * Number of items.
5248 static LRESULT LISTVIEW_GetItemCount(HWND hwnd)
5250 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5252 return GETITEMCOUNT(infoPtr);
5255 /***
5256 * DESCRIPTION:
5257 * Retrieves the position (upper-left) of the listview control item.
5259 * PARAMETER(S):
5260 * [I] HWND : window handle
5261 * [I] INT : item index
5262 * [O] LPPOINT : coordinate information
5264 * RETURN:
5265 * SUCCESS : TRUE
5266 * FAILURE : FALSE
5268 static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem,
5269 LPPOINT lpptPosition)
5271 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5272 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5273 BOOL bResult = FALSE;
5274 HDPA hdpaSubItems;
5275 LISTVIEW_ITEM *lpItem;
5276 INT nCountPerColumn;
5277 INT nRow;
5279 TRACE("(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd, nItem,
5280 lpptPosition);
5282 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
5283 (lpptPosition != NULL))
5285 if (uView == LVS_LIST)
5287 bResult = TRUE;
5288 nItem = nItem - ListView_GetTopIndex(hwnd);
5289 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
5290 if (nItem < 0)
5292 nRow = nItem % nCountPerColumn;
5293 if (nRow == 0)
5295 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
5296 lpptPosition->y = 0;
5298 else
5300 lpptPosition->x = (nItem / nCountPerColumn -1) * infoPtr->nItemWidth;
5301 lpptPosition->y = (nRow + nCountPerColumn) * infoPtr->nItemHeight;
5304 else
5306 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
5307 lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight;
5310 else if (uView == LVS_REPORT)
5312 SCROLLINFO scrollInfo;
5313 bResult = TRUE;
5314 lpptPosition->x = REPORT_MARGINX;
5315 lpptPosition->y = ((nItem - ListView_GetTopIndex(hwnd)) *
5316 infoPtr->nItemHeight) + infoPtr->rcList.top;
5318 /* Adjust position by scrollbar offset */
5319 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
5320 scrollInfo.cbSize = sizeof(SCROLLINFO);
5321 scrollInfo.fMask = SIF_POS;
5322 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
5323 lpptPosition->x -= scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
5325 else
5327 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
5328 if (hdpaSubItems != NULL)
5330 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
5331 if (lpItem != NULL)
5333 bResult = TRUE;
5334 lpptPosition->x = lpItem->ptPosition.x;
5335 lpptPosition->y = lpItem->ptPosition.y;
5340 return bResult;
5343 /***
5344 * DESCRIPTION:
5345 * Retrieves the bounding rectangle for a listview control item.
5347 * PARAMETER(S):
5348 * [I] HWND : window handle
5349 * [I] INT : item index
5350 * [IO] LPRECT : bounding rectangle coordinates
5351 * lprc->left specifies the portion of the item for which the bounding
5352 * rectangle will be retrieved.
5354 * LVIR_BOUNDS Returns the bounding rectangle of the entire item,
5355 * including the icon and label.
5356 * LVIR_ICON Returns the bounding rectangle of the icon or small icon.
5357 * LVIR_LABEL Returns the bounding rectangle of the item text.
5358 * LVIR_SELECTBOUNDS Returns the union of the LVIR_ICON and LVIR_LABEL
5359 * rectangles, but excludes columns in report view.
5361 * RETURN:
5362 * SUCCESS : TRUE
5363 * FAILURE : FALSE
5365 static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc)
5367 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5368 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5369 BOOL bResult = FALSE;
5370 POINT ptOrigin;
5371 POINT ptItem;
5372 HDC hdc;
5373 HFONT hOldFont;
5374 INT nLeftPos;
5375 INT nLabelWidth;
5376 INT nIndent;
5377 TEXTMETRICA tm;
5378 LVITEMA lvItem;
5380 TRACE("(hwnd=%x, nItem=%d, lprc=%p)\n", hwnd, nItem, lprc);
5382 if (uView & LVS_REPORT)
5384 ZeroMemory(&lvItem, sizeof(LVITEMA));
5385 lvItem.mask = LVIF_INDENT;
5386 lvItem.iItem = nItem;
5387 lvItem.iSubItem = 0;
5388 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
5390 /* do indent */
5391 if (lvItem.iIndent>0 && infoPtr->iconSize.cx > 0)
5393 nIndent = infoPtr->iconSize.cx * lvItem.iIndent;
5395 else
5396 nIndent = 0;
5398 else
5399 nIndent = 0;
5401 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL))
5403 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) != FALSE)
5405 switch(lprc->left)
5407 case LVIR_ICON:
5408 if (uView == LVS_ICON)
5410 if (infoPtr->himlNormal != NULL)
5412 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5414 bResult = TRUE;
5415 lprc->left = ptItem.x + ptOrigin.x;
5416 lprc->top = ptItem.y + ptOrigin.y;
5417 lprc->right = lprc->left + infoPtr->iconSize.cx;
5418 lprc->bottom = (lprc->top + infoPtr->iconSize.cy +
5419 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
5423 else if (uView == LVS_SMALLICON)
5425 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5427 bResult = TRUE;
5428 lprc->left = ptItem.x + ptOrigin.x;
5429 lprc->top = ptItem.y + ptOrigin.y;
5430 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5432 if (infoPtr->himlState != NULL)
5433 lprc->left += infoPtr->iconSize.cx;
5435 if (infoPtr->himlSmall != NULL)
5436 lprc->right = lprc->left + infoPtr->iconSize.cx;
5437 else
5438 lprc->right = lprc->left;
5441 else
5443 bResult = TRUE;
5444 lprc->left = ptItem.x;
5445 if (uView & LVS_REPORT)
5446 lprc->left += nIndent;
5447 lprc->top = ptItem.y;
5448 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5450 if (infoPtr->himlState != NULL)
5452 lprc->left += infoPtr->iconSize.cx;
5455 if (infoPtr->himlSmall != NULL)
5457 lprc->right = lprc->left + infoPtr->iconSize.cx;
5459 else
5461 lprc->right = lprc->left;
5464 break;
5466 case LVIR_LABEL:
5467 if (uView == LVS_ICON)
5469 if (infoPtr->himlNormal != NULL)
5471 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5473 bResult = TRUE;
5474 lprc->left = ptItem.x + ptOrigin.x;
5475 lprc->top = (ptItem.y + ptOrigin.y + infoPtr->iconSize.cy +
5476 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
5477 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5478 if (infoPtr->iconSpacing.cx - nLabelWidth > 1)
5480 lprc->left += (infoPtr->iconSpacing.cx - nLabelWidth) / 2;
5481 lprc->right = lprc->left + nLabelWidth;
5483 else
5485 lprc->left += 1;
5486 lprc->right = lprc->left + infoPtr->iconSpacing.cx - 1;
5489 hdc = GetDC(hwnd);
5490 hOldFont = SelectObject(hdc, infoPtr->hFont);
5491 GetTextMetricsA(hdc, &tm);
5492 lprc->bottom = lprc->top + tm.tmHeight + HEIGHT_PADDING;
5493 SelectObject(hdc, hOldFont);
5494 ReleaseDC(hwnd, hdc);
5498 else if (uView == LVS_SMALLICON)
5500 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5502 bResult = TRUE;
5503 nLeftPos = lprc->left = ptItem.x + ptOrigin.x;
5504 lprc->top = ptItem.y + ptOrigin.y;
5505 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5507 if (infoPtr->himlState != NULL)
5509 lprc->left += infoPtr->iconSize.cx;
5512 if (infoPtr->himlSmall != NULL)
5514 lprc->left += infoPtr->iconSize.cx;
5517 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5518 nLabelWidth += TRAILING_PADDING;
5519 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5521 lprc->right = lprc->left + nLabelWidth;
5523 else
5525 lprc->right = nLeftPos + infoPtr->nItemWidth;
5529 else
5531 bResult = TRUE;
5532 if (uView & LVS_REPORT)
5533 nLeftPos = lprc->left = ptItem.x + nIndent;
5534 else
5535 nLeftPos = lprc->left = ptItem.x;
5536 lprc->top = ptItem.y;
5537 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5539 if (infoPtr->himlState != NULL)
5541 lprc->left += infoPtr->iconSize.cx;
5544 if (infoPtr->himlSmall != NULL)
5546 lprc->left += infoPtr->iconSize.cx;
5549 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5550 nLabelWidth += TRAILING_PADDING;
5551 if (infoPtr->himlSmall)
5552 nLabelWidth += IMAGE_PADDING;
5553 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5555 lprc->right = lprc->left + nLabelWidth;
5557 else
5559 lprc->right = nLeftPos + infoPtr->nItemWidth;
5562 break;
5564 case LVIR_BOUNDS:
5565 if (uView == LVS_ICON)
5567 if (infoPtr->himlNormal != NULL)
5569 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5571 bResult = TRUE;
5572 lprc->left = ptItem.x + ptOrigin.x;
5573 lprc->top = ptItem.y + ptOrigin.y;
5574 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
5575 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
5579 else if (uView == LVS_SMALLICON)
5581 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5583 bResult = TRUE;
5584 lprc->left = ptItem.x + ptOrigin.x;
5585 lprc->right = lprc->left;
5586 lprc->top = ptItem.y + ptOrigin.y;
5587 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5588 if (infoPtr->himlState != NULL)
5589 lprc->right += infoPtr->iconSize.cx;
5590 if (infoPtr->himlSmall != NULL)
5591 lprc->right += infoPtr->iconSize.cx;
5593 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5594 nLabelWidth += TRAILING_PADDING;
5595 if (infoPtr->himlSmall)
5596 nLabelWidth += IMAGE_PADDING;
5597 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
5599 lprc->right += nLabelWidth;
5601 else
5603 lprc->right = lprc->left + infoPtr->nItemWidth;
5607 else
5609 bResult = TRUE;
5610 lprc->left = ptItem.x;
5611 if (!(infoPtr->dwExStyle&LVS_EX_FULLROWSELECT) && uView&LVS_REPORT)
5612 lprc->left += nIndent;
5613 lprc->right = lprc->left;
5614 lprc->top = ptItem.y;
5615 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5617 if (infoPtr->dwExStyle & LVS_EX_FULLROWSELECT)
5619 RECT br;
5620 int nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
5621 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
5623 lprc->right = max(lprc->left, br.right - REPORT_MARGINX);
5625 else
5627 if (infoPtr->himlState != NULL)
5629 lprc->right += infoPtr->iconSize.cx;
5632 if (infoPtr->himlSmall != NULL)
5634 lprc->right += infoPtr->iconSize.cx;
5637 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5638 nLabelWidth += TRAILING_PADDING;
5639 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
5641 lprc->right += nLabelWidth;
5643 else
5645 lprc->right = lprc->left + infoPtr->nItemWidth;
5649 break;
5651 case LVIR_SELECTBOUNDS:
5652 if (uView == LVS_ICON)
5654 if (infoPtr->himlNormal != NULL)
5656 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5658 bResult = TRUE;
5659 lprc->left = ptItem.x + ptOrigin.x;
5660 lprc->top = ptItem.y + ptOrigin.y;
5661 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
5662 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
5666 else if (uView == LVS_SMALLICON)
5668 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5670 bResult = TRUE;
5671 nLeftPos= lprc->left = ptItem.x + ptOrigin.x;
5672 lprc->top = ptItem.y + ptOrigin.y;
5673 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5675 if (infoPtr->himlState != NULL)
5677 lprc->left += infoPtr->iconSize.cx;
5680 lprc->right = lprc->left;
5682 if (infoPtr->himlSmall != NULL)
5684 lprc->right += infoPtr->iconSize.cx;
5687 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5688 nLabelWidth += TRAILING_PADDING;
5689 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5691 lprc->right += nLabelWidth;
5693 else
5695 lprc->right = nLeftPos + infoPtr->nItemWidth;
5699 else
5701 bResult = TRUE;
5702 if (!(infoPtr->dwExStyle&LVS_EX_FULLROWSELECT) && (uView&LVS_REPORT))
5703 nLeftPos = lprc->left = ptItem.x + nIndent;
5704 else
5705 nLeftPos = lprc->left = ptItem.x;
5706 lprc->top = ptItem.y;
5707 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5709 if (infoPtr->himlState != NULL)
5711 lprc->left += infoPtr->iconSize.cx;
5714 lprc->right = lprc->left;
5716 if (infoPtr->dwExStyle & LVS_EX_FULLROWSELECT)
5718 RECT br;
5719 int nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
5720 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
5722 lprc->right = max(lprc->left, br.right - REPORT_MARGINX);
5724 else
5726 if (infoPtr->himlSmall != NULL)
5728 lprc->right += infoPtr->iconSize.cx;
5731 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5732 nLabelWidth += TRAILING_PADDING;
5733 if (infoPtr->himlSmall)
5734 nLabelWidth += IMAGE_PADDING;
5735 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5737 lprc->right += nLabelWidth;
5739 else
5741 lprc->right = nLeftPos + infoPtr->nItemWidth;
5745 break;
5749 return bResult;
5752 /***
5753 * DESCRIPTION:
5754 * Retrieves the width of a label.
5756 * PARAMETER(S):
5757 * [I] HWND : window handle
5759 * RETURN:
5760 * SUCCESS : string width (in pixels)
5761 * FAILURE : zero
5763 static INT LISTVIEW_GetLabelWidth(HWND hwnd, INT nItem)
5765 CHAR szDispText[DISP_TEXT_SIZE];
5766 INT nLabelWidth = 0;
5767 LVITEMA lvItem;
5769 TRACE("(hwnd=%x, nItem=%d)\n", hwnd, nItem);
5771 ZeroMemory(&lvItem, sizeof(LVITEMA));
5772 lvItem.mask = LVIF_TEXT;
5773 lvItem.iItem = nItem;
5774 lvItem.cchTextMax = DISP_TEXT_SIZE;
5775 lvItem.pszText = szDispText;
5776 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
5778 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
5781 return nLabelWidth;
5784 /***
5785 * DESCRIPTION:
5786 * Retrieves the spacing between listview control items.
5788 * PARAMETER(S):
5789 * [I] HWND : window handle
5790 * [I] BOOL : flag for small or large icon
5792 * RETURN:
5793 * Horizontal + vertical spacing
5795 static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall)
5797 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5798 LONG lResult;
5800 if (bSmall == FALSE)
5802 lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
5804 else
5806 /* TODO: need to store width of smallicon item */
5807 lResult = MAKELONG(0, infoPtr->nItemHeight);
5810 return lResult;
5813 /***
5814 * DESCRIPTION:
5815 * Retrieves the state of a listview control item.
5817 * PARAMETER(S):
5818 * [I] HWND : window handle
5819 * [I] INT : item index
5820 * [I] UINT : state mask
5822 * RETURN:
5823 * State specified by the mask.
5825 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask)
5827 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5828 LVITEMA lvItem;
5829 UINT uState = 0;
5831 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5833 ZeroMemory(&lvItem, sizeof(LVITEMA));
5834 lvItem.iItem = nItem;
5835 lvItem.stateMask = uMask;
5836 lvItem.mask = LVIF_STATE;
5837 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
5839 uState = lvItem.state;
5843 return uState;
5846 /***
5847 * DESCRIPTION:
5848 * Retrieves the text of a listview control item or subitem.
5850 * PARAMETER(S):
5851 * [I] HWND : window handle
5852 * [I] INT : item index
5853 * [IO] LPLVITEMA : item information
5855 * RETURN:
5856 * SUCCESS : string length
5857 * FAILURE : 0
5859 static LRESULT LISTVIEW_GetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5861 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5862 INT nLength = 0;
5864 if (lpLVItem != NULL)
5866 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5868 lpLVItem->mask = LVIF_TEXT;
5869 lpLVItem->iItem = nItem;
5870 if (LISTVIEW_GetItemA(hwnd, lpLVItem, FALSE) != FALSE)
5872 nLength = lstrlenA(lpLVItem->pszText);
5877 return nLength;
5880 /***
5881 * DESCRIPTION:
5882 * Searches for an item based on properties + relationships.
5884 * PARAMETER(S):
5885 * [I] HWND : window handle
5886 * [I] INT : item index
5887 * [I] INT : relationship flag
5889 * RETURN:
5890 * SUCCESS : item index
5891 * FAILURE : -1
5893 static LRESULT LISTVIEW_GetNextItem(HWND hwnd, INT nItem, UINT uFlags)
5895 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5896 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5897 UINT uMask = 0;
5898 LVFINDINFO lvFindInfo;
5899 INT nCountPerColumn;
5900 INT i;
5902 if ((nItem >= -1) && (nItem < GETITEMCOUNT(infoPtr)))
5904 ZeroMemory(&lvFindInfo, sizeof(LVFINDINFO));
5906 if (uFlags & LVNI_CUT)
5907 uMask |= LVIS_CUT;
5909 if (uFlags & LVNI_DROPHILITED)
5910 uMask |= LVIS_DROPHILITED;
5912 if (uFlags & LVNI_FOCUSED)
5913 uMask |= LVIS_FOCUSED;
5915 if (uFlags & LVNI_SELECTED)
5916 uMask |= LVIS_SELECTED;
5918 if (uFlags & LVNI_ABOVE)
5920 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
5922 while (nItem >= 0)
5924 nItem--;
5925 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5926 return nItem;
5929 else
5931 lvFindInfo.flags = LVFI_NEARESTXY;
5932 lvFindInfo.vkDirection = VK_UP;
5933 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5934 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5936 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5937 return nItem;
5941 else if (uFlags & LVNI_BELOW)
5943 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
5945 while (nItem < GETITEMCOUNT(infoPtr))
5947 nItem++;
5948 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5949 return nItem;
5952 else
5954 lvFindInfo.flags = LVFI_NEARESTXY;
5955 lvFindInfo.vkDirection = VK_DOWN;
5956 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5957 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5959 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5960 return nItem;
5964 else if (uFlags & LVNI_TOLEFT)
5966 if (uView == LVS_LIST)
5968 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
5969 while (nItem - nCountPerColumn >= 0)
5971 nItem -= nCountPerColumn;
5972 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5973 return nItem;
5976 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
5978 lvFindInfo.flags = LVFI_NEARESTXY;
5979 lvFindInfo.vkDirection = VK_LEFT;
5980 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5981 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5983 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5984 return nItem;
5988 else if (uFlags & LVNI_TORIGHT)
5990 if (uView == LVS_LIST)
5992 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
5993 while (nItem + nCountPerColumn < GETITEMCOUNT(infoPtr))
5995 nItem += nCountPerColumn;
5996 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5997 return nItem;
6000 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
6002 lvFindInfo.flags = LVFI_NEARESTXY;
6003 lvFindInfo.vkDirection = VK_RIGHT;
6004 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
6005 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
6007 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
6008 return nItem;
6012 else
6014 nItem++;
6016 /* search by index */
6017 for (i = nItem; i < GETITEMCOUNT(infoPtr); i++)
6019 if ((ListView_GetItemState(hwnd, i, uMask) & uMask) == uMask)
6020 return i;
6025 return -1;
6028 /* LISTVIEW_GetNumberOfWorkAreas */
6030 /***
6031 * DESCRIPTION:
6032 * Retrieves the origin coordinates when in icon or small icon display mode.
6034 * PARAMETER(S):
6035 * [I] HWND : window handle
6036 * [O] LPPOINT : coordinate information
6038 * RETURN:
6039 * SUCCESS : TRUE
6040 * FAILURE : FALSE
6042 static LRESULT LISTVIEW_GetOrigin(HWND hwnd, LPPOINT lpptOrigin)
6044 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6045 UINT uView = lStyle & LVS_TYPEMASK;
6046 BOOL bResult = FALSE;
6048 TRACE("(hwnd=%x, lpptOrigin=%p)\n", hwnd, lpptOrigin);
6050 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
6052 SCROLLINFO scrollInfo;
6053 ZeroMemory(lpptOrigin, sizeof(POINT));
6054 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
6055 scrollInfo.cbSize = sizeof(SCROLLINFO);
6057 if (lStyle & WS_HSCROLL)
6059 scrollInfo.fMask = SIF_POS;
6060 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
6062 lpptOrigin->x = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
6066 if (lStyle & WS_VSCROLL)
6068 scrollInfo.fMask = SIF_POS;
6069 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
6071 lpptOrigin->y = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
6075 bResult = TRUE;
6078 return bResult;
6081 /***
6082 * DESCRIPTION:
6083 * Retrieves the number of items that are marked as selected.
6085 * PARAMETER(S):
6086 * [I] HWND : window handle
6088 * RETURN:
6089 * Number of items selected.
6091 static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd)
6093 /* REDO THIS */
6094 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6095 INT nSelectedCount = 0;
6096 INT i;
6098 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
6100 if (ListView_GetItemState(hwnd, i, LVIS_SELECTED) & LVIS_SELECTED)
6102 nSelectedCount++;
6106 return nSelectedCount;
6109 /***
6110 * DESCRIPTION:
6111 * Retrieves item index that marks the start of a multiple selection.
6113 * PARAMETER(S):
6114 * [I] HWND : window handle
6116 * RETURN:
6117 * Index number or -1 if there is no selection mark.
6119 static LRESULT LISTVIEW_GetSelectionMark(HWND hwnd)
6121 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6123 return infoPtr->nSelectionMark;
6126 /***
6127 * DESCRIPTION:
6128 * Retrieves the width of a string.
6130 * PARAMETER(S):
6131 * [I] HWND : window handle
6133 * RETURN:
6134 * SUCCESS : string width (in pixels)
6135 * FAILURE : zero
6137 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText)
6139 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6140 HFONT hFont, hOldFont;
6141 SIZE stringSize;
6142 HDC hdc;
6144 ZeroMemory(&stringSize, sizeof(SIZE));
6145 if (lpszText != NULL && lpszText != LPSTR_TEXTCALLBACKA)
6147 hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
6148 hdc = GetDC(hwnd);
6149 hOldFont = SelectObject(hdc, hFont);
6150 GetTextExtentPointA(hdc, lpszText, lstrlenA(lpszText), &stringSize);
6151 SelectObject(hdc, hOldFont);
6152 ReleaseDC(hwnd, hdc);
6155 return stringSize.cx;
6158 /***
6159 * DESCRIPTION:
6160 * Retrieves the text backgound color.
6162 * PARAMETER(S):
6163 * [I] HWND : window handle
6165 * RETURN:
6166 * COLORREF associated with the the background.
6168 static LRESULT LISTVIEW_GetTextBkColor(HWND hwnd)
6170 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
6172 return infoPtr->clrTextBk;
6175 /***
6176 * DESCRIPTION:
6177 * Retrieves the text color.
6179 * PARAMETER(S):
6180 * [I] HWND : window handle
6182 * RETURN:
6183 * COLORREF associated with the text.
6185 static LRESULT LISTVIEW_GetTextColor(HWND hwnd)
6187 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
6189 return infoPtr->clrText;
6192 /***
6193 * DESCRIPTION:
6194 * Determines which section of the item was selected (if any).
6196 * PARAMETER(S):
6197 * [I] HWND : window handle
6198 * [IO] LPLVHITTESTINFO : hit test information
6199 * [I] subitem : fill out iSubItem.
6201 * RETURN:
6202 * SUCCESS : item index
6203 * FAILURE : -1
6205 static INT LISTVIEW_HitTestItem(
6206 HWND hwnd, LPLVHITTESTINFO lpHitTestInfo, BOOL subitem
6208 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6209 RECT rcItem;
6210 INT i,topindex,bottomindex;
6211 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6212 UINT uView = lStyle & LVS_TYPEMASK;
6215 TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpHitTestInfo->pt.x,
6216 lpHitTestInfo->pt.y);
6218 topindex = ListView_GetTopIndex(hwnd);
6219 if (uView == LVS_REPORT)
6221 bottomindex = topindex + LISTVIEW_GetCountPerColumn(hwnd) + 1;
6222 bottomindex = min(bottomindex,GETITEMCOUNT(infoPtr));
6224 else
6226 bottomindex = GETITEMCOUNT(infoPtr);
6229 for (i = topindex; i < bottomindex; i++)
6231 rcItem.left = LVIR_BOUNDS;
6232 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
6234 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
6236 rcItem.left = LVIR_ICON;
6237 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
6239 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
6241 lpHitTestInfo->flags = LVHT_ONITEMICON;
6242 lpHitTestInfo->iItem = i;
6243 if (subitem) lpHitTestInfo->iSubItem = 0;
6244 return i;
6248 rcItem.left = LVIR_LABEL;
6249 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
6251 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
6253 lpHitTestInfo->flags = LVHT_ONITEMLABEL;
6254 lpHitTestInfo->iItem = i;
6255 if (subitem) lpHitTestInfo->iSubItem = 0;
6256 return i;
6260 lpHitTestInfo->flags = LVHT_ONITEMSTATEICON;
6261 lpHitTestInfo->iItem = i;
6262 if (subitem) lpHitTestInfo->iSubItem = 0;
6263 return i;
6268 lpHitTestInfo->flags = LVHT_NOWHERE;
6270 return -1;
6273 /***
6274 * DESCRIPTION:
6275 * Determines which listview item is located at the specified position.
6277 * PARAMETER(S):
6278 * [I] HWND : window handle
6279 * [IO} LPLVHITTESTINFO : hit test information
6281 * RETURN:
6282 * SUCCESS : item index
6283 * FAILURE : -1
6285 static LRESULT LISTVIEW_HitTest(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
6287 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6288 INT nItem = -1;
6290 lpHitTestInfo->flags = 0;
6292 if (infoPtr->rcList.left > lpHitTestInfo->pt.x)
6294 lpHitTestInfo->flags = LVHT_TOLEFT;
6296 else if (infoPtr->rcList.right < lpHitTestInfo->pt.x)
6298 lpHitTestInfo->flags = LVHT_TORIGHT;
6300 if (infoPtr->rcList.top > lpHitTestInfo->pt.y)
6302 lpHitTestInfo->flags |= LVHT_ABOVE;
6304 else if (infoPtr->rcList.bottom < lpHitTestInfo->pt.y)
6306 lpHitTestInfo->flags |= LVHT_BELOW;
6309 if (lpHitTestInfo->flags == 0)
6311 /* NOTE (mm 20001022): We must not allow iSubItem to be touched, for
6312 * an app might pass only a structure with space up to iItem!
6313 * (MS Office 97 does that for instance in the file open dialog)
6315 nItem = LISTVIEW_HitTestItem(hwnd, lpHitTestInfo, FALSE);
6318 return nItem;
6321 /***
6322 * DESCRIPTION:
6323 * Inserts a new column.
6325 * PARAMETER(S):
6326 * [I] HWND : window handle
6327 * [I] INT : column index
6328 * [I] LPLVCOLUMNA : column information
6330 * RETURN:
6331 * SUCCESS : new column index
6332 * FAILURE : -1
6334 static LRESULT LISTVIEW_InsertColumnA(HWND hwnd, INT nColumn,
6335 LPLVCOLUMNA lpColumn)
6337 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6338 HDITEMA hdi;
6339 INT nNewColumn = -1;
6341 TRACE("(hwnd=%x, nColumn=%d, lpColumn=%p)\n",hwnd, nColumn,
6342 lpColumn);
6344 if (lpColumn != NULL)
6346 /* initialize memory */
6347 ZeroMemory(&hdi, sizeof(HDITEMA));
6349 if (lpColumn->mask & LVCF_FMT)
6351 /* format member is valid */
6352 hdi.mask |= HDI_FORMAT;
6354 /* set text alignment (leftmost column must be left-aligned) */
6355 if (nColumn == 0)
6357 hdi.fmt |= HDF_LEFT;
6359 else
6361 if (lpColumn->fmt & LVCFMT_LEFT)
6363 hdi.fmt |= HDF_LEFT;
6365 else if (lpColumn->fmt & LVCFMT_RIGHT)
6367 hdi.fmt |= HDF_RIGHT;
6369 else if (lpColumn->fmt & LVCFMT_CENTER)
6371 hdi.fmt |= HDF_CENTER;
6375 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
6377 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
6378 /* ??? */
6381 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
6383 /* ??? */
6386 if (lpColumn->fmt & LVCFMT_IMAGE)
6388 hdi.fmt |= HDF_IMAGE;
6389 hdi.iImage = I_IMAGECALLBACK;
6393 if (lpColumn->mask & LVCF_WIDTH)
6395 hdi.mask |= HDI_WIDTH;
6396 hdi.cxy = lpColumn->cx;
6399 if (lpColumn->mask & LVCF_TEXT)
6401 hdi.mask |= HDI_TEXT | HDI_FORMAT;
6402 hdi.pszText = lpColumn->pszText;
6403 hdi.cchTextMax = ((lpColumn->pszText!=NULL) && (lpColumn->pszText!=LPSTR_TEXTCALLBACKA) ? strlen(lpColumn->pszText) : 0);
6404 hdi.fmt |= HDF_STRING;
6407 if (lpColumn->mask & LVCF_IMAGE)
6409 hdi.mask |= HDI_IMAGE;
6410 hdi.iImage = lpColumn->iImage;
6413 if (lpColumn->mask & LVCF_ORDER)
6415 hdi.mask |= HDI_ORDER;
6416 hdi.iOrder = lpColumn->iOrder;
6419 /* insert item in header control */
6420 nNewColumn = SendMessageA(infoPtr->hwndHeader, HDM_INSERTITEMA,
6421 (WPARAM)nColumn, (LPARAM)&hdi);
6423 /* Need to reset the item width when inserting a new column */
6424 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6426 LISTVIEW_UpdateScroll(hwnd);
6427 InvalidateRect(hwnd, NULL, FALSE);
6430 return nNewColumn;
6433 static LRESULT LISTVIEW_InsertColumnW(HWND hwnd, INT nColumn,
6434 LPLVCOLUMNW lpColumn)
6436 LVCOLUMNA lvca;
6437 LRESULT lres;
6439 memcpy(&lvca,lpColumn,sizeof(lvca));
6440 if (lpColumn->mask & LVCF_TEXT) {
6441 if (lpColumn->pszText == LPSTR_TEXTCALLBACKW)
6442 lvca.pszText = LPSTR_TEXTCALLBACKA;
6443 else
6444 lvca.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpColumn->pszText);
6446 lres = LISTVIEW_InsertColumnA(hwnd,nColumn,&lvca);
6447 if (lpColumn->mask & LVCF_TEXT) {
6448 if (lpColumn->pszText != LPSTR_TEXTCALLBACKW)
6449 HeapFree(GetProcessHeap(),0,lvca.pszText);
6451 return lres;
6454 /* LISTVIEW_InsertCompare: callback routine for comparing pszText members of the LV_ITEMS
6455 in a LISTVIEW on insert. Passed to DPA_Sort in LISTVIEW_InsertItem.
6456 This function should only be used for inserting items into a sorted list (LVM_INSERTITEM)
6457 and not during the processing of a LVM_SORTITEMS message. Applications should provide
6458 their own sort proc. when sending LVM_SORTITEMS.
6460 /* Platform SDK:
6461 (remarks on LVITEM: LVM_INSERTITEM will insert the new item in the proper sort postion...
6463 LVS_SORTXXX must be specified,
6464 LVS_OWNERDRAW is not set,
6465 <item>.pszText is not LPSTR_TEXTCALLBACK.
6467 (LVS_SORT* flags): "For the LVS_SORTASCENDING... styles, item indices
6468 are sorted based on item text..."
6470 static INT WINAPI LISTVIEW_InsertCompare( LPVOID first, LPVOID second, LPARAM lParam)
6472 HDPA hdpa_first = (HDPA) first;
6473 HDPA hdpa_second = (HDPA) second;
6474 LISTVIEW_ITEM* lv_first = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_first, 0 );
6475 LISTVIEW_ITEM* lv_second = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_second, 0 );
6476 LONG lStyle = GetWindowLongA((HWND) lParam, GWL_STYLE);
6477 INT cmpv = lstrcmpA( lv_first->pszText, lv_second->pszText );
6478 /* if we're sorting descending, negate the return value */
6479 return (lStyle & LVS_SORTDESCENDING) ? -cmpv : cmpv;
6482 /***
6483 * nESCRIPTION:
6484 * Inserts a new item in the listview control.
6486 * PARAMETER(S):
6487 * [I] HWND : window handle
6488 * [I] LPLVITEMA : item information
6490 * RETURN:
6491 * SUCCESS : new item index
6492 * FAILURE : -1
6494 static LRESULT LISTVIEW_InsertItemA(HWND hwnd, LPLVITEMA lpLVItem)
6496 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6497 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6498 UINT uView = lStyle & LVS_TYPEMASK;
6499 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
6500 NMLISTVIEW nmlv;
6501 INT nItem = -1;
6502 HDPA hdpaSubItems;
6503 INT nItemWidth = 0;
6504 LISTVIEW_ITEM *lpItem = NULL;
6506 TRACE("(hwnd=%x,lpLVItem=%p)\n", hwnd, lpLVItem);
6508 if (lStyle & LVS_OWNERDATA)
6510 nItem = infoPtr->hdpaItems->nItemCount;
6511 infoPtr->hdpaItems->nItemCount ++;
6512 return nItem;
6515 if (lpLVItem != NULL)
6517 /* make sure it's not a subitem; cannot insert a subitem */
6518 if (lpLVItem->iSubItem == 0)
6520 lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM));
6521 if (lpItem != NULL)
6523 ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
6524 if (LISTVIEW_InitItem(hwnd, lpItem, lpLVItem) != FALSE)
6526 /* insert item in listview control data structure */
6527 hdpaSubItems = DPA_Create(8);
6528 if (hdpaSubItems != NULL)
6530 nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem);
6531 if (nItem != -1)
6533 if ( ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
6534 && !(lStyle & LVS_OWNERDRAWFIXED)
6535 && (LPSTR_TEXTCALLBACKA != lpLVItem->pszText) )
6537 /* Insert the item in the proper sort order based on the pszText
6538 member. See comments for LISTVIEW_InsertCompare() for greater detail */
6539 nItem = DPA_InsertPtr( infoPtr->hdpaItems,
6540 GETITEMCOUNT( infoPtr ) + 1, hdpaSubItems );
6541 DPA_Sort( infoPtr->hdpaItems, LISTVIEW_InsertCompare, hwnd );
6542 nItem = DPA_GetPtrIndex( infoPtr->hdpaItems, hdpaSubItems );
6544 else
6546 nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpLVItem->iItem,
6547 hdpaSubItems);
6549 if (nItem != -1)
6551 LISTVIEW_ShiftSelections(hwnd,nItem,1);
6553 /* manage item focus */
6554 if (lpLVItem->mask & LVIF_STATE)
6556 lpItem->state &= ~(LVIS_FOCUSED|LVIS_SELECTED);
6557 if (lpLVItem->stateMask & LVIS_SELECTED)
6559 LISTVIEW_SetSelection(hwnd, nItem);
6561 else if (lpLVItem->stateMask & LVIS_FOCUSED)
6563 LISTVIEW_SetItemFocus(hwnd, nItem);
6567 /* send LVN_INSERTITEM notification */
6568 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
6569 nmlv.hdr.hwndFrom = hwnd;
6570 nmlv.hdr.idFrom = lCtrlId;
6571 nmlv.hdr.code = LVN_INSERTITEM;
6572 nmlv.iItem = nItem;
6573 nmlv.lParam = lpItem->lParam;;
6574 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
6576 if ((uView == LVS_SMALLICON) || (uView == LVS_LIST))
6578 nItemWidth = LISTVIEW_CalculateWidth(hwnd, lpLVItem->iItem);
6579 if (nItemWidth > infoPtr->nItemWidth)
6581 infoPtr->nItemWidth = nItemWidth;
6585 /* align items (set position of each item) */
6586 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
6588 if (lStyle & LVS_ALIGNLEFT)
6590 LISTVIEW_AlignLeft(hwnd);
6592 else
6594 LISTVIEW_AlignTop(hwnd);
6598 LISTVIEW_UpdateScroll(hwnd);
6599 /* refresh client area */
6600 InvalidateRect(hwnd, NULL, FALSE);
6609 /* free memory if unsuccessful */
6610 if ((nItem == -1) && (lpItem != NULL))
6612 COMCTL32_Free(lpItem);
6615 return nItem;
6618 static LRESULT LISTVIEW_InsertItemW(HWND hwnd, LPLVITEMW lpLVItem) {
6619 LVITEMA lvia;
6620 LRESULT lres;
6622 memcpy(&lvia,lpLVItem,sizeof(LVITEMA));
6623 if (lvia.mask & LVIF_TEXT) {
6624 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKW)
6625 lvia.pszText = LPSTR_TEXTCALLBACKA;
6626 else
6627 lvia.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpLVItem->pszText);
6629 lres = LISTVIEW_InsertItemA(hwnd, &lvia);
6630 if (lvia.mask & LVIF_TEXT) {
6631 if (lpLVItem->pszText != LPSTR_TEXTCALLBACKW)
6632 HeapFree(GetProcessHeap(),0,lvia.pszText);
6634 return lres;
6637 /* LISTVIEW_InsertItemW */
6639 /***
6640 * DESCRIPTION:
6641 * Redraws a range of items.
6643 * PARAMETER(S):
6644 * [I] HWND : window handle
6645 * [I] INT : first item
6646 * [I] INT : last item
6648 * RETURN:
6649 * SUCCESS : TRUE
6650 * FAILURE : FALSE
6652 static LRESULT LISTVIEW_RedrawItems(HWND hwnd, INT nFirst, INT nLast)
6654 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6655 BOOL bResult = FALSE;
6656 RECT rcItem;
6658 if (nFirst <= nLast)
6660 if ((nFirst >= 0) && (nFirst < GETITEMCOUNT(infoPtr)))
6662 if ((nLast >= 0) && (nLast < GETITEMCOUNT(infoPtr)))
6664 INT i;
6665 for (i = nFirst; i <= nLast; i++)
6667 rcItem.left = LVIR_BOUNDS;
6668 LISTVIEW_GetItemRect(hwnd, i, &rcItem);
6669 InvalidateRect(hwnd, &rcItem, TRUE);
6675 return bResult;
6678 /* LISTVIEW_Scroll */
6680 /***
6681 * DESCRIPTION:
6682 * Sets the background color.
6684 * PARAMETER(S):
6685 * [I] HWND : window handle
6686 * [I] COLORREF : background color
6688 * RETURN:
6689 * SUCCESS : TRUE
6690 * FAILURE : FALSE
6692 static LRESULT LISTVIEW_SetBkColor(HWND hwnd, COLORREF clrBk)
6694 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6696 infoPtr->clrBk = clrBk;
6697 InvalidateRect(hwnd, NULL, TRUE);
6699 return TRUE;
6702 /* LISTVIEW_SetBkImage */
6704 /***
6705 * DESCRIPTION:
6706 * Sets the callback mask. This mask will be used when the parent
6707 * window stores state information (some or all).
6709 * PARAMETER(S):
6710 * [I] HWND : window handle
6711 * [I] UINT : state mask
6713 * RETURN:
6714 * SUCCESS : TRUE
6715 * FAILURE : FALSE
6717 static BOOL LISTVIEW_SetCallbackMask(HWND hwnd, UINT uMask)
6719 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6721 infoPtr->uCallbackMask = uMask;
6723 return TRUE;
6726 /***
6727 * DESCRIPTION:
6728 * Sets the attributes of a header item.
6730 * PARAMETER(S):
6731 * [I] HWND : window handle
6732 * [I] INT : column index
6733 * [I] LPLVCOLUMNA : column attributes
6735 * RETURN:
6736 * SUCCESS : TRUE
6737 * FAILURE : FALSE
6739 static LRESULT LISTVIEW_SetColumnA(HWND hwnd, INT nColumn,
6740 LPLVCOLUMNA lpColumn)
6742 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6743 BOOL bResult = FALSE;
6744 HDITEMA hdi, hdiget;
6746 if ((lpColumn != NULL) && (nColumn >= 0) &&
6747 (nColumn < Header_GetItemCount(infoPtr->hwndHeader)))
6749 /* initialize memory */
6750 ZeroMemory(&hdi, sizeof(HDITEMA));
6752 if (lpColumn->mask & LVCF_FMT)
6754 /* format member is valid */
6755 hdi.mask |= HDI_FORMAT;
6757 /* get current format first */
6758 hdiget.mask = HDI_FORMAT;
6759 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdiget))
6760 /* preserve HDF_STRING if present */
6761 hdi.fmt = hdiget.fmt & HDF_STRING;
6763 /* set text alignment (leftmost column must be left-aligned) */
6764 if (nColumn == 0)
6766 hdi.fmt |= HDF_LEFT;
6768 else
6770 if (lpColumn->fmt & LVCFMT_LEFT)
6772 hdi.fmt |= HDF_LEFT;
6774 else if (lpColumn->fmt & LVCFMT_RIGHT)
6776 hdi.fmt |= HDF_RIGHT;
6778 else if (lpColumn->fmt & LVCFMT_CENTER)
6780 hdi.fmt |= HDF_CENTER;
6784 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
6786 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
6789 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
6791 hdi.fmt |= HDF_IMAGE;
6794 if (lpColumn->fmt & LVCFMT_IMAGE)
6796 hdi.fmt |= HDF_IMAGE;
6797 hdi.iImage = I_IMAGECALLBACK;
6801 if (lpColumn->mask & LVCF_WIDTH)
6803 hdi.mask |= HDI_WIDTH;
6804 hdi.cxy = lpColumn->cx;
6807 if (lpColumn->mask & LVCF_TEXT)
6809 hdi.mask |= HDI_TEXT | HDI_FORMAT;
6810 hdi.pszText = lpColumn->pszText;
6811 hdi.cchTextMax = ((lpColumn->pszText!=NULL) && (lpColumn->pszText!=LPSTR_TEXTCALLBACKA) ? strlen(lpColumn->pszText) : 0);
6812 hdi.fmt |= HDF_STRING;
6815 if (lpColumn->mask & LVCF_IMAGE)
6817 hdi.mask |= HDI_IMAGE;
6818 hdi.iImage = lpColumn->iImage;
6821 if (lpColumn->mask & LVCF_ORDER)
6823 hdi.mask |= HDI_ORDER;
6824 hdi.iOrder = lpColumn->iOrder;
6827 /* set header item attributes */
6828 bResult = Header_SetItemA(infoPtr->hwndHeader, nColumn, &hdi);
6831 return bResult;
6834 /* LISTVIEW_SetColumnW */
6836 /***
6837 * DESCRIPTION:
6838 * Sets the column order array
6840 * PARAMETERS:
6841 * [I] HWND : window handle
6842 * [I] INT : number of elements in column order array
6843 * [I] INT : pointer to column order array
6845 * RETURN:
6846 * SUCCESS : TRUE
6847 * FAILURE : FALSE
6849 static LRESULT LISTVIEW_SetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
6851 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
6853 FIXME("iCount %d lpiArray %p\n", iCount, lpiArray);
6855 if (!lpiArray)
6856 return FALSE;
6858 return TRUE;
6862 /***
6863 * DESCRIPTION:
6864 * Sets the width of a column
6866 * PARAMETERS:
6867 * [I] HWND : window handle
6868 * [I] INT : column index
6869 * [I] INT : column width
6871 * RETURN:
6872 * SUCCESS : TRUE
6873 * FAILURE : FALSE
6875 static LRESULT LISTVIEW_SetColumnWidth(HWND hwnd, INT iCol, INT cx)
6877 LISTVIEW_INFO *infoPtr;
6878 HDITEMA hdi;
6879 LRESULT lret;
6880 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6881 UINT uView = lStyle & LVS_TYPEMASK;
6882 HDC hdc;
6883 HFONT header_font;
6884 HFONT old_font;
6885 SIZE size;
6886 CHAR text_buffer[DISP_TEXT_SIZE];
6887 INT header_item_count;
6888 INT item_index;
6889 RECT rcHeader;
6892 /* make sure we can get the listview info */
6893 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
6894 return (FALSE);
6896 if (!infoPtr->hwndHeader) /* make sure we have a header */
6897 return (FALSE);
6899 /* set column width only if in report or list mode */
6900 if ((uView != LVS_REPORT) && (uView != LVS_LIST))
6901 return (FALSE);
6903 /* take care of invalid cx values */
6904 if((uView == LVS_REPORT) && (cx < -2))
6905 cx = LVSCW_AUTOSIZE;
6906 else if (uView == LVS_LIST && (cx < 1))
6907 return FALSE;
6909 /* resize all columns if in LVS_LIST mode */
6910 if(uView == LVS_LIST) {
6911 infoPtr->nItemWidth = cx;
6912 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
6913 return TRUE;
6916 /* autosize based on listview items width */
6917 if(cx == LVSCW_AUTOSIZE)
6919 /* set the width of the header to the width of the widest item */
6920 for(item_index = 0; item_index < GETITEMCOUNT(infoPtr); item_index++)
6922 if(cx < LISTVIEW_GetLabelWidth(hwnd, item_index))
6923 cx = LISTVIEW_GetLabelWidth(hwnd, item_index);
6925 } /* autosize based on listview header width */
6926 else if(cx == LVSCW_AUTOSIZE_USEHEADER)
6928 header_item_count = Header_GetItemCount(infoPtr->hwndHeader);
6930 /* if iCol is the last column make it fill the remainder of the controls width */
6931 if(iCol == (header_item_count - 1)) {
6932 /* get the width of every item except the current one */
6933 hdi.mask = HDI_WIDTH;
6934 cx = 0;
6936 for(item_index = 0; item_index < (header_item_count - 1); item_index++) {
6937 Header_GetItemA(infoPtr->hwndHeader, item_index, (LPARAM)(&hdi));
6938 cx+=hdi.cxy;
6941 /* retrieve the layout of the header */
6942 GetWindowRect(infoPtr->hwndHeader, &rcHeader);
6944 cx = (rcHeader.right - rcHeader.left) - cx;
6946 else
6948 /* retrieve header font */
6949 header_font = SendMessageA(infoPtr->hwndHeader, WM_GETFONT, 0L, 0L);
6951 /* retrieve header text */
6952 hdi.mask = HDI_TEXT;
6953 hdi.cchTextMax = sizeof(text_buffer);
6954 hdi.pszText = text_buffer;
6956 Header_GetItemA(infoPtr->hwndHeader, iCol, (LPARAM)(&hdi));
6958 /* determine the width of the text in the header */
6959 hdc = GetDC(hwnd);
6960 old_font = SelectObject(hdc, header_font); /* select the font into hdc */
6962 GetTextExtentPoint32A(hdc, text_buffer, strlen(text_buffer), &size);
6964 SelectObject(hdc, old_font); /* restore the old font */
6965 ReleaseDC(hwnd, hdc);
6967 /* set the width of this column to the width of the text */
6968 cx = size.cx;
6972 /* call header to update the column change */
6973 hdi.mask = HDI_WIDTH;
6975 hdi.cxy = cx;
6976 lret = Header_SetItemA(infoPtr->hwndHeader, (WPARAM)iCol, (LPARAM)&hdi);
6978 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
6980 return lret;
6983 /***
6984 * DESCRIPTION:
6985 * Sets the extended listview style.
6987 * PARAMETERS:
6988 * [I] HWND : window handle
6989 * [I] DWORD : mask
6990 * [I] DWORD : style
6992 * RETURN:
6993 * SUCCESS : previous style
6994 * FAILURE : 0
6996 static LRESULT LISTVIEW_SetExtendedListViewStyle(HWND hwnd, DWORD dwMask, DWORD dwStyle)
6998 LISTVIEW_INFO *infoPtr;
6999 DWORD dwOldStyle;
7001 /* make sure we can get the listview info */
7002 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
7003 return (0);
7005 /* store previous style */
7006 dwOldStyle = infoPtr->dwExStyle;
7008 /* set new style */
7009 if (dwMask)
7010 infoPtr->dwExStyle = (dwOldStyle & ~dwMask) | (dwStyle & dwMask);
7011 else
7012 infoPtr->dwExStyle = dwStyle;
7014 return (dwOldStyle);
7017 /* LISTVIEW_SetHotCursor */
7019 /***
7020 * DESCRIPTION:
7021 * Sets the hot item index.
7023 * PARAMETERS:
7024 * [I] HWND : window handle
7025 * [I] INT : index
7027 * RETURN:
7028 * SUCCESS : previous hot item index
7029 * FAILURE : -1 (no hot item)
7031 static LRESULT LISTVIEW_SetHotItem(HWND hwnd, INT iIndex)
7033 LISTVIEW_INFO *infoPtr;
7034 INT iOldIndex;
7036 /* make sure we can get the listview info */
7037 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
7038 return (-1);
7040 /* store previous index */
7041 iOldIndex = infoPtr->nHotItem;
7043 /* set new style */
7044 infoPtr->nHotItem = iIndex;
7046 return (iOldIndex);
7049 /***
7050 * DESCRIPTION:
7051 * Sets the amount of time the cursor must hover over an item before it is selected.
7053 * PARAMETER(S):
7054 * [I] HWND : window handle
7055 * [I] DWORD : dwHoverTime, if -1 the hover time is set to the default
7057 * RETURN:
7058 * Returns the previous hover time
7060 static LRESULT LISTVIEW_SetHoverTime(HWND hwnd, DWORD dwHoverTime)
7062 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7063 DWORD oldHoverTime = infoPtr->dwHoverTime;
7065 infoPtr->dwHoverTime = dwHoverTime;
7067 return oldHoverTime;
7070 /* LISTVIEW_SetIconSpacing */
7072 /***
7073 * DESCRIPTION:
7074 * Sets image lists.
7076 * PARAMETER(S):
7077 * [I] HWND : window handle
7078 * [I] INT : image list type
7079 * [I] HIMAGELIST : image list handle
7081 * RETURN:
7082 * SUCCESS : old image list
7083 * FAILURE : NULL
7085 static LRESULT LISTVIEW_SetImageList(HWND hwnd, INT nType, HIMAGELIST himl)
7087 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7088 HIMAGELIST himlOld = 0;
7089 INT oldHeight;
7091 switch (nType)
7093 case LVSIL_NORMAL:
7094 himlOld = infoPtr->himlNormal;
7095 infoPtr->himlNormal = himl;
7096 break;
7098 case LVSIL_SMALL:
7099 himlOld = infoPtr->himlSmall;
7100 infoPtr->himlSmall = himl;
7101 break;
7103 case LVSIL_STATE:
7104 himlOld = infoPtr->himlState;
7105 infoPtr->himlState = himl;
7106 ImageList_SetBkColor(infoPtr->himlState, CLR_NONE);
7107 break;
7110 oldHeight = infoPtr->nItemHeight;
7111 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7112 if (infoPtr->nItemHeight != oldHeight)
7113 LISTVIEW_UpdateScroll(hwnd);
7115 return (LRESULT)himlOld;
7119 /***
7120 * DESCRIPTION:
7121 * Sets the attributes of an item.
7123 * PARAMETER(S):
7124 * [I] HWND : window handle
7125 * [I] LPLVITEM : item information
7127 * RETURN:
7128 * SUCCESS : TRUE
7129 * FAILURE : FALSE
7131 static LRESULT LISTVIEW_SetItemA(HWND hwnd, LPLVITEMA lpLVItem)
7133 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7134 BOOL bResult = FALSE;
7136 if (lpLVItem != NULL)
7138 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
7140 if (lpLVItem->iSubItem == 0)
7142 bResult = LISTVIEW_SetItem(hwnd, lpLVItem);
7144 else
7146 bResult = LISTVIEW_SetSubItem(hwnd, lpLVItem);
7152 return bResult;
7155 /* LISTVIEW_SetItemW */
7157 /***
7158 * DESCRIPTION:
7159 * Preallocates memory (does *not* set the actual count of items !)
7161 * PARAMETER(S):
7162 * [I] HWND : window handle
7163 * [I] INT : item count (projected number of items to allocate)
7164 * [I] DWORD : update flags
7166 * RETURN:
7167 * SUCCESS : TRUE
7168 * FAILURE : FALSE
7170 static BOOL LISTVIEW_SetItemCount(HWND hwnd, INT nItems, DWORD dwFlags)
7172 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
7174 if (GetWindowLongA(hwnd, GWL_STYLE) & LVS_OWNERDATA)
7176 int precount,topvisible;
7177 TRACE("LVS_OWNERDATA is set!\n");
7180 * Internally remove all the selections.
7184 LISTVIEW_SELECTION *selection;
7185 selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,0);
7186 if (selection)
7187 LISTVIEW_RemoveSelectionRange(hwnd,selection->lower,
7188 selection->upper);
7190 while (infoPtr->hdpaSelectionRanges->nItemCount>0);
7192 precount = infoPtr->hdpaItems->nItemCount;
7193 topvisible = ListView_GetTopIndex(hwnd) +
7194 LISTVIEW_GetCountPerColumn(hwnd) + 1;
7196 infoPtr->hdpaItems->nItemCount = nItems;
7198 LISTVIEW_UpdateSize(hwnd);
7199 LISTVIEW_UpdateScroll(hwnd);
7200 if (min(precount,infoPtr->hdpaItems->nItemCount)<topvisible)
7201 InvalidateRect(hwnd, NULL, TRUE);
7203 else
7205 FIXME("setitemcount not done for non-ownerdata\n");
7208 return TRUE;
7211 /***
7212 * DESCRIPTION:
7213 * Sets the position of an item.
7215 * PARAMETER(S):
7216 * [I] HWND : window handle
7217 * [I] INT : item index
7218 * [I] LONG : x coordinate
7219 * [I] LONG : y coordinate
7221 * RETURN:
7222 * SUCCESS : TRUE
7223 * FAILURE : FALSE
7225 static BOOL LISTVIEW_SetItemPosition(HWND hwnd, INT nItem,
7226 LONG nPosX, LONG nPosY)
7228 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
7229 UINT lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7230 UINT uView = lStyle & LVS_TYPEMASK;
7231 LISTVIEW_ITEM *lpItem;
7232 HDPA hdpaSubItems;
7233 BOOL bResult = FALSE;
7235 TRACE("(hwnd=%x,nItem=%d,X=%ld,Y=%ld)\n", hwnd, nItem, nPosX, nPosY);
7237 if (lStyle & LVS_OWNERDATA)
7238 return FALSE;
7240 if ((nItem >= 0) || (nItem < GETITEMCOUNT(infoPtr)))
7242 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
7244 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
7245 if (hdpaSubItems != NULL)
7247 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
7248 if (lpItem != NULL)
7250 bResult = TRUE;
7251 lpItem->ptPosition.x = nPosX;
7252 lpItem->ptPosition.y = nPosY;
7258 return bResult;
7261 /***
7262 * DESCRIPTION:
7263 * Sets the state of one or many items.
7265 * PARAMETER(S):
7266 * [I] HWND : window handle
7267 * [I]INT : item index
7268 * [I] LPLVITEM : item or subitem info
7270 * RETURN:
7271 * SUCCESS : TRUE
7272 * FAILURE : FALSE
7274 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
7276 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7277 BOOL bResult = FALSE;
7278 LVITEMA lvItem;
7279 INT i;
7281 if (nItem == -1)
7283 bResult = TRUE;
7284 ZeroMemory(&lvItem, sizeof(LVITEMA));
7285 lvItem.mask = LVIF_STATE;
7286 lvItem.state = lpLVItem->state;
7287 lvItem.stateMask = lpLVItem->stateMask ;
7289 /* apply to all items */
7290 for (i = 0; i< GETITEMCOUNT(infoPtr); i++)
7292 lvItem.iItem = i;
7293 if (ListView_SetItemA(hwnd, &lvItem) == FALSE)
7295 bResult = FALSE;
7299 else
7301 ZeroMemory(&lvItem, sizeof(LVITEMA));
7302 lvItem.mask = LVIF_STATE;
7303 lvItem.state = lpLVItem->state;
7304 lvItem.stateMask = lpLVItem->stateMask;
7305 lvItem.iItem = nItem;
7306 bResult = ListView_SetItemA(hwnd, &lvItem);
7309 return bResult;
7312 /***
7313 * DESCRIPTION:
7314 * Sets the text of an item or subitem.
7316 * PARAMETER(S):
7317 * [I] HWND : window handle
7318 * [I] INT : item index
7319 * [I] LPLVITEMA : item or subitem info
7321 * RETURN:
7322 * SUCCESS : TRUE
7323 * FAILURE : FALSE
7325 static BOOL LISTVIEW_SetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
7327 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7328 BOOL bResult = FALSE;
7329 LVITEMA lvItem;
7331 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
7333 ZeroMemory(&lvItem, sizeof(LVITEMA));
7334 lvItem.mask = LVIF_TEXT;
7335 lvItem.pszText = lpLVItem->pszText;
7336 lvItem.iItem = nItem;
7337 lvItem.iSubItem = lpLVItem->iSubItem;
7338 bResult = ListView_SetItemA(hwnd, &lvItem);
7341 return bResult;
7344 /* LISTVIEW_SetItemTextW */
7346 /***
7347 * DESCRIPTION:
7348 * Set item index that marks the start of a multiple selection.
7350 * PARAMETER(S):
7351 * [I] HWND : window handle
7352 * [I] INT : index
7354 * RETURN:
7355 * Index number or -1 if there is no selection mark.
7357 static LRESULT LISTVIEW_SetSelectionMark(HWND hwnd, INT nIndex)
7359 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7360 INT nOldIndex = infoPtr->nSelectionMark;
7362 infoPtr->nSelectionMark = nIndex;
7364 return nOldIndex;
7367 /***
7368 * DESCRIPTION:
7369 * Sets the text background color.
7371 * PARAMETER(S):
7372 * [I] HWND : window handle
7373 * [I] COLORREF : text background color
7375 * RETURN:
7376 * SUCCESS : TRUE
7377 * FAILURE : FALSE
7379 static LRESULT LISTVIEW_SetTextBkColor(HWND hwnd, COLORREF clrTextBk)
7381 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7383 infoPtr->clrTextBk = clrTextBk;
7384 InvalidateRect(hwnd, NULL, TRUE);
7386 return TRUE;
7389 /***
7390 * DESCRIPTION:
7391 * Sets the text foreground color.
7393 * PARAMETER(S):
7394 * [I] HWND : window handle
7395 * [I] COLORREF : text color
7397 * RETURN:
7398 * SUCCESS : TRUE
7399 * FAILURE : FALSE
7401 static LRESULT LISTVIEW_SetTextColor (HWND hwnd, COLORREF clrText)
7403 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7405 infoPtr->clrText = clrText;
7406 InvalidateRect(hwnd, NULL, TRUE);
7408 return TRUE;
7411 /* LISTVIEW_SetToolTips */
7412 /* LISTVIEW_SetUnicodeFormat */
7413 /* LISTVIEW_SetWorkAreas */
7415 /***
7416 * DESCRIPTION:
7417 * Callback internally used by LISTVIEW_SortItems()
7419 * PARAMETER(S):
7420 * [I] LPVOID : first LISTVIEW_ITEM to compare
7421 * [I] LPVOID : second LISTVIEW_ITEM to compare
7422 * [I] LPARAM : HWND of control
7424 * RETURN:
7425 * if first comes before second : negative
7426 * if first comes after second : positive
7427 * if first and second are equivalent : zero
7429 static INT WINAPI LISTVIEW_CallBackCompare(
7430 LPVOID first,
7431 LPVOID second,
7432 LPARAM lParam)
7434 /* Forward the call to the client defined callback */
7435 INT rv;
7436 HWND hwnd = (HWND)lParam;
7437 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7438 HDPA hdpa_first = (HDPA) first;
7439 HDPA hdpa_second = (HDPA) second;
7440 LISTVIEW_ITEM* lv_first = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_first, 0 );
7441 LISTVIEW_ITEM* lv_second = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_second, 0 );
7443 rv = (infoPtr->pfnCompare)( lv_first->lParam , lv_second->lParam, infoPtr->lParamSort );
7445 return rv;
7448 /***
7449 * DESCRIPTION:
7450 * Sorts the listview items.
7452 * PARAMETER(S):
7453 * [I] HWND : window handle
7454 * [I] WPARAM : application-defined value
7455 * [I] LPARAM : pointer to comparision callback
7457 * RETURN:
7458 * SUCCESS : TRUE
7459 * FAILURE : FALSE
7461 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam)
7463 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7464 int nCount;
7465 UINT lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7467 if (lStyle & LVS_OWNERDATA)
7468 return FALSE;
7470 if (!infoPtr || !infoPtr->hdpaItems)
7471 return FALSE;
7473 nCount = GETITEMCOUNT(infoPtr);
7474 /* if there are 0 or 1 items, there is no need to sort */
7475 if (nCount > 1)
7477 infoPtr->pfnCompare = (PFNLVCOMPARE)lParam;
7478 infoPtr->lParamSort = (LPARAM)wParam;
7480 DPA_Sort(infoPtr->hdpaItems, LISTVIEW_CallBackCompare, hwnd);
7483 /* align the items */
7484 LISTVIEW_AlignTop(hwnd);
7486 /* refresh the display */
7487 InvalidateRect(hwnd, NULL, TRUE);
7489 return TRUE;
7492 /* LISTVIEW_SubItemHitTest */
7494 /***
7495 * DESCRIPTION:
7496 * Updates an items or rearranges the listview control.
7498 * PARAMETER(S):
7499 * [I] HWND : window handle
7500 * [I] INT : item index
7502 * RETURN:
7503 * SUCCESS : TRUE
7504 * FAILURE : FALSE
7506 static LRESULT LISTVIEW_Update(HWND hwnd, INT nItem)
7508 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7509 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7510 BOOL bResult = FALSE;
7511 RECT rc;
7513 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
7515 bResult = TRUE;
7517 /* rearrange with default alignment style */
7518 if ((lStyle & LVS_AUTOARRANGE) && (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
7519 ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON)))
7521 ListView_Arrange(hwnd, 0);
7523 else
7525 /* get item bounding rectangle */
7526 rc.left = LVIR_BOUNDS;
7527 ListView_GetItemRect(hwnd, nItem, &rc, rc.left);
7528 InvalidateRect(hwnd, &rc, TRUE);
7532 return bResult;
7535 /***
7536 * DESCRIPTION:
7537 * Creates the listview control.
7539 * PARAMETER(S):
7540 * [I] HWND : window handle
7542 * RETURN:
7543 * Zero
7545 static LRESULT LISTVIEW_Create(HWND hwnd, WPARAM wParam, LPARAM lParam)
7547 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7548 LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam;
7549 UINT uView = lpcs->style & LVS_TYPEMASK;
7550 LOGFONTA logFont;
7552 /* initialize info pointer */
7553 ZeroMemory(infoPtr, sizeof(LISTVIEW_INFO));
7555 /* determine the type of structures to use */
7556 infoPtr->notifyFormat = SendMessageA(GetParent(hwnd), WM_NOTIFYFORMAT,
7557 (WPARAM)hwnd, (LPARAM)NF_QUERY);
7558 if (infoPtr->notifyFormat != NFR_ANSI)
7560 FIXME("ANSI notify format is NOT used\n");
7563 /* initialize color information */
7564 infoPtr->clrBk = GetSysColor(COLOR_WINDOW);
7565 infoPtr->clrText = GetSysColor(COLOR_WINDOWTEXT);
7566 infoPtr->clrTextBk = CLR_DEFAULT;
7568 /* set default values */
7569 infoPtr->uCallbackMask = 0;
7570 infoPtr->nFocusedItem = -1;
7571 infoPtr->nSelectionMark = -1;
7572 infoPtr->nHotItem = -1;
7573 infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING);
7574 infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING);
7575 ZeroMemory(&infoPtr->rcList, sizeof(RECT));
7576 infoPtr->hwndEdit = 0;
7577 infoPtr->pedititem = NULL;
7578 infoPtr->nEditLabelItem = -1;
7580 /* get default font (icon title) */
7581 SystemParametersInfoA(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
7582 infoPtr->hDefaultFont = CreateFontIndirectA(&logFont);
7583 infoPtr->hFont = infoPtr->hDefaultFont;
7585 /* create header */
7586 infoPtr->hwndHeader = CreateWindowA(WC_HEADERA, (LPCSTR)NULL,
7587 WS_CHILD | HDS_HORZ | HDS_BUTTONS,
7588 0, 0, 0, 0, hwnd, (HMENU)0,
7589 lpcs->hInstance, NULL);
7591 /* set header font */
7592 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont,
7593 (LPARAM)TRUE);
7595 if (uView == LVS_ICON)
7597 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
7598 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
7600 else if (uView == LVS_REPORT)
7602 if (!(LVS_NOCOLUMNHEADER & lpcs->style))
7604 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
7606 else
7608 /* set HDS_HIDDEN flag to hide the header bar */
7609 SetWindowLongA(infoPtr->hwndHeader, GWL_STYLE,
7610 GetWindowLongA(infoPtr->hwndHeader, GWL_STYLE) | HDS_HIDDEN);
7614 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7615 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7617 else
7619 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7620 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7623 /* display unsupported listview window styles */
7624 LISTVIEW_UnsupportedStyles(lpcs->style);
7626 /* allocate memory for the data structure */
7627 infoPtr->hdpaItems = DPA_Create(10);
7629 /* allocate memory for the selection ranges */
7630 infoPtr->hdpaSelectionRanges = DPA_Create(10);
7632 /* initialize size of items */
7633 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7634 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7636 /* initialize the hover time to -1(indicating the default system hover time) */
7637 infoPtr->dwHoverTime = -1;
7639 return 0;
7642 /***
7643 * DESCRIPTION:
7644 * Erases the background of the listview control.
7646 * PARAMETER(S):
7647 * [I] HWND : window handle
7648 * [I] WPARAM : device context handle
7649 * [I] LPARAM : not used
7651 * RETURN:
7652 * SUCCESS : TRUE
7653 * FAILURE : FALSE
7655 static LRESULT LISTVIEW_EraseBackground(HWND hwnd, WPARAM wParam,
7656 LPARAM lParam)
7658 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7659 BOOL bResult;
7661 if (infoPtr->clrBk == CLR_NONE)
7663 bResult = SendMessageA(GetParent(hwnd), WM_ERASEBKGND, wParam, lParam);
7665 else
7667 RECT rc;
7668 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
7669 GetClientRect(hwnd, &rc);
7670 FillRect((HDC)wParam, &rc, hBrush);
7671 DeleteObject(hBrush);
7672 bResult = TRUE;
7675 return bResult;
7679 static void LISTVIEW_FillBackground(HWND hwnd, HDC hdc, LPRECT rc)
7681 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7683 if (infoPtr->clrBk != CLR_NONE)
7685 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
7686 FillRect(hdc, rc, hBrush);
7687 DeleteObject(hBrush);
7691 /***
7692 * DESCRIPTION:
7693 * Retrieves the listview control font.
7695 * PARAMETER(S):
7696 * [I] HWND : window handle
7698 * RETURN:
7699 * Font handle.
7701 static LRESULT LISTVIEW_GetFont(HWND hwnd)
7703 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7705 return infoPtr->hFont;
7708 /***
7709 * DESCRIPTION:
7710 * Performs vertical scrolling.
7712 * PARAMETER(S):
7713 * [I] HWND : window handle
7714 * [I] INT : scroll code
7715 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
7716 * or SB_THUMBTRACK.
7717 * [I] HWND : scrollbar control window handle
7719 * RETURN:
7720 * Zero
7722 static LRESULT LISTVIEW_VScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
7723 HWND hScrollWnd)
7725 SCROLLINFO scrollInfo;
7727 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7728 SendMessageA(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
7730 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
7731 scrollInfo.cbSize = sizeof(SCROLLINFO);
7732 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
7734 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
7736 INT nOldScrollPos = scrollInfo.nPos;
7737 switch (nScrollCode)
7739 case SB_LINEUP:
7740 if (scrollInfo.nPos > scrollInfo.nMin)
7742 scrollInfo.nPos--;
7744 break;
7746 case SB_LINEDOWN:
7747 if (scrollInfo.nPos < scrollInfo.nMax)
7749 scrollInfo.nPos++;
7751 break;
7753 case SB_PAGEUP:
7754 if (scrollInfo.nPos > scrollInfo.nMin)
7756 if (scrollInfo.nPos >= scrollInfo.nPage)
7758 scrollInfo.nPos -= scrollInfo.nPage;
7760 else
7762 scrollInfo.nPos = scrollInfo.nMin;
7765 break;
7767 case SB_PAGEDOWN:
7768 if (scrollInfo.nPos < scrollInfo.nMax)
7770 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
7772 scrollInfo.nPos += scrollInfo.nPage;
7774 else
7776 scrollInfo.nPos = scrollInfo.nMax;
7779 break;
7781 case SB_THUMBTRACK:
7782 scrollInfo.nPos = nCurrentPos;
7783 if (scrollInfo.nPos > scrollInfo.nMax)
7784 scrollInfo.nPos=scrollInfo.nMax;
7786 if (scrollInfo.nPos < scrollInfo.nMin)
7787 scrollInfo.nPos=scrollInfo.nMin;
7789 break;
7792 if (nOldScrollPos != scrollInfo.nPos)
7794 scrollInfo.fMask = SIF_POS;
7795 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
7796 InvalidateRect(hwnd, NULL, TRUE);
7800 return 0;
7803 /***
7804 * DESCRIPTION:
7805 * Performs horizontal scrolling.
7807 * PARAMETER(S):
7808 * [I] HWND : window handle
7809 * [I] INT : scroll code
7810 * [I] SHORT : current scroll position if scroll code is SB_THUMBPOSITION
7811 * or SB_THUMBTRACK.
7812 * [I] HWND : scrollbar control window handle
7814 * RETURN:
7815 * Zero
7817 static LRESULT LISTVIEW_HScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
7818 HWND hScrollWnd)
7820 SCROLLINFO scrollInfo;
7822 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7823 SendMessageA(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
7826 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
7827 scrollInfo.cbSize = sizeof(SCROLLINFO);
7828 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
7830 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
7832 INT nOldScrollPos = scrollInfo.nPos;
7834 switch (nScrollCode)
7836 case SB_LINELEFT:
7837 if (scrollInfo.nPos > scrollInfo.nMin)
7839 scrollInfo.nPos--;
7841 break;
7843 case SB_LINERIGHT:
7844 if (scrollInfo.nPos < scrollInfo.nMax)
7846 scrollInfo.nPos++;
7848 break;
7850 case SB_PAGELEFT:
7851 if (scrollInfo.nPos > scrollInfo.nMin)
7853 if (scrollInfo.nPos >= scrollInfo.nPage)
7855 scrollInfo.nPos -= scrollInfo.nPage;
7857 else
7859 scrollInfo.nPos = scrollInfo.nMin;
7862 break;
7864 case SB_PAGERIGHT:
7865 if (scrollInfo.nPos < scrollInfo.nMax)
7867 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
7869 scrollInfo.nPos += scrollInfo.nPage;
7871 else
7873 scrollInfo.nPos = scrollInfo.nMax;
7876 break;
7878 case SB_THUMBTRACK:
7879 scrollInfo.nPos = nCurrentPos;
7881 if (scrollInfo.nPos > scrollInfo.nMax)
7882 scrollInfo.nPos=scrollInfo.nMax;
7884 if (scrollInfo.nPos < scrollInfo.nMin)
7885 scrollInfo.nPos=scrollInfo.nMin;
7886 break;
7889 if (nOldScrollPos != scrollInfo.nPos)
7891 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
7892 scrollInfo.fMask = SIF_POS;
7893 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
7894 if(uView == LVS_REPORT)
7896 scrollInfo.fMask = SIF_POS;
7897 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
7898 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
7900 InvalidateRect(hwnd, NULL, TRUE);
7904 return 0;
7907 static LRESULT LISTVIEW_MouseWheel(HWND hwnd, INT wheelDelta)
7909 INT gcWheelDelta = 0;
7910 UINT pulScrollLines = 3;
7911 SCROLLINFO scrollInfo;
7913 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
7915 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
7916 gcWheelDelta -= wheelDelta;
7918 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
7919 scrollInfo.cbSize = sizeof(SCROLLINFO);
7920 scrollInfo.fMask = SIF_POS | SIF_RANGE;
7922 switch(uView)
7924 case LVS_ICON:
7925 case LVS_SMALLICON:
7927 * listview should be scrolled by a multiple of 37 dependently on its dimension or its visible item number
7928 * should be fixed in the future.
7930 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
7931 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + (gcWheelDelta < 0) ? 37 : -37, 0);
7932 break;
7934 case LVS_REPORT:
7935 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
7937 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
7939 int cLineScroll = min(LISTVIEW_GetCountPerColumn(hwnd), pulScrollLines);
7940 cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
7941 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + cLineScroll, 0);
7944 break;
7946 case LVS_LIST:
7947 LISTVIEW_HScroll(hwnd, (gcWheelDelta < 0) ? SB_LINELEFT : SB_LINERIGHT, 0, 0);
7948 break;
7950 return 0;
7953 /***
7954 * DESCRIPTION:
7955 * ???
7957 * PARAMETER(S):
7958 * [I] HWND : window handle
7959 * [I] INT : virtual key
7960 * [I] LONG : key data
7962 * RETURN:
7963 * Zero
7965 static LRESULT LISTVIEW_KeyDown(HWND hwnd, INT nVirtualKey, LONG lKeyData)
7967 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7968 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
7969 HWND hwndParent = GetParent(hwnd);
7970 NMLVKEYDOWN nmKeyDown;
7971 NMHDR nmh;
7972 INT nItem = -1;
7973 BOOL bRedraw = FALSE;
7974 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7975 UINT uView = lStyle & LVS_TYPEMASK;
7977 /* send LVN_KEYDOWN notification */
7978 ZeroMemory(&nmKeyDown, sizeof(NMLVKEYDOWN));
7979 nmKeyDown.hdr.hwndFrom = hwnd;
7980 nmKeyDown.hdr.idFrom = nCtrlId;
7981 nmKeyDown.hdr.code = LVN_KEYDOWN;
7982 nmKeyDown.wVKey = nVirtualKey;
7983 nmKeyDown.flags = 0;
7984 SendMessageA(hwndParent, WM_NOTIFY, (WPARAM)nCtrlId, (LPARAM)&nmKeyDown);
7986 /* initialize */
7987 nmh.hwndFrom = hwnd;
7988 nmh.idFrom = nCtrlId;
7990 switch (nVirtualKey)
7992 case VK_RETURN:
7993 if ((GETITEMCOUNT(infoPtr) > 0) && (infoPtr->nFocusedItem != -1))
7995 /* send NM_RETURN notification */
7996 nmh.code = NM_RETURN;
7997 ListView_Notify(hwndParent, nCtrlId, &nmh);
7999 /* send LVN_ITEMACTIVATE notification */
8000 nmh.code = LVN_ITEMACTIVATE;
8001 ListView_Notify(hwndParent, nCtrlId, &nmh);
8003 break;
8005 case VK_HOME:
8006 if (GETITEMCOUNT(infoPtr) > 0)
8008 nItem = 0;
8010 break;
8012 case VK_END:
8013 if (GETITEMCOUNT(infoPtr) > 0)
8015 nItem = GETITEMCOUNT(infoPtr) - 1;
8017 break;
8019 case VK_LEFT:
8020 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TOLEFT);
8021 break;
8023 case VK_UP:
8024 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_ABOVE);
8025 break;
8027 case VK_RIGHT:
8028 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TORIGHT);
8029 break;
8031 case VK_DOWN:
8032 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_BELOW);
8033 break;
8035 case VK_PRIOR:
8036 if (uView == LVS_REPORT)
8038 nItem = infoPtr->nFocusedItem - LISTVIEW_GetCountPerColumn(hwnd);
8040 else
8042 nItem = infoPtr->nFocusedItem - LISTVIEW_GetCountPerColumn(hwnd)
8043 * LISTVIEW_GetCountPerRow(hwnd);
8045 if(nItem < 0) nItem = 0;
8046 break;
8048 case VK_NEXT:
8049 if (uView == LVS_REPORT)
8051 nItem = infoPtr->nFocusedItem + LISTVIEW_GetCountPerColumn(hwnd);
8053 else
8055 nItem = infoPtr->nFocusedItem + LISTVIEW_GetCountPerColumn(hwnd)
8056 * LISTVIEW_GetCountPerRow(hwnd);
8058 if(nItem >= GETITEMCOUNT(infoPtr)) nItem = GETITEMCOUNT(infoPtr) - 1;
8059 break;
8062 if ((nItem != -1) && (nItem != infoPtr->nFocusedItem))
8064 bRedraw = LISTVIEW_KeySelection(hwnd, nItem);
8065 if (bRedraw != FALSE)
8067 /* refresh client area */
8068 UpdateWindow(hwnd);
8072 return 0;
8075 /***
8076 * DESCRIPTION:
8077 * Kills the focus.
8079 * PARAMETER(S):
8080 * [I] HWND : window handle
8082 * RETURN:
8083 * Zero
8085 static LRESULT LISTVIEW_KillFocus(HWND hwnd)
8087 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
8088 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8089 NMHDR nmh;
8090 INT i,nTop,nBottom;
8091 RECT rcItem;
8092 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8093 UINT uView = lStyle & LVS_TYPEMASK;
8095 TRACE("(hwnd=%x)\n", hwnd);
8097 /* send NM_KILLFOCUS notification */
8098 nmh.hwndFrom = hwnd;
8099 nmh.idFrom = nCtrlId;
8100 nmh.code = NM_KILLFOCUS;
8101 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8103 /* set window focus flag */
8104 infoPtr->bFocus = FALSE;
8106 /* NEED drawing optimization ; redraw the selected items */
8107 if (uView & LVS_REPORT)
8109 nTop = LISTVIEW_GetTopIndex(hwnd);
8110 nBottom = nTop +
8111 LISTVIEW_GetCountPerColumn(hwnd) + 1;
8113 else
8115 nTop = 0;
8116 nBottom = GETITEMCOUNT(infoPtr);
8118 for (i = nTop; i<nBottom; i++)
8120 if (LISTVIEW_IsSelected(hwnd,i))
8122 rcItem.left = LVIR_BOUNDS;
8123 LISTVIEW_GetItemRect(hwnd, i, &rcItem);
8124 InvalidateRect(hwnd, &rcItem, FALSE);
8128 return 0;
8131 /***
8132 * DESCRIPTION:
8133 * Processes double click messages (left mouse button).
8135 * PARAMETER(S):
8136 * [I] HWND : window handle
8137 * [I] WORD : key flag
8138 * [I] WORD : x coordinate
8139 * [I] WORD : y coordinate
8141 * RETURN:
8142 * Zero
8144 static LRESULT LISTVIEW_LButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
8145 WORD wPosY)
8147 LONG nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8148 LVHITTESTINFO htInfo;
8149 NMHDR nmh;
8150 NMLISTVIEW nmlv;
8151 INT ret;
8153 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8155 htInfo.pt.x = wPosX;
8156 htInfo.pt.y = wPosY;
8158 /* send NM_DBLCLK notification */
8159 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
8160 nmlv.hdr.hwndFrom = hwnd;
8161 nmlv.hdr.idFrom = nCtrlId;
8162 nmlv.hdr.code = NM_DBLCLK;
8163 ret = LISTVIEW_HitTestItem(hwnd, &htInfo, TRUE);
8164 if (ret != -1)
8166 nmlv.iItem = htInfo.iItem;
8167 nmlv.iSubItem = htInfo.iSubItem;
8169 else
8171 nmlv.iItem = -1;
8172 nmlv.iSubItem = 0;
8174 nmlv.ptAction.x = wPosX;
8175 nmlv.ptAction.y = wPosY;
8176 ListView_LVNotify(GetParent(hwnd), nCtrlId, &nmlv);
8179 /* To send the LVN_ITEMACTIVATE, it must be on an Item */
8180 if(ret != -1)
8182 /* send LVN_ITEMACTIVATE notification */
8183 nmh.hwndFrom = hwnd;
8184 nmh.idFrom = nCtrlId;
8185 nmh.code = LVN_ITEMACTIVATE;
8186 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8189 return 0;
8192 /***
8193 * DESCRIPTION:
8194 * Processes mouse down messages (left mouse button).
8196 * PARAMETER(S):
8197 * [I] HWND : window handle
8198 * [I] WORD : key flag
8199 * [I] WORD : x coordinate
8200 * [I] WORD : y coordinate
8202 * RETURN:
8203 * Zero
8205 static LRESULT LISTVIEW_LButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
8206 WORD wPosY)
8208 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8209 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8210 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8211 static BOOL bGroupSelect = TRUE;
8212 POINT ptPosition;
8213 NMHDR nmh;
8214 INT nItem;
8216 TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd, wKey, wPosX,
8217 wPosY);
8219 /* send NM_RELEASEDCAPTURE notification */
8220 nmh.hwndFrom = hwnd;
8221 nmh.idFrom = nCtrlId;
8222 nmh.code = NM_RELEASEDCAPTURE;
8223 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8225 if (infoPtr->bFocus == FALSE)
8227 SetFocus(hwnd);
8230 /* set left button down flag */
8231 infoPtr->bLButtonDown = TRUE;
8233 ptPosition.x = wPosX;
8234 ptPosition.y = wPosY;
8235 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
8236 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
8238 if (lStyle & LVS_SINGLESEL)
8240 if ((ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
8241 && infoPtr->nEditLabelItem == -1)
8243 infoPtr->nEditLabelItem = nItem;
8245 else
8247 LISTVIEW_SetSelection(hwnd, nItem);
8250 else
8252 if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
8254 if (bGroupSelect != FALSE)
8256 LISTVIEW_AddGroupSelection(hwnd, nItem);
8258 else
8260 LISTVIEW_AddSelection(hwnd, nItem);
8263 else if (wKey & MK_CONTROL)
8265 bGroupSelect = LISTVIEW_ToggleSelection(hwnd, nItem);
8267 else if (wKey & MK_SHIFT)
8269 LISTVIEW_SetGroupSelection(hwnd, nItem);
8271 else
8273 BOOL was_selected =
8274 (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED);
8276 /* set selection (clears other pre-existing selections) */
8277 LISTVIEW_SetSelection(hwnd, nItem);
8279 if (was_selected && infoPtr->nEditLabelItem == -1)
8281 infoPtr->nEditLabelItem = nItem;
8286 else
8288 /* remove all selections */
8289 LISTVIEW_RemoveAllSelections(hwnd);
8292 /* redraw if we could have possibly selected something */
8293 if(!GETITEMCOUNT(infoPtr)) InvalidateRect(hwnd, NULL, TRUE);
8295 return 0;
8298 /***
8299 * DESCRIPTION:
8300 * Processes mouse up messages (left mouse button).
8302 * PARAMETER(S):
8303 * [I] HWND : window handle
8304 * [I] WORD : key flag
8305 * [I] WORD : x coordinate
8306 * [I] WORD : y coordinate
8308 * RETURN:
8309 * Zero
8311 static LRESULT LISTVIEW_LButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
8312 WORD wPosY)
8314 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8316 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8318 if (infoPtr->bLButtonDown != FALSE)
8320 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8321 NMLISTVIEW nmlv;
8322 LVHITTESTINFO lvHitTestInfo;
8323 INT ret;
8325 lvHitTestInfo.pt.x = wPosX;
8326 lvHitTestInfo.pt.y = wPosY;
8328 /* send NM_CLICK notification */
8329 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
8330 nmlv.hdr.hwndFrom = hwnd;
8331 nmlv.hdr.idFrom = nCtrlId;
8332 nmlv.hdr.code = NM_CLICK;
8333 ret = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo, TRUE);
8334 if (ret != -1)
8336 nmlv.iItem = lvHitTestInfo.iItem;
8337 nmlv.iSubItem = lvHitTestInfo.iSubItem;
8339 else
8341 nmlv.iItem = -1;
8342 nmlv.iSubItem = 0;
8344 nmlv.ptAction.x = wPosX;
8345 nmlv.ptAction.y = wPosY;
8346 ListView_LVNotify(GetParent(hwnd), nCtrlId, &nmlv);
8349 /* set left button flag */
8350 infoPtr->bLButtonDown = FALSE;
8352 if(infoPtr->nEditLabelItem != -1)
8354 if(lvHitTestInfo.iItem == infoPtr->nEditLabelItem)
8356 LISTVIEW_EditLabelA(hwnd, lvHitTestInfo.iItem);
8358 infoPtr->nEditLabelItem = -1;
8362 return 0;
8365 /***
8366 * DESCRIPTION:
8367 * Creates the listview control (called before WM_CREATE).
8369 * PARAMETER(S):
8370 * [I] HWND : window handle
8371 * [I] WPARAM : unhandled
8372 * [I] LPARAM : widow creation info
8374 * RETURN:
8375 * Zero
8377 static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
8379 LISTVIEW_INFO *infoPtr;
8381 TRACE("(hwnd=%x,wParam=%x,lParam=%lx)\n", hwnd, wParam, lParam);
8383 /* allocate memory for info structure */
8384 infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc(sizeof(LISTVIEW_INFO));
8385 SetWindowLongA(hwnd, 0, (LONG)infoPtr);
8386 if (infoPtr == NULL)
8388 ERR("could not allocate info memory!\n");
8389 return 0;
8392 if ((LISTVIEW_INFO *)GetWindowLongA(hwnd, 0) != infoPtr)
8394 ERR("pointer assignment error!\n");
8395 return 0;
8398 return DefWindowProcA(hwnd, WM_NCCREATE, wParam, lParam);
8401 /***
8402 * DESCRIPTION:
8403 * Destroys the listview control (called after WM_DESTROY).
8405 * PARAMETER(S):
8406 * [I] HWND : window handle
8408 * RETURN:
8409 * Zero
8411 static LRESULT LISTVIEW_NCDestroy(HWND hwnd)
8413 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8415 TRACE("(hwnd=%x)\n", hwnd);
8417 /* delete all items */
8418 LISTVIEW_DeleteAllItems(hwnd);
8420 /* destroy data structure */
8421 DPA_Destroy(infoPtr->hdpaItems);
8422 DPA_Destroy(infoPtr->hdpaSelectionRanges);
8424 /* destroy font */
8425 infoPtr->hFont = (HFONT)0;
8426 if (infoPtr->hDefaultFont)
8428 DeleteObject(infoPtr->hDefaultFont);
8431 /* free listview info pointer*/
8432 COMCTL32_Free(infoPtr);
8434 SetWindowLongA(hwnd, 0, 0);
8435 return 0;
8438 /***
8439 * DESCRIPTION:
8440 * Handles notifications from children.
8442 * PARAMETER(S):
8443 * [I] HWND : window handle
8444 * [I] INT : control identifier
8445 * [I] LPNMHDR : notification information
8447 * RETURN:
8448 * Zero
8450 static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh)
8452 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8454 if (lpnmh->hwndFrom == infoPtr->hwndHeader)
8456 /* handle notification from header control */
8457 if (lpnmh->code == HDN_ENDTRACKA)
8459 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8460 InvalidateRect(hwnd, NULL, TRUE);
8462 else if(lpnmh->code == HDN_ITEMCLICKA)
8464 /* Handle sorting by Header Column */
8465 NMLISTVIEW nmlv;
8466 LPNMHEADERA pnmHeader = (LPNMHEADERA) lpnmh;
8467 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
8469 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
8470 nmlv.hdr.hwndFrom = hwnd;
8471 nmlv.hdr.idFrom = lCtrlId;
8472 nmlv.hdr.code = LVN_COLUMNCLICK;
8473 nmlv.iItem = -1;
8474 nmlv.iSubItem = pnmHeader->iItem;
8476 ListView_LVNotify(GetParent(hwnd),lCtrlId, &nmlv);
8479 else if(lpnmh->code == NM_RELEASEDCAPTURE)
8481 /* Idealy this should be done in HDN_ENDTRACKA
8482 * but since SetItemBounds in Header.c is called after
8483 * the notification is sent, it is neccessary to handle the
8484 * update of the scroll bar here (Header.c works fine as it is,
8485 * no need to disturb it)
8487 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8488 LISTVIEW_UpdateScroll(hwnd);
8489 InvalidateRect(hwnd, NULL, TRUE);
8494 return 0;
8497 /***
8498 * DESCRIPTION:
8499 * Determines the type of structure to use.
8501 * PARAMETER(S):
8502 * [I] HWND : window handle of the sender
8503 * [I] HWND : listview window handle
8504 * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
8506 * RETURN:
8507 * Zero
8509 static LRESULT LISTVIEW_NotifyFormat(HWND hwndFrom, HWND hwnd, INT nCommand)
8511 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8513 if (nCommand == NF_REQUERY)
8515 /* determine the type of structure to use */
8516 infoPtr->notifyFormat = SendMessageA(hwndFrom, WM_NOTIFYFORMAT,
8517 (WPARAM)hwnd, (LPARAM)NF_QUERY);
8518 if (infoPtr->notifyFormat == NFR_UNICODE)
8520 FIXME("NO support for unicode structures");
8524 return 0;
8527 /***
8528 * DESCRIPTION:
8529 * Paints/Repaints the listview control.
8531 * PARAMETER(S):
8532 * [I] HWND : window handle
8533 * [I] HDC : device context handle
8535 * RETURN:
8536 * Zero
8538 static LRESULT LISTVIEW_Paint(HWND hwnd, HDC hdc)
8540 PAINTSTRUCT ps;
8542 TRACE("(hwnd=%x,hdc=%x)\n", hwnd, hdc);
8544 if (hdc == 0)
8546 hdc = BeginPaint(hwnd, &ps);
8547 LISTVIEW_Refresh(hwnd, hdc);
8548 EndPaint(hwnd, &ps);
8550 else
8552 LISTVIEW_Refresh(hwnd, hdc);
8555 return 0;
8558 /***
8559 * DESCRIPTION:
8560 * Processes double click messages (right mouse button).
8562 * PARAMETER(S):
8563 * [I] HWND : window handle
8564 * [I] WORD : key flag
8565 * [I] WORD : x coordinate
8566 * [I] WORD : y coordinate
8568 * RETURN:
8569 * Zero
8571 static LRESULT LISTVIEW_RButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
8572 WORD wPosY)
8574 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8575 NMHDR nmh;
8577 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8579 /* send NM_RELEASEDCAPTURE notification */
8580 nmh.hwndFrom = hwnd;
8581 nmh.idFrom = nCtrlId;
8582 nmh.code = NM_RELEASEDCAPTURE;
8583 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8585 /* send NM_RDBLCLK notification */
8586 nmh.code = NM_RDBLCLK;
8587 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8589 return 0;
8592 /***
8593 * DESCRIPTION:
8594 * Processes mouse down messages (right mouse button).
8596 * PARAMETER(S):
8597 * [I] HWND : window handle
8598 * [I] WORD : key flag
8599 * [I] WORD : x coordinate
8600 * [I] WORD : y coordinate
8602 * RETURN:
8603 * Zero
8605 static LRESULT LISTVIEW_RButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
8606 WORD wPosY)
8608 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8609 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8610 POINT ptPosition;
8611 NMHDR nmh;
8612 INT nItem;
8614 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8616 /* send NM_RELEASEDCAPTURE notification */
8617 nmh.hwndFrom = hwnd;
8618 nmh.idFrom = nCtrlId;
8619 nmh.code = NM_RELEASEDCAPTURE;
8620 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8622 /* make sure the listview control window has the focus */
8623 if (infoPtr->bFocus == FALSE)
8625 SetFocus(hwnd);
8628 /* set right button down flag */
8629 infoPtr->bRButtonDown = TRUE;
8631 /* determine the index of the selected item */
8632 ptPosition.x = wPosX;
8633 ptPosition.y = wPosY;
8634 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
8635 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
8637 if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)))
8639 LISTVIEW_SetSelection(hwnd, nItem);
8642 else
8644 LISTVIEW_RemoveAllSelections(hwnd);
8647 return 0;
8650 /***
8651 * DESCRIPTION:
8652 * Processes mouse up messages (right mouse button).
8654 * PARAMETER(S):
8655 * [I] HWND : window handle
8656 * [I] WORD : key flag
8657 * [I] WORD : x coordinate
8658 * [I] WORD : y coordinate
8660 * RETURN:
8661 * Zero
8663 static LRESULT LISTVIEW_RButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
8664 WORD wPosY)
8666 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8667 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8669 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8671 if (infoPtr->bRButtonDown != FALSE)
8673 NMLISTVIEW nmlv;
8674 LVHITTESTINFO lvHitTestInfo;
8675 POINT pt;
8676 INT ret;
8678 lvHitTestInfo.pt.x = wPosX;
8679 lvHitTestInfo.pt.y = wPosY;
8681 /* Send NM_RClICK notification */
8682 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
8683 nmlv.hdr.hwndFrom = hwnd;
8684 nmlv.hdr.idFrom = nCtrlId;
8685 nmlv.hdr.code = NM_RCLICK;
8686 ret = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo, TRUE);
8687 if (ret != -1)
8689 nmlv.iItem = lvHitTestInfo.iItem;
8690 nmlv.iSubItem = lvHitTestInfo.iSubItem;
8692 else
8694 nmlv.iItem = -1;
8695 nmlv.iSubItem = 0;
8697 nmlv.ptAction.x = wPosX;
8698 nmlv.ptAction.y = wPosY;
8699 ListView_LVNotify(GetParent(hwnd), nCtrlId, &nmlv);
8701 pt.x = wPosX;
8702 pt.y = wPosY;
8704 /* set button flag */
8705 infoPtr->bRButtonDown = FALSE;
8707 /* Change to screen coordinate for WM_CONTEXTMENU */
8708 ClientToScreen(hwnd, &pt);
8710 /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
8711 SendMessageA( hwnd, WM_CONTEXTMENU, (WPARAM) hwnd, MAKELPARAM(pt.x, pt.y));
8714 return 0;
8717 /***
8718 * DESCRIPTION:
8719 * Sets the focus.
8721 * PARAMETER(S):
8722 * [I] HWND : window handle
8723 * [I] HWND : window handle of previously focused window
8725 * RETURN:
8726 * Zero
8728 static LRESULT LISTVIEW_SetFocus(HWND hwnd, HWND hwndLoseFocus)
8730 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8731 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8732 NMHDR nmh;
8734 TRACE("(hwnd=%x, hwndLoseFocus=%x)\n", hwnd, hwndLoseFocus);
8736 /* send NM_SETFOCUS notification */
8737 nmh.hwndFrom = hwnd;
8738 nmh.idFrom = nCtrlId;
8739 nmh.code = NM_SETFOCUS;
8740 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8742 /* set window focus flag */
8743 infoPtr->bFocus = TRUE;
8745 UpdateWindow(hwnd);
8747 return 0;
8750 /***
8751 * DESCRIPTION:
8752 * Sets the font.
8754 * PARAMETER(S):
8755 * [I] HWND : window handle
8756 * [I] HFONT : font handle
8757 * [I] WORD : redraw flag
8759 * RETURN:
8760 * Zero
8762 static LRESULT LISTVIEW_SetFont(HWND hwnd, HFONT hFont, WORD fRedraw)
8764 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8765 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
8767 TRACE("(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd, hFont, fRedraw);
8769 if (hFont == 0)
8771 infoPtr->hFont = infoPtr->hDefaultFont;
8773 else
8775 infoPtr->hFont = hFont;
8778 if (uView == LVS_REPORT)
8780 /* set header font */
8781 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont,
8782 MAKELPARAM(fRedraw, 0));
8785 /* invalidate listview control client area */
8786 InvalidateRect(hwnd, NULL, TRUE);
8788 if (fRedraw != FALSE)
8790 UpdateWindow(hwnd);
8793 return 0;
8796 /***
8797 * DESCRIPTION:
8798 * Message handling for WM_SETREDRAW.
8799 * For the Listview, it invalidates the entire window (the doc specifies otherwise)
8801 * PARAMETER(S):
8802 * [I] HWND : window handle
8803 * [I] bRedraw: state of redraw flag
8805 * RETURN:
8806 * DefWinProc return value
8808 static LRESULT LISTVIEW_SetRedraw(HWND hwnd, BOOL bRedraw)
8810 LRESULT lResult;
8811 lResult = DefWindowProcA(hwnd, WM_SETREDRAW, bRedraw, 0);
8812 if(bRedraw)
8814 RedrawWindow(hwnd, NULL, 0,
8815 RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN | RDW_ERASENOW);
8817 return lResult;
8820 /***
8821 * DESCRIPTION:
8822 * Resizes the listview control. This function processes WM_SIZE
8823 * messages. At this time, the width and height are not used.
8825 * PARAMETER(S):
8826 * [I] HWND : window handle
8827 * [I] WORD : new width
8828 * [I] WORD : new height
8830 * RETURN:
8831 * Zero
8833 static LRESULT LISTVIEW_Size(HWND hwnd, int Width, int Height)
8835 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8836 UINT uView = lStyle & LVS_TYPEMASK;
8838 TRACE("(hwnd=%x, width=%d, height=%d)\n",hwnd, Width, Height);
8840 LISTVIEW_UpdateSize(hwnd);
8842 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
8844 if (lStyle & LVS_ALIGNLEFT)
8846 LISTVIEW_AlignLeft(hwnd);
8848 else
8850 LISTVIEW_AlignTop(hwnd);
8854 LISTVIEW_UpdateScroll(hwnd);
8856 /* invalidate client area + erase background */
8857 InvalidateRect(hwnd, NULL, TRUE);
8859 return 0;
8862 /***
8863 * DESCRIPTION:
8864 * Sets the size information.
8866 * PARAMETER(S):
8867 * [I] HWND : window handle
8869 * RETURN:
8870 * Zero
8872 static VOID LISTVIEW_UpdateSize(HWND hwnd)
8874 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8875 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8876 UINT uView = lStyle & LVS_TYPEMASK;
8877 RECT rcList;
8879 GetClientRect(hwnd, &rcList);
8880 infoPtr->rcList.left = 0;
8881 infoPtr->rcList.right = max(rcList.right - rcList.left, 1);
8882 infoPtr->rcList.top = 0;
8883 infoPtr->rcList.bottom = max(rcList.bottom - rcList.top, 1);
8885 if (uView == LVS_LIST)
8887 if (lStyle & WS_HSCROLL)
8889 INT nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
8890 if (infoPtr->rcList.bottom > nHScrollHeight)
8892 infoPtr->rcList.bottom -= nHScrollHeight;
8896 else if (uView == LVS_REPORT)
8898 HDLAYOUT hl;
8899 WINDOWPOS wp;
8901 hl.prc = &rcList;
8902 hl.pwpos = &wp;
8903 Header_Layout(infoPtr->hwndHeader, &hl);
8905 SetWindowPos(wp.hwnd, wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
8907 if (!(LVS_NOCOLUMNHEADER & lStyle))
8909 infoPtr->rcList.top = max(wp.cy, 0);
8914 /***
8915 * DESCRIPTION:
8916 * Processes WM_STYLECHANGED messages.
8918 * PARAMETER(S):
8919 * [I] HWND : window handle
8920 * [I] WPARAM : window style type (normal or extended)
8921 * [I] LPSTYLESTRUCT : window style information
8923 * RETURN:
8924 * Zero
8926 static INT LISTVIEW_StyleChanged(HWND hwnd, WPARAM wStyleType,
8927 LPSTYLESTRUCT lpss)
8929 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8930 UINT uNewView = lpss->styleNew & LVS_TYPEMASK;
8931 UINT uOldView = lpss->styleOld & LVS_TYPEMASK;
8932 RECT rcList = infoPtr->rcList;
8934 TRACE("(hwnd=%x, styletype=%x, stylestruct=%p)\n",
8935 hwnd, wStyleType, lpss);
8937 if (wStyleType == GWL_STYLE)
8939 if (uOldView == LVS_REPORT)
8941 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
8944 if ((lpss->styleOld & WS_HSCROLL) != 0)
8946 ShowScrollBar(hwnd, SB_HORZ, FALSE);
8949 if ((lpss->styleOld & WS_VSCROLL) != 0)
8951 ShowScrollBar(hwnd, SB_VERT, FALSE);
8954 if (uNewView == LVS_ICON)
8956 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
8957 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
8958 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8959 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8960 if (lpss->styleNew & LVS_ALIGNLEFT)
8962 LISTVIEW_AlignLeft(hwnd);
8964 else
8966 LISTVIEW_AlignTop(hwnd);
8969 else if (uNewView == LVS_REPORT)
8971 HDLAYOUT hl;
8972 WINDOWPOS wp;
8974 hl.prc = &rcList;
8975 hl.pwpos = &wp;
8976 Header_Layout(infoPtr->hwndHeader, &hl);
8977 SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, wp.cy,
8978 wp.flags);
8979 if (!(LVS_NOCOLUMNHEADER & lpss->styleNew))
8980 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
8982 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
8983 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
8984 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8985 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8987 else if (uNewView == LVS_LIST)
8989 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
8990 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
8991 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8992 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8994 else
8996 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
8997 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
8998 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8999 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
9000 if (lpss->styleNew & LVS_ALIGNLEFT)
9002 LISTVIEW_AlignLeft(hwnd);
9004 else
9006 LISTVIEW_AlignTop(hwnd);
9010 /* update the size of the client area */
9011 LISTVIEW_UpdateSize(hwnd);
9013 /* add scrollbars if needed */
9014 LISTVIEW_UpdateScroll(hwnd);
9016 /* invalidate client area + erase background */
9017 InvalidateRect(hwnd, NULL, TRUE);
9019 /* print the list of unsupported window styles */
9020 LISTVIEW_UnsupportedStyles(lpss->styleNew);
9023 /* If they change the view and we have an active edit control
9024 we will need to kill the control since the redraw will
9025 misplace the edit control.
9027 if (infoPtr->hwndEdit &&
9028 ((uNewView & (LVS_ICON|LVS_LIST|LVS_SMALLICON)) !=
9029 ((LVS_ICON|LVS_LIST|LVS_SMALLICON) & uOldView)))
9031 SendMessageA(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
9034 return 0;
9037 /***
9038 * DESCRIPTION:
9039 * Window procedure of the listview control.
9042 static LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
9043 LPARAM lParam)
9045 TRACE("hwnd=%x uMsg=%x wParam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam);
9046 if (!GetWindowLongA(hwnd, 0) && (uMsg != WM_NCCREATE))
9047 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
9048 switch (uMsg)
9050 case LVM_APPROXIMATEVIEWRECT:
9051 return LISTVIEW_ApproximateViewRect(hwnd, (INT)wParam,
9052 LOWORD(lParam), HIWORD(lParam));
9053 case LVM_ARRANGE:
9054 return LISTVIEW_Arrange(hwnd, (INT)wParam);
9056 /* case LVM_CREATEDRAGIMAGE: */
9058 case LVM_DELETEALLITEMS:
9059 return LISTVIEW_DeleteAllItems(hwnd);
9061 case LVM_DELETECOLUMN:
9062 return LISTVIEW_DeleteColumn(hwnd, (INT)wParam);
9064 case LVM_DELETEITEM:
9065 return LISTVIEW_DeleteItem(hwnd, (INT)wParam);
9067 case LVM_EDITLABELW:
9068 case LVM_EDITLABELA:
9069 return LISTVIEW_EditLabelA(hwnd, (INT)wParam);
9071 case LVM_ENSUREVISIBLE:
9072 return LISTVIEW_EnsureVisible(hwnd, (INT)wParam, (BOOL)lParam);
9074 case LVM_FINDITEMA:
9075 return LISTVIEW_FindItem(hwnd, (INT)wParam, (LPLVFINDINFO)lParam);
9077 case LVM_GETBKCOLOR:
9078 return LISTVIEW_GetBkColor(hwnd);
9080 /* case LVM_GETBKIMAGE: */
9082 case LVM_GETCALLBACKMASK:
9083 return LISTVIEW_GetCallbackMask(hwnd);
9085 case LVM_GETCOLUMNA:
9086 return LISTVIEW_GetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
9088 /* case LVM_GETCOLUMNW: */
9090 case LVM_GETCOLUMNORDERARRAY:
9091 return LISTVIEW_GetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
9093 case LVM_GETCOLUMNWIDTH:
9094 return LISTVIEW_GetColumnWidth(hwnd, (INT)wParam);
9096 case LVM_GETCOUNTPERPAGE:
9097 return LISTVIEW_GetCountPerPage(hwnd);
9099 case LVM_GETEDITCONTROL:
9100 return LISTVIEW_GetEditControl(hwnd);
9102 case LVM_GETEXTENDEDLISTVIEWSTYLE:
9103 return LISTVIEW_GetExtendedListViewStyle(hwnd);
9105 case LVM_GETHEADER:
9106 return LISTVIEW_GetHeader(hwnd);
9108 /* case LVM_GETHOTCURSOR: */
9110 case LVM_GETHOTITEM:
9111 return LISTVIEW_GetHotItem(hwnd);
9113 case LVM_GETHOVERTIME:
9114 return LISTVIEW_GetHoverTime(hwnd);
9116 case LVM_GETIMAGELIST:
9117 return LISTVIEW_GetImageList(hwnd, (INT)wParam);
9119 /* case LVM_GETISEARCHSTRING: */
9121 case LVM_GETITEMA:
9122 return LISTVIEW_GetItemA(hwnd, (LPLVITEMA)lParam, FALSE);
9124 /* case LVM_GETITEMW: */
9126 case LVM_GETITEMCOUNT:
9127 return LISTVIEW_GetItemCount(hwnd);
9129 case LVM_GETITEMPOSITION:
9130 return LISTVIEW_GetItemPosition(hwnd, (INT)wParam, (LPPOINT)lParam);
9132 case LVM_GETITEMRECT:
9133 return LISTVIEW_GetItemRect(hwnd, (INT)wParam, (LPRECT)lParam);
9135 case LVM_GETITEMSPACING:
9136 return LISTVIEW_GetItemSpacing(hwnd, (BOOL)wParam);
9138 case LVM_GETITEMSTATE:
9139 return LISTVIEW_GetItemState(hwnd, (INT)wParam, (UINT)lParam);
9141 case LVM_GETITEMTEXTA:
9142 LISTVIEW_GetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
9143 break;
9145 /* case LVM_GETITEMTEXTW: */
9147 case LVM_GETNEXTITEM:
9148 return LISTVIEW_GetNextItem(hwnd, (INT)wParam, LOWORD(lParam));
9150 /* case LVM_GETNUMBEROFWORKAREAS: */
9152 case LVM_GETORIGIN:
9153 return LISTVIEW_GetOrigin(hwnd, (LPPOINT)lParam);
9155 case LVM_GETSELECTEDCOUNT:
9156 return LISTVIEW_GetSelectedCount(hwnd);
9158 case LVM_GETSELECTIONMARK:
9159 return LISTVIEW_GetSelectionMark(hwnd);
9161 case LVM_GETSTRINGWIDTHA:
9162 return LISTVIEW_GetStringWidthA (hwnd, (LPCSTR)lParam);
9164 /* case LVM_GETSTRINGWIDTHW: */
9165 /* case LVM_GETSUBITEMRECT: */
9167 case LVM_GETTEXTBKCOLOR:
9168 return LISTVIEW_GetTextBkColor(hwnd);
9170 case LVM_GETTEXTCOLOR:
9171 return LISTVIEW_GetTextColor(hwnd);
9173 /* case LVM_GETTOOLTIPS: */
9175 case LVM_GETTOPINDEX:
9176 return LISTVIEW_GetTopIndex(hwnd);
9178 /* case LVM_GETUNICODEFORMAT: */
9180 case LVM_GETVIEWRECT:
9181 return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam);
9183 /* case LVM_GETWORKAREAS: */
9185 case LVM_HITTEST:
9186 return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam);
9188 case LVM_INSERTCOLUMNA:
9189 return LISTVIEW_InsertColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
9191 case LVM_INSERTCOLUMNW:
9192 return LISTVIEW_InsertColumnW(hwnd, (INT)wParam, (LPLVCOLUMNW)lParam);
9194 case LVM_INSERTITEMA:
9195 return LISTVIEW_InsertItemA(hwnd, (LPLVITEMA)lParam);
9197 case LVM_INSERTITEMW:
9198 return LISTVIEW_InsertItemW(hwnd, (LPLVITEMW)lParam);
9200 case LVM_REDRAWITEMS:
9201 return LISTVIEW_RedrawItems(hwnd, (INT)wParam, (INT)lParam);
9203 /* case LVM_SCROLL: */
9204 /* return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); */
9206 case LVM_SETBKCOLOR:
9207 return LISTVIEW_SetBkColor(hwnd, (COLORREF)lParam);
9209 /* case LVM_SETBKIMAGE: */
9211 case LVM_SETCALLBACKMASK:
9212 return LISTVIEW_SetCallbackMask(hwnd, (UINT)wParam);
9214 case LVM_SETCOLUMNA:
9215 return LISTVIEW_SetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
9217 case LVM_SETCOLUMNW:
9218 FIXME("Unimplemented msg LVM_SETCOLUMNW\n");
9219 return 0;
9221 case LVM_SETCOLUMNORDERARRAY:
9222 return LISTVIEW_SetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
9224 case LVM_SETCOLUMNWIDTH:
9225 return LISTVIEW_SetColumnWidth(hwnd, (INT)wParam, SLOWORD(lParam));
9227 case LVM_SETEXTENDEDLISTVIEWSTYLE:
9228 return LISTVIEW_SetExtendedListViewStyle(hwnd, (DWORD)wParam, (DWORD)lParam);
9230 /* case LVM_SETHOTCURSOR: */
9232 case LVM_SETHOTITEM:
9233 return LISTVIEW_SetHotItem(hwnd, (INT)wParam);
9235 case LVM_SETHOVERTIME:
9236 return LISTVIEW_SetHoverTime(hwnd, (DWORD)wParam);
9238 /* case LVM_SETICONSPACING: */
9240 case LVM_SETIMAGELIST:
9241 return LISTVIEW_SetImageList(hwnd, (INT)wParam, (HIMAGELIST)lParam);
9243 case LVM_SETITEMA:
9244 return LISTVIEW_SetItemA(hwnd, (LPLVITEMA)lParam);
9246 /* case LVM_SETITEMW: */
9248 case LVM_SETITEMCOUNT:
9249 return LISTVIEW_SetItemCount(hwnd, (INT)wParam, (DWORD)lParam);
9251 case LVM_SETITEMPOSITION:
9252 return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, (INT)LOWORD(lParam),
9253 (INT)HIWORD(lParam));
9255 case LVM_SETITEMPOSITION32:
9256 return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, ((POINT*)lParam)->x,
9257 ((POINT*)lParam)->y);
9259 case LVM_SETITEMSTATE:
9260 return LISTVIEW_SetItemState(hwnd, (INT)wParam, (LPLVITEMA)lParam);
9262 case LVM_SETITEMTEXTA:
9263 return LISTVIEW_SetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
9265 /* case LVM_SETITEMTEXTW: */
9267 case LVM_SETSELECTIONMARK:
9268 return LISTVIEW_SetSelectionMark(hwnd, (INT)lParam);
9270 case LVM_SETTEXTBKCOLOR:
9271 return LISTVIEW_SetTextBkColor(hwnd, (COLORREF)lParam);
9273 case LVM_SETTEXTCOLOR:
9274 return LISTVIEW_SetTextColor(hwnd, (COLORREF)lParam);
9276 /* case LVM_SETTOOLTIPS: */
9277 /* case LVM_SETUNICODEFORMAT: */
9278 /* case LVM_SETWORKAREAS: */
9280 case LVM_SORTITEMS:
9281 return LISTVIEW_SortItems(hwnd, wParam, lParam);
9283 /* case LVM_SUBITEMHITTEST: */
9285 case LVM_UPDATE:
9286 return LISTVIEW_Update(hwnd, (INT)wParam);
9288 /* case WM_CHAR: */
9289 case WM_CHAR:
9290 return LISTVIEW_ProcessLetterKeys( hwnd, wParam, lParam );
9292 case WM_COMMAND:
9293 return LISTVIEW_Command(hwnd, wParam, lParam);
9295 case WM_CREATE:
9296 return LISTVIEW_Create(hwnd, wParam, lParam);
9298 case WM_ERASEBKGND:
9299 return LISTVIEW_EraseBackground(hwnd, wParam, lParam);
9301 case WM_GETDLGCODE:
9302 return DLGC_WANTCHARS | DLGC_WANTARROWS;
9304 case WM_GETFONT:
9305 return LISTVIEW_GetFont(hwnd);
9307 case WM_HSCROLL:
9308 return LISTVIEW_HScroll(hwnd, (INT)LOWORD(wParam),
9309 (INT)HIWORD(wParam), (HWND)lParam);
9311 case WM_KEYDOWN:
9312 return LISTVIEW_KeyDown(hwnd, (INT)wParam, (LONG)lParam);
9314 case WM_KILLFOCUS:
9315 return LISTVIEW_KillFocus(hwnd);
9317 case WM_LBUTTONDBLCLK:
9318 return LISTVIEW_LButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
9319 HIWORD(lParam));
9321 case WM_LBUTTONDOWN:
9322 return LISTVIEW_LButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
9323 HIWORD(lParam));
9324 case WM_LBUTTONUP:
9325 return LISTVIEW_LButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
9326 HIWORD(lParam));
9327 case WM_MOUSEMOVE:
9328 return LISTVIEW_MouseMove (hwnd, wParam, lParam);
9330 case WM_MOUSEHOVER:
9331 return LISTVIEW_MouseHover(hwnd, wParam, lParam);
9333 case WM_NCCREATE:
9334 return LISTVIEW_NCCreate(hwnd, wParam, lParam);
9336 case WM_NCDESTROY:
9337 return LISTVIEW_NCDestroy(hwnd);
9339 case WM_NOTIFY:
9340 return LISTVIEW_Notify(hwnd, (INT)wParam, (LPNMHDR)lParam);
9342 case WM_NOTIFYFORMAT:
9343 return LISTVIEW_NotifyFormat(hwnd, (HWND)wParam, (INT)lParam);
9345 case WM_PAINT:
9346 return LISTVIEW_Paint(hwnd, (HDC)wParam);
9348 case WM_RBUTTONDBLCLK:
9349 return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
9350 HIWORD(lParam));
9352 case WM_RBUTTONDOWN:
9353 return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
9354 HIWORD(lParam));
9356 case WM_RBUTTONUP:
9357 return LISTVIEW_RButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
9358 HIWORD(lParam));
9360 case WM_SETFOCUS:
9361 return LISTVIEW_SetFocus(hwnd, (HWND)wParam);
9363 case WM_SETFONT:
9364 return LISTVIEW_SetFont(hwnd, (HFONT)wParam, (WORD)lParam);
9366 case WM_SETREDRAW:
9367 return LISTVIEW_SetRedraw(hwnd, (BOOL)wParam);
9369 case WM_SIZE:
9370 return LISTVIEW_Size(hwnd, (int)SLOWORD(lParam), (int)SHIWORD(lParam));
9372 case WM_STYLECHANGED:
9373 return LISTVIEW_StyleChanged(hwnd, wParam, (LPSTYLESTRUCT)lParam);
9375 /* case WM_TIMER: */
9377 case WM_VSCROLL:
9378 return LISTVIEW_VScroll(hwnd, (INT)LOWORD(wParam),
9379 (INT)HIWORD(wParam), (HWND)lParam);
9381 case WM_MOUSEWHEEL:
9382 if (wParam & (MK_SHIFT | MK_CONTROL))
9383 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
9384 return LISTVIEW_MouseWheel(hwnd, (short int)HIWORD(wParam));/* case WM_WINDOWPOSCHANGED: */
9386 /* case WM_WININICHANGE: */
9388 default:
9389 if (uMsg >= WM_USER)
9391 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam,
9392 lParam);
9395 /* call default window procedure */
9396 return DefWindowProcA(hwnd, uMsg, wParam, lParam);
9399 return 0;
9402 /***
9403 * DESCRIPTION:
9404 * Registers the window class.
9406 * PARAMETER(S):
9407 * None
9409 * RETURN:
9410 * None
9412 VOID LISTVIEW_Register(void)
9414 WNDCLASSA wndClass;
9416 ZeroMemory(&wndClass, sizeof(WNDCLASSA));
9417 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
9418 wndClass.lpfnWndProc = (WNDPROC)LISTVIEW_WindowProc;
9419 wndClass.cbClsExtra = 0;
9420 wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *);
9421 wndClass.hCursor = LoadCursorA(0, IDC_ARROWA);
9422 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
9423 wndClass.lpszClassName = WC_LISTVIEWA;
9424 RegisterClassA(&wndClass);
9427 /***
9428 * DESCRIPTION:
9429 * Unregisters the window class.
9431 * PARAMETER(S):
9432 * None
9434 * RETURN:
9435 * None
9437 VOID LISTVIEW_Unregister(void)
9439 UnregisterClassA(WC_LISTVIEWA, (HINSTANCE)NULL);
9442 /***
9443 * DESCRIPTION:
9444 * Handle any WM_COMMAND messages
9446 * PARAMETER(S):
9448 * RETURN:
9450 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam)
9452 switch (HIWORD(wParam))
9454 case EN_UPDATE:
9457 * Adjust the edit window size
9459 char buffer[1024];
9460 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
9461 HDC hdc = GetDC(infoPtr->hwndEdit);
9462 HFONT hFont, hOldFont = 0;
9463 RECT rect;
9464 SIZE sz;
9465 int len;
9467 len = GetWindowTextA(infoPtr->hwndEdit, buffer, 1023);
9468 GetWindowRect(infoPtr->hwndEdit, &rect);
9470 /* Select font to get the right dimension of the string */
9471 hFont = SendMessageA(infoPtr->hwndEdit, WM_GETFONT, 0, 0);
9472 if(hFont != 0)
9474 hOldFont = SelectObject(hdc, hFont);
9477 if (GetTextExtentPoint32A(hdc, buffer, strlen(buffer), &sz))
9479 TEXTMETRICA textMetric;
9481 /* Add Extra spacing for the next character */
9482 GetTextMetricsA(hdc, &textMetric);
9483 sz.cx += (textMetric.tmMaxCharWidth * 2);
9485 SetWindowPos (
9486 infoPtr->hwndEdit,
9487 HWND_TOP,
9490 sz.cx,
9491 rect.bottom - rect.top,
9492 SWP_DRAWFRAME|SWP_NOMOVE);
9494 if(hFont != 0)
9496 SelectObject(hdc, hOldFont);
9499 ReleaseDC(hwnd, hdc);
9501 break;
9504 default:
9505 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
9508 return 0;
9512 /***
9513 * DESCRIPTION:
9514 * Subclassed edit control windproc function
9516 * PARAMETER(S):
9518 * RETURN:
9520 LRESULT CALLBACK EditLblWndProc(HWND hwnd, UINT uMsg,
9521 WPARAM wParam, LPARAM lParam)
9523 BOOL cancel = FALSE;
9524 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(GetParent(hwnd), 0);
9525 EDITLABEL_ITEM *einfo = infoPtr->pedititem;
9526 static BOOL bIgnoreKillFocus = FALSE;
9527 switch (uMsg)
9529 case WM_GETDLGCODE:
9530 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
9532 case WM_KILLFOCUS:
9533 if(bIgnoreKillFocus)
9535 return TRUE;
9537 break;
9539 case WM_DESTROY:
9541 WNDPROC editProc = einfo->EditWndProc;
9542 SetWindowLongA(hwnd, GWL_WNDPROC, (LONG)editProc);
9543 COMCTL32_Free(einfo);
9544 infoPtr->pedititem = NULL;
9545 return CallWindowProcA(editProc, hwnd, uMsg, wParam, lParam);
9548 case WM_KEYDOWN:
9549 if (VK_ESCAPE == (INT)wParam)
9551 cancel = TRUE;
9552 break;
9555 else if (VK_RETURN == (INT)wParam)
9556 break;
9558 default:
9559 return CallWindowProcA(einfo->EditWndProc, hwnd,
9560 uMsg, wParam, lParam);
9563 if (einfo->EditLblCb)
9565 char *buffer = NULL;
9568 if (!cancel)
9570 int len = 1 + GetWindowTextLengthA(hwnd);
9572 if (len > 1)
9574 if (NULL != (buffer = (char *)COMCTL32_Alloc(len*sizeof(char))))
9576 GetWindowTextA(hwnd, buffer, len);
9580 /* Processing LVN_ENDLABELEDIT message could kill the focus */
9581 /* eg. Using a messagebox */
9582 bIgnoreKillFocus = TRUE;
9583 einfo->EditLblCb(GetParent(hwnd), buffer, einfo->param);
9585 if (buffer)
9586 COMCTL32_Free(buffer);
9588 einfo->EditLblCb = NULL;
9589 bIgnoreKillFocus = FALSE;
9592 SendMessageA(hwnd, WM_CLOSE, 0, 0);
9593 return TRUE;
9597 /***
9598 * DESCRIPTION:
9599 * Creates a subclassed edit cotrol
9601 * PARAMETER(S):
9603 * RETURN:
9605 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
9606 INT width, INT height, HWND parent, HINSTANCE hinst,
9607 EditlblCallback EditLblCb, DWORD param)
9609 HWND hedit;
9610 SIZE sz;
9611 HDC hdc;
9612 HDC hOldFont=0;
9613 TEXTMETRICA textMetric;
9614 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(parent, 0);
9616 if (NULL == (infoPtr->pedititem = COMCTL32_Alloc(sizeof(EDITLABEL_ITEM))))
9617 return 0;
9619 style |= WS_CHILDWINDOW|WS_CLIPSIBLINGS|ES_LEFT|WS_BORDER;
9620 hdc = GetDC(parent);
9622 /* Select the font to get appropriate metric dimensions */
9623 if(infoPtr->hFont != 0)
9625 hOldFont = SelectObject(hdc, infoPtr->hFont);
9628 /*Get String Lenght in pixels */
9629 GetTextExtentPoint32A(hdc, text, strlen(text), &sz);
9631 /*Add Extra spacing for the next character */
9632 GetTextMetricsA(hdc, &textMetric);
9633 sz.cx += (textMetric.tmMaxCharWidth * 2);
9635 if(infoPtr->hFont != 0)
9637 SelectObject(hdc, hOldFont);
9640 ReleaseDC(parent, hdc);
9641 if (!(hedit = CreateWindowA("Edit", text, style, x, y, sz.cx, height,
9642 parent, 0, hinst, 0)))
9644 COMCTL32_Free(infoPtr->pedititem);
9645 return 0;
9648 infoPtr->pedititem->param = param;
9649 infoPtr->pedititem->EditLblCb = EditLblCb;
9650 infoPtr->pedititem->EditWndProc = (WNDPROC)SetWindowLongA(hedit,
9651 GWL_WNDPROC, (LONG) EditLblWndProc);
9653 SendMessageA(hedit, WM_SETFONT, infoPtr->hFont, FALSE);
9655 return hedit;