Beginning of some simple optimization of the listview
[wine.git] / dlls / comctl32 / listview.c
blobd2e8435170f4b5bcd9e22afc324b2f1d729640b4
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
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_GetColumnOrderArray : simple hack only
35 * LISTVIEW_SetColumnOrderArray : simple hack only
36 * LISTVIEW_Arrange : empty stub
37 * LISTVIEW_ApproximateViewRect : incomplete
38 * LISTVIEW_Scroll : not implemented
39 * LISTVIEW_RedrawItems : empty stub
40 * LISTVIEW_Update : not completed
43 #include <ctype.h>
44 #include <string.h>
46 #include "winbase.h"
47 #include "heap.h"
48 #include "commctrl.h"
49 #include "debugtools.h"
51 DEFAULT_DEBUG_CHANNEL(listview);
53 /* Some definitions for inline edit control */
54 typedef BOOL (*EditlblCallback)(HWND, LPSTR, DWORD);
56 typedef struct tagEDITLABEL_ITEM
58 WNDPROC EditWndProc;
59 DWORD param;
60 EditlblCallback EditLblCb;
61 } EDITLABEL_ITEM;
63 typedef struct tagLISTVIEW_SUBITEM
65 LPSTR pszText;
66 INT iImage;
67 INT iSubItem;
69 } LISTVIEW_SUBITEM;
71 typedef struct tagLISTVIEW_ITEM
73 UINT state;
74 LPSTR pszText;
75 INT iImage;
76 LPARAM lParam;
77 INT iIndent;
78 POINT ptPosition;
80 } LISTVIEW_ITEM;
82 typedef struct tagLISTVIEW_SELECTION
84 DWORD lower;
85 DWORD upper;
86 } LISTVIEW_SELECTION;
88 typedef struct tagLISTVIEW_INFO
90 COLORREF clrBk;
91 COLORREF clrText;
92 COLORREF clrTextBk;
93 HIMAGELIST himlNormal;
94 HIMAGELIST himlSmall;
95 HIMAGELIST himlState;
96 BOOL bLButtonDown;
97 BOOL bRButtonDown;
98 INT nFocusedItem;
99 HDPA hdpaSelectionRanges;
100 INT nItemHeight;
101 INT nItemWidth;
102 INT nSelectionMark;
103 INT nHotItem;
104 SHORT notifyFormat;
105 RECT rcList;
106 RECT rcView;
107 SIZE iconSize;
108 SIZE iconSpacing;
109 UINT uCallbackMask;
110 HWND hwndHeader;
111 HFONT hDefaultFont;
112 HFONT hFont;
113 BOOL bFocus;
114 DWORD dwExStyle; /* extended listview style */
115 HDPA hdpaItems;
116 PFNLVCOMPARE pfnCompare;
117 LPARAM lParamSort;
118 HWND hwndEdit;
119 INT nEditLabelItem;
120 EDITLABEL_ITEM *pedititem;
121 DWORD dwHoverTime;
123 WPARAM charCode; /* Added */
124 CHAR szSearchParam[ MAX_PATH ]; /* Added */
125 DWORD timeSinceLastKeyPress; /* Added */
126 INT nSearchParamLength; /* Added */
127 } LISTVIEW_INFO;
130 * constants
133 /* maximum size of a label */
134 #define DISP_TEXT_SIZE 512
136 /* padding for items in list and small icon display modes */
137 #define WIDTH_PADDING 12
139 /* padding for items in list, report and small icon display modes */
140 #define HEIGHT_PADDING 1
142 /* offset of items in report display mode */
143 #define REPORT_MARGINX 2
145 /* padding for icon in large icon display mode */
146 #define ICON_TOP_PADDING 2
147 #define ICON_BOTTOM_PADDING 2
149 /* padding for label in large icon display mode */
150 #define LABEL_VERT_OFFSET 2
152 /* default label width for items in list and small icon display modes */
153 #define DEFAULT_LABEL_WIDTH 40
155 /* default column width for items in list display mode */
156 #define DEFAULT_COLUMN_WIDTH 96
158 /* Increment size of the horizontal scroll bar */
159 #define LISTVIEW_SCROLL_DIV_SIZE 10
161 /* Padding betwen image and label */
162 #define IMAGE_PADDING 2
164 /* Padding behind the label */
165 #define TRAILING_PADDING 5
168 * macros
170 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
171 #define ListView_LVNotify(hwnd,lCtrlId,plvnm) \
172 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMLISTVIEW)(plvnm))
173 #define ListView_Notify(hwnd,lCtrlId,pnmh) \
174 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMHDR)(pnmh))
175 /* retrieve the number of items in the listview */
176 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
178 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
179 INT width, INT height, HWND parent, HINSTANCE hinst,
180 EditlblCallback EditLblCb, DWORD param);
183 * forward declarations
185 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem, BOOL internal);
186 static INT LISTVIEW_HitTestItem(HWND, LPLVHITTESTINFO);
187 static INT LISTVIEW_GetCountPerRow(HWND);
188 static INT LISTVIEW_GetCountPerColumn(HWND);
189 static VOID LISTVIEW_AlignLeft(HWND);
190 static VOID LISTVIEW_AlignTop(HWND);
191 static VOID LISTVIEW_AddGroupSelection(HWND, INT);
192 static VOID LISTVIEW_AddSelection(HWND, INT);
193 static BOOL LISTVIEW_AddSubItem(HWND, LPLVITEMA);
194 static INT LISTVIEW_FindInsertPosition(HDPA, INT);
195 static INT LISTVIEW_GetItemHeight(HWND);
196 static BOOL LISTVIEW_GetItemPosition(HWND, INT, LPPOINT);
197 static LRESULT LISTVIEW_GetItemRect(HWND, INT, LPRECT);
198 static INT LISTVIEW_GetItemWidth(HWND);
199 static INT LISTVIEW_GetLabelWidth(HWND, INT);
200 static LRESULT LISTVIEW_GetOrigin(HWND, LPPOINT);
201 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem);
202 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA, INT);
203 static LRESULT LISTVIEW_GetViewRect(HWND, LPRECT);
204 static BOOL LISTVIEW_InitItem(HWND, LISTVIEW_ITEM *, LPLVITEMA);
205 static BOOL LISTVIEW_InitSubItem(HWND, LISTVIEW_SUBITEM *, LPLVITEMA);
206 static LRESULT LISTVIEW_MouseSelection(HWND, POINT);
207 static BOOL LISTVIEW_RemoveColumn(HDPA, INT);
208 static BOOL LISTVIEW_RemoveSubItem(HDPA, INT);
209 static VOID LISTVIEW_SetGroupSelection(HWND, INT);
210 static BOOL LISTVIEW_SetItem(HWND, LPLVITEMA);
211 static BOOL LISTVIEW_SetItemFocus(HWND, INT);
212 static BOOL LISTVIEW_SetItemPosition(HWND, INT, INT, INT);
213 static VOID LISTVIEW_UpdateScroll(HWND);
214 static VOID LISTVIEW_SetSelection(HWND, INT);
215 static VOID LISTVIEW_UpdateSize(HWND);
216 static BOOL LISTVIEW_SetSubItem(HWND, LPLVITEMA);
217 static LRESULT LISTVIEW_SetViewRect(HWND, LPRECT);
218 static BOOL LISTVIEW_ToggleSelection(HWND, INT);
219 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle);
220 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem);
221 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem);
222 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam);
223 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam);
224 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText);
225 static INT LISTVIEW_ProcessLetterKeys( HWND hwnd, WPARAM charCode, LPARAM keyData );
226 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem);
227 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask);
228 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem);
230 /******** Defines that LISTVIEW_ProcessLetterKeys uses ****************/
231 #define KEY_DELAY 900
232 #define LISTVIEW_InitLvItemStruct(item,idx,TEXT) \
233 ZeroMemory(&(item), sizeof(LVITEMA)); \
234 (item).mask = LVIF_TEXT; \
235 (item).iItem = (idx); \
236 (item).iSubItem = 0; \
237 (item).pszText = (TEXT); \
238 (item).cchTextMax = MAX_PATH
240 /*************************************************************************
241 * DESCRIPTION:
242 * Processes keyboard messages generated by pressing the letter keys on the keyboard.
243 * Assumes the list is sorted alphabetically, without regard to case.
245 * PARAMETERS:
246 * [I] HWND: handle to the window
247 * [I] WPARAM: the character code, the actual character
248 * [I] LPARAM: key data
251 * RETURN:
252 * Zero.
254 * TODO:
258 static INT LISTVIEW_ProcessLetterKeys( HWND hwnd, WPARAM charCode, LPARAM keyData )
260 LISTVIEW_INFO *infoPtr = NULL;
261 INT nItem = -1;
262 BOOL bRedraw;
263 INT nSize = 0;
264 INT idx = 0;
265 BOOL bFoundMatchingFiles = FALSE;
266 LVITEMA item;
267 CHAR TEXT[ MAX_PATH ];
268 CHAR szCharCode[ 2 ];
269 DWORD timeSinceLastKeyPress = 0;
271 szCharCode[0] = charCode;
272 szCharCode[1] = 0;
274 /* simple parameter checking */
275 if ( !hwnd || !charCode || !keyData )
276 return 0;
278 infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
280 if ( !infoPtr )
281 return 0;
283 /* only allow the valid WM_CHARs through */
284 if ( isalnum( charCode ) || charCode == '.' || charCode == '`' || charCode == '!'
285 || charCode == '@' || charCode == '#' || charCode == '$' || charCode == '%'
286 || charCode == '^' || charCode == '&' || charCode == '*' || charCode == '('
287 || charCode == ')' || charCode == '-' || charCode == '_' || charCode == '+'
288 || charCode == '=' || charCode == '\\'|| charCode == ']' || charCode == '}'
289 || charCode == '[' || charCode == '{' || charCode == '/' || charCode == '?'
290 || charCode == '>' || charCode == '<' || charCode == ',' || charCode == '~')
292 timeSinceLastKeyPress = GetTickCount();
294 nSize = GETITEMCOUNT( infoPtr );
295 /* if there are 0 items, there is no where to go */
296 if ( nSize == 0 )
297 return 0;
299 * If the last charCode equals the current charCode then look
300 * to the next element in list to see if it matches the previous
301 * charCode.
303 if ( infoPtr->charCode == charCode )
305 if ( timeSinceLastKeyPress - infoPtr->timeSinceLastKeyPress < KEY_DELAY )
306 { /* append new character to search string */
307 strcat( infoPtr->szSearchParam, szCharCode );
308 infoPtr->nSearchParamLength++;
310 /* loop from start of list view */
311 for( idx = infoPtr->nFocusedItem; idx < nSize; idx++ )
312 { /* get item */
313 LISTVIEW_InitLvItemStruct( item, idx, TEXT );
314 ListView_GetItemA( hwnd, &item );
316 /* compare items */
317 if ( strncasecmp( item.pszText, infoPtr->szSearchParam,
318 infoPtr->nSearchParamLength ) == 0 )
320 nItem = idx;
321 break;
325 else if ( infoPtr->timeSinceLastKeyPress > timeSinceLastKeyPress )
326 { /* The DWORD went over it's boundery?? Ergo assuming too slow??. */
327 for ( idx = 0; idx < nSize; idx++ )
329 LISTVIEW_InitLvItemStruct( item, idx, TEXT );
330 ListView_GetItemA( hwnd, &item );
332 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
334 nItem = idx;
335 break;
338 strcpy( infoPtr->szSearchParam, szCharCode );
339 infoPtr->nSearchParamLength = 1;
341 else
342 { /* Save szCharCode for use in later searches */
343 strcpy( infoPtr->szSearchParam, szCharCode );
344 infoPtr->nSearchParamLength = 1;
346 LISTVIEW_InitLvItemStruct( item, infoPtr->nFocusedItem + 1, TEXT );
347 ListView_GetItemA( hwnd, &item );
349 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
350 nItem = infoPtr->nFocusedItem + 1;
351 else
352 { /*
353 * Ok so there are no more folders that match
354 * now we look for files.
356 for ( idx = infoPtr->nFocusedItem + 1; idx < nSize; idx ++ )
358 LISTVIEW_InitLvItemStruct( item, idx, TEXT );
359 ListView_GetItemA( hwnd, &item );
361 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
363 nItem = idx;
364 bFoundMatchingFiles = TRUE;
365 break;
368 if ( !bFoundMatchingFiles )
369 { /* go back to first instance */
370 for ( idx = 0; idx < nSize; idx ++ )
372 LISTVIEW_InitLvItemStruct( item,idx, TEXT );
373 ListView_GetItemA( hwnd, &item );
375 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
377 nItem = idx;
378 break;
384 } /*END: if ( infoPtr->charCode == charCode )*/
386 else /* different keypressed */
388 /* could be that they are spelling the file/directory for us */
389 if ( timeSinceLastKeyPress - infoPtr->timeSinceLastKeyPress > KEY_DELAY )
390 { /*
391 * Too slow, move to the first instance of the
392 * charCode.
394 for ( idx = 0; idx < nSize; idx++ )
396 LISTVIEW_InitLvItemStruct( item,idx, TEXT );
397 ListView_GetItemA( hwnd, &item );
399 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
401 nItem = idx;
402 break;
405 strcpy( infoPtr->szSearchParam, szCharCode );
406 infoPtr->nSearchParamLength = 1;
408 else if ( infoPtr->timeSinceLastKeyPress > timeSinceLastKeyPress )
409 { /* The DWORD went over it's boundery?? Ergo assuming too slow??. */
410 for ( idx = 0; idx < nSize; idx++ )
412 LISTVIEW_InitLvItemStruct( item,idx, TEXT );
413 ListView_GetItemA( hwnd, &item );
415 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
417 nItem = idx;
418 break;
421 strcpy( infoPtr->szSearchParam, szCharCode );
422 infoPtr->nSearchParamLength = 1;
424 else /* Search for the string the user is typing */
426 /* append new character to search string */
427 strcat( infoPtr->szSearchParam, szCharCode );
428 infoPtr->nSearchParamLength++;
430 /* loop from start of list view */
431 for( idx = 0; idx < nSize; idx++ )
432 { /* get item */
433 LISTVIEW_InitLvItemStruct( item, idx, TEXT );
434 ListView_GetItemA( hwnd, &item );
436 /* compare items */
437 if ( strncasecmp( item.pszText, infoPtr->szSearchParam,
438 infoPtr->nSearchParamLength ) == 0 )
440 nItem = idx;
441 break;
445 }/*END: else */
447 else
448 return 0;
450 bRedraw = LISTVIEW_KeySelection(hwnd, nItem );
451 if (bRedraw != FALSE)
453 /* refresh client area */
454 InvalidateRect(hwnd, NULL, TRUE);
455 UpdateWindow(hwnd);
458 /* Store the WM_CHAR for next time */
459 infoPtr->charCode = charCode;
461 /* Store time */
462 infoPtr->timeSinceLastKeyPress = timeSinceLastKeyPress;
464 return 0;
468 /*************************************************************************
469 * LISTVIEW_UpdateHeaderSize [Internal]
471 * Function to resize the header control
473 * PARAMS
474 * hwnd [I] handle to a window
475 * nNewScrollPos [I] Scroll Pos to Set
477 * RETURNS
478 * nothing
480 * NOTES
482 static VOID LISTVIEW_UpdateHeaderSize(HWND hwnd, INT nNewScrollPos)
484 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
485 RECT winRect;
486 POINT point[2];
488 GetWindowRect(infoPtr->hwndHeader, &winRect);
489 point[0].x = winRect.left;
490 point[0].y = winRect.top;
491 point[1].x = winRect.right;
492 point[1].y = winRect.bottom;
494 MapWindowPoints(HWND_DESKTOP, hwnd, point, 2);
495 point[0].x = -(nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
496 point[1].x += (nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
498 SetWindowPos(infoPtr->hwndHeader,0,
499 point[0].x,point[0].y,point[1].x,point[1].y,
500 SWP_NOZORDER | SWP_NOACTIVATE);
503 /***
504 * DESCRIPTION:
505 * Update the scrollbars. This functions should be called whenever
506 * the content, size or view changes.
508 * PARAMETER(S):
509 * [I] HWND : window handle
511 * RETURN:
512 * None
514 static VOID LISTVIEW_UpdateScroll(HWND hwnd)
516 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
517 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
518 UINT uView = lStyle & LVS_TYPEMASK;
519 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
520 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
521 SCROLLINFO scrollInfo;
523 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
524 scrollInfo.cbSize = sizeof(SCROLLINFO);
526 if (uView == LVS_LIST)
528 /* update horizontal scrollbar */
530 INT nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
531 INT nCountPerRow = LISTVIEW_GetCountPerRow(hwnd);
532 INT nNumOfItems = GETITEMCOUNT(infoPtr);
534 scrollInfo.nMax = nNumOfItems / nCountPerColumn;
535 if((nNumOfItems % nCountPerColumn) == 0)
537 scrollInfo.nMax--;
539 scrollInfo.nPos = ListView_GetTopIndex(hwnd) / nCountPerColumn;
540 scrollInfo.nPage = nCountPerRow;
541 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
542 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
544 else if (uView == LVS_REPORT)
546 /* update vertical scrollbar */
547 scrollInfo.nMin = 0;
548 scrollInfo.nMax = GETITEMCOUNT(infoPtr) - 1;
549 scrollInfo.nPos = ListView_GetTopIndex(hwnd);
550 scrollInfo.nPage = LISTVIEW_GetCountPerColumn(hwnd);
551 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
552 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
554 /* update horizontal scrollbar */
555 nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
556 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE
557 || GETITEMCOUNT(infoPtr) == 0)
559 scrollInfo.nPos = 0;
561 scrollInfo.nMin = 0;
562 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE ;
563 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
564 scrollInfo.nMax = max(infoPtr->nItemWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
565 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
567 /* Update the Header Control */
568 scrollInfo.fMask = SIF_POS;
569 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
570 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
573 else
575 RECT rcView;
577 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
579 INT nViewWidth = rcView.right - rcView.left;
580 INT nViewHeight = rcView.bottom - rcView.top;
582 /* Update Horizontal Scrollbar */
583 scrollInfo.fMask = SIF_POS;
584 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE
585 || GETITEMCOUNT(infoPtr) == 0)
587 scrollInfo.nPos = 0;
589 scrollInfo.nMax = max(nViewWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
590 scrollInfo.nMin = 0;
591 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
592 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
593 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
595 /* Update Vertical Scrollbar */
596 nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
597 scrollInfo.fMask = SIF_POS;
598 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) == FALSE
599 || GETITEMCOUNT(infoPtr) == 0)
601 scrollInfo.nPos = 0;
603 scrollInfo.nMax = max(nViewHeight / LISTVIEW_SCROLL_DIV_SIZE,0)-1;
604 scrollInfo.nMin = 0;
605 scrollInfo.nPage = nListHeight / LISTVIEW_SCROLL_DIV_SIZE;
606 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
607 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
612 /***
613 * DESCRIPTION:
614 * Prints a message for unsupported window styles.
615 * A kind of TODO list for window styles.
617 * PARAMETER(S):
618 * [I] LONG : window style
620 * RETURN:
621 * None
623 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle)
625 if ((LVS_TYPEMASK & lStyle) == LVS_EDITLABELS)
627 FIXME(" LVS_EDITLABELS\n");
630 if ((LVS_TYPEMASK & lStyle) == LVS_NOLABELWRAP)
632 FIXME(" LVS_NOLABELWRAP\n");
635 if ((LVS_TYPEMASK & lStyle) == LVS_NOSCROLL)
637 FIXME(" LVS_NOSCROLL\n");
640 if ((LVS_TYPEMASK & lStyle) == LVS_NOSORTHEADER)
642 FIXME(" LVS_NOSORTHEADER\n");
645 if ((LVS_TYPEMASK & lStyle) == LVS_OWNERDRAWFIXED)
647 FIXME(" LVS_OWNERDRAWFIXED\n");
650 if ((LVS_TYPEMASK & lStyle) == LVS_SHAREIMAGELISTS)
652 FIXME(" LVS_SHAREIMAGELISTS\n");
655 if ((LVS_TYPEMASK & lStyle) == LVS_SORTASCENDING)
657 FIXME(" LVS_SORTASCENDING\n");
660 if ((LVS_TYPEMASK & lStyle) == LVS_SORTDESCENDING)
662 FIXME(" LVS_SORTDESCENDING\n");
666 /***
667 * DESCRIPTION:
668 * Aligns the items with the top edge of the window.
670 * PARAMETER(S):
671 * [I] HWND : window handle
673 * RETURN:
674 * None
676 static VOID LISTVIEW_AlignTop(HWND hwnd)
678 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
679 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
680 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
681 POINT ptItem;
682 RECT rcView;
683 INT i;
685 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
687 ZeroMemory(&ptItem, sizeof(POINT));
688 ZeroMemory(&rcView, sizeof(RECT));
690 if (nListWidth > infoPtr->nItemWidth)
692 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
694 if (ptItem.x + infoPtr->nItemWidth > nListWidth)
696 ptItem.x = 0;
697 ptItem.y += infoPtr->nItemHeight;
700 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
701 ptItem.x += infoPtr->nItemWidth;
702 rcView.right = max(rcView.right, ptItem.x);
705 rcView.bottom = ptItem.y + infoPtr->nItemHeight;
707 else
709 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
711 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
712 ptItem.y += infoPtr->nItemHeight;
715 rcView.right = infoPtr->nItemWidth;
716 rcView.bottom = ptItem.y;
719 LISTVIEW_SetViewRect(hwnd, &rcView);
723 /***
724 * DESCRIPTION:
725 * Aligns the items with the left edge of the window.
727 * PARAMETER(S):
728 * [I] HWND : window handle
730 * RETURN:
731 * None
733 static VOID LISTVIEW_AlignLeft(HWND hwnd)
735 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
736 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
737 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
738 POINT ptItem;
739 RECT rcView;
740 INT i;
742 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
744 ZeroMemory(&ptItem, sizeof(POINT));
745 ZeroMemory(&rcView, sizeof(RECT));
747 if (nListHeight > infoPtr->nItemHeight)
749 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
751 if (ptItem.y + infoPtr->nItemHeight > nListHeight)
753 ptItem.y = 0;
754 ptItem.x += infoPtr->nItemWidth;
757 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
758 ptItem.y += infoPtr->nItemHeight;
759 rcView.bottom = max(rcView.bottom, ptItem.y);
762 rcView.right = ptItem.x + infoPtr->nItemWidth;
764 else
766 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
768 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
769 ptItem.x += infoPtr->nItemWidth;
772 rcView.bottom = infoPtr->nItemHeight;
773 rcView.right = ptItem.x;
776 LISTVIEW_SetViewRect(hwnd, &rcView);
780 /***
781 * DESCRIPTION:
782 * Set the bounding rectangle of all the items.
784 * PARAMETER(S):
785 * [I] HWND : window handle
786 * [I] LPRECT : bounding rectangle
788 * RETURN:
789 * SUCCESS : TRUE
790 * FAILURE : FALSE
792 static LRESULT LISTVIEW_SetViewRect(HWND hwnd, LPRECT lprcView)
794 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
795 BOOL bResult = FALSE;
797 TRACE("(hwnd=%x, left=%d, top=%d, right=%d, bottom=%d)\n", hwnd,
798 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
800 if (lprcView != NULL)
802 bResult = TRUE;
803 infoPtr->rcView.left = lprcView->left;
804 infoPtr->rcView.top = lprcView->top;
805 infoPtr->rcView.right = lprcView->right;
806 infoPtr->rcView.bottom = lprcView->bottom;
809 return bResult;
812 /***
813 * DESCRIPTION:
814 * Retrieves the bounding rectangle of all the items.
816 * PARAMETER(S):
817 * [I] HWND : window handle
818 * [O] LPRECT : bounding rectangle
820 * RETURN:
821 * SUCCESS : TRUE
822 * FAILURE : FALSE
824 static LRESULT LISTVIEW_GetViewRect(HWND hwnd, LPRECT lprcView)
826 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
827 BOOL bResult = FALSE;
828 POINT ptOrigin;
830 TRACE("(hwnd=%x, lprcView=%p)\n", hwnd, lprcView);
832 if (lprcView != NULL)
834 bResult = LISTVIEW_GetOrigin(hwnd, &ptOrigin);
835 if (bResult != FALSE)
837 lprcView->left = infoPtr->rcView.left + ptOrigin.x;
838 lprcView->top = infoPtr->rcView.top + ptOrigin.y;
839 lprcView->right = infoPtr->rcView.right + ptOrigin.x;
840 lprcView->bottom = infoPtr->rcView.bottom + ptOrigin.y;
843 TRACE("(left=%d, top=%d, right=%d, bottom=%d)\n",
844 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
847 return bResult;
850 /***
851 * DESCRIPTION:
852 * Retrieves the subitem pointer associated with the subitem index.
854 * PARAMETER(S):
855 * [I] HDPA : DPA handle for a specific item
856 * [I] INT : index of subitem
858 * RETURN:
859 * SUCCESS : subitem pointer
860 * FAILURE : NULL
862 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems,
863 INT nSubItem)
865 LISTVIEW_SUBITEM *lpSubItem;
866 INT i;
868 for (i = 1; i < hdpaSubItems->nItemCount; i++)
870 lpSubItem = (LISTVIEW_SUBITEM *) DPA_GetPtr(hdpaSubItems, i);
871 if (lpSubItem != NULL)
873 if (lpSubItem->iSubItem == nSubItem)
875 return lpSubItem;
880 return NULL;
883 /***
884 * DESCRIPTION:
885 * Calculates the width of an item.
887 * PARAMETER(S):
888 * [I] HWND : window handle
889 * [I] LONG : window style
891 * RETURN:
892 * Returns item width.
894 static INT LISTVIEW_GetItemWidth(HWND hwnd)
896 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
897 LONG style = GetWindowLongA(hwnd, GWL_STYLE);
898 UINT uView = style & LVS_TYPEMASK;
899 INT nHeaderItemCount;
900 RECT rcHeaderItem;
901 INT nItemWidth = 0;
902 INT nLabelWidth;
903 INT i;
905 TRACE("(hwnd=%x)\n", hwnd);
907 if (uView == LVS_ICON)
909 nItemWidth = infoPtr->iconSpacing.cx;
911 else if (uView == LVS_REPORT && (!(LVS_NOCOLUMNHEADER & style)) )
913 /* calculate width of header */
914 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
915 for (i = 0; i < nHeaderItemCount; i++)
917 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
919 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
923 else
925 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
927 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, i);
928 nItemWidth = max(nItemWidth, nLabelWidth);
931 /* default label size */
932 if (GETITEMCOUNT(infoPtr) == 0)
934 nItemWidth = DEFAULT_COLUMN_WIDTH;
936 else
938 if (nItemWidth == 0)
940 nItemWidth = DEFAULT_LABEL_WIDTH;
942 else
944 /* add padding */
945 nItemWidth += WIDTH_PADDING;
947 if (infoPtr->himlSmall != NULL)
949 nItemWidth += infoPtr->iconSize.cx;
952 if (infoPtr->himlState != NULL)
954 nItemWidth += infoPtr->iconSize.cx;
959 if(nItemWidth == 0)
961 /* nItemWidth Cannot be Zero */
962 nItemWidth = 1;
964 return nItemWidth;
967 /***
968 * DESCRIPTION:
969 * Calculates the width of a specific item.
971 * PARAMETER(S):
972 * [I] HWND : window handle
973 * [I] LPSTR : string
975 * RETURN:
976 * Returns the width of an item width a specified string.
978 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem)
980 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
981 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
982 INT nHeaderItemCount;
983 RECT rcHeaderItem;
984 INT nItemWidth = 0;
985 INT i;
987 TRACE("(hwnd=%x)\n", hwnd);
989 if (uView == LVS_ICON)
991 nItemWidth = infoPtr->iconSpacing.cx;
993 else if (uView == LVS_REPORT)
995 /* calculate width of header */
996 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
997 for (i = 0; i < nHeaderItemCount; i++)
999 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
1001 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
1005 else
1007 /* get width of string */
1008 nItemWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
1010 /* default label size */
1011 if (GETITEMCOUNT(infoPtr) == 0)
1013 nItemWidth = DEFAULT_COLUMN_WIDTH;
1015 else
1017 if (nItemWidth == 0)
1019 nItemWidth = DEFAULT_LABEL_WIDTH;
1021 else
1023 /* add padding */
1024 nItemWidth += WIDTH_PADDING;
1026 if (infoPtr->himlSmall != NULL)
1028 nItemWidth += infoPtr->iconSize.cx;
1031 if (infoPtr->himlState != NULL)
1033 nItemWidth += infoPtr->iconSize.cx;
1039 return nItemWidth;
1042 /***
1043 * DESCRIPTION:
1044 * Calculates the height of an item.
1046 * PARAMETER(S):
1047 * [I] HWND : window handle
1048 * [I] LONG : window style
1050 * RETURN:
1051 * Returns item height.
1053 static INT LISTVIEW_GetItemHeight(HWND hwnd)
1055 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1056 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
1057 INT nItemHeight = 0;
1059 if (uView == LVS_ICON)
1061 nItemHeight = infoPtr->iconSpacing.cy;
1063 else
1065 TEXTMETRICA tm;
1066 HDC hdc = GetDC(hwnd);
1067 HFONT hOldFont = SelectObject(hdc, infoPtr->hFont);
1068 GetTextMetricsA(hdc, &tm);
1070 if(infoPtr->himlState || infoPtr->himlSmall)
1071 nItemHeight = max(tm.tmHeight, infoPtr->iconSize.cy) + HEIGHT_PADDING;
1072 else
1073 nItemHeight = tm.tmHeight;
1075 SelectObject(hdc, hOldFont);
1076 ReleaseDC(hwnd, hdc);
1079 return nItemHeight;
1083 static void LISTVIEW_PrintSelectionRanges(hwnd)
1085 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1086 LISTVIEW_SELECTION *selection;
1087 INT topSelection = infoPtr->hdpaSelectionRanges->nItemCount;
1088 INT i;
1090 TRACE("Selections are:\n");
1091 for (i = 0; i < topSelection; i++)
1093 selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,i);
1094 TRACE(" %lu - %lu\n",selection->lower,selection->upper);
1098 /***
1099 * DESCRIPTION:
1100 * A compare function for selection ranges
1102 *PARAMETER(S)
1103 * [I] LPVOID : Item 1;
1104 * [I] LPVOID : Item 2;
1105 * [I] LPARAM : flags
1107 *RETURNS:
1108 * >0 : if Item 1 > Item 2
1109 * <0 : if Item 2 > Item 1
1110 * 0 : if Item 1 == Item 2
1112 static INT CALLBACK LISTVIEW_CompareSelectionRanges(LPVOID range1, LPVOID range2,
1113 LPARAM flags)
1115 int l1 = ((LISTVIEW_SELECTION*)(range1))->lower;
1116 int l2 = ((LISTVIEW_SELECTION*)(range2))->lower;
1117 int u1 = ((LISTVIEW_SELECTION*)(range1))->upper;
1118 int u2 = ((LISTVIEW_SELECTION*)(range2))->upper;
1119 int rc=0;
1121 if (u1 < l2)
1122 rc= -1;
1124 if (u2 < l1)
1125 rc= 1;
1127 return rc;
1131 * DESCRIPTION:
1132 * Adds a selection range.
1134 * PARAMETER(S):
1135 * [I] HWND : window handle
1136 * [I] INT : lower item index
1137 * [I] INT : upper item index
1139 * RETURN:
1140 * None
1142 static VOID LISTVIEW_AddSelectionRange(HWND hwnd, INT lItem, INT uItem)
1144 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1145 LISTVIEW_SELECTION *selection;
1146 INT topSelection = infoPtr->hdpaSelectionRanges->nItemCount;
1147 BOOL lowerzero=FALSE;
1149 selection = (LISTVIEW_SELECTION *)COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION));
1150 selection->lower = lItem;
1151 selection->upper = uItem;
1153 TRACE("Add range %i - %i\n",lItem,uItem);
1154 if (topSelection)
1156 LISTVIEW_SELECTION *checkselection,*checkselection2;
1157 INT index,mergeindex;
1159 /* find overlapping selections */
1160 /* we want to catch adjacent ranges so expand our range by 1 */
1162 selection->upper++;
1163 if (selection->lower == 0)
1164 lowerzero = TRUE;
1165 else
1166 selection->lower--;
1168 index = DPA_Search(infoPtr->hdpaSelectionRanges, selection, 0,
1169 LISTVIEW_CompareSelectionRanges,
1170 0,0);
1171 selection->upper --;
1172 if (lowerzero)
1173 lowerzero=FALSE;
1174 else
1175 selection->lower ++;
1177 if (index >=0)
1179 checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,index);
1180 TRACE("Merge with index %i (%lu - %lu)\n",index,checkselection->lower,
1181 checkselection->upper);
1183 checkselection->lower = min(selection->lower,checkselection->lower);
1184 checkselection->upper = max(selection->upper,checkselection->upper);
1186 TRACE("New range (%lu - %lu)\n", checkselection->lower,
1187 checkselection->upper);
1189 COMCTL32_Free(selection);
1191 /* merge now common selection ranges in the lower group*/
1194 checkselection->upper ++;
1195 if (checkselection->lower == 0)
1196 lowerzero = TRUE;
1197 else
1198 checkselection->lower --;
1200 TRACE("search lower range (%lu - %lu)\n", checkselection->lower,
1201 checkselection->upper);
1203 /* not sorted yet */
1204 mergeindex = DPA_Search(infoPtr->hdpaSelectionRanges, checkselection, 0,
1205 LISTVIEW_CompareSelectionRanges, 0,
1208 checkselection->upper --;
1209 if (lowerzero)
1210 lowerzero = FALSE;
1211 else
1212 checkselection->lower ++;
1214 if (mergeindex >=0 && mergeindex != index)
1216 TRACE("Merge with index %i\n",mergeindex);
1217 checkselection2 = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
1218 mergeindex);
1219 checkselection->lower = min(checkselection->lower,
1220 checkselection2->lower);
1221 checkselection->upper = max(checkselection->upper,
1222 checkselection2->upper);
1223 COMCTL32_Free(checkselection2);
1224 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,mergeindex);
1225 index --;
1228 while (mergeindex > -1 && mergeindex <index);
1230 /* merge now common selection ranges in the upper group*/
1233 checkselection->upper ++;
1234 if (checkselection->lower == 0)
1235 lowerzero = TRUE;
1236 else
1237 checkselection->lower --;
1239 TRACE("search upper range %i (%lu - %lu)\n",index,
1240 checkselection->lower, checkselection->upper);
1242 /* not sorted yet */
1243 mergeindex = DPA_Search(infoPtr->hdpaSelectionRanges, checkselection,
1244 index+1,
1245 LISTVIEW_CompareSelectionRanges, 0,
1248 checkselection->upper --;
1249 if (lowerzero)
1250 lowerzero = FALSE;
1251 else
1252 checkselection->lower ++;
1254 if (mergeindex >=0 && mergeindex !=index)
1256 TRACE("Merge with index %i\n",mergeindex);
1257 checkselection2 = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
1258 mergeindex);
1259 checkselection->lower = min(checkselection->lower,
1260 checkselection2->lower);
1261 checkselection->upper = max(checkselection->upper,
1262 checkselection2->upper);
1263 COMCTL32_Free(checkselection2);
1264 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,mergeindex);
1267 while (mergeindex > -1);
1269 else
1272 index = DPA_Search(infoPtr->hdpaSelectionRanges, selection, 0,
1273 LISTVIEW_CompareSelectionRanges, 0,
1274 DPAS_INSERTAFTER);
1276 TRACE("Insert before index %i\n",index);
1277 if (index == -1)
1278 index = 0;
1279 DPA_InsertPtr(infoPtr->hdpaSelectionRanges,index,selection);
1282 else
1284 DPA_InsertPtr(infoPtr->hdpaSelectionRanges,0,selection);
1287 * Incase of error
1289 DPA_Sort(infoPtr->hdpaSelectionRanges,LISTVIEW_CompareSelectionRanges,0);
1290 LISTVIEW_PrintSelectionRanges(hwnd);
1294 * DESCRIPTION:
1295 * check if a specified index is selected.
1297 * PARAMETER(S):
1298 * [I] HWND : window handle
1299 * [I] INT : item index
1301 * RETURN:
1302 * None
1304 static BOOL LISTVIEW_IsSelected(HWND hwnd, INT nItem)
1306 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1307 LISTVIEW_SELECTION selection;
1308 INT index;
1310 selection.upper = nItem;
1311 selection.lower = nItem;
1313 index = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, 0,
1314 LISTVIEW_CompareSelectionRanges,
1315 0,DPAS_SORTED);
1316 if (index != -1)
1317 return TRUE;
1318 else
1319 return FALSE;
1322 /***
1323 * DESCRIPTION:
1324 * Removes all selection ranges
1326 * Parameters(s):
1327 * HWND: window handle
1329 * RETURNS:
1330 * SUCCESS : TRUE
1331 * FAILURE : TRUE
1333 static LRESULT LISTVIEW_RemoveAllSelections(HWND hwnd)
1335 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1336 LISTVIEW_SELECTION *selection;
1337 INT i;
1338 LVITEMA item;
1340 TRACE("(0x%x)\n",hwnd);
1342 ZeroMemory(&item,sizeof(LVITEMA));
1343 item.stateMask = LVIS_SELECTED;
1347 selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,0);
1348 if (selection)
1350 TRACE("Removing %lu to %lu\n",selection->lower, selection->upper);
1351 for (i = selection->lower; i<=selection->upper; i++)
1352 LISTVIEW_SetItemState(hwnd,i,&item);
1355 while (infoPtr->hdpaSelectionRanges->nItemCount>0);
1357 TRACE("done\n");
1359 return TRUE;
1363 * DESCRIPTION:
1364 * Removes a range selections.
1366 * PARAMETER(S):
1367 * [I] HWND : window handle
1368 * [I] INT : lower item index
1369 * [I] INT : upper item index
1371 * RETURN:
1372 * None
1374 static VOID LISTVIEW_RemoveSelectionRange(HWND hwnd, INT lItem, INT uItem)
1376 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1377 LISTVIEW_SELECTION removeselection,*checkselection;
1378 INT index;
1380 removeselection.lower = lItem;
1381 removeselection.upper = uItem;
1383 TRACE("Remove range %lu - %lu\n",removeselection.lower,removeselection.upper);
1384 LISTVIEW_PrintSelectionRanges(hwnd);
1386 index = DPA_Search(infoPtr->hdpaSelectionRanges, &removeselection, 0,
1387 LISTVIEW_CompareSelectionRanges,
1388 0,0);
1390 if (index == -1)
1391 return;
1394 checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
1395 index);
1397 TRACE("Matches range index %i (%lu-%lu)\n",index,checkselection->lower,
1398 checkselection->upper);
1400 /* case 1: Same */
1401 if ((checkselection->upper == removeselection.upper) &&
1402 (checkselection->lower == removeselection.lower))
1404 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,index);
1405 TRACE("Case 1\n");
1407 /* case 2: engulf */
1408 else if (((checkselection->upper < removeselection.upper) &&
1409 (checkselection->lower > removeselection.lower))||
1410 ((checkselection->upper <= removeselection.upper) &&
1411 (checkselection->lower > removeselection.lower)) ||
1412 ((checkselection->upper < removeselection.upper) &&
1413 (checkselection->lower >= removeselection.lower)))
1416 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,index);
1417 /* do it again because others may also get caught */
1418 TRACE("Case 2\n");
1419 LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
1421 /* case 3: overlap upper */
1422 else if ((checkselection->upper < removeselection.upper) &&
1423 (checkselection->lower < removeselection.lower))
1425 checkselection->upper = removeselection.lower - 1;
1426 TRACE("Case 3\n");
1427 LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
1429 /* case 4: overlap lower */
1430 else if ((checkselection->upper > removeselection.upper) &&
1431 (checkselection->lower > removeselection.lower))
1433 checkselection->lower = removeselection.upper + 1;
1434 TRACE("Case 4\n");
1435 LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
1437 /* case 5: fully internal */
1438 else if (checkselection->upper == removeselection.upper)
1439 checkselection->upper = removeselection.lower - 1;
1440 else if (checkselection->lower == removeselection.lower)
1441 checkselection->lower = removeselection.upper + 1;
1442 else
1444 /* bisect the range */
1445 LISTVIEW_SELECTION *newselection;
1447 newselection = (LISTVIEW_SELECTION *)
1448 COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION));
1449 newselection -> lower = checkselection->lower;
1450 newselection -> upper = removeselection.lower - 1;
1451 checkselection -> lower = removeselection.upper + 1;
1452 DPA_InsertPtr(infoPtr->hdpaSelectionRanges,index,newselection);
1453 TRACE("Case 5\n");
1454 DPA_Sort(infoPtr->hdpaSelectionRanges,LISTVIEW_CompareSelectionRanges,0);
1456 LISTVIEW_PrintSelectionRanges(hwnd);
1460 * DESCRIPTION:
1461 * shifts all selection indexs starting with the indesx specified
1462 * in the direction specified.
1464 * PARAMETER(S):
1465 * [I] HWND : window handle
1466 * [I] INT : item index
1467 * [I] INT : amount and direction of shift
1469 * RETURN:
1470 * None
1472 static VOID LISTVIEW_ShiftSelections(HWND hwnd, INT nItem, INT direction)
1474 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1475 LISTVIEW_SELECTION selection,*checkselection;
1476 INT index;
1478 selection.upper = nItem;
1479 selection.lower = nItem;
1481 index = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, 0,
1482 LISTVIEW_CompareSelectionRanges,
1483 0,DPAS_SORTED|DPAS_INSERTAFTER);
1485 while ((index < infoPtr->hdpaSelectionRanges->nItemCount)&&(index != -1))
1487 checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,index);
1488 if (checkselection->lower >= nItem)
1489 checkselection->lower += direction;
1490 if (checkselection->upper >= nItem)
1491 checkselection->upper += direction;
1492 index ++;
1498 * DESCRIPTION:
1499 * Adds a block of selections.
1501 * PARAMETER(S):
1502 * [I] HWND : window handle
1503 * [I] INT : item index
1505 * RETURN:
1506 * None
1508 static VOID LISTVIEW_AddGroupSelection(HWND hwnd, INT nItem)
1510 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1511 INT nFirst = min(infoPtr->nSelectionMark, nItem);
1512 INT nLast = max(infoPtr->nSelectionMark, nItem);
1513 INT i;
1514 LVITEMA item;
1516 ZeroMemory(&item,sizeof(LVITEMA));
1517 item.stateMask = LVIS_SELECTED;
1518 item.state = LVIS_SELECTED;
1520 for (i = nFirst; i <= nLast; i++);
1522 LISTVIEW_SetItemState(hwnd,i,&item);
1525 LISTVIEW_SetItemFocus(hwnd, nItem);
1526 infoPtr->nSelectionMark = nItem;
1530 /***
1531 * DESCRIPTION:
1532 * Adds a single selection.
1534 * PARAMETER(S):
1535 * [I] HWND : window handle
1536 * [I] INT : item index
1538 * RETURN:
1539 * None
1541 static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem)
1543 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1544 LVITEMA item;
1546 ZeroMemory(&item,sizeof(LVITEMA));
1547 item.state = LVIS_SELECTED;
1548 item.stateMask = LVIS_SELECTED;
1550 LISTVIEW_SetItemState(hwnd,nItem,&item);
1552 LISTVIEW_SetItemFocus(hwnd, nItem);
1553 infoPtr->nSelectionMark = nItem;
1556 /***
1557 * DESCRIPTION:
1558 * Selects or unselects an item.
1560 * PARAMETER(S):
1561 * [I] HWND : window handle
1562 * [I] INT : item index
1564 * RETURN:
1565 * SELECT: TRUE
1566 * UNSELECT : FALSE
1568 static BOOL LISTVIEW_ToggleSelection(HWND hwnd, INT nItem)
1570 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1571 BOOL bResult;
1572 LVITEMA item;
1574 ZeroMemory(&item,sizeof(LVITEMA));
1575 item.stateMask = LVIS_SELECTED;
1577 if (LISTVIEW_IsSelected(hwnd,nItem))
1580 LISTVIEW_SetItemState(hwnd,nItem,&item);
1581 bResult = FALSE;
1583 else
1585 item.state = LVIS_SELECTED;
1586 LISTVIEW_SetItemState(hwnd,nItem,&item);
1587 bResult = TRUE;
1590 LISTVIEW_SetItemFocus(hwnd, nItem);
1591 infoPtr->nSelectionMark = nItem;
1593 return bResult;
1596 /***
1597 * DESCRIPTION:
1598 * Selects items based on view coorddiantes.
1600 * PARAMETER(S):
1601 * [I] HWND : window handle
1602 * [I] RECT : selection rectangle
1604 * RETURN:
1605 * None
1607 static VOID LISTVIEW_SetSelectionRect(HWND hwnd, RECT rcSelRect)
1609 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1610 POINT ptItem;
1611 INT i;
1612 LVITEMA item;
1614 ZeroMemory(&item,sizeof(LVITEMA));
1615 item.stateMask = LVIS_SELECTED;
1617 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
1619 LISTVIEW_GetItemPosition(hwnd, i, &ptItem);
1621 if (PtInRect(&rcSelRect, ptItem) != FALSE)
1623 item.state = LVIS_SELECTED;
1624 LISTVIEW_SetItemState(hwnd,i,&item);
1626 else
1628 item.state = 0;
1629 LISTVIEW_SetItemState(hwnd,i,&item);
1634 /***
1635 * DESCRIPTION:
1636 * Sets a single group selection.
1638 * PARAMETER(S):
1639 * [I] HWND : window handle
1640 * [I] INT : item index
1642 * RETURN:
1643 * None
1645 static VOID LISTVIEW_SetGroupSelection(HWND hwnd, INT nItem)
1647 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1648 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
1649 LVITEMA item;
1651 ZeroMemory(&item,sizeof(LVITEMA));
1652 item.stateMask = LVIS_SELECTED;
1654 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
1656 INT i;
1657 INT nFirst = min(infoPtr->nSelectionMark, nItem);
1658 INT nLast = max(infoPtr->nSelectionMark, nItem);
1660 for (i = 0; i <= GETITEMCOUNT(infoPtr); i++)
1662 if ((i < nFirst) || (i > nLast))
1664 item.state = 0;
1665 LISTVIEW_SetItemState(hwnd,i,&item);
1667 else
1669 item.state = LVIS_SELECTED;
1670 LISTVIEW_SetItemState(hwnd,i,&item);
1674 else
1676 POINT ptItem;
1677 POINT ptSelMark;
1678 RECT rcSel;
1679 LISTVIEW_GetItemPosition(hwnd, nItem, &ptItem);
1680 LISTVIEW_GetItemPosition(hwnd, infoPtr->nSelectionMark, &ptSelMark);
1681 rcSel.left = min(ptSelMark.x, ptItem.x);
1682 rcSel.top = min(ptSelMark.y, ptItem.y);
1683 rcSel.right = max(ptSelMark.x, ptItem.x) + infoPtr->nItemWidth;
1684 rcSel.bottom = max(ptSelMark.y, ptItem.y) + infoPtr->nItemHeight;
1685 LISTVIEW_SetSelectionRect(hwnd, rcSel);
1688 LISTVIEW_SetItemFocus(hwnd, nItem);
1691 /***
1692 * DESCRIPTION:
1693 * Manages the item focus.
1695 * PARAMETER(S):
1696 * [I] HWND : window handle
1697 * [I] INT : item index
1699 * RETURN:
1700 * TRUE : focused item changed
1701 * FALSE : focused item has NOT changed
1703 static BOOL LISTVIEW_SetItemFocus(HWND hwnd, INT nItem)
1705 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1706 BOOL bResult = FALSE;
1707 LVITEMA lvItem;
1709 if (infoPtr->nFocusedItem != nItem)
1711 if (infoPtr->nFocusedItem >= 0)
1713 INT oldFocus = infoPtr->nFocusedItem;
1714 bResult = TRUE;
1715 infoPtr->nFocusedItem = -1;
1716 ZeroMemory(&lvItem, sizeof(LVITEMA));
1717 lvItem.stateMask = LVIS_FOCUSED;
1718 ListView_SetItemState(hwnd, oldFocus, &lvItem);
1722 lvItem.state = LVIS_FOCUSED;
1723 lvItem.stateMask = LVIS_FOCUSED;
1724 ListView_SetItemState(hwnd, nItem, &lvItem);
1726 infoPtr->nFocusedItem = nItem;
1727 ListView_EnsureVisible(hwnd, nItem, FALSE);
1730 return bResult;
1733 /***
1734 * DESCRIPTION:
1735 * Sets a single selection.
1737 * PARAMETER(S):
1738 * [I] HWND : window handle
1739 * [I] INT : item index
1741 * RETURN:
1742 * None
1744 static VOID LISTVIEW_SetSelection(HWND hwnd, INT nItem)
1746 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1747 LVITEMA lvItem;
1749 ZeroMemory(&lvItem, sizeof(LVITEMA));
1750 lvItem.stateMask = LVIS_FOCUSED;
1751 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
1753 LISTVIEW_RemoveAllSelections(hwnd);
1755 lvItem.state = LVIS_FOCUSED|LVIS_SELECTED;
1756 lvItem.stateMask = LVIS_FOCUSED|LVIS_SELECTED;
1757 ListView_SetItemState(hwnd, nItem, &lvItem);
1759 infoPtr->nFocusedItem = nItem;
1760 infoPtr->nSelectionMark = nItem;
1763 /***
1764 * DESCRIPTION:
1765 * Set selection(s) with keyboard.
1767 * PARAMETER(S):
1768 * [I] HWND : window handle
1769 * [I] INT : item index
1771 * RETURN:
1772 * SUCCESS : TRUE (needs to be repainted)
1773 * FAILURE : FALSE (nothing has changed)
1775 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem)
1777 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1778 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1779 WORD wShift = HIWORD(GetKeyState(VK_SHIFT));
1780 WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL));
1781 BOOL bResult = FALSE;
1783 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
1785 if (lStyle & LVS_SINGLESEL)
1787 bResult = TRUE;
1788 LISTVIEW_SetSelection(hwnd, nItem);
1789 ListView_EnsureVisible(hwnd, nItem, FALSE);
1791 else
1793 if (wShift)
1795 bResult = TRUE;
1796 LISTVIEW_SetGroupSelection(hwnd, nItem);
1798 else if (wCtrl)
1800 bResult = LISTVIEW_SetItemFocus(hwnd, nItem);
1802 else
1804 bResult = TRUE;
1805 LISTVIEW_SetSelection(hwnd, nItem);
1806 ListView_EnsureVisible(hwnd, nItem, FALSE);
1811 return bResult;
1814 /***
1815 * DESCRIPTION:
1816 * Called when the mouse is being actively tracked and has hovered for a specified
1817 * amount of time
1819 * PARAMETER(S):
1820 * [I] HWND : window handle
1821 * [I] wParam : key indicator
1822 * [I] lParam : mouse position
1824 * RETURN:
1825 * 0 if the message was processed, non-zero if there was an error
1827 * INFO:
1828 * LVS_EX_TRACKSELECT: An item is automatically selected when the cursor remains
1829 * over the item for a certain period of time.
1832 static LRESULT LISTVIEW_MouseHover(hwnd, wParam, lParam)
1834 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1835 POINT pt;
1837 pt.x = (INT)LOWORD(lParam);
1838 pt.y = (INT)HIWORD(lParam);
1840 if(infoPtr->dwExStyle & LVS_EX_TRACKSELECT) {
1841 /* select the item under the cursor */
1842 LISTVIEW_MouseSelection(hwnd, pt);
1845 return 0;
1848 /***
1849 * DESCRIPTION:
1850 * Called whenever WM_MOUSEMOVE is recieved.
1852 * PARAMETER(S):
1853 * [I] HWND : window handle
1854 * [I] wParam : key indicators
1855 * [I] lParam : cursor position
1857 * RETURN:
1858 * 0 if the message is processed, non-zero if there was an error
1860 static LRESULT LISTVIEW_MouseMove(HWND hwnd, WPARAM wParam, LPARAM lParam)
1862 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1863 TRACKMOUSEEVENT trackinfo;
1865 /* see if we are supposed to be tracking mouse hovering */
1866 if(infoPtr->dwExStyle & LVS_EX_TRACKSELECT) {
1867 /* fill in the trackinfo struct */
1868 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
1869 trackinfo.dwFlags = TME_QUERY;
1870 trackinfo.hwndTrack = hwnd;
1871 trackinfo.dwHoverTime = infoPtr->dwHoverTime;
1873 /* see if we are already tracking this hwnd */
1874 _TrackMouseEvent(&trackinfo);
1876 if(!(trackinfo.dwFlags & TME_HOVER)) {
1877 trackinfo.dwFlags = TME_HOVER;
1879 /* call TRACKMOUSEEVENT so we recieve WM_MOUSEHOVER messages */
1880 _TrackMouseEvent(&trackinfo);
1884 return 0;
1887 /***
1888 * DESCRIPTION:
1889 * Selects an item based on coordinates.
1891 * PARAMETER(S):
1892 * [I] HWND : window handle
1893 * [I] POINT : mouse click ccordinates
1895 * RETURN:
1896 * SUCCESS : item index
1897 * FAILURE : -1
1899 static LRESULT LISTVIEW_MouseSelection(HWND hwnd, POINT pt)
1901 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1902 RECT rcItem;
1903 INT i,topindex,bottomindex;
1904 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1905 UINT uView = lStyle & LVS_TYPEMASK;
1907 topindex = ListView_GetTopIndex(hwnd);
1908 if (uView == LVS_REPORT)
1910 bottomindex = topindex + LISTVIEW_GetCountPerColumn(hwnd) + 1;
1911 bottomindex = min(bottomindex,GETITEMCOUNT(infoPtr));
1913 else
1915 bottomindex = GETITEMCOUNT(infoPtr);
1918 for (i = topindex; i < bottomindex; i++)
1920 rcItem.left = LVIR_SELECTBOUNDS;
1921 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) == TRUE)
1923 if (PtInRect(&rcItem, pt) != FALSE)
1925 return i;
1930 return -1;
1933 /***
1934 * DESCRIPTION:
1935 * Removes a column.
1937 * PARAMETER(S):
1938 * [IO] HDPA : dynamic pointer array handle
1939 * [I] INT : column index (subitem index)
1941 * RETURN:
1942 * SUCCCESS : TRUE
1943 * FAILURE : FALSE
1945 static BOOL LISTVIEW_RemoveColumn(HDPA hdpaItems, INT nSubItem)
1947 BOOL bResult = TRUE;
1948 HDPA hdpaSubItems;
1949 INT i;
1951 for (i = 0; i < hdpaItems->nItemCount; i++)
1953 hdpaSubItems = (HDPA)DPA_GetPtr(hdpaItems, i);
1954 if (hdpaSubItems != NULL)
1956 if (LISTVIEW_RemoveSubItem(hdpaSubItems, nSubItem) == FALSE)
1958 bResult = FALSE;
1963 return bResult;
1966 /***
1967 * DESCRIPTION:
1968 * Removes a subitem at a given position.
1970 * PARAMETER(S):
1971 * [IO] HDPA : dynamic pointer array handle
1972 * [I] INT : subitem index
1974 * RETURN:
1975 * SUCCCESS : TRUE
1976 * FAILURE : FALSE
1978 static BOOL LISTVIEW_RemoveSubItem(HDPA hdpaSubItems, INT nSubItem)
1980 LISTVIEW_SUBITEM *lpSubItem;
1981 INT i;
1983 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1985 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1986 if (lpSubItem != NULL)
1988 if (lpSubItem->iSubItem == nSubItem)
1990 /* free string */
1991 if ((lpSubItem->pszText != NULL) &&
1992 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1994 COMCTL32_Free(lpSubItem->pszText);
1997 /* free item */
1998 COMCTL32_Free(lpSubItem);
2000 /* free dpa memory */
2001 if (DPA_DeletePtr(hdpaSubItems, i) == NULL)
2003 return FALSE;
2006 else if (lpSubItem->iSubItem > nSubItem)
2008 return TRUE;
2013 return TRUE;
2016 /***
2017 * DESCRIPTION:
2018 * Compares the item information.
2020 * PARAMETER(S):
2021 * [I] LISTVIEW_ITEM *: destination item
2022 * [I] LPLVITEM : source item
2024 * RETURN:
2025 * SUCCCESS : TRUE (EQUAL)
2026 * FAILURE : FALSE (NOT EQUAL)
2028 static UINT LISTVIEW_GetItemChanges(LISTVIEW_ITEM *lpItem, LPLVITEMA lpLVItem)
2030 UINT uChanged = 0;
2032 if ((lpItem != NULL) && (lpLVItem != NULL))
2034 if (lpLVItem->mask & LVIF_STATE)
2036 if ((lpItem->state & lpLVItem->stateMask) !=
2037 (lpLVItem->state & lpLVItem->stateMask))
2039 uChanged |= LVIF_STATE;
2043 if (lpLVItem->mask & LVIF_IMAGE)
2045 if (lpItem->iImage != lpLVItem->iImage)
2047 uChanged |= LVIF_IMAGE;
2051 if (lpLVItem->mask & LVIF_PARAM)
2053 if (lpItem->lParam != lpLVItem->lParam)
2055 uChanged |= LVIF_PARAM;
2059 if (lpLVItem->mask & LVIF_INDENT)
2061 if (lpItem->iIndent != lpLVItem->iIndent)
2063 uChanged |= LVIF_INDENT;
2067 if (lpLVItem->mask & LVIF_TEXT)
2069 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
2071 if (lpItem->pszText != LPSTR_TEXTCALLBACKA)
2073 uChanged |= LVIF_TEXT;
2076 else
2078 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
2080 uChanged |= LVIF_TEXT;
2082 else
2084 if (lpLVItem->pszText)
2086 if (lpItem->pszText)
2088 if (strcmp(lpLVItem->pszText, lpItem->pszText) != 0)
2090 uChanged |= LVIF_TEXT;
2093 else
2095 uChanged |= LVIF_TEXT;
2098 else
2100 if (lpItem->pszText)
2102 uChanged |= LVIF_TEXT;
2109 return uChanged;
2112 /***
2113 * DESCRIPTION:
2114 * Initializes item attributes.
2116 * PARAMETER(S):
2117 * [I] HWND : window handle
2118 * [O] LISTVIEW_ITEM *: destination item
2119 * [I] LPLVITEM : source item
2121 * RETURN:
2122 * SUCCCESS : TRUE
2123 * FAILURE : FALSE
2125 static BOOL LISTVIEW_InitItem(HWND hwnd, LISTVIEW_ITEM *lpItem,
2126 LPLVITEMA lpLVItem)
2128 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2129 BOOL bResult = FALSE;
2131 if ((lpItem != NULL) && (lpLVItem != NULL))
2133 bResult = TRUE;
2135 if (lpLVItem->mask & LVIF_STATE)
2137 lpItem->state &= ~lpLVItem->stateMask;
2138 lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
2141 if (lpLVItem->mask & LVIF_IMAGE)
2143 lpItem->iImage = lpLVItem->iImage;
2146 if (lpLVItem->mask & LVIF_PARAM)
2148 lpItem->lParam = lpLVItem->lParam;
2151 if (lpLVItem->mask & LVIF_INDENT)
2153 lpItem->iIndent = lpLVItem->iIndent;
2156 if (lpLVItem->mask & LVIF_TEXT)
2158 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
2160 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
2162 return FALSE;
2165 if ((lpItem->pszText != NULL) &&
2166 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2168 COMCTL32_Free(lpItem->pszText);
2171 lpItem->pszText = LPSTR_TEXTCALLBACKA;
2173 else
2175 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
2177 lpItem->pszText = NULL;
2180 bResult = Str_SetPtrA(&lpItem->pszText, lpLVItem->pszText);
2185 return bResult;
2188 /***
2189 * DESCRIPTION:
2190 * Initializes subitem attributes.
2192 * NOTE: The documentation specifies that the operation fails if the user
2193 * tries to set the indent of a subitem.
2195 * PARAMETER(S):
2196 * [I] HWND : window handle
2197 * [O] LISTVIEW_SUBITEM *: destination subitem
2198 * [I] LPLVITEM : source subitem
2200 * RETURN:
2201 * SUCCCESS : TRUE
2202 * FAILURE : FALSE
2204 static BOOL LISTVIEW_InitSubItem(HWND hwnd, LISTVIEW_SUBITEM *lpSubItem,
2205 LPLVITEMA lpLVItem)
2207 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2208 BOOL bResult = FALSE;
2210 if ((lpSubItem != NULL) && (lpLVItem != NULL))
2212 if (!(lpLVItem->mask & LVIF_INDENT))
2214 bResult = TRUE;
2216 lpSubItem->iSubItem = lpLVItem->iSubItem;
2218 if (lpLVItem->mask & LVIF_IMAGE)
2220 lpSubItem->iImage = lpLVItem->iImage;
2223 if (lpLVItem->mask & LVIF_TEXT)
2225 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
2227 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
2229 return FALSE;
2232 if ((lpSubItem->pszText != NULL) &&
2233 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2235 COMCTL32_Free(lpSubItem->pszText);
2238 lpSubItem->pszText = LPSTR_TEXTCALLBACKA;
2240 else
2242 if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
2244 lpSubItem->pszText = NULL;
2247 bResult = Str_SetPtrA(&lpSubItem->pszText, lpLVItem->pszText);
2253 return bResult;
2256 /***
2257 * DESCRIPTION:
2258 * Adds a subitem at a given position (column index).
2260 * PARAMETER(S):
2261 * [I] HWND : window handle
2262 * [I] LPLVITEM : new subitem atttributes
2264 * RETURN:
2265 * SUCCESS : TRUE
2266 * FAILURE : FALSE
2268 static BOOL LISTVIEW_AddSubItem(HWND hwnd, LPLVITEMA lpLVItem)
2270 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2271 LISTVIEW_SUBITEM *lpSubItem = NULL;
2272 BOOL bResult = FALSE;
2273 HDPA hdpaSubItems;
2274 INT nPosition, nItem;
2275 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2277 if (lStyle & LVS_OWNERDATA)
2278 return FALSE;
2280 if (lpLVItem != NULL)
2282 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
2283 if (hdpaSubItems != NULL)
2285 lpSubItem = (LISTVIEW_SUBITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM));
2286 if (lpSubItem != NULL)
2288 ZeroMemory(lpSubItem, sizeof(LISTVIEW_SUBITEM));
2289 if (LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem) != FALSE)
2291 nPosition = LISTVIEW_FindInsertPosition(hdpaSubItems,
2292 lpSubItem->iSubItem);
2293 nItem = DPA_InsertPtr(hdpaSubItems, nPosition, lpSubItem);
2294 if (nItem != -1)
2296 bResult = TRUE;
2303 /* cleanup if unsuccessful */
2304 if ((bResult == FALSE) && (lpSubItem != NULL))
2306 COMCTL32_Free(lpSubItem);
2309 return bResult;
2312 /***
2313 * DESCRIPTION:
2314 * Finds the dpa insert position (array index).
2316 * PARAMETER(S):
2317 * [I] HWND : window handle
2318 * [I] INT : subitem index
2320 * RETURN:
2321 * SUCCESS : TRUE
2322 * FAILURE : FALSE
2324 static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem)
2326 LISTVIEW_SUBITEM *lpSubItem;
2327 INT i;
2329 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2331 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2332 if (lpSubItem != NULL)
2334 if (lpSubItem->iSubItem > nSubItem)
2336 return i;
2341 return hdpaSubItems->nItemCount;
2344 /***
2345 * DESCRIPTION:
2346 * Retrieves a listview subitem at a given position (column index).
2348 * PARAMETER(S):
2349 * [I] HWND : window handle
2350 * [I] INT : subitem index
2352 * RETURN:
2353 * SUCCESS : TRUE
2354 * FAILURE : FALSE
2356 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem)
2358 LISTVIEW_SUBITEM *lpSubItem;
2359 INT i;
2361 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2363 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2364 if (lpSubItem != NULL)
2366 if (lpSubItem->iSubItem == nSubItem)
2368 return lpSubItem;
2370 else if (lpSubItem->iSubItem > nSubItem)
2372 return NULL;
2377 return NULL;
2380 /***
2381 * DESCRIPTION:
2382 * Sets item attributes.
2384 * PARAMETER(S):
2385 * [I] HWND : window handle
2386 * [I] LPLVITEM : new item atttributes
2388 * RETURN:
2389 * SUCCESS : TRUE
2390 * FAILURE : FALSE
2392 static BOOL LISTVIEW_SetItem(HWND hwnd, LPLVITEMA lpLVItem)
2394 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2395 BOOL bResult = FALSE;
2396 HDPA hdpaSubItems;
2397 LISTVIEW_ITEM *lpItem;
2398 NMLISTVIEW nmlv;
2399 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2400 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2401 UINT uChanged;
2402 UINT uView = lStyle & LVS_TYPEMASK;
2403 INT item_width;
2404 RECT rcItem;
2406 if (lStyle & LVS_OWNERDATA)
2408 if ((lpLVItem->iSubItem == 0)&&(lpLVItem->mask == LVIF_STATE))
2410 LVITEMA itm;
2412 ZeroMemory(&itm,sizeof(LVITEMA));
2413 itm.mask = LVIF_STATE | LVIF_PARAM;
2414 itm.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
2415 itm.iItem = lpLVItem->iItem;
2416 itm.iSubItem = 0;
2417 ListView_GetItemA(hwnd,&itm);
2420 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2421 nmlv.hdr.hwndFrom = hwnd;
2422 nmlv.hdr.idFrom = lCtrlId;
2423 nmlv.hdr.code = LVN_ITEMCHANGING;
2424 nmlv.uNewState = lpLVItem->state;
2425 nmlv.uOldState = itm.state;
2426 nmlv.uChanged = LVIF_STATE;
2427 nmlv.lParam = itm.lParam;
2428 nmlv.iItem = lpLVItem->iItem;
2430 if ((itm.state & lpLVItem->stateMask) !=
2431 (lpLVItem->state & lpLVItem->stateMask))
2433 /* send LVN_ITEMCHANGING notification */
2434 if (!ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv))
2436 if (lpLVItem->stateMask & LVIS_FOCUSED)
2438 if (lpLVItem->state & LVIS_FOCUSED)
2439 infoPtr->nFocusedItem = lpLVItem->iItem;
2440 else if (infoPtr->nFocusedItem == lpLVItem->iItem)
2441 infoPtr->nFocusedItem = -1;
2443 if (lpLVItem->stateMask & LVIS_SELECTED)
2445 if (lpLVItem->state & LVIS_SELECTED)
2446 LISTVIEW_AddSelectionRange(hwnd,lpLVItem->iItem,lpLVItem->iItem);
2447 else
2448 LISTVIEW_RemoveSelectionRange(hwnd,lpLVItem->iItem,
2449 lpLVItem->iItem);
2452 nmlv.hdr.code = LVN_ITEMCHANGED;
2454 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2456 rcItem.left = LVIR_BOUNDS;
2457 LISTVIEW_GetItemRect(hwnd, lpLVItem->iItem, &rcItem);
2458 InvalidateRect(hwnd, &rcItem, TRUE);
2461 return TRUE;
2463 return FALSE;
2466 if (lpLVItem != NULL)
2468 if (lpLVItem->iSubItem == 0)
2470 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
2471 if (hdpaSubItems != NULL && hdpaSubItems != (HDPA)-1)
2473 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem);
2474 if (lpItem != NULL)
2476 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2477 nmlv.hdr.hwndFrom = hwnd;
2478 nmlv.hdr.idFrom = lCtrlId;
2479 nmlv.hdr.code = LVN_ITEMCHANGING;
2480 nmlv.lParam = lpItem->lParam;
2481 uChanged = LISTVIEW_GetItemChanges(lpItem, lpLVItem);
2482 if (uChanged != 0)
2484 if (uChanged & LVIF_STATE)
2486 nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask;
2487 nmlv.uOldState = lpItem->state & lpLVItem->stateMask;
2489 if (nmlv.uNewState & LVIS_SELECTED)
2492 * This is redundent if called through SetSelection
2494 * however is required if the used directly calls SetItem
2495 * to set the selection.
2497 if (lStyle & LVS_SINGLESEL)
2499 LISTVIEW_RemoveAllSelections(hwnd);
2502 LISTVIEW_AddSelectionRange(hwnd,lpLVItem->iItem,
2503 lpLVItem->iItem);
2505 else if (lpLVItem->stateMask & LVIS_SELECTED)
2507 LISTVIEW_RemoveSelectionRange(hwnd,lpLVItem->iItem,
2508 lpLVItem->iItem);
2510 if (nmlv.uNewState & LVIS_FOCUSED)
2513 * This is a fun hoop to jump to try to catch if
2514 * the user is calling us directly to call focuse or if
2515 * this function is being called as a result of a
2516 * SetItemFocuse call.
2518 if (infoPtr->nFocusedItem >= 0)
2519 LISTVIEW_SetItemFocus(hwnd, lpLVItem->iItem);
2523 nmlv.uChanged = uChanged;
2524 nmlv.iItem = lpLVItem->iItem;
2525 nmlv.lParam = lpItem->lParam;
2526 /* send LVN_ITEMCHANGING notification */
2527 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2529 /* copy information */
2530 bResult = LISTVIEW_InitItem(hwnd, lpItem, lpLVItem);
2532 /* if LVS_LIST or LVS_SMALLICON, update the width of the items based on */
2533 /* the width of the items text */
2534 if((uView == LVS_LIST) || (uView == LVS_SMALLICON))
2536 item_width = LISTVIEW_GetStringWidthA(hwnd, lpItem->pszText);
2538 if(item_width > infoPtr->nItemWidth)
2539 infoPtr->nItemWidth = item_width;
2542 /* send LVN_ITEMCHANGED notification */
2543 nmlv.hdr.code = LVN_ITEMCHANGED;
2544 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2546 else
2548 bResult = TRUE;
2551 if (uChanged)
2553 rcItem.left = LVIR_BOUNDS;
2554 LISTVIEW_GetItemRect(hwnd, lpLVItem->iItem, &rcItem);
2555 InvalidateRect(hwnd, &rcItem, TRUE);
2562 return bResult;
2565 /***
2566 * DESCRIPTION:
2567 * Sets subitem attributes.
2569 * PARAMETER(S):
2570 * [I] HWND : window handle
2571 * [I] LPLVITEM : new subitem atttributes
2573 * RETURN:
2574 * SUCCESS : TRUE
2575 * FAILURE : FALSE
2577 static BOOL LISTVIEW_SetSubItem(HWND hwnd, LPLVITEMA lpLVItem)
2579 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2580 BOOL bResult = FALSE;
2581 HDPA hdpaSubItems;
2582 LISTVIEW_SUBITEM *lpSubItem;
2583 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2584 RECT rcItem;
2586 if (lStyle & LVS_OWNERDATA)
2587 return FALSE;
2589 if (lpLVItem != NULL)
2591 if (lpLVItem->iSubItem > 0)
2593 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
2594 if (hdpaSubItems != NULL)
2596 /* set subitem only if column is present */
2597 if (Header_GetItemCount(infoPtr->hwndHeader) > lpLVItem->iSubItem)
2599 lpSubItem = LISTVIEW_GetSubItem(hdpaSubItems, lpLVItem->iSubItem);
2600 if (lpSubItem != NULL)
2602 bResult = LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem);
2604 else
2606 bResult = LISTVIEW_AddSubItem(hwnd, lpLVItem);
2609 rcItem.left = LVIR_BOUNDS;
2610 LISTVIEW_GetItemRect(hwnd, lpLVItem->iItem, &rcItem);
2611 InvalidateRect(hwnd, &rcItem, FALSE);
2617 return bResult;
2620 /***
2621 * DESCRIPTION:
2622 * Retrieves the index of the item at coordinate (0, 0) of the client area.
2624 * PARAMETER(S):
2625 * [I] HWND : window handle
2627 * RETURN:
2628 * item index
2630 static INT LISTVIEW_GetTopIndex(HWND hwnd)
2632 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2633 UINT uView = lStyle & LVS_TYPEMASK;
2634 INT nItem = 0;
2635 SCROLLINFO scrollInfo;
2637 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2638 scrollInfo.cbSize = sizeof(SCROLLINFO);
2639 scrollInfo.fMask = SIF_POS;
2641 if (uView == LVS_LIST)
2643 if (lStyle & WS_HSCROLL)
2645 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2647 nItem = scrollInfo.nPos * LISTVIEW_GetCountPerColumn(hwnd);
2651 else if (uView == LVS_REPORT)
2653 if (lStyle & WS_VSCROLL)
2655 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
2657 nItem = scrollInfo.nPos;
2662 return nItem;
2665 /***
2666 * DESCRIPTION:
2667 * Draws a subitem.
2669 * PARAMETER(S):
2670 * [I] HWND : window handle
2671 * [I] HDC : device context handle
2672 * [I] INT : item index
2673 * [I] INT : subitem index
2674 * [I] RECT * : clipping rectangle
2676 * RETURN:
2677 * None
2679 static VOID LISTVIEW_DrawSubItem(HWND hwnd, HDC hdc, INT nItem, INT nSubItem,
2680 RECT rcItem, BOOL Selected)
2682 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2683 CHAR szDispText[DISP_TEXT_SIZE];
2684 LVITEMA lvItem;
2686 TRACE("(hwnd=%x, hdc=%x, nItem=%d, nSubItem=%d)\n", hwnd, hdc,
2687 nItem, nSubItem);
2689 /* get information needed for drawing the item */
2690 ZeroMemory(&lvItem, sizeof(LVITEMA));
2691 lvItem.mask = LVIF_TEXT;
2692 lvItem.iItem = nItem;
2693 lvItem.iSubItem = nSubItem;
2694 lvItem.cchTextMax = DISP_TEXT_SIZE;
2695 lvItem.pszText = szDispText;
2696 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
2698 /* set item colors */
2699 if (ListView_GetItemState(hwnd,nItem,LVIS_SELECTED)
2700 &&(infoPtr->bFocus != FALSE) && Selected)
2702 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
2703 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2705 else
2707 SetBkColor(hdc, infoPtr->clrTextBk);
2708 SetTextColor(hdc, infoPtr->clrText);
2711 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
2712 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
2714 if (Selected)
2716 /* fill in the gap */
2717 RECT rec;
2718 if (nSubItem < Header_GetItemCount(infoPtr->hwndHeader)-1)
2720 CopyRect(&rec,&rcItem);
2721 rec.left = rec.right;
2722 rec.right = rec.left+REPORT_MARGINX;
2723 ExtTextOutA(hdc, rec.left , rec.top, ETO_OPAQUE | ETO_CLIPPED,
2724 &rec, NULL, 0, NULL);
2726 CopyRect(&rec,&rcItem);
2727 rec.right = rec.left;
2728 rec.left = rec.left - REPORT_MARGINX;
2729 ExtTextOutA(hdc, rec.left , rec.top, ETO_OPAQUE | ETO_CLIPPED,
2730 &rec, NULL, 0, NULL);
2735 /***
2736 * DESCRIPTION:
2737 * Draws an item.
2739 * PARAMETER(S):
2740 * [I] HWND : window handle
2741 * [I] HDC : device context handle
2742 * [I] INT : item index
2743 * [I] RECT * : clipping rectangle
2745 * RETURN:
2746 * None
2748 static VOID LISTVIEW_DrawItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem, BOOL FullSelect, RECT* SuggestedFocus)
2750 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2751 CHAR szDispText[DISP_TEXT_SIZE];
2752 INT nLabelWidth;
2753 LVITEMA lvItem;
2754 INT nMixMode;
2755 DWORD dwBkColor;
2756 DWORD dwTextColor,dwTextX;
2757 BOOL bImage = FALSE;
2760 TRACE("(hwnd=%x, hdc=%x, nItem=%d)\n", hwnd, hdc, nItem);
2763 /* get information needed for drawing the item */
2764 ZeroMemory(&lvItem, sizeof(LVITEMA));
2765 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_INDENT;
2766 lvItem.stateMask = LVIS_SELECTED | LVIS_STATEIMAGEMASK;
2767 lvItem.iItem = nItem;
2768 lvItem.iSubItem = 0;
2769 lvItem.cchTextMax = DISP_TEXT_SIZE;
2770 lvItem.pszText = szDispText;
2771 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
2773 /* do indent */
2774 if (lvItem.iIndent>0 && infoPtr->iconSize.cx > 0)
2776 rcItem.left += infoPtr->iconSize.cx * lvItem.iIndent;
2778 if (SuggestedFocus)
2779 SuggestedFocus->left += infoPtr->iconSize.cx * lvItem.iIndent;
2782 /* state icons */
2783 if (infoPtr->himlState != NULL)
2785 UINT uStateImage = (lvItem.state & LVIS_STATEIMAGEMASK) >> 12;
2786 if (uStateImage > 0)
2788 ImageList_Draw(infoPtr->himlState, uStateImage - 1, hdc, rcItem.left,
2789 rcItem.top, ILD_NORMAL);
2792 rcItem.left += infoPtr->iconSize.cx;
2793 if (SuggestedFocus)
2794 SuggestedFocus->left += infoPtr->iconSize.cx;
2795 bImage = TRUE;
2798 /* small icons */
2799 if (infoPtr->himlSmall != NULL)
2801 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE) &&
2802 (lvItem.iImage>=0))
2804 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
2805 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
2806 rcItem.top, ILD_SELECTED);
2808 else if (lvItem.iImage>=0)
2810 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
2811 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
2812 rcItem.top, ILD_NORMAL);
2815 rcItem.left += infoPtr->iconSize.cx;
2817 if (SuggestedFocus)
2818 SuggestedFocus->left += infoPtr->iconSize.cx;
2819 bImage = TRUE;
2822 /* Don't bother painting item being edited */
2823 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED && !FullSelect)
2824 return;
2826 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
2828 /* set item colors */
2829 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
2830 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2831 /* set raster mode */
2832 nMixMode = SetROP2(hdc, R2_XORPEN);
2834 else if ((GetWindowLongA(hwnd, GWL_STYLE) & LVS_SHOWSELALWAYS) &&
2835 (lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus == FALSE))
2837 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
2838 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
2839 /* set raster mode */
2840 nMixMode = SetROP2(hdc, R2_COPYPEN);
2842 else
2844 /* set item colors */
2845 dwBkColor = SetBkColor(hdc, infoPtr->clrTextBk);
2846 dwTextColor = SetTextColor(hdc, infoPtr->clrText);
2847 /* set raster mode */
2848 nMixMode = SetROP2(hdc, R2_COPYPEN);
2851 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
2852 if (rcItem.left + nLabelWidth < rcItem.right)
2854 if (!FullSelect)
2855 rcItem.right = rcItem.left + nLabelWidth + TRAILING_PADDING;
2856 if (bImage)
2857 rcItem.right += IMAGE_PADDING;
2860 /* draw label */
2861 dwTextX = rcItem.left + 1;
2862 if (bImage)
2863 dwTextX += IMAGE_PADDING;
2864 ExtTextOutA(hdc, dwTextX, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
2865 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
2867 if ((FullSelect)&&(Header_GetItemCount(infoPtr->hwndHeader) > 1))
2869 /* fill in the gap */
2870 RECT rec;
2871 CopyRect(&rec,&rcItem);
2872 rec.left = rec.right;
2873 rec.right = rec.left+REPORT_MARGINX;
2874 ExtTextOutA(hdc, rec.left , rec.top, ETO_OPAQUE | ETO_CLIPPED,
2875 &rec, NULL, 0, NULL);
2878 if (!FullSelect)
2879 CopyRect(SuggestedFocus,&rcItem);
2881 if (nMixMode != 0)
2883 SetROP2(hdc, R2_COPYPEN);
2884 SetBkColor(hdc, infoPtr->clrTextBk);
2885 SetTextColor(hdc, infoPtr->clrText);
2889 /***
2890 * DESCRIPTION:
2891 * Draws an item when in large icon display mode.
2893 * PARAMETER(S):
2894 * [I] HWND : window handle
2895 * [I] HDC : device context handle
2896 * [I] LISTVIEW_ITEM * : item
2897 * [I] INT : item index
2898 * [I] RECT * : clipping rectangle
2900 * RETURN:
2901 * None
2903 static VOID LISTVIEW_DrawLargeItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem,
2904 RECT *SuggestedFocus)
2906 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2907 CHAR szDispText[DISP_TEXT_SIZE];
2908 INT nDrawPosX = rcItem.left;
2909 INT nLabelWidth;
2910 TEXTMETRICA tm;
2911 LVITEMA lvItem;
2913 TRACE("(hwnd=%x, hdc=%x, nItem=%d, left=%d, top=%d, right=%d, \
2914 bottom=%d)\n", hwnd, hdc, nItem, rcItem.left, rcItem.top, rcItem.right,
2915 rcItem.bottom);
2917 /* get information needed for drawing the item */
2918 ZeroMemory(&lvItem, sizeof(LVITEMA));
2919 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
2920 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
2921 lvItem.iItem = nItem;
2922 lvItem.iSubItem = 0;
2923 lvItem.cchTextMax = DISP_TEXT_SIZE;
2924 lvItem.pszText = szDispText;
2925 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
2927 if (lvItem.state & LVIS_SELECTED)
2929 /* set item colors */
2930 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
2931 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2932 /* set raster mode */
2933 SetROP2(hdc, R2_XORPEN);
2935 else
2937 /* set item colors */
2938 SetBkColor(hdc, infoPtr->clrTextBk);
2939 SetTextColor(hdc, infoPtr->clrText);
2940 /* set raster mode */
2941 SetROP2(hdc, R2_COPYPEN);
2944 if (infoPtr->himlNormal != NULL)
2946 rcItem.top += ICON_TOP_PADDING;
2947 nDrawPosX += (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
2948 if ((lvItem.state & LVIS_SELECTED) && (lvItem.iImage>=0))
2950 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
2951 rcItem.top, ILD_SELECTED);
2953 else if (lvItem.iImage>=0)
2955 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
2956 rcItem.top, ILD_NORMAL);
2960 /* Don't bother painting item being edited */
2961 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED)
2962 return;
2964 rcItem.top += infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
2965 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
2966 nDrawPosX = infoPtr->iconSpacing.cx - nLabelWidth;
2967 if (nDrawPosX > 1)
2969 rcItem.left += nDrawPosX / 2;
2970 rcItem.right = rcItem.left + nLabelWidth;
2972 else
2974 rcItem.left += 1;
2975 rcItem.right = rcItem.left + infoPtr->iconSpacing.cx - 1;
2978 /* draw label */
2979 GetTextMetricsA(hdc, &tm);
2980 rcItem.bottom = rcItem.top + tm.tmHeight + HEIGHT_PADDING;
2981 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
2982 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
2985 CopyRect(SuggestedFocus,&rcItem);
2988 /***
2989 * DESCRIPTION:
2990 * Draws listview items when in report display mode.
2992 * PARAMETER(S):
2993 * [I] HWND : window handle
2994 * [I] HDC : device context handle
2996 * RETURN:
2997 * None
2999 static VOID LISTVIEW_RefreshReport(HWND hwnd, HDC hdc)
3001 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
3002 SCROLLINFO scrollInfo;
3003 INT nDrawPosY = infoPtr->rcList.top;
3004 INT nColumnCount;
3005 RECT rcItem;
3006 INT j;
3007 INT nItem;
3008 INT nLast;
3009 BOOL FullSelected;
3011 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
3012 scrollInfo.cbSize = sizeof(SCROLLINFO);
3013 scrollInfo.fMask = SIF_POS;
3015 nItem = ListView_GetTopIndex(hwnd);
3017 /* add 1 for displaying a partial item at the bottom */
3018 nLast = nItem + LISTVIEW_GetCountPerColumn(hwnd) + 1;
3019 nLast = min(nLast, GETITEMCOUNT(infoPtr));
3021 /* send cache hint notification */
3022 if (GetWindowLongA(hwnd,GWL_STYLE) & LVS_OWNERDATA)
3024 NMLVCACHEHINT nmlv;
3026 nmlv.hdr.hwndFrom = hwnd;
3027 nmlv.hdr.idFrom = GetWindowLongA(hwnd,GWL_ID);
3028 nmlv.hdr.code = LVN_ODCACHEHINT;
3029 nmlv.iFrom = nItem;
3030 nmlv.iTo = nLast;
3032 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)nmlv.hdr.idFrom,
3033 (LPARAM)&nmlv);
3036 nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
3037 FullSelected = infoPtr->dwExStyle & LVS_EX_FULLROWSELECT;
3039 for (; nItem < nLast; nItem++)
3041 RECT SuggestedFocusRect;
3043 if (FullSelected)
3045 RECT ir,br;
3047 Header_GetItemRect(infoPtr->hwndHeader, 0, &ir);
3048 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
3050 ir.left += REPORT_MARGINX;
3051 ir.right = max(ir.left, br.right - REPORT_MARGINX);
3052 ir.top = nDrawPosY;
3053 ir.bottom = ir.top + infoPtr->nItemHeight;
3055 CopyRect(&SuggestedFocusRect,&ir);
3058 for (j = 0; j < nColumnCount; j++)
3060 Header_GetItemRect(infoPtr->hwndHeader, j, &rcItem);
3062 rcItem.left += REPORT_MARGINX;
3063 rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX);
3064 rcItem.top = nDrawPosY;
3065 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
3067 /* Offset the Scroll Bar Pos */
3068 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
3070 rcItem.left -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
3071 rcItem.right -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
3074 if (j == 0)
3076 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem, FullSelected,
3077 &SuggestedFocusRect);
3079 else
3081 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, j, rcItem,
3082 FullSelected);
3086 * Draw Focus Rect
3088 if (LISTVIEW_GetItemState(hwnd,nItem,LVIS_FOCUSED) && infoPtr->bFocus)
3090 BOOL rop=FALSE;
3091 if (FullSelected && LISTVIEW_GetItemState(hwnd,nItem,LVIS_SELECTED))
3092 rop = SetROP2(hdc, R2_XORPEN);
3094 Rectangle(hdc, SuggestedFocusRect.left, SuggestedFocusRect.top,
3095 SuggestedFocusRect.right,SuggestedFocusRect.bottom);
3097 if (rop)
3098 SetROP2(hdc, R2_COPYPEN);
3100 nDrawPosY += infoPtr->nItemHeight;
3104 /***
3105 * DESCRIPTION:
3106 * Retrieves the number of items that can fit vertically in the client area.
3108 * PARAMETER(S):
3109 * [I] HWND : window handle
3111 * RETURN:
3112 * Number of items per row.
3114 static INT LISTVIEW_GetCountPerRow(HWND hwnd)
3116 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
3117 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3118 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
3119 INT nCountPerRow = 1;
3121 if (nListWidth > 0)
3123 if (uView == LVS_REPORT)
3125 nCountPerRow = 1;
3127 else
3129 nCountPerRow = nListWidth / infoPtr->nItemWidth;
3130 if (nCountPerRow == 0)
3132 nCountPerRow = 1;
3137 return nCountPerRow;
3140 /***
3141 * DESCRIPTION:
3142 * Retrieves the number of items that can fit horizontally in the client
3143 * area.
3145 * PARAMETER(S):
3146 * [I] HWND : window handle
3148 * RETURN:
3149 * Number of items per column.
3151 static INT LISTVIEW_GetCountPerColumn(HWND hwnd)
3153 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
3154 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
3155 INT nCountPerColumn = 1;
3157 if (nListHeight > 0)
3159 nCountPerColumn = nListHeight / infoPtr->nItemHeight;
3160 if (nCountPerColumn == 0)
3162 nCountPerColumn = 1;
3166 return nCountPerColumn;
3169 /***
3170 * DESCRIPTION:
3171 * Retrieves the number of columns needed to display all the items when in
3172 * list display mode.
3174 * PARAMETER(S):
3175 * [I] HWND : window handle
3177 * RETURN:
3178 * Number of columns.
3180 static INT LISTVIEW_GetColumnCount(HWND hwnd)
3182 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3183 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3184 INT nColumnCount = 0;
3186 if ((lStyle & LVS_TYPEMASK) == LVS_LIST)
3188 if (infoPtr->rcList.right % infoPtr->nItemWidth == 0)
3190 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth;
3192 else
3194 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth + 1;
3198 return nColumnCount;
3202 /***
3203 * DESCRIPTION:
3204 * Draws listview items when in list display mode.
3206 * PARAMETER(S):
3207 * [I] HWND : window handle
3208 * [I] HDC : device context handle
3210 * RETURN:
3211 * None
3213 static VOID LISTVIEW_RefreshList(HWND hwnd, HDC hdc)
3215 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3216 RECT rcItem,FocusRect;
3217 INT i, j;
3218 INT nItem;
3219 INT nColumnCount;
3220 INT nCountPerColumn;
3221 INT nItemWidth = infoPtr->nItemWidth;
3222 INT nItemHeight = infoPtr->nItemHeight;
3224 /* get number of fully visible columns */
3225 nColumnCount = LISTVIEW_GetColumnCount(hwnd);
3226 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
3227 nItem = ListView_GetTopIndex(hwnd);
3229 for (i = 0; i < nColumnCount; i++)
3231 for (j = 0; j < nCountPerColumn; j++, nItem++)
3233 if (nItem >= GETITEMCOUNT(infoPtr))
3234 return;
3236 rcItem.top = j * nItemHeight;
3237 rcItem.left = i * nItemWidth;
3238 rcItem.bottom = rcItem.top + nItemHeight;
3239 rcItem.right = rcItem.left + nItemWidth;
3240 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem, FALSE, &FocusRect);
3242 * Draw Focus Rect
3244 if (LISTVIEW_GetItemState(hwnd,nItem,LVIS_FOCUSED) && infoPtr->bFocus)
3245 Rectangle(hdc, FocusRect.left, FocusRect.top,
3246 FocusRect.right,FocusRect.bottom);
3251 /***
3252 * DESCRIPTION:
3253 * Draws listview items when in icon or small icon display mode.
3255 * PARAMETER(S):
3256 * [I] HWND : window handle
3257 * [I] HDC : device context handle
3259 * RETURN:
3260 * None
3262 static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc, BOOL bSmall)
3264 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3265 POINT ptPosition;
3266 POINT ptOrigin;
3267 RECT rcItem,SuggestedFocus;
3268 INT i;
3270 LISTVIEW_GetOrigin(hwnd, &ptOrigin);
3271 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
3273 LISTVIEW_GetItemPosition(hwnd, i, &ptPosition);
3274 ptPosition.x += ptOrigin.x;
3275 ptPosition.y += ptOrigin.y;
3277 if (ptPosition.y + infoPtr->nItemHeight > infoPtr->rcList.top)
3279 if (ptPosition.x + infoPtr->nItemWidth > infoPtr->rcList.left)
3281 if (ptPosition.y < infoPtr->rcList.bottom)
3283 if (ptPosition.x < infoPtr->rcList.right)
3285 rcItem.top = ptPosition.y;
3286 rcItem.left = ptPosition.x;
3287 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
3288 rcItem.right = rcItem.left + infoPtr->nItemWidth;
3289 if (bSmall == FALSE)
3291 LISTVIEW_DrawLargeItem(hwnd, hdc, i, rcItem, &SuggestedFocus);
3293 else
3295 LISTVIEW_DrawItem(hwnd, hdc, i, rcItem, FALSE, &SuggestedFocus);
3298 * Draw Focus Rect
3300 if (LISTVIEW_GetItemState(hwnd,i,LVIS_FOCUSED) &&
3301 infoPtr->bFocus)
3302 Rectangle(hdc, SuggestedFocus.left, SuggestedFocus.top,
3303 SuggestedFocus.right,SuggestedFocus.bottom);
3311 /***
3312 * DESCRIPTION:
3313 * Draws listview items.
3315 * PARAMETER(S):
3316 * [I] HWND : window handle
3317 * [I] HDC : device context handle
3319 * RETURN:
3320 * NoneX
3322 static VOID LISTVIEW_Refresh(HWND hwnd, HDC hdc)
3324 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3325 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3326 HFONT hOldFont;
3327 HPEN hPen, hOldPen;
3329 /* select font */
3330 hOldFont = SelectObject(hdc, infoPtr->hFont);
3332 /* select the doted pen (for drawing the focus box) */
3333 hPen = CreatePen(PS_DOT, 1, 0);
3334 hOldPen = SelectObject(hdc, hPen);
3336 /* select transparent brush (for drawing the focus box) */
3337 SelectObject(hdc, GetStockObject(NULL_BRUSH));
3339 if (uView == LVS_LIST)
3341 LISTVIEW_RefreshList(hwnd, hdc);
3343 else if (uView == LVS_REPORT)
3345 LISTVIEW_RefreshReport(hwnd, hdc);
3347 else if (uView == LVS_SMALLICON)
3349 LISTVIEW_RefreshIcon(hwnd, hdc, TRUE);
3351 else if (uView == LVS_ICON)
3353 LISTVIEW_RefreshIcon(hwnd, hdc, FALSE);
3356 /* unselect objects */
3357 SelectObject(hdc, hOldFont);
3358 SelectObject(hdc, hOldPen);
3360 /* delete pen */
3361 DeleteObject(hPen);
3365 /***
3366 * DESCRIPTION:
3367 * Calculates the approximate width and height of a given number of items.
3369 * PARAMETER(S):
3370 * [I] HWND : window handle
3371 * [I] INT : number of items
3372 * [I] INT : width
3373 * [I] INT : height
3375 * RETURN:
3376 * Returns a DWORD. The width in the low word and the height in high word.
3378 static LRESULT LISTVIEW_ApproximateViewRect(HWND hwnd, INT nItemCount,
3379 WORD wWidth, WORD wHeight)
3381 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3382 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3383 INT nItemCountPerColumn = 1;
3384 INT nColumnCount = 0;
3385 DWORD dwViewRect = 0;
3387 if (nItemCount == -1)
3389 nItemCount = GETITEMCOUNT(infoPtr);
3392 if (uView == LVS_LIST)
3394 if (wHeight == 0xFFFF)
3396 /* use current height */
3397 wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
3400 if (wHeight < infoPtr->nItemHeight)
3402 wHeight = infoPtr->nItemHeight;
3405 if (nItemCount > 0)
3407 if (infoPtr->nItemHeight > 0)
3409 nItemCountPerColumn = wHeight / infoPtr->nItemHeight;
3410 if (nItemCountPerColumn == 0)
3412 nItemCountPerColumn = 1;
3415 if (nItemCount % nItemCountPerColumn != 0)
3417 nColumnCount = nItemCount / nItemCountPerColumn;
3419 else
3421 nColumnCount = nItemCount / nItemCountPerColumn + 1;
3426 /* Microsoft padding magic */
3427 wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2;
3428 wWidth = nColumnCount * infoPtr->nItemWidth + 2;
3430 dwViewRect = MAKELONG(wWidth, wHeight);
3432 else if (uView == LVS_REPORT)
3434 /* TO DO */
3436 else if (uView == LVS_SMALLICON)
3438 /* TO DO */
3440 else if (uView == LVS_ICON)
3442 /* TO DO */
3445 return dwViewRect;
3448 /***
3449 * DESCRIPTION:
3450 * Arranges listview items in icon display mode.
3452 * PARAMETER(S):
3453 * [I] HWND : window handle
3454 * [I] INT : alignment code
3456 * RETURN:
3457 * SUCCESS : TRUE
3458 * FAILURE : FALSE
3460 static LRESULT LISTVIEW_Arrange(HWND hwnd, INT nAlignCode)
3462 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3463 BOOL bResult = FALSE;
3465 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
3467 switch (nAlignCode)
3469 case LVA_ALIGNLEFT:
3470 /* TO DO */
3471 break;
3472 case LVA_ALIGNTOP:
3473 /* TO DO */
3474 break;
3475 case LVA_DEFAULT:
3476 /* TO DO */
3477 break;
3478 case LVA_SNAPTOGRID:
3479 /* TO DO */
3480 break;
3484 return bResult;
3487 /* << LISTVIEW_CreateDragImage >> */
3490 /***
3491 * DESCRIPTION:
3492 * Removes all listview items and subitems.
3494 * PARAMETER(S):
3495 * [I] HWND : window handle
3497 * RETURN:
3498 * SUCCESS : TRUE
3499 * FAILURE : FALSE
3501 static LRESULT LISTVIEW_DeleteAllItems(HWND hwnd)
3503 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3504 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
3505 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3506 UINT uView = lStyle & LVS_TYPEMASK;
3507 LISTVIEW_ITEM *lpItem;
3508 LISTVIEW_SUBITEM *lpSubItem;
3509 NMLISTVIEW nmlv;
3510 BOOL bSuppress;
3511 BOOL bResult = FALSE;
3512 INT i;
3513 INT j;
3514 HDPA hdpaSubItems;
3516 TRACE("(hwnd=%x,)\n", hwnd);
3517 LISTVIEW_RemoveAllSelections(hwnd);
3519 if (lStyle & LVS_OWNERDATA)
3521 infoPtr->hdpaItems->nItemCount = 0;
3522 InvalidateRect(hwnd, NULL, TRUE);
3523 return TRUE;
3526 if (GETITEMCOUNT(infoPtr) > 0)
3528 /* initialize memory */
3529 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
3531 /* send LVN_DELETEALLITEMS notification */
3532 nmlv.hdr.hwndFrom = hwnd;
3533 nmlv.hdr.idFrom = lCtrlId;
3534 nmlv.hdr.code = LVN_DELETEALLITEMS;
3535 nmlv.iItem = -1;
3537 /* verify if subsequent LVN_DELETEITEM notifications should be
3538 suppressed */
3539 bSuppress = ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
3541 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
3543 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
3544 if (hdpaSubItems != NULL)
3546 for (j = 1; j < hdpaSubItems->nItemCount; j++)
3548 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, j);
3549 if (lpSubItem != NULL)
3551 /* free subitem string */
3552 if ((lpSubItem->pszText != NULL) &&
3553 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
3555 COMCTL32_Free(lpSubItem->pszText);
3558 /* free subitem */
3559 COMCTL32_Free(lpSubItem);
3563 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3564 if (lpItem != NULL)
3566 if (bSuppress == FALSE)
3568 /* send LVN_DELETEITEM notification */
3569 nmlv.hdr.code = LVN_DELETEITEM;
3570 nmlv.iItem = i;
3571 nmlv.lParam = lpItem->lParam;
3572 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
3575 /* free item string */
3576 if ((lpItem->pszText != NULL) &&
3577 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
3579 COMCTL32_Free(lpItem->pszText);
3582 /* free item */
3583 COMCTL32_Free(lpItem);
3586 DPA_Destroy(hdpaSubItems);
3590 /* reinitialize listview memory */
3591 bResult = DPA_DeleteAllPtrs(infoPtr->hdpaItems);
3593 /* align items (set position of each item) */
3594 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
3596 if (lStyle & LVS_ALIGNLEFT)
3598 LISTVIEW_AlignLeft(hwnd);
3600 else
3602 LISTVIEW_AlignTop(hwnd);
3606 LISTVIEW_UpdateScroll(hwnd);
3608 /* invalidate client area (optimization needed) */
3609 InvalidateRect(hwnd, NULL, TRUE);
3612 return bResult;
3615 /***
3616 * DESCRIPTION:
3617 * Removes a column from the listview control.
3619 * PARAMETER(S):
3620 * [I] HWND : window handle
3621 * [I] INT : column index
3623 * RETURN:
3624 * SUCCESS : TRUE
3625 * FAILURE : FALSE
3627 static LRESULT LISTVIEW_DeleteColumn(HWND hwnd, INT nColumn)
3629 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3630 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3631 BOOL bResult = FALSE;
3633 if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) != FALSE)
3635 bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
3637 /* Need to reset the item width when deleting a column */
3638 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
3640 /* reset scroll parameters */
3641 if (uView == LVS_REPORT)
3643 /* update scrollbar(s) */
3644 LISTVIEW_UpdateScroll(hwnd);
3646 /* refresh client area */
3647 InvalidateRect(hwnd, NULL, FALSE);
3651 return bResult;
3654 /***
3655 * DESCRIPTION:
3656 * Removes an item from the listview control.
3658 * PARAMETER(S):
3659 * [I] HWND : window handle
3660 * [I] INT : item index
3662 * RETURN:
3663 * SUCCESS : TRUE
3664 * FAILURE : FALSE
3666 static LRESULT LISTVIEW_DeleteItem(HWND hwnd, INT nItem)
3668 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3669 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3670 UINT uView = lStyle & LVS_TYPEMASK;
3671 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
3672 NMLISTVIEW nmlv;
3673 BOOL bResult = FALSE;
3674 HDPA hdpaSubItems;
3675 LISTVIEW_ITEM *lpItem;
3676 LISTVIEW_SUBITEM *lpSubItem;
3677 INT i;
3679 TRACE("(hwnd=%x,nItem=%d)\n", hwnd, nItem);
3681 LISTVIEW_ShiftSelections(hwnd,nItem,-1);
3683 if (lStyle & LVS_OWNERDATA)
3685 infoPtr->hdpaItems->nItemCount --;
3686 InvalidateRect(hwnd, NULL, TRUE);
3687 return TRUE;
3690 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
3692 /* initialize memory */
3693 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
3695 hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem);
3696 if (hdpaSubItems != NULL)
3698 for (i = 1; i < hdpaSubItems->nItemCount; i++)
3700 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
3701 if (lpSubItem != NULL)
3703 /* free item string */
3704 if ((lpSubItem->pszText != NULL) &&
3705 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
3707 COMCTL32_Free(lpSubItem->pszText);
3710 /* free item */
3711 COMCTL32_Free(lpSubItem);
3715 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3716 if (lpItem != NULL)
3718 /* send LVN_DELETEITEM notification */
3719 nmlv.hdr.hwndFrom = hwnd;
3720 nmlv.hdr.idFrom = lCtrlId;
3721 nmlv.hdr.code = LVN_DELETEITEM;
3722 nmlv.iItem = nItem;
3723 nmlv.lParam = lpItem->lParam;
3724 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId,
3725 (LPARAM)&nmlv);
3727 /* free item string */
3728 if ((lpItem->pszText != NULL) &&
3729 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
3731 COMCTL32_Free(lpItem->pszText);
3734 /* free item */
3735 COMCTL32_Free(lpItem);
3738 bResult = DPA_Destroy(hdpaSubItems);
3741 /* align items (set position of each item) */
3742 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
3744 if (lStyle & LVS_ALIGNLEFT)
3746 LISTVIEW_AlignLeft(hwnd);
3748 else
3750 LISTVIEW_AlignTop(hwnd);
3754 /* If this item had focus change focus to next or previous item */
3755 if (GETITEMCOUNT(infoPtr) > 0)
3757 int sItem = nItem < GETITEMCOUNT(infoPtr) ? nItem : nItem - 1;
3758 if (infoPtr->nFocusedItem == nItem)
3759 LISTVIEW_SetItemFocus(hwnd, sItem);
3761 else
3762 infoPtr->nFocusedItem = -1;
3764 LISTVIEW_UpdateScroll(hwnd);
3766 /* refresh client area */
3767 InvalidateRect(hwnd, NULL, TRUE);
3770 return bResult;
3774 /***
3775 * DESCRIPTION:
3776 * Return edit control handle of current edit label
3778 * PARAMETER(S):
3779 * [I] HWND : window handle
3781 * RETURN:
3782 * SUCCESS : HWND
3783 * FAILURE : 0
3785 static LRESULT LISTVIEW_GetEditControl(hwnd)
3787 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3788 return infoPtr->hwndEdit;
3792 /***
3793 * DESCRIPTION:
3794 * Callback implementation for editlabel control
3796 * PARAMETER(S):
3797 * [I] HWND : window handle
3798 * [I] LPSTR : modified text
3799 * [I] DWORD : item index
3801 * RETURN:
3802 * SUCCESS : TRUE
3803 * FAILURE : FALSE
3806 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem)
3808 NMLVDISPINFOA dispInfo;
3809 LISTVIEW_ITEM *lpItem;
3810 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
3811 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3812 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3813 HDPA hdpaSubItems;
3814 BOOL bUpdateItemText;
3815 LISTVIEW_ITEM lvItemRef;
3816 LVITEMA item;
3818 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
3820 if (!(lStyle & LVS_OWNERDATA))
3822 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
3823 return FALSE;
3825 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
3826 return FALSE;
3828 else
3830 ZeroMemory(&lvItemRef,sizeof(LISTVIEW_ITEM));
3831 ZeroMemory(&item,sizeof(LVITEMA));
3832 item.iItem = nItem;
3833 item.iSubItem = 0;
3834 item.mask = LVIF_PARAM | LVIF_STATE;
3835 ListView_GetItemA(hwnd,&item);
3836 lvItemRef.state = item.state;
3837 lvItemRef.iImage = item.iImage;
3838 lvItemRef.lParam = item.lParam;
3839 lpItem = &lvItemRef;
3842 dispInfo.hdr.hwndFrom = hwnd;
3843 dispInfo.hdr.idFrom = nCtrlId;
3844 dispInfo.hdr.code = LVN_ENDLABELEDITA;
3845 dispInfo.item.mask = 0;
3846 dispInfo.item.iItem = nItem;
3847 dispInfo.item.state = lpItem->state;
3848 dispInfo.item.stateMask = 0;
3849 dispInfo.item.pszText = pszText;
3850 dispInfo.item.cchTextMax = pszText ? strlen(pszText) : 0;
3851 dispInfo.item.iImage = lpItem->iImage;
3852 dispInfo.item.lParam = lpItem->lParam;
3853 infoPtr->hwndEdit = 0;
3855 bUpdateItemText = ListView_Notify(GetParent(hwnd), nCtrlId, &dispInfo);
3857 /* Do we need to update the Item Text */
3858 if(bUpdateItemText)
3860 if ((lpItem->pszText != LPSTR_TEXTCALLBACKA)&&(!(lStyle & LVS_OWNERDATA)))
3862 Str_SetPtrA(&lpItem->pszText, pszText);
3866 return TRUE;
3869 /***
3870 * DESCRIPTION:
3871 * Begin in place editing of specified list view item
3873 * PARAMETER(S):
3874 * [I] HWND : window handle
3875 * [I] INT : item index
3877 * RETURN:
3878 * SUCCESS : TRUE
3879 * FAILURE : FALSE
3882 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem)
3884 NMLVDISPINFOA dispInfo;
3885 RECT rect;
3886 LISTVIEW_ITEM *lpItem;
3887 HWND hedit;
3888 HINSTANCE hinst = GetWindowLongA(hwnd, GWL_HINSTANCE);
3889 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
3890 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3891 HDPA hdpaSubItems;
3892 CHAR szDispText[DISP_TEXT_SIZE];
3893 LVITEMA lvItem,item;
3894 LISTVIEW_ITEM lvItemRef;
3895 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3897 if (~GetWindowLongA(hwnd, GWL_STYLE) & LVS_EDITLABELS)
3898 return FALSE;
3900 /* Is the EditBox still there, if so remove it */
3901 if(infoPtr->hwndEdit != 0)
3903 SetFocus(hwnd);
3906 LISTVIEW_SetSelection(hwnd, nItem);
3907 LISTVIEW_SetItemFocus(hwnd, nItem);
3909 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
3910 if (!(lStyle & LVS_OWNERDATA))
3912 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
3913 return 0;
3915 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
3916 return 0;
3918 else
3920 ZeroMemory(&lvItemRef,sizeof(LISTVIEW_ITEM));
3921 ZeroMemory(&item,sizeof(LVITEMA));
3922 item.iItem = nItem;
3923 item.iSubItem = 0;
3924 item.mask = LVIF_PARAM | LVIF_STATE;
3925 ListView_GetItemA(hwnd,&item);
3926 lvItemRef.iImage = item.iImage;
3927 lvItemRef.state = item.state;
3928 lvItemRef.lParam = item.lParam;
3929 lpItem = &lvItemRef;
3932 /* get information needed for drawing the item */
3933 ZeroMemory(&lvItem, sizeof(LVITEMA));
3934 lvItem.mask = LVIF_TEXT;
3935 lvItem.iItem = nItem;
3936 lvItem.iSubItem = 0;
3937 lvItem.cchTextMax = DISP_TEXT_SIZE;
3938 lvItem.pszText = szDispText;
3939 ListView_GetItemA(hwnd, &lvItem);
3941 dispInfo.hdr.hwndFrom = hwnd;
3942 dispInfo.hdr.idFrom = nCtrlId;
3943 dispInfo.hdr.code = LVN_BEGINLABELEDITA;
3944 dispInfo.item.mask = 0;
3945 dispInfo.item.iItem = nItem;
3946 dispInfo.item.state = lpItem->state;
3947 dispInfo.item.stateMask = 0;
3948 dispInfo.item.pszText = lvItem.pszText;
3949 dispInfo.item.cchTextMax = strlen(lvItem.pszText);
3950 dispInfo.item.iImage = lpItem->iImage;
3951 dispInfo.item.lParam = lpItem->lParam;
3953 if (ListView_LVNotify(GetParent(hwnd), nCtrlId, &dispInfo))
3954 return 0;
3956 rect.left = LVIR_LABEL;
3957 if (!LISTVIEW_GetItemRect(hwnd, nItem, &rect))
3958 return 0;
3960 if (!(hedit = CreateEditLabel(szDispText , WS_VISIBLE,
3961 rect.left-2, rect.top-1, 0,
3962 rect.bottom - rect.top+2,
3963 hwnd, hinst, LISTVIEW_EndEditLabel, nItem)))
3964 return 0;
3966 infoPtr->hwndEdit = hedit;
3967 SetFocus(hedit);
3968 SendMessageA(hedit, EM_SETSEL, 0, -1);
3970 return hedit;
3974 /***
3975 * DESCRIPTION:
3976 * Ensures the specified item is visible, scrolling into view if necessary.
3978 * PARAMETER(S):
3979 * [I] HWND : window handle
3980 * [I] INT : item index
3981 * [I] BOOL : partially or entirely visible
3983 * RETURN:
3984 * SUCCESS : TRUE
3985 * FAILURE : FALSE
3987 static BOOL LISTVIEW_EnsureVisible(HWND hwnd, INT nItem, BOOL bPartial)
3989 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3990 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3991 INT nScrollPosHeight = 0;
3992 INT nScrollPosWidth = 0;
3993 SCROLLINFO scrollInfo;
3994 RECT rcItem;
3995 BOOL bRedraw = FALSE;
3997 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
3998 scrollInfo.cbSize = sizeof(SCROLLINFO);
3999 scrollInfo.fMask = SIF_POS;
4001 /* ALWAYS bPartial == FALSE, FOR NOW! */
4003 rcItem.left = LVIR_BOUNDS;
4004 if (LISTVIEW_GetItemRect(hwnd, nItem, &rcItem) != FALSE)
4006 if (rcItem.left < infoPtr->rcList.left)
4008 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4010 /* scroll left */
4011 bRedraw = TRUE;
4012 if (uView == LVS_LIST)
4014 nScrollPosWidth = infoPtr->nItemWidth;
4015 rcItem.left += infoPtr->rcList.left;
4017 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4019 nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
4020 rcItem.left += infoPtr->rcList.left;
4023 /* When in LVS_REPORT view, the scroll position should
4024 not be updated. */
4025 if (nScrollPosWidth != 0)
4027 if (rcItem.left % nScrollPosWidth == 0)
4029 scrollInfo.nPos += rcItem.left / nScrollPosWidth;
4031 else
4033 scrollInfo.nPos += rcItem.left / nScrollPosWidth - 1;
4036 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
4040 else if (rcItem.right > infoPtr->rcList.right)
4042 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4044 /* scroll right */
4045 bRedraw = TRUE;
4046 if (uView == LVS_LIST)
4048 rcItem.right -= infoPtr->rcList.right;
4049 nScrollPosWidth = infoPtr->nItemWidth;
4051 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4053 rcItem.right -= infoPtr->rcList.right;
4054 nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
4057 /* When in LVS_REPORT view, the scroll position should
4058 not be updated. */
4059 if (nScrollPosWidth != 0)
4061 if (rcItem.right % nScrollPosWidth == 0)
4063 scrollInfo.nPos += rcItem.right / nScrollPosWidth;
4065 else
4067 scrollInfo.nPos += rcItem.right / nScrollPosWidth + 1;
4070 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
4075 if (rcItem.top < infoPtr->rcList.top)
4077 /* scroll up */
4078 bRedraw = TRUE;
4079 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4081 if (uView == LVS_REPORT)
4083 rcItem.top -= infoPtr->rcList.top;
4084 nScrollPosHeight = infoPtr->nItemHeight;
4086 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
4088 nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
4089 rcItem.top += infoPtr->rcList.top;
4092 if (rcItem.top % nScrollPosHeight == 0)
4094 scrollInfo.nPos += rcItem.top / nScrollPosHeight;
4096 else
4098 scrollInfo.nPos += rcItem.top / nScrollPosHeight - 1;
4101 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
4104 else if (rcItem.bottom > infoPtr->rcList.bottom)
4106 /* scroll down */
4107 bRedraw = TRUE;
4108 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4110 if (uView == LVS_REPORT)
4112 rcItem.bottom -= infoPtr->rcList.bottom;
4113 nScrollPosHeight = infoPtr->nItemHeight;
4115 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
4117 nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
4118 rcItem.bottom -= infoPtr->rcList.bottom;
4121 if (rcItem.bottom % nScrollPosHeight == 0)
4123 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight;
4125 else
4127 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight + 1;
4130 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
4135 if(bRedraw)
4136 InvalidateRect(hwnd,NULL,TRUE);
4137 return TRUE;
4140 /***
4141 * DESCRIPTION:
4142 * Retrieves the nearest item, given a position and a direction.
4144 * PARAMETER(S):
4145 * [I] HWND : window handle
4146 * [I] POINT : start position
4147 * [I] UINT : direction
4149 * RETURN:
4150 * Item index if successdful, -1 otherwise.
4152 static INT LISTVIEW_GetNearestItem(HWND hwnd, POINT pt, UINT vkDirection)
4154 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4155 LVHITTESTINFO lvHitTestInfo;
4156 INT nItem = -1;
4157 RECT rcView;
4159 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
4161 ZeroMemory(&lvHitTestInfo, sizeof(LVHITTESTINFO));
4162 LISTVIEW_GetOrigin(hwnd, &lvHitTestInfo.pt);
4163 lvHitTestInfo.pt.x += pt.x;
4164 lvHitTestInfo.pt.y += pt.y;
4168 if (vkDirection == VK_DOWN)
4170 lvHitTestInfo.pt.y += infoPtr->nItemHeight;
4172 else if (vkDirection == VK_UP)
4174 lvHitTestInfo.pt.y -= infoPtr->nItemHeight;
4176 else if (vkDirection == VK_LEFT)
4178 lvHitTestInfo.pt.x -= infoPtr->nItemWidth;
4180 else if (vkDirection == VK_RIGHT)
4182 lvHitTestInfo.pt.x += infoPtr->nItemWidth;
4185 if (PtInRect(&rcView, lvHitTestInfo.pt) == FALSE)
4187 return -1;
4189 else
4191 nItem = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo);
4195 while (nItem == -1);
4198 return nItem;
4201 /***
4202 * DESCRIPTION:
4203 * Searches for an item with specific characteristics.
4205 * PARAMETER(S):
4206 * [I] HWND : window handle
4207 * [I] INT : base item index
4208 * [I] LPLVFINDINFO : item information to look for
4210 * RETURN:
4211 * SUCCESS : index of item
4212 * FAILURE : -1
4214 static LRESULT LISTVIEW_FindItem(HWND hwnd, INT nStart,
4215 LPLVFINDINFO lpFindInfo)
4217 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4218 POINT ptItem;
4219 CHAR szDispText[DISP_TEXT_SIZE];
4220 LVITEMA lvItem;
4221 BOOL bWrap = FALSE;
4222 INT nItem = nStart;
4223 INT nLast = GETITEMCOUNT(infoPtr);
4225 if ((nItem >= -1) && (lpFindInfo != NULL))
4227 ZeroMemory(&lvItem, sizeof(LVITEMA));
4229 if (lpFindInfo->flags & LVFI_PARAM)
4231 lvItem.mask |= LVIF_PARAM;
4234 if (lpFindInfo->flags & LVFI_STRING)
4236 lvItem.mask |= LVIF_TEXT;
4237 lvItem.pszText = szDispText;
4238 lvItem.cchTextMax = DISP_TEXT_SIZE;
4241 if (lpFindInfo->flags & LVFI_PARTIAL)
4243 lvItem.mask |= LVIF_TEXT;
4244 lvItem.pszText = szDispText;
4245 lvItem.cchTextMax = DISP_TEXT_SIZE;
4248 if (lpFindInfo->flags & LVFI_WRAP)
4250 bWrap = TRUE;
4253 if (lpFindInfo->flags & LVFI_NEARESTXY)
4255 ptItem.x = lpFindInfo->pt.x;
4256 ptItem.y = lpFindInfo->pt.y;
4259 while (1)
4261 while (nItem < nLast)
4263 if (lpFindInfo->flags & LVFI_NEARESTXY)
4265 nItem = LISTVIEW_GetNearestItem(hwnd, ptItem,
4266 lpFindInfo->vkDirection);
4267 if (nItem != -1)
4269 /* get position of the new item index */
4270 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) == FALSE)
4271 return -1;
4273 else
4274 return -1;
4276 else
4278 nItem++;
4281 lvItem.iItem = nItem;
4282 lvItem.iSubItem = 0;
4283 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
4285 if (lvItem.mask & LVIF_TEXT)
4287 if (lpFindInfo->flags & LVFI_PARTIAL)
4289 if (strstr(lvItem.pszText, lpFindInfo->psz) == NULL)
4290 continue;
4292 else
4294 if (strcmp(lvItem.pszText, lpFindInfo->psz) != 0)
4295 continue;
4299 if (lvItem.mask & LVIF_PARAM)
4301 if (lpFindInfo->lParam != lvItem.lParam)
4302 continue;
4305 return nItem;
4309 if (bWrap != FALSE)
4311 nItem = -1;
4312 nLast = nStart + 1;
4313 bWrap = FALSE;
4315 else
4317 return -1;
4322 return -1;
4325 /***
4326 * DESCRIPTION:
4327 * Retrieves the background color of the listview control.
4329 * PARAMETER(S):
4330 * [I] HWND : window handle
4332 * RETURN:
4333 * COLORREF associated with the background.
4335 static LRESULT LISTVIEW_GetBkColor(HWND hwnd)
4337 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4339 return infoPtr->clrBk;
4342 /***
4343 * DESCRIPTION:
4344 * Retrieves the background image of the listview control.
4346 * PARAMETER(S):
4347 * [I] HWND : window handle
4348 * [O] LPLVMKBIMAGE : background image attributes
4350 * RETURN:
4351 * SUCCESS : TRUE
4352 * FAILURE : FALSE`
4354 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
4355 /* { */
4356 /* FIXME (listview, "empty stub!\n"); */
4357 /* return FALSE; */
4358 /* } */
4360 /***
4361 * DESCRIPTION:
4362 * Retrieves the callback mask.
4364 * PARAMETER(S):
4365 * [I] HWND : window handle
4367 * RETURN:
4368 * Value of mask
4370 static UINT LISTVIEW_GetCallbackMask(HWND hwnd)
4372 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4374 return infoPtr->uCallbackMask;
4377 /***
4378 * DESCRIPTION:
4379 * Retrieves column attributes.
4381 * PARAMETER(S):
4382 * [I] HWND : window handle
4383 * [I] INT : column index
4384 * [IO] LPLVCOLUMNA : column information
4386 * RETURN:
4387 * SUCCESS : TRUE
4388 * FAILURE : FALSE
4390 static LRESULT LISTVIEW_GetColumnA(HWND hwnd, INT nItem, LPLVCOLUMNA lpColumn)
4392 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4393 HDITEMA hdi;
4394 BOOL bResult = FALSE;
4396 if (lpColumn != NULL)
4398 /* initialize memory */
4399 ZeroMemory(&hdi, sizeof(HDITEMA));
4401 if (lpColumn->mask & LVCF_FMT)
4403 hdi.mask |= HDI_FORMAT;
4406 if (lpColumn->mask & LVCF_WIDTH)
4408 hdi.mask |= HDI_WIDTH;
4411 if (lpColumn->mask & LVCF_TEXT)
4413 hdi.mask |= HDI_TEXT;
4414 hdi.cchTextMax = lpColumn->cchTextMax;
4415 hdi.pszText = lpColumn->pszText;
4418 if (lpColumn->mask & LVCF_IMAGE)
4420 hdi.mask |= HDI_IMAGE;
4423 if (lpColumn->mask & LVCF_ORDER)
4425 hdi.mask |= HDI_ORDER;
4428 bResult = Header_GetItemA(infoPtr->hwndHeader, nItem, &hdi);
4429 if (bResult != FALSE)
4431 if (lpColumn->mask & LVCF_FMT)
4433 lpColumn->fmt = 0;
4435 if (hdi.fmt & HDF_LEFT)
4437 lpColumn->fmt |= LVCFMT_LEFT;
4439 else if (hdi.fmt & HDF_RIGHT)
4441 lpColumn->fmt |= LVCFMT_RIGHT;
4443 else if (hdi.fmt & HDF_CENTER)
4445 lpColumn->fmt |= LVCFMT_CENTER;
4448 if (hdi.fmt & HDF_IMAGE)
4450 lpColumn->fmt |= LVCFMT_COL_HAS_IMAGES;
4453 if (hdi.fmt & HDF_BITMAP_ON_RIGHT)
4455 lpColumn->fmt |= LVCFMT_BITMAP_ON_RIGHT;
4459 if (lpColumn->mask & LVCF_WIDTH)
4461 lpColumn->cx = hdi.cxy;
4464 if (lpColumn->mask & LVCF_IMAGE)
4466 lpColumn->iImage = hdi.iImage;
4469 if (lpColumn->mask & LVCF_ORDER)
4471 lpColumn->iOrder = hdi.iOrder;
4476 return bResult;
4479 /* LISTVIEW_GetColumnW */
4482 static LRESULT LISTVIEW_GetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
4484 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
4485 INT i;
4487 if (!lpiArray)
4488 return FALSE;
4490 /* little hack */
4491 for (i = 0; i < iCount; i++)
4492 lpiArray[i] = i;
4494 return TRUE;
4497 /***
4498 * DESCRIPTION:
4499 * Retrieves the column width.
4501 * PARAMETER(S):
4502 * [I] HWND : window handle
4503 * [I] int : column index
4505 * RETURN:
4506 * SUCCESS : column width
4507 * FAILURE : zero
4509 static LRESULT LISTVIEW_GetColumnWidth(HWND hwnd, INT nColumn)
4511 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4512 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4513 INT nColumnWidth = 0;
4514 HDITEMA hdi;
4516 if (uView == LVS_LIST)
4518 nColumnWidth = infoPtr->nItemWidth;
4520 else if (uView == LVS_REPORT)
4522 /* get column width from header */
4523 ZeroMemory(&hdi, sizeof(HDITEMA));
4524 hdi.mask = HDI_WIDTH;
4525 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdi) != FALSE)
4527 nColumnWidth = hdi.cxy;
4531 return nColumnWidth;
4534 /***
4535 * DESCRIPTION:
4536 * In list or report display mode, retrieves the number of items that can fit
4537 * vertically in the visible area. In icon or small icon display mode,
4538 * retrieves the total number of visible items.
4540 * PARAMETER(S):
4541 * [I] HWND : window handle
4543 * RETURN:
4544 * Number of fully visible items.
4546 static LRESULT LISTVIEW_GetCountPerPage(HWND hwnd)
4548 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4549 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4550 INT nItemCount = 0;
4552 if (uView == LVS_LIST)
4554 if (infoPtr->rcList.right > infoPtr->nItemWidth)
4556 nItemCount = LISTVIEW_GetCountPerRow(hwnd) *
4557 LISTVIEW_GetCountPerColumn(hwnd);
4560 else if (uView == LVS_REPORT)
4562 nItemCount = LISTVIEW_GetCountPerColumn(hwnd);
4564 else
4566 nItemCount = GETITEMCOUNT(infoPtr);
4569 return nItemCount;
4572 /* LISTVIEW_GetEditControl */
4574 /***
4575 * DESCRIPTION:
4576 * Retrieves the extended listview style.
4578 * PARAMETERS:
4579 * [I] HWND : window handle
4581 * RETURN:
4582 * SUCCESS : previous style
4583 * FAILURE : 0
4585 static LRESULT LISTVIEW_GetExtendedListViewStyle(HWND hwnd)
4587 LISTVIEW_INFO *infoPtr;
4589 /* make sure we can get the listview info */
4590 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
4591 return (0);
4593 return (infoPtr->dwExStyle);
4596 /***
4597 * DESCRIPTION:
4598 * Retrieves the handle to the header control.
4600 * PARAMETER(S):
4601 * [I] HWND : window handle
4603 * RETURN:
4604 * Header handle.
4606 static LRESULT LISTVIEW_GetHeader(HWND hwnd)
4608 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4610 return infoPtr->hwndHeader;
4613 /* LISTVIEW_GetHotCursor */
4615 /***
4616 * DESCRIPTION:
4617 * Returns the time that the mouse cursor must hover over an item
4618 * before it is selected.
4620 * PARAMETER(S):
4621 * [I] HWND : window handle
4623 * RETURN:
4624 * Returns the previously set hover time or (DWORD)-1 to indicate that the
4625 * hover time is set to the default hover time.
4627 static LRESULT LISTVIEW_GetHoverTime(HWND hwnd)
4629 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4631 return infoPtr->dwHoverTime;
4634 /***
4635 * DESCRIPTION:
4636 * Retrieves an image list handle.
4638 * PARAMETER(S):
4639 * [I] HWND : window handle
4640 * [I] INT : image list identifier
4642 * RETURN:
4643 * SUCCESS : image list handle
4644 * FAILURE : NULL
4646 static LRESULT LISTVIEW_GetImageList(HWND hwnd, INT nImageList)
4648 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4649 HIMAGELIST himl = NULL;
4651 switch (nImageList)
4653 case LVSIL_NORMAL:
4654 himl = infoPtr->himlNormal;
4655 break;
4656 case LVSIL_SMALL:
4657 himl = infoPtr->himlSmall;
4658 break;
4659 case LVSIL_STATE:
4660 himl = infoPtr->himlState;
4661 break;
4664 return (LRESULT)himl;
4667 /* LISTVIEW_GetISearchString */
4669 /***
4670 * DESCRIPTION:
4671 * Retrieves item attributes.
4673 * PARAMETER(S):
4674 * [I] HWND : window handle
4675 * [IO] LPLVITEMA : item info
4676 * [I] internal : if true then we will use tricks that avoid copies
4677 * but are not compatible with the regular interface
4679 * RETURN:
4680 * SUCCESS : TRUE
4681 * FAILURE : FALSE
4683 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem, BOOL internal)
4685 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4686 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
4687 NMLVDISPINFOA dispInfo;
4688 LISTVIEW_SUBITEM *lpSubItem;
4689 LISTVIEW_ITEM *lpItem;
4690 INT* piImage;
4691 LPSTR* ppszText;
4692 HDPA hdpaSubItems;
4693 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4694 /* In the following:
4695 * lpLVItem describes the information requested by the user
4696 * lpItem/lpSubItem is what we have
4697 * dispInfo is a structure we use to request the missing
4698 * information from the application
4701 TRACE("(hwnd=%x, lpLVItem=%p)\n", hwnd, lpLVItem);
4703 if ((lpLVItem == NULL) ||
4704 (lpLVItem->iItem < 0) ||
4705 (lpLVItem->iItem >= GETITEMCOUNT(infoPtr))
4707 return FALSE;
4709 if (lStyle & LVS_OWNERDATA)
4711 if (lpLVItem->mask & ~LVIF_STATE)
4713 dispInfo.hdr.hwndFrom = hwnd;
4714 dispInfo.hdr.idFrom = lCtrlId;
4715 dispInfo.hdr.code = LVN_GETDISPINFOA;
4716 memcpy(&dispInfo.item,lpLVItem,sizeof(LVITEMA));
4718 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
4719 memcpy(lpLVItem,&dispInfo.item,sizeof(LVITEMA));
4722 if ((lpLVItem->mask & LVIF_STATE)&&(lpLVItem->iSubItem == 0))
4724 lpLVItem->state = 0;
4725 if (infoPtr->nFocusedItem == lpLVItem->iItem)
4726 lpLVItem->state |= LVIS_FOCUSED;
4727 if (LISTVIEW_IsSelected(hwnd,lpLVItem->iItem))
4728 lpLVItem->state |= LVIS_SELECTED;
4731 return TRUE;
4735 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
4736 if (hdpaSubItems == NULL)
4737 return FALSE;
4739 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
4740 if (lpItem == NULL)
4741 return FALSE;
4743 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
4744 if (lpLVItem->iSubItem == 0)
4746 piImage=&lpItem->iImage;
4747 ppszText=&lpItem->pszText;
4748 if ((infoPtr->uCallbackMask != 0) && (lpLVItem->mask & LVIF_STATE))
4750 dispInfo.item.mask |= LVIF_STATE;
4751 dispInfo.item.stateMask = infoPtr->uCallbackMask;
4754 else
4756 lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem);
4757 if (lpSubItem != NULL)
4759 piImage=&lpSubItem->iImage;
4760 ppszText=&lpSubItem->pszText;
4762 else
4764 piImage=NULL;
4765 ppszText=NULL;
4769 if ((lpLVItem->mask & LVIF_IMAGE) &&
4770 ((piImage==NULL) || (*piImage == I_IMAGECALLBACK)))
4772 dispInfo.item.mask |= LVIF_IMAGE;
4775 if ((lpLVItem->mask & LVIF_TEXT) &&
4776 ((ppszText==NULL) || (*ppszText == LPSTR_TEXTCALLBACKA)))
4778 dispInfo.item.mask |= LVIF_TEXT;
4779 dispInfo.item.pszText = lpLVItem->pszText;
4780 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
4783 if (dispInfo.item.mask != 0)
4785 /* We don't have all the requested info, query the application */
4786 dispInfo.hdr.hwndFrom = hwnd;
4787 dispInfo.hdr.idFrom = lCtrlId;
4788 dispInfo.hdr.code = LVN_GETDISPINFOA;
4789 dispInfo.item.iItem = lpLVItem->iItem;
4790 dispInfo.item.iSubItem = lpLVItem->iSubItem;
4791 dispInfo.item.lParam = lpItem->lParam;
4792 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
4795 if (dispInfo.item.mask & LVIF_IMAGE)
4797 lpLVItem->iImage = dispInfo.item.iImage;
4799 else if (lpLVItem->mask & LVIF_IMAGE)
4801 lpLVItem->iImage = *piImage;
4804 if (dispInfo.item.mask & LVIF_PARAM)
4806 lpLVItem->lParam = dispInfo.item.lParam;
4808 else if (lpLVItem->mask & LVIF_PARAM)
4810 lpLVItem->lParam = lpItem->lParam;
4813 if (dispInfo.item.mask & LVIF_TEXT)
4815 if ((dispInfo.item.mask & LVIF_DI_SETITEM) && (ppszText != NULL))
4817 Str_SetPtrA(ppszText, dispInfo.item.pszText);
4819 /* If lpLVItem->pszText==dispInfo.item.pszText a copy is unnecessary, but */
4820 /* some apps give a new pointer in ListView_Notify so we can't be sure. */
4821 if (lpLVItem->pszText!=dispInfo.item.pszText) {
4822 lstrcpynA(lpLVItem->pszText, dispInfo.item.pszText, lpLVItem->cchTextMax);
4825 else if (lpLVItem->mask & LVIF_TEXT)
4827 if (internal==TRUE)
4829 lpLVItem->pszText=*ppszText;
4830 } else {
4831 lstrcpynA(lpLVItem->pszText, *ppszText, lpLVItem->cchTextMax);
4835 if (lpLVItem->iSubItem == 0)
4837 if (dispInfo.item.mask & LVIF_STATE)
4839 lpLVItem->state = lpItem->state;
4840 lpLVItem->state &= ~dispInfo.item.stateMask;
4841 lpLVItem->state |= (dispInfo.item.state & dispInfo.item.stateMask);
4843 lpLVItem->state &= ~LVIS_SELECTED;
4844 if ((dispInfo.item.stateMask & LVIS_SELECTED) &&
4845 (LISTVIEW_IsSelected(hwnd,dispInfo.item.iItem)))
4846 lpLVItem->state |= LVIS_SELECTED;
4848 else if (lpLVItem->mask & LVIF_STATE)
4850 lpLVItem->state = lpItem->state & lpLVItem->stateMask;
4852 lpLVItem->state &= ~LVIS_SELECTED;
4853 if ((lpLVItem->stateMask & LVIS_SELECTED) &&
4854 (LISTVIEW_IsSelected(hwnd,lpLVItem->iItem)))
4855 lpLVItem->state |= LVIS_SELECTED;
4858 if (lpLVItem->mask & LVIF_PARAM)
4860 lpLVItem->lParam = lpItem->lParam;
4863 if (lpLVItem->mask & LVIF_INDENT)
4865 lpLVItem->iIndent = lpItem->iIndent;
4869 return TRUE;
4872 /* LISTVIEW_GetItemW */
4873 /* LISTVIEW_GetHotCursor */
4875 /***
4876 * DESCRIPTION:
4877 * Retrieves the index of the hot item.
4879 * PARAMETERS:
4880 * [I] HWND : window handle
4882 * RETURN:
4883 * SUCCESS : hot item index
4884 * FAILURE : -1 (no hot item)
4886 static LRESULT LISTVIEW_GetHotItem(HWND hwnd)
4888 LISTVIEW_INFO *infoPtr;
4890 /* make sure we can get the listview info */
4891 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
4892 return (-1);
4894 return (infoPtr->nHotItem);
4897 /* LISTVIEW_GetHoverTime */
4899 /***
4900 * DESCRIPTION:
4901 * Retrieves the number of items in the listview control.
4903 * PARAMETER(S):
4904 * [I] HWND : window handle
4906 * RETURN:
4907 * Number of items.
4909 static LRESULT LISTVIEW_GetItemCount(HWND hwnd)
4911 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4913 return GETITEMCOUNT(infoPtr);
4916 /***
4917 * DESCRIPTION:
4918 * Retrieves the position (upper-left) of the listview control item.
4920 * PARAMETER(S):
4921 * [I] HWND : window handle
4922 * [I] INT : item index
4923 * [O] LPPOINT : coordinate information
4925 * RETURN:
4926 * SUCCESS : TRUE
4927 * FAILURE : FALSE
4929 static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem,
4930 LPPOINT lpptPosition)
4932 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4933 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4934 BOOL bResult = FALSE;
4935 HDPA hdpaSubItems;
4936 LISTVIEW_ITEM *lpItem;
4937 INT nCountPerColumn;
4938 INT nRow;
4940 TRACE("(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd, nItem,
4941 lpptPosition);
4943 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
4944 (lpptPosition != NULL))
4946 if (uView == LVS_LIST)
4948 bResult = TRUE;
4949 nItem = nItem - ListView_GetTopIndex(hwnd);
4950 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
4951 if (nItem < 0)
4953 nRow = nItem % nCountPerColumn;
4954 if (nRow == 0)
4956 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
4957 lpptPosition->y = 0;
4959 else
4961 lpptPosition->x = (nItem / nCountPerColumn -1) * infoPtr->nItemWidth;
4962 lpptPosition->y = (nRow + nCountPerColumn) * infoPtr->nItemHeight;
4965 else
4967 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
4968 lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight;
4971 else if (uView == LVS_REPORT)
4973 bResult = TRUE;
4974 lpptPosition->x = REPORT_MARGINX;
4975 lpptPosition->y = ((nItem - ListView_GetTopIndex(hwnd)) *
4976 infoPtr->nItemHeight) + infoPtr->rcList.top;
4978 else
4980 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
4981 if (hdpaSubItems != NULL)
4983 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
4984 if (lpItem != NULL)
4986 bResult = TRUE;
4987 lpptPosition->x = lpItem->ptPosition.x;
4988 lpptPosition->y = lpItem->ptPosition.y;
4993 return bResult;
4996 /***
4997 * DESCRIPTION:
4998 * Retrieves the bounding rectangle for a listview control item.
5000 * PARAMETER(S):
5001 * [I] HWND : window handle
5002 * [I] INT : item index
5003 * [IO] LPRECT : bounding rectangle coordinates
5005 * RETURN:
5006 * SUCCESS : TRUE
5007 * FAILURE : FALSE
5009 static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc)
5011 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5012 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5013 BOOL bResult = FALSE;
5014 POINT ptOrigin;
5015 POINT ptItem;
5016 HDC hdc;
5017 HFONT hOldFont;
5018 INT nLeftPos;
5019 INT nLabelWidth;
5020 INT nIndent;
5021 TEXTMETRICA tm;
5022 LVITEMA lvItem;
5024 TRACE("(hwnd=%x, nItem=%d, lprc=%p)\n", hwnd, nItem, lprc);
5026 if (uView & LVS_REPORT)
5028 ZeroMemory(&lvItem, sizeof(LVITEMA));
5029 lvItem.mask = LVIF_INDENT;
5030 lvItem.iItem = nItem;
5031 lvItem.iSubItem = 0;
5032 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
5034 /* do indent */
5035 if (lvItem.iIndent>0 && infoPtr->iconSize.cx > 0)
5037 nIndent = infoPtr->iconSize.cx * lvItem.iIndent;
5039 else
5040 nIndent = 0;
5042 else
5043 nIndent = 0;
5045 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL))
5047 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) != FALSE)
5049 switch(lprc->left)
5051 case LVIR_ICON:
5052 if (uView == LVS_ICON)
5054 if (infoPtr->himlNormal != NULL)
5056 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5058 bResult = TRUE;
5059 lprc->left = ptItem.x + ptOrigin.x;
5060 lprc->top = ptItem.y + ptOrigin.y;
5061 lprc->right = lprc->left + infoPtr->iconSize.cx;
5062 lprc->bottom = (lprc->top + infoPtr->iconSize.cy +
5063 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
5067 else if (uView == LVS_SMALLICON)
5069 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5071 bResult = TRUE;
5072 lprc->left = ptItem.x + ptOrigin.x;
5073 lprc->top = ptItem.y + ptOrigin.y;
5074 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5076 if (infoPtr->himlState != NULL)
5077 lprc->left += infoPtr->iconSize.cx;
5079 if (infoPtr->himlSmall != NULL)
5080 lprc->right = lprc->left + infoPtr->iconSize.cx;
5081 else
5082 lprc->right = lprc->left;
5085 else
5087 bResult = TRUE;
5088 lprc->left = ptItem.x;
5089 if (uView & LVS_REPORT)
5090 lprc->left += nIndent;
5091 lprc->top = ptItem.y;
5092 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5094 if (infoPtr->himlState != NULL)
5096 lprc->left += infoPtr->iconSize.cx;
5099 if (infoPtr->himlSmall != NULL)
5101 lprc->right = lprc->left + infoPtr->iconSize.cx;
5103 else
5105 lprc->right = lprc->left;
5108 break;
5110 case LVIR_LABEL:
5111 if (uView == LVS_ICON)
5113 if (infoPtr->himlNormal != NULL)
5115 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5117 bResult = TRUE;
5118 lprc->left = ptItem.x + ptOrigin.x;
5119 lprc->top = (ptItem.y + ptOrigin.y + infoPtr->iconSize.cy +
5120 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
5121 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5122 if (infoPtr->iconSpacing.cx - nLabelWidth > 1)
5124 lprc->left += (infoPtr->iconSpacing.cx - nLabelWidth) / 2;
5125 lprc->right = lprc->left + nLabelWidth;
5127 else
5129 lprc->left += 1;
5130 lprc->right = lprc->left + infoPtr->iconSpacing.cx - 1;
5133 hdc = GetDC(hwnd);
5134 hOldFont = SelectObject(hdc, infoPtr->hFont);
5135 GetTextMetricsA(hdc, &tm);
5136 lprc->bottom = lprc->top + tm.tmHeight + HEIGHT_PADDING;
5137 SelectObject(hdc, hOldFont);
5138 ReleaseDC(hwnd, hdc);
5142 else if (uView == LVS_SMALLICON)
5144 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5146 bResult = TRUE;
5147 nLeftPos = lprc->left = ptItem.x + ptOrigin.x;
5148 lprc->top = ptItem.y + ptOrigin.y;
5149 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5151 if (infoPtr->himlState != NULL)
5153 lprc->left += infoPtr->iconSize.cx;
5156 if (infoPtr->himlSmall != NULL)
5158 lprc->left += infoPtr->iconSize.cx;
5161 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5162 nLabelWidth += TRAILING_PADDING;
5163 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5165 lprc->right = lprc->left + nLabelWidth;
5167 else
5169 lprc->right = nLeftPos + infoPtr->nItemWidth;
5173 else
5175 bResult = TRUE;
5176 if (uView & LVS_REPORT)
5177 nLeftPos = lprc->left = ptItem.x + nIndent;
5178 else
5179 nLeftPos = lprc->left = ptItem.x;
5180 lprc->top = ptItem.y;
5181 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5183 if (infoPtr->himlState != NULL)
5185 lprc->left += infoPtr->iconSize.cx;
5188 if (infoPtr->himlSmall != NULL)
5190 lprc->left += infoPtr->iconSize.cx;
5193 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5194 nLabelWidth += TRAILING_PADDING;
5195 if (infoPtr->himlSmall)
5196 nLabelWidth += IMAGE_PADDING;
5197 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5199 lprc->right = lprc->left + nLabelWidth;
5201 else
5203 lprc->right = nLeftPos + infoPtr->nItemWidth;
5206 break;
5208 case LVIR_BOUNDS:
5209 if (uView == LVS_ICON)
5211 if (infoPtr->himlNormal != NULL)
5213 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5215 bResult = TRUE;
5216 lprc->left = ptItem.x + ptOrigin.x;
5217 lprc->top = ptItem.y + ptOrigin.y;
5218 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
5219 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
5223 else if (uView == LVS_SMALLICON)
5225 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5227 bResult = TRUE;
5228 lprc->left = ptItem.x + ptOrigin.x;
5229 lprc->right = lprc->left;
5230 lprc->top = ptItem.y + ptOrigin.y;
5231 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5232 if (infoPtr->himlState != NULL)
5233 lprc->right += infoPtr->iconSize.cx;
5234 if (infoPtr->himlSmall != NULL)
5235 lprc->right += infoPtr->iconSize.cx;
5237 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5238 nLabelWidth += TRAILING_PADDING;
5239 if (infoPtr->himlSmall)
5240 nLabelWidth += IMAGE_PADDING;
5241 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
5243 lprc->right += nLabelWidth;
5245 else
5247 lprc->right = lprc->left + infoPtr->nItemWidth;
5251 else
5253 bResult = TRUE;
5254 lprc->left = ptItem.x;
5255 if (!(infoPtr->dwExStyle&LVS_EX_FULLROWSELECT) && uView&LVS_REPORT)
5256 lprc->left += nIndent;
5257 lprc->right = lprc->left;
5258 lprc->top = ptItem.y;
5259 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5261 if (infoPtr->dwExStyle & LVS_EX_FULLROWSELECT)
5263 RECT br;
5264 int nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
5265 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
5267 lprc->right = max(lprc->left, br.right - REPORT_MARGINX);
5269 else
5271 if (infoPtr->himlState != NULL)
5273 lprc->right += infoPtr->iconSize.cx;
5276 if (infoPtr->himlSmall != NULL)
5278 lprc->right += infoPtr->iconSize.cx;
5281 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5282 nLabelWidth += TRAILING_PADDING;
5283 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
5285 lprc->right += nLabelWidth;
5287 else
5289 lprc->right = lprc->left + infoPtr->nItemWidth;
5293 break;
5295 case LVIR_SELECTBOUNDS:
5296 if (uView == LVS_ICON)
5298 if (infoPtr->himlNormal != NULL)
5300 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5302 bResult = TRUE;
5303 lprc->left = ptItem.x + ptOrigin.x;
5304 lprc->top = ptItem.y + ptOrigin.y;
5305 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
5306 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
5310 else if (uView == LVS_SMALLICON)
5312 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5314 bResult = TRUE;
5315 nLeftPos= lprc->left = ptItem.x + ptOrigin.x;
5316 lprc->top = ptItem.y + ptOrigin.y;
5317 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5319 if (infoPtr->himlState != NULL)
5321 lprc->left += infoPtr->iconSize.cx;
5324 lprc->right = lprc->left;
5326 if (infoPtr->himlSmall != NULL)
5328 lprc->right += infoPtr->iconSize.cx;
5331 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5332 nLabelWidth += TRAILING_PADDING;
5333 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5335 lprc->right += nLabelWidth;
5337 else
5339 lprc->right = nLeftPos + infoPtr->nItemWidth;
5343 else
5345 bResult = TRUE;
5346 if (!(infoPtr->dwExStyle&LVS_EX_FULLROWSELECT) && (uView&LVS_REPORT))
5347 nLeftPos = lprc->left = ptItem.x + nIndent;
5348 else
5349 nLeftPos = lprc->left = ptItem.x;
5350 lprc->top = ptItem.y;
5351 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5353 if (infoPtr->himlState != NULL)
5355 lprc->left += infoPtr->iconSize.cx;
5358 lprc->right = lprc->left;
5360 if (infoPtr->dwExStyle & LVS_EX_FULLROWSELECT)
5362 RECT br;
5363 int nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
5364 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
5366 lprc->right = max(lprc->left, br.right - REPORT_MARGINX);
5368 else
5370 if (infoPtr->himlSmall != NULL)
5372 lprc->right += infoPtr->iconSize.cx;
5375 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5376 nLabelWidth += TRAILING_PADDING;
5377 if (infoPtr->himlSmall)
5378 nLabelWidth += IMAGE_PADDING;
5379 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5381 lprc->right += nLabelWidth;
5383 else
5385 lprc->right = nLeftPos + infoPtr->nItemWidth;
5389 break;
5393 return bResult;
5396 /***
5397 * DESCRIPTION:
5398 * Retrieves the width of a label.
5400 * PARAMETER(S):
5401 * [I] HWND : window handle
5403 * RETURN:
5404 * SUCCESS : string width (in pixels)
5405 * FAILURE : zero
5407 static INT LISTVIEW_GetLabelWidth(HWND hwnd, INT nItem)
5409 CHAR szDispText[DISP_TEXT_SIZE];
5410 INT nLabelWidth = 0;
5411 LVITEMA lvItem;
5413 TRACE("(hwnd=%x, nItem=%d)\n", hwnd, nItem);
5415 ZeroMemory(&lvItem, sizeof(LVITEMA));
5416 lvItem.mask = LVIF_TEXT;
5417 lvItem.iItem = nItem;
5418 lvItem.cchTextMax = DISP_TEXT_SIZE;
5419 lvItem.pszText = szDispText;
5420 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
5422 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
5425 return nLabelWidth;
5428 /***
5429 * DESCRIPTION:
5430 * Retrieves the spacing between listview control items.
5432 * PARAMETER(S):
5433 * [I] HWND : window handle
5434 * [I] BOOL : flag for small or large icon
5436 * RETURN:
5437 * Horizontal + vertical spacing
5439 static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall)
5441 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5442 LONG lResult;
5444 if (bSmall == FALSE)
5446 lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
5448 else
5450 /* TODO: need to store width of smallicon item */
5451 lResult = MAKELONG(0, infoPtr->nItemHeight);
5454 return lResult;
5457 /***
5458 * DESCRIPTION:
5459 * Retrieves the state of a listview control item.
5461 * PARAMETER(S):
5462 * [I] HWND : window handle
5463 * [I] INT : item index
5464 * [I] UINT : state mask
5466 * RETURN:
5467 * State specified by the mask.
5469 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask)
5471 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5472 LVITEMA lvItem;
5473 UINT uState = 0;
5475 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5477 ZeroMemory(&lvItem, sizeof(LVITEMA));
5478 lvItem.iItem = nItem;
5479 lvItem.stateMask = uMask;
5480 lvItem.mask = LVIF_STATE;
5481 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
5483 uState = lvItem.state;
5487 return uState;
5490 /***
5491 * DESCRIPTION:
5492 * Retrieves the text of a listview control item or subitem.
5494 * PARAMETER(S):
5495 * [I] HWND : window handle
5496 * [I] INT : item index
5497 * [IO] LPLVITEMA : item information
5499 * RETURN:
5500 * SUCCESS : string length
5501 * FAILURE : 0
5503 static LRESULT LISTVIEW_GetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5505 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5506 INT nLength = 0;
5508 if (lpLVItem != NULL)
5510 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5512 lpLVItem->mask = LVIF_TEXT;
5513 lpLVItem->iItem = nItem;
5514 if (LISTVIEW_GetItemA(hwnd, lpLVItem, FALSE) != FALSE)
5516 nLength = lstrlenA(lpLVItem->pszText);
5521 return nLength;
5524 /***
5525 * DESCRIPTION:
5526 * Searches for an item based on properties + relationships.
5528 * PARAMETER(S):
5529 * [I] HWND : window handle
5530 * [I] INT : item index
5531 * [I] INT : relationship flag
5533 * RETURN:
5534 * SUCCESS : item index
5535 * FAILURE : -1
5537 static LRESULT LISTVIEW_GetNextItem(HWND hwnd, INT nItem, UINT uFlags)
5539 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5540 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5541 UINT uMask = 0;
5542 LVFINDINFO lvFindInfo;
5543 INT nCountPerColumn;
5544 INT i;
5546 if ((nItem >= -1) && (nItem < GETITEMCOUNT(infoPtr)))
5548 ZeroMemory(&lvFindInfo, sizeof(LVFINDINFO));
5550 if (uFlags & LVNI_CUT)
5551 uMask |= LVIS_CUT;
5553 if (uFlags & LVNI_DROPHILITED)
5554 uMask |= LVIS_DROPHILITED;
5556 if (uFlags & LVNI_FOCUSED)
5557 uMask |= LVIS_FOCUSED;
5559 if (uFlags & LVNI_SELECTED)
5560 uMask |= LVIS_SELECTED;
5562 if (uFlags & LVNI_ABOVE)
5564 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
5566 while (nItem >= 0)
5568 nItem--;
5569 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5570 return nItem;
5573 else
5575 lvFindInfo.flags = LVFI_NEARESTXY;
5576 lvFindInfo.vkDirection = VK_UP;
5577 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5578 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5580 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5581 return nItem;
5585 else if (uFlags & LVNI_BELOW)
5587 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
5589 while (nItem < GETITEMCOUNT(infoPtr))
5591 nItem++;
5592 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5593 return nItem;
5596 else
5598 lvFindInfo.flags = LVFI_NEARESTXY;
5599 lvFindInfo.vkDirection = VK_DOWN;
5600 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5601 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5603 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5604 return nItem;
5608 else if (uFlags & LVNI_TOLEFT)
5610 if (uView == LVS_LIST)
5612 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
5613 while (nItem - nCountPerColumn >= 0)
5615 nItem -= nCountPerColumn;
5616 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5617 return nItem;
5620 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
5622 lvFindInfo.flags = LVFI_NEARESTXY;
5623 lvFindInfo.vkDirection = VK_LEFT;
5624 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5625 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5627 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5628 return nItem;
5632 else if (uFlags & LVNI_TORIGHT)
5634 if (uView == LVS_LIST)
5636 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
5637 while (nItem + nCountPerColumn < GETITEMCOUNT(infoPtr))
5639 nItem += nCountPerColumn;
5640 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5641 return nItem;
5644 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
5646 lvFindInfo.flags = LVFI_NEARESTXY;
5647 lvFindInfo.vkDirection = VK_RIGHT;
5648 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5649 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5651 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5652 return nItem;
5656 else
5658 nItem++;
5660 /* search by index */
5661 for (i = nItem; i < GETITEMCOUNT(infoPtr); i++)
5663 if ((ListView_GetItemState(hwnd, i, uMask) & uMask) == uMask)
5664 return i;
5669 return -1;
5672 /* LISTVIEW_GetNumberOfWorkAreas */
5674 /***
5675 * DESCRIPTION:
5676 * Retrieves the origin coordinates when in icon or small icon display mode.
5678 * PARAMETER(S):
5679 * [I] HWND : window handle
5680 * [O] LPPOINT : coordinate information
5682 * RETURN:
5683 * SUCCESS : TRUE
5684 * FAILURE : FALSE
5686 static LRESULT LISTVIEW_GetOrigin(HWND hwnd, LPPOINT lpptOrigin)
5688 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5689 UINT uView = lStyle & LVS_TYPEMASK;
5690 BOOL bResult = FALSE;
5692 TRACE("(hwnd=%x, lpptOrigin=%p)\n", hwnd, lpptOrigin);
5694 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
5696 SCROLLINFO scrollInfo;
5697 ZeroMemory(lpptOrigin, sizeof(POINT));
5698 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
5699 scrollInfo.cbSize = sizeof(SCROLLINFO);
5701 if (lStyle & WS_HSCROLL)
5703 scrollInfo.fMask = SIF_POS;
5704 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
5706 lpptOrigin->x = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
5710 if (lStyle & WS_VSCROLL)
5712 scrollInfo.fMask = SIF_POS;
5713 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
5715 lpptOrigin->y = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
5719 bResult = TRUE;
5722 return bResult;
5725 /***
5726 * DESCRIPTION:
5727 * Retrieves the number of items that are marked as selected.
5729 * PARAMETER(S):
5730 * [I] HWND : window handle
5732 * RETURN:
5733 * Number of items selected.
5735 static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd)
5737 /* REDO THIS */
5738 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5739 INT nSelectedCount = 0;
5740 INT i;
5742 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
5744 if (ListView_GetItemState(hwnd, i, LVIS_SELECTED) & LVIS_SELECTED)
5746 nSelectedCount++;
5750 return nSelectedCount;
5753 /***
5754 * DESCRIPTION:
5755 * Retrieves item index that marks the start of a multiple selection.
5757 * PARAMETER(S):
5758 * [I] HWND : window handle
5760 * RETURN:
5761 * Index number or -1 if there is no selection mark.
5763 static LRESULT LISTVIEW_GetSelectionMark(HWND hwnd)
5765 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5767 return infoPtr->nSelectionMark;
5770 /***
5771 * DESCRIPTION:
5772 * Retrieves the width of a string.
5774 * PARAMETER(S):
5775 * [I] HWND : window handle
5777 * RETURN:
5778 * SUCCESS : string width (in pixels)
5779 * FAILURE : zero
5781 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText)
5783 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5784 HFONT hFont, hOldFont;
5785 SIZE stringSize;
5786 HDC hdc;
5788 ZeroMemory(&stringSize, sizeof(SIZE));
5789 if (lpszText != NULL && lpszText != (LPCSTR)-1)
5791 hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
5792 hdc = GetDC(hwnd);
5793 hOldFont = SelectObject(hdc, hFont);
5794 GetTextExtentPointA(hdc, lpszText, lstrlenA(lpszText), &stringSize);
5795 SelectObject(hdc, hOldFont);
5796 ReleaseDC(hwnd, hdc);
5799 return stringSize.cx;
5802 /***
5803 * DESCRIPTION:
5804 * Retrieves the text backgound color.
5806 * PARAMETER(S):
5807 * [I] HWND : window handle
5809 * RETURN:
5810 * COLORREF associated with the the background.
5812 static LRESULT LISTVIEW_GetTextBkColor(HWND hwnd)
5814 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5816 return infoPtr->clrTextBk;
5819 /***
5820 * DESCRIPTION:
5821 * Retrieves the text color.
5823 * PARAMETER(S):
5824 * [I] HWND : window handle
5826 * RETURN:
5827 * COLORREF associated with the text.
5829 static LRESULT LISTVIEW_GetTextColor(HWND hwnd)
5831 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5833 return infoPtr->clrText;
5836 /***
5837 * DESCRIPTION:
5838 * Determines which section of the item was selected (if any).
5840 * PARAMETER(S):
5841 * [I] HWND : window handle
5842 * [IO] LPLVHITTESTINFO : hit test information
5844 * RETURN:
5845 * SUCCESS : item index
5846 * FAILURE : -1
5848 static INT LISTVIEW_HitTestItem(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
5850 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5851 RECT rcItem;
5852 INT i,topindex,bottomindex;
5853 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5854 UINT uView = lStyle & LVS_TYPEMASK;
5857 TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpHitTestInfo->pt.x,
5858 lpHitTestInfo->pt.y);
5860 topindex = ListView_GetTopIndex(hwnd);
5861 if (uView == LVS_REPORT)
5863 bottomindex = topindex + LISTVIEW_GetCountPerColumn(hwnd) + 1;
5864 bottomindex = min(bottomindex,GETITEMCOUNT(infoPtr));
5866 else
5868 bottomindex = GETITEMCOUNT(infoPtr);
5871 for (i = topindex; i < bottomindex; i++)
5873 rcItem.left = LVIR_BOUNDS;
5874 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
5876 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
5878 rcItem.left = LVIR_ICON;
5879 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
5881 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
5883 lpHitTestInfo->flags = LVHT_ONITEMICON;
5884 lpHitTestInfo->iItem = i;
5885 lpHitTestInfo->iSubItem = 0;
5886 return i;
5890 rcItem.left = LVIR_LABEL;
5891 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
5893 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
5895 lpHitTestInfo->flags = LVHT_ONITEMLABEL;
5896 lpHitTestInfo->iItem = i;
5897 lpHitTestInfo->iSubItem = 0;
5898 return i;
5902 lpHitTestInfo->flags = LVHT_ONITEMSTATEICON;
5903 lpHitTestInfo->iItem = i;
5904 lpHitTestInfo->iSubItem = 0;
5905 return i;
5910 lpHitTestInfo->flags = LVHT_NOWHERE;
5912 return -1;
5915 /***
5916 * DESCRIPTION:
5917 * Determines which listview item is located at the specified position.
5919 * PARAMETER(S):
5920 * [I] HWND : window handle
5921 * [IO} LPLVHITTESTINFO : hit test information
5923 * RETURN:
5924 * SUCCESS : item index
5925 * FAILURE : -1
5927 static LRESULT LISTVIEW_HitTest(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
5929 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5930 INT nItem = -1;
5932 lpHitTestInfo->flags = 0;
5934 if (infoPtr->rcList.left > lpHitTestInfo->pt.x)
5936 lpHitTestInfo->flags = LVHT_TOLEFT;
5938 else if (infoPtr->rcList.right < lpHitTestInfo->pt.x)
5940 lpHitTestInfo->flags = LVHT_TORIGHT;
5942 if (infoPtr->rcList.top > lpHitTestInfo->pt.y)
5944 lpHitTestInfo->flags |= LVHT_ABOVE;
5946 else if (infoPtr->rcList.bottom < lpHitTestInfo->pt.y)
5948 lpHitTestInfo->flags |= LVHT_BELOW;
5951 if (lpHitTestInfo->flags == 0)
5953 nItem = LISTVIEW_HitTestItem(hwnd, lpHitTestInfo);
5956 return nItem;
5959 /***
5960 * DESCRIPTION:
5961 * Inserts a new column.
5963 * PARAMETER(S):
5964 * [I] HWND : window handle
5965 * [I] INT : column index
5966 * [I] LPLVCOLUMNA : column information
5968 * RETURN:
5969 * SUCCESS : new column index
5970 * FAILURE : -1
5972 static LRESULT LISTVIEW_InsertColumnA(HWND hwnd, INT nColumn,
5973 LPLVCOLUMNA lpColumn)
5975 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5976 HDITEMA hdi;
5977 INT nNewColumn = -1;
5979 TRACE("(hwnd=%x, nColumn=%d, lpColumn=%p)\n",hwnd, nColumn,
5980 lpColumn);
5982 if (lpColumn != NULL)
5984 /* initialize memory */
5985 ZeroMemory(&hdi, sizeof(HDITEMA));
5987 if (lpColumn->mask & LVCF_FMT)
5989 /* format member is valid */
5990 hdi.mask |= HDI_FORMAT;
5992 /* set text alignment (leftmost column must be left-aligned) */
5993 if (nColumn == 0)
5995 hdi.fmt |= HDF_LEFT;
5997 else
5999 if (lpColumn->fmt & LVCFMT_LEFT)
6001 hdi.fmt |= HDF_LEFT;
6003 else if (lpColumn->fmt & LVCFMT_RIGHT)
6005 hdi.fmt |= HDF_RIGHT;
6007 else if (lpColumn->fmt & LVCFMT_CENTER)
6009 hdi.fmt |= HDF_CENTER;
6013 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
6015 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
6016 /* ??? */
6019 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
6021 /* ??? */
6024 if (lpColumn->fmt & LVCFMT_IMAGE)
6026 hdi.fmt |= HDF_IMAGE;
6027 hdi.iImage = I_IMAGECALLBACK;
6031 if (lpColumn->mask & LVCF_WIDTH)
6033 hdi.mask |= HDI_WIDTH;
6034 hdi.cxy = lpColumn->cx;
6037 if (lpColumn->mask & LVCF_TEXT)
6039 hdi.mask |= HDI_TEXT | HDI_FORMAT;
6040 hdi.pszText = lpColumn->pszText;
6041 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
6042 hdi.fmt |= HDF_STRING;
6045 if (lpColumn->mask & LVCF_IMAGE)
6047 hdi.mask |= HDI_IMAGE;
6048 hdi.iImage = lpColumn->iImage;
6051 if (lpColumn->mask & LVCF_ORDER)
6053 hdi.mask |= HDI_ORDER;
6054 hdi.iOrder = lpColumn->iOrder;
6057 /* insert item in header control */
6058 nNewColumn = SendMessageA(infoPtr->hwndHeader, HDM_INSERTITEMA,
6059 (WPARAM)nColumn, (LPARAM)&hdi);
6061 /* Need to reset the item width when inserting a new column */
6062 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6064 LISTVIEW_UpdateScroll(hwnd);
6065 InvalidateRect(hwnd, NULL, FALSE);
6068 return nNewColumn;
6071 static LRESULT LISTVIEW_InsertColumnW(HWND hwnd, INT nColumn,
6072 LPLVCOLUMNW lpColumn)
6074 LVCOLUMNA lvca;
6075 LRESULT lres;
6077 memcpy(&lvca,lpColumn,sizeof(lvca));
6078 if (lpColumn->mask & LVCF_TEXT)
6079 lvca.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpColumn->pszText);
6080 lres = LISTVIEW_InsertColumnA(hwnd,nColumn,&lvca);
6081 if (lpColumn->mask & LVCF_TEXT)
6082 HeapFree(GetProcessHeap(),0,lvca.pszText);
6083 return lres;
6086 /* LISTVIEW_InsertCompare: callback routine for comparing pszText members of the LV_ITEMS
6087 in a LISTVIEW on insert. Passed to DPA_Sort in LISTVIEW_InsertItem.
6088 This function should only be used for inserting items into a sorted list (LVM_INSERTITEM)
6089 and not during the processing of a LVM_SORTITEMS message. Applications should provide
6090 their own sort proc. when sending LVM_SORTITEMS.
6092 /* Platform SDK:
6093 (remarks on LVITEM: LVM_INSERTITEM will insert the new item in the proper sort postion...
6095 LVS_SORTXXX must be specified,
6096 LVS_OWNERDRAW is not set,
6097 <item>.pszText is not LPSTR_TEXTCALLBACK.
6099 (LVS_SORT* flags): "For the LVS_SORTASCENDING... styles, item indices
6100 are sorted based on item text..."
6102 static INT WINAPI LISTVIEW_InsertCompare( LPVOID first, LPVOID second, LPARAM lParam)
6104 HDPA hdpa_first = (HDPA) first;
6105 HDPA hdpa_second = (HDPA) second;
6106 LISTVIEW_ITEM* lv_first = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_first, 0 );
6107 LISTVIEW_ITEM* lv_second = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_second, 0 );
6108 LONG lStyle = GetWindowLongA((HWND) lParam, GWL_STYLE);
6109 INT cmpv = lstrcmpA( lv_first->pszText, lv_second->pszText );
6110 /* if we're sorting descending, negate the return value */
6111 return (lStyle & LVS_SORTDESCENDING) ? -cmpv : cmpv;
6114 /***
6115 * nESCRIPTION:
6116 * Inserts a new item in the listview control.
6118 * PARAMETER(S):
6119 * [I] HWND : window handle
6120 * [I] LPLVITEMA : item information
6122 * RETURN:
6123 * SUCCESS : new item index
6124 * FAILURE : -1
6126 static LRESULT LISTVIEW_InsertItemA(HWND hwnd, LPLVITEMA lpLVItem)
6128 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6129 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6130 UINT uView = lStyle & LVS_TYPEMASK;
6131 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
6132 NMLISTVIEW nmlv;
6133 INT nItem = -1;
6134 HDPA hdpaSubItems;
6135 INT nItemWidth = 0;
6136 LISTVIEW_ITEM *lpItem = NULL;
6138 TRACE("(hwnd=%x,lpLVItem=%p)\n", hwnd, lpLVItem);
6140 if (lStyle & LVS_OWNERDATA)
6142 nItem = infoPtr->hdpaItems->nItemCount;
6143 infoPtr->hdpaItems->nItemCount ++;
6144 return nItem;
6147 if (lpLVItem != NULL)
6149 /* make sure it's not a subitem; cannot insert a subitem */
6150 if (lpLVItem->iSubItem == 0)
6152 lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM));
6153 if (lpItem != NULL)
6155 ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
6156 if (LISTVIEW_InitItem(hwnd, lpItem, lpLVItem) != FALSE)
6158 /* insert item in listview control data structure */
6159 hdpaSubItems = DPA_Create(8);
6160 if (hdpaSubItems != NULL)
6162 nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem);
6163 if (nItem != -1)
6165 if ( ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
6166 && !(lStyle & LVS_OWNERDRAWFIXED)
6167 && (LPSTR_TEXTCALLBACKA != lpLVItem->pszText) )
6169 /* Insert the item in the proper sort order based on the pszText
6170 member. See comments for LISTVIEW_InsertCompare() for greater detail */
6171 nItem = DPA_InsertPtr( infoPtr->hdpaItems,
6172 GETITEMCOUNT( infoPtr ) + 1, hdpaSubItems );
6173 DPA_Sort( infoPtr->hdpaItems, LISTVIEW_InsertCompare, hwnd );
6174 nItem = DPA_GetPtrIndex( infoPtr->hdpaItems, hdpaSubItems );
6176 else
6178 nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpLVItem->iItem,
6179 hdpaSubItems);
6181 if (nItem != -1)
6183 LISTVIEW_ShiftSelections(hwnd,nItem,1);
6185 /* manage item focus */
6186 if (lpLVItem->mask & LVIF_STATE)
6188 lpItem->state &= ~(LVIS_FOCUSED|LVIS_SELECTED);
6189 if (lpLVItem->stateMask & LVIS_SELECTED)
6191 LISTVIEW_SetSelection(hwnd, nItem);
6193 else if (lpLVItem->stateMask & LVIS_FOCUSED)
6195 LISTVIEW_SetItemFocus(hwnd, nItem);
6199 /* send LVN_INSERTITEM notification */
6200 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
6201 nmlv.hdr.hwndFrom = hwnd;
6202 nmlv.hdr.idFrom = lCtrlId;
6203 nmlv.hdr.code = LVN_INSERTITEM;
6204 nmlv.iItem = nItem;
6205 nmlv.lParam = lpItem->lParam;;
6206 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
6208 if ((uView == LVS_SMALLICON) || (uView == LVS_LIST))
6210 nItemWidth = LISTVIEW_CalculateWidth(hwnd, lpLVItem->iItem);
6211 if (nItemWidth > infoPtr->nItemWidth)
6213 infoPtr->nItemWidth = nItemWidth;
6217 /* align items (set position of each item) */
6218 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
6220 if (lStyle & LVS_ALIGNLEFT)
6222 LISTVIEW_AlignLeft(hwnd);
6224 else
6226 LISTVIEW_AlignTop(hwnd);
6230 LISTVIEW_UpdateScroll(hwnd);
6231 /* refresh client area */
6232 InvalidateRect(hwnd, NULL, FALSE);
6241 /* free memory if unsuccessful */
6242 if ((nItem == -1) && (lpItem != NULL))
6244 COMCTL32_Free(lpItem);
6247 return nItem;
6250 static LRESULT LISTVIEW_InsertItemW(HWND hwnd, LPLVITEMW lpLVItem) {
6251 LVITEMA lvia;
6252 LRESULT lres;
6254 memcpy(&lvia,lpLVItem,sizeof(LVITEMA));
6255 if (lvia.mask & LVIF_TEXT) {
6256 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKW)
6257 lvia.pszText = LPSTR_TEXTCALLBACKA;
6258 else
6259 lvia.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpLVItem->pszText);
6261 lres = LISTVIEW_InsertItemA(hwnd, &lvia);
6262 if (lvia.mask & LVIF_TEXT) {
6263 if (lpLVItem->pszText != LPSTR_TEXTCALLBACKW)
6264 HeapFree(GetProcessHeap(),0,lvia.pszText);
6266 return lres;
6269 /* LISTVIEW_InsertItemW */
6271 /***
6272 * DESCRIPTION:
6273 * Redraws a range of items.
6275 * PARAMETER(S):
6276 * [I] HWND : window handle
6277 * [I] INT : first item
6278 * [I] INT : last item
6280 * RETURN:
6281 * SUCCESS : TRUE
6282 * FAILURE : FALSE
6284 static LRESULT LISTVIEW_RedrawItems(HWND hwnd, INT nFirst, INT nLast)
6286 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6287 BOOL bResult = FALSE;
6288 RECT rc;
6290 if (nFirst <= nLast)
6292 if ((nFirst >= 0) && (nFirst < GETITEMCOUNT(infoPtr)))
6294 if ((nLast >= 0) && (nLast < GETITEMCOUNT(infoPtr)))
6296 /* bResult = */
6297 InvalidateRect(hwnd, &rc, FALSE);
6302 return bResult;
6305 /* LISTVIEW_Scroll */
6307 /***
6308 * DESCRIPTION:
6309 * Sets the background color.
6311 * PARAMETER(S):
6312 * [I] HWND : window handle
6313 * [I] COLORREF : background color
6315 * RETURN:
6316 * SUCCESS : TRUE
6317 * FAILURE : FALSE
6319 static LRESULT LISTVIEW_SetBkColor(HWND hwnd, COLORREF clrBk)
6321 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6323 infoPtr->clrBk = clrBk;
6324 InvalidateRect(hwnd, NULL, TRUE);
6326 return TRUE;
6329 /* LISTVIEW_SetBkImage */
6331 /***
6332 * DESCRIPTION:
6333 * Sets the callback mask. This mask will be used when the parent
6334 * window stores state information (some or all).
6336 * PARAMETER(S):
6337 * [I] HWND : window handle
6338 * [I] UINT : state mask
6340 * RETURN:
6341 * SUCCESS : TRUE
6342 * FAILURE : FALSE
6344 static BOOL LISTVIEW_SetCallbackMask(HWND hwnd, UINT uMask)
6346 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6348 infoPtr->uCallbackMask = uMask;
6350 return TRUE;
6353 /***
6354 * DESCRIPTION:
6355 * Sets the attributes of a header item.
6357 * PARAMETER(S):
6358 * [I] HWND : window handle
6359 * [I] INT : column index
6360 * [I] LPLVCOLUMNA : column attributes
6362 * RETURN:
6363 * SUCCESS : TRUE
6364 * FAILURE : FALSE
6366 static LRESULT LISTVIEW_SetColumnA(HWND hwnd, INT nColumn,
6367 LPLVCOLUMNA lpColumn)
6369 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6370 BOOL bResult = FALSE;
6371 HDITEMA hdi, hdiget;
6373 if ((lpColumn != NULL) && (nColumn >= 0) &&
6374 (nColumn < Header_GetItemCount(infoPtr->hwndHeader)))
6376 /* initialize memory */
6377 ZeroMemory(&hdi, sizeof(HDITEMA));
6379 if (lpColumn->mask & LVCF_FMT)
6381 /* format member is valid */
6382 hdi.mask |= HDI_FORMAT;
6384 /* get current format first */
6385 hdiget.mask = HDI_FORMAT;
6386 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdiget))
6387 /* preserve HDF_STRING if present */
6388 hdi.fmt = hdiget.fmt & HDF_STRING;
6390 /* set text alignment (leftmost column must be left-aligned) */
6391 if (nColumn == 0)
6393 hdi.fmt |= HDF_LEFT;
6395 else
6397 if (lpColumn->fmt & LVCFMT_LEFT)
6399 hdi.fmt |= HDF_LEFT;
6401 else if (lpColumn->fmt & LVCFMT_RIGHT)
6403 hdi.fmt |= HDF_RIGHT;
6405 else if (lpColumn->fmt & LVCFMT_CENTER)
6407 hdi.fmt |= HDF_CENTER;
6411 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
6413 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
6416 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
6418 hdi.fmt |= HDF_IMAGE;
6421 if (lpColumn->fmt & LVCFMT_IMAGE)
6423 hdi.fmt |= HDF_IMAGE;
6424 hdi.iImage = I_IMAGECALLBACK;
6428 if (lpColumn->mask & LVCF_WIDTH)
6430 hdi.mask |= HDI_WIDTH;
6431 hdi.cxy = lpColumn->cx;
6434 if (lpColumn->mask & LVCF_TEXT)
6436 hdi.mask |= HDI_TEXT | HDI_FORMAT;
6437 hdi.pszText = lpColumn->pszText;
6438 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
6439 hdi.fmt |= HDF_STRING;
6442 if (lpColumn->mask & LVCF_IMAGE)
6444 hdi.mask |= HDI_IMAGE;
6445 hdi.iImage = lpColumn->iImage;
6448 if (lpColumn->mask & LVCF_ORDER)
6450 hdi.mask |= HDI_ORDER;
6451 hdi.iOrder = lpColumn->iOrder;
6454 /* set header item attributes */
6455 bResult = Header_SetItemA(infoPtr->hwndHeader, nColumn, &hdi);
6458 return bResult;
6461 /* LISTVIEW_SetColumnW */
6463 /***
6464 * DESCRIPTION:
6465 * Sets the column order array
6467 * PARAMETERS:
6468 * [I] HWND : window handle
6469 * [I] INT : number of elements in column order array
6470 * [I] INT : pointer to column order array
6472 * RETURN:
6473 * SUCCESS : TRUE
6474 * FAILURE : FALSE
6476 static LRESULT LISTVIEW_SetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
6478 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
6480 FIXME("iCount %d lpiArray %p\n", iCount, lpiArray);
6482 if (!lpiArray)
6483 return FALSE;
6485 return TRUE;
6489 /***
6490 * DESCRIPTION:
6491 * Sets the width of a column
6493 * PARAMETERS:
6494 * [I] HWND : window handle
6495 * [I] INT : column index
6496 * [I] INT : column width
6498 * RETURN:
6499 * SUCCESS : TRUE
6500 * FAILURE : FALSE
6502 static LRESULT LISTVIEW_SetColumnWidth(HWND hwnd, INT iCol, INT cx)
6504 LISTVIEW_INFO *infoPtr;
6505 HDITEMA hdi;
6506 LRESULT lret;
6507 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6508 UINT uView = lStyle & LVS_TYPEMASK;
6509 HDC hdc;
6510 HFONT header_font;
6511 HFONT old_font;
6512 SIZE size;
6513 CHAR text_buffer[DISP_TEXT_SIZE];
6514 INT header_item_count;
6515 INT item_index;
6516 RECT rcHeader;
6519 /* make sure we can get the listview info */
6520 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
6521 return (FALSE);
6523 if (!infoPtr->hwndHeader) /* make sure we have a header */
6524 return (FALSE);
6526 /* set column width only if in report or list mode */
6527 if ((uView != LVS_REPORT) && (uView != LVS_LIST))
6528 return (FALSE);
6530 /* take care of invalid cx values */
6531 if((uView == LVS_REPORT) && (cx < -2))
6532 cx = LVSCW_AUTOSIZE;
6533 else if (uView == LVS_LIST && (cx < 1))
6534 return FALSE;
6536 /* resize all columns if in LVS_LIST mode */
6537 if(uView == LVS_LIST) {
6538 infoPtr->nItemWidth = cx;
6539 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
6540 return TRUE;
6543 /* autosize based on listview items width */
6544 if(cx == LVSCW_AUTOSIZE)
6546 /* set the width of the header to the width of the widest item */
6547 for(item_index = 0; item_index < GETITEMCOUNT(infoPtr); item_index++)
6549 if(cx < LISTVIEW_GetLabelWidth(hwnd, item_index))
6550 cx = LISTVIEW_GetLabelWidth(hwnd, item_index);
6552 } /* autosize based on listview header width */
6553 else if(cx == LVSCW_AUTOSIZE_USEHEADER)
6555 header_item_count = Header_GetItemCount(infoPtr->hwndHeader);
6557 /* if iCol is the last column make it fill the remainder of the controls width */
6558 if(iCol == (header_item_count - 1)) {
6559 /* get the width of every item except the current one */
6560 hdi.mask = HDI_WIDTH;
6561 cx = 0;
6563 for(item_index = 0; item_index < (header_item_count - 1); item_index++) {
6564 Header_GetItemA(infoPtr->hwndHeader, item_index, (LPARAM)(&hdi));
6565 cx+=hdi.cxy;
6568 /* retrieve the layout of the header */
6569 GetWindowRect(infoPtr->hwndHeader, &rcHeader);
6571 cx = (rcHeader.right - rcHeader.left) - cx;
6573 else
6575 /* retrieve header font */
6576 header_font = SendMessageA(infoPtr->hwndHeader, WM_GETFONT, 0L, 0L);
6578 /* retrieve header text */
6579 hdi.mask = HDI_TEXT;
6580 hdi.cchTextMax = sizeof(text_buffer);
6581 hdi.pszText = text_buffer;
6583 Header_GetItemA(infoPtr->hwndHeader, iCol, (LPARAM)(&hdi));
6585 /* determine the width of the text in the header */
6586 hdc = GetDC(hwnd);
6587 old_font = SelectObject(hdc, header_font); /* select the font into hdc */
6589 GetTextExtentPoint32A(hdc, text_buffer, strlen(text_buffer), &size);
6591 SelectObject(hdc, old_font); /* restore the old font */
6592 ReleaseDC(hwnd, hdc);
6594 /* set the width of this column to the width of the text */
6595 cx = size.cx;
6599 /* call header to update the column change */
6600 hdi.mask = HDI_WIDTH;
6602 hdi.cxy = cx;
6603 lret = Header_SetItemA(infoPtr->hwndHeader, (WPARAM)iCol, (LPARAM)&hdi);
6605 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
6607 return lret;
6610 /***
6611 * DESCRIPTION:
6612 * Sets the extended listview style.
6614 * PARAMETERS:
6615 * [I] HWND : window handle
6616 * [I] DWORD : mask
6617 * [I] DWORD : style
6619 * RETURN:
6620 * SUCCESS : previous style
6621 * FAILURE : 0
6623 static LRESULT LISTVIEW_SetExtendedListViewStyle(HWND hwnd, DWORD dwMask, DWORD dwStyle)
6625 LISTVIEW_INFO *infoPtr;
6626 DWORD dwOldStyle;
6628 /* make sure we can get the listview info */
6629 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
6630 return (0);
6632 /* store previous style */
6633 dwOldStyle = infoPtr->dwExStyle;
6635 /* set new style */
6636 if (dwMask)
6637 infoPtr->dwExStyle = (dwOldStyle & ~dwMask) | (dwStyle & dwMask);
6638 else
6639 infoPtr->dwExStyle = dwStyle;
6641 return (dwOldStyle);
6644 /* LISTVIEW_SetHotCursor */
6646 /***
6647 * DESCRIPTION:
6648 * Sets the hot item index.
6650 * PARAMETERS:
6651 * [I] HWND : window handle
6652 * [I] INT : index
6654 * RETURN:
6655 * SUCCESS : previous hot item index
6656 * FAILURE : -1 (no hot item)
6658 static LRESULT LISTVIEW_SetHotItem(HWND hwnd, INT iIndex)
6660 LISTVIEW_INFO *infoPtr;
6661 INT iOldIndex;
6663 /* make sure we can get the listview info */
6664 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
6665 return (-1);
6667 /* store previous index */
6668 iOldIndex = infoPtr->nHotItem;
6670 /* set new style */
6671 infoPtr->nHotItem = iIndex;
6673 return (iOldIndex);
6676 /***
6677 * DESCRIPTION:
6678 * Sets the amount of time the cursor must hover over an item before it is selected.
6680 * PARAMETER(S):
6681 * [I] HWND : window handle
6682 * [I] DWORD : dwHoverTime, if -1 the hover time is set to the default
6684 * RETURN:
6685 * Returns the previous hover time
6687 static LRESULT LISTVIEW_SetHoverTime(HWND hwnd, DWORD dwHoverTime)
6689 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6690 DWORD oldHoverTime = infoPtr->dwHoverTime;
6692 infoPtr->dwHoverTime = dwHoverTime;
6694 return oldHoverTime;
6697 /* LISTVIEW_SetIconSpacing */
6699 /***
6700 * DESCRIPTION:
6701 * Sets image lists.
6703 * PARAMETER(S):
6704 * [I] HWND : window handle
6705 * [I] INT : image list type
6706 * [I] HIMAGELIST : image list handle
6708 * RETURN:
6709 * SUCCESS : old image list
6710 * FAILURE : NULL
6712 static LRESULT LISTVIEW_SetImageList(HWND hwnd, INT nType, HIMAGELIST himl)
6714 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6715 HIMAGELIST himlTemp = 0;
6717 switch (nType)
6719 case LVSIL_NORMAL:
6720 himlTemp = infoPtr->himlNormal;
6721 infoPtr->himlNormal = himl;
6722 return (LRESULT)himlTemp;
6724 case LVSIL_SMALL:
6725 himlTemp = infoPtr->himlSmall;
6726 infoPtr->himlSmall = himl;
6727 return (LRESULT)himlTemp;
6729 case LVSIL_STATE:
6730 himlTemp = infoPtr->himlState;
6731 infoPtr->himlState = himl;
6732 ImageList_SetBkColor(infoPtr->himlState, CLR_NONE);
6733 return (LRESULT)himlTemp;
6736 return (LRESULT)NULL;
6740 /***
6741 * DESCRIPTION:
6742 * Sets the attributes of an item.
6744 * PARAMETER(S):
6745 * [I] HWND : window handle
6746 * [I] LPLVITEM : item information
6748 * RETURN:
6749 * SUCCESS : TRUE
6750 * FAILURE : FALSE
6752 static LRESULT LISTVIEW_SetItemA(HWND hwnd, LPLVITEMA lpLVItem)
6754 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6755 BOOL bResult = FALSE;
6757 if (lpLVItem != NULL)
6759 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
6761 if (lpLVItem->iSubItem == 0)
6763 bResult = LISTVIEW_SetItem(hwnd, lpLVItem);
6765 else
6767 bResult = LISTVIEW_SetSubItem(hwnd, lpLVItem);
6773 return bResult;
6776 /* LISTVIEW_SetItemW */
6778 /***
6779 * DESCRIPTION:
6780 * Preallocates memory.
6782 * PARAMETER(S):
6783 * [I] HWND : window handle
6784 * [I] INT : item count (projected number of items)
6785 * [I] DWORD : update flags
6787 * RETURN:
6788 * SUCCESS : TRUE
6789 * FAILURE : FALSE
6791 static BOOL LISTVIEW_SetItemCount(HWND hwnd, INT nItems, DWORD dwFlags)
6793 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
6795 FIXME("(%d %08lx)stub!\n", nItems, dwFlags);
6797 if (nItems == 0)
6798 return LISTVIEW_DeleteAllItems (hwnd);
6800 if (GetWindowLongA(hwnd, GWL_STYLE) & LVS_OWNERDATA)
6802 int precount,topvisible;
6803 TRACE("LVS_OWNERDATA is set!\n");
6805 precount = infoPtr->hdpaItems->nItemCount;
6806 topvisible = ListView_GetTopIndex(hwnd) +
6807 LISTVIEW_GetCountPerColumn(hwnd) + 1;
6809 infoPtr->hdpaItems->nItemCount = nItems;
6811 LISTVIEW_UpdateSize(hwnd);
6812 LISTVIEW_UpdateScroll(hwnd);
6813 if (min(precount,infoPtr->hdpaItems->nItemCount)<topvisible)
6814 InvalidateRect(hwnd, NULL, TRUE);
6816 else
6818 if (nItems > GETITEMCOUNT(infoPtr))
6820 /* append items */
6821 FIXME("append items\n");
6824 else if (nItems < GETITEMCOUNT(infoPtr))
6826 /* remove items */
6827 while(nItems < GETITEMCOUNT(infoPtr)) {
6828 LISTVIEW_DeleteItem(hwnd, GETITEMCOUNT(infoPtr) - 1);
6833 return TRUE;
6836 /***
6837 * DESCRIPTION:
6838 * Sets the position of an item.
6840 * PARAMETER(S):
6841 * [I] HWND : window handle
6842 * [I] INT : item index
6843 * [I] INT : x coordinate
6844 * [I] INT : y coordinate
6846 * RETURN:
6847 * SUCCESS : TRUE
6848 * FAILURE : FALSE
6850 static BOOL LISTVIEW_SetItemPosition(HWND hwnd, INT nItem,
6851 INT nPosX, INT nPosY)
6853 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
6854 UINT lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6855 UINT uView = lStyle & LVS_TYPEMASK;
6856 LISTVIEW_ITEM *lpItem;
6857 HDPA hdpaSubItems;
6858 BOOL bResult = FALSE;
6860 TRACE("(hwnd=%x,nItem=%d,X=%d,Y=%d)\n", hwnd, nItem, nPosX, nPosY);
6862 if (lStyle & LVS_OWNERDATA)
6863 return FALSE;
6865 if ((nItem >= 0) || (nItem < GETITEMCOUNT(infoPtr)))
6867 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
6869 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
6870 if (hdpaSubItems != NULL)
6872 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
6873 if (lpItem != NULL)
6875 bResult = TRUE;
6876 lpItem->ptPosition.x = nPosX;
6877 lpItem->ptPosition.y = nPosY;
6883 return bResult;
6886 /* LISTVIEW_SetItemPosition32 */
6888 /***
6889 * DESCRIPTION:
6890 * Sets the state of one or many items.
6892 * PARAMETER(S):
6893 * [I] HWND : window handle
6894 * [I]INT : item index
6895 * [I] LPLVITEM : item or subitem info
6897 * RETURN:
6898 * SUCCESS : TRUE
6899 * FAILURE : FALSE
6901 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
6903 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6904 BOOL bResult = FALSE;
6905 LVITEMA lvItem;
6906 INT i;
6908 if (nItem == -1)
6910 bResult = TRUE;
6911 ZeroMemory(&lvItem, sizeof(LVITEMA));
6912 lvItem.mask = LVIF_STATE;
6913 lvItem.state = lpLVItem->state;
6914 lvItem.stateMask = lpLVItem->stateMask ;
6916 /* apply to all items */
6917 for (i = 0; i< GETITEMCOUNT(infoPtr); i++)
6919 lvItem.iItem = i;
6920 if (ListView_SetItemA(hwnd, &lvItem) == FALSE)
6922 bResult = FALSE;
6926 else
6928 ZeroMemory(&lvItem, sizeof(LVITEMA));
6929 lvItem.mask = LVIF_STATE;
6930 lvItem.state = lpLVItem->state;
6931 lvItem.stateMask = lpLVItem->stateMask;
6932 lvItem.iItem = nItem;
6933 bResult = ListView_SetItemA(hwnd, &lvItem);
6936 return bResult;
6939 /***
6940 * DESCRIPTION:
6941 * Sets the text of an item or subitem.
6943 * PARAMETER(S):
6944 * [I] HWND : window handle
6945 * [I] INT : item index
6946 * [I] LPLVITEMA : item or subitem info
6948 * RETURN:
6949 * SUCCESS : TRUE
6950 * FAILURE : FALSE
6952 static BOOL LISTVIEW_SetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
6954 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6955 BOOL bResult = FALSE;
6956 LVITEMA lvItem;
6958 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
6960 ZeroMemory(&lvItem, sizeof(LVITEMA));
6961 lvItem.mask = LVIF_TEXT;
6962 lvItem.pszText = lpLVItem->pszText;
6963 lvItem.iItem = nItem;
6964 lvItem.iSubItem = lpLVItem->iSubItem;
6965 bResult = ListView_SetItemA(hwnd, &lvItem);
6968 return bResult;
6971 /* LISTVIEW_SetItemTextW */
6973 /***
6974 * DESCRIPTION:
6975 * Set item index that marks the start of a multiple selection.
6977 * PARAMETER(S):
6978 * [I] HWND : window handle
6979 * [I] INT : index
6981 * RETURN:
6982 * Index number or -1 if there is no selection mark.
6984 static LRESULT LISTVIEW_SetSelectionMark(HWND hwnd, INT nIndex)
6986 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6987 INT nOldIndex = infoPtr->nSelectionMark;
6989 infoPtr->nSelectionMark = nIndex;
6991 return nOldIndex;
6994 /***
6995 * DESCRIPTION:
6996 * Sets the text background color.
6998 * PARAMETER(S):
6999 * [I] HWND : window handle
7000 * [I] COLORREF : text background color
7002 * RETURN:
7003 * SUCCESS : TRUE
7004 * FAILURE : FALSE
7006 static LRESULT LISTVIEW_SetTextBkColor(HWND hwnd, COLORREF clrTextBk)
7008 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7010 infoPtr->clrTextBk = clrTextBk;
7011 InvalidateRect(hwnd, NULL, TRUE);
7013 return TRUE;
7016 /***
7017 * DESCRIPTION:
7018 * Sets the text foreground color.
7020 * PARAMETER(S):
7021 * [I] HWND : window handle
7022 * [I] COLORREF : text color
7024 * RETURN:
7025 * SUCCESS : TRUE
7026 * FAILURE : FALSE
7028 static LRESULT LISTVIEW_SetTextColor (HWND hwnd, COLORREF clrText)
7030 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7032 infoPtr->clrText = clrText;
7033 InvalidateRect(hwnd, NULL, TRUE);
7035 return TRUE;
7038 /* LISTVIEW_SetToolTips */
7039 /* LISTVIEW_SetUnicodeFormat */
7040 /* LISTVIEW_SetWorkAreas */
7042 /***
7043 * DESCRIPTION:
7044 * Callback internally used by LISTVIEW_SortItems()
7046 * PARAMETER(S):
7047 * [I] LPVOID : first LISTVIEW_ITEM to compare
7048 * [I] LPVOID : second LISTVIEW_ITEM to compare
7049 * [I] LPARAM : HWND of control
7051 * RETURN:
7052 * if first comes before second : negative
7053 * if first comes after second : positive
7054 * if first and second are equivalent : zero
7056 static INT WINAPI LISTVIEW_CallBackCompare(
7057 LPVOID first,
7058 LPVOID second,
7059 LPARAM lParam)
7061 /* Forward the call to the client defined callback */
7062 INT rv;
7063 HWND hwnd = (HWND)lParam;
7064 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7066 rv = (infoPtr->pfnCompare)( ((LISTVIEW_ITEM*) first)->lParam,
7067 ((LISTVIEW_ITEM*) second)->lParam, infoPtr->lParamSort );
7069 return rv;
7072 /***
7073 * DESCRIPTION:
7074 * Sorts the listview items.
7076 * PARAMETER(S):
7077 * [I] HWND : window handle
7078 * [I] WPARAM : application-defined value
7079 * [I] LPARAM : pointer to comparision callback
7081 * RETURN:
7082 * SUCCESS : TRUE
7083 * FAILURE : FALSE
7085 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam)
7087 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7088 HDPA hdpaSubItems;
7089 LISTVIEW_ITEM *lpItem;
7090 int nCount, i;
7091 HDPA sortList;
7092 UINT lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7094 if (lStyle & LVS_OWNERDATA)
7095 return FALSE;
7097 if (!infoPtr || !infoPtr->hdpaItems)
7098 return FALSE;
7100 nCount = GETITEMCOUNT(infoPtr);
7101 /* if there are 0 or 1 items, there is no need to sort */
7102 if (nCount > 1)
7104 sortList = DPA_Create(nCount);
7106 infoPtr->pfnCompare = (PFNLVCOMPARE)lParam;
7107 infoPtr->lParamSort = (LPARAM)wParam;
7109 /* append pointers one by one to sortList */
7110 for (i = 0; i < nCount; i++)
7112 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)))
7113 if ((lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(hdpaSubItems, 0)))
7114 DPA_InsertPtr(sortList, nCount + 1, lpItem);
7117 /* sort the sortList */
7118 DPA_Sort(sortList, LISTVIEW_CallBackCompare, hwnd);
7120 /* copy the pointers back */
7121 for (i = 0; i < nCount; i++)
7123 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)) &&
7124 (lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(sortList, i)))
7125 DPA_SetPtr(hdpaSubItems, 0, lpItem);
7128 DPA_Destroy(sortList);
7131 return TRUE;
7134 /* LISTVIEW_SubItemHitTest */
7136 /***
7137 * DESCRIPTION:
7138 * Updates an items or rearranges the listview control.
7140 * PARAMETER(S):
7141 * [I] HWND : window handle
7142 * [I] INT : item index
7144 * RETURN:
7145 * SUCCESS : TRUE
7146 * FAILURE : FALSE
7148 static LRESULT LISTVIEW_Update(HWND hwnd, INT nItem)
7150 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7151 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7152 BOOL bResult = FALSE;
7153 RECT rc;
7155 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
7157 bResult = TRUE;
7159 /* rearrange with default alignment style */
7160 if ((lStyle & LVS_AUTOARRANGE) && (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
7161 ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON)))
7163 ListView_Arrange(hwnd, 0);
7165 else
7167 /* get item bounding rectangle */
7168 rc.left = LVIR_BOUNDS;
7169 ListView_GetItemRect(hwnd, nItem, &rc);
7170 InvalidateRect(hwnd, &rc, TRUE);
7174 return bResult;
7177 /***
7178 * DESCRIPTION:
7179 * Creates the listview control.
7181 * PARAMETER(S):
7182 * [I] HWND : window handle
7184 * RETURN:
7185 * Zero
7187 static LRESULT LISTVIEW_Create(HWND hwnd, WPARAM wParam, LPARAM lParam)
7189 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7190 LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam;
7191 UINT uView = lpcs->style & LVS_TYPEMASK;
7192 LOGFONTA logFont;
7194 /* initialize info pointer */
7195 ZeroMemory(infoPtr, sizeof(LISTVIEW_INFO));
7197 /* determine the type of structures to use */
7198 infoPtr->notifyFormat = SendMessageA(GetParent(hwnd), WM_NOTIFYFORMAT,
7199 (WPARAM)hwnd, (LPARAM)NF_QUERY);
7200 if (infoPtr->notifyFormat != NFR_ANSI)
7202 FIXME("ANSI notify format is NOT used\n");
7205 /* initialize color information */
7206 infoPtr->clrBk = GetSysColor(COLOR_WINDOW);
7207 infoPtr->clrText = GetSysColor(COLOR_WINDOWTEXT);
7208 infoPtr->clrTextBk = GetSysColor(COLOR_WINDOW);
7210 /* set default values */
7211 infoPtr->uCallbackMask = 0;
7212 infoPtr->nFocusedItem = -1;
7213 infoPtr->nSelectionMark = -1;
7214 infoPtr->nHotItem = -1;
7215 infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING);
7216 infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING);
7217 ZeroMemory(&infoPtr->rcList, sizeof(RECT));
7218 infoPtr->hwndEdit = 0;
7219 infoPtr->pedititem = NULL;
7220 infoPtr->nEditLabelItem = -1;
7222 /* get default font (icon title) */
7223 SystemParametersInfoA(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
7224 infoPtr->hDefaultFont = CreateFontIndirectA(&logFont);
7225 infoPtr->hFont = infoPtr->hDefaultFont;
7227 /* create header */
7228 infoPtr->hwndHeader = CreateWindowA(WC_HEADERA, (LPCSTR)NULL,
7229 WS_CHILD | HDS_HORZ | HDS_BUTTONS,
7230 0, 0, 0, 0, hwnd, (HMENU)0,
7231 lpcs->hInstance, NULL);
7233 /* set header font */
7234 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont,
7235 (LPARAM)TRUE);
7237 if (uView == LVS_ICON)
7239 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
7240 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
7242 else if (uView == LVS_REPORT)
7244 if (!(LVS_NOCOLUMNHEADER & lpcs->style))
7246 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
7248 else
7250 /* resize our header to nothing */
7251 RECT zeroRect;
7252 WINDOWPOS wp;
7253 HDLAYOUT hd;
7254 memset(&zeroRect,0,sizeof(RECT));
7255 hd.prc = &zeroRect;
7256 hd.pwpos = &wp;
7258 Header_Layout(infoPtr->hwndHeader,&hd);
7262 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7263 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7265 else
7267 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7268 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7271 /* display unsupported listview window styles */
7272 LISTVIEW_UnsupportedStyles(lpcs->style);
7274 /* allocate memory for the data structure */
7275 infoPtr->hdpaItems = DPA_Create(10);
7277 /* allocate memory for the selection ranges */
7278 infoPtr->hdpaSelectionRanges = DPA_Create(10);
7280 /* initialize size of items */
7281 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7282 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7284 /* initialize the hover time to -1(indicating the default system hover time) */
7285 infoPtr->dwHoverTime = -1;
7287 return 0;
7290 /***
7291 * DESCRIPTION:
7292 * Erases the background of the listview control.
7294 * PARAMETER(S):
7295 * [I] HWND : window handle
7296 * [I] WPARAM : device context handle
7297 * [I] LPARAM : not used
7299 * RETURN:
7300 * SUCCESS : TRUE
7301 * FAILURE : FALSE
7303 static LRESULT LISTVIEW_EraseBackground(HWND hwnd, WPARAM wParam,
7304 LPARAM lParam)
7306 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7307 BOOL bResult;
7309 if (infoPtr->clrBk == CLR_NONE)
7311 bResult = SendMessageA(GetParent(hwnd), WM_ERASEBKGND, wParam, lParam);
7313 else
7315 RECT rc;
7316 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
7317 GetClientRect(hwnd, &rc);
7318 FillRect((HDC)wParam, &rc, hBrush);
7319 DeleteObject(hBrush);
7320 bResult = TRUE;
7323 return bResult;
7326 /***
7327 * DESCRIPTION:
7328 * Retrieves the listview control font.
7330 * PARAMETER(S):
7331 * [I] HWND : window handle
7333 * RETURN:
7334 * Font handle.
7336 static LRESULT LISTVIEW_GetFont(HWND hwnd)
7338 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7340 return infoPtr->hFont;
7343 /***
7344 * DESCRIPTION:
7345 * Performs vertical scrolling.
7347 * PARAMETER(S):
7348 * [I] HWND : window handle
7349 * [I] INT : scroll code
7350 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
7351 * or SB_THUMBTRACK.
7352 * [I] HWND : scrollbar control window handle
7354 * RETURN:
7355 * Zero
7357 static LRESULT LISTVIEW_VScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
7358 HWND hScrollWnd)
7360 SCROLLINFO scrollInfo;
7362 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
7363 scrollInfo.cbSize = sizeof(SCROLLINFO);
7364 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
7366 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
7368 INT nOldScrollPos = scrollInfo.nPos;
7369 switch (nScrollCode)
7371 case SB_LINEUP:
7372 if (scrollInfo.nPos > scrollInfo.nMin)
7374 scrollInfo.nPos--;
7376 break;
7378 case SB_LINEDOWN:
7379 if (scrollInfo.nPos < scrollInfo.nMax)
7381 scrollInfo.nPos++;
7383 break;
7385 case SB_PAGEUP:
7386 if (scrollInfo.nPos > scrollInfo.nMin)
7388 if (scrollInfo.nPos >= scrollInfo.nPage)
7390 scrollInfo.nPos -= scrollInfo.nPage;
7392 else
7394 scrollInfo.nPos = scrollInfo.nMin;
7397 break;
7399 case SB_PAGEDOWN:
7400 if (scrollInfo.nPos < scrollInfo.nMax)
7402 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
7404 scrollInfo.nPos += scrollInfo.nPage;
7406 else
7408 scrollInfo.nPos = scrollInfo.nMax;
7411 break;
7413 case SB_THUMBTRACK:
7414 scrollInfo.nPos = nCurrentPos;
7415 if (scrollInfo.nPos > scrollInfo.nMax)
7416 scrollInfo.nPos=scrollInfo.nMax;
7418 if (scrollInfo.nPos < scrollInfo.nMin)
7419 scrollInfo.nPos=scrollInfo.nMin;
7421 break;
7424 if (nOldScrollPos != scrollInfo.nPos)
7426 scrollInfo.fMask = SIF_POS;
7427 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
7428 InvalidateRect(hwnd, NULL, TRUE);
7432 return 0;
7435 /***
7436 * DESCRIPTION:
7437 * Performs horizontal scrolling.
7439 * PARAMETER(S):
7440 * [I] HWND : window handle
7441 * [I] INT : scroll code
7442 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
7443 * or SB_THUMBTRACK.
7444 * [I] HWND : scrollbar control window handle
7446 * RETURN:
7447 * Zero
7449 static LRESULT LISTVIEW_HScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
7450 HWND hScrollWnd)
7452 SCROLLINFO scrollInfo;
7454 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
7455 scrollInfo.cbSize = sizeof(SCROLLINFO);
7456 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
7458 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
7460 INT nOldScrollPos = scrollInfo.nPos;
7462 switch (nScrollCode)
7464 case SB_LINELEFT:
7465 if (scrollInfo.nPos > scrollInfo.nMin)
7467 scrollInfo.nPos--;
7469 break;
7471 case SB_LINERIGHT:
7472 if (scrollInfo.nPos < scrollInfo.nMax)
7474 scrollInfo.nPos++;
7476 break;
7478 case SB_PAGELEFT:
7479 if (scrollInfo.nPos > scrollInfo.nMin)
7481 if (scrollInfo.nPos >= scrollInfo.nPage)
7483 scrollInfo.nPos -= scrollInfo.nPage;
7485 else
7487 scrollInfo.nPos = scrollInfo.nMin;
7490 break;
7492 case SB_PAGERIGHT:
7493 if (scrollInfo.nPos < scrollInfo.nMax)
7495 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
7497 scrollInfo.nPos += scrollInfo.nPage;
7499 else
7501 scrollInfo.nPos = scrollInfo.nMax;
7504 break;
7506 case SB_THUMBTRACK:
7507 scrollInfo.nPos = nCurrentPos;
7509 if (scrollInfo.nPos > scrollInfo.nMax)
7510 scrollInfo.nPos=scrollInfo.nMax;
7512 if (scrollInfo.nPos < scrollInfo.nMin)
7513 scrollInfo.nPos=scrollInfo.nMin;
7514 break;
7517 if (nOldScrollPos != scrollInfo.nPos)
7519 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
7520 scrollInfo.fMask = SIF_POS;
7521 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
7522 if(uView == LVS_REPORT)
7524 scrollInfo.fMask = SIF_POS;
7525 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
7526 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
7528 InvalidateRect(hwnd, NULL, TRUE);
7532 return 0;
7535 static LRESULT LISTVIEW_MouseWheel(HWND hwnd, INT wheelDelta)
7537 INT gcWheelDelta = 0;
7538 UINT pulScrollLines = 3;
7539 SCROLLINFO scrollInfo;
7541 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
7543 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
7544 gcWheelDelta -= wheelDelta;
7546 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
7547 scrollInfo.cbSize = sizeof(SCROLLINFO);
7548 scrollInfo.fMask = SIF_POS | SIF_RANGE;
7550 switch(uView)
7552 case LVS_ICON:
7553 case LVS_SMALLICON:
7555 * listview should be scrolled by a multiple of 37 dependently on its dimension or its visible item number
7556 * should be fixed in the future.
7558 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
7559 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + (gcWheelDelta < 0) ? 37 : -37, 0);
7560 break;
7562 case LVS_REPORT:
7563 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
7565 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
7567 int cLineScroll = min(LISTVIEW_GetCountPerColumn(hwnd), pulScrollLines);
7568 cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
7569 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + cLineScroll, 0);
7572 break;
7574 case LVS_LIST:
7575 LISTVIEW_HScroll(hwnd, (gcWheelDelta < 0) ? SB_LINELEFT : SB_LINERIGHT, 0, 0);
7576 break;
7578 return 0;
7581 /***
7582 * DESCRIPTION:
7583 * ???
7585 * PARAMETER(S):
7586 * [I] HWND : window handle
7587 * [I] INT : virtual key
7588 * [I] LONG : key data
7590 * RETURN:
7591 * Zero
7593 static LRESULT LISTVIEW_KeyDown(HWND hwnd, INT nVirtualKey, LONG lKeyData)
7595 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7596 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
7597 HWND hwndParent = GetParent(hwnd);
7598 NMLVKEYDOWN nmKeyDown;
7599 NMHDR nmh;
7600 INT nItem = -1;
7601 BOOL bRedraw = FALSE;
7603 /* send LVN_KEYDOWN notification */
7604 ZeroMemory(&nmKeyDown, sizeof(NMLVKEYDOWN));
7605 nmKeyDown.hdr.hwndFrom = hwnd;
7606 nmKeyDown.hdr.idFrom = nCtrlId;
7607 nmKeyDown.hdr.code = LVN_KEYDOWN;
7608 nmKeyDown.wVKey = nVirtualKey;
7609 nmKeyDown.flags = 0;
7610 SendMessageA(hwndParent, WM_NOTIFY, (WPARAM)nCtrlId, (LPARAM)&nmKeyDown);
7612 /* initialize */
7613 nmh.hwndFrom = hwnd;
7614 nmh.idFrom = nCtrlId;
7616 switch (nVirtualKey)
7618 case VK_RETURN:
7619 if ((GETITEMCOUNT(infoPtr) > 0) && (infoPtr->nFocusedItem != -1))
7621 /* send NM_RETURN notification */
7622 nmh.code = NM_RETURN;
7623 ListView_Notify(hwndParent, nCtrlId, &nmh);
7625 /* send LVN_ITEMACTIVATE notification */
7626 nmh.code = LVN_ITEMACTIVATE;
7627 ListView_Notify(hwndParent, nCtrlId, &nmh);
7629 break;
7631 case VK_HOME:
7632 if (GETITEMCOUNT(infoPtr) > 0)
7634 nItem = 0;
7636 break;
7638 case VK_END:
7639 if (GETITEMCOUNT(infoPtr) > 0)
7641 nItem = GETITEMCOUNT(infoPtr) - 1;
7643 break;
7645 case VK_LEFT:
7646 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TOLEFT);
7647 break;
7649 case VK_UP:
7650 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_ABOVE);
7651 break;
7653 case VK_RIGHT:
7654 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TORIGHT);
7655 break;
7657 case VK_DOWN:
7658 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_BELOW);
7659 break;
7661 case VK_PRIOR:
7662 /* TO DO */
7663 break;
7665 case VK_NEXT:
7666 /* TO DO */
7667 break;
7670 if ((nItem != -1) && (nItem != infoPtr->nFocusedItem))
7672 bRedraw = LISTVIEW_KeySelection(hwnd, nItem);
7673 if (bRedraw != FALSE)
7675 /* refresh client area */
7676 UpdateWindow(hwnd);
7680 return 0;
7683 /***
7684 * DESCRIPTION:
7685 * Kills the focus.
7687 * PARAMETER(S):
7688 * [I] HWND : window handle
7690 * RETURN:
7691 * Zero
7693 static LRESULT LISTVIEW_KillFocus(HWND hwnd)
7695 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
7696 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
7697 NMHDR nmh;
7698 INT i,nTop,nBottom;
7699 RECT rcItem;
7700 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7701 UINT uView = lStyle & LVS_TYPEMASK;
7703 TRACE("(hwnd=%x)\n", hwnd);
7705 /* send NM_KILLFOCUS notification */
7706 nmh.hwndFrom = hwnd;
7707 nmh.idFrom = nCtrlId;
7708 nmh.code = NM_KILLFOCUS;
7709 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
7711 /* set window focus flag */
7712 infoPtr->bFocus = FALSE;
7714 /* NEED drawing optimization ; redraw the selected items */
7715 if (uView & LVS_REPORT)
7717 nTop = LISTVIEW_GetTopIndex(hwnd);
7718 nBottom = nTop +
7719 LISTVIEW_GetCountPerColumn(hwnd) + 1;
7721 else
7723 nTop = 0;
7724 nBottom = GETITEMCOUNT(infoPtr);
7726 for (i = nTop; i<nBottom; i++)
7728 if (LISTVIEW_IsSelected(hwnd,i))
7730 rcItem.left = LVIR_BOUNDS;
7731 LISTVIEW_GetItemRect(hwnd, i, &rcItem);
7732 InvalidateRect(hwnd, &rcItem, FALSE);
7736 return 0;
7739 /***
7740 * DESCRIPTION:
7741 * Processes double click messages (left mouse button).
7743 * PARAMETER(S):
7744 * [I] HWND : window handle
7745 * [I] WORD : key flag
7746 * [I] WORD : x coordinate
7747 * [I] WORD : y coordinate
7749 * RETURN:
7750 * Zero
7752 static LRESULT LISTVIEW_LButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
7753 WORD wPosY)
7755 LONG nCtrlId = GetWindowLongA(hwnd, GWL_ID);
7756 NMHDR nmh;
7757 LVHITTESTINFO htInfo;
7759 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
7761 /* send NM_DBLCLK notification */
7762 nmh.hwndFrom = hwnd;
7763 nmh.idFrom = nCtrlId;
7764 nmh.code = NM_DBLCLK;
7765 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
7767 /* To send the LVN_ITEMACTIVATE, it must be on an Item */
7768 ZeroMemory(&htInfo, sizeof(LVHITTESTINFO));
7769 htInfo.pt.x = wPosX;
7770 htInfo.pt.y = wPosY;
7771 if(LISTVIEW_HitTest(hwnd, &htInfo) != -1)
7773 /* send LVN_ITEMACTIVATE notification */
7774 nmh.code = LVN_ITEMACTIVATE;
7775 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
7778 return 0;
7781 /***
7782 * DESCRIPTION:
7783 * Processes mouse down messages (left mouse button).
7785 * PARAMETER(S):
7786 * [I] HWND : window handle
7787 * [I] WORD : key flag
7788 * [I] WORD : x coordinate
7789 * [I] WORD : y coordinate
7791 * RETURN:
7792 * Zero
7794 static LRESULT LISTVIEW_LButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
7795 WORD wPosY)
7797 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7798 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7799 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
7800 static BOOL bGroupSelect = TRUE;
7801 POINT ptPosition;
7802 NMHDR nmh;
7803 INT nItem;
7805 TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd, wKey, wPosX,
7806 wPosY);
7808 /* send NM_RELEASEDCAPTURE notification */
7809 nmh.hwndFrom = hwnd;
7810 nmh.idFrom = nCtrlId;
7811 nmh.code = NM_RELEASEDCAPTURE;
7812 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
7814 if (infoPtr->bFocus == FALSE)
7816 SetFocus(hwnd);
7819 /* set left button down flag */
7820 infoPtr->bLButtonDown = TRUE;
7822 ptPosition.x = wPosX;
7823 ptPosition.y = wPosY;
7824 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
7825 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
7827 if (lStyle & LVS_SINGLESEL)
7829 if ((ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
7830 && infoPtr->nEditLabelItem == -1)
7832 infoPtr->nEditLabelItem = nItem;
7834 else
7836 LISTVIEW_SetSelection(hwnd, nItem);
7839 else
7841 if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
7843 if (bGroupSelect != FALSE)
7845 LISTVIEW_AddGroupSelection(hwnd, nItem);
7847 else
7849 LISTVIEW_AddSelection(hwnd, nItem);
7852 else if (wKey & MK_CONTROL)
7854 bGroupSelect = LISTVIEW_ToggleSelection(hwnd, nItem);
7856 else if (wKey & MK_SHIFT)
7858 LISTVIEW_SetGroupSelection(hwnd, nItem);
7860 else
7862 if (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED
7863 && infoPtr->nEditLabelItem == -1)
7865 infoPtr->nEditLabelItem = nItem;
7867 else
7869 LISTVIEW_SetSelection(hwnd, nItem);
7875 else
7877 /* remove all selections */
7878 LISTVIEW_RemoveAllSelections(hwnd);
7881 InvalidateRect(hwnd, NULL, TRUE);
7883 return 0;
7886 /***
7887 * DESCRIPTION:
7888 * Processes mouse up messages (left mouse button).
7890 * PARAMETER(S):
7891 * [I] HWND : window handle
7892 * [I] WORD : key flag
7893 * [I] WORD : x coordinate
7894 * [I] WORD : y coordinate
7896 * RETURN:
7897 * Zero
7899 static LRESULT LISTVIEW_LButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
7900 WORD wPosY)
7902 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7904 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
7906 if (infoPtr->bLButtonDown != FALSE)
7908 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
7909 NMHDR nmh;
7911 /* send NM_CLICK notification */
7912 nmh.hwndFrom = hwnd;
7913 nmh.idFrom = nCtrlId;
7914 nmh.code = NM_CLICK;
7915 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
7917 /* set left button flag */
7918 infoPtr->bLButtonDown = FALSE;
7920 if(infoPtr->nEditLabelItem != -1)
7922 POINT ptPosition;
7923 int nItem;
7924 ptPosition.x = wPosX;
7925 ptPosition.y = wPosY;
7926 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
7927 if(nItem == infoPtr->nEditLabelItem)
7929 LISTVIEW_EditLabelA(hwnd, nItem);
7931 infoPtr->nEditLabelItem = -1;
7935 return 0;
7938 /***
7939 * DESCRIPTION:
7940 * Creates the listview control (called before WM_CREATE).
7942 * PARAMETER(S):
7943 * [I] HWND : window handle
7944 * [I] WPARAM : unhandled
7945 * [I] LPARAM : widow creation info
7947 * RETURN:
7948 * Zero
7950 static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
7952 LISTVIEW_INFO *infoPtr;
7954 TRACE("(hwnd=%x,wParam=%x,lParam=%lx)\n", hwnd, wParam, lParam);
7956 /* allocate memory for info structure */
7957 infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc(sizeof(LISTVIEW_INFO));
7958 SetWindowLongA(hwnd, 0, (LONG)infoPtr);
7959 if (infoPtr == NULL)
7961 ERR("could not allocate info memory!\n");
7962 return 0;
7965 if ((LISTVIEW_INFO *)GetWindowLongA(hwnd, 0) != infoPtr)
7967 ERR("pointer assignment error!\n");
7968 return 0;
7971 return DefWindowProcA(hwnd, WM_NCCREATE, wParam, lParam);
7974 /***
7975 * DESCRIPTION:
7976 * Destroys the listview control (called after WM_DESTROY).
7978 * PARAMETER(S):
7979 * [I] HWND : window handle
7981 * RETURN:
7982 * Zero
7984 static LRESULT LISTVIEW_NCDestroy(HWND hwnd)
7986 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7988 TRACE("(hwnd=%x)\n", hwnd);
7990 /* delete all items */
7991 LISTVIEW_DeleteAllItems(hwnd);
7993 /* destroy data structure */
7994 DPA_Destroy(infoPtr->hdpaItems);
7995 DPA_Destroy(infoPtr->hdpaSelectionRanges);
7997 /* destroy font */
7998 infoPtr->hFont = (HFONT)0;
7999 if (infoPtr->hDefaultFont)
8001 DeleteObject(infoPtr->hDefaultFont);
8004 /* free listview info pointer*/
8005 COMCTL32_Free(infoPtr);
8007 SetWindowLongA(hwnd, 0, 0);
8008 return 0;
8011 /***
8012 * DESCRIPTION:
8013 * Handles notifications from children.
8015 * PARAMETER(S):
8016 * [I] HWND : window handle
8017 * [I] INT : control identifier
8018 * [I] LPNMHDR : notification information
8020 * RETURN:
8021 * Zero
8023 static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh)
8025 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8027 if (lpnmh->hwndFrom == infoPtr->hwndHeader)
8029 /* handle notification from header control */
8030 if (lpnmh->code == HDN_ENDTRACKA)
8032 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8033 InvalidateRect(hwnd, NULL, TRUE);
8035 else if(lpnmh->code == HDN_ITEMCLICKA)
8037 /* Handle sorting by Header Column */
8038 NMLISTVIEW nmlv;
8039 LPNMHEADERA pnmHeader = (LPNMHEADERA) lpnmh;
8040 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
8042 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
8043 nmlv.hdr.hwndFrom = hwnd;
8044 nmlv.hdr.idFrom = lCtrlId;
8045 nmlv.hdr.code = LVN_COLUMNCLICK;
8046 nmlv.iItem = -1;
8047 nmlv.iSubItem = pnmHeader->iItem;
8049 ListView_LVNotify(GetParent(hwnd),lCtrlId, &nmlv);
8052 else if(lpnmh->code == NM_RELEASEDCAPTURE)
8054 /* Idealy this should be done in HDN_ENDTRACKA
8055 * but since SetItemBounds in Header.c is called after
8056 * the notification is sent, it is neccessary to handle the
8057 * update of the scroll bar here (Header.c works fine as it is,
8058 * no need to disturb it)
8060 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8061 LISTVIEW_UpdateScroll(hwnd);
8062 InvalidateRect(hwnd, NULL, TRUE);
8067 return 0;
8070 /***
8071 * DESCRIPTION:
8072 * Determines the type of structure to use.
8074 * PARAMETER(S):
8075 * [I] HWND : window handle of the sender
8076 * [I] HWND : listview window handle
8077 * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
8079 * RETURN:
8080 * Zero
8082 static LRESULT LISTVIEW_NotifyFormat(HWND hwndFrom, HWND hwnd, INT nCommand)
8084 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8086 if (nCommand == NF_REQUERY)
8088 /* determine the type of structure to use */
8089 infoPtr->notifyFormat = SendMessageA(hwndFrom, WM_NOTIFYFORMAT,
8090 (WPARAM)hwnd, (LPARAM)NF_QUERY);
8091 if (infoPtr->notifyFormat == NFR_UNICODE)
8093 FIXME("NO support for unicode structures");
8097 return 0;
8100 /***
8101 * DESCRIPTION:
8102 * Paints/Repaints the listview control.
8104 * PARAMETER(S):
8105 * [I] HWND : window handle
8106 * [I] HDC : device context handle
8108 * RETURN:
8109 * Zero
8111 static LRESULT LISTVIEW_Paint(HWND hwnd, HDC hdc)
8113 PAINTSTRUCT ps;
8115 TRACE("(hwnd=%x,hdc=%x)\n", hwnd, hdc);
8117 if (hdc == 0)
8119 hdc = BeginPaint(hwnd, &ps);
8120 LISTVIEW_Refresh(hwnd, hdc);
8121 EndPaint(hwnd, &ps);
8123 else
8125 LISTVIEW_Refresh(hwnd, hdc);
8128 return 0;
8131 /***
8132 * DESCRIPTION:
8133 * Processes double click messages (right 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_RButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
8145 WORD wPosY)
8147 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8148 NMHDR nmh;
8150 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8152 /* send NM_RELEASEDCAPTURE notification */
8153 nmh.hwndFrom = hwnd;
8154 nmh.idFrom = nCtrlId;
8155 nmh.code = NM_RELEASEDCAPTURE;
8156 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8158 /* send NM_RDBLCLK notification */
8159 nmh.code = NM_RDBLCLK;
8160 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8162 return 0;
8165 /***
8166 * DESCRIPTION:
8167 * Processes mouse down messages (right mouse button).
8169 * PARAMETER(S):
8170 * [I] HWND : window handle
8171 * [I] WORD : key flag
8172 * [I] WORD : x coordinate
8173 * [I] WORD : y coordinate
8175 * RETURN:
8176 * Zero
8178 static LRESULT LISTVIEW_RButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
8179 WORD wPosY)
8181 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8182 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8183 POINT ptPosition;
8184 NMHDR nmh;
8185 INT nItem;
8187 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8189 /* send NM_RELEASEDCAPTURE notification */
8190 nmh.hwndFrom = hwnd;
8191 nmh.idFrom = nCtrlId;
8192 nmh.code = NM_RELEASEDCAPTURE;
8193 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8195 /* make sure the listview control window has the focus */
8196 if (infoPtr->bFocus == FALSE)
8198 SetFocus(hwnd);
8201 /* set right button down flag */
8202 infoPtr->bRButtonDown = TRUE;
8204 /* determine the index of the selected item */
8205 ptPosition.x = wPosX;
8206 ptPosition.y = wPosY;
8207 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
8208 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
8210 if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)))
8212 LISTVIEW_SetSelection(hwnd, nItem);
8215 else
8217 LISTVIEW_RemoveAllSelections(hwnd);
8220 return 0;
8223 /***
8224 * DESCRIPTION:
8225 * Processes mouse up messages (right mouse button).
8227 * PARAMETER(S):
8228 * [I] HWND : window handle
8229 * [I] WORD : key flag
8230 * [I] WORD : x coordinate
8231 * [I] WORD : y coordinate
8233 * RETURN:
8234 * Zero
8236 static LRESULT LISTVIEW_RButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
8237 WORD wPosY)
8239 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8240 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8241 NMHDR nmh;
8243 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8245 if (infoPtr->bRButtonDown != FALSE)
8247 POINT pt;
8248 pt.x = wPosX;
8249 pt.y = wPosY;
8251 /* Send NM_RClICK notification */
8252 ZeroMemory(&nmh, sizeof(NMHDR));
8253 nmh.hwndFrom = hwnd;
8254 nmh.idFrom = nCtrlId;
8255 nmh.code = NM_RCLICK;
8256 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8258 /* set button flag */
8259 infoPtr->bRButtonDown = FALSE;
8261 /* Change to screen coordinate for WM_CONTEXTMENU */
8262 ClientToScreen(hwnd, &pt);
8264 /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
8265 SendMessageA( hwnd, WM_CONTEXTMENU, (WPARAM) hwnd, MAKELPARAM(pt.x, pt.y));
8268 return 0;
8271 /***
8272 * DESCRIPTION:
8273 * Sets the focus.
8275 * PARAMETER(S):
8276 * [I] HWND : window handle
8277 * [I] HWND : window handle of previously focused window
8279 * RETURN:
8280 * Zero
8282 static LRESULT LISTVIEW_SetFocus(HWND hwnd, HWND hwndLoseFocus)
8284 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8285 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8286 NMHDR nmh;
8288 TRACE("(hwnd=%x, hwndLoseFocus=%x)\n", hwnd, hwndLoseFocus);
8290 /* send NM_SETFOCUS notification */
8291 nmh.hwndFrom = hwnd;
8292 nmh.idFrom = nCtrlId;
8293 nmh.code = NM_SETFOCUS;
8294 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8296 /* set window focus flag */
8297 infoPtr->bFocus = TRUE;
8299 UpdateWindow(hwnd);
8301 return 0;
8304 /***
8305 * DESCRIPTION:
8306 * Sets the font.
8308 * PARAMETER(S):
8309 * [I] HWND : window handle
8310 * [I] HFONT : font handle
8311 * [I] WORD : redraw flag
8313 * RETURN:
8314 * Zero
8316 static LRESULT LISTVIEW_SetFont(HWND hwnd, HFONT hFont, WORD fRedraw)
8318 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8319 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
8321 TRACE("(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd, hFont, fRedraw);
8323 if (hFont == 0)
8325 infoPtr->hFont = infoPtr->hDefaultFont;
8327 else
8329 infoPtr->hFont = hFont;
8332 if (uView == LVS_REPORT)
8334 /* set header font */
8335 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont,
8336 MAKELPARAM(fRedraw, 0));
8339 /* invalidate listview control client area */
8340 InvalidateRect(hwnd, NULL, TRUE);
8342 if (fRedraw != FALSE)
8344 UpdateWindow(hwnd);
8347 return 0;
8350 /***
8351 * DESCRIPTION:
8352 * Message handling for WM_SETREDRAW.
8353 * For the Listview, it invalidates the entire window (the doc specifies otherwise)
8355 * PARAMETER(S):
8356 * [I] HWND : window handle
8357 * [I] bRedraw: state of redraw flag
8359 * RETURN:
8360 * DefWinProc return value
8362 static LRESULT LISTVIEW_SetRedraw(HWND hwnd, BOOL bRedraw)
8364 LRESULT lResult;
8365 lResult = DefWindowProcA(hwnd, WM_SETREDRAW, bRedraw, 0);
8366 if(bRedraw)
8368 RedrawWindow(hwnd, NULL, 0,
8369 RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN | RDW_ERASENOW);
8371 return lResult;
8374 /***
8375 * DESCRIPTION:
8376 * Resizes the listview control. This function processes WM_SIZE
8377 * messages. At this time, the width and height are not used.
8379 * PARAMETER(S):
8380 * [I] HWND : window handle
8381 * [I] WORD : new width
8382 * [I] WORD : new height
8384 * RETURN:
8385 * Zero
8387 static LRESULT LISTVIEW_Size(HWND hwnd, int Width, int Height)
8389 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8390 UINT uView = lStyle & LVS_TYPEMASK;
8392 TRACE("(hwnd=%x, width=%d, height=%d)\n",hwnd, Width, Height);
8394 LISTVIEW_UpdateSize(hwnd);
8396 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
8398 if (lStyle & LVS_ALIGNLEFT)
8400 LISTVIEW_AlignLeft(hwnd);
8402 else
8404 LISTVIEW_AlignTop(hwnd);
8408 LISTVIEW_UpdateScroll(hwnd);
8410 /* invalidate client area + erase background */
8411 InvalidateRect(hwnd, NULL, TRUE);
8413 return 0;
8416 /***
8417 * DESCRIPTION:
8418 * Sets the size information.
8420 * PARAMETER(S):
8421 * [I] HWND : window handle
8423 * RETURN:
8424 * Zero
8426 static VOID LISTVIEW_UpdateSize(HWND hwnd)
8428 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8429 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8430 UINT uView = lStyle & LVS_TYPEMASK;
8431 RECT rcList;
8433 GetClientRect(hwnd, &rcList);
8434 infoPtr->rcList.left = 0;
8435 infoPtr->rcList.right = max(rcList.right - rcList.left, 1);
8436 infoPtr->rcList.top = 0;
8437 infoPtr->rcList.bottom = max(rcList.bottom - rcList.top, 1);
8439 if (uView == LVS_LIST)
8441 if ((lStyle & WS_HSCROLL) == 0)
8443 INT nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
8444 if (infoPtr->rcList.bottom > nHScrollHeight)
8446 infoPtr->rcList.bottom -= nHScrollHeight;
8450 else if ((uView == LVS_REPORT)&&(!(LVS_NOCOLUMNHEADER & lStyle)))
8452 HDLAYOUT hl;
8453 WINDOWPOS wp;
8455 hl.prc = &rcList;
8456 hl.pwpos = &wp;
8457 Header_Layout(infoPtr->hwndHeader, &hl);
8459 SetWindowPos(wp.hwnd, wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
8461 if (!(LVS_NOCOLUMNHEADER & lStyle))
8463 infoPtr->rcList.top = max(wp.cy, 0);
8468 /***
8469 * DESCRIPTION:
8470 * Processes WM_STYLECHANGED messages.
8472 * PARAMETER(S):
8473 * [I] HWND : window handle
8474 * [I] WPARAM : window style type (normal or extended)
8475 * [I] LPSTYLESTRUCT : window style information
8477 * RETURN:
8478 * Zero
8480 static INT LISTVIEW_StyleChanged(HWND hwnd, WPARAM wStyleType,
8481 LPSTYLESTRUCT lpss)
8483 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8484 UINT uNewView = lpss->styleNew & LVS_TYPEMASK;
8485 UINT uOldView = lpss->styleOld & LVS_TYPEMASK;
8486 RECT rcList = infoPtr->rcList;
8488 TRACE("(hwnd=%x, styletype=%x, stylestruct=%p)\n",
8489 hwnd, wStyleType, lpss);
8491 if (wStyleType == GWL_STYLE)
8493 if (uOldView == LVS_REPORT)
8495 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
8498 if ((lpss->styleOld & WS_HSCROLL) != 0)
8500 ShowScrollBar(hwnd, SB_HORZ, FALSE);
8503 if ((lpss->styleOld & WS_VSCROLL) != 0)
8505 ShowScrollBar(hwnd, SB_VERT, FALSE);
8508 if (uNewView == LVS_ICON)
8510 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
8511 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
8512 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8513 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8514 if (lpss->styleNew & LVS_ALIGNLEFT)
8516 LISTVIEW_AlignLeft(hwnd);
8518 else
8520 LISTVIEW_AlignTop(hwnd);
8523 else if (uNewView == LVS_REPORT)
8525 HDLAYOUT hl;
8526 WINDOWPOS wp;
8528 if (!(LVS_NOCOLUMNHEADER & lpss->styleNew))
8530 hl.prc = &rcList;
8531 hl.pwpos = &wp;
8532 Header_Layout(infoPtr->hwndHeader, &hl);
8533 SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, wp.cy,
8534 wp.flags);
8535 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
8537 else
8539 RECT zeroRect;
8540 ZeroMemory(&zeroRect,sizeof(RECT));
8542 hl.prc = &zeroRect;
8543 hl.pwpos = &wp;
8544 Header_Layout(infoPtr->hwndHeader, &hl);
8547 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
8548 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
8549 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8550 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8552 else if (uNewView == LVS_LIST)
8554 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
8555 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
8556 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8557 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8559 else
8561 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
8562 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
8563 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8564 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8565 if (lpss->styleNew & LVS_ALIGNLEFT)
8567 LISTVIEW_AlignLeft(hwnd);
8569 else
8571 LISTVIEW_AlignTop(hwnd);
8575 /* update the size of the client area */
8576 LISTVIEW_UpdateSize(hwnd);
8578 /* add scrollbars if needed */
8579 LISTVIEW_UpdateScroll(hwnd);
8581 /* invalidate client area + erase background */
8582 InvalidateRect(hwnd, NULL, TRUE);
8584 /* print the list of unsupported window styles */
8585 LISTVIEW_UnsupportedStyles(lpss->styleNew);
8588 /* If they change the view and we have an active edit control
8589 we will need to kill the control since the redraw will
8590 misplace the edit control.
8592 if (infoPtr->hwndEdit &&
8593 ((uNewView & (LVS_ICON|LVS_LIST|LVS_SMALLICON)) !=
8594 ((LVS_ICON|LVS_LIST|LVS_SMALLICON) & uOldView)))
8596 SendMessageA(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
8599 return 0;
8602 /***
8603 * DESCRIPTION:
8604 * Window procedure of the listview control.
8607 static LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
8608 LPARAM lParam)
8610 TRACE("hwnd=%x uMsg=%x wParam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam);
8611 if (!GetWindowLongA(hwnd, 0) && (uMsg != WM_NCCREATE))
8612 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
8613 switch (uMsg)
8615 case LVM_APPROXIMATEVIEWRECT:
8616 return LISTVIEW_ApproximateViewRect(hwnd, (INT)wParam,
8617 LOWORD(lParam), HIWORD(lParam));
8618 case LVM_ARRANGE:
8619 return LISTVIEW_Arrange(hwnd, (INT)wParam);
8621 /* case LVM_CREATEDRAGIMAGE: */
8623 case LVM_DELETEALLITEMS:
8624 return LISTVIEW_DeleteAllItems(hwnd);
8626 case LVM_DELETECOLUMN:
8627 return LISTVIEW_DeleteColumn(hwnd, (INT)wParam);
8629 case LVM_DELETEITEM:
8630 return LISTVIEW_DeleteItem(hwnd, (INT)wParam);
8632 case LVM_EDITLABELW:
8633 case LVM_EDITLABELA:
8634 return LISTVIEW_EditLabelA(hwnd, (INT)wParam);
8636 case LVM_ENSUREVISIBLE:
8637 return LISTVIEW_EnsureVisible(hwnd, (INT)wParam, (BOOL)lParam);
8639 case LVM_FINDITEMA:
8640 return LISTVIEW_FindItem(hwnd, (INT)wParam, (LPLVFINDINFO)lParam);
8642 case LVM_GETBKCOLOR:
8643 return LISTVIEW_GetBkColor(hwnd);
8645 /* case LVM_GETBKIMAGE: */
8647 case LVM_GETCALLBACKMASK:
8648 return LISTVIEW_GetCallbackMask(hwnd);
8650 case LVM_GETCOLUMNA:
8651 return LISTVIEW_GetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
8653 /* case LVM_GETCOLUMNW: */
8655 case LVM_GETCOLUMNORDERARRAY:
8656 return LISTVIEW_GetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
8658 case LVM_GETCOLUMNWIDTH:
8659 return LISTVIEW_GetColumnWidth(hwnd, (INT)wParam);
8661 case LVM_GETCOUNTPERPAGE:
8662 return LISTVIEW_GetCountPerPage(hwnd);
8664 case LVM_GETEDITCONTROL:
8665 return LISTVIEW_GetEditControl(hwnd);
8667 case LVM_GETEXTENDEDLISTVIEWSTYLE:
8668 return LISTVIEW_GetExtendedListViewStyle(hwnd);
8670 case LVM_GETHEADER:
8671 return LISTVIEW_GetHeader(hwnd);
8673 /* case LVM_GETHOTCURSOR: */
8675 case LVM_GETHOTITEM:
8676 return LISTVIEW_GetHotItem(hwnd);
8678 case LVM_GETHOVERTIME:
8679 return LISTVIEW_GetHoverTime(hwnd);
8681 case LVM_GETIMAGELIST:
8682 return LISTVIEW_GetImageList(hwnd, (INT)wParam);
8684 /* case LVM_GETISEARCHSTRING: */
8686 case LVM_GETITEMA:
8687 return LISTVIEW_GetItemA(hwnd, (LPLVITEMA)lParam, FALSE);
8689 /* case LVM_GETITEMW: */
8691 case LVM_GETITEMCOUNT:
8692 return LISTVIEW_GetItemCount(hwnd);
8694 case LVM_GETITEMPOSITION:
8695 return LISTVIEW_GetItemPosition(hwnd, (INT)wParam, (LPPOINT)lParam);
8697 case LVM_GETITEMRECT:
8698 return LISTVIEW_GetItemRect(hwnd, (INT)wParam, (LPRECT)lParam);
8700 case LVM_GETITEMSPACING:
8701 return LISTVIEW_GetItemSpacing(hwnd, (BOOL)wParam);
8703 case LVM_GETITEMSTATE:
8704 return LISTVIEW_GetItemState(hwnd, (INT)wParam, (UINT)lParam);
8706 case LVM_GETITEMTEXTA:
8707 LISTVIEW_GetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
8708 break;
8710 /* case LVM_GETITEMTEXTW: */
8712 case LVM_GETNEXTITEM:
8713 return LISTVIEW_GetNextItem(hwnd, (INT)wParam, LOWORD(lParam));
8715 /* case LVM_GETNUMBEROFWORKAREAS: */
8717 case LVM_GETORIGIN:
8718 return LISTVIEW_GetOrigin(hwnd, (LPPOINT)lParam);
8720 case LVM_GETSELECTEDCOUNT:
8721 return LISTVIEW_GetSelectedCount(hwnd);
8723 case LVM_GETSELECTIONMARK:
8724 return LISTVIEW_GetSelectionMark(hwnd);
8726 case LVM_GETSTRINGWIDTHA:
8727 return LISTVIEW_GetStringWidthA (hwnd, (LPCSTR)lParam);
8729 /* case LVM_GETSTRINGWIDTHW: */
8730 /* case LVM_GETSUBITEMRECT: */
8732 case LVM_GETTEXTBKCOLOR:
8733 return LISTVIEW_GetTextBkColor(hwnd);
8735 case LVM_GETTEXTCOLOR:
8736 return LISTVIEW_GetTextColor(hwnd);
8738 /* case LVM_GETTOOLTIPS: */
8740 case LVM_GETTOPINDEX:
8741 return LISTVIEW_GetTopIndex(hwnd);
8743 /* case LVM_GETUNICODEFORMAT: */
8745 case LVM_GETVIEWRECT:
8746 return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam);
8748 /* case LVM_GETWORKAREAS: */
8750 case LVM_HITTEST:
8751 return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam);
8753 case LVM_INSERTCOLUMNA:
8754 return LISTVIEW_InsertColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
8756 case LVM_INSERTCOLUMNW:
8757 return LISTVIEW_InsertColumnW(hwnd, (INT)wParam, (LPLVCOLUMNW)lParam);
8759 case LVM_INSERTITEMA:
8760 return LISTVIEW_InsertItemA(hwnd, (LPLVITEMA)lParam);
8762 case LVM_INSERTITEMW:
8763 return LISTVIEW_InsertItemW(hwnd, (LPLVITEMW)lParam);
8765 case LVM_REDRAWITEMS:
8766 return LISTVIEW_RedrawItems(hwnd, (INT)wParam, (INT)lParam);
8768 /* case LVM_SCROLL: */
8769 /* return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); */
8771 case LVM_SETBKCOLOR:
8772 return LISTVIEW_SetBkColor(hwnd, (COLORREF)lParam);
8774 /* case LVM_SETBKIMAGE: */
8776 case LVM_SETCALLBACKMASK:
8777 return LISTVIEW_SetCallbackMask(hwnd, (UINT)wParam);
8779 case LVM_SETCOLUMNA:
8780 return LISTVIEW_SetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
8782 case LVM_SETCOLUMNW:
8783 FIXME("Unimplemented msg LVM_SETCOLUMNW\n");
8784 return 0;
8786 case LVM_SETCOLUMNORDERARRAY:
8787 return LISTVIEW_SetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
8789 case LVM_SETCOLUMNWIDTH:
8790 return LISTVIEW_SetColumnWidth(hwnd, (INT)wParam, SLOWORD(lParam));
8792 case LVM_SETEXTENDEDLISTVIEWSTYLE:
8793 return LISTVIEW_SetExtendedListViewStyle(hwnd, (DWORD)wParam, (DWORD)lParam);
8795 /* case LVM_SETHOTCURSOR: */
8797 case LVM_SETHOTITEM:
8798 return LISTVIEW_SetHotItem(hwnd, (INT)wParam);
8800 case LVM_SETHOVERTIME:
8801 return LISTVIEW_SetHoverTime(hwnd, (DWORD)wParam);
8803 /* case LVM_SETICONSPACING: */
8805 case LVM_SETIMAGELIST:
8806 return LISTVIEW_SetImageList(hwnd, (INT)wParam, (HIMAGELIST)lParam);
8808 case LVM_SETITEMA:
8809 return LISTVIEW_SetItemA(hwnd, (LPLVITEMA)lParam);
8811 /* case LVM_SETITEMW: */
8813 case LVM_SETITEMCOUNT:
8814 return LISTVIEW_SetItemCount(hwnd, (INT)wParam, (DWORD)lParam);
8816 case LVM_SETITEMPOSITION:
8817 return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, (INT)LOWORD(lParam),
8818 (INT)HIWORD(lParam));
8820 /* case LVM_SETITEMPOSITION32: */
8822 case LVM_SETITEMSTATE:
8823 return LISTVIEW_SetItemState(hwnd, (INT)wParam, (LPLVITEMA)lParam);
8825 case LVM_SETITEMTEXTA:
8826 return LISTVIEW_SetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
8828 /* case LVM_SETITEMTEXTW: */
8830 case LVM_SETSELECTIONMARK:
8831 return LISTVIEW_SetSelectionMark(hwnd, (INT)lParam);
8833 case LVM_SETTEXTBKCOLOR:
8834 return LISTVIEW_SetTextBkColor(hwnd, (COLORREF)lParam);
8836 case LVM_SETTEXTCOLOR:
8837 return LISTVIEW_SetTextColor(hwnd, (COLORREF)lParam);
8839 /* case LVM_SETTOOLTIPS: */
8840 /* case LVM_SETUNICODEFORMAT: */
8841 /* case LVM_SETWORKAREAS: */
8843 case LVM_SORTITEMS:
8844 return LISTVIEW_SortItems(hwnd, wParam, lParam);
8846 /* case LVM_SUBITEMHITTEST: */
8848 case LVM_UPDATE:
8849 return LISTVIEW_Update(hwnd, (INT)wParam);
8851 /* case WM_CHAR: */
8852 case WM_CHAR:
8853 return LISTVIEW_ProcessLetterKeys( hwnd, wParam, lParam );
8855 case WM_COMMAND:
8856 return LISTVIEW_Command(hwnd, wParam, lParam);
8858 case WM_CREATE:
8859 return LISTVIEW_Create(hwnd, wParam, lParam);
8861 case WM_ERASEBKGND:
8862 return LISTVIEW_EraseBackground(hwnd, wParam, lParam);
8864 case WM_GETDLGCODE:
8865 return DLGC_WANTCHARS | DLGC_WANTARROWS;
8867 case WM_GETFONT:
8868 return LISTVIEW_GetFont(hwnd);
8870 case WM_HSCROLL:
8871 return LISTVIEW_HScroll(hwnd, (INT)LOWORD(wParam),
8872 (INT)HIWORD(wParam), (HWND)lParam);
8874 case WM_KEYDOWN:
8875 return LISTVIEW_KeyDown(hwnd, (INT)wParam, (LONG)lParam);
8877 case WM_KILLFOCUS:
8878 return LISTVIEW_KillFocus(hwnd);
8880 case WM_LBUTTONDBLCLK:
8881 return LISTVIEW_LButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
8882 HIWORD(lParam));
8884 case WM_LBUTTONDOWN:
8885 return LISTVIEW_LButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
8886 HIWORD(lParam));
8887 case WM_LBUTTONUP:
8888 return LISTVIEW_LButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
8889 HIWORD(lParam));
8890 case WM_MOUSEMOVE:
8891 return LISTVIEW_MouseMove (hwnd, wParam, lParam);
8893 case WM_MOUSEHOVER:
8894 return LISTVIEW_MouseHover(hwnd, wParam, lParam);
8896 case WM_NCCREATE:
8897 return LISTVIEW_NCCreate(hwnd, wParam, lParam);
8899 case WM_NCDESTROY:
8900 return LISTVIEW_NCDestroy(hwnd);
8902 case WM_NOTIFY:
8903 return LISTVIEW_Notify(hwnd, (INT)wParam, (LPNMHDR)lParam);
8905 case WM_NOTIFYFORMAT:
8906 return LISTVIEW_NotifyFormat(hwnd, (HWND)wParam, (INT)lParam);
8908 case WM_PAINT:
8909 return LISTVIEW_Paint(hwnd, (HDC)wParam);
8911 case WM_RBUTTONDBLCLK:
8912 return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
8913 HIWORD(lParam));
8915 case WM_RBUTTONDOWN:
8916 return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
8917 HIWORD(lParam));
8919 case WM_RBUTTONUP:
8920 return LISTVIEW_RButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
8921 HIWORD(lParam));
8923 case WM_SETFOCUS:
8924 return LISTVIEW_SetFocus(hwnd, (HWND)wParam);
8926 case WM_SETFONT:
8927 return LISTVIEW_SetFont(hwnd, (HFONT)wParam, (WORD)lParam);
8929 case WM_SETREDRAW:
8930 return LISTVIEW_SetRedraw(hwnd, (BOOL)wParam);
8932 case WM_SIZE:
8933 return LISTVIEW_Size(hwnd, (int)SLOWORD(lParam), (int)SHIWORD(lParam));
8935 case WM_STYLECHANGED:
8936 return LISTVIEW_StyleChanged(hwnd, wParam, (LPSTYLESTRUCT)lParam);
8938 /* case WM_TIMER: */
8940 case WM_VSCROLL:
8941 return LISTVIEW_VScroll(hwnd, (INT)LOWORD(wParam),
8942 (INT)HIWORD(wParam), (HWND)lParam);
8944 case WM_MOUSEWHEEL:
8945 if (wParam & (MK_SHIFT | MK_CONTROL))
8946 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
8947 return LISTVIEW_MouseWheel(hwnd, (short int)HIWORD(wParam));/* case WM_WINDOWPOSCHANGED: */
8949 /* case WM_WININICHANGE: */
8951 default:
8952 if (uMsg >= WM_USER)
8954 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam,
8955 lParam);
8958 /* call default window procedure */
8959 return DefWindowProcA(hwnd, uMsg, wParam, lParam);
8962 return 0;
8965 /***
8966 * DESCRIPTION:
8967 * Registers the window class.
8969 * PARAMETER(S):
8970 * None
8972 * RETURN:
8973 * None
8975 VOID LISTVIEW_Register(void)
8977 WNDCLASSA wndClass;
8979 ZeroMemory(&wndClass, sizeof(WNDCLASSA));
8980 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
8981 wndClass.lpfnWndProc = (WNDPROC)LISTVIEW_WindowProc;
8982 wndClass.cbClsExtra = 0;
8983 wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *);
8984 wndClass.hCursor = LoadCursorA(0, IDC_ARROWA);
8985 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
8986 wndClass.lpszClassName = WC_LISTVIEWA;
8987 RegisterClassA(&wndClass);
8990 /***
8991 * DESCRIPTION:
8992 * Unregisters the window class.
8994 * PARAMETER(S):
8995 * None
8997 * RETURN:
8998 * None
9000 VOID LISTVIEW_Unregister(void)
9002 UnregisterClassA(WC_LISTVIEWA, (HINSTANCE)NULL);
9005 /***
9006 * DESCRIPTION:
9007 * Handle any WM_COMMAND messages
9009 * PARAMETER(S):
9011 * RETURN:
9013 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam)
9015 switch (HIWORD(wParam))
9017 case EN_UPDATE:
9020 * Adjust the edit window size
9022 char buffer[1024];
9023 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
9024 HDC hdc = GetDC(infoPtr->hwndEdit);
9025 HFONT hFont, hOldFont = 0;
9026 RECT rect;
9027 SIZE sz;
9028 int len;
9030 len = GetWindowTextA(infoPtr->hwndEdit, buffer, 1023);
9031 GetWindowRect(infoPtr->hwndEdit, &rect);
9033 /* Select font to get the right dimension of the string */
9034 hFont = SendMessageA(infoPtr->hwndEdit, WM_GETFONT, 0, 0);
9035 if(hFont != 0)
9037 hOldFont = SelectObject(hdc, hFont);
9040 if (GetTextExtentPoint32A(hdc, buffer, strlen(buffer), &sz))
9042 TEXTMETRICA textMetric;
9044 /* Add Extra spacing for the next character */
9045 GetTextMetricsA(hdc, &textMetric);
9046 sz.cx += (textMetric.tmMaxCharWidth * 2);
9048 SetWindowPos (
9049 infoPtr->hwndEdit,
9050 HWND_TOP,
9053 sz.cx,
9054 rect.bottom - rect.top,
9055 SWP_DRAWFRAME|SWP_NOMOVE);
9057 if(hFont != 0)
9059 SelectObject(hdc, hOldFont);
9062 ReleaseDC(hwnd, hdc);
9064 break;
9067 default:
9068 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
9071 return 0;
9075 /***
9076 * DESCRIPTION:
9077 * Subclassed edit control windproc function
9079 * PARAMETER(S):
9081 * RETURN:
9083 LRESULT CALLBACK EditLblWndProc(HWND hwnd, UINT uMsg,
9084 WPARAM wParam, LPARAM lParam)
9086 BOOL cancel = FALSE;
9087 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(GetParent(hwnd), 0);
9088 EDITLABEL_ITEM *einfo = infoPtr->pedititem;
9089 static BOOL bIgnoreKillFocus = FALSE;
9090 switch (uMsg)
9092 case WM_GETDLGCODE:
9093 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
9095 case WM_KILLFOCUS:
9096 if(bIgnoreKillFocus)
9098 return TRUE;
9100 break;
9102 case WM_DESTROY:
9104 WNDPROC editProc = einfo->EditWndProc;
9105 SetWindowLongA(hwnd, GWL_WNDPROC, (LONG)editProc);
9106 COMCTL32_Free(einfo);
9107 infoPtr->pedititem = NULL;
9108 return CallWindowProcA(editProc, hwnd, uMsg, wParam, lParam);
9111 case WM_KEYDOWN:
9112 if (VK_ESCAPE == (INT)wParam)
9114 cancel = TRUE;
9115 break;
9118 else if (VK_RETURN == (INT)wParam)
9119 break;
9121 default:
9122 return CallWindowProcA(einfo->EditWndProc, hwnd,
9123 uMsg, wParam, lParam);
9126 if (einfo->EditLblCb)
9128 char *buffer = NULL;
9131 if (!cancel)
9133 int len = 1 + GetWindowTextLengthA(hwnd);
9135 if (len > 1)
9137 if (NULL != (buffer = (char *)COMCTL32_Alloc(len*sizeof(char))))
9139 GetWindowTextA(hwnd, buffer, len);
9143 /* Processing LVN_ENDLABELEDIT message could kill the focus */
9144 /* eg. Using a messagebox */
9145 bIgnoreKillFocus = TRUE;
9146 einfo->EditLblCb(GetParent(hwnd), buffer, einfo->param);
9148 if (buffer)
9149 COMCTL32_Free(buffer);
9151 einfo->EditLblCb = NULL;
9152 bIgnoreKillFocus = FALSE;
9155 SendMessageA(hwnd, WM_CLOSE, 0, 0);
9156 return TRUE;
9160 /***
9161 * DESCRIPTION:
9162 * Creates a subclassed edit cotrol
9164 * PARAMETER(S):
9166 * RETURN:
9168 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
9169 INT width, INT height, HWND parent, HINSTANCE hinst,
9170 EditlblCallback EditLblCb, DWORD param)
9172 HWND hedit;
9173 SIZE sz;
9174 HDC hdc;
9175 HDC hOldFont=0;
9176 TEXTMETRICA textMetric;
9177 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(parent, 0);
9179 if (NULL == (infoPtr->pedititem = COMCTL32_Alloc(sizeof(EDITLABEL_ITEM))))
9180 return 0;
9182 style |= WS_CHILDWINDOW|WS_CLIPSIBLINGS|ES_LEFT|WS_BORDER;
9183 hdc = GetDC(parent);
9185 /* Select the font to get appropriate metric dimensions */
9186 if(infoPtr->hFont != 0)
9188 hOldFont = SelectObject(hdc, infoPtr->hFont);
9191 /*Get String Lenght in pixels */
9192 GetTextExtentPoint32A(hdc, text, strlen(text), &sz);
9194 /*Add Extra spacing for the next character */
9195 GetTextMetricsA(hdc, &textMetric);
9196 sz.cx += (textMetric.tmMaxCharWidth * 2);
9198 if(infoPtr->hFont != 0)
9200 SelectObject(hdc, hOldFont);
9203 ReleaseDC(parent, hdc);
9204 if (!(hedit = CreateWindowA("Edit", text, style, x, y, sz.cx, height,
9205 parent, 0, hinst, 0)))
9207 COMCTL32_Free(infoPtr->pedititem);
9208 return 0;
9211 infoPtr->pedititem->param = param;
9212 infoPtr->pedititem->EditLblCb = EditLblCb;
9213 infoPtr->pedititem->EditWndProc = (WNDPROC)SetWindowLongA(hedit,
9214 GWL_WNDPROC, (LONG) EditLblWndProc);
9216 SendMessageA(hedit, WM_SETFONT, infoPtr->hFont, FALSE);
9218 return hedit;