Fixed hash function.
[wine/dcerpc.git] / dlls / comctl32 / listview.c
blob325e31e3d9158385d3d8fe13cc778de6d9cf33d6
1 /*
2 * Listview control
4 * Copyright 1998, 1999 Eric Kohl
5 * Copyright 1999 Luc Tourangeau
7 * NOTES
8 * Listview control implementation.
10 * TODO:
11 * 1. No horizontal scrolling when header is larger than the client area.
12 * 2. Drawing optimizations.
13 * 3. Hot item handling.
15 * Notifications:
16 * LISTVIEW_Notify : most notifications from children (editbox and header)
18 * Data structure:
19 * LISTVIEW_SetItemCount : empty stub
21 * Unicode:
22 * LISTVIEW_SetItemW : no unicode support
23 * LISTVIEW_InsertItemW : no unicode support
24 * LISTVIEW_InsertColumnW : no unicode support
25 * LISTVIEW_GetColumnW : no unicode support
26 * LISTVIEW_SetColumnW : no unicode support
28 * Advanced functionality:
29 * LISTVIEW_GetNumberOfWorkAreas : not implemented
30 * LISTVIEW_GetHotCursor : not implemented
31 * LISTVIEW_GetHoverTime : not implemented
32 * LISTVIEW_GetISearchString : not implemented
33 * LISTVIEW_GetBkImage : not implemented
34 * LISTVIEW_GetColumnOrderArray : not implemented
35 * LISTVIEW_SetColumnOrderArray : not implemented
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 <string.h>
44 #include "winbase.h"
45 #include "heap.h"
46 #include "commctrl.h"
47 #include "listview.h"
48 #include "debugtools.h"
50 DEFAULT_DEBUG_CHANNEL(listview)
53 * constants
56 /* maximum size of a label */
57 #define DISP_TEXT_SIZE 128
59 /* padding for items in list and small icon display modes */
60 #define WIDTH_PADDING 12
62 /* padding for items in list, report and small icon display modes */
63 #define HEIGHT_PADDING 1
65 /* offset of items in report display mode */
66 #define REPORT_MARGINX 2
68 /* padding for icon in large icon display mode */
69 #define ICON_TOP_PADDING 2
70 #define ICON_BOTTOM_PADDING 2
72 /* padding for label in large icon display mode */
73 #define LABEL_VERT_OFFSET 2
75 /* default label width for items in list and small icon display modes */
76 #define DEFAULT_LABEL_WIDTH 40
78 /* default column width for items in list display mode */
79 #define DEFAULT_COLUMN_WIDTH 96
81 /* Increment size of the horizontal scroll bar */
82 #define LISTVIEW_SCROLL_DIV_SIZE 10
84 /*
85 * macros
87 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
88 #define ListView_LVNotify(hwnd,lCtrlId,plvnm) \
89 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMLISTVIEW)(plvnm))
90 #define ListView_Notify(hwnd,lCtrlId,pnmh) \
91 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMHDR)(pnmh))
92 /* retrieve the number of items in the listview */
93 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
95 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
96 INT width, INT height, HWND parent, HINSTANCE hinst,
97 EditlblCallback EditLblCb, DWORD param);
99 /*
100 * forward declarations
102 static INT LISTVIEW_HitTestItem(HWND, LPLVHITTESTINFO);
103 static INT LISTVIEW_GetCountPerRow(HWND);
104 static INT LISTVIEW_GetCountPerColumn(HWND);
105 static VOID LISTVIEW_AlignLeft(HWND);
106 static VOID LISTVIEW_AlignTop(HWND);
107 static VOID LISTVIEW_AddGroupSelection(HWND, INT);
108 static VOID LISTVIEW_AddSelection(HWND, INT);
109 static BOOL LISTVIEW_AddSubItem(HWND, LPLVITEMA);
110 static INT LISTVIEW_FindInsertPosition(HDPA, INT);
111 static INT LISTVIEW_GetItemHeight(HWND);
112 static BOOL LISTVIEW_GetItemPosition(HWND, INT, LPPOINT);
113 static LRESULT LISTVIEW_GetItemRect(HWND, INT, LPRECT);
114 static INT LISTVIEW_GetItemWidth(HWND);
115 static INT LISTVIEW_GetLabelWidth(HWND, INT);
116 static LRESULT LISTVIEW_GetOrigin(HWND, LPPOINT);
117 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem);
118 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA, INT);
119 static LRESULT LISTVIEW_GetViewRect(HWND, LPRECT);
120 static BOOL LISTVIEW_InitItem(HWND, LISTVIEW_ITEM *, LPLVITEMA);
121 static BOOL LISTVIEW_InitSubItem(HWND, LISTVIEW_SUBITEM *, LPLVITEMA);
122 static LRESULT LISTVIEW_MouseSelection(HWND, POINT);
123 static BOOL LISTVIEW_RemoveColumn(HDPA, INT);
124 static VOID LISTVIEW_RemoveSelections(HWND, INT, INT);
125 static BOOL LISTVIEW_RemoveSubItem(HDPA, INT);
126 static VOID LISTVIEW_SetGroupSelection(HWND, INT);
127 static BOOL LISTVIEW_SetItem(HWND, LPLVITEMA);
128 static BOOL LISTVIEW_SetItemFocus(HWND, INT);
129 static BOOL LISTVIEW_SetItemPosition(HWND, INT, INT, INT);
130 static VOID LISTVIEW_UpdateScroll(HWND);
131 static VOID LISTVIEW_SetSelection(HWND, INT);
132 static VOID LISTVIEW_UpdateSize(HWND);
133 static BOOL LISTVIEW_SetSubItem(HWND, LPLVITEMA);
134 static LRESULT LISTVIEW_SetViewRect(HWND, LPRECT);
135 static BOOL LISTVIEW_ToggleSelection(HWND, INT);
136 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle);
137 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem);
138 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem);
139 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam);
141 /*************************************************************************
142 * LISTVIEW_UpdateHeaderSize [Internal]
144 * Function to resize the header control
146 * PARAMS
147 * hwnd [I] handle to a window
148 * nNewScrollPos [I] Scroll Pos to Set
150 * RETURNS
151 * nothing
153 * NOTES
155 static VOID LISTVIEW_UpdateHeaderSize(HWND hwnd, INT nNewScrollPos)
157 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
158 RECT winRect;
159 POINT point[2];
161 GetWindowRect(infoPtr->hwndHeader, &winRect);
162 point[0].x = winRect.left;
163 point[0].y = winRect.top;
164 point[1].x = winRect.right;
165 point[1].y = winRect.bottom;
167 MapWindowPoints(HWND_DESKTOP, hwnd, point, 2);
168 point[0].x = -(nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
169 point[1].x += (nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
171 SetWindowPos(infoPtr->hwndHeader,0,
172 point[0].x,point[0].y,point[1].x,point[1].y,
173 SWP_NOZORDER | SWP_NOACTIVATE);
176 /***
177 * DESCRIPTION:
178 * Update the scrollbars. This functions should be called whenever
179 * the content, size or view changes.
181 * PARAMETER(S):
182 * [I] HWND : window handle
184 * RETURN:
185 * None
187 static VOID LISTVIEW_UpdateScroll(HWND hwnd)
189 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
190 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
191 UINT uView = lStyle & LVS_TYPEMASK;
192 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
193 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
194 SCROLLINFO scrollInfo;
196 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
197 scrollInfo.cbSize = sizeof(SCROLLINFO);
199 if (uView == LVS_LIST)
201 /* update horizontal scrollbar */
203 INT nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
204 INT nCountPerRow = LISTVIEW_GetCountPerRow(hwnd);
205 INT nCountPerPage = nCountPerRow * nCountPerColumn;
206 INT nNumOfItems = GETITEMCOUNT(infoPtr);
208 if (nCountPerPage < GETITEMCOUNT(infoPtr))
210 scrollInfo.nMax = nNumOfItems / nCountPerColumn;
211 if((nNumOfItems % nCountPerColumn) == 0)
213 scrollInfo.nMax--;
215 scrollInfo.nPos = ListView_GetTopIndex(hwnd) / nCountPerColumn;
216 scrollInfo.nPage = nCountPerRow;
217 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
218 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
220 else
222 /* hide scrollbar */
223 if (lStyle & WS_HSCROLL)
225 ShowScrollBar(hwnd, SB_HORZ, FALSE);
229 else if (uView == LVS_REPORT)
231 /* update vertical scrollbar */
232 scrollInfo.nMin = 0;
233 scrollInfo.nMax = GETITEMCOUNT(infoPtr) - 1;
234 scrollInfo.nPos = ListView_GetTopIndex(hwnd);
235 scrollInfo.nPage = LISTVIEW_GetCountPerColumn(hwnd);
236 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
237 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
239 /* update horizontal scrollbar */
240 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE)
242 scrollInfo.nPos = 0;
244 scrollInfo.nMin = 0;
245 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE ;
246 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
247 scrollInfo.nMax = max(infoPtr->nItemWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
248 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
250 /* Update the Header Control */
251 scrollInfo.fMask = SIF_POS;
252 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
253 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
256 else
258 RECT rcView;
260 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
262 INT nViewWidth = rcView.right - rcView.left;
263 INT nViewHeight = rcView.bottom - rcView.top;
265 if (nViewWidth > nListWidth)
267 scrollInfo.fMask = SIF_POS;
268 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE)
270 scrollInfo.nPos = 0;
272 scrollInfo.nMax = max(nViewWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
273 scrollInfo.nMin = 0;
274 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
275 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
276 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
278 else
280 if (lStyle & WS_HSCROLL)
282 ShowScrollBar(hwnd, SB_HORZ, FALSE);
286 if (nViewHeight > nListHeight)
288 scrollInfo.fMask = SIF_POS;
289 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) == FALSE)
291 scrollInfo.nPos = 0;
293 scrollInfo.nMax = max(nViewHeight / LISTVIEW_SCROLL_DIV_SIZE,0)-1;
294 scrollInfo.nMin = 0;
295 scrollInfo.nPage = nListHeight / LISTVIEW_SCROLL_DIV_SIZE;
296 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
297 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
299 else
301 if (lStyle & WS_VSCROLL)
303 ShowScrollBar(hwnd, SB_VERT, FALSE);
310 /***
311 * DESCRIPTION:
312 * Prints a message for unsupported window styles.
313 * A kind of TODO list for window styles.
315 * PARAMETER(S):
316 * [I] LONG : window style
318 * RETURN:
319 * None
321 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle)
323 if ((LVS_TYPEMASK & lStyle) == LVS_EDITLABELS)
325 FIXME(" LVS_EDITLABELS\n");
328 if ((LVS_TYPEMASK & lStyle) == LVS_NOLABELWRAP)
330 FIXME(" LVS_NOLABELWRAP\n");
333 if ((LVS_TYPEMASK & lStyle) == LVS_NOSCROLL)
335 FIXME(" LVS_NOSCROLL\n");
338 if ((LVS_TYPEMASK & lStyle) == LVS_NOSORTHEADER)
340 FIXME(" LVS_NOSORTHEADER\n");
343 if ((LVS_TYPEMASK & lStyle) == LVS_OWNERDRAWFIXED)
345 FIXME(" LVS_OWNERDRAWFIXED\n");
348 if ((LVS_TYPEMASK & lStyle) == LVS_SHAREIMAGELISTS)
350 FIXME(" LVS_SHAREIMAGELISTS\n");
353 if ((LVS_TYPEMASK & lStyle) == LVS_SORTASCENDING)
355 FIXME(" LVS_SORTASCENDING\n");
358 if ((LVS_TYPEMASK & lStyle) == LVS_SORTDESCENDING)
360 FIXME(" LVS_SORTDESCENDING\n");
364 /***
365 * DESCRIPTION:
366 * Aligns the items with the top edge of the window.
368 * PARAMETER(S):
369 * [I] HWND : window handle
371 * RETURN:
372 * None
374 static VOID LISTVIEW_AlignTop(HWND hwnd)
376 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
377 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
378 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
379 POINT ptItem;
380 RECT rcView;
381 INT i;
383 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
385 ZeroMemory(&ptItem, sizeof(POINT));
386 ZeroMemory(&rcView, sizeof(RECT));
388 if (nListWidth > infoPtr->nItemWidth)
390 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
392 if (ptItem.x + infoPtr->nItemWidth > nListWidth)
394 ptItem.x = 0;
395 ptItem.y += infoPtr->nItemHeight;
398 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
399 ptItem.x += infoPtr->nItemWidth;
400 rcView.right = max(rcView.right, ptItem.x);
403 rcView.bottom = ptItem.y + infoPtr->nItemHeight;
405 else
407 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
409 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
410 ptItem.y += infoPtr->nItemHeight;
413 rcView.right = infoPtr->nItemWidth;
414 rcView.bottom = ptItem.y;
417 LISTVIEW_SetViewRect(hwnd, &rcView);
421 /***
422 * DESCRIPTION:
423 * Aligns the items with the left edge of the window.
425 * PARAMETER(S):
426 * [I] HWND : window handle
428 * RETURN:
429 * None
431 static VOID LISTVIEW_AlignLeft(HWND hwnd)
433 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
434 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
435 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
436 POINT ptItem;
437 RECT rcView;
438 INT i;
440 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
442 ZeroMemory(&ptItem, sizeof(POINT));
443 ZeroMemory(&rcView, sizeof(RECT));
445 if (nListHeight > infoPtr->nItemHeight)
447 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
449 if (ptItem.y + infoPtr->nItemHeight > nListHeight)
451 ptItem.y = 0;
452 ptItem.x += infoPtr->nItemWidth;
455 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
456 ptItem.y += infoPtr->nItemHeight;
457 rcView.bottom = max(rcView.bottom, ptItem.y);
460 rcView.right = ptItem.x + infoPtr->nItemWidth;
462 else
464 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
466 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
467 ptItem.x += infoPtr->nItemWidth;
470 rcView.bottom = infoPtr->nItemHeight;
471 rcView.right = ptItem.x;
474 LISTVIEW_SetViewRect(hwnd, &rcView);
478 /***
479 * DESCRIPTION:
480 * Set the bounding rectangle of all the items.
482 * PARAMETER(S):
483 * [I] HWND : window handle
484 * [I] LPRECT : bounding rectangle
486 * RETURN:
487 * SUCCESS : TRUE
488 * FAILURE : FALSE
490 static LRESULT LISTVIEW_SetViewRect(HWND hwnd, LPRECT lprcView)
492 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
493 BOOL bResult = FALSE;
495 TRACE("(hwnd=%x, left=%d, top=%d, right=%d, bottom=%d)\n", hwnd,
496 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
498 if (lprcView != NULL)
500 bResult = TRUE;
501 infoPtr->rcView.left = lprcView->left;
502 infoPtr->rcView.top = lprcView->top;
503 infoPtr->rcView.right = lprcView->right;
504 infoPtr->rcView.bottom = lprcView->bottom;
507 return bResult;
510 /***
511 * DESCRIPTION:
512 * Retrieves the bounding rectangle of all the items.
514 * PARAMETER(S):
515 * [I] HWND : window handle
516 * [O] LPRECT : bounding rectangle
518 * RETURN:
519 * SUCCESS : TRUE
520 * FAILURE : FALSE
522 static LRESULT LISTVIEW_GetViewRect(HWND hwnd, LPRECT lprcView)
524 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
525 BOOL bResult = FALSE;
526 POINT ptOrigin;
528 TRACE("(hwnd=%x, lprcView=%p)\n", hwnd, lprcView);
530 if (lprcView != NULL)
532 bResult = LISTVIEW_GetOrigin(hwnd, &ptOrigin);
533 if (bResult != FALSE)
535 lprcView->left = infoPtr->rcView.left + ptOrigin.x;
536 lprcView->top = infoPtr->rcView.top + ptOrigin.y;
537 lprcView->right = infoPtr->rcView.right + ptOrigin.x;
538 lprcView->bottom = infoPtr->rcView.bottom + ptOrigin.y;
541 TRACE("(left=%d, top=%d, right=%d, bottom=%d)\n",
542 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
545 return bResult;
548 /***
549 * DESCRIPTION:
550 * Retrieves the subitem pointer associated with the subitem index.
552 * PARAMETER(S):
553 * [I] HDPA : DPA handle for a specific item
554 * [I] INT : index of subitem
556 * RETURN:
557 * SUCCESS : subitem pointer
558 * FAILURE : NULL
560 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems,
561 INT nSubItem)
563 LISTVIEW_SUBITEM *lpSubItem;
564 INT i;
566 for (i = 1; i < hdpaSubItems->nItemCount; i++)
568 lpSubItem = (LISTVIEW_SUBITEM *) DPA_GetPtr(hdpaSubItems, i);
569 if (lpSubItem != NULL)
571 if (lpSubItem->iSubItem == nSubItem)
573 return lpSubItem;
578 return NULL;
581 /***
582 * DESCRIPTION:
583 * Calculates the width of an item.
585 * PARAMETER(S):
586 * [I] HWND : window handle
587 * [I] LONG : window style
589 * RETURN:
590 * Returns item width.
592 static INT LISTVIEW_GetItemWidth(HWND hwnd)
594 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
595 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
596 INT nHeaderItemCount;
597 RECT rcHeaderItem;
598 INT nItemWidth = 0;
599 INT nLabelWidth;
600 INT i;
602 TRACE("(hwnd=%x)\n", hwnd);
604 if (uView == LVS_ICON)
606 nItemWidth = infoPtr->iconSpacing.cx;
608 else if (uView == LVS_REPORT)
610 /* calculate width of header */
611 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
612 for (i = 0; i < nHeaderItemCount; i++)
614 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
616 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
620 else
622 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
624 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, i);
625 nItemWidth = max(nItemWidth, nLabelWidth);
628 /* default label size */
629 if (GETITEMCOUNT(infoPtr) == 0)
631 nItemWidth = DEFAULT_COLUMN_WIDTH;
633 else
635 if (nItemWidth == 0)
637 nItemWidth = DEFAULT_LABEL_WIDTH;
639 else
641 /* add padding */
642 nItemWidth += WIDTH_PADDING;
644 if (infoPtr->himlSmall != NULL)
646 nItemWidth += infoPtr->iconSize.cx;
649 if (infoPtr->himlState != NULL)
651 nItemWidth += infoPtr->iconSize.cx;
657 return nItemWidth;
660 /***
661 * DESCRIPTION:
662 * Calculates the width of a specific item.
664 * PARAMETER(S):
665 * [I] HWND : window handle
666 * [I] LPSTR : string
668 * RETURN:
669 * Returns the width of an item width a specified string.
671 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem)
673 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
674 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
675 INT nHeaderItemCount;
676 RECT rcHeaderItem;
677 INT nItemWidth = 0;
678 INT i;
680 TRACE("(hwnd=%x)\n", hwnd);
682 if (uView == LVS_ICON)
684 nItemWidth = infoPtr->iconSpacing.cx;
686 else if (uView == LVS_REPORT)
688 /* calculate width of header */
689 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
690 for (i = 0; i < nHeaderItemCount; i++)
692 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
694 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
698 else
700 /* get width of string */
701 nItemWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
703 /* default label size */
704 if (GETITEMCOUNT(infoPtr) == 0)
706 nItemWidth = DEFAULT_COLUMN_WIDTH;
708 else
710 if (nItemWidth == 0)
712 nItemWidth = DEFAULT_LABEL_WIDTH;
714 else
716 /* add padding */
717 nItemWidth += WIDTH_PADDING;
719 if (infoPtr->himlSmall != NULL)
721 nItemWidth += infoPtr->iconSize.cx;
724 if (infoPtr->himlState != NULL)
726 nItemWidth += infoPtr->iconSize.cx;
732 return nItemWidth;
735 /***
736 * DESCRIPTION:
737 * Calculates the height of an item.
739 * PARAMETER(S):
740 * [I] HWND : window handle
741 * [I] LONG : window style
743 * RETURN:
744 * Returns item height.
746 static INT LISTVIEW_GetItemHeight(HWND hwnd)
748 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
749 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
750 INT nItemHeight = 0;
752 if (uView == LVS_ICON)
754 nItemHeight = infoPtr->iconSpacing.cy;
756 else
758 TEXTMETRICA tm;
759 HDC hdc = GetDC(hwnd);
760 HFONT hOldFont = SelectObject(hdc, infoPtr->hFont);
761 GetTextMetricsA(hdc, &tm);
762 nItemHeight = max(tm.tmHeight, infoPtr->iconSize.cy) + HEIGHT_PADDING;
763 SelectObject(hdc, hOldFont);
764 ReleaseDC(hwnd, hdc);
767 return nItemHeight;
770 /***
771 * DESCRIPTION:
772 * Adds a block of selections.
774 * PARAMETER(S):
775 * [I] HWND : window handle
776 * [I] INT : item index
778 * RETURN:
779 * None
781 static VOID LISTVIEW_AddGroupSelection(HWND hwnd, INT nItem)
783 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
784 INT nFirst = min(infoPtr->nSelectionMark, nItem);
785 INT nLast = max(infoPtr->nSelectionMark, nItem);
786 LVITEMA lvItem;
787 INT i;
789 lvItem.state = LVIS_SELECTED;
790 lvItem.stateMask= LVIS_SELECTED;
792 for (i = nFirst; i <= nLast; i++)
794 ListView_SetItemState(hwnd, i, &lvItem);
797 LISTVIEW_SetItemFocus(hwnd, nItem);
798 infoPtr->nSelectionMark = nItem;
801 /***
802 * DESCRIPTION:
803 * Adds a single selection.
805 * PARAMETER(S):
806 * [I] HWND : window handle
807 * [I] INT : item index
809 * RETURN:
810 * None
812 static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem)
814 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
815 LVITEMA lvItem;
817 lvItem.state = LVIS_SELECTED;
818 lvItem.stateMask= LVIS_SELECTED;
820 ListView_SetItemState(hwnd, nItem, &lvItem);
822 LISTVIEW_SetItemFocus(hwnd, nItem);
823 infoPtr->nSelectionMark = nItem;
826 /***
827 * DESCRIPTION:
828 * Selects or unselects an item.
830 * PARAMETER(S):
831 * [I] HWND : window handle
832 * [I] INT : item index
834 * RETURN:
835 * SELECT: TRUE
836 * UNSELECT : FALSE
838 static BOOL LISTVIEW_ToggleSelection(HWND hwnd, INT nItem)
840 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
841 BOOL bResult;
842 LVITEMA lvItem;
844 lvItem.stateMask= LVIS_SELECTED;
846 if (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
848 lvItem.state = 0;
849 ListView_SetItemState(hwnd, nItem, &lvItem);
850 bResult = FALSE;
852 else
854 lvItem.state = LVIS_SELECTED;
855 ListView_SetItemState(hwnd, nItem, &lvItem);
856 bResult = TRUE;
859 LISTVIEW_SetItemFocus(hwnd, nItem);
860 infoPtr->nSelectionMark = nItem;
862 return bResult;
865 /***
866 * DESCRIPTION:
867 * Selects items based on view coorddiantes.
869 * PARAMETER(S):
870 * [I] HWND : window handle
871 * [I] RECT : selection rectangle
873 * RETURN:
874 * None
876 static VOID LISTVIEW_SetSelectionRect(HWND hwnd, RECT rcSelRect)
878 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
879 LVITEMA lvItem;
880 POINT ptItem;
881 INT i;
883 lvItem.stateMask = LVIS_SELECTED;
885 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
887 LISTVIEW_GetItemPosition(hwnd, i, &ptItem);
888 if (PtInRect(&rcSelRect, ptItem) != FALSE)
890 lvItem.state = LVIS_SELECTED;
892 else
894 lvItem.state = 0;
897 ListView_SetItemState(hwnd, i, &lvItem);
901 /***
902 * DESCRIPTION:
903 * Sets a single group selection.
905 * PARAMETER(S):
906 * [I] HWND : window handle
907 * [I] INT : item index
909 * RETURN:
910 * None
912 static VOID LISTVIEW_SetGroupSelection(HWND hwnd, INT nItem)
914 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
915 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
916 LVITEMA lvItem;
918 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
920 INT i;
921 INT nFirst = min(infoPtr->nSelectionMark, nItem);
922 INT nLast = max(infoPtr->nSelectionMark, nItem);
923 lvItem.stateMask = LVIS_SELECTED;
925 for (i = 0; i <= GETITEMCOUNT(infoPtr); i++)
927 if ((i < nFirst) || (i > nLast))
929 lvItem.state = 0;
931 else
933 lvItem.state = LVIS_SELECTED;
936 ListView_SetItemState(hwnd, i, &lvItem);
939 else
941 POINT ptItem;
942 POINT ptSelMark;
943 RECT rcSel;
944 LISTVIEW_GetItemPosition(hwnd, nItem, &ptItem);
945 LISTVIEW_GetItemPosition(hwnd, infoPtr->nSelectionMark, &ptSelMark);
946 rcSel.left = min(ptSelMark.x, ptItem.x);
947 rcSel.top = min(ptSelMark.y, ptItem.y);
948 rcSel.right = max(ptSelMark.x, ptItem.x) + infoPtr->nItemWidth;
949 rcSel.bottom = max(ptSelMark.y, ptItem.y) + infoPtr->nItemHeight;
950 LISTVIEW_SetSelectionRect(hwnd, rcSel);
953 LISTVIEW_SetItemFocus(hwnd, nItem);
956 /***
957 * DESCRIPTION:
958 * Manages the item focus.
960 * PARAMETER(S):
961 * [I] HWND : window handle
962 * [I] INT : item index
964 * RETURN:
965 * TRUE : focused item changed
966 * FALSE : focused item has NOT changed
968 static BOOL LISTVIEW_SetItemFocus(HWND hwnd, INT nItem)
970 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
971 BOOL bResult = FALSE;
972 LVITEMA lvItem;
974 if (infoPtr->nFocusedItem != nItem)
976 bResult = TRUE;
977 ZeroMemory(&lvItem, sizeof(LVITEMA));
978 lvItem.stateMask = LVIS_FOCUSED;
979 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
981 lvItem.state = LVIS_FOCUSED;
982 lvItem.stateMask = LVIS_FOCUSED;
983 ListView_SetItemState(hwnd, nItem, &lvItem);
985 infoPtr->nFocusedItem = nItem;
986 ListView_EnsureVisible(hwnd, nItem, FALSE);
989 return bResult;
992 /***
993 * DESCRIPTION:
994 * Sets a single selection.
996 * PARAMETER(S):
997 * [I] HWND : window handle
998 * [I] INT : item index
1000 * RETURN:
1001 * None
1003 static VOID LISTVIEW_SetSelection(HWND hwnd, INT nItem)
1005 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1006 LVITEMA lvItem;
1008 if (nItem > 0)
1010 LISTVIEW_RemoveSelections(hwnd, 0, nItem - 1);
1013 if (nItem < GETITEMCOUNT(infoPtr))
1015 LISTVIEW_RemoveSelections(hwnd, nItem + 1, GETITEMCOUNT(infoPtr));
1018 ZeroMemory(&lvItem, sizeof(LVITEMA));
1019 lvItem.stateMask = LVIS_FOCUSED;
1020 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
1022 lvItem.state = LVIS_SELECTED | LVIS_FOCUSED;
1023 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
1024 ListView_SetItemState(hwnd, nItem, &lvItem);
1026 infoPtr->nFocusedItem = nItem;
1027 infoPtr->nSelectionMark = nItem;
1030 /***
1031 * DESCRIPTION:
1032 * Set selection(s) with keyboard.
1034 * PARAMETER(S):
1035 * [I] HWND : window handle
1036 * [I] INT : item index
1038 * RETURN:
1039 * SUCCESS : TRUE (needs to be repainted)
1040 * FAILURE : FALSE (nothing has changed)
1042 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem)
1044 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1045 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1046 WORD wShift = HIWORD(GetKeyState(VK_SHIFT));
1047 WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL));
1048 BOOL bResult = FALSE;
1050 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
1052 if (lStyle & LVS_SINGLESEL)
1054 bResult = TRUE;
1055 LISTVIEW_SetSelection(hwnd, nItem);
1056 ListView_EnsureVisible(hwnd, nItem, FALSE);
1058 else
1060 if (wShift)
1062 bResult = TRUE;
1063 LISTVIEW_SetGroupSelection(hwnd, nItem);
1065 else if (wCtrl)
1067 bResult = LISTVIEW_SetItemFocus(hwnd, nItem);
1069 else
1071 bResult = TRUE;
1072 LISTVIEW_SetSelection(hwnd, nItem);
1073 ListView_EnsureVisible(hwnd, nItem, FALSE);
1078 return bResult;
1081 /***
1082 * DESCRIPTION:
1083 * Selects an item based on coordinates.
1085 * PARAMETER(S):
1086 * [I] HWND : window handle
1087 * [I] POINT : mouse click ccordinates
1089 * RETURN:
1090 * SUCCESS : item index
1091 * FAILURE : -1
1093 static LRESULT LISTVIEW_MouseSelection(HWND hwnd, POINT pt)
1095 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1096 RECT rcItem;
1097 INT i;
1099 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
1101 rcItem.left = LVIR_SELECTBOUNDS;
1102 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) == TRUE)
1104 if (PtInRect(&rcItem, pt) != FALSE)
1106 return i;
1111 return -1;
1114 /***
1115 * DESCRIPTION:
1116 * Removes all selection states.
1118 * PARAMETER(S):
1119 * [I] HWND : window handle
1120 * [I] INT : item index
1122 * RETURN:
1123 * SUCCCESS : TRUE
1124 * FAILURE : FALSE
1126 static VOID LISTVIEW_RemoveSelections(HWND hwnd, INT nFirst, INT nLast)
1128 LVITEMA lvItem;
1129 INT i;
1131 lvItem.state = 0;
1132 lvItem.stateMask = LVIS_SELECTED;
1134 for (i = nFirst; i <= nLast; i++)
1136 ListView_SetItemState(hwnd, i, &lvItem);
1140 /***
1141 * DESCRIPTION:
1142 * Removes a column.
1144 * PARAMETER(S):
1145 * [IO] HDPA : dynamic pointer array handle
1146 * [I] INT : column index (subitem index)
1148 * RETURN:
1149 * SUCCCESS : TRUE
1150 * FAILURE : FALSE
1152 static BOOL LISTVIEW_RemoveColumn(HDPA hdpaItems, INT nSubItem)
1154 BOOL bResult = TRUE;
1155 HDPA hdpaSubItems;
1156 INT i;
1158 for (i = 0; i < hdpaItems->nItemCount; i++)
1160 hdpaSubItems = (HDPA)DPA_GetPtr(hdpaItems, i);
1161 if (hdpaSubItems != NULL)
1163 if (LISTVIEW_RemoveSubItem(hdpaSubItems, nSubItem) == FALSE)
1165 bResult = FALSE;
1170 return bResult;
1173 /***
1174 * DESCRIPTION:
1175 * Removes a subitem at a given position.
1177 * PARAMETER(S):
1178 * [IO] HDPA : dynamic pointer array handle
1179 * [I] INT : subitem index
1181 * RETURN:
1182 * SUCCCESS : TRUE
1183 * FAILURE : FALSE
1185 static BOOL LISTVIEW_RemoveSubItem(HDPA hdpaSubItems, INT nSubItem)
1187 LISTVIEW_SUBITEM *lpSubItem;
1188 INT i;
1190 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1192 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1193 if (lpSubItem != NULL)
1195 if (lpSubItem->iSubItem == nSubItem)
1197 /* free string */
1198 if ((lpSubItem->pszText != NULL) &&
1199 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1201 COMCTL32_Free(lpSubItem->pszText);
1204 /* free item */
1205 COMCTL32_Free(lpSubItem);
1207 /* free dpa memory */
1208 if (DPA_DeletePtr(hdpaSubItems, i) == NULL)
1210 return FALSE;
1213 else if (lpSubItem->iSubItem > nSubItem)
1215 return TRUE;
1220 return TRUE;
1223 /***
1224 * DESCRIPTION:
1225 * Compares the item information.
1227 * PARAMETER(S):
1228 * [I] LISTVIEW_ITEM *: destination item
1229 * [I] LPLVITEM : source item
1231 * RETURN:
1232 * SUCCCESS : TRUE (EQUAL)
1233 * FAILURE : FALSE (NOT EQUAL)
1235 static UINT LISTVIEW_GetItemChanges(LISTVIEW_ITEM *lpItem, LPLVITEMA lpLVItem)
1237 UINT uChanged = 0;
1239 if ((lpItem != NULL) && (lpLVItem != NULL))
1241 if (lpLVItem->mask & LVIF_STATE)
1243 if ((lpItem->state & lpLVItem->stateMask) !=
1244 (lpLVItem->state & lpLVItem->stateMask))
1246 uChanged |= LVIF_STATE;
1250 if (lpLVItem->mask & LVIF_IMAGE)
1252 if (lpItem->iImage != lpLVItem->iImage)
1254 uChanged |= LVIF_IMAGE;
1258 if (lpLVItem->mask & LVIF_PARAM)
1260 if (lpItem->lParam != lpLVItem->lParam)
1262 uChanged |= LVIF_PARAM;
1266 if (lpLVItem->mask & LVIF_INDENT)
1268 if (lpItem->iIndent != lpLVItem->iIndent)
1270 uChanged |= LVIF_INDENT;
1274 if (lpLVItem->mask & LVIF_TEXT)
1276 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1278 if (lpItem->pszText != LPSTR_TEXTCALLBACKA)
1280 uChanged |= LVIF_TEXT;
1283 else
1285 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1287 uChanged |= LVIF_TEXT;
1289 else
1291 if (lpLVItem->pszText)
1293 if (lpItem->pszText)
1295 if (strcmp(lpLVItem->pszText, lpItem->pszText) != 0)
1297 uChanged |= LVIF_TEXT;
1300 else
1302 uChanged |= LVIF_TEXT;
1305 else
1307 if (lpItem->pszText)
1309 uChanged |= LVIF_TEXT;
1316 return uChanged;
1319 /***
1320 * DESCRIPTION:
1321 * Initializes item attributes.
1323 * PARAMETER(S):
1324 * [I] HWND : window handle
1325 * [O] LISTVIEW_ITEM *: destination item
1326 * [I] LPLVITEM : source item
1328 * RETURN:
1329 * SUCCCESS : TRUE
1330 * FAILURE : FALSE
1332 static BOOL LISTVIEW_InitItem(HWND hwnd, LISTVIEW_ITEM *lpItem,
1333 LPLVITEMA lpLVItem)
1335 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1336 BOOL bResult = FALSE;
1338 if ((lpItem != NULL) && (lpLVItem != NULL))
1340 bResult = TRUE;
1342 if (lpLVItem->mask & LVIF_STATE)
1344 lpItem->state &= ~lpLVItem->stateMask;
1345 lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
1348 if (lpLVItem->mask & LVIF_IMAGE)
1350 lpItem->iImage = lpLVItem->iImage;
1353 if (lpLVItem->mask & LVIF_PARAM)
1355 lpItem->lParam = lpLVItem->lParam;
1358 if (lpLVItem->mask & LVIF_INDENT)
1360 lpItem->iIndent = lpLVItem->iIndent;
1363 if (lpLVItem->mask & LVIF_TEXT)
1365 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1367 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1369 return FALSE;
1372 if ((lpItem->pszText != NULL) &&
1373 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
1375 COMCTL32_Free(lpItem->pszText);
1378 lpItem->pszText = LPSTR_TEXTCALLBACKA;
1380 else
1382 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1384 lpItem->pszText = NULL;
1387 bResult = Str_SetPtrA(&lpItem->pszText, lpLVItem->pszText);
1392 return bResult;
1395 /***
1396 * DESCRIPTION:
1397 * Initializes subitem attributes.
1399 * NOTE: The documentation specifies that the operation fails if the user
1400 * tries to set the indent of a subitem.
1402 * PARAMETER(S):
1403 * [I] HWND : window handle
1404 * [O] LISTVIEW_SUBITEM *: destination subitem
1405 * [I] LPLVITEM : source subitem
1407 * RETURN:
1408 * SUCCCESS : TRUE
1409 * FAILURE : FALSE
1411 static BOOL LISTVIEW_InitSubItem(HWND hwnd, LISTVIEW_SUBITEM *lpSubItem,
1412 LPLVITEMA lpLVItem)
1414 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1415 BOOL bResult = FALSE;
1417 if ((lpSubItem != NULL) && (lpLVItem != NULL))
1419 if (!(lpLVItem->mask & LVIF_INDENT))
1421 bResult = TRUE;
1422 ZeroMemory(lpSubItem, sizeof(LISTVIEW_SUBITEM));
1424 lpSubItem->iSubItem = lpLVItem->iSubItem;
1426 if (lpLVItem->mask & LVIF_IMAGE)
1428 lpSubItem->iImage = lpLVItem->iImage;
1431 if (lpLVItem->mask & LVIF_TEXT)
1433 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1435 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1437 return FALSE;
1440 if ((lpSubItem->pszText != NULL) &&
1441 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1443 COMCTL32_Free(lpSubItem->pszText);
1446 lpSubItem->pszText = LPSTR_TEXTCALLBACKA;
1448 else
1450 if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
1452 lpSubItem->pszText = NULL;
1455 bResult = Str_SetPtrA(&lpSubItem->pszText, lpLVItem->pszText);
1461 return bResult;
1464 /***
1465 * DESCRIPTION:
1466 * Adds a subitem at a given position (column index).
1468 * PARAMETER(S):
1469 * [I] HWND : window handle
1470 * [I] LPLVITEM : new subitem atttributes
1472 * RETURN:
1473 * SUCCESS : TRUE
1474 * FAILURE : FALSE
1476 static BOOL LISTVIEW_AddSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1478 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1479 LISTVIEW_SUBITEM *lpSubItem = NULL;
1480 BOOL bResult = FALSE;
1481 HDPA hdpaSubItems;
1482 INT nPosition, nItem;
1484 if (lpLVItem != NULL)
1486 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1487 if (hdpaSubItems != NULL)
1489 lpSubItem = (LISTVIEW_SUBITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM));
1490 if (lpSubItem != NULL)
1492 if (LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem) != FALSE)
1494 nPosition = LISTVIEW_FindInsertPosition(hdpaSubItems,
1495 lpSubItem->iSubItem);
1496 nItem = DPA_InsertPtr(hdpaSubItems, nPosition, lpSubItem);
1497 if (nItem != -1)
1499 bResult = TRUE;
1506 /* cleanup if unsuccessful */
1507 if ((bResult == FALSE) && (lpSubItem != NULL))
1509 COMCTL32_Free(lpSubItem);
1512 return bResult;
1515 /***
1516 * DESCRIPTION:
1517 * Finds the dpa insert position (array index).
1519 * PARAMETER(S):
1520 * [I] HWND : window handle
1521 * [I] INT : subitem index
1523 * RETURN:
1524 * SUCCESS : TRUE
1525 * FAILURE : FALSE
1527 static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem)
1529 LISTVIEW_SUBITEM *lpSubItem;
1530 INT i;
1532 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1534 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1535 if (lpSubItem != NULL)
1537 if (lpSubItem->iSubItem > nSubItem)
1539 return i;
1544 return hdpaSubItems->nItemCount;
1547 /***
1548 * DESCRIPTION:
1549 * Retrieves a listview subitem at a given position (column index).
1551 * PARAMETER(S):
1552 * [I] HWND : window handle
1553 * [I] INT : subitem index
1555 * RETURN:
1556 * SUCCESS : TRUE
1557 * FAILURE : FALSE
1559 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem)
1561 LISTVIEW_SUBITEM *lpSubItem;
1562 INT i;
1564 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1566 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1567 if (lpSubItem != NULL)
1569 if (lpSubItem->iSubItem == nSubItem)
1571 return lpSubItem;
1573 else if (lpSubItem->iSubItem > nSubItem)
1575 return NULL;
1580 return NULL;
1583 /***
1584 * DESCRIPTION:
1585 * Sets item attributes.
1587 * PARAMETER(S):
1588 * [I] HWND : window handle
1589 * [I] LPLVITEM : new item atttributes
1591 * RETURN:
1592 * SUCCESS : TRUE
1593 * FAILURE : FALSE
1595 static BOOL LISTVIEW_SetItem(HWND hwnd, LPLVITEMA lpLVItem)
1597 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1598 BOOL bResult = FALSE;
1599 HDPA hdpaSubItems;
1600 LISTVIEW_ITEM *lpItem;
1601 NMLISTVIEW nmlv;
1602 UINT uChanged;
1603 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
1605 if (lpLVItem != NULL)
1607 if (lpLVItem->iSubItem == 0)
1609 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1610 if (hdpaSubItems != NULL)
1612 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem);
1613 if (lpItem != NULL)
1615 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
1616 nmlv.hdr.hwndFrom = hwnd;
1617 nmlv.hdr.idFrom = lCtrlId;
1618 nmlv.hdr.code = LVN_ITEMCHANGING;
1619 nmlv.lParam = lpItem->lParam;
1620 uChanged = LISTVIEW_GetItemChanges(lpItem, lpLVItem);
1621 if (uChanged != 0)
1623 if (uChanged & LVIF_STATE)
1625 nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask;
1626 nmlv.uOldState = lpItem->state & lpLVItem->stateMask;
1629 nmlv.uChanged = uChanged;
1630 nmlv.iItem = lpLVItem->iItem;
1631 nmlv.lParam = lpItem->lParam;
1632 /* send LVN_ITEMCHANGING notification */
1633 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1635 /* copy information */
1636 bResult = LISTVIEW_InitItem(hwnd, lpItem, lpLVItem);
1638 /* send LVN_ITEMCHANGED notification */
1639 nmlv.hdr.code = LVN_ITEMCHANGED;
1640 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1642 else
1644 bResult = TRUE;
1647 InvalidateRect(hwnd, NULL, FALSE);
1653 return bResult;
1656 /***
1657 * DESCRIPTION:
1658 * Sets subitem attributes.
1660 * PARAMETER(S):
1661 * [I] HWND : window handle
1662 * [I] LPLVITEM : new subitem atttributes
1664 * RETURN:
1665 * SUCCESS : TRUE
1666 * FAILURE : FALSE
1668 static BOOL LISTVIEW_SetSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1670 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1671 BOOL bResult = FALSE;
1672 HDPA hdpaSubItems;
1673 LISTVIEW_SUBITEM *lpSubItem;
1675 if (lpLVItem != NULL)
1677 if (lpLVItem->iSubItem > 0)
1679 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1680 if (hdpaSubItems != NULL)
1682 /* set subitem only if column is present */
1683 if (Header_GetItemCount(infoPtr->hwndHeader) > lpLVItem->iSubItem)
1685 lpSubItem = LISTVIEW_GetSubItem(hdpaSubItems, lpLVItem->iSubItem);
1686 if (lpSubItem != NULL)
1688 bResult = LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem);
1690 else
1692 bResult = LISTVIEW_AddSubItem(hwnd, lpLVItem);
1695 InvalidateRect(hwnd, NULL, FALSE);
1701 return bResult;
1704 /***
1705 * DESCRIPTION:
1706 * Retrieves the index of the item at coordinate (0, 0) of the client area.
1708 * PARAMETER(S):
1709 * [I] HWND : window handle
1711 * RETURN:
1712 * item index
1714 static INT LISTVIEW_GetTopIndex(HWND hwnd)
1716 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1717 UINT uView = lStyle & LVS_TYPEMASK;
1718 INT nItem = 0;
1719 SCROLLINFO scrollInfo;
1721 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
1722 scrollInfo.cbSize = sizeof(SCROLLINFO);
1723 scrollInfo.fMask = SIF_POS;
1725 if (uView == LVS_LIST)
1727 if (lStyle & WS_HSCROLL)
1729 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
1731 nItem = scrollInfo.nPos * LISTVIEW_GetCountPerColumn(hwnd);
1735 else if (uView == LVS_REPORT)
1737 if (lStyle & WS_VSCROLL)
1739 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
1741 nItem = scrollInfo.nPos;
1746 return nItem;
1749 /***
1750 * DESCRIPTION:
1751 * Draws a subitem.
1753 * PARAMETER(S):
1754 * [I] HWND : window handle
1755 * [I] HDC : device context handle
1756 * [I] INT : item index
1757 * [I] INT : subitem index
1758 * [I] RECT * : clipping rectangle
1760 * RETURN:
1761 * None
1763 static VOID LISTVIEW_DrawSubItem(HWND hwnd, HDC hdc, INT nItem, INT nSubItem,
1764 RECT rcItem)
1766 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1767 CHAR szDispText[DISP_TEXT_SIZE];
1768 LVITEMA lvItem;
1770 TRACE("(hwnd=%x, hdc=%x, nItem=%d, nSubItem=%d\n", hwnd, hdc,
1771 nItem, nSubItem);
1773 /* get information needed for drawing the item */
1774 ZeroMemory(&lvItem, sizeof(LVITEMA));
1775 lvItem.mask = LVIF_TEXT;
1776 lvItem.iItem = nItem;
1777 lvItem.iSubItem = nSubItem;
1778 lvItem.cchTextMax = DISP_TEXT_SIZE;
1779 lvItem.pszText = szDispText;
1780 ListView_GetItemA(hwnd, &lvItem);
1782 /* set item colors */
1783 SetBkColor(hdc, infoPtr->clrTextBk);
1784 SetTextColor(hdc, infoPtr->clrText);
1786 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1787 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
1791 /***
1792 * DESCRIPTION:
1793 * Draws an item.
1795 * PARAMETER(S):
1796 * [I] HWND : window handle
1797 * [I] HDC : device context handle
1798 * [I] INT : item index
1799 * [I] RECT * : clipping rectangle
1801 * RETURN:
1802 * None
1804 static VOID LISTVIEW_DrawItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem)
1806 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1807 CHAR szDispText[DISP_TEXT_SIZE];
1808 INT nLabelWidth;
1809 LVITEMA lvItem;
1810 INT nMixMode;
1811 DWORD dwBkColor;
1812 DWORD dwTextColor;
1814 TRACE("(hwnd=%x, hdc=%x, nItem=%d\n", hwnd, hdc, nItem);
1816 /* get information needed for drawing the item */
1817 ZeroMemory(&lvItem, sizeof(LVITEMA));
1818 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_INDENT;
1819 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED | LVIS_STATEIMAGEMASK;
1820 lvItem.iItem = nItem;
1821 lvItem.iSubItem = 0;
1822 lvItem.cchTextMax = DISP_TEXT_SIZE;
1823 lvItem.pszText = szDispText;
1824 ListView_GetItemA(hwnd, &lvItem);
1826 /* state icons */
1827 if (infoPtr->himlState != NULL)
1829 UINT uStateImage = (lvItem.state & LVIS_STATEIMAGEMASK) >> 12;
1830 if (uStateImage != 0)
1832 ImageList_Draw(infoPtr->himlState, uStateImage - 1, hdc, rcItem.left,
1833 rcItem.top, ILD_NORMAL);
1836 rcItem.left += infoPtr->iconSize.cx;
1839 /* small icons */
1840 if (infoPtr->himlSmall != NULL)
1842 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
1844 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
1845 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
1846 rcItem.top, ILD_SELECTED);
1848 else
1850 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
1851 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
1852 rcItem.top, ILD_NORMAL);
1855 rcItem.left += infoPtr->iconSize.cx;
1858 /* Don't bother painting item being edited */
1859 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED)
1860 return;
1862 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
1864 /* set item colors */
1865 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1866 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1867 /* set raster mode */
1868 nMixMode = SetROP2(hdc, R2_XORPEN);
1870 else if ((GetWindowLongA(hwnd, GWL_STYLE) & LVS_SHOWSELALWAYS) &&
1871 (lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus == FALSE))
1873 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
1874 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
1875 /* set raster mode */
1876 nMixMode = SetROP2(hdc, R2_COPYPEN);
1878 else
1880 /* set item colors */
1881 dwBkColor = SetBkColor(hdc, infoPtr->clrTextBk);
1882 dwTextColor = SetTextColor(hdc, infoPtr->clrText);
1883 /* set raster mode */
1884 nMixMode = SetROP2(hdc, R2_COPYPEN);
1887 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
1888 if (rcItem.left + nLabelWidth < rcItem.right)
1890 rcItem.right = rcItem.left + nLabelWidth;
1893 /* draw label */
1894 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1895 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
1897 if ((lvItem.state & LVIS_FOCUSED) && (infoPtr->bFocus == TRUE))
1899 Rectangle(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
1902 if (nMixMode != 0)
1904 SetROP2(hdc, R2_COPYPEN);
1905 SetBkColor(hdc, infoPtr->clrTextBk);
1906 SetTextColor(hdc, infoPtr->clrText);
1910 /***
1911 * DESCRIPTION:
1912 * Draws an item when in large icon display mode.
1914 * PARAMETER(S):
1915 * [I] HWND : window handle
1916 * [I] HDC : device context handle
1917 * [I] LISTVIEW_ITEM * : item
1918 * [I] INT : item index
1919 * [I] RECT * : clipping rectangle
1921 * RETURN:
1922 * None
1924 static VOID LISTVIEW_DrawLargeItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem)
1926 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1927 CHAR szDispText[DISP_TEXT_SIZE];
1928 INT nDrawPosX = rcItem.left;
1929 INT nLabelWidth;
1930 TEXTMETRICA tm;
1931 LVITEMA lvItem;
1933 TRACE("(hwnd=%x, hdc=%x, nItem=%d, left=%d, top=%d, right=%d, \
1934 bottom=%d)\n", hwnd, hdc, nItem, rcItem.left, rcItem.top, rcItem.right,
1935 rcItem.bottom);
1937 /* get information needed for drawing the item */
1938 ZeroMemory(&lvItem, sizeof(LVITEMA));
1939 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
1940 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
1941 lvItem.iItem = nItem;
1942 lvItem.iSubItem = 0;
1943 lvItem.cchTextMax = DISP_TEXT_SIZE;
1944 lvItem.pszText = szDispText;
1945 ListView_GetItemA(hwnd, &lvItem);
1947 if (lvItem.state & LVIS_SELECTED)
1949 /* set item colors */
1950 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1951 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1952 /* set raster mode */
1953 SetROP2(hdc, R2_XORPEN);
1955 else
1957 /* set item colors */
1958 SetBkColor(hdc, infoPtr->clrTextBk);
1959 SetTextColor(hdc, infoPtr->clrText);
1960 /* set raster mode */
1961 SetROP2(hdc, R2_COPYPEN);
1964 if (infoPtr->himlNormal != NULL)
1966 rcItem.top += ICON_TOP_PADDING;
1967 nDrawPosX += (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
1968 if (lvItem.state & LVIS_SELECTED)
1970 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
1971 rcItem.top, ILD_SELECTED);
1973 else
1975 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
1976 rcItem.top, ILD_NORMAL);
1980 rcItem.top += infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
1981 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
1982 nDrawPosX = infoPtr->iconSpacing.cx - nLabelWidth;
1983 if (nDrawPosX > 1)
1985 rcItem.left += nDrawPosX / 2;
1986 rcItem.right = rcItem.left + nLabelWidth;
1988 else
1990 rcItem.left += 1;
1991 rcItem.right = rcItem.left + infoPtr->iconSpacing.cx - 1;
1994 /* draw label */
1995 GetTextMetricsA(hdc, &tm);
1996 rcItem.bottom = rcItem.top + tm.tmHeight + HEIGHT_PADDING;
1997 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1998 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
2000 if (lvItem.state & LVIS_FOCUSED)
2002 Rectangle(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
2006 /***
2007 * DESCRIPTION:
2008 * Draws listview items when in report display mode.
2010 * PARAMETER(S):
2011 * [I] HWND : window handle
2012 * [I] HDC : device context handle
2014 * RETURN:
2015 * None
2017 static VOID LISTVIEW_RefreshReport(HWND hwnd, HDC hdc)
2019 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2020 SCROLLINFO scrollInfo;
2021 INT nDrawPosY = infoPtr->rcList.top;
2022 INT nColumnCount;
2023 RECT rcItem;
2024 INT j;
2025 INT nItem;
2026 INT nLast;
2028 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2029 scrollInfo.cbSize = sizeof(SCROLLINFO);
2030 scrollInfo.fMask = SIF_POS;
2032 nItem = ListView_GetTopIndex(hwnd);
2034 /* add 1 for displaying a partial item at the bottom */
2035 nLast = nItem + LISTVIEW_GetCountPerColumn(hwnd) + 1;
2036 nLast = min(nLast, GETITEMCOUNT(infoPtr));
2037 for (; nItem < nLast; nItem++)
2039 nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
2040 for (j = 0; j < nColumnCount; j++)
2042 Header_GetItemRect(infoPtr->hwndHeader, j, &rcItem);
2043 rcItem.left += REPORT_MARGINX;
2044 rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX);
2045 rcItem.top = nDrawPosY;
2046 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2048 /* Offset the Scroll Bar Pos */
2049 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2051 rcItem.left -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
2052 rcItem.right -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
2055 if (j == 0)
2057 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem);
2059 else
2061 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, j, rcItem);
2065 nDrawPosY += infoPtr->nItemHeight;
2069 /***
2070 * DESCRIPTION:
2071 * Retrieves the number of items that can fit vertically in the client area.
2073 * PARAMETER(S):
2074 * [I] HWND : window handle
2076 * RETURN:
2077 * Number of items per row.
2079 static INT LISTVIEW_GetCountPerRow(HWND hwnd)
2081 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2082 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2083 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
2084 INT nCountPerRow = 1;
2086 if (nListWidth > 0)
2088 if (uView == LVS_REPORT)
2090 nCountPerRow = 1;
2092 else
2094 nCountPerRow = nListWidth / infoPtr->nItemWidth;
2095 if (nCountPerRow == 0)
2097 nCountPerRow = 1;
2102 return nCountPerRow;
2105 /***
2106 * DESCRIPTION:
2107 * Retrieves the number of items that can fit horizontally in the client
2108 * area.
2110 * PARAMETER(S):
2111 * [I] HWND : window handle
2113 * RETURN:
2114 * Number of items per column.
2116 static INT LISTVIEW_GetCountPerColumn(HWND hwnd)
2118 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2119 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2120 INT nCountPerColumn = 1;
2122 if (nListHeight > 0)
2124 nCountPerColumn = nListHeight / infoPtr->nItemHeight;
2125 if (nCountPerColumn == 0)
2127 nCountPerColumn = 1;
2131 return nCountPerColumn;
2134 /***
2135 * DESCRIPTION:
2136 * Retrieves the number of columns needed to display all the items when in
2137 * list display mode.
2139 * PARAMETER(S):
2140 * [I] HWND : window handle
2142 * RETURN:
2143 * Number of columns.
2145 static INT LISTVIEW_GetColumnCount(HWND hwnd)
2147 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2148 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2149 INT nColumnCount = 0;
2151 if ((lStyle & LVS_TYPEMASK) == LVS_LIST)
2153 if (infoPtr->rcList.right % infoPtr->nItemWidth == 0)
2155 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth;
2157 else
2159 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth + 1;
2163 return nColumnCount;
2167 /***
2168 * DESCRIPTION:
2169 * Draws listview items when in list display mode.
2171 * PARAMETER(S):
2172 * [I] HWND : window handle
2173 * [I] HDC : device context handle
2175 * RETURN:
2176 * None
2178 static VOID LISTVIEW_RefreshList(HWND hwnd, HDC hdc)
2180 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2181 RECT rcItem;
2182 INT i, j;
2183 INT nItem;
2184 INT nColumnCount;
2185 INT nCountPerColumn;
2186 INT nItemWidth = LISTVIEW_GetItemWidth(hwnd);
2187 INT nItemHeight = LISTVIEW_GetItemHeight(hwnd);
2189 /* get number of fully visible columns */
2190 nColumnCount = LISTVIEW_GetColumnCount(hwnd);
2191 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
2192 nItem = ListView_GetTopIndex(hwnd);
2194 for (i = 0; i < nColumnCount; i++)
2196 for (j = 0; j < nCountPerColumn; j++, nItem++)
2198 if (nItem >= GETITEMCOUNT(infoPtr))
2199 return;
2201 rcItem.top = j * nItemHeight;
2202 rcItem.left = i * nItemWidth;
2203 rcItem.bottom = rcItem.top + nItemHeight;
2204 rcItem.right = rcItem.left + nItemWidth;
2205 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem);
2210 /***
2211 * DESCRIPTION:
2212 * Draws listview items when in icon or small icon display mode.
2214 * PARAMETER(S):
2215 * [I] HWND : window handle
2216 * [I] HDC : device context handle
2218 * RETURN:
2219 * None
2221 static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc, BOOL bSmall)
2223 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2224 POINT ptPosition;
2225 POINT ptOrigin;
2226 RECT rcItem;
2227 INT i;
2229 LISTVIEW_GetOrigin(hwnd, &ptOrigin);
2230 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2232 LISTVIEW_GetItemPosition(hwnd, i, &ptPosition);
2233 ptPosition.x += ptOrigin.x;
2234 ptPosition.y += ptOrigin.y;
2236 if (ptPosition.y + infoPtr->nItemHeight > infoPtr->rcList.top)
2238 if (ptPosition.x + infoPtr->nItemWidth > infoPtr->rcList.left)
2240 if (ptPosition.y < infoPtr->rcList.bottom)
2242 if (ptPosition.x < infoPtr->rcList.right)
2244 rcItem.top = ptPosition.y;
2245 rcItem.left = ptPosition.x;
2246 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2247 rcItem.right = rcItem.left + infoPtr->nItemWidth;
2248 if (bSmall == FALSE)
2250 LISTVIEW_DrawLargeItem(hwnd, hdc, i, rcItem);
2252 else
2254 LISTVIEW_DrawItem(hwnd, hdc, i, rcItem);
2263 /***
2264 * DESCRIPTION:
2265 * Draws listview items.
2267 * PARAMETER(S):
2268 * [I] HWND : window handle
2269 * [I] HDC : device context handle
2271 * RETURN:
2272 * NoneX
2274 static VOID LISTVIEW_Refresh(HWND hwnd, HDC hdc)
2276 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2277 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2278 HFONT hOldFont;
2279 HPEN hPen, hOldPen;
2281 /* select font */
2282 hOldFont = SelectObject(hdc, infoPtr->hFont);
2284 /* select the doted pen (for drawing the focus box) */
2285 hPen = CreatePen(PS_DOT, 1, 0);
2286 hOldPen = SelectObject(hdc, hPen);
2288 /* select transparent brush (for drawing the focus box) */
2289 SelectObject(hdc, GetStockObject(NULL_BRUSH));
2291 if (uView == LVS_LIST)
2293 LISTVIEW_RefreshList(hwnd, hdc);
2295 else if (uView == LVS_REPORT)
2297 LISTVIEW_RefreshReport(hwnd, hdc);
2299 else if (uView == LVS_SMALLICON)
2301 LISTVIEW_RefreshIcon(hwnd, hdc, TRUE);
2303 else if (uView == LVS_ICON)
2305 LISTVIEW_RefreshIcon(hwnd, hdc, FALSE);
2308 /* unselect objects */
2309 SelectObject(hdc, hOldFont);
2310 SelectObject(hdc, hOldPen);
2312 /* delete pen */
2313 DeleteObject(hPen);
2317 /***
2318 * DESCRIPTION:
2319 * Calculates the approximate width and height of a given number of items.
2321 * PARAMETER(S):
2322 * [I] HWND : window handle
2323 * [I] INT : number of items
2324 * [I] INT : width
2325 * [I] INT : height
2327 * RETURN:
2328 * Returns a DWORD. The width in the low word and the height in high word.
2330 static LRESULT LISTVIEW_ApproximateViewRect(HWND hwnd, INT nItemCount,
2331 WORD wWidth, WORD wHeight)
2333 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2334 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2335 INT nItemCountPerColumn = 1;
2336 INT nColumnCount = 0;
2337 DWORD dwViewRect = 0;
2339 if (nItemCount == -1)
2341 nItemCount = GETITEMCOUNT(infoPtr);
2344 if (uView == LVS_LIST)
2346 if (wHeight == 0xFFFF)
2348 /* use current height */
2349 wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2352 if (wHeight < infoPtr->nItemHeight)
2354 wHeight = infoPtr->nItemHeight;
2357 if (nItemCount > 0)
2359 if (infoPtr->nItemHeight > 0)
2361 nItemCountPerColumn = wHeight / infoPtr->nItemHeight;
2362 if (nItemCountPerColumn == 0)
2364 nItemCountPerColumn = 1;
2367 if (nItemCount % nItemCountPerColumn != 0)
2369 nColumnCount = nItemCount / nItemCountPerColumn;
2371 else
2373 nColumnCount = nItemCount / nItemCountPerColumn + 1;
2378 /* Microsoft padding magic */
2379 wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2;
2380 wWidth = nColumnCount * infoPtr->nItemWidth + 2;
2382 dwViewRect = MAKELONG(wWidth, wHeight);
2384 else if (uView == LVS_REPORT)
2386 /* TO DO */
2388 else if (uView == LVS_SMALLICON)
2390 /* TO DO */
2392 else if (uView == LVS_ICON)
2394 /* TO DO */
2397 return dwViewRect;
2400 /***
2401 * DESCRIPTION:
2402 * Arranges listview items in icon display mode.
2404 * PARAMETER(S):
2405 * [I] HWND : window handle
2406 * [I] INT : alignment code
2408 * RETURN:
2409 * SUCCESS : TRUE
2410 * FAILURE : FALSE
2412 static LRESULT LISTVIEW_Arrange(HWND hwnd, INT nAlignCode)
2414 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2415 BOOL bResult = FALSE;
2417 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2419 switch (nAlignCode)
2421 case LVA_ALIGNLEFT:
2422 /* TO DO */
2423 break;
2424 case LVA_ALIGNTOP:
2425 /* TO DO */
2426 break;
2427 case LVA_DEFAULT:
2428 /* TO DO */
2429 break;
2430 case LVA_SNAPTOGRID:
2431 /* TO DO */
2432 break;
2436 return bResult;
2439 /* << LISTVIEW_CreateDragImage >> */
2441 /***
2442 * DESCRIPTION:
2443 * Removes all listview items and subitems.
2445 * PARAMETER(S):
2446 * [I] HWND : window handle
2448 * RETURN:
2449 * SUCCESS : TRUE
2450 * FAILURE : FALSE
2452 static LRESULT LISTVIEW_DeleteAllItems(HWND hwnd)
2454 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2455 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2456 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2457 UINT uView = lStyle & LVS_TYPEMASK;
2458 LISTVIEW_ITEM *lpItem;
2459 LISTVIEW_SUBITEM *lpSubItem;
2460 NMLISTVIEW nmlv;
2461 BOOL bSuppress;
2462 BOOL bResult = FALSE;
2463 INT i;
2464 INT j;
2465 HDPA hdpaSubItems;
2467 TRACE("(hwnd=%x,)\n", hwnd);
2469 if (GETITEMCOUNT(infoPtr) > 0)
2471 /* initialize memory */
2472 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2474 /* send LVN_DELETEALLITEMS notification */
2475 nmlv.hdr.hwndFrom = hwnd;
2476 nmlv.hdr.idFrom = lCtrlId;
2477 nmlv.hdr.code = LVN_DELETEALLITEMS;
2478 nmlv.iItem = -1;
2480 /* verify if subsequent LVN_DELETEITEM notifications should be
2481 suppressed */
2482 bSuppress = ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2484 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2486 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
2487 if (hdpaSubItems != NULL)
2489 for (j = 1; j < hdpaSubItems->nItemCount; j++)
2491 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, j);
2492 if (lpSubItem != NULL)
2494 /* free subitem string */
2495 if ((lpSubItem->pszText != NULL) &&
2496 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2498 COMCTL32_Free(lpSubItem->pszText);
2501 /* free subitem */
2502 COMCTL32_Free(lpSubItem);
2506 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2507 if (lpItem != NULL)
2509 if (bSuppress == FALSE)
2511 /* send LVN_DELETEITEM notification */
2512 nmlv.hdr.code = LVN_DELETEITEM;
2513 nmlv.iItem = i;
2514 nmlv.lParam = lpItem->lParam;
2515 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2518 /* free item string */
2519 if ((lpItem->pszText != NULL) &&
2520 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2522 COMCTL32_Free(lpItem->pszText);
2525 /* free item */
2526 COMCTL32_Free(lpItem);
2529 DPA_Destroy(hdpaSubItems);
2533 /* reinitialize listview memory */
2534 bResult = DPA_DeleteAllPtrs(infoPtr->hdpaItems);
2536 /* align items (set position of each item) */
2537 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2539 if (lStyle & LVS_ALIGNLEFT)
2541 LISTVIEW_AlignLeft(hwnd);
2543 else
2545 LISTVIEW_AlignTop(hwnd);
2549 LISTVIEW_UpdateScroll(hwnd);
2551 /* invalidate client area (optimization needed) */
2552 InvalidateRect(hwnd, NULL, TRUE);
2555 return bResult;
2558 /***
2559 * DESCRIPTION:
2560 * Removes a column from the listview control.
2562 * PARAMETER(S):
2563 * [I] HWND : window handle
2564 * [I] INT : column index
2566 * RETURN:
2567 * SUCCESS : TRUE
2568 * FAILURE : FALSE
2570 static LRESULT LISTVIEW_DeleteColumn(HWND hwnd, INT nColumn)
2572 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2573 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2574 BOOL bResult = FALSE;
2576 if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) != FALSE)
2578 bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
2580 /* Need to reset the item width when deleting a column */
2581 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
2583 /* reset scroll parameters */
2584 if (uView == LVS_REPORT)
2586 /* update scrollbar(s) */
2587 LISTVIEW_UpdateScroll(hwnd);
2589 /* refresh client area */
2590 InvalidateRect(hwnd, NULL, FALSE);
2594 return bResult;
2597 /***
2598 * DESCRIPTION:
2599 * Removes an item from the listview control.
2601 * PARAMETER(S):
2602 * [I] HWND : window handle
2603 * [I] INT : item index
2605 * RETURN:
2606 * SUCCESS : TRUE
2607 * FAILURE : FALSE
2609 static LRESULT LISTVIEW_DeleteItem(HWND hwnd, INT nItem)
2611 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2612 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2613 UINT uView = lStyle & LVS_TYPEMASK;
2614 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2615 NMLISTVIEW nmlv;
2616 BOOL bResult = FALSE;
2617 HDPA hdpaSubItems;
2618 LISTVIEW_ITEM *lpItem;
2619 LISTVIEW_SUBITEM *lpSubItem;
2620 INT i;
2622 TRACE("(hwnd=%x,nItem=%d)\n", hwnd, nItem);
2624 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
2626 /* initialize memory */
2627 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2629 hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem);
2630 if (hdpaSubItems != NULL)
2632 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2634 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2635 if (lpSubItem != NULL)
2637 /* free item string */
2638 if ((lpSubItem->pszText != NULL) &&
2639 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2641 COMCTL32_Free(lpSubItem->pszText);
2644 /* free item */
2645 COMCTL32_Free(lpSubItem);
2649 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2650 if (lpItem != NULL)
2652 /* send LVN_DELETEITEM notification */
2653 nmlv.hdr.hwndFrom = hwnd;
2654 nmlv.hdr.idFrom = lCtrlId;
2655 nmlv.hdr.code = LVN_DELETEITEM;
2656 nmlv.iItem = nItem;
2657 nmlv.lParam = lpItem->lParam;
2658 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId,
2659 (LPARAM)&nmlv);
2661 /* free item string */
2662 if ((lpItem->pszText != NULL) &&
2663 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2665 COMCTL32_Free(lpItem->pszText);
2668 /* free item */
2669 COMCTL32_Free(lpItem);
2672 bResult = DPA_Destroy(hdpaSubItems);
2675 /* align items (set position of each item) */
2676 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2678 if (lStyle & LVS_ALIGNLEFT)
2680 LISTVIEW_AlignLeft(hwnd);
2682 else
2684 LISTVIEW_AlignTop(hwnd);
2688 /* If this item had focus change focus to next or previous item */
2689 if (GETITEMCOUNT(infoPtr) > 0)
2691 int sItem = nItem < GETITEMCOUNT(infoPtr) ? nItem : nItem - 1;
2692 if (infoPtr->nFocusedItem == nItem)
2693 LISTVIEW_SetItemFocus(hwnd, sItem);
2695 else
2696 infoPtr->nFocusedItem = -1;
2698 LISTVIEW_UpdateScroll(hwnd);
2700 /* refresh client area */
2701 InvalidateRect(hwnd, NULL, TRUE);
2704 return bResult;
2708 /***
2709 * DESCRIPTION:
2710 * Return edit control handle of current edit label
2712 * PARAMETER(S):
2713 * [I] HWND : window handle
2715 * RETURN:
2716 * SUCCESS : HWND
2717 * FAILURE : 0
2719 static LRESULT LISTVIEW_GetEditControl(hwnd)
2721 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2722 return infoPtr->hwndEdit;
2726 /***
2727 * DESCRIPTION:
2728 * Callback implementation for editlabel control
2730 * PARAMETER(S):
2731 * [I] HWND : window handle
2732 * [I] LPSTR : modified text
2733 * [I] DWORD : item index
2735 * RETURN:
2736 * SUCCESS : TRUE
2737 * FAILURE : FALSE
2740 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem)
2742 NMLVDISPINFOA dispInfo;
2743 LISTVIEW_ITEM *lpItem;
2744 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
2745 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2746 HDPA hdpaSubItems;
2748 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
2750 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
2751 return FALSE;
2753 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
2754 return FALSE;
2756 dispInfo.hdr.hwndFrom = hwnd;
2757 dispInfo.hdr.idFrom = nCtrlId;
2758 dispInfo.hdr.code = LVN_ENDLABELEDITA;
2759 dispInfo.item.mask = 0;
2760 dispInfo.item.iItem = nItem;
2761 dispInfo.item.state = lpItem->state;
2762 dispInfo.item.stateMask = 0;
2763 dispInfo.item.pszText = pszText;
2764 dispInfo.item.cchTextMax = pszText ? strlen(pszText) : 0;
2765 dispInfo.item.iImage = lpItem->iImage;
2766 dispInfo.item.lParam = lpItem->lParam;
2768 ListView_Notify(GetParent(hwnd), nCtrlId, &dispInfo);
2769 infoPtr->hwndEdit = 0;
2771 return TRUE;
2774 /***
2775 * DESCRIPTION:
2776 * Begin in place editing of specified list view item
2778 * PARAMETER(S):
2779 * [I] HWND : window handle
2780 * [I] INT : item index
2782 * RETURN:
2783 * SUCCESS : TRUE
2784 * FAILURE : FALSE
2787 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem)
2789 NMLVDISPINFOA dispInfo;
2790 RECT rect;
2791 LISTVIEW_ITEM *lpItem;
2792 HWND hedit;
2793 HINSTANCE hinst = GetWindowLongA(hwnd, GWL_HINSTANCE);
2794 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
2795 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2796 HDPA hdpaSubItems;
2798 if (~GetWindowLongA(hwnd, GWL_STYLE) & LVS_EDITLABELS)
2799 return FALSE;
2801 LISTVIEW_SetSelection(hwnd, nItem);
2802 LISTVIEW_SetItemFocus(hwnd, nItem);
2804 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
2805 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
2806 return 0;
2808 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
2809 return 0;
2811 dispInfo.hdr.hwndFrom = hwnd;
2812 dispInfo.hdr.idFrom = nCtrlId;
2813 dispInfo.hdr.code = LVN_BEGINLABELEDITA;
2814 dispInfo.item.mask = 0;
2815 dispInfo.item.iItem = nItem;
2816 dispInfo.item.state = lpItem->state;
2817 dispInfo.item.stateMask = 0;
2818 dispInfo.item.pszText = lpItem->pszText;
2819 dispInfo.item.cchTextMax = strlen(lpItem->pszText);
2820 dispInfo.item.iImage = lpItem->iImage;
2821 dispInfo.item.lParam = lpItem->lParam;
2823 if (ListView_LVNotify(GetParent(hwnd), nCtrlId, &dispInfo))
2824 return 0;
2826 rect.left = LVIR_LABEL;
2827 if (!LISTVIEW_GetItemRect(hwnd, nItem, &rect))
2828 return 0;
2830 if (!(hedit = CreateEditLabel(dispInfo.item.pszText , WS_VISIBLE,
2831 rect.left, rect.top, rect.right - rect.left + 15,
2832 rect.bottom - rect.top,
2833 hwnd, hinst, LISTVIEW_EndEditLabel, nItem)))
2834 return 0;
2836 infoPtr->hwndEdit = hedit;
2837 SetFocus(hedit);
2838 SendMessageA(hedit, EM_SETSEL, 0, -1);
2840 return hedit;
2844 /***
2845 * DESCRIPTION:
2846 * Ensures the specified item is visible, scrolling into view if necessary.
2848 * PARAMETER(S):
2849 * [I] HWND : window handle
2850 * [I] INT : item index
2851 * [I] BOOL : partially or entirely visible
2853 * RETURN:
2854 * SUCCESS : TRUE
2855 * FAILURE : FALSE
2857 static BOOL LISTVIEW_EnsureVisible(HWND hwnd, INT nItem, BOOL bPartial)
2859 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2860 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2861 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2862 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
2863 INT nScrollPosHeight = 0;
2864 INT nScrollPosWidth = 0;
2865 SCROLLINFO scrollInfo;
2866 RECT rcItem;
2868 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2869 scrollInfo.cbSize = sizeof(SCROLLINFO);
2870 scrollInfo.fMask = SIF_POS;
2872 /* ALWAYS bPartial == FALSE, FOR NOW! */
2874 rcItem.left = LVIR_BOUNDS;
2875 if (LISTVIEW_GetItemRect(hwnd, nItem, &rcItem) != FALSE)
2877 if (rcItem.left < infoPtr->rcList.left)
2879 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2881 /* scroll left */
2882 if (uView == LVS_LIST)
2884 nScrollPosWidth = infoPtr->nItemWidth;
2885 rcItem.left += infoPtr->rcList.left;
2887 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2889 nScrollPosWidth = max(1, nListWidth / LISTVIEW_SCROLL_DIV_SIZE);
2890 rcItem.left += infoPtr->rcList.left;
2893 if (rcItem.left % nScrollPosWidth == 0)
2895 scrollInfo.nPos += rcItem.left / nScrollPosWidth;
2897 else
2899 scrollInfo.nPos += rcItem.left / nScrollPosWidth - 1;
2902 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
2905 else if (rcItem.right > infoPtr->rcList.right)
2907 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2909 /* scroll right */
2910 if (uView == LVS_LIST)
2912 rcItem.right -= infoPtr->rcList.right;
2913 nScrollPosWidth = infoPtr->nItemWidth;
2915 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2917 rcItem.right -= infoPtr->rcList.right;
2918 nScrollPosWidth = max(1, nListWidth / LISTVIEW_SCROLL_DIV_SIZE);
2921 if (rcItem.right % nScrollPosWidth == 0)
2923 scrollInfo.nPos += rcItem.right / nScrollPosWidth;
2925 else
2927 scrollInfo.nPos += rcItem.right / nScrollPosWidth + 1;
2930 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
2934 if (rcItem.top < infoPtr->rcList.top)
2936 /* scroll up */
2937 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
2939 if (uView == LVS_REPORT)
2941 rcItem.top -= infoPtr->rcList.top;
2942 nScrollPosHeight = infoPtr->nItemHeight;
2944 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2946 nScrollPosHeight = max(1, nListHeight / LISTVIEW_SCROLL_DIV_SIZE);
2947 rcItem.top += infoPtr->rcList.top;
2950 if (rcItem.top % nScrollPosHeight == 0)
2952 scrollInfo.nPos += rcItem.top / nScrollPosHeight;
2954 else
2956 scrollInfo.nPos += rcItem.top / nScrollPosHeight - 1;
2959 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
2962 else if (rcItem.bottom > infoPtr->rcList.bottom)
2964 /* scroll down */
2965 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
2967 if (uView == LVS_REPORT)
2969 rcItem.bottom -= infoPtr->rcList.bottom;
2970 nScrollPosHeight = infoPtr->nItemHeight;
2972 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2974 nScrollPosHeight = max(1, nListHeight / LISTVIEW_SCROLL_DIV_SIZE);
2975 rcItem.bottom -= infoPtr->rcList.bottom;
2978 if (rcItem.bottom % nScrollPosHeight == 0)
2980 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight;
2982 else
2984 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight + 1;
2987 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
2992 return TRUE;
2995 /***
2996 * DESCRIPTION:
2997 * Retrieves the nearest item, given a position and a direction.
2999 * PARAMETER(S):
3000 * [I] HWND : window handle
3001 * [I] POINT : start position
3002 * [I] UINT : direction
3004 * RETURN:
3005 * Item index if successdful, -1 otherwise.
3007 static INT LISTVIEW_GetNearestItem(HWND hwnd, POINT pt, UINT vkDirection)
3009 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3010 LVHITTESTINFO lvHitTestInfo;
3011 INT nItem = -1;
3012 RECT rcView;
3014 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
3016 ZeroMemory(&lvHitTestInfo, sizeof(LVHITTESTINFO));
3017 LISTVIEW_GetOrigin(hwnd, &lvHitTestInfo.pt);
3018 lvHitTestInfo.pt.x += pt.x;
3019 lvHitTestInfo.pt.y += pt.y;
3023 if (vkDirection == VK_DOWN)
3025 lvHitTestInfo.pt.y += infoPtr->nItemHeight;
3027 else if (vkDirection == VK_UP)
3029 lvHitTestInfo.pt.y -= infoPtr->nItemHeight;
3031 else if (vkDirection == VK_LEFT)
3033 lvHitTestInfo.pt.x -= infoPtr->nItemWidth;
3035 else if (vkDirection == VK_RIGHT)
3037 lvHitTestInfo.pt.x += infoPtr->nItemWidth;
3040 if (PtInRect(&rcView, lvHitTestInfo.pt) == FALSE)
3042 return -1;
3044 else
3046 nItem = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo);
3050 while (nItem == -1);
3053 return nItem;
3056 /***
3057 * DESCRIPTION:
3058 * Searches for an item with specific characteristics.
3060 * PARAMETER(S):
3061 * [I] HWND : window handle
3062 * [I] INT : base item index
3063 * [I] LPLVFINDINFO : item information to look for
3065 * RETURN:
3066 * SUCCESS : index of item
3067 * FAILURE : -1
3069 static LRESULT LISTVIEW_FindItem(HWND hwnd, INT nStart,
3070 LPLVFINDINFO lpFindInfo)
3072 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3073 POINT ptItem;
3074 CHAR szDispText[DISP_TEXT_SIZE];
3075 LVITEMA lvItem;
3076 BOOL bWrap = FALSE;
3077 INT nItem = nStart;
3078 INT nLast = GETITEMCOUNT(infoPtr);
3080 if ((nItem >= -1) && (lpFindInfo != NULL))
3082 ZeroMemory(&lvItem, sizeof(LVITEMA));
3084 if (lpFindInfo->flags & LVFI_PARAM)
3086 lvItem.mask |= LVIF_PARAM;
3089 if (lpFindInfo->flags & LVFI_STRING)
3091 lvItem.mask |= LVIF_TEXT;
3092 lvItem.pszText = szDispText;
3093 lvItem.cchTextMax = DISP_TEXT_SIZE;
3096 if (lpFindInfo->flags & LVFI_PARTIAL)
3098 lvItem.mask |= LVIF_TEXT;
3099 lvItem.pszText = szDispText;
3100 lvItem.cchTextMax = DISP_TEXT_SIZE;
3103 if (lpFindInfo->flags & LVFI_WRAP)
3105 bWrap = TRUE;
3108 if (lpFindInfo->flags & LVFI_NEARESTXY)
3110 ptItem.x = lpFindInfo->pt.x;
3111 ptItem.y = lpFindInfo->pt.y;
3114 while (1)
3116 while (nItem < nLast)
3118 if (lpFindInfo->flags & LVFI_NEARESTXY)
3120 nItem = LISTVIEW_GetNearestItem(hwnd, ptItem,
3121 lpFindInfo->vkDirection);
3122 if (nItem != -1)
3124 /* get position of the new item index */
3125 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) == FALSE)
3126 return -1;
3128 else
3129 return -1;
3131 else
3133 nItem++;
3136 lvItem.iItem = nItem;
3137 lvItem.iSubItem = 0;
3138 if (ListView_GetItemA(hwnd, &lvItem) != FALSE)
3140 if (lvItem.mask & LVIF_TEXT)
3142 if (lpFindInfo->flags & LVFI_PARTIAL)
3144 if (strstr(lvItem.pszText, lpFindInfo->psz) == NULL)
3145 continue;
3147 else
3149 if (strcmp(lvItem.pszText, lpFindInfo->psz) != 0)
3150 continue;
3154 if (lvItem.mask & LVIF_PARAM)
3156 if (lpFindInfo->lParam != lvItem.lParam)
3157 continue;
3160 return nItem;
3164 if (bWrap != FALSE)
3166 nItem = -1;
3167 nLast = nStart + 1;
3168 bWrap = FALSE;
3170 else
3172 return -1;
3177 return -1;
3180 /***
3181 * DESCRIPTION:
3182 * Retrieves the background color of the listview control.
3184 * PARAMETER(S):
3185 * [I] HWND : window handle
3187 * RETURN:
3188 * COLORREF associated with the background.
3190 static LRESULT LISTVIEW_GetBkColor(HWND hwnd)
3192 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3194 return infoPtr->clrBk;
3197 /***
3198 * DESCRIPTION:
3199 * Retrieves the background image of the listview control.
3201 * PARAMETER(S):
3202 * [I] HWND : window handle
3203 * [O] LPLVMKBIMAGE : background image attributes
3205 * RETURN:
3206 * SUCCESS : TRUE
3207 * FAILURE : FALSE`
3209 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
3210 /* { */
3211 /* FIXME (listview, "empty stub!\n"); */
3212 /* return FALSE; */
3213 /* } */
3215 /***
3216 * DESCRIPTION:
3217 * Retrieves the callback mask.
3219 * PARAMETER(S):
3220 * [I] HWND : window handle
3222 * RETURN:
3223 * Value of mask
3225 static UINT LISTVIEW_GetCallbackMask(HWND hwnd)
3227 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3229 return infoPtr->uCallbackMask;
3232 /***
3233 * DESCRIPTION:
3234 * Retrieves column attributes.
3236 * PARAMETER(S):
3237 * [I] HWND : window handle
3238 * [I] INT : column index
3239 * [IO] LPLVCOLUMNA : column information
3241 * RETURN:
3242 * SUCCESS : TRUE
3243 * FAILURE : FALSE
3245 static LRESULT LISTVIEW_GetColumnA(HWND hwnd, INT nItem, LPLVCOLUMNA lpColumn)
3247 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3248 HDITEMA hdi;
3249 BOOL bResult = FALSE;
3251 if (lpColumn != NULL)
3253 /* initialize memory */
3254 ZeroMemory(&hdi, sizeof(HDITEMA));
3256 if (lpColumn->mask & LVCF_FMT)
3258 hdi.mask |= HDI_FORMAT;
3261 if (lpColumn->mask & LVCF_WIDTH)
3263 hdi.mask |= HDI_WIDTH;
3266 if (lpColumn->mask & LVCF_TEXT)
3268 hdi.mask |= (HDI_TEXT | HDI_FORMAT);
3271 if (lpColumn->mask & LVCF_IMAGE)
3273 hdi.mask |= HDI_IMAGE;
3276 if (lpColumn->mask & LVCF_ORDER)
3278 hdi.mask |= HDI_ORDER;
3281 bResult = Header_GetItemA(infoPtr->hwndHeader, nItem, &hdi);
3282 if (bResult != FALSE)
3284 if (lpColumn->mask & LVCF_FMT)
3286 lpColumn->fmt = 0;
3288 if (hdi.fmt & HDF_LEFT)
3290 lpColumn->fmt |= LVCFMT_LEFT;
3292 else if (hdi.fmt & HDF_RIGHT)
3294 lpColumn->fmt |= LVCFMT_RIGHT;
3296 else if (hdi.fmt & HDF_CENTER)
3298 lpColumn->fmt |= LVCFMT_CENTER;
3301 if (hdi.fmt & HDF_IMAGE)
3303 lpColumn->fmt |= LVCFMT_COL_HAS_IMAGES;
3306 if (hdi.fmt & HDF_BITMAP_ON_RIGHT)
3308 lpColumn->fmt |= LVCFMT_BITMAP_ON_RIGHT;
3312 if (lpColumn->mask & LVCF_WIDTH)
3314 lpColumn->cx = hdi.cxy;
3317 if ((lpColumn->mask & LVCF_TEXT) && (lpColumn->pszText) && (hdi.pszText))
3319 lstrcpynA (lpColumn->pszText, hdi.pszText, lpColumn->cchTextMax);
3322 if (lpColumn->mask & LVCF_IMAGE)
3324 lpColumn->iImage = hdi.iImage;
3327 if (lpColumn->mask & LVCF_ORDER)
3329 lpColumn->iOrder = hdi.iOrder;
3334 return bResult;
3337 /* LISTVIEW_GetColumnW */
3338 /* LISTVIEW_GetColumnOrderArray */
3340 /***
3341 * DESCRIPTION:
3342 * Retrieves the column width.
3344 * PARAMETER(S):
3345 * [I] HWND : window handle
3346 * [I] int : column index
3348 * RETURN:
3349 * SUCCESS : column width
3350 * FAILURE : zero
3352 static LRESULT LISTVIEW_GetColumnWidth(HWND hwnd, INT nColumn)
3354 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3355 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3356 INT nColumnWidth = 0;
3357 HDITEMA hdi;
3359 if (uView == LVS_LIST)
3361 nColumnWidth = infoPtr->nItemWidth;
3363 else if (uView == LVS_REPORT)
3365 /* get column width from header */
3366 ZeroMemory(&hdi, sizeof(HDITEMA));
3367 hdi.mask = HDI_WIDTH;
3368 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdi) != FALSE)
3370 nColumnWidth = hdi.cxy;
3374 return nColumnWidth;
3377 /***
3378 * DESCRIPTION:
3379 * In list or report display mode, retrieves the number of items that can fit
3380 * vertically in the visible area. In icon or small icon display mode,
3381 * retrieves the total number of visible items.
3383 * PARAMETER(S):
3384 * [I] HWND : window handle
3386 * RETURN:
3387 * Number of fully visible items.
3389 static LRESULT LISTVIEW_GetCountPerPage(HWND hwnd)
3391 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3392 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3393 INT nItemCount = 0;
3395 if (uView == LVS_LIST)
3397 if (infoPtr->rcList.right > infoPtr->nItemWidth)
3399 nItemCount = LISTVIEW_GetCountPerRow(hwnd) *
3400 LISTVIEW_GetCountPerColumn(hwnd);
3403 else if (uView == LVS_REPORT)
3405 nItemCount = LISTVIEW_GetCountPerColumn(hwnd);
3407 else
3409 nItemCount = GETITEMCOUNT(infoPtr);
3412 return nItemCount;
3415 /* LISTVIEW_GetEditControl */
3417 /***
3418 * DESCRIPTION:
3419 * Retrieves the extended listview style.
3421 * PARAMETERS:
3422 * [I] HWND : window handle
3424 * RETURN:
3425 * SUCCESS : previous style
3426 * FAILURE : 0
3428 static LRESULT LISTVIEW_GetExtendedListViewStyle(HWND hwnd)
3430 LISTVIEW_INFO *infoPtr;
3432 /* make sure we can get the listview info */
3433 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
3434 return (0);
3436 return (infoPtr->dwExStyle);
3439 /***
3440 * DESCRIPTION:
3441 * Retrieves the handle to the header control.
3443 * PARAMETER(S):
3444 * [I] HWND : window handle
3446 * RETURN:
3447 * Header handle.
3449 static LRESULT LISTVIEW_GetHeader(HWND hwnd)
3451 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3453 return infoPtr->hwndHeader;
3456 /* LISTVIEW_GetHotCursor */
3457 /* LISTVIEW_GetHotItem */
3458 /* LISTVIEW_GetHoverTime */
3460 /***
3461 * DESCRIPTION:
3462 * Retrieves an image list handle.
3464 * PARAMETER(S):
3465 * [I] HWND : window handle
3466 * [I] INT : image list identifier
3468 * RETURN:
3469 * SUCCESS : image list handle
3470 * FAILURE : NULL
3472 static LRESULT LISTVIEW_GetImageList(HWND hwnd, INT nImageList)
3474 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3475 HIMAGELIST himl = NULL;
3477 switch (nImageList)
3479 case LVSIL_NORMAL:
3480 himl = infoPtr->himlNormal;
3481 break;
3482 case LVSIL_SMALL:
3483 himl = infoPtr->himlSmall;
3484 break;
3485 case LVSIL_STATE:
3486 himl = infoPtr->himlState;
3487 break;
3490 return (LRESULT)himl;
3493 /* LISTVIEW_GetISearchString */
3495 /***
3496 * DESCRIPTION:
3497 * Retrieves item attributes.
3499 * PARAMETER(S):
3500 * [I] HWND : window handle
3501 * [IO] LPLVITEMA : item info
3503 * RETURN:
3504 * SUCCESS : TRUE
3505 * FAILURE : FALSE
3507 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem)
3509 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3510 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
3511 BOOL bResult = FALSE;
3512 NMLVDISPINFOA dispInfo;
3513 LISTVIEW_SUBITEM *lpSubItem;
3514 LISTVIEW_ITEM *lpItem;
3515 HDPA hdpaSubItems;
3517 TRACE("(hwnd=%x, lpLVItem=%p)\n", hwnd, lpLVItem);
3519 if (lpLVItem != NULL)
3521 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
3523 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
3524 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
3525 if (hdpaSubItems != NULL)
3527 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3528 if (lpItem != NULL)
3530 bResult = TRUE;
3531 if (lpLVItem->iSubItem == 0)
3533 if ((lpItem->iImage == I_IMAGECALLBACK) &&
3534 (lpLVItem->mask & LVIF_IMAGE))
3536 dispInfo.item.mask |= LVIF_IMAGE;
3539 if ((lpItem->pszText == LPSTR_TEXTCALLBACKA) &&
3540 (lpLVItem->mask & LVIF_TEXT))
3542 dispInfo.item.mask |= LVIF_TEXT;
3543 ZeroMemory(lpLVItem->pszText, sizeof(CHAR)*lpLVItem->cchTextMax);
3544 dispInfo.item.pszText = lpLVItem->pszText;
3545 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
3548 if ((infoPtr->uCallbackMask != 0) && (lpLVItem->mask & LVIF_STATE))
3550 dispInfo.item.mask |= LVIF_STATE;
3551 dispInfo.item.stateMask = infoPtr->uCallbackMask;
3554 if (dispInfo.item.mask != 0)
3556 dispInfo.hdr.hwndFrom = hwnd;
3557 dispInfo.hdr.idFrom = lCtrlId;
3558 dispInfo.hdr.code = LVN_GETDISPINFOA;
3559 dispInfo.item.iItem = lpLVItem->iItem;
3560 dispInfo.item.iSubItem = 0;
3561 dispInfo.item.lParam = lpItem->lParam;
3562 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
3565 if (dispInfo.item.mask & LVIF_IMAGE)
3567 lpLVItem->iImage = dispInfo.item.iImage;
3569 else if (lpLVItem->mask & LVIF_IMAGE)
3571 lpLVItem->iImage = lpItem->iImage;
3574 if (dispInfo.item.mask & LVIF_TEXT)
3576 if (dispInfo.item.mask & LVIF_DI_SETITEM)
3578 Str_SetPtrA(&lpItem->pszText, dispInfo.item.pszText);
3580 strncpy(lpLVItem->pszText, dispInfo.item.pszText, lpLVItem->cchTextMax);
3582 else if (lpLVItem->mask & LVIF_TEXT)
3584 strncpy(lpLVItem->pszText, lpItem->pszText, lpLVItem->cchTextMax);
3587 if (dispInfo.item.mask & LVIF_STATE)
3589 lpLVItem->state = lpItem->state;
3590 lpLVItem->state &= ~dispInfo.item.stateMask;
3591 lpLVItem->state |= (dispInfo.item.state &
3592 dispInfo.item.stateMask);
3594 else if (lpLVItem->mask & LVIF_STATE)
3596 lpLVItem->state = lpItem->state & lpLVItem->stateMask;
3599 if (lpLVItem->mask & LVIF_PARAM)
3601 lpLVItem->lParam = lpItem->lParam;
3604 if (lpLVItem->mask & LVIF_INDENT)
3606 lpLVItem->iIndent = lpItem->iIndent;
3609 else
3611 lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems,
3612 lpLVItem->iSubItem);
3613 if (lpSubItem != NULL)
3615 if ((lpSubItem->iImage == I_IMAGECALLBACK) &&
3616 (lpLVItem->mask & LVIF_IMAGE))
3618 dispInfo.item.mask |= LVIF_IMAGE;
3621 if ((lpSubItem->pszText == LPSTR_TEXTCALLBACKA) &&
3622 (lpLVItem->mask & LVIF_TEXT))
3624 dispInfo.item.mask |= LVIF_TEXT;
3625 ZeroMemory(lpLVItem->pszText,
3626 sizeof(CHAR)*lpLVItem->cchTextMax);
3627 dispInfo.item.pszText = lpLVItem->pszText;
3628 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
3631 else
3633 if (lpLVItem->mask & LVIF_IMAGE)
3635 dispInfo.item.mask |= LVIF_IMAGE;
3638 if (lpLVItem->mask & LVIF_TEXT)
3640 dispInfo.item.mask |= LVIF_TEXT;
3641 ZeroMemory(lpLVItem->pszText,
3642 sizeof(CHAR)*lpLVItem->cchTextMax);
3643 dispInfo.item.pszText = lpLVItem->pszText;
3644 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
3648 if (dispInfo.item.mask != 0)
3650 dispInfo.hdr.hwndFrom = hwnd;
3651 dispInfo.hdr.idFrom = lCtrlId;
3652 dispInfo.hdr.code = LVN_GETDISPINFOA;
3653 dispInfo.item.iItem = lpLVItem->iItem;
3654 dispInfo.item.iSubItem = lpLVItem->iSubItem;
3655 dispInfo.item.lParam = lpItem->lParam;
3656 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
3659 if (dispInfo.item.mask & LVIF_IMAGE)
3661 lpLVItem->iImage = dispInfo.item.iImage;
3663 else if (lpLVItem->mask & LVIF_IMAGE)
3665 lpLVItem->iImage = lpItem->iImage;
3668 if (dispInfo.item.mask & LVIF_TEXT)
3670 if (dispInfo.item.mask & LVIF_DI_SETITEM)
3672 if (lpSubItem)
3673 Str_SetPtrA(&lpSubItem->pszText, dispInfo.item.pszText);
3675 strncpy(lpLVItem->pszText, dispInfo.item.pszText, lpLVItem->cchTextMax);
3677 else if (lpLVItem->mask & LVIF_TEXT)
3679 strncpy(lpLVItem->pszText, lpSubItem->pszText, lpLVItem->cchTextMax);
3687 return bResult;
3690 /* LISTVIEW_GetItemW */
3691 /* LISTVIEW_GetHotCursor */
3693 /***
3694 * DESCRIPTION:
3695 * Retrieves the index of the hot item.
3697 * PARAMETERS:
3698 * [I] HWND : window handle
3700 * RETURN:
3701 * SUCCESS : hot item index
3702 * FAILURE : -1 (no hot item)
3704 static LRESULT LISTVIEW_GetHotItem(HWND hwnd)
3706 LISTVIEW_INFO *infoPtr;
3708 /* make sure we can get the listview info */
3709 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
3710 return (-1);
3712 return (infoPtr->nHotItem);
3715 /* LISTVIEW_GetHoverTime */
3717 /***
3718 * DESCRIPTION:
3719 * Retrieves the number of items in the listview control.
3721 * PARAMETER(S):
3722 * [I] HWND : window handle
3724 * RETURN:
3725 * Number of items.
3727 static LRESULT LISTVIEW_GetItemCount(HWND hwnd)
3729 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3731 return GETITEMCOUNT(infoPtr);
3734 /***
3735 * DESCRIPTION:
3736 * Retrieves the position (upper-left) of the listview control item.
3738 * PARAMETER(S):
3739 * [I] HWND : window handle
3740 * [I] INT : item index
3741 * [O] LPPOINT : coordinate information
3743 * RETURN:
3744 * SUCCESS : TRUE
3745 * FAILURE : FALSE
3747 static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem,
3748 LPPOINT lpptPosition)
3750 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3751 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3752 BOOL bResult = FALSE;
3753 HDPA hdpaSubItems;
3754 LISTVIEW_ITEM *lpItem;
3755 INT nCountPerColumn;
3756 INT nRow;
3758 TRACE("(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd, nItem,
3759 lpptPosition);
3761 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
3762 (lpptPosition != NULL))
3764 if (uView == LVS_LIST)
3766 bResult = TRUE;
3767 nItem = nItem - ListView_GetTopIndex(hwnd);
3768 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
3769 if (nItem < 0)
3771 nRow = nItem % nCountPerColumn;
3772 if (nRow == 0)
3774 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
3775 lpptPosition->y = 0;
3777 else
3779 lpptPosition->x = (nItem / nCountPerColumn -1) * infoPtr->nItemWidth;
3780 lpptPosition->y = (nRow + nCountPerColumn) * infoPtr->nItemHeight;
3783 else
3785 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
3786 lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight;
3789 else if (uView == LVS_REPORT)
3791 bResult = TRUE;
3792 lpptPosition->x = REPORT_MARGINX;
3793 lpptPosition->y = ((nItem - ListView_GetTopIndex(hwnd)) *
3794 infoPtr->nItemHeight) + infoPtr->rcList.top;
3796 else
3798 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
3799 if (hdpaSubItems != NULL)
3801 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3802 if (lpItem != NULL)
3804 bResult = TRUE;
3805 lpptPosition->x = lpItem->ptPosition.x;
3806 lpptPosition->y = lpItem->ptPosition.y;
3812 return bResult;
3815 /***
3816 * DESCRIPTION:
3817 * Retrieves the bounding rectangle for a listview control item.
3819 * PARAMETER(S):
3820 * [I] HWND : window handle
3821 * [I] INT : item index
3822 * [IO] LPRECT : bounding rectangle coordinates
3824 * RETURN:
3825 * SUCCESS : TRUE
3826 * FAILURE : FALSE
3828 static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc)
3830 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3831 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3832 BOOL bResult = FALSE;
3833 POINT ptOrigin;
3834 POINT ptItem;
3835 HDC hdc;
3836 HFONT hOldFont;
3837 INT nLeftPos;
3838 INT nLabelWidth;
3839 TEXTMETRICA tm;
3841 TRACE("(hwnd=%x, nItem=%d, lprc=%p)\n", hwnd, nItem, lprc);
3843 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL))
3845 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) != FALSE)
3847 switch(lprc->left)
3849 case LVIR_ICON:
3850 if (uView == LVS_ICON)
3852 if (infoPtr->himlNormal != NULL)
3854 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3856 bResult = TRUE;
3857 lprc->left = ptItem.x + ptOrigin.x;
3858 lprc->top = ptItem.y + ptOrigin.y;
3859 lprc->right = lprc->left + infoPtr->iconSize.cx;
3860 lprc->bottom = (lprc->top + infoPtr->iconSize.cy +
3861 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
3865 else if (uView == LVS_SMALLICON)
3867 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3869 bResult = TRUE;
3870 lprc->left = ptItem.x + ptOrigin.x;
3871 lprc->top = ptItem.y + ptOrigin.y;
3872 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3874 if (infoPtr->himlState != NULL)
3875 lprc->left += infoPtr->iconSize.cx;
3877 if (infoPtr->himlSmall != NULL)
3878 lprc->right = lprc->left + infoPtr->iconSize.cx;
3879 else
3880 lprc->right = lprc->left;
3883 else
3885 bResult = TRUE;
3886 lprc->left = ptItem.x;
3887 lprc->top = ptItem.y;
3888 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3890 if (infoPtr->himlState != NULL)
3892 lprc->left += infoPtr->iconSize.cx;
3895 if (infoPtr->himlSmall != NULL)
3897 lprc->right = lprc->left + infoPtr->iconSize.cx;
3899 else
3901 lprc->right = lprc->left;
3904 break;
3906 case LVIR_LABEL:
3907 if (uView == LVS_ICON)
3909 if (infoPtr->himlNormal != NULL)
3911 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3913 bResult = TRUE;
3914 lprc->left = ptItem.x + ptOrigin.x;
3915 lprc->top = (ptItem.y + ptOrigin.y + infoPtr->iconSize.cy +
3916 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
3917 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3918 if (infoPtr->iconSpacing.cx - nLabelWidth > 1)
3920 lprc->left += (infoPtr->iconSpacing.cx - nLabelWidth) / 2;
3921 lprc->right = lprc->left + nLabelWidth;
3923 else
3925 lprc->left += 1;
3926 lprc->right = lprc->left + infoPtr->iconSpacing.cx - 1;
3929 hdc = GetDC(hwnd);
3930 hOldFont = SelectObject(hdc, infoPtr->hFont);
3931 GetTextMetricsA(hdc, &tm);
3932 lprc->bottom = lprc->top + tm.tmHeight + HEIGHT_PADDING;
3933 SelectObject(hdc, hOldFont);
3934 ReleaseDC(hwnd, hdc);
3938 else if (uView == LVS_SMALLICON)
3940 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3942 bResult = TRUE;
3943 nLeftPos = lprc->left = ptItem.x + ptOrigin.x;
3944 lprc->top = ptItem.y + ptOrigin.y;
3945 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3947 if (infoPtr->himlState != NULL)
3949 lprc->left += infoPtr->iconSize.cx;
3952 if (infoPtr->himlSmall != NULL)
3954 lprc->left += infoPtr->iconSize.cx;
3957 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3958 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
3960 lprc->right = lprc->left + nLabelWidth;
3962 else
3964 lprc->right = nLeftPos + infoPtr->nItemWidth;
3968 else
3970 bResult = TRUE;
3971 nLeftPos = lprc->left = ptItem.x;
3972 lprc->top = ptItem.y;
3973 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3975 if (infoPtr->himlState != NULL)
3977 lprc->left += infoPtr->iconSize.cx;
3980 if (infoPtr->himlSmall != NULL)
3982 lprc->left += infoPtr->iconSize.cx;
3985 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3986 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
3988 lprc->right = lprc->left + nLabelWidth;
3990 else
3992 lprc->right = nLeftPos + infoPtr->nItemWidth;
3995 break;
3997 case LVIR_BOUNDS:
3998 if (uView == LVS_ICON)
4000 if (infoPtr->himlNormal != NULL)
4002 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4004 bResult = TRUE;
4005 lprc->left = ptItem.x + ptOrigin.x;
4006 lprc->top = ptItem.y + ptOrigin.y;
4007 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
4008 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
4012 else if (uView == LVS_SMALLICON)
4014 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4016 bResult = TRUE;
4017 lprc->left = ptItem.x + ptOrigin.x;
4018 lprc->right = lprc->left;
4019 lprc->top = ptItem.y + ptOrigin.y;
4020 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4021 if (infoPtr->himlState != NULL)
4022 lprc->right += infoPtr->iconSize.cx;
4023 if (infoPtr->himlSmall != NULL)
4024 lprc->right += infoPtr->iconSize.cx;
4026 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4027 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
4029 lprc->right += nLabelWidth;
4031 else
4033 lprc->right = lprc->left + infoPtr->nItemWidth;
4037 else
4039 bResult = TRUE;
4040 lprc->left = ptItem.x;
4041 lprc->right = lprc->left;
4042 lprc->top = ptItem.y;
4043 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4045 if (infoPtr->himlState != NULL)
4047 lprc->right += infoPtr->iconSize.cx;
4050 if (infoPtr->himlSmall != NULL)
4052 lprc->right += infoPtr->iconSize.cx;
4055 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4056 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
4058 lprc->right += nLabelWidth;
4060 else
4062 lprc->right = lprc->left + infoPtr->nItemWidth;
4065 break;
4067 case LVIR_SELECTBOUNDS:
4068 if (uView == LVS_ICON)
4070 if (infoPtr->himlNormal != NULL)
4072 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4074 bResult = TRUE;
4075 lprc->left = ptItem.x + ptOrigin.x;
4076 lprc->top = ptItem.y + ptOrigin.y;
4077 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
4078 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
4082 else if (uView == LVS_SMALLICON)
4084 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4086 bResult = TRUE;
4087 nLeftPos= lprc->left = ptItem.x + ptOrigin.x;
4088 lprc->top = ptItem.y + ptOrigin.y;
4089 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4091 if (infoPtr->himlState != NULL)
4093 lprc->left += infoPtr->iconSize.cx;
4096 lprc->right = lprc->left;
4098 if (infoPtr->himlSmall != NULL)
4100 lprc->right += infoPtr->iconSize.cx;
4103 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4104 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4106 lprc->right += nLabelWidth;
4108 else
4110 lprc->right = nLeftPos + infoPtr->nItemWidth;
4114 else
4116 bResult = TRUE;
4117 nLeftPos = lprc->left = ptItem.x;
4118 lprc->top = ptItem.y;
4119 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4121 if (infoPtr->himlState != NULL)
4123 lprc->left += infoPtr->iconSize.cx;
4126 lprc->right = lprc->left;
4128 if (infoPtr->himlSmall != NULL)
4130 lprc->right += infoPtr->iconSize.cx;
4133 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4134 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4136 lprc->right += nLabelWidth;
4138 else
4140 lprc->right = nLeftPos + infoPtr->nItemWidth;
4143 break;
4148 return bResult;
4151 /***
4152 * DESCRIPTION:
4153 * Retrieves the width of a label.
4155 * PARAMETER(S):
4156 * [I] HWND : window handle
4158 * RETURN:
4159 * SUCCESS : string width (in pixels)
4160 * FAILURE : zero
4162 static INT LISTVIEW_GetLabelWidth(HWND hwnd, INT nItem)
4164 CHAR szDispText[DISP_TEXT_SIZE];
4165 INT nLabelWidth = 0;
4166 LVITEMA lvItem;
4168 TRACE("(hwnd=%x, nItem=%d)\n", hwnd, nItem);
4170 ZeroMemory(&lvItem, sizeof(LVITEMA));
4171 lvItem.mask = LVIF_TEXT;
4172 lvItem.iItem = nItem;
4173 lvItem.cchTextMax = DISP_TEXT_SIZE;
4174 lvItem.pszText = szDispText;
4175 if (ListView_GetItemA(hwnd, &lvItem) != FALSE)
4177 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
4180 return nLabelWidth;
4183 /***
4184 * DESCRIPTION:
4185 * Retrieves the spacing between listview control items.
4187 * PARAMETER(S):
4188 * [I] HWND : window handle
4189 * [I] BOOL : flag for small or large icon
4191 * RETURN:
4192 * Horizontal + vertical spacing
4194 static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall)
4196 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4197 LONG lResult;
4199 if (bSmall == FALSE)
4201 lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
4203 else
4205 /* TODO: need to store width of smallicon item */
4206 lResult = MAKELONG(0, infoPtr->nItemHeight);
4209 return lResult;
4212 /***
4213 * DESCRIPTION:
4214 * Retrieves the state of a listview control item.
4216 * PARAMETER(S):
4217 * [I] HWND : window handle
4218 * [I] INT : item index
4219 * [I] UINT : state mask
4221 * RETURN:
4222 * State specified by the mask.
4224 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask)
4226 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4227 LVITEMA lvItem;
4228 UINT uState = 0;
4230 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4232 ZeroMemory(&lvItem, sizeof(LVITEMA));
4233 lvItem.iItem = nItem;
4234 lvItem.stateMask = uMask;
4235 lvItem.mask = LVIF_STATE;
4236 if (ListView_GetItemA(hwnd, &lvItem) != FALSE)
4238 uState = lvItem.state;
4242 return uState;
4245 /***
4246 * DESCRIPTION:
4247 * Retrieves the text of a listview control item or subitem.
4249 * PARAMETER(S):
4250 * [I] HWND : window handle
4251 * [I] INT : item index
4252 * [IO] LPLVITEMA : item information
4254 * RETURN:
4255 * SUCCESS : string length
4256 * FAILURE : 0
4258 static LRESULT LISTVIEW_GetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
4260 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4261 INT nLength = 0;
4263 if (lpLVItem != NULL)
4265 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4267 lpLVItem->mask = LVIF_TEXT;
4268 lpLVItem->iItem = nItem;
4269 if (ListView_GetItemA(hwnd, lpLVItem) != FALSE)
4271 nLength = lstrlenA(lpLVItem->pszText);
4276 return nLength;
4279 /***
4280 * DESCRIPTION:
4281 * Searches for an item based on properties + relationships.
4283 * PARAMETER(S):
4284 * [I] HWND : window handle
4285 * [I] INT : item index
4286 * [I] INT : relationship flag
4288 * RETURN:
4289 * SUCCESS : item index
4290 * FAILURE : -1
4292 static LRESULT LISTVIEW_GetNextItem(HWND hwnd, INT nItem, UINT uFlags)
4294 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4295 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4296 UINT uMask = 0;
4297 LVFINDINFO lvFindInfo;
4298 INT nCountPerColumn;
4299 INT i;
4301 if ((nItem >= -1) && (nItem < GETITEMCOUNT(infoPtr)))
4303 ZeroMemory(&lvFindInfo, sizeof(LVFINDINFO));
4305 if (uFlags & LVNI_CUT)
4306 uMask |= LVIS_CUT;
4308 if (uFlags & LVNI_DROPHILITED)
4309 uMask |= LVIS_DROPHILITED;
4311 if (uFlags & LVNI_FOCUSED)
4312 uMask |= LVIS_FOCUSED;
4314 if (uFlags & LVNI_SELECTED)
4315 uMask |= LVIS_SELECTED;
4317 if (uFlags & LVNI_ABOVE)
4319 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
4321 while (nItem >= 0)
4323 nItem--;
4324 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4325 return nItem;
4328 else
4330 lvFindInfo.flags = LVFI_NEARESTXY;
4331 lvFindInfo.vkDirection = VK_UP;
4332 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4333 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4335 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4336 return nItem;
4340 else if (uFlags & LVNI_BELOW)
4342 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
4344 while (nItem < GETITEMCOUNT(infoPtr))
4346 nItem++;
4347 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4348 return nItem;
4351 else
4353 lvFindInfo.flags = LVFI_NEARESTXY;
4354 lvFindInfo.vkDirection = VK_DOWN;
4355 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4356 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4358 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4359 return nItem;
4363 else if (uFlags & LVNI_TOLEFT)
4365 if (uView == LVS_LIST)
4367 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
4368 while (nItem - nCountPerColumn >= 0)
4370 nItem -= nCountPerColumn;
4371 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4372 return nItem;
4375 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4377 lvFindInfo.flags = LVFI_NEARESTXY;
4378 lvFindInfo.vkDirection = VK_LEFT;
4379 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4380 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4382 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4383 return nItem;
4387 else if (uFlags & LVNI_TORIGHT)
4389 if (uView == LVS_LIST)
4391 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
4392 while (nItem + nCountPerColumn < GETITEMCOUNT(infoPtr))
4394 nItem += nCountPerColumn;
4395 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4396 return nItem;
4399 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4401 lvFindInfo.flags = LVFI_NEARESTXY;
4402 lvFindInfo.vkDirection = VK_RIGHT;
4403 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4404 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4406 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4407 return nItem;
4411 else
4413 nItem++;
4415 /* search by index */
4416 for (i = nItem; i < GETITEMCOUNT(infoPtr); i++)
4418 if ((ListView_GetItemState(hwnd, i, uMask) & uMask) == uMask)
4419 return i;
4424 return -1;
4427 /* LISTVIEW_GetNumberOfWorkAreas */
4429 /***
4430 * DESCRIPTION:
4431 * Retrieves the origin coordinates when in icon or small icon display mode.
4433 * PARAMETER(S):
4434 * [I] HWND : window handle
4435 * [O] LPPOINT : coordinate information
4437 * RETURN:
4438 * SUCCESS : TRUE
4439 * FAILURE : FALSE
4441 static LRESULT LISTVIEW_GetOrigin(HWND hwnd, LPPOINT lpptOrigin)
4443 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4444 UINT uView = lStyle & LVS_TYPEMASK;
4445 BOOL bResult = FALSE;
4447 TRACE("(hwnd=%x, lpptOrigin=%p)\n", hwnd, lpptOrigin);
4449 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4451 SCROLLINFO scrollInfo;
4452 ZeroMemory(lpptOrigin, sizeof(POINT));
4453 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
4454 scrollInfo.cbSize = sizeof(SCROLLINFO);
4456 if (lStyle & WS_HSCROLL)
4458 scrollInfo.fMask = SIF_POS;
4459 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4461 lpptOrigin->x = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
4465 if (lStyle & WS_VSCROLL)
4467 scrollInfo.fMask = SIF_POS;
4468 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4470 lpptOrigin->y = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
4474 bResult = TRUE;
4477 return bResult;
4480 /***
4481 * DESCRIPTION:
4482 * Retrieves the number of items that are marked as selected.
4484 * PARAMETER(S):
4485 * [I] HWND : window handle
4487 * RETURN:
4488 * Number of items selected.
4490 static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd)
4492 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4493 INT nSelectedCount = 0;
4494 INT i;
4496 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4498 if (ListView_GetItemState(hwnd, i, LVIS_SELECTED) & LVIS_SELECTED)
4500 nSelectedCount++;
4504 return nSelectedCount;
4507 /***
4508 * DESCRIPTION:
4509 * Retrieves item index that marks the start of a multiple selection.
4511 * PARAMETER(S):
4512 * [I] HWND : window handle
4514 * RETURN:
4515 * Index number or -1 if there is no selection mark.
4517 static LRESULT LISTVIEW_GetSelectionMark(HWND hwnd)
4519 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4521 return infoPtr->nSelectionMark;
4524 /***
4525 * DESCRIPTION:
4526 * Retrieves the width of a string.
4528 * PARAMETER(S):
4529 * [I] HWND : window handle
4531 * RETURN:
4532 * SUCCESS : string width (in pixels)
4533 * FAILURE : zero
4535 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText)
4537 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4538 HFONT hFont, hOldFont;
4539 SIZE stringSize;
4540 HDC hdc;
4542 ZeroMemory(&stringSize, sizeof(SIZE));
4543 if (lpszText != NULL)
4545 hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
4546 hdc = GetDC(hwnd);
4547 hOldFont = SelectObject(hdc, hFont);
4548 GetTextExtentPointA(hdc, lpszText, lstrlenA(lpszText), &stringSize);
4549 SelectObject(hdc, hOldFont);
4550 ReleaseDC(hwnd, hdc);
4553 return stringSize.cx;
4556 /***
4557 * DESCRIPTION:
4558 * Retrieves the text backgound color.
4560 * PARAMETER(S):
4561 * [I] HWND : window handle
4563 * RETURN:
4564 * COLORREF associated with the the background.
4566 static LRESULT LISTVIEW_GetTextBkColor(HWND hwnd)
4568 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4570 return infoPtr->clrTextBk;
4573 /***
4574 * DESCRIPTION:
4575 * Retrieves the text color.
4577 * PARAMETER(S):
4578 * [I] HWND : window handle
4580 * RETURN:
4581 * COLORREF associated with the text.
4583 static LRESULT LISTVIEW_GetTextColor(HWND hwnd)
4585 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4587 return infoPtr->clrText;
4590 /***
4591 * DESCRIPTION:
4592 * Determines which section of the item was selected (if any).
4594 * PARAMETER(S):
4595 * [I] HWND : window handle
4596 * [IO] LPLVHITTESTINFO : hit test information
4598 * RETURN:
4599 * SUCCESS : item index
4600 * FAILURE : -1
4602 static INT LISTVIEW_HitTestItem(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4604 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4605 RECT rcItem;
4606 INT i;
4608 TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpHitTestInfo->pt.x,
4609 lpHitTestInfo->pt.y);
4611 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4613 rcItem.left = LVIR_BOUNDS;
4614 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4616 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4618 rcItem.left = LVIR_ICON;
4619 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4621 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4623 lpHitTestInfo->flags = LVHT_ONITEMICON;
4624 lpHitTestInfo->iItem = i;
4625 lpHitTestInfo->iSubItem = 0;
4626 return i;
4630 rcItem.left = LVIR_LABEL;
4631 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4633 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4635 lpHitTestInfo->flags = LVHT_ONITEMLABEL;
4636 lpHitTestInfo->iItem = i;
4637 lpHitTestInfo->iSubItem = 0;
4638 return i;
4642 lpHitTestInfo->flags = LVHT_ONITEMSTATEICON;
4643 lpHitTestInfo->iItem = i;
4644 lpHitTestInfo->iSubItem = 0;
4645 return i;
4650 lpHitTestInfo->flags = LVHT_NOWHERE;
4652 return -1;
4655 /***
4656 * DESCRIPTION:
4657 * Determines which listview item is located at the specified position.
4659 * PARAMETER(S):
4660 * [I] HWND : window handle
4661 * [IO} LPLVHITTESTINFO : hit test information
4663 * RETURN:
4664 * SUCCESS : item index
4665 * FAILURE : -1
4667 static LRESULT LISTVIEW_HitTest(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4669 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4670 INT nItem = -1;
4672 lpHitTestInfo->flags = 0;
4674 if (infoPtr->rcList.left > lpHitTestInfo->pt.x)
4676 lpHitTestInfo->flags = LVHT_TOLEFT;
4678 else if (infoPtr->rcList.right < lpHitTestInfo->pt.x)
4680 lpHitTestInfo->flags = LVHT_TORIGHT;
4682 if (infoPtr->rcList.top > lpHitTestInfo->pt.y)
4684 lpHitTestInfo->flags |= LVHT_ABOVE;
4686 else if (infoPtr->rcList.bottom < lpHitTestInfo->pt.y)
4688 lpHitTestInfo->flags |= LVHT_BELOW;
4691 if (lpHitTestInfo->flags == 0)
4693 nItem = LISTVIEW_HitTestItem(hwnd, lpHitTestInfo);
4696 return nItem;
4699 /***
4700 * DESCRIPTION:
4701 * Inserts a new column.
4703 * PARAMETER(S):
4704 * [I] HWND : window handle
4705 * [I] INT : column index
4706 * [I] LPLVCOLUMNA : column information
4708 * RETURN:
4709 * SUCCESS : new column index
4710 * FAILURE : -1
4712 static LRESULT LISTVIEW_InsertColumnA(HWND hwnd, INT nColumn,
4713 LPLVCOLUMNA lpColumn)
4715 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4716 HDITEMA hdi;
4717 INT nNewColumn = -1;
4719 TRACE("(hwnd=%x, nColumn=%d, lpColumn=%p)\n",hwnd, nColumn,
4720 lpColumn);
4722 if (lpColumn != NULL)
4724 /* initialize memory */
4725 ZeroMemory(&hdi, sizeof(HDITEMA));
4727 if (lpColumn->mask & LVCF_FMT)
4729 /* format member is valid */
4730 hdi.mask |= HDI_FORMAT;
4732 /* set text alignment (leftmost column must be left-aligned) */
4733 if (nColumn == 0)
4735 hdi.fmt |= HDF_LEFT;
4737 else
4739 if (lpColumn->fmt & LVCFMT_LEFT)
4741 hdi.fmt |= HDF_LEFT;
4743 else if (lpColumn->fmt & LVCFMT_RIGHT)
4745 hdi.fmt |= HDF_RIGHT;
4747 else if (lpColumn->fmt & LVCFMT_CENTER)
4749 hdi.fmt |= HDF_CENTER;
4753 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
4755 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
4756 /* ??? */
4759 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
4761 /* ??? */
4764 if (lpColumn->fmt & LVCFMT_IMAGE)
4766 hdi.fmt |= HDF_IMAGE;
4767 hdi.iImage = I_IMAGECALLBACK;
4771 if (lpColumn->mask & LVCF_WIDTH)
4773 hdi.mask |= HDI_WIDTH;
4774 hdi.cxy = lpColumn->cx;
4777 if (lpColumn->mask & LVCF_TEXT)
4779 hdi.mask |= HDI_TEXT | HDI_FORMAT;
4780 hdi.pszText = lpColumn->pszText;
4781 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
4782 hdi.fmt |= HDF_STRING;
4785 if (lpColumn->mask & LVCF_IMAGE)
4787 hdi.mask |= HDI_IMAGE;
4788 hdi.iImage = lpColumn->iImage;
4791 if (lpColumn->mask & LVCF_ORDER)
4793 hdi.mask |= HDI_ORDER;
4794 hdi.iOrder = lpColumn->iOrder;
4797 /* insert item in header control */
4798 nNewColumn = SendMessageA(infoPtr->hwndHeader, HDM_INSERTITEMA,
4799 (WPARAM)nColumn, (LPARAM)&hdi);
4801 /* Need to reset the item width when inserting a new column */
4802 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
4804 LISTVIEW_UpdateScroll(hwnd);
4805 InvalidateRect(hwnd, NULL, FALSE);
4808 return nNewColumn;
4811 static LRESULT LISTVIEW_InsertColumnW(HWND hwnd, INT nColumn,
4812 LPLVCOLUMNW lpColumn)
4814 LVCOLUMNA lvca;
4815 LRESULT lres;
4817 memcpy(&lvca,lpColumn,sizeof(lvca));
4818 if (lpColumn->mask & LVCF_TEXT)
4819 lvca.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpColumn->pszText);
4820 lres = LISTVIEW_InsertColumnA(hwnd,nColumn,&lvca);
4821 if (lpColumn->mask & LVCF_TEXT)
4822 HeapFree(GetProcessHeap(),0,lvca.pszText);
4823 return lres;
4827 /***
4828 * DESCRIPTION:
4829 * Inserts a new item in the listview control.
4831 * PARAMETER(S):
4832 * [I] HWND : window handle
4833 * [I] LPLVITEMA : item information
4835 * RETURN:
4836 * SUCCESS : new item index
4837 * FAILURE : -1
4839 static LRESULT LISTVIEW_InsertItemA(HWND hwnd, LPLVITEMA lpLVItem)
4841 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4842 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4843 UINT uView = lStyle & LVS_TYPEMASK;
4844 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
4845 NMLISTVIEW nmlv;
4846 INT nItem = -1;
4847 HDPA hdpaSubItems;
4848 INT nItemWidth = 0;
4849 LISTVIEW_ITEM *lpItem = NULL;
4851 TRACE("(hwnd=%x,lpLVItem=%p)\n", hwnd, lpLVItem);
4853 if (lpLVItem != NULL)
4855 /* make sure it's not a subitem; cannot insert a subitem */
4856 if (lpLVItem->iSubItem == 0)
4858 lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM));
4859 if (lpItem != NULL)
4861 ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
4862 if (LISTVIEW_InitItem(hwnd, lpItem, lpLVItem) != FALSE)
4864 /* insert item in listview control data structure */
4865 hdpaSubItems = DPA_Create(8);
4866 if (hdpaSubItems != NULL)
4868 nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem);
4869 if (nItem != -1)
4871 nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpLVItem->iItem,
4872 hdpaSubItems);
4873 if (nItem != -1)
4875 /* manage item focus */
4876 if (lpLVItem->mask & LVIF_STATE)
4878 if (lpLVItem->stateMask & LVIS_FOCUSED)
4880 LISTVIEW_SetItemFocus(hwnd, nItem);
4884 /* send LVN_INSERTITEM notification */
4885 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
4886 nmlv.hdr.hwndFrom = hwnd;
4887 nmlv.hdr.idFrom = lCtrlId;
4888 nmlv.hdr.code = LVN_INSERTITEM;
4889 nmlv.iItem = nItem;
4890 nmlv.lParam = lpItem->lParam;;
4891 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
4893 if ((uView == LVS_SMALLICON) || (uView == LVS_LIST))
4895 nItemWidth = LISTVIEW_CalculateWidth(hwnd, lpLVItem->iItem);
4896 if (nItemWidth > infoPtr->nItemWidth)
4898 infoPtr->nItemWidth = nItemWidth;
4902 /* align items (set position of each item) */
4903 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4905 if (lStyle & LVS_ALIGNLEFT)
4907 LISTVIEW_AlignLeft(hwnd);
4909 else
4911 LISTVIEW_AlignTop(hwnd);
4915 LISTVIEW_UpdateScroll(hwnd);
4916 /* refresh client area */
4917 InvalidateRect(hwnd, NULL, FALSE);
4926 /* free memory if unsuccessful */
4927 if ((nItem == -1) && (lpItem != NULL))
4929 COMCTL32_Free(lpItem);
4932 return nItem;
4935 static LRESULT LISTVIEW_InsertItemW(HWND hwnd, LPLVITEMW lpLVItem) {
4936 LVITEMA lvia;
4937 LRESULT lres;
4939 memcpy(&lvia,lpLVItem,sizeof(LVITEMA));
4940 if (lvia.mask & LVIF_TEXT) {
4941 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKW)
4942 lvia.pszText = LPSTR_TEXTCALLBACKA;
4943 else
4944 lvia.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpLVItem->pszText);
4946 lres = LISTVIEW_InsertItemA(hwnd, &lvia);
4947 if (lvia.mask & LVIF_TEXT) {
4948 if (lpLVItem->pszText != LPSTR_TEXTCALLBACKW)
4949 HeapFree(GetProcessHeap(),0,lvia.pszText);
4951 return lres;
4954 /* LISTVIEW_InsertItemW */
4956 /***
4957 * DESCRIPTION:
4958 * Redraws a range of items.
4960 * PARAMETER(S):
4961 * [I] HWND : window handle
4962 * [I] INT : first item
4963 * [I] INT : last item
4965 * RETURN:
4966 * SUCCESS : TRUE
4967 * FAILURE : FALSE
4969 static LRESULT LISTVIEW_RedrawItems(HWND hwnd, INT nFirst, INT nLast)
4971 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4972 BOOL bResult = FALSE;
4973 RECT rc;
4975 if (nFirst <= nLast)
4977 if ((nFirst >= 0) && (nFirst < GETITEMCOUNT(infoPtr)))
4979 if ((nLast >= 0) && (nLast < GETITEMCOUNT(infoPtr)))
4981 /* bResult = */
4982 InvalidateRect(hwnd, &rc, FALSE);
4987 return bResult;
4990 /* LISTVIEW_Scroll */
4992 /***
4993 * DESCRIPTION:
4994 * Sets the background color.
4996 * PARAMETER(S):
4997 * [I] HWND : window handle
4998 * [I] COLORREF : background color
5000 * RETURN:
5001 * SUCCESS : TRUE
5002 * FAILURE : FALSE
5004 static LRESULT LISTVIEW_SetBkColor(HWND hwnd, COLORREF clrBk)
5006 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5008 infoPtr->clrBk = clrBk;
5009 InvalidateRect(hwnd, NULL, TRUE);
5011 return TRUE;
5014 /* LISTVIEW_SetBkImage */
5016 /***
5017 * DESCRIPTION:
5018 * Sets the callback mask. This mask will be used when the parent
5019 * window stores state information (some or all).
5021 * PARAMETER(S):
5022 * [I] HWND : window handle
5023 * [I] UINT : state mask
5025 * RETURN:
5026 * SUCCESS : TRUE
5027 * FAILURE : FALSE
5029 static BOOL LISTVIEW_SetCallbackMask(HWND hwnd, UINT uMask)
5031 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5033 infoPtr->uCallbackMask = uMask;
5035 return TRUE;
5038 /***
5039 * DESCRIPTION:
5040 * Sets the attributes of a header item.
5042 * PARAMETER(S):
5043 * [I] HWND : window handle
5044 * [I] INT : column index
5045 * [I] LPLVCOLUMNA : column attributes
5047 * RETURN:
5048 * SUCCESS : TRUE
5049 * FAILURE : FALSE
5051 static LRESULT LISTVIEW_SetColumnA(HWND hwnd, INT nColumn,
5052 LPLVCOLUMNA lpColumn)
5054 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5055 BOOL bResult = FALSE;
5056 HDITEMA hdi, hdiget;
5058 if ((lpColumn != NULL) && (nColumn >= 0) &&
5059 (nColumn < Header_GetItemCount(infoPtr->hwndHeader)))
5061 /* initialize memory */
5062 ZeroMemory(&hdi, sizeof(HDITEMA));
5064 if (lpColumn->mask & LVCF_FMT)
5066 /* format member is valid */
5067 hdi.mask |= HDI_FORMAT;
5069 /* get current format first */
5070 hdiget.mask = HDI_FORMAT;
5071 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdiget))
5072 /* preserve HDF_STRING if present */
5073 hdi.fmt = hdiget.fmt & HDF_STRING;
5075 /* set text alignment (leftmost column must be left-aligned) */
5076 if (nColumn == 0)
5078 hdi.fmt |= HDF_LEFT;
5080 else
5082 if (lpColumn->fmt & LVCFMT_LEFT)
5084 hdi.fmt |= HDF_LEFT;
5086 else if (lpColumn->fmt & LVCFMT_RIGHT)
5088 hdi.fmt |= HDF_RIGHT;
5090 else if (lpColumn->fmt & LVCFMT_CENTER)
5092 hdi.fmt |= HDF_CENTER;
5096 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
5098 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
5101 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
5103 hdi.fmt |= HDF_IMAGE;
5106 if (lpColumn->fmt & LVCFMT_IMAGE)
5108 hdi.fmt |= HDF_IMAGE;
5109 hdi.iImage = I_IMAGECALLBACK;
5113 if (lpColumn->mask & LVCF_WIDTH)
5115 hdi.mask |= HDI_WIDTH;
5116 hdi.cxy = lpColumn->cx;
5119 if (lpColumn->mask & LVCF_TEXT)
5121 hdi.mask |= HDI_TEXT | HDI_FORMAT;
5122 hdi.pszText = lpColumn->pszText;
5123 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
5124 hdi.fmt |= HDF_STRING;
5127 if (lpColumn->mask & LVCF_IMAGE)
5129 hdi.mask |= HDI_IMAGE;
5130 hdi.iImage = lpColumn->iImage;
5133 if (lpColumn->mask & LVCF_ORDER)
5135 hdi.mask |= HDI_ORDER;
5136 hdi.iOrder = lpColumn->iOrder;
5139 /* set header item attributes */
5140 bResult = Header_SetItemA(infoPtr->hwndHeader, nColumn, &hdi);
5143 return bResult;
5146 /* LISTVIEW_SetColumnW */
5147 /* LISTVIEW_SetColumnOrderArray */
5149 /***
5150 * DESCRIPTION:
5151 * Sets the width of a column
5153 * PARAMETERS:
5154 * [I] HWND : window handle
5155 * [I] INT : column index
5156 * [I] INT : column width
5158 * RETURN:
5159 * SUCCESS : TRUE
5160 * FAILURE : FALSE
5162 static LRESULT LISTVIEW_SetColumnWidth(HWND hwnd, INT iCol, INT cx)
5164 LISTVIEW_INFO *infoPtr;
5165 HDITEMA hdi;
5166 LRESULT lret;
5167 LONG lStyle;
5169 /* set column width only if in report mode */
5170 lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5171 if ((lStyle & LVS_TYPEMASK) != LVS_REPORT)
5172 return (FALSE);
5174 /* make sure we can get the listview info */
5175 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5176 return (FALSE);
5177 if (!infoPtr->hwndHeader) /* make sure we have a header */
5178 return (FALSE);
5180 /* FIXME: currently ignoring LVSCW_AUTOSIZE (-1) and
5181 * LVSCV_AUTOSIZE_USEHEADER (-2)
5183 if (cx < 0)
5184 return (FALSE);
5186 hdi.mask = HDI_WIDTH;
5187 hdi.cxy = cx;
5189 /* call header to update the column change */
5190 lret = Header_SetItemA(infoPtr->hwndHeader, (WPARAM)iCol, (LPARAM)&hdi);
5192 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
5194 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
5196 return lret;
5199 /***
5200 * DESCRIPTION:
5201 * Sets the extended listview style.
5203 * PARAMETERS:
5204 * [I] HWND : window handle
5205 * [I] DWORD : mask
5206 * [I] DWORD : style
5208 * RETURN:
5209 * SUCCESS : previous style
5210 * FAILURE : 0
5212 static LRESULT LISTVIEW_SetExtendedListViewStyle(HWND hwnd, DWORD dwMask, DWORD dwStyle)
5214 LISTVIEW_INFO *infoPtr;
5215 DWORD dwOldStyle;
5217 /* make sure we can get the listview info */
5218 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5219 return (0);
5221 /* store previous style */
5222 dwOldStyle = infoPtr->dwExStyle;
5224 /* set new style */
5225 infoPtr->dwExStyle = (dwOldStyle & ~dwMask) | (dwStyle & dwMask);
5227 return (dwOldStyle);
5230 /* LISTVIEW_SetHotCursor */
5232 /***
5233 * DESCRIPTION:
5234 * Sets the hot item index.
5236 * PARAMETERS:
5237 * [I] HWND : window handle
5238 * [I] INT : index
5240 * RETURN:
5241 * SUCCESS : previous hot item index
5242 * FAILURE : -1 (no hot item)
5244 static LRESULT LISTVIEW_SetHotItem(HWND hwnd, INT iIndex)
5246 LISTVIEW_INFO *infoPtr;
5247 INT iOldIndex;
5249 /* make sure we can get the listview info */
5250 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5251 return (-1);
5253 /* store previous index */
5254 iOldIndex = infoPtr->nHotItem;
5256 /* set new style */
5257 infoPtr->nHotItem = iIndex;
5259 return (iOldIndex);
5262 /* LISTVIEW_SetIconSpacing */
5264 /***
5265 * DESCRIPTION:
5266 * Sets image lists.
5268 * PARAMETER(S):
5269 * [I] HWND : window handle
5270 * [I] INT : image list type
5271 * [I] HIMAGELIST : image list handle
5273 * RETURN:
5274 * SUCCESS : old image list
5275 * FAILURE : NULL
5277 static LRESULT LISTVIEW_SetImageList(HWND hwnd, INT nType, HIMAGELIST himl)
5279 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5280 HIMAGELIST himlTemp = 0;
5282 switch (nType)
5284 case LVSIL_NORMAL:
5285 himlTemp = infoPtr->himlNormal;
5286 infoPtr->himlNormal = himl;
5287 return (LRESULT)himlTemp;
5289 case LVSIL_SMALL:
5290 himlTemp = infoPtr->himlSmall;
5291 infoPtr->himlSmall = himl;
5292 return (LRESULT)himlTemp;
5294 case LVSIL_STATE:
5295 himlTemp = infoPtr->himlState;
5296 infoPtr->himlState = himl;
5297 ImageList_SetBkColor(infoPtr->himlState, CLR_NONE);
5298 return (LRESULT)himlTemp;
5301 return (LRESULT)NULL;
5305 /***
5306 * DESCRIPTION:
5307 * Sets the attributes of an item.
5309 * PARAMETER(S):
5310 * [I] HWND : window handle
5311 * [I] LPLVITEM : item information
5313 * RETURN:
5314 * SUCCESS : TRUE
5315 * FAILURE : FALSE
5317 static LRESULT LISTVIEW_SetItemA(HWND hwnd, LPLVITEMA lpLVItem)
5319 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5320 BOOL bResult = FALSE;
5322 if (lpLVItem != NULL)
5324 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
5326 if (lpLVItem->iSubItem == 0)
5328 bResult = LISTVIEW_SetItem(hwnd, lpLVItem);
5330 else
5332 bResult = LISTVIEW_SetSubItem(hwnd, lpLVItem);
5338 return bResult;
5341 /* LISTVIEW_SetItemW */
5343 /***
5344 * DESCRIPTION:
5345 * Preallocates memory.
5347 * PARAMETER(S):
5348 * [I] HWND : window handle
5349 * [I] INT : item count (prjected number of items)
5350 * [I] DWORD : update flags
5352 * RETURN:
5353 * SUCCESS : TRUE
5354 * FAILURE : FALSE
5356 static BOOL LISTVIEW_SetItemCount(HWND hwnd, INT nItems, DWORD dwFlags)
5358 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5360 FIXME("(%d %08lx)empty stub!\n", nItems, dwFlags);
5362 if (nItems == 0)
5363 return LISTVIEW_DeleteAllItems (hwnd);
5365 if (nItems > GETITEMCOUNT(infoPtr))
5367 /* append items */
5368 FIXME("append items\n");
5371 else if (nItems < GETITEMCOUNT(infoPtr))
5373 /* remove items */
5374 FIXME("remove items\n");
5378 return TRUE;
5381 /***
5382 * DESCRIPTION:
5383 * Sets the position of an item.
5385 * PARAMETER(S):
5386 * [I] HWND : window handle
5387 * [I] INT : item index
5388 * [I] INT : x coordinate
5389 * [I] INT : y coordinate
5391 * RETURN:
5392 * SUCCESS : TRUE
5393 * FAILURE : FALSE
5395 static BOOL LISTVIEW_SetItemPosition(HWND hwnd, INT nItem,
5396 INT nPosX, INT nPosY)
5398 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5399 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5400 LISTVIEW_ITEM *lpItem;
5401 HDPA hdpaSubItems;
5402 BOOL bResult = FALSE;
5404 TRACE("(hwnd=%x,nItem=%d,X=%d,Y=%d)\n", hwnd, nItem, nPosX, nPosY);
5406 if ((nItem >= 0) || (nItem < GETITEMCOUNT(infoPtr)))
5408 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
5410 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
5411 if (hdpaSubItems != NULL)
5413 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
5414 if (lpItem != NULL)
5416 bResult = TRUE;
5417 lpItem->ptPosition.x = nPosX;
5418 lpItem->ptPosition.y = nPosY;
5424 return bResult;
5427 /* LISTVIEW_SetItemPosition32 */
5429 /***
5430 * DESCRIPTION:
5431 * Sets the state of one or many items.
5433 * PARAMETER(S):
5434 * [I] HWND : window handle
5435 * [I]INT : item index
5436 * [I] LPLVITEM : item or subitem info
5438 * RETURN:
5439 * SUCCESS : TRUE
5440 * FAILURE : FALSE
5442 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5444 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5445 BOOL bResult = FALSE;
5446 LVITEMA lvItem;
5447 INT i;
5449 if (nItem == -1)
5451 bResult = TRUE;
5452 ZeroMemory(&lvItem, sizeof(LVITEMA));
5453 lvItem.mask = LVIF_STATE;
5454 lvItem.state = lpLVItem->state;
5455 lvItem.stateMask = lpLVItem->stateMask ;
5457 /* apply to all items */
5458 for (i = 0; i< GETITEMCOUNT(infoPtr); i++)
5460 lvItem.iItem = i;
5461 if (ListView_SetItemA(hwnd, &lvItem) == FALSE)
5463 bResult = FALSE;
5467 else
5469 ZeroMemory(&lvItem, sizeof(LVITEMA));
5470 lvItem.mask = LVIF_STATE;
5471 lvItem.state = lpLVItem->state;
5472 lvItem.stateMask = lpLVItem->stateMask;
5473 lvItem.iItem = nItem;
5474 bResult = ListView_SetItemA(hwnd, &lvItem);
5477 return bResult;
5480 /***
5481 * DESCRIPTION:
5482 * Sets the text of an item or subitem.
5484 * PARAMETER(S):
5485 * [I] HWND : window handle
5486 * [I] INT : item index
5487 * [I] LPLVITEMA : item or subitem info
5489 * RETURN:
5490 * SUCCESS : TRUE
5491 * FAILURE : FALSE
5493 static BOOL LISTVIEW_SetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5495 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5496 BOOL bResult = FALSE;
5497 LVITEMA lvItem;
5499 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5501 ZeroMemory(&lvItem, sizeof(LVITEMA));
5502 lvItem.mask = LVIF_TEXT;
5503 lvItem.pszText = lpLVItem->pszText;
5504 lvItem.iItem = nItem;
5505 lvItem.iSubItem = lpLVItem->iSubItem;
5506 bResult = ListView_SetItemA(hwnd, &lvItem);
5509 return bResult;
5512 /* LISTVIEW_SetItemTextW */
5514 /***
5515 * DESCRIPTION:
5516 * Set item index that marks the start of a multiple selection.
5518 * PARAMETER(S):
5519 * [I] HWND : window handle
5520 * [I] INT : index
5522 * RETURN:
5523 * Index number or -1 if there is no selection mark.
5525 static LRESULT LISTVIEW_SetSelectionMark(HWND hwnd, INT nIndex)
5527 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5528 INT nOldIndex = infoPtr->nSelectionMark;
5530 infoPtr->nSelectionMark = nIndex;
5532 return nOldIndex;
5535 /***
5536 * DESCRIPTION:
5537 * Sets the text background color.
5539 * PARAMETER(S):
5540 * [I] HWND : window handle
5541 * [I] COLORREF : text background color
5543 * RETURN:
5544 * SUCCESS : TRUE
5545 * FAILURE : FALSE
5547 static LRESULT LISTVIEW_SetTextBkColor(HWND hwnd, COLORREF clrTextBk)
5549 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5551 infoPtr->clrTextBk = clrTextBk;
5552 InvalidateRect(hwnd, NULL, TRUE);
5554 return TRUE;
5557 /***
5558 * DESCRIPTION:
5559 * Sets the text foreground color.
5561 * PARAMETER(S):
5562 * [I] HWND : window handle
5563 * [I] COLORREF : text color
5565 * RETURN:
5566 * SUCCESS : TRUE
5567 * FAILURE : FALSE
5569 static LRESULT LISTVIEW_SetTextColor (HWND hwnd, COLORREF clrText)
5571 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5573 infoPtr->clrText = clrText;
5574 InvalidateRect(hwnd, NULL, TRUE);
5576 return TRUE;
5579 /* LISTVIEW_SetToolTips */
5580 /* LISTVIEW_SetUnicodeFormat */
5581 /* LISTVIEW_SetWorkAreas */
5583 /***
5584 * DESCRIPTION:
5585 * Callback internally used by LISTVIEW_SortItems()
5587 * PARAMETER(S):
5588 * [I] LPVOID : first LISTVIEW_ITEM to compare
5589 * [I] LPVOID : second LISTVIEW_ITEM to compare
5590 * [I] LPARAM : HWND of control
5592 * RETURN:
5593 * if first comes before second : negative
5594 * if first comes after second : positive
5595 * if first and second are equivalent : zero
5597 static INT WINAPI LISTVIEW_CallBackCompare(
5598 LPVOID first,
5599 LPVOID second,
5600 LPARAM lParam)
5602 /* Forward the call to the client defined callback */
5603 HWND hwnd = (HWND)lParam;
5604 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5606 return (infoPtr->pfnCompare)(
5607 ((LISTVIEW_ITEM *)first)->lParam,
5608 ((LISTVIEW_ITEM *)second)->lParam,
5609 infoPtr->lParamSort);
5612 /***
5613 * DESCRIPTION:
5614 * Sorts the listview items.
5616 * PARAMETER(S):
5617 * [I] HWND : window handle
5618 * [I] WPARAM : application-defined value
5619 * [I] LPARAM : pointer to comparision callback
5621 * RETURN:
5622 * SUCCESS : TRUE
5623 * FAILURE : FALSE
5625 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam)
5627 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5628 HDPA hdpaSubItems;
5629 LISTVIEW_ITEM *lpItem;
5630 int nCount, i;
5631 HDPA sortList;
5633 if (!infoPtr || !infoPtr->hdpaItems)
5634 return FALSE;
5636 nCount = GETITEMCOUNT(infoPtr);
5637 /* if there are 0 or 1 items, there is no need to sort */
5638 if (nCount > 1)
5640 sortList = DPA_Create(nCount);
5642 infoPtr->pfnCompare = (PFNLVCOMPARE)lParam;
5643 infoPtr->lParamSort = (LPARAM)wParam;
5645 /* append pointers one by one to sortList */
5646 for (i = 0; i < nCount; i++)
5648 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)))
5649 if ((lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(hdpaSubItems, 0)))
5650 DPA_InsertPtr(sortList, nCount + 1, lpItem);
5653 /* sort the sortList */
5654 DPA_Sort(sortList, LISTVIEW_CallBackCompare, hwnd);
5656 /* copy the pointers back */
5657 for (i = 0; i < nCount; i++)
5659 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)) &&
5660 (lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(sortList, i)))
5661 DPA_SetPtr(hdpaSubItems, 0, lpItem);
5664 DPA_Destroy(sortList);
5667 return TRUE;
5670 /* LISTVIEW_SubItemHitTest */
5672 /***
5673 * DESCRIPTION:
5674 * Updates an items or rearranges the listview control.
5676 * PARAMETER(S):
5677 * [I] HWND : window handle
5678 * [I] INT : item index
5680 * RETURN:
5681 * SUCCESS : TRUE
5682 * FAILURE : FALSE
5684 static LRESULT LISTVIEW_Update(HWND hwnd, INT nItem)
5686 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5687 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5688 BOOL bResult = FALSE;
5689 RECT rc;
5691 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5693 bResult = TRUE;
5695 /* rearrange with default alignment style */
5696 if ((lStyle & LVS_AUTOARRANGE) && (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
5697 ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON)))
5699 ListView_Arrange(hwnd, 0);
5701 else
5703 /* get item bounding rectangle */
5704 rc.left = LVIR_BOUNDS;
5705 ListView_GetItemRect(hwnd, nItem, &rc);
5706 InvalidateRect(hwnd, &rc, TRUE);
5710 return bResult;
5713 /***
5714 * DESCRIPTION:
5715 * Creates the listview control.
5717 * PARAMETER(S):
5718 * [I] HWND : window handle
5720 * RETURN:
5721 * Zero
5723 static LRESULT LISTVIEW_Create(HWND hwnd, WPARAM wParam, LPARAM lParam)
5725 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5726 LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam;
5727 UINT uView = lpcs->style & LVS_TYPEMASK;
5728 LOGFONTA logFont;
5730 /* initialize info pointer */
5731 ZeroMemory(infoPtr, sizeof(LISTVIEW_INFO));
5733 /* determine the type of structures to use */
5734 infoPtr->notifyFormat = SendMessageA(GetParent(hwnd), WM_NOTIFYFORMAT,
5735 (WPARAM)hwnd, (LPARAM)NF_QUERY);
5736 if (infoPtr->notifyFormat != NFR_ANSI)
5738 FIXME("ANSI notify format is NOT used\n");
5741 /* initialize color information */
5742 infoPtr->clrBk = GetSysColor(COLOR_WINDOW);
5743 infoPtr->clrText = GetSysColor(COLOR_WINDOWTEXT);
5744 infoPtr->clrTextBk = GetSysColor(COLOR_WINDOW);
5746 /* set default values */
5747 infoPtr->uCallbackMask = 0;
5748 infoPtr->nFocusedItem = -1;
5749 infoPtr->nSelectionMark = -1;
5750 infoPtr->nHotItem = -1;
5751 infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING);
5752 infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING);
5753 ZeroMemory(&infoPtr->rcList, sizeof(RECT));
5754 infoPtr->hwndEdit = 0;
5755 infoPtr->pedititem = NULL;
5757 /* get default font (icon title) */
5758 SystemParametersInfoA(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
5759 infoPtr->hDefaultFont = CreateFontIndirectA(&logFont);
5760 infoPtr->hFont = infoPtr->hDefaultFont;
5762 /* create header */
5763 infoPtr->hwndHeader = CreateWindowA(WC_HEADERA, (LPCSTR)NULL,
5764 WS_CHILD | HDS_HORZ | HDS_BUTTONS,
5765 0, 0, 0, 0, hwnd, (HMENU)0,
5766 lpcs->hInstance, NULL);
5768 /* set header font */
5769 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont,
5770 (LPARAM)TRUE);
5772 if (uView == LVS_ICON)
5774 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
5775 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
5777 else if (uView == LVS_REPORT)
5779 if (!(LVS_NOCOLUMNHEADER & lpcs->style))
5781 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
5784 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
5785 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
5787 else
5789 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
5790 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
5793 /* display unsupported listview window styles */
5794 LISTVIEW_UnsupportedStyles(lpcs->style);
5796 /* allocate memory for the data structure */
5797 infoPtr->hdpaItems = DPA_Create(10);
5799 /* initialize size of items */
5800 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
5801 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
5803 return 0;
5806 /***
5807 * DESCRIPTION:
5808 * Erases the background of the listview control.
5810 * PARAMETER(S):
5811 * [I] HWND : window handle
5812 * [I] WPARAM : device context handle
5813 * [I] LPARAM : not used
5815 * RETURN:
5816 * SUCCESS : TRUE
5817 * FAILURE : FALSE
5819 static LRESULT LISTVIEW_EraseBackground(HWND hwnd, WPARAM wParam,
5820 LPARAM lParam)
5822 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5823 BOOL bResult;
5825 if (infoPtr->clrBk == CLR_NONE)
5827 bResult = SendMessageA(GetParent(hwnd), WM_ERASEBKGND, wParam, lParam);
5829 else
5831 RECT rc;
5832 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
5833 GetClientRect(hwnd, &rc);
5834 FillRect((HDC)wParam, &rc, hBrush);
5835 DeleteObject(hBrush);
5836 bResult = TRUE;
5839 return bResult;
5842 /***
5843 * DESCRIPTION:
5844 * Retrieves the listview control font.
5846 * PARAMETER(S):
5847 * [I] HWND : window handle
5849 * RETURN:
5850 * Font handle.
5852 static LRESULT LISTVIEW_GetFont(HWND hwnd)
5854 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5856 return infoPtr->hFont;
5859 /***
5860 * DESCRIPTION:
5861 * Performs vertical scrolling.
5863 * PARAMETER(S):
5864 * [I] HWND : window handle
5865 * [I] INT : scroll code
5866 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
5867 * or SB_THUMBTRACK.
5868 * [I] HWND : scrollbar control window handle
5870 * RETURN:
5871 * Zero
5873 static LRESULT LISTVIEW_VScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
5874 HWND hScrollWnd)
5876 SCROLLINFO scrollInfo;
5878 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
5879 scrollInfo.cbSize = sizeof(SCROLLINFO);
5880 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
5882 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
5884 INT nOldScrollPos = scrollInfo.nPos;
5885 switch (nScrollCode)
5887 case SB_LINEUP:
5888 if (scrollInfo.nPos > scrollInfo.nMin)
5890 scrollInfo.nPos--;
5892 break;
5894 case SB_LINEDOWN:
5895 if (scrollInfo.nPos < scrollInfo.nMax)
5897 scrollInfo.nPos++;
5899 break;
5901 case SB_PAGEUP:
5902 if (scrollInfo.nPos > scrollInfo.nMin)
5905 if (scrollInfo.nPos >= scrollInfo.nPage)
5907 scrollInfo.nPos -= scrollInfo.nPage;
5909 else
5911 scrollInfo.nPos = scrollInfo.nMin;
5914 break;
5916 case SB_PAGEDOWN:
5917 if (scrollInfo.nPos < scrollInfo.nMax)
5919 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
5921 scrollInfo.nPos += scrollInfo.nPage;
5923 else
5925 scrollInfo.nPos = scrollInfo.nMax;
5928 break;
5930 case SB_THUMBTRACK:
5931 scrollInfo.nPos = nCurrentPos;
5932 break;
5935 if (nOldScrollPos != scrollInfo.nPos)
5937 scrollInfo.fMask = SIF_POS;
5938 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
5939 InvalidateRect(hwnd, NULL, TRUE);
5943 return 0;
5946 /***
5947 * DESCRIPTION:
5948 * Performs horizontal scrolling.
5950 * PARAMETER(S):
5951 * [I] HWND : window handle
5952 * [I] INT : scroll code
5953 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
5954 * or SB_THUMBTRACK.
5955 * [I] HWND : scrollbar control window handle
5957 * RETURN:
5958 * Zero
5960 static LRESULT LISTVIEW_HScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
5961 HWND hScrollWnd)
5963 SCROLLINFO scrollInfo;
5965 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
5966 scrollInfo.cbSize = sizeof(SCROLLINFO);
5967 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
5969 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
5971 INT nOldScrollPos = scrollInfo.nPos;
5973 switch (nScrollCode)
5975 case SB_LINELEFT:
5976 if (scrollInfo.nPos > scrollInfo.nMin)
5978 scrollInfo.nPos--;
5980 break;
5982 case SB_LINERIGHT:
5983 if (scrollInfo.nPos < scrollInfo.nMax)
5985 scrollInfo.nPos++;
5987 break;
5989 case SB_PAGELEFT:
5990 if (scrollInfo.nPos > scrollInfo.nMin)
5992 if (scrollInfo.nPos >= scrollInfo.nPage)
5994 scrollInfo.nPos -= scrollInfo.nPage;
5996 else
5998 scrollInfo.nPos = scrollInfo.nMin;
6001 break;
6003 case SB_PAGERIGHT:
6004 if (scrollInfo.nPos < scrollInfo.nMax)
6006 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
6008 scrollInfo.nPos += scrollInfo.nPage;
6010 else
6012 scrollInfo.nPos = scrollInfo.nMax;
6015 break;
6017 case SB_THUMBTRACK:
6018 scrollInfo.nPos = nCurrentPos;
6019 break;
6022 if (nOldScrollPos != scrollInfo.nPos)
6024 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
6025 scrollInfo.fMask = SIF_POS;
6026 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
6027 if(uView == LVS_REPORT)
6029 scrollInfo.fMask = SIF_POS;
6030 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
6031 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
6033 InvalidateRect(hwnd, NULL, TRUE);
6037 return 0;
6040 /***
6041 * DESCRIPTION:
6042 * ???
6044 * PARAMETER(S):
6045 * [I] HWND : window handle
6046 * [I] INT : virtual key
6047 * [I] LONG : key data
6049 * RETURN:
6050 * Zero
6052 static LRESULT LISTVIEW_KeyDown(HWND hwnd, INT nVirtualKey, LONG lKeyData)
6054 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6055 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6056 HWND hwndParent = GetParent(hwnd);
6057 NMLVKEYDOWN nmKeyDown;
6058 NMHDR nmh;
6059 INT nItem = -1;
6060 BOOL bRedraw = FALSE;
6062 /* send LVN_KEYDOWN notification */
6063 ZeroMemory(&nmKeyDown, sizeof(NMLVKEYDOWN));
6064 nmKeyDown.hdr.hwndFrom = hwnd;
6065 nmKeyDown.hdr.idFrom = nCtrlId;
6066 nmKeyDown.hdr.code = LVN_KEYDOWN;
6067 nmKeyDown.wVKey = nVirtualKey;
6068 nmKeyDown.flags = 0;
6069 SendMessageA(hwndParent, WM_NOTIFY, (WPARAM)nCtrlId, (LPARAM)&nmKeyDown);
6071 /* initialize */
6072 nmh.hwndFrom = hwnd;
6073 nmh.idFrom = nCtrlId;
6075 switch (nVirtualKey)
6077 case VK_RETURN:
6078 if ((GETITEMCOUNT(infoPtr) > 0) && (infoPtr->nFocusedItem != -1))
6080 /* send NM_RETURN notification */
6081 nmh.code = NM_RETURN;
6082 ListView_Notify(hwndParent, nCtrlId, &nmh);
6084 /* send LVN_ITEMACTIVATE notification */
6085 nmh.code = LVN_ITEMACTIVATE;
6086 ListView_Notify(hwndParent, nCtrlId, &nmh);
6088 break;
6090 case VK_HOME:
6091 if (GETITEMCOUNT(infoPtr) > 0)
6093 nItem = 0;
6095 break;
6097 case VK_END:
6098 if (GETITEMCOUNT(infoPtr) > 0)
6100 nItem = GETITEMCOUNT(infoPtr) - 1;
6102 break;
6104 case VK_LEFT:
6105 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TOLEFT);
6106 break;
6108 case VK_UP:
6109 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_ABOVE);
6110 break;
6112 case VK_RIGHT:
6113 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TORIGHT);
6114 break;
6116 case VK_DOWN:
6117 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_BELOW);
6118 break;
6120 case VK_PRIOR:
6121 /* TO DO */
6122 break;
6124 case VK_NEXT:
6125 /* TO DO */
6126 break;
6129 if ((nItem != -1) && (nItem != infoPtr->nFocusedItem))
6131 bRedraw = LISTVIEW_KeySelection(hwnd, nItem);
6132 if (bRedraw != FALSE)
6134 /* refresh client area */
6135 InvalidateRect(hwnd, NULL, TRUE);
6136 UpdateWindow(hwnd);
6140 return 0;
6143 /***
6144 * DESCRIPTION:
6145 * Kills the focus.
6147 * PARAMETER(S):
6148 * [I] HWND : window handle
6150 * RETURN:
6151 * Zero
6153 static LRESULT LISTVIEW_KillFocus(HWND hwnd)
6155 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
6156 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6157 NMHDR nmh;
6159 TRACE("(hwnd=%x)\n", hwnd);
6161 /* send NM_KILLFOCUS notification */
6162 nmh.hwndFrom = hwnd;
6163 nmh.idFrom = nCtrlId;
6164 nmh.code = NM_KILLFOCUS;
6165 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6167 /* set window focus flag */
6168 infoPtr->bFocus = FALSE;
6170 /* NEED drawing optimization ; redraw the selected items */
6171 InvalidateRect(hwnd, NULL, FALSE);
6173 return 0;
6176 /***
6177 * DESCRIPTION:
6178 * Processes double click messages (left mouse button).
6180 * PARAMETER(S):
6181 * [I] HWND : window handle
6182 * [I] WORD : key flag
6183 * [I] WORD : x coordinate
6184 * [I] WORD : y coordinate
6186 * RETURN:
6187 * Zero
6189 static LRESULT LISTVIEW_LButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
6190 WORD wPosY)
6192 LONG nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6193 NMHDR nmh;
6195 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6197 /* send NM_DBLCLK notification */
6198 nmh.hwndFrom = hwnd;
6199 nmh.idFrom = nCtrlId;
6200 nmh.code = NM_DBLCLK;
6201 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6203 /* send LVN_ITEMACTIVATE notification */
6204 nmh.code = LVN_ITEMACTIVATE;
6205 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6207 return 0;
6210 /***
6211 * DESCRIPTION:
6212 * Processes mouse down messages (left mouse button).
6214 * PARAMETER(S):
6215 * [I] HWND : window handle
6216 * [I] WORD : key flag
6217 * [I] WORD : x coordinate
6218 * [I] WORD : y coordinate
6220 * RETURN:
6221 * Zero
6223 static LRESULT LISTVIEW_LButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
6224 WORD wPosY)
6226 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6227 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6228 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6229 static BOOL bGroupSelect = TRUE;
6230 POINT ptPosition;
6231 NMHDR nmh;
6232 INT nItem;
6234 TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd, wKey, wPosX,
6235 wPosY);
6237 /* send NM_RELEASEDCAPTURE notification */
6238 nmh.hwndFrom = hwnd;
6239 nmh.idFrom = nCtrlId;
6240 nmh.code = NM_RELEASEDCAPTURE;
6241 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6243 if (infoPtr->bFocus == FALSE)
6245 SetFocus(hwnd);
6248 /* set left button down flag */
6249 infoPtr->bLButtonDown = TRUE;
6251 ptPosition.x = wPosX;
6252 ptPosition.y = wPosY;
6253 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
6254 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
6256 if (lStyle & LVS_SINGLESEL)
6258 LISTVIEW_SetSelection(hwnd, nItem);
6260 else
6262 if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
6264 if (bGroupSelect != FALSE)
6266 LISTVIEW_AddGroupSelection(hwnd, nItem);
6268 else
6270 LISTVIEW_AddSelection(hwnd, nItem);
6273 else if (wKey & MK_CONTROL)
6275 bGroupSelect = LISTVIEW_ToggleSelection(hwnd, nItem);
6277 else if (wKey & MK_SHIFT)
6279 LISTVIEW_SetGroupSelection(hwnd, nItem);
6281 else
6283 LISTVIEW_SetSelection(hwnd, nItem);
6287 else
6289 /* remove all selections */
6290 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
6293 InvalidateRect(hwnd, NULL, TRUE);
6295 return 0;
6298 /***
6299 * DESCRIPTION:
6300 * Processes mouse up messages (left mouse button).
6302 * PARAMETER(S):
6303 * [I] HWND : window handle
6304 * [I] WORD : key flag
6305 * [I] WORD : x coordinate
6306 * [I] WORD : y coordinate
6308 * RETURN:
6309 * Zero
6311 static LRESULT LISTVIEW_LButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
6312 WORD wPosY)
6314 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6316 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6318 if (infoPtr->bLButtonDown != FALSE)
6320 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6321 NMHDR nmh;
6323 /* send NM_CLICK notification */
6324 nmh.hwndFrom = hwnd;
6325 nmh.idFrom = nCtrlId;
6326 nmh.code = NM_CLICK;
6327 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6329 /* set left button flag */
6330 infoPtr->bLButtonDown = FALSE;
6333 return 0;
6336 /***
6337 * DESCRIPTION:
6338 * Creates the listview control (called before WM_CREATE).
6340 * PARAMETER(S):
6341 * [I] HWND : window handle
6342 * [I] WPARAM : unhandled
6343 * [I] LPARAM : widow creation info
6345 * RETURN:
6346 * Zero
6348 static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
6350 LISTVIEW_INFO *infoPtr;
6352 TRACE("(hwnd=%x,wParam=%x,lParam=%lx)\n", hwnd, wParam, lParam);
6354 /* allocate memory for info structure */
6355 infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc(sizeof(LISTVIEW_INFO));
6356 SetWindowLongA(hwnd, 0, (LONG)infoPtr);
6357 if (infoPtr == NULL)
6359 ERR("could not allocate info memory!\n");
6360 return 0;
6363 if ((LISTVIEW_INFO *)GetWindowLongA(hwnd, 0) != infoPtr)
6365 ERR("pointer assignment error!\n");
6366 return 0;
6369 return DefWindowProcA(hwnd, WM_NCCREATE, wParam, lParam);
6372 /***
6373 * DESCRIPTION:
6374 * Destroys the listview control (called after WM_DESTROY).
6376 * PARAMETER(S):
6377 * [I] HWND : window handle
6379 * RETURN:
6380 * Zero
6382 static LRESULT LISTVIEW_NCDestroy(HWND hwnd)
6384 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6386 TRACE("(hwnd=%x)\n", hwnd);
6388 /* delete all items */
6389 LISTVIEW_DeleteAllItems(hwnd);
6391 /* destroy data structure */
6392 DPA_Destroy(infoPtr->hdpaItems);
6394 /* destroy font */
6395 infoPtr->hFont = (HFONT)0;
6396 if (infoPtr->hDefaultFont)
6398 DeleteObject(infoPtr->hDefaultFont);
6401 /* free listview info pointer*/
6402 COMCTL32_Free(infoPtr);
6404 return 0;
6407 /***
6408 * DESCRIPTION:
6409 * Handles notifications from children.
6411 * PARAMETER(S):
6412 * [I] HWND : window handle
6413 * [I] INT : control identifier
6414 * [I] LPNMHDR : notification information
6416 * RETURN:
6417 * Zero
6419 static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh)
6421 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6423 if (lpnmh->hwndFrom == infoPtr->hwndHeader)
6425 /* handle notification from header control */
6426 if (lpnmh->code == HDN_ENDTRACKA)
6428 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6429 InvalidateRect(hwnd, NULL, TRUE);
6431 else if(lpnmh->code == HDN_ITEMCLICKA)
6433 /* Handle sorting by Header Column */
6434 NMLISTVIEW nmlv;
6435 LPNMHEADERA pnmHeader = (LPNMHEADERA) lpnmh;
6436 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
6438 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
6439 nmlv.hdr.hwndFrom = hwnd;
6440 nmlv.hdr.idFrom = lCtrlId;
6441 nmlv.hdr.code = LVN_COLUMNCLICK;
6442 nmlv.iItem = -1;
6443 nmlv.iSubItem = pnmHeader->iItem;
6445 ListView_LVNotify(GetParent(hwnd),lCtrlId, &nmlv);
6448 else if(lpnmh->code == NM_RELEASEDCAPTURE)
6450 /* Idealy this should be done in HDN_ENDTRACKA
6451 * but since SetItemBounds in Header.c is called after
6452 * the notification is sent, it is neccessary to handle the
6453 * update of the scroll bar here (Header.c works fine as it is,
6454 * no need to disturb it)
6456 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6457 LISTVIEW_UpdateScroll(hwnd);
6458 InvalidateRect(hwnd, NULL, TRUE);
6463 return 0;
6466 /***
6467 * DESCRIPTION:
6468 * Determines the type of structure to use.
6470 * PARAMETER(S):
6471 * [I] HWND : window handle of the sender
6472 * [I] HWND : listview window handle
6473 * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
6475 * RETURN:
6476 * Zero
6478 static LRESULT LISTVIEW_NotifyFormat(HWND hwndFrom, HWND hwnd, INT nCommand)
6480 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6482 if (nCommand == NF_REQUERY)
6484 /* determine the type of structure to use */
6485 infoPtr->notifyFormat = SendMessageA(hwndFrom, WM_NOTIFYFORMAT,
6486 (WPARAM)hwnd, (LPARAM)NF_QUERY);
6487 if (infoPtr->notifyFormat == NFR_UNICODE)
6489 FIXME("NO support for unicode structures");
6493 return 0;
6496 /***
6497 * DESCRIPTION:
6498 * Paints/Repaints the listview control.
6500 * PARAMETER(S):
6501 * [I] HWND : window handle
6502 * [I] HDC : device context handle
6504 * RETURN:
6505 * Zero
6507 static LRESULT LISTVIEW_Paint(HWND hwnd, HDC hdc)
6509 PAINTSTRUCT ps;
6511 TRACE("(hwnd=%x,hdc=%x)\n", hwnd, hdc);
6513 if (hdc == 0)
6515 hdc = BeginPaint(hwnd, &ps);
6516 LISTVIEW_Refresh(hwnd, hdc);
6517 EndPaint(hwnd, &ps);
6519 else
6521 LISTVIEW_Refresh(hwnd, hdc);
6524 return 0;
6527 /***
6528 * DESCRIPTION:
6529 * Processes double click messages (right mouse button).
6531 * PARAMETER(S):
6532 * [I] HWND : window handle
6533 * [I] WORD : key flag
6534 * [I] WORD : x coordinate
6535 * [I] WORD : y coordinate
6537 * RETURN:
6538 * Zero
6540 static LRESULT LISTVIEW_RButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
6541 WORD wPosY)
6543 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6544 NMHDR nmh;
6546 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6548 /* send NM_RELEASEDCAPTURE notification */
6549 nmh.hwndFrom = hwnd;
6550 nmh.idFrom = nCtrlId;
6551 nmh.code = NM_RELEASEDCAPTURE;
6552 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6554 /* send NM_RDBLCLK notification */
6555 nmh.code = NM_RDBLCLK;
6556 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6558 return 0;
6561 /***
6562 * DESCRIPTION:
6563 * Processes mouse down messages (right mouse button).
6565 * PARAMETER(S):
6566 * [I] HWND : window handle
6567 * [I] WORD : key flag
6568 * [I] WORD : x coordinate
6569 * [I] WORD : y coordinate
6571 * RETURN:
6572 * Zero
6574 static LRESULT LISTVIEW_RButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
6575 WORD wPosY)
6577 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6578 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6579 POINT ptPosition;
6580 NMHDR nmh;
6581 INT nItem;
6583 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6585 /* send NM_RELEASEDCAPTURE notification */
6586 nmh.hwndFrom = hwnd;
6587 nmh.idFrom = nCtrlId;
6588 nmh.code = NM_RELEASEDCAPTURE;
6589 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6591 /* make sure the listview control window has the focus */
6592 if (infoPtr->bFocus == FALSE)
6594 SetFocus(hwnd);
6597 /* set right button down flag */
6598 infoPtr->bRButtonDown = TRUE;
6600 /* determine the index of the selected item */
6601 ptPosition.x = wPosX;
6602 ptPosition.y = wPosY;
6603 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
6604 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
6606 if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)))
6608 LISTVIEW_SetSelection(hwnd, nItem);
6611 else
6613 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
6616 return 0;
6619 /***
6620 * DESCRIPTION:
6621 * Processes mouse up messages (right mouse button).
6623 * PARAMETER(S):
6624 * [I] HWND : window handle
6625 * [I] WORD : key flag
6626 * [I] WORD : x coordinate
6627 * [I] WORD : y coordinate
6629 * RETURN:
6630 * Zero
6632 static LRESULT LISTVIEW_RButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
6633 WORD wPosY)
6635 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6636 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6637 NMHDR nmh;
6639 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6641 if (infoPtr->bRButtonDown != FALSE)
6643 /* send NM_RClICK notification */
6644 ZeroMemory(&nmh, sizeof(NMHDR));
6645 nmh.hwndFrom = hwnd;
6646 nmh.idFrom = nCtrlId;
6647 nmh.code = NM_RCLICK;
6648 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6650 /* set button flag */
6651 infoPtr->bRButtonDown = FALSE;
6654 return 0;
6657 /***
6658 * DESCRIPTION:
6659 * Sets the focus.
6661 * PARAMETER(S):
6662 * [I] HWND : window handle
6663 * [I] HWND : window handle of previously focused window
6665 * RETURN:
6666 * Zero
6668 static LRESULT LISTVIEW_SetFocus(HWND hwnd, HWND hwndLoseFocus)
6670 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6671 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6672 NMHDR nmh;
6674 TRACE("(hwnd=%x, hwndLoseFocus=%x)\n", hwnd, hwndLoseFocus);
6676 /* send NM_SETFOCUS notification */
6677 nmh.hwndFrom = hwnd;
6678 nmh.idFrom = nCtrlId;
6679 nmh.code = NM_SETFOCUS;
6680 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6682 /* set window focus flag */
6683 infoPtr->bFocus = TRUE;
6685 InvalidateRect(hwnd, NULL, TRUE);
6686 UpdateWindow(hwnd);
6688 return 0;
6691 /***
6692 * DESCRIPTION:
6693 * Sets the font.
6695 * PARAMETER(S):
6696 * [I] HWND : window handle
6697 * [I] HFONT : font handle
6698 * [I] WORD : redraw flag
6700 * RETURN:
6701 * Zero
6703 static LRESULT LISTVIEW_SetFont(HWND hwnd, HFONT hFont, WORD fRedraw)
6705 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6706 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
6708 TRACE("(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd, hFont, fRedraw);
6710 if (hFont == 0)
6712 infoPtr->hFont = infoPtr->hDefaultFont;
6714 else
6716 infoPtr->hFont = hFont;
6719 if (uView == LVS_REPORT)
6721 /* set header font */
6722 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont,
6723 MAKELPARAM(fRedraw, 0));
6726 /* invalidate listview control client area */
6727 InvalidateRect(hwnd, NULL, TRUE);
6729 if (fRedraw != FALSE)
6731 UpdateWindow(hwnd);
6734 return 0;
6737 /***
6738 * DESCRIPTION:
6739 * Resizes the listview control. This function processes WM_SIZE
6740 * messages. At this time, the width and height are not used.
6742 * PARAMETER(S):
6743 * [I] HWND : window handle
6744 * [I] WORD : new width
6745 * [I] WORD : new height
6747 * RETURN:
6748 * Zero
6750 static LRESULT LISTVIEW_Size(HWND hwnd, int Width, int Height)
6752 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6753 UINT uView = lStyle & LVS_TYPEMASK;
6755 TRACE("(hwnd=%x, width=%d, height=%d)\n",hwnd, Width, Height);
6757 LISTVIEW_UpdateSize(hwnd);
6759 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
6761 if (lStyle & LVS_ALIGNLEFT)
6763 LISTVIEW_AlignLeft(hwnd);
6765 else
6767 LISTVIEW_AlignTop(hwnd);
6771 LISTVIEW_UpdateScroll(hwnd);
6773 /* invalidate client area + erase background */
6774 InvalidateRect(hwnd, NULL, TRUE);
6776 return 0;
6779 /***
6780 * DESCRIPTION:
6781 * Sets the size information.
6783 * PARAMETER(S):
6784 * [I] HWND : window handle
6786 * RETURN:
6787 * Zero
6789 static VOID LISTVIEW_UpdateSize(HWND hwnd)
6791 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6792 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6793 UINT uView = lStyle & LVS_TYPEMASK;
6794 RECT rcList;
6796 GetClientRect(hwnd, &rcList);
6797 infoPtr->rcList.left = 0;
6798 infoPtr->rcList.right = max(rcList.right - rcList.left, 1);
6799 infoPtr->rcList.top = 0;
6800 infoPtr->rcList.bottom = max(rcList.bottom - rcList.top, 1);
6802 if (uView == LVS_LIST)
6804 if ((lStyle & WS_HSCROLL) == 0)
6806 INT nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
6807 if (infoPtr->rcList.bottom > nHScrollHeight)
6809 infoPtr->rcList.bottom -= nHScrollHeight;
6813 else if (uView == LVS_REPORT)
6815 HDLAYOUT hl;
6816 WINDOWPOS wp;
6818 hl.prc = &rcList;
6819 hl.pwpos = &wp;
6820 Header_Layout(infoPtr->hwndHeader, &hl);
6821 if (!(LVS_NOCOLUMNHEADER & lStyle))
6823 infoPtr->rcList.top = max(wp.cy, 0);
6828 /***
6829 * DESCRIPTION:
6830 * Processes WM_STYLECHANGED messages.
6832 * PARAMETER(S):
6833 * [I] HWND : window handle
6834 * [I] WPARAM : window style type (normal or extended)
6835 * [I] LPSTYLESTRUCT : window style information
6837 * RETURN:
6838 * Zero
6840 static INT LISTVIEW_StyleChanged(HWND hwnd, WPARAM wStyleType,
6841 LPSTYLESTRUCT lpss)
6843 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6844 UINT uNewView = lpss->styleNew & LVS_TYPEMASK;
6845 UINT uOldView = lpss->styleOld & LVS_TYPEMASK;
6846 RECT rcList = infoPtr->rcList;
6848 TRACE("(hwnd=%x, styletype=%x, stylestruct=%p)\n",
6849 hwnd, wStyleType, lpss);
6851 if (wStyleType == GWL_STYLE)
6853 if (uOldView == LVS_REPORT)
6855 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
6858 if ((lpss->styleOld & WS_HSCROLL) != 0)
6860 ShowScrollBar(hwnd, SB_HORZ, FALSE);
6863 if ((lpss->styleOld & WS_VSCROLL) != 0)
6865 ShowScrollBar(hwnd, SB_VERT, FALSE);
6868 if (uNewView == LVS_ICON)
6870 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
6871 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
6872 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6873 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6874 if (lpss->styleNew & LVS_ALIGNLEFT)
6876 LISTVIEW_AlignLeft(hwnd);
6878 else
6880 LISTVIEW_AlignTop(hwnd);
6883 else if (uNewView == LVS_REPORT)
6885 HDLAYOUT hl;
6886 WINDOWPOS wp;
6888 hl.prc = &rcList;
6889 hl.pwpos = &wp;
6890 Header_Layout(infoPtr->hwndHeader, &hl);
6891 SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, wp.cy,
6892 wp.flags);
6893 if (!(LVS_NOCOLUMNHEADER & lpss->styleNew))
6895 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
6897 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6898 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6899 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6900 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6902 else if (uNewView == LVS_LIST)
6904 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6905 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6906 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6907 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6909 else
6911 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6912 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6913 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6914 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6915 if (lpss->styleNew & LVS_ALIGNLEFT)
6917 LISTVIEW_AlignLeft(hwnd);
6919 else
6921 LISTVIEW_AlignTop(hwnd);
6925 /* update the size of the client area */
6926 LISTVIEW_UpdateSize(hwnd);
6928 /* add scrollbars if needed */
6929 LISTVIEW_UpdateScroll(hwnd);
6931 /* invalidate client area + erase background */
6932 InvalidateRect(hwnd, NULL, TRUE);
6934 /* print the list of unsupported window styles */
6935 LISTVIEW_UnsupportedStyles(lpss->styleNew);
6938 return 0;
6941 /***
6942 * DESCRIPTION:
6943 * Window procedure of the listview control.
6946 static LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
6947 LPARAM lParam)
6949 switch (uMsg)
6951 case LVM_APPROXIMATEVIEWRECT:
6952 return LISTVIEW_ApproximateViewRect(hwnd, (INT)wParam,
6953 LOWORD(lParam), HIWORD(lParam));
6954 case LVM_ARRANGE:
6955 return LISTVIEW_Arrange(hwnd, (INT)wParam);
6957 /* case LVM_CREATEDRAGIMAGE: */
6959 case LVM_DELETEALLITEMS:
6960 return LISTVIEW_DeleteAllItems(hwnd);
6962 case LVM_DELETECOLUMN:
6963 return LISTVIEW_DeleteColumn(hwnd, (INT)wParam);
6965 case LVM_DELETEITEM:
6966 return LISTVIEW_DeleteItem(hwnd, (INT)wParam);
6968 case LVM_EDITLABELW:
6969 case LVM_EDITLABELA:
6970 return LISTVIEW_EditLabelA(hwnd, (INT)wParam);
6972 case LVM_ENSUREVISIBLE:
6973 return LISTVIEW_EnsureVisible(hwnd, (INT)wParam, (BOOL)lParam);
6975 case LVM_FINDITEMA:
6976 return LISTVIEW_FindItem(hwnd, (INT)wParam, (LPLVFINDINFO)lParam);
6978 case LVM_GETBKCOLOR:
6979 return LISTVIEW_GetBkColor(hwnd);
6981 /* case LVM_GETBKIMAGE: */
6983 case LVM_GETCALLBACKMASK:
6984 return LISTVIEW_GetCallbackMask(hwnd);
6986 case LVM_GETCOLUMNA:
6987 return LISTVIEW_GetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
6989 /* case LVM_GETCOLUMNW: */
6991 case LVM_GETCOLUMNORDERARRAY:
6992 FIXME("Unimplemented msg LVM_GETCOLUMNORDERARRAY\n");
6993 return 0;
6995 case LVM_GETCOLUMNWIDTH:
6996 return LISTVIEW_GetColumnWidth(hwnd, (INT)wParam);
6998 case LVM_GETCOUNTPERPAGE:
6999 return LISTVIEW_GetCountPerPage(hwnd);
7001 case LVM_GETEDITCONTROL:
7002 return LISTVIEW_GetEditControl(hwnd);
7004 case LVM_GETEXTENDEDLISTVIEWSTYLE:
7005 return LISTVIEW_GetExtendedListViewStyle(hwnd);
7007 case LVM_GETHEADER:
7008 return LISTVIEW_GetHeader(hwnd);
7010 /* case LVM_GETHOTCURSOR: */
7012 case LVM_GETHOTITEM:
7013 return LISTVIEW_GetHotItem(hwnd);
7015 /* case LVM_GETHOVERTIME: */
7017 case LVM_GETIMAGELIST:
7018 return LISTVIEW_GetImageList(hwnd, (INT)wParam);
7020 /* case LVM_GETISEARCHSTRING: */
7022 case LVM_GETITEMA:
7023 return LISTVIEW_GetItemA(hwnd, (LPLVITEMA)lParam);
7025 /* case LVM_GETITEMW: */
7027 case LVM_GETITEMCOUNT:
7028 return LISTVIEW_GetItemCount(hwnd);
7030 case LVM_GETITEMPOSITION:
7031 return LISTVIEW_GetItemPosition(hwnd, (INT)wParam, (LPPOINT)lParam);
7033 case LVM_GETITEMRECT:
7034 return LISTVIEW_GetItemRect(hwnd, (INT)wParam, (LPRECT)lParam);
7036 case LVM_GETITEMSPACING:
7037 return LISTVIEW_GetItemSpacing(hwnd, (BOOL)wParam);
7039 case LVM_GETITEMSTATE:
7040 return LISTVIEW_GetItemState(hwnd, (INT)wParam, (UINT)lParam);
7042 case LVM_GETITEMTEXTA:
7043 LISTVIEW_GetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
7044 break;
7046 /* case LVM_GETITEMTEXTW: */
7048 case LVM_GETNEXTITEM:
7049 return LISTVIEW_GetNextItem(hwnd, (INT)wParam, LOWORD(lParam));
7051 /* case LVM_GETNUMBEROFWORKAREAS: */
7053 case LVM_GETORIGIN:
7054 return LISTVIEW_GetOrigin(hwnd, (LPPOINT)lParam);
7056 case LVM_GETSELECTEDCOUNT:
7057 return LISTVIEW_GetSelectedCount(hwnd);
7059 case LVM_GETSELECTIONMARK:
7060 return LISTVIEW_GetSelectionMark(hwnd);
7062 case LVM_GETSTRINGWIDTHA:
7063 return LISTVIEW_GetStringWidthA (hwnd, (LPCSTR)lParam);
7065 /* case LVM_GETSTRINGWIDTHW: */
7066 /* case LVM_GETSUBITEMRECT: */
7068 case LVM_GETTEXTBKCOLOR:
7069 return LISTVIEW_GetTextBkColor(hwnd);
7071 case LVM_GETTEXTCOLOR:
7072 return LISTVIEW_GetTextColor(hwnd);
7074 /* case LVM_GETTOOLTIPS: */
7076 case LVM_GETTOPINDEX:
7077 return LISTVIEW_GetTopIndex(hwnd);
7079 /* case LVM_GETUNICODEFORMAT: */
7081 case LVM_GETVIEWRECT:
7082 return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam);
7084 /* case LVM_GETWORKAREAS: */
7086 case LVM_HITTEST:
7087 return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam);
7089 case LVM_INSERTCOLUMNA:
7090 return LISTVIEW_InsertColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
7092 case LVM_INSERTCOLUMNW:
7093 return LISTVIEW_InsertColumnW(hwnd, (INT)wParam, (LPLVCOLUMNW)lParam);
7095 case LVM_INSERTITEMA:
7096 return LISTVIEW_InsertItemA(hwnd, (LPLVITEMA)lParam);
7098 case LVM_INSERTITEMW:
7099 return LISTVIEW_InsertItemW(hwnd, (LPLVITEMW)lParam);
7101 case LVM_REDRAWITEMS:
7102 return LISTVIEW_RedrawItems(hwnd, (INT)wParam, (INT)lParam);
7104 /* case LVM_SCROLL: */
7105 /* return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); */
7107 case LVM_SETBKCOLOR:
7108 return LISTVIEW_SetBkColor(hwnd, (COLORREF)lParam);
7110 /* case LVM_SETBKIMAGE: */
7112 case LVM_SETCALLBACKMASK:
7113 return LISTVIEW_SetCallbackMask(hwnd, (UINT)wParam);
7115 case LVM_SETCOLUMNA:
7116 return LISTVIEW_SetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
7118 case LVM_SETCOLUMNW:
7119 FIXME("Unimplemented msg LVM_SETCOLUMNW\n");
7120 return 0;
7122 case LVM_SETCOLUMNORDERARRAY:
7123 FIXME("Unimplemented msg LVM_SETCOLUMNORDERARRAY\n");
7124 return 0;
7126 case LVM_SETCOLUMNWIDTH:
7127 return LISTVIEW_SetColumnWidth(hwnd, (INT)wParam, (INT)lParam);
7129 case LVM_SETEXTENDEDLISTVIEWSTYLE:
7130 return LISTVIEW_SetExtendedListViewStyle(hwnd, (DWORD)wParam, (DWORD)lParam);
7132 /* case LVM_SETHOTCURSOR: */
7134 case LVM_SETHOTITEM:
7135 return LISTVIEW_SetHotItem(hwnd, (INT)wParam);
7137 /* case LVM_SETHOVERTIME: */
7138 /* case LVM_SETICONSPACING: */
7140 case LVM_SETIMAGELIST:
7141 return LISTVIEW_SetImageList(hwnd, (INT)wParam, (HIMAGELIST)lParam);
7143 case LVM_SETITEMA:
7144 return LISTVIEW_SetItemA(hwnd, (LPLVITEMA)lParam);
7146 /* case LVM_SETITEMW: */
7148 case LVM_SETITEMCOUNT:
7149 return LISTVIEW_SetItemCount(hwnd, (INT)wParam, (DWORD)lParam);
7151 case LVM_SETITEMPOSITION:
7152 return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, (INT)LOWORD(lParam),
7153 (INT)HIWORD(lParam));
7155 /* case LVM_SETITEMPOSITION32: */
7157 case LVM_SETITEMSTATE:
7158 return LISTVIEW_SetItemState(hwnd, (INT)wParam, (LPLVITEMA)lParam);
7160 case LVM_SETITEMTEXTA:
7161 return LISTVIEW_SetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
7163 /* case LVM_SETITEMTEXTW: */
7165 case LVM_SETSELECTIONMARK:
7166 return LISTVIEW_SetSelectionMark(hwnd, (INT)lParam);
7168 case LVM_SETTEXTBKCOLOR:
7169 return LISTVIEW_SetTextBkColor(hwnd, (COLORREF)lParam);
7171 case LVM_SETTEXTCOLOR:
7172 return LISTVIEW_SetTextColor(hwnd, (COLORREF)lParam);
7174 /* case LVM_SETTOOLTIPS: */
7175 /* case LVM_SETUNICODEFORMAT: */
7176 /* case LVM_SETWORKAREAS: */
7178 case LVM_SORTITEMS:
7179 return LISTVIEW_SortItems(hwnd, wParam, lParam);
7181 /* case LVM_SUBITEMHITTEST: */
7183 case LVM_UPDATE:
7184 return LISTVIEW_Update(hwnd, (INT)wParam);
7186 /* case WM_CHAR: */
7187 case WM_COMMAND:
7188 return LISTVIEW_Command(hwnd, wParam, lParam);
7190 case WM_CREATE:
7191 return LISTVIEW_Create(hwnd, wParam, lParam);
7193 case WM_ERASEBKGND:
7194 return LISTVIEW_EraseBackground(hwnd, wParam, lParam);
7196 case WM_GETDLGCODE:
7197 return DLGC_WANTCHARS | DLGC_WANTARROWS;
7199 case WM_GETFONT:
7200 return LISTVIEW_GetFont(hwnd);
7202 case WM_HSCROLL:
7203 return LISTVIEW_HScroll(hwnd, (INT)LOWORD(wParam),
7204 (INT)HIWORD(wParam), (HWND)lParam);
7206 case WM_KEYDOWN:
7207 return LISTVIEW_KeyDown(hwnd, (INT)wParam, (LONG)lParam);
7209 case WM_KILLFOCUS:
7210 return LISTVIEW_KillFocus(hwnd);
7212 case WM_LBUTTONDBLCLK:
7213 return LISTVIEW_LButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
7214 HIWORD(lParam));
7216 case WM_LBUTTONDOWN:
7217 return LISTVIEW_LButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
7218 HIWORD(lParam));
7219 case WM_LBUTTONUP:
7220 return LISTVIEW_LButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
7221 HIWORD(lParam));
7223 /* case WM_MOUSEMOVE: */
7224 /* return LISTVIEW_MouseMove (hwnd, wParam, lParam); */
7226 case WM_NCCREATE:
7227 return LISTVIEW_NCCreate(hwnd, wParam, lParam);
7229 case WM_NCDESTROY:
7230 return LISTVIEW_NCDestroy(hwnd);
7232 case WM_NOTIFY:
7233 return LISTVIEW_Notify(hwnd, (INT)wParam, (LPNMHDR)lParam);
7235 case WM_NOTIFYFORMAT:
7236 return LISTVIEW_NotifyFormat(hwnd, (HWND)wParam, (INT)lParam);
7238 case WM_PAINT:
7239 return LISTVIEW_Paint(hwnd, (HDC)wParam);
7241 case WM_RBUTTONDBLCLK:
7242 return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
7243 HIWORD(lParam));
7245 case WM_RBUTTONDOWN:
7246 return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
7247 HIWORD(lParam));
7249 case WM_RBUTTONUP:
7250 return LISTVIEW_RButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
7251 HIWORD(lParam));
7253 case WM_SETFOCUS:
7254 return LISTVIEW_SetFocus(hwnd, (HWND)wParam);
7256 case WM_SETFONT:
7257 return LISTVIEW_SetFont(hwnd, (HFONT)wParam, (WORD)lParam);
7259 /* case WM_SETREDRAW: */
7261 case WM_SIZE:
7262 return LISTVIEW_Size(hwnd, (int)SLOWORD(lParam), (int)SHIWORD(lParam));
7264 case WM_STYLECHANGED:
7265 return LISTVIEW_StyleChanged(hwnd, wParam, (LPSTYLESTRUCT)lParam);
7267 /* case WM_TIMER: */
7269 case WM_VSCROLL:
7270 return LISTVIEW_VScroll(hwnd, (INT)LOWORD(wParam),
7271 (INT)HIWORD(wParam), (HWND)lParam);
7273 /* case WM_WINDOWPOSCHANGED: */
7274 /* case WM_WININICHANGE: */
7276 default:
7277 if (uMsg >= WM_USER)
7279 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam,
7280 lParam);
7283 /* call default window procedure */
7284 return DefWindowProcA(hwnd, uMsg, wParam, lParam);
7287 return 0;
7290 /***
7291 * DESCRIPTION:
7292 * Registers the window class.
7294 * PARAMETER(S):
7295 * None
7297 * RETURN:
7298 * None
7300 VOID LISTVIEW_Register(void)
7302 WNDCLASSA wndClass;
7304 if (!GlobalFindAtomA(WC_LISTVIEWA))
7306 ZeroMemory(&wndClass, sizeof(WNDCLASSA));
7307 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
7308 wndClass.lpfnWndProc = (WNDPROC)LISTVIEW_WindowProc;
7309 wndClass.cbClsExtra = 0;
7310 wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *);
7311 wndClass.hCursor = LoadCursorA(0, IDC_ARROWA);
7312 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
7313 wndClass.lpszClassName = WC_LISTVIEWA;
7314 RegisterClassA(&wndClass);
7318 /***
7319 * DESCRIPTION:
7320 * Unregisters the window class.
7322 * PARAMETER(S):
7323 * None
7325 * RETURN:
7326 * None
7328 VOID LISTVIEW_Unregister(void)
7330 if (GlobalFindAtomA(WC_LISTVIEWA))
7332 UnregisterClassA(WC_LISTVIEWA, (HINSTANCE)NULL);
7336 /***
7337 * DESCRIPTION:
7338 * Handle any WM_COMMAND messages
7340 * PARAMETER(S):
7342 * RETURN:
7344 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam)
7346 switch (HIWORD(wParam))
7348 case EN_UPDATE:
7351 * Adjust the edit window size
7353 char buffer[1024];
7354 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7355 HDC hdc = GetDC(infoPtr->hwndEdit);
7356 RECT rect;
7357 SIZE sz;
7359 GetWindowTextA(infoPtr->hwndEdit, buffer, 1024);
7360 GetWindowRect(infoPtr->hwndEdit, &rect);
7361 if (GetTextExtentPoint32A(hdc, buffer, strlen(buffer), &sz))
7363 SetWindowPos (
7364 infoPtr->hwndEdit,
7365 HWND_TOP,
7368 sz.cx + 15,
7369 rect.bottom - rect.top,
7370 SWP_DRAWFRAME|SWP_NOMOVE);
7372 ReleaseDC(hwnd, hdc);
7374 break;
7377 default:
7378 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
7381 return 0;
7385 /***
7386 * DESCRIPTION:
7387 * Subclassed edit control windproc function
7389 * PARAMETER(S):
7391 * RETURN:
7393 LRESULT CALLBACK EditLblWndProc(HWND hwnd, UINT uMsg,
7394 WPARAM wParam, LPARAM lParam)
7396 BOOL cancel = TRUE;
7397 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(GetParent(hwnd), 0);
7398 EDITLABEL_ITEM *einfo = infoPtr->pedititem;
7400 switch (uMsg)
7402 case WM_GETDLGCODE:
7403 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
7405 case WM_KILLFOCUS:
7406 break;
7408 case WM_DESTROY:
7410 WNDPROC editProc = einfo->EditWndProc;
7411 SetWindowLongA(hwnd, GWL_WNDPROC, (LONG)editProc);
7412 COMCTL32_Free(einfo);
7413 infoPtr->pedititem = NULL;
7414 return CallWindowProcA(editProc, hwnd, uMsg, wParam, lParam);
7417 case WM_CHAR:
7418 if (VK_RETURN == (INT)wParam)
7420 cancel = FALSE;
7421 break;
7423 else if (VK_ESCAPE == (INT)wParam)
7424 break;
7426 default:
7427 return CallWindowProcA(einfo->EditWndProc, hwnd,
7428 uMsg, wParam, lParam);
7431 if (einfo->EditLblCb)
7433 char *buffer = NULL;
7435 if (!cancel)
7437 int len = 1 + GetWindowTextLengthA(hwnd);
7439 if (len > 1)
7441 if (NULL != (buffer = (char *)COMCTL32_Alloc(len*sizeof(char))))
7443 GetWindowTextA(hwnd, buffer, len);
7448 einfo->EditLblCb(GetParent(hwnd), buffer, einfo->param);
7450 if (buffer)
7451 COMCTL32_Free(buffer);
7453 einfo->EditLblCb = NULL;
7456 SendMessageA(hwnd, WM_CLOSE, 0, 0);
7457 return TRUE;
7461 /***
7462 * DESCRIPTION:
7463 * Creates a subclassed edit cotrol
7465 * PARAMETER(S):
7467 * RETURN:
7469 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
7470 INT width, INT height, HWND parent, HINSTANCE hinst,
7471 EditlblCallback EditLblCb, DWORD param)
7473 HWND hedit;
7474 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(parent, 0);
7475 if (NULL == (infoPtr->pedititem = COMCTL32_Alloc(sizeof(EDITLABEL_ITEM))))
7476 return 0;
7478 style |= WS_CHILDWINDOW|WS_CLIPSIBLINGS|ES_LEFT|WS_BORDER;
7479 if (!(hedit = CreateWindowA("Edit", text, style, x, y, width, height,
7480 parent, 0, hinst, 0)))
7482 COMCTL32_Free(infoPtr->pedititem);
7483 return 0;
7486 infoPtr->pedititem->param = param;
7487 infoPtr->pedititem->EditLblCb = EditLblCb;
7488 infoPtr->pedititem->EditWndProc = (WNDPROC)SetWindowLongA(hedit,
7489 GWL_WNDPROC, (LONG) EditLblWndProc);
7491 return hedit;