Authors: Chris Morgan <cmorgan@wpi.edu>, James Abbatiello <abbeyj@wpi.edu>
[wine/multimedia.git] / dlls / comctl32 / listview.c
blobc376432ad68701887196cdfc2b838eed01bd206c
1 /*
2 * Listview control
4 * Copyright 1998 Eric Kohl
5 * Copyright 1999 Luc Tourangeau
7 * NOTES
8 * Listview control implementation.
10 * TODO:
12 * 1. Multiple selections in icon or small icon display modes DO NOT
13 * behave like the Microsoft control.
14 * 2. No horizontal scrolling when header is larger than the client area.
15 * 3. Implement LVM_FINDITEM for key selections.
16 * 4. Drawing optimizations.
18 * Notifications:
19 * LISTVIEW_Notify : most notifications from children (editbox and header)
21 * Data structure:
22 * LISTVIEW_SortItems : empty stub
23 * LISTVIEW_SetItemCount : empty stub
25 * Unicode:
26 * LISTVIEW_SetItem32W : no unicode support
27 * LISTVIEW_InsertItem32W : no unicode support
28 * LISTVIEW_InsertColumn32W : no unicode support
29 * LISTVIEW_GetColumnW : no unicode support
31 * Advanced functionality:
32 * LISTVIEW_GetNumberOfWorkAreas : not implemented
33 * LISTVIEW_GetHotCursor : not implemented
34 * LISTVIEW_GetHotItem : not implemented
35 * LISTVIEW_GetHoverTime : not implemented
36 * LISTVIEW_GetISearchString : not implemented
37 * LISTVIEW_GetBkImage : not implemented
38 * LISTVIEW_EditLabel : REPORT (need to implement a timer)
39 * LISTVIEW_GetColumnOrderArray : not implemented
40 * LISTVIEW_Arrange : empty stub
41 * LISTVIEW_FindItem : empty stub
42 * LISTVIEW_ApproximateViewRect : incomplete
43 * LISTVIEW_Scroll : not implemented
44 * LISTVIEW_KeyDown : page up and page down + redo small icon and icon
45 * LISTVIEW_RedrawItems : empty stub
46 * LISTVIEW_Update : not completed
49 #include <string.h>
50 #include "winbase.h"
51 #include "commctrl.h"
52 #include "listview.h"
53 #include "debug.h"
55 DEFAULT_DEBUG_CHANNEL(listview)
58 * constants
61 /* maximum size of a label */
62 #define DISP_TEXT_SIZE 128
64 /* padding for items in list and small icon display modes */
65 #define WIDTH_PADDING 12
67 /* padding for items in list, report and small icon display modes */
68 #define HEIGHT_PADDING 1
70 /* offset of items in report display mode */
71 #define REPORT_MARGINX 2
73 /* padding for icon in large icon display mode */
74 #define ICON_TOP_PADDING 2
75 #define ICON_BOTTOM_PADDING 2
77 /* padding for label in large icon display mode */
78 #define LABEL_VERT_OFFSET 2
80 /* default label width for items in list and small icon display modes */
81 #define DEFAULT_LABEL_WIDTH 40
83 /* default column width for items in list display mode */
84 #define DEFAULT_COLUMN_WIDTH 96
86 /*
87 * macros
90 /* retrieve the number of items in the listview */
91 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
92 #define ListView_LVNotify(hwnd,lCtrlId,plvnm) \
93 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMLISTVIEW)(plvnm))
94 #define ListView_Notify(hwnd,lCtrlId,pnmh) \
95 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMHDR)(pnmh))
97 /*
98 * forward declarations
101 static VOID LISTVIEW_AlignLeft(HWND);
102 static VOID LISTVIEW_AlignTop(HWND);
103 static VOID LISTVIEW_AddGroupSelection(HWND, INT);
104 static VOID LISTVIEW_AddSelection(HWND, INT);
105 static BOOL LISTVIEW_AddSubItem(HWND, LPLVITEMA);
106 static INT LISTVIEW_FindInsertPosition(HDPA, INT);
107 static VOID LISTVIEW_GetItemDispInfo(HWND, INT, LISTVIEW_ITEM *lpItem, INT *,
108 UINT *, CHAR **, INT);
109 static INT LISTVIEW_GetItemHeight(HWND, LONG);
110 static BOOL LISTVIEW_GetItemPosition(HWND, INT, LPPOINT);
111 static LRESULT LISTVIEW_GetItemRect(HWND, INT, LPRECT);
112 static INT LISTVIEW_GetItemWidth(HWND, LONG);
113 static INT LISTVIEW_GetLabelWidth(HWND, INT);
114 static LRESULT LISTVIEW_GetOrigin(HWND, LPPOINT);
115 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA, INT);
116 static VOID LISTVIEW_GetSubItemDispInfo(HWND hwnd, INT, LPARAM,
117 LISTVIEW_SUBITEM *, INT, INT *,
118 CHAR **, 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, INT, INT);
123 static BOOL LISTVIEW_RemoveColumn(HDPA, INT);
124 static VOID LISTVIEW_RemoveSelections(HWND, INT, INT);
125 static BOOL LISTVIEW_RemoveSubItem(HDPA, INT);
126 static BOOL LISTVIEW_ScrollView(HWND, INT, INT);
127 static VOID LISTVIEW_SetGroupSelection(HWND, INT);
128 static BOOL LISTVIEW_SetItem(HWND, LPLVITEMA);
129 static VOID LISTVIEW_SetItemFocus(HWND, INT);
130 static BOOL LISTVIEW_SetItemPosition(HWND, INT, INT, INT);
131 static VOID LISTVIEW_SetScroll(HWND, LONG);
132 static VOID LISTVIEW_SetSelection(HWND, INT);
133 static VOID LISTVIEW_SetSize(HWND, LONG, LONG, LONG);
134 static BOOL LISTVIEW_SetSubItem(HWND, LPLVITEMA);
135 static VOID LISTVIEW_SetViewInfo(HWND, LONG);
136 static LRESULT LISTVIEW_SetViewRect(HWND, LPRECT);
137 static BOOL LISTVIEW_ToggleSelection(HWND, INT);
138 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle);
140 /***
141 * DESCRIPTION:
142 * Scrolls the content of the listview.
144 * PARAMETER(S):
145 * [I] HWND : window handle
146 * [I] INT : number of horizontal scroll positions
147 * (relative to the current scroll postioon)
148 * [I] INT : number of vertical scroll positions
149 * (relative to the current scroll postioon)
151 * RETURN:
152 * SUCCESS : TRUE
153 * FAILURE : FALSE
155 static BOOL LISTVIEW_ScrollView(HWND hwnd, INT nHScroll, INT nVScroll)
157 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
158 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
159 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
160 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
161 INT nHScrollPos = 0;
162 INT nVScrollPos = 0;
163 INT nHScrollInc = 0;
164 INT nVScrollInc = 0;
165 BOOL bResult = FALSE;
167 if (((lStyle & WS_HSCROLL) != 0) && (nHScroll != 0))
169 switch (LVS_TYPEMASK & lStyle)
171 case LVS_LIST:
172 nHScrollInc = nHScroll * infoPtr->nItemWidth;
173 break;
175 case LVS_REPORT:
176 /* TO DO : not implemented at this point. I experiences some
177 problems when performing child window scrolling. */
178 break;
180 case LVS_SMALLICON:
181 case LVS_ICON:
182 nHScrollInc = nHScroll * max(nListWidth, nListWidth / 10);
183 break;
186 nHScrollPos = GetScrollPos(hwnd, SB_HORZ) + nHScroll;
189 if (((lStyle & WS_VSCROLL) != 0) & (nVScroll != 0))
191 switch (LVS_TYPEMASK & lStyle)
193 case LVS_REPORT:
194 nVScrollInc = nVScroll * infoPtr->nItemHeight;
195 nVScrollPos = GetScrollPos(hwnd, SB_VERT) + nVScroll;
196 break;
198 case LVS_SMALLICON:
199 case LVS_ICON:
200 nVScrollInc = nVScroll * max(nListHeight, nListHeight / 10);
201 nVScrollPos = GetScrollPos(hwnd, SB_VERT) + nVScroll;
202 break;
206 /* perform scroll operation & set new scroll position */
207 if ((nHScrollInc != 0) || (nVScrollInc != 0))
209 RECT rc;
210 HDC hdc = GetDC(hwnd);
211 ScrollDC(hdc, -nHScrollInc, -nVScrollInc, &infoPtr->rcList, NULL,
212 (HRGN) NULL, &rc);
213 InvalidateRect(hwnd, &rc, TRUE);
214 SetScrollPos(hwnd, SB_HORZ, nHScrollPos, TRUE);
215 SetScrollPos(hwnd, SB_VERT, nVScrollPos, TRUE);
216 ReleaseDC(hwnd, hdc);
217 bResult = TRUE;
220 return bResult;
223 /***
224 * DESCRIPTION:
225 * Prints a message for unsupported window styles.
226 * A kind of TODO list for window styles.
228 * PARAMETER(S):
229 * [I] LONG : window style
231 * RETURN:
232 * None
234 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle)
236 if ((LVS_TYPEMASK & lStyle) == LVS_EDITLABELS)
238 FIXME( listview, " LVS_EDITLABELS\n");
241 if ((LVS_TYPEMASK & lStyle) == LVS_NOCOLUMNHEADER)
243 FIXME( listview, " LVS_SORTDESCENDING\n");
246 if ((LVS_TYPEMASK & lStyle) == LVS_NOLABELWRAP)
248 FIXME( listview, " LVS_NOLABELWRAP\n");
251 if ((LVS_TYPEMASK & lStyle) == LVS_NOSCROLL)
253 FIXME( listview, " LVS_NOSCROLL\n");
256 if ((LVS_TYPEMASK & lStyle) == LVS_NOSORTHEADER)
258 FIXME( listview, " LVS_NOSORTHEADER\n");
261 if ((LVS_TYPEMASK & lStyle) == LVS_OWNERDRAWFIXED)
263 FIXME( listview, " LVS_OWNERDRAWFIXED\n");
266 if ((LVS_TYPEMASK & lStyle) == LVS_SHAREIMAGELISTS)
268 FIXME( listview, " LVS_SHAREIMAGELISTS\n");
271 if ((LVS_TYPEMASK & lStyle) == LVS_SHOWSELALWAYS)
273 FIXME( listview, " LVS_SHOWSELALWAYS\n");
276 if ((LVS_TYPEMASK & lStyle) == LVS_SINGLESEL)
278 FIXME( listview, " LVS_SINGLESEL\n");
281 if ((LVS_TYPEMASK & lStyle) == LVS_SORTASCENDING)
283 FIXME( listview, " LVS_SORTASCENDING\n");
286 if ((LVS_TYPEMASK & lStyle) == LVS_SORTDESCENDING)
288 FIXME( listview, " LVS_SORTDESCENDING\n");
292 /***
293 * DESCRIPTION:
294 * Aligns the items with the top edge of the window.
296 * PARAMETER(S):
297 * [I] HWND : window handle
299 * RETURN:
300 * None
302 static VOID LISTVIEW_AlignTop(HWND hwnd)
304 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
305 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
306 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
307 POINT ptItem;
308 RECT rcView;
309 INT i;
311 switch (LVS_TYPEMASK & lStyle)
313 case LVS_SMALLICON:
314 case LVS_ICON:
315 ZeroMemory(&ptItem, sizeof(POINT));
316 ZeroMemory(&rcView, sizeof(RECT));
317 if (nListWidth > infoPtr->nItemWidth)
319 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
321 if (ptItem.x + infoPtr->nItemWidth > nListWidth)
323 ptItem.x = 0;
324 ptItem.y += infoPtr->nItemHeight;
327 LISTVIEW_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
328 ptItem.x += infoPtr->nItemWidth;
329 rcView.right = max(rcView.right, ptItem.x);
332 else
334 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
336 LISTVIEW_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
337 ptItem.x += infoPtr->nItemWidth;
339 rcView.right = ptItem.x;
340 rcView.bottom = infoPtr->nItemHeight;
343 rcView.bottom = ptItem.y + infoPtr->nItemHeight;
344 LISTVIEW_SetViewRect(hwnd, &rcView);
348 /***
349 * DESCRIPTION:
350 * Aligns the items with the left edge of the window.
352 * PARAMETER(S):
353 * [I] HWND : window handle
355 * RETURN:
356 * None
358 static VOID LISTVIEW_AlignLeft(HWND hwnd)
360 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
361 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
362 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
363 POINT ptItem;
364 RECT rcView;
365 INT i;
367 switch (LVS_TYPEMASK & lStyle)
369 case LVS_SMALLICON:
370 case LVS_ICON:
371 ZeroMemory(&ptItem, sizeof(POINT));
372 ZeroMemory(&rcView, sizeof(RECT));
373 if (nListHeight > infoPtr->nItemHeight)
375 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
377 if (ptItem.y + infoPtr->nItemHeight > nListHeight)
379 ptItem.y = 0;
380 ptItem.x += infoPtr->nItemWidth;
383 LISTVIEW_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
384 ptItem.y += infoPtr->nItemHeight;
385 rcView.bottom = max(rcView.bottom, ptItem.y);
388 else
390 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
392 LISTVIEW_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
393 ptItem.y += infoPtr->nItemHeight;
395 rcView.bottom = ptItem.y;
396 rcView.right = infoPtr->nItemWidth;
399 rcView.right = ptItem.x + infoPtr->nItemWidth;
400 LISTVIEW_SetViewRect(hwnd, &rcView);
401 break;
405 /***
406 * DESCRIPTION:
407 * Retrieves display information.
409 * PARAMETER(S):
410 * [I] HWND : window handle
411 * [I] INT : item index
412 * [I] LISTVIEW_ITEM* : listview control item
413 * [O] INT : image index
414 * [O] UINT : state value
415 * [O] CHAR** : string
416 * [I] INT : size of string
418 * RETURN:
419 * None
421 static VOID LISTVIEW_GetItemDispInfo(HWND hwnd, INT nItem,
422 LISTVIEW_ITEM *lpItem, INT *pnDispImage,
423 UINT *puState, CHAR **ppszDispText,
424 INT nDispTextSize)
426 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
427 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
428 NMLVDISPINFOA dispInfo;
429 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
431 if ((pnDispImage != NULL) && (lpItem->iImage == I_IMAGECALLBACK))
433 dispInfo.item.mask |= LVIF_IMAGE;
436 if ((ppszDispText != NULL) && (lpItem->pszText == LPSTR_TEXTCALLBACKA))
438 ZeroMemory(*ppszDispText, sizeof(CHAR)*nDispTextSize);
439 dispInfo.item.mask |= LVIF_TEXT;
440 dispInfo.item.pszText = *ppszDispText;
441 dispInfo.item.cchTextMax = nDispTextSize;
444 if ((puState != NULL) && (infoPtr->uCallbackMask != 0))
446 dispInfo.item.mask |= LVIF_STATE;
447 dispInfo.item.stateMask = infoPtr->uCallbackMask;
450 if (dispInfo.item.mask != 0)
452 dispInfo.hdr.hwndFrom = hwnd;
453 dispInfo.hdr.idFrom = lCtrlId;
454 dispInfo.hdr.code = LVN_GETDISPINFOA;
455 dispInfo.item.iItem = nItem;
456 dispInfo.item.iSubItem = 0;
457 dispInfo.item.lParam = lpItem->lParam;
458 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
461 if (pnDispImage != NULL)
463 if (dispInfo.item.mask & LVIF_IMAGE)
465 *pnDispImage = dispInfo.item.iImage;
467 else
469 *pnDispImage = lpItem->iImage;
473 if (ppszDispText != NULL)
475 if (dispInfo.item.mask & LVIF_TEXT)
477 if (dispInfo.item.mask & LVIF_DI_SETITEM)
479 Str_SetPtrA(&lpItem->pszText, dispInfo.item.pszText);
481 *ppszDispText = dispInfo.item.pszText;
483 else
485 *ppszDispText = lpItem->pszText;
489 if (puState != NULL)
491 if (dispInfo.item.mask & LVIF_STATE)
493 *puState = lpItem->state;
494 *puState &= ~dispInfo.item.stateMask;
495 *puState |= (dispInfo.item.state & dispInfo.item.stateMask);
497 else
499 *puState = lpItem->state;
504 /***
505 * DESCRIPTION:
506 * Retrieves subitem display information.
508 * PARAMETER(S):
509 * [I] HWND : window handle
510 * [I] INT : item index
511 * [I] LONG : LPARAM of item
512 * [I] LISTVIEW_SUBITEM* : listview control subitem
513 * [I] INT : subitem position/order
514 * [O] INT : image index
515 * [O] UINT : state value
516 * [O] CHAR** : display string
517 * [I] INT : size of string
519 * RETURN:
520 * None
522 static VOID LISTVIEW_GetSubItemDispInfo(HWND hwnd, INT nItem, LPARAM lParam,
523 LISTVIEW_SUBITEM *lpSubItem,
524 INT nSubItemPos, INT *pnDispImage,
525 CHAR **ppszDispText, INT nDispTextSize)
527 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
528 NMLVDISPINFOA dispInfo;
529 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
531 if (lpSubItem == NULL)
533 ZeroMemory(*ppszDispText, sizeof(CHAR)*nDispTextSize);
534 dispInfo.item.mask |= LVIF_TEXT;
535 dispInfo.item.pszText = *ppszDispText;
536 dispInfo.item.cchTextMax = nDispTextSize;
537 dispInfo.hdr.hwndFrom = hwnd;
538 dispInfo.hdr.idFrom = lCtrlId;
539 dispInfo.hdr.code = LVN_GETDISPINFOA;
540 dispInfo.item.iItem = nItem;
541 dispInfo.item.iSubItem = nSubItemPos;
542 dispInfo.item.lParam = lParam;
543 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
544 if (dispInfo.item.mask & LVIF_DI_SETITEM)
546 Str_SetPtrA(&lpSubItem->pszText, dispInfo.item.pszText);
548 *ppszDispText = dispInfo.item.pszText;
550 else
552 if ((pnDispImage != NULL) && (lpSubItem->iImage == I_IMAGECALLBACK))
554 dispInfo.item.mask |= LVIF_IMAGE;
557 if ((ppszDispText != NULL) && (lpSubItem->pszText == LPSTR_TEXTCALLBACKA))
559 ZeroMemory(*ppszDispText, sizeof(CHAR)*nDispTextSize);
560 dispInfo.item.mask |= LVIF_TEXT;
561 dispInfo.item.pszText = *ppszDispText;
562 dispInfo.item.cchTextMax = nDispTextSize;
565 if (dispInfo.item.mask != 0)
567 dispInfo.hdr.hwndFrom = hwnd;
568 dispInfo.hdr.idFrom = lCtrlId;
569 dispInfo.hdr.code = LVN_GETDISPINFOA;
570 dispInfo.item.iItem = nItem;
571 dispInfo.item.iSubItem = lpSubItem->iSubItem;
572 dispInfo.item.lParam = lParam;
573 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
576 if (pnDispImage != NULL)
578 if (dispInfo.item.mask & LVIF_IMAGE)
580 *pnDispImage = dispInfo.item.iImage;
582 else
584 *pnDispImage = lpSubItem->iImage;
588 if (ppszDispText != NULL)
590 if (dispInfo.item.mask & LVIF_TEXT)
592 if (dispInfo.item.mask & LVIF_DI_SETITEM)
594 Str_SetPtrA(&lpSubItem->pszText, dispInfo.item.pszText);
596 *ppszDispText = dispInfo.item.pszText;
598 else
600 *ppszDispText = lpSubItem->pszText;
606 /***
607 * DESCRIPTION:
608 * Calculates the width of an item.
610 * PARAMETER(S):
611 * [I] HWND : window handle
612 * [I] LONG : window style
614 * RETURN:
615 * Returns item width.
617 static INT LISTVIEW_GetItemWidth(HWND hwnd, LONG lStyle)
619 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
620 INT nHeaderItemCount;
621 RECT rcHeaderItem;
622 INT nItemWidth = 0;
623 INT nLabelWidth;
624 INT i;
626 TRACE(listview, "(hwnd=%x,lStyle=%lx)\n", hwnd, lStyle);
628 switch (LVS_TYPEMASK & lStyle)
630 case LVS_ICON:
631 nItemWidth = infoPtr->iconSpacing.cx;
632 break;
634 case LVS_REPORT:
635 /* calculate width of header */
636 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
637 for (i = 0; i < nHeaderItemCount; i++)
639 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
641 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
644 break;
646 case LVS_SMALLICON:
647 case LVS_LIST:
648 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
650 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, i);
651 nItemWidth = max(nItemWidth, nLabelWidth);
654 /* default label size */
655 if (GETITEMCOUNT(infoPtr) == 0)
657 nItemWidth = DEFAULT_COLUMN_WIDTH;
659 else
661 if (nItemWidth == 0)
663 nItemWidth = DEFAULT_LABEL_WIDTH;
665 else
667 /* add padding */
668 nItemWidth += WIDTH_PADDING;
670 if (infoPtr->himlSmall != NULL)
672 nItemWidth += infoPtr->iconSize.cx;
675 if (infoPtr->himlState != NULL)
677 nItemWidth += infoPtr->iconSize.cx;
681 break;
685 return nItemWidth;
688 /***
689 * DESCRIPTION:
690 * Calculates the height of an item.
692 * PARAMETER(S):
693 * [I] HWND : window handle
694 * [I] LONG : window style
696 * RETURN:
697 * Returns item width.
699 static INT LISTVIEW_GetItemHeight(HWND hwnd, LONG lStyle)
701 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
702 INT nItemHeight = 0;
703 TEXTMETRICA tm;
704 HFONT hOldFont;
705 HDC hdc;
707 switch (LVS_TYPEMASK & lStyle)
709 case LVS_ICON:
710 nItemHeight = infoPtr->iconSpacing.cy;
711 break;
713 case LVS_SMALLICON:
714 case LVS_REPORT:
715 case LVS_LIST:
716 hdc = GetDC(hwnd);
717 hOldFont = SelectObject(hdc, infoPtr->hFont);
718 GetTextMetricsA(hdc, &tm);
719 nItemHeight = max(tm.tmHeight, infoPtr->iconSize.cy) + HEIGHT_PADDING;
720 SelectObject(hdc, hOldFont);
721 ReleaseDC(hwnd, hdc);
722 break;
725 return nItemHeight;
728 /***
729 * DESCRIPTION:
730 * Sets diplay information (needed for drawing operations).
732 * PARAMETER(S):
733 * [I] HWND : window handle
735 * RETURN:
736 * None
738 static VOID LISTVIEW_SetViewInfo(HWND hwnd, LONG lStyle)
740 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
741 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
742 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
744 switch (LVS_TYPEMASK & lStyle)
746 case LVS_REPORT:
747 /* get number of fully visible items per column */
748 infoPtr->nCountPerColumn = max(1, nListHeight / infoPtr->nItemHeight);
749 break;
751 case LVS_LIST:
752 /* get number of fully visible items per column */
753 infoPtr->nCountPerColumn = max(1, nListHeight / infoPtr->nItemHeight);
755 /* get number of fully visible items per row */
756 infoPtr->nCountPerRow = max(1, nListWidth / infoPtr->nItemWidth);
757 break;
761 /***
762 * DESCRIPTION:
763 * Adds a block of selections.
765 * PARAMETER(S):
766 * [I] HWND : window handle
767 * [I] INT : item index
769 * RETURN:
770 * None
772 static VOID LISTVIEW_AddGroupSelection(HWND hwnd, INT nItem)
774 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
775 INT nFirst = min(infoPtr->nSelectionMark, nItem);
776 INT nLast = max(infoPtr->nSelectionMark, nItem);
777 LVITEMA lvItem;
778 INT i;
780 lvItem.state = LVIS_SELECTED;
781 lvItem.stateMask= LVIS_SELECTED;
783 for (i = nFirst; i <= nLast; i++)
785 ListView_SetItemState(hwnd, i, &lvItem);
788 LISTVIEW_SetItemFocus(hwnd, nItem);
789 infoPtr->nSelectionMark = nItem;
792 /***
793 * DESCRIPTION:
794 * Adds a single selection.
796 * PARAMETER(S):
797 * [I] HWND : window handle
798 * [I] INT : item index
800 * RETURN:
801 * None
803 static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem)
805 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
806 LVITEMA lvItem;
808 lvItem.state = LVIS_SELECTED;
809 lvItem.stateMask= LVIS_SELECTED;
811 ListView_SetItemState(hwnd, nItem, &lvItem);
813 LISTVIEW_SetItemFocus(hwnd, nItem);
814 infoPtr->nSelectionMark = nItem;
817 /***
818 * DESCRIPTION:
819 * Selects or unselects an item.
821 * PARAMETER(S):
822 * [I] HWND : window handle
823 * [I] INT : item index
825 * RETURN:
826 * SELECT: TRUE
827 * UNSELECT : FALSE
829 static BOOL LISTVIEW_ToggleSelection(HWND hwnd, INT nItem)
831 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
832 BOOL bResult;
833 LVITEMA lvItem;
835 lvItem.stateMask= LVIS_SELECTED;
837 if (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
839 lvItem.state = 0;
840 ListView_SetItemState(hwnd, nItem, &lvItem);
841 bResult = FALSE;
843 else
845 lvItem.state = LVIS_SELECTED;
846 ListView_SetItemState(hwnd, nItem, &lvItem);
847 bResult = TRUE;
850 LISTVIEW_SetItemFocus(hwnd, nItem);
851 infoPtr->nSelectionMark = nItem;
853 return bResult;
856 /***
857 * DESCRIPTION:
858 * Sets a single group selection.
860 * PARAMETER(S):
861 * [I] HWND : window handle
862 * [I] INT : item index
864 * RETURN:
865 * None
867 static VOID LISTVIEW_SetGroupSelection(HWND hwnd, INT nItem)
869 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
870 INT nFirst = min(infoPtr->nSelectionMark, nItem);
871 INT nLast = max(infoPtr->nSelectionMark, nItem);
872 LVITEMA lvItem;
873 INT i;
875 if (nFirst > 0)
877 LISTVIEW_RemoveSelections(hwnd, 0, nFirst - 1);
880 if (nLast < GETITEMCOUNT(infoPtr))
882 LISTVIEW_RemoveSelections(hwnd, nLast + 1, GETITEMCOUNT(infoPtr));
885 lvItem.state = LVIS_SELECTED;
886 lvItem.stateMask = LVIS_SELECTED;
888 for (i = nFirst; i <= nLast; i++)
890 ListView_SetItemState(hwnd, i, &lvItem);
893 LISTVIEW_SetItemFocus(hwnd, nItem);
896 /***
897 * DESCRIPTION:
898 * Manages the item focus.
900 * PARAMETER(S):
901 * [I] HWND : window handle
902 * [I] INT : item index
904 * RETURN:
905 * None
907 static VOID LISTVIEW_SetItemFocus(HWND hwnd, INT nItem)
909 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
910 LVITEMA lvItem;
912 lvItem.state = 0;
913 lvItem.stateMask = LVIS_FOCUSED;
914 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
916 lvItem.state = LVIS_FOCUSED;
917 lvItem.stateMask = LVIS_FOCUSED;
918 ListView_SetItemState(hwnd, nItem, &lvItem);
920 infoPtr->nFocusedItem = nItem;
922 /* if multiple selection is allowed */
923 ListView_EnsureVisible(hwnd, nItem, FALSE);
926 /***
927 * DESCRIPTION:
928 * Sets a single selection.
930 * PARAMETER(S):
931 * [I] HWND : window handle
932 * [I] INT : item index
934 * RETURN:
935 * None
937 static VOID LISTVIEW_SetSelection(HWND hwnd, INT nItem)
939 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
940 LVITEMA lvItem;
942 if (nItem > 0)
944 LISTVIEW_RemoveSelections(hwnd, 0, nItem - 1);
947 if (nItem < GETITEMCOUNT(infoPtr))
949 LISTVIEW_RemoveSelections(hwnd, nItem + 1, GETITEMCOUNT(infoPtr));
952 lvItem.state = 0;
953 lvItem.stateMask = LVIS_FOCUSED;
954 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
956 lvItem.state = LVIS_SELECTED | LVIS_FOCUSED;
957 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
958 ListView_SetItemState(hwnd, nItem, &lvItem);
960 infoPtr->nFocusedItem = nItem;
961 infoPtr->nSelectionMark = nItem;
964 /***
965 * DESCRIPTION:
966 * Set selection(s) with keyboard.
968 * PARAMETER(S):
969 * [I] HWND : window handle
970 * [I] INT : item index
972 * RETURN:
973 * None
975 static VOID LISTVIEW_KeySelection(HWND hwnd, INT nItem)
977 WORD wShift = HIWORD(GetKeyState(VK_SHIFT));
978 WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL));
980 if (wShift)
982 LISTVIEW_SetGroupSelection(hwnd, nItem);
984 else if (wCtrl)
986 LISTVIEW_SetItemFocus(hwnd, nItem);
988 else
990 LISTVIEW_SetSelection(hwnd, nItem);
992 /* if multiple selection is allowed */
993 ListView_EnsureVisible(hwnd, nItem, FALSE);
997 /***
998 * DESCRIPTION:
999 * Determines the selected item.
1001 * PARAMETER(S):
1002 * [I] HWND : window handle
1003 * [I] INT : x ccordinate
1004 * [I] INT : y coordinate
1006 * RETURN:
1007 * SUCCESS : item index
1008 * FAILURE : -1
1010 static LRESULT LISTVIEW_MouseSelection(HWND hwnd, INT nPosX, INT nPosY)
1012 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1013 RECT rcItem;
1014 INT i;
1016 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
1018 rcItem.left = LVIR_SELECTBOUNDS;
1019 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) == TRUE)
1021 if ((rcItem.left <= nPosX) && (nPosX <= rcItem.right) &&
1022 (rcItem.top <= nPosY) && (nPosY <= rcItem.bottom))
1024 return i;
1029 return -1;
1032 /***
1033 * DESCRIPTION:
1034 * Removes all selection states.
1036 * PARAMETER(S):
1037 * [I] HWND : window handle
1038 * [I] INT : item index
1040 * RETURN:
1041 * SUCCCESS : TRUE
1042 * FAILURE : FALSE
1044 static VOID LISTVIEW_RemoveSelections(HWND hwnd, INT nFirst, INT nLast)
1046 LVITEMA lvItem;
1047 INT i;
1049 lvItem.state = 0;
1050 lvItem.stateMask = LVIS_SELECTED;
1052 for (i = nFirst; i <= nLast; i++)
1054 ListView_SetItemState(hwnd, i, &lvItem);
1058 /***
1059 * DESCRIPTION:
1060 * Removes a column.
1062 * PARAMETER(S):
1063 * [IO] HDPA : dynamic pointer array handle
1064 * [I] INT : column index (subitem index)
1066 * RETURN:
1067 * SUCCCESS : TRUE
1068 * FAILURE : FALSE
1070 static BOOL LISTVIEW_RemoveColumn(HDPA hdpaItems, INT nSubItem)
1072 BOOL bResult = TRUE;
1073 HDPA hdpaSubItems;
1074 INT i;
1076 for (i = 0; i < hdpaItems->nItemCount; i++)
1078 hdpaSubItems = (HDPA)DPA_GetPtr(hdpaItems, i);
1079 if (hdpaSubItems != NULL)
1081 if (LISTVIEW_RemoveSubItem(hdpaSubItems, nSubItem) == FALSE)
1083 bResult = FALSE;
1088 return bResult;
1091 /***
1092 * DESCRIPTION:
1093 * Removes a subitem at a given position.
1095 * PARAMETER(S):
1096 * [IO] HDPA : dynamic pointer array handle
1097 * [I] INT : subitem index
1099 * RETURN:
1100 * SUCCCESS : TRUE
1101 * FAILURE : FALSE
1103 static BOOL LISTVIEW_RemoveSubItem(HDPA hdpaSubItems, INT nSubItem)
1105 LISTVIEW_SUBITEM *lpSubItem;
1106 INT i;
1108 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1110 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1111 if (lpSubItem != NULL)
1113 if (lpSubItem->iSubItem == nSubItem)
1115 /* free string */
1116 if ((lpSubItem->pszText != NULL) &&
1117 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1119 COMCTL32_Free(lpSubItem->pszText);
1122 /* free item */
1123 COMCTL32_Free(lpSubItem);
1125 /* free dpa memory */
1126 if (DPA_DeletePtr(hdpaSubItems, i) == NULL)
1128 return FALSE;
1131 else if (lpSubItem->iSubItem > nSubItem)
1133 return TRUE;
1138 return TRUE;
1141 /***
1142 * DESCRIPTION:
1143 * Compares the item information.
1145 * PARAMETER(S):
1146 * [I] LISTVIEW_ITEM *: destination item
1147 * [I] LPLVITEM : source item
1149 * RETURN:
1150 * SUCCCESS : TRUE (EQUAL)
1151 * FAILURE : FALSE (NOT EQUAL)
1153 static UINT LISTVIEW_GetItemChanges(LISTVIEW_ITEM *lpItem, LPLVITEMA lpLVItem)
1155 UINT uChanged = 0;
1157 if ((lpItem != NULL) && (lpLVItem != NULL))
1159 if (lpLVItem->mask & LVIF_STATE)
1161 if ((lpItem->state & lpLVItem->stateMask) !=
1162 (lpLVItem->state & lpLVItem->stateMask))
1164 uChanged |= LVIF_STATE;
1168 if (lpLVItem->mask & LVIF_IMAGE)
1170 if (lpItem->iImage != lpLVItem->iImage)
1172 uChanged |= LVIF_IMAGE;
1176 if (lpLVItem->mask & LVIF_PARAM)
1178 if (lpItem->lParam != lpLVItem->lParam)
1180 uChanged |= LVIF_PARAM;
1184 if (lpLVItem->mask & LVIF_INDENT)
1186 if (lpItem->iIndent != lpLVItem->iIndent)
1188 uChanged |= LVIF_INDENT;
1192 if (lpLVItem->mask & LVIF_TEXT)
1194 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1196 if (lpItem->pszText != LPSTR_TEXTCALLBACKA)
1198 uChanged |= LVIF_TEXT;
1201 else
1203 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1205 uChanged |= LVIF_TEXT;
1207 else
1209 if (lpLVItem->pszText)
1211 if (lpItem->pszText)
1213 if (strcmp(lpLVItem->pszText, lpItem->pszText) != 0)
1215 uChanged |= LVIF_TEXT;
1218 else
1220 uChanged |= LVIF_TEXT;
1223 else
1225 if (lpItem->pszText)
1227 uChanged |= LVIF_TEXT;
1234 return uChanged;
1237 /***
1238 * DESCRIPTION:
1239 * Initializes item attributes.
1241 * PARAMETER(S):
1242 * [I] HWND : window handle
1243 * [O] LISTVIEW_ITEM *: destination item
1244 * [I] LPLVITEM : source item
1246 * RETURN:
1247 * SUCCCESS : TRUE
1248 * FAILURE : FALSE
1250 static BOOL LISTVIEW_InitItem(HWND hwnd, LISTVIEW_ITEM *lpItem,
1251 LPLVITEMA lpLVItem)
1253 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1254 BOOL bResult = FALSE;
1256 if ((lpItem != NULL) && (lpLVItem != NULL))
1258 bResult = TRUE;
1260 if (lpLVItem->mask & LVIF_STATE)
1262 lpItem->state &= ~lpLVItem->stateMask;
1263 lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
1266 if (lpLVItem->mask & LVIF_IMAGE)
1268 lpItem->iImage = lpLVItem->iImage;
1271 if (lpLVItem->mask & LVIF_PARAM)
1273 lpItem->lParam = lpLVItem->lParam;
1276 if (lpLVItem->mask & LVIF_INDENT)
1278 lpItem->iIndent = lpLVItem->iIndent;
1281 if (lpLVItem->mask & LVIF_TEXT)
1283 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1285 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1287 return FALSE;
1290 if ((lpItem->pszText != NULL) &&
1291 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
1293 COMCTL32_Free(lpItem->pszText);
1296 lpItem->pszText = LPSTR_TEXTCALLBACKA;
1298 else
1300 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1302 lpItem->pszText = NULL;
1305 bResult = Str_SetPtrA(&lpItem->pszText, lpLVItem->pszText);
1310 return bResult;
1313 /***
1314 * DESCRIPTION:
1315 * Initializes subitem attributes.
1317 * NOTE: the documentation specifies that the operation fails if the user
1318 * tries to set the indent of a subitem.
1320 * PARAMETER(S):
1321 * [I] HWND : window handle
1322 * [O] LISTVIEW_SUBITEM *: destination subitem
1323 * [I] LPLVITEM : source subitem
1325 * RETURN:
1326 * SUCCCESS : TRUE
1327 * FAILURE : FALSE
1329 static BOOL LISTVIEW_InitSubItem(HWND hwnd, LISTVIEW_SUBITEM *lpSubItem,
1330 LPLVITEMA lpLVItem)
1332 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1333 BOOL bResult = FALSE;
1335 if ((lpSubItem != NULL) && (lpLVItem != NULL))
1337 if (!(lpLVItem->mask & LVIF_INDENT))
1339 bResult = TRUE;
1340 ZeroMemory(lpSubItem, sizeof(LISTVIEW_SUBITEM));
1342 lpSubItem->iSubItem = lpLVItem->iSubItem;
1344 if (lpLVItem->mask & LVIF_IMAGE)
1346 lpSubItem->iImage = lpLVItem->iImage;
1349 if (lpLVItem->mask & LVIF_TEXT)
1351 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1353 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1355 return FALSE;
1358 if ((lpSubItem->pszText != NULL) &&
1359 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1361 COMCTL32_Free(lpSubItem->pszText);
1364 lpSubItem->pszText = LPSTR_TEXTCALLBACKA;
1366 else
1368 if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
1370 lpSubItem->pszText = NULL;
1373 bResult = Str_SetPtrA(&lpSubItem->pszText, lpLVItem->pszText);
1379 return bResult;
1382 /***
1383 * DESCRIPTION:
1384 * Adds a subitem at a given position (column index).
1386 * PARAMETER(S):
1387 * [I] HWND : window handle
1388 * [I] LPLVITEM : new subitem atttributes
1390 * RETURN:
1391 * SUCCESS : TRUE
1392 * FAILURE : FALSE
1394 static BOOL LISTVIEW_AddSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1396 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1397 LISTVIEW_SUBITEM *lpSubItem = NULL;
1398 BOOL bResult = FALSE;
1399 HDPA hdpaSubItems;
1400 INT nPosition, nItem;
1402 if (lpLVItem != NULL)
1404 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1405 if (hdpaSubItems != NULL)
1407 lpSubItem = (LISTVIEW_SUBITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM));
1408 if (lpSubItem != NULL)
1410 if (LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem) != FALSE)
1412 nPosition = LISTVIEW_FindInsertPosition(hdpaSubItems,
1413 lpSubItem->iSubItem);
1414 nItem = DPA_InsertPtr(hdpaSubItems, nPosition, lpSubItem);
1415 if (nItem != -1)
1417 bResult = TRUE;
1424 /* cleanup if unsuccessful */
1425 if ((bResult == FALSE) && (lpSubItem != NULL))
1427 COMCTL32_Free(lpSubItem);
1430 return bResult;
1433 /***
1434 * DESCRIPTION:
1435 * Finds the dpa insert position (array index).
1437 * PARAMETER(S):
1438 * [I] HWND : window handle
1439 * [I] INT : subitem index
1441 * RETURN:
1442 * SUCCESS : TRUE
1443 * FAILURE : FALSE
1445 static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem)
1447 LISTVIEW_SUBITEM *lpSubItem;
1448 INT i;
1450 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1452 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1453 if (lpSubItem != NULL)
1455 if (lpSubItem->iSubItem > nSubItem)
1457 return i;
1462 return hdpaSubItems->nItemCount;
1465 /***
1466 * DESCRIPTION:
1467 * Retrieves a listview subitem at a given position (column index).
1469 * PARAMETER(S):
1470 * [I] HWND : window handle
1471 * [I] INT : subitem index
1473 * RETURN:
1474 * SUCCESS : TRUE
1475 * FAILURE : FALSE
1477 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem)
1479 LISTVIEW_SUBITEM *lpSubItem;
1480 INT i;
1482 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1484 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1485 if (lpSubItem != NULL)
1487 if (lpSubItem->iSubItem == nSubItem)
1489 return lpSubItem;
1491 else if (lpSubItem->iSubItem > nSubItem)
1493 return NULL;
1498 return NULL;
1501 /***
1502 * DESCRIPTION:
1503 * Sets item attributes.
1505 * PARAMETER(S):
1506 * [I] HWND : window handle
1507 * [I] LPLVITEM : new item atttributes
1509 * RETURN:
1510 * SUCCESS : TRUE
1511 * FAILURE : FALSE
1513 static BOOL LISTVIEW_SetItem(HWND hwnd, LPLVITEMA lpLVItem)
1515 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1516 BOOL bResult = FALSE;
1517 HDPA hdpaSubItems;
1518 LISTVIEW_ITEM *lpItem;
1519 NMLISTVIEW nmlv;
1520 UINT uChanged;
1521 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
1523 if (lpLVItem != NULL)
1525 if (lpLVItem->iSubItem == 0)
1527 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1528 if (hdpaSubItems != NULL)
1530 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem);
1531 if (lpItem != NULL)
1533 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
1534 nmlv.hdr.hwndFrom = hwnd;
1535 nmlv.hdr.idFrom = lCtrlId;
1536 nmlv.hdr.code = LVN_ITEMCHANGING;
1537 nmlv.lParam = lpItem->lParam;
1538 uChanged = LISTVIEW_GetItemChanges(lpItem, lpLVItem);
1539 if (uChanged != 0)
1541 if (uChanged & LVIF_STATE)
1543 nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask;
1544 nmlv.uOldState = lpItem->state & lpLVItem->stateMask;
1547 nmlv.uChanged = uChanged;
1548 nmlv.iItem = lpLVItem->iItem;
1549 nmlv.lParam = lpItem->lParam;
1550 /* send LVN_ITEMCHANGING notification */
1551 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1553 /* copy information */
1554 bResult = LISTVIEW_InitItem(hwnd, lpItem, lpLVItem);
1556 /* send LVN_ITEMCHANGED notification */
1557 nmlv.hdr.code = LVN_ITEMCHANGED;
1558 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1560 else
1562 bResult = TRUE;
1565 InvalidateRect(hwnd, NULL, FALSE);
1571 return bResult;
1574 /***
1575 * DESCRIPTION:
1576 * Sets subitem attributes.
1578 * PARAMETER(S):
1579 * [I] HWND : window handle
1580 * [I] LPLVITEM : new subitem atttributes
1582 * RETURN:
1583 * SUCCESS : TRUE
1584 * FAILURE : FALSE
1586 static BOOL LISTVIEW_SetSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1588 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1589 BOOL bResult = FALSE;
1590 HDPA hdpaSubItems;
1591 LISTVIEW_SUBITEM *lpSubItem;
1593 if (lpLVItem != NULL)
1595 if (lpLVItem->iSubItem > 0)
1597 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1598 if (hdpaSubItems != NULL)
1600 /* set subitem only if column is present */
1601 if (Header_GetItemCount(infoPtr->hwndHeader) > lpLVItem->iSubItem)
1603 lpSubItem = LISTVIEW_GetSubItem(hdpaSubItems, lpLVItem->iSubItem);
1604 if (lpSubItem != NULL)
1606 bResult = LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem);
1608 else
1610 bResult = LISTVIEW_AddSubItem(hwnd, lpLVItem);
1613 InvalidateRect(hwnd, NULL, FALSE);
1619 return bResult;
1622 /***
1623 * DESCRIPTION:
1624 * Retrieves the index of the item at coordinate (0, 0) of the client area.
1626 * PARAMETER(S):
1627 * [I] HWND : window handle
1629 * RETURN:
1630 * item index
1632 static INT LISTVIEW_GetTopIndex(HWND hwnd)
1634 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *) GetWindowLongA(hwnd, 0);
1635 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1636 INT nItem = 0;
1638 switch (LVS_TYPEMASK & lStyle)
1640 case LVS_LIST:
1641 if (lStyle & WS_HSCROLL)
1643 nItem = GetScrollPos(hwnd, SB_HORZ) * infoPtr->nCountPerColumn;
1645 break;
1647 case LVS_REPORT:
1648 if (lStyle & WS_VSCROLL)
1650 nItem = GetScrollPos(hwnd, SB_VERT);
1652 break;
1655 return nItem;
1658 /***
1659 * DESCRIPTION:
1660 * Evaluates if scrollbars are needed & sets the scroll range/position.
1662 * PARAMETER(S):
1663 * [I] HWND : window handle
1664 * [I] LONG : window style
1666 * RETURN:
1667 * None
1669 static VOID LISTVIEW_SetScroll(HWND hwnd, LONG lStyle)
1671 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1672 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
1673 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
1674 INT nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
1675 INT nVScrollWidth = GetSystemMetrics(SM_CXVSCROLL);
1676 INT nHiddenWidth;
1677 INT nHiddenHeight;
1678 INT nHiddenItemCount;
1679 INT nScrollPos;
1680 INT nMaxRange;
1681 INT nCountPerPage;
1682 INT nPixPerScrollPos;
1683 RECT rcView;
1685 TRACE(listview, "(hwnd=%x,lStyle=%lx)\n", hwnd, lStyle);
1687 switch (LVS_TYPEMASK & lStyle)
1689 case LVS_LIST:
1690 nCountPerPage = infoPtr->nCountPerRow * infoPtr->nCountPerColumn;
1691 if (nCountPerPage < GETITEMCOUNT(infoPtr))
1693 /* display horizontal scrollbar */
1694 if ((lStyle & WS_HSCROLL) == 0)
1696 ShowScrollBar(hwnd, SB_HORZ, TRUE);
1699 /* calculate new scrollbar range */
1700 nHiddenItemCount = GETITEMCOUNT(infoPtr) - nCountPerPage;
1701 if ((nHiddenItemCount % infoPtr->nCountPerColumn) == 0)
1703 nMaxRange = nHiddenItemCount / infoPtr->nCountPerColumn;
1705 else
1707 nMaxRange = nHiddenItemCount / infoPtr->nCountPerColumn + 1;
1710 SetScrollRange(hwnd, SB_HORZ, 0, nMaxRange, FALSE);
1711 nScrollPos = ListView_GetTopIndex(hwnd) / infoPtr->nCountPerColumn;
1712 SetScrollPos(hwnd, SB_HORZ, nScrollPos, TRUE);
1714 else
1716 /* hide scrollbar */
1717 if ((lStyle & WS_HSCROLL) != 0)
1719 ShowScrollBar(hwnd, SB_HORZ, FALSE);
1722 break;
1724 case LVS_REPORT:
1726 * This section was commented out because I experienced some problems
1727 * with the scrolling of the header control. The idea was to add a
1728 * horizontal scrollbar when the width of the client area was smaller
1729 * than the width of the header control.
1732 /* if (infoPtr->nItemWidth > nListWidth) */
1733 /* { */
1734 /* if ((lStyle & WS_HSCROLL) == 0) */
1735 /* { */
1736 /* ShowScrollBar(hwnd, SB_HORZ, TRUE); */
1737 /* LISTVIEW_SetSize(hwnd, lStyle, -1, -1); */
1738 /* LISTVIEW_SetViewInfo(hwnd, lStyle); */
1739 /* } */
1741 /* nListWidth = infoPtr->rcList.right - infoPtr->rcList.left; */
1742 /* nHiddenWidth = infoPtr->nItemWidth - nListWidth; */
1743 /* nPixPerScrollPos = max(1, nListWidth / 10); */
1745 /* if ((nHiddenWidth % nPixPerScrollPos) == 0) */
1746 /* { */
1747 /* nMaxRange = nHiddenWidth / nPixPerScrollPos; */
1748 /* } */
1749 /* else */
1750 /* { */
1751 /* nMaxRange = nHiddenWidth / nPixPerScrollPos + 1; */
1752 /* } */
1754 /* SetScrollRange(hwnd, SB_HORZ, 0, nMaxRange, FALSE); */
1755 /* SetScrollPos(hwnd, SB_HORZ, 0, TRUE); */
1756 /* } */
1757 /* else */
1758 /* { */
1759 /* if ((lStyle & WS_HSCROLL) != 0) */
1760 /* { */
1761 /* ShowScrollBar(hwnd, SB_HORZ, FASLE); */
1762 /* LISTVIEW_SetSize(hwnd, lStyle, -1, -1); */
1763 /* LISTVIEW_SetViewInfo(hwnd, lStyle); */
1764 /* } */
1765 /* } */
1767 if (infoPtr->nCountPerColumn < GETITEMCOUNT(infoPtr))
1769 if ((lStyle & WS_VSCROLL) == 0)
1771 if (nListWidth > nVScrollWidth)
1773 ShowScrollBar(hwnd, SB_VERT, TRUE);
1774 nListWidth -= nVScrollWidth;
1778 /* vertical range & position */
1779 nMaxRange = GETITEMCOUNT(infoPtr) - infoPtr->nCountPerColumn;
1780 SetScrollRange(hwnd, SB_VERT, 0, nMaxRange, FALSE);
1781 SetScrollPos(hwnd, SB_VERT, ListView_GetTopIndex(hwnd), TRUE);
1783 else
1785 if ((lStyle & WS_VSCROLL) != 0)
1787 ShowScrollBar(hwnd, SB_VERT, FALSE);
1788 nListWidth += nVScrollWidth;
1791 break;
1793 case LVS_ICON:
1794 case LVS_SMALLICON:
1795 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
1797 if (rcView.right - rcView.left > nListWidth)
1799 if ((lStyle & WS_HSCROLL) == 0)
1801 if (nListHeight > nHScrollHeight)
1803 ShowScrollBar(hwnd, SB_HORZ, TRUE);
1804 nListHeight -= nHScrollHeight;
1808 /* calculate size of hidden items */
1809 nHiddenWidth = rcView.right - rcView.left - nListWidth;
1810 nPixPerScrollPos = max(1, nListWidth / 10);
1812 /* vertical range & position */
1813 if ((nHiddenWidth % nPixPerScrollPos) == 0)
1815 nMaxRange = nHiddenWidth / nPixPerScrollPos;
1817 else
1819 nMaxRange = nHiddenWidth / nPixPerScrollPos + 1;
1822 /* set range and position */
1823 SetScrollRange(hwnd, SB_HORZ, 0, nMaxRange, FALSE);
1824 SetScrollPos(hwnd, SB_HORZ, 0, TRUE);
1826 else
1828 if ((lStyle & WS_HSCROLL) != 0)
1830 ShowScrollBar(hwnd, SB_HORZ, FALSE);
1831 nListHeight += nHScrollHeight;
1835 if (rcView.bottom - rcView.top > nListHeight)
1837 if ((lStyle & WS_VSCROLL) == 0)
1839 if (nListWidth > nVScrollWidth)
1841 ShowScrollBar(hwnd, SB_VERT, TRUE);
1842 nListWidth -= nVScrollWidth;
1846 /* calculate size of hidden items */
1847 nHiddenHeight = rcView.bottom - rcView.top - nListHeight;
1848 nPixPerScrollPos = max(1, nListHeight / 10);
1850 /* set vertical range & position */
1851 if ((nHiddenHeight % nPixPerScrollPos) == 0)
1853 nMaxRange = nHiddenHeight / nPixPerScrollPos;
1855 else
1857 nMaxRange = nHiddenHeight / nPixPerScrollPos + 1;
1860 /* set range and position */
1861 SetScrollRange(hwnd, SB_VERT, 0, nMaxRange, FALSE);
1862 SetScrollPos(hwnd, SB_VERT, 0, TRUE);
1864 else
1866 if ((lStyle & WS_VSCROLL) != 0)
1868 ShowScrollBar(hwnd, SB_VERT, FALSE);
1869 nListWidth += nVScrollWidth;
1873 break;
1877 /***
1878 * DESCRIPTION:
1879 * Draws a subitem.
1881 * PARAMETER(S):
1882 * [I] HWND : window handle
1883 * [I] HDC : device context handle
1884 * [I] INT : item index
1885 * [I] LPARAM : item lparam
1886 * [I] LISTVIEW_SUBITEM * : item
1887 * [I] INT : column index (header index)
1888 * [I] RECT * : clipping rectangle
1890 * RETURN:
1891 * None
1893 static VOID LISTVIEW_DrawSubItem(HWND hwnd, HDC hdc, INT nItem, LPARAM lParam,
1894 LISTVIEW_SUBITEM *lpSubItem, INT nColumn,
1895 RECT *lprc)
1897 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1898 CHAR szDispText[DISP_TEXT_SIZE];
1899 LPSTR pszDispText = NULL;
1901 /* set item colors */
1902 SetBkColor(hdc, infoPtr->clrTextBk);
1903 SetTextColor(hdc, infoPtr->clrText);
1905 pszDispText = szDispText;
1906 LISTVIEW_GetSubItemDispInfo(hwnd, nItem, lParam, lpSubItem, nColumn, NULL,
1907 &pszDispText, DISP_TEXT_SIZE);
1909 /* draw text : using arbitrary offset of 10 pixels */
1911 ExtTextOutA(hdc, lprc->left, lprc->top, ETO_OPAQUE|ETO_CLIPPED,
1912 lprc, pszDispText, lstrlenA(pszDispText), NULL);
1915 /***
1916 * DESCRIPTION:
1917 * Draws an item.
1919 * PARAMETER(S):
1920 * [I] HWND : window handle
1921 * [I] HDC : device context handle
1922 * [I] LISTVIEW_ITEM * : item
1923 * [I] INT : item index
1924 * [I] RECT * : clipping rectangle
1926 * RETURN:
1927 * None
1929 static VOID LISTVIEW_DrawItem(HWND hwnd, HDC hdc, LISTVIEW_ITEM *lpItem,
1930 INT nItem, RECT rc)
1932 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1933 CHAR szDispText[DISP_TEXT_SIZE];
1934 LPSTR pszDispText = NULL;
1935 BOOL bSelected;
1936 INT nLabelWidth;
1937 INT nImage;
1938 UINT uState;
1940 TRACE(listview, "(hwnd=%x,hdc=%x,lpItem=%p,nItem=%d,rc.left=%d,rctop=%d,rc.right=%d,rc.bottom=%d)\n", hwnd, hdc, lpItem, nItem, rc.left, rc.top, rc.right, rc.bottom);
1942 pszDispText = szDispText;
1943 LISTVIEW_GetItemDispInfo(hwnd, nItem, lpItem, &nImage, &uState, &pszDispText,
1944 DISP_TEXT_SIZE);
1946 if (uState & LVIS_SELECTED)
1948 bSelected = TRUE;
1950 /* set item colors */
1951 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1952 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1954 /* set raster mode */
1955 SetROP2(hdc, R2_XORPEN);
1957 else
1959 bSelected = FALSE;
1961 /* set item colors */
1962 SetBkColor(hdc, infoPtr->clrTextBk);
1963 SetTextColor(hdc, infoPtr->clrText);
1965 /* set raster mode */
1966 SetROP2(hdc, R2_COPYPEN);
1969 /* state icons */
1970 if (infoPtr->himlState != NULL)
1972 /* right shift 12 bits to obtain index in image list */
1973 if (bSelected != FALSE)
1975 ImageList_Draw(infoPtr->himlState, uState >> 12, hdc, rc.left,
1976 rc.top, ILD_SELECTED);
1978 else
1980 ImageList_Draw(infoPtr->himlState, uState >> 12, hdc, rc.left,
1981 rc.top, ILD_NORMAL);
1984 rc.left += infoPtr->iconSize.cx;
1987 /* small icons */
1988 if (infoPtr->himlSmall != NULL)
1990 if (bSelected != FALSE)
1992 ImageList_Draw(infoPtr->himlSmall, nImage, hdc, rc.left,
1993 rc.top, ILD_SELECTED);
1995 else
1997 ImageList_Draw(infoPtr->himlSmall, nImage, hdc, rc.left,
1998 rc.top, ILD_NORMAL);
2001 rc.left += infoPtr->iconSize.cx;
2004 nLabelWidth = ListView_GetStringWidthA(hwnd, pszDispText);
2005 if (rc.left + nLabelWidth < rc.right)
2007 rc.right = rc.left + nLabelWidth;
2010 /* draw label */
2011 ExtTextOutA(hdc, rc.left, rc.top, ETO_OPAQUE|ETO_CLIPPED,
2012 &rc, pszDispText, lstrlenA(pszDispText), NULL);
2014 if (lpItem->state & LVIS_FOCUSED)
2016 Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);
2020 /***
2021 * DESCRIPTION:
2022 * Draws an item when in large icon display mode.
2024 * PARAMETER(S):
2025 * [I] HWND : window handle
2026 * [I] HDC : device context handle
2027 * [I] LISTVIEW_ITEM * : item
2028 * [I] INT : item index
2029 * [I] RECT * : clipping rectangle
2031 * RETURN:
2032 * None
2034 static VOID LISTVIEW_DrawLargeItem(HWND hwnd, HDC hdc, LISTVIEW_ITEM *lpItem,
2035 INT nItem, RECT rc)
2037 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2038 CHAR szDispText[DISP_TEXT_SIZE];
2039 LPSTR pszDispText = NULL;
2040 BOOL bSelected;
2041 INT nLabelWidth;
2042 INT nImage;
2043 UINT uState;
2044 INT nDrawPosX = 0;
2045 TEXTMETRICA tm;
2047 TRACE(listview, "(hwnd=%x,hdc=%x,lpItem=%p,nItem=%d,rc.left=%d,rctop=%d,rc.right=%d,rc.bottom=%d)\n", hwnd, hdc, lpItem, nItem, rc.left, rc.top, rc.right, rc.bottom);
2049 pszDispText = szDispText;
2050 LISTVIEW_GetItemDispInfo(hwnd, nItem, lpItem, &nImage, &uState, &pszDispText,
2051 DISP_TEXT_SIZE);
2052 if (uState & LVIS_SELECTED)
2054 bSelected = TRUE;
2056 /* set item colors */
2057 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
2058 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2060 /* set raster mode */
2061 SetROP2(hdc, R2_XORPEN);
2063 else
2065 bSelected = FALSE;
2067 /* set item colors */
2068 SetBkColor(hdc, infoPtr->clrTextBk);
2069 SetTextColor(hdc, infoPtr->clrText);
2071 /* set raster mode */
2072 SetROP2(hdc, R2_COPYPEN);
2075 if (infoPtr->himlNormal != NULL)
2077 rc.top += ICON_TOP_PADDING;
2078 nDrawPosX = rc.left + (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
2079 if (bSelected != FALSE)
2081 ImageList_Draw(infoPtr->himlNormal, nImage, hdc, nDrawPosX, rc.top,
2082 ILD_SELECTED);
2084 else
2086 ImageList_Draw(infoPtr->himlNormal, nImage, hdc, nDrawPosX, rc.top,
2087 ILD_NORMAL);
2091 rc.top += infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
2092 nLabelWidth = ListView_GetStringWidthA(hwnd, pszDispText);
2093 nDrawPosX = infoPtr->iconSpacing.cx - nLabelWidth;
2094 if (nDrawPosX > 1)
2096 rc.left += nDrawPosX / 2;
2097 rc.right = rc.left + nLabelWidth;
2099 else
2101 rc.left += 1;
2102 rc.right = rc.left + infoPtr->iconSpacing.cx - 1;
2105 /* draw label */
2106 GetTextMetricsA(hdc, &tm);
2107 rc.bottom = rc.top + tm.tmHeight + HEIGHT_PADDING;
2108 ExtTextOutA(hdc, rc.left, rc.top, ETO_OPAQUE|ETO_CLIPPED,
2109 &rc, pszDispText, lstrlenA(pszDispText), NULL);
2111 if (lpItem->state & LVIS_FOCUSED)
2113 Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);
2117 /***
2118 * DESCRIPTION:
2119 * Draws listview items when in report display mode.
2121 * PARAMETER(S):
2122 * [I] HWND : window handle
2123 * [I] HDC : device context handle
2125 * RETURN:
2126 * None
2128 static VOID LISTVIEW_RefreshReport(HWND hwnd, HDC hdc)
2130 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2131 INT nDrawPosY = infoPtr->rcList.top;
2132 LISTVIEW_ITEM *lpItem;
2133 LISTVIEW_SUBITEM *lpSubItem = NULL;
2134 BOOL bNeedSubItem = TRUE;
2135 INT nColumnCount;
2136 HDPA hdpaSubItems;
2137 RECT rcItem;
2138 INT j, k;
2139 INT nItem;
2140 INT nLast;
2142 nItem = ListView_GetTopIndex(hwnd);
2143 nLast = nItem + infoPtr->nCountPerColumn;
2144 while (nItem <= nLast)
2146 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
2147 if (hdpaSubItems != NULL)
2149 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2150 if (lpItem != NULL)
2152 /* the width of the header items will determine the size of the
2153 listview items */
2154 Header_GetItemRect(infoPtr->hwndHeader, 0, &rcItem);
2155 rcItem.left += REPORT_MARGINX;
2156 rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX);
2157 rcItem.top = nDrawPosY;
2158 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2159 LISTVIEW_DrawItem(hwnd, hdc, lpItem, nItem, rcItem);
2162 nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
2163 for (k = 1, j = 1; j < nColumnCount; j++)
2165 Header_GetItemRect(infoPtr->hwndHeader, j, &rcItem);
2166 rcItem.left += REPORT_MARGINX;
2167 rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX);
2168 rcItem.top = nDrawPosY;
2169 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2171 if (k < hdpaSubItems->nItemCount)
2173 if (bNeedSubItem != FALSE)
2175 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, k);
2176 k++;
2179 if (lpSubItem != NULL)
2181 if (lpSubItem->iSubItem == j)
2183 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, lpItem->lParam, lpSubItem,
2184 j, &rcItem);
2185 bNeedSubItem = TRUE;
2187 else
2189 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, lpItem->lParam, NULL, j,
2190 &rcItem);
2191 bNeedSubItem = FALSE;
2194 else
2196 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, lpItem->lParam, NULL, j,
2197 &rcItem);
2198 bNeedSubItem = TRUE;
2201 else
2203 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, lpItem->lParam, NULL, j,
2204 &rcItem);
2209 nDrawPosY += infoPtr->nItemHeight;
2210 nItem++;
2214 /***
2215 * DESCRIPTION:
2216 * Draws listview items when in list display mode.
2218 * PARAMETER(S):
2219 * [I] HWND : window handle
2220 * [I] HDC : device context handle
2222 * RETURN:
2223 * None
2225 static VOID LISTVIEW_RefreshList(HWND hwnd, HDC hdc)
2227 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2228 LISTVIEW_ITEM *lpItem;
2229 HDPA hdpaSubItems;
2230 RECT rc;
2231 INT i, j;
2232 INT nColumnCount;
2233 INT nItem = ListView_GetTopIndex(hwnd);
2235 if (infoPtr->rcList.right > 0)
2237 /* get number of display columns */
2238 if (infoPtr->rcList.right % infoPtr->nItemWidth == 0)
2240 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth;
2242 else
2244 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth + 1;
2247 for (i = 0; i < nColumnCount; i++)
2249 j = 0;
2250 while ((nItem < GETITEMCOUNT(infoPtr)) &&
2251 (j<infoPtr->nCountPerColumn))
2253 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
2254 if (hdpaSubItems != NULL)
2256 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2257 if (lpItem != NULL)
2259 rc.top = j * infoPtr->nItemHeight;
2260 rc.left = i * infoPtr->nItemWidth;
2261 rc.bottom = rc.top + infoPtr->nItemHeight;
2262 rc.right = rc.left + infoPtr->nItemWidth;
2263 LISTVIEW_DrawItem(hwnd, hdc, lpItem, nItem, rc);
2267 nItem++;
2268 j++;
2274 /***
2275 * DESCRIPTION:
2276 * Draws listview items when in icon or small icon display mode.
2278 * PARAMETER(S):
2279 * [I] HWND : window handle
2280 * [I] HDC : device context handle
2282 * RETURN:
2283 * None
2285 static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc, BOOL bSmall)
2287 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2288 LISTVIEW_ITEM *lpItem;
2289 HDPA hdpaSubItems;
2290 POINT ptPosition;
2291 POINT ptOrigin;
2292 RECT rc;
2293 INT i;
2295 LISTVIEW_GetOrigin(hwnd, &ptOrigin);
2297 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2299 LISTVIEW_GetItemPosition(hwnd, i, &ptPosition);
2300 ptPosition.x += ptOrigin.x;
2301 ptPosition.y += ptOrigin.y;
2303 if (ptPosition.y + infoPtr->nItemHeight > infoPtr->rcList.top)
2305 if (ptPosition.x + infoPtr->nItemWidth > infoPtr->rcList.left)
2307 if (ptPosition.y < infoPtr->rcList.bottom)
2309 if (ptPosition.x < infoPtr->rcList.right)
2311 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
2312 if (hdpaSubItems != NULL)
2314 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2315 if (lpItem != NULL)
2317 rc.top = ptPosition.y;
2318 rc.left = ptPosition.x;
2319 rc.bottom = rc.top + infoPtr->nItemHeight;
2320 rc.right = rc.left + infoPtr->nItemWidth;
2321 if (bSmall == FALSE)
2323 LISTVIEW_DrawLargeItem(hwnd, hdc, lpItem, i, rc);
2325 else
2327 LISTVIEW_DrawItem(hwnd, hdc, lpItem, i, rc);
2338 /***
2339 * DESCRIPTION:
2340 * Draws listview items.
2342 * PARAMETER(S):
2343 * [I] HWND : window handle
2344 * [I] HDC : device context handle
2346 * RETURN:
2347 * NoneX
2349 static VOID LISTVIEW_Refresh(HWND hwnd, HDC hdc)
2351 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2352 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2353 HFONT hOldFont;
2354 HPEN hPen, hOldPen;
2356 /* select font */
2357 hOldFont = SelectObject(hdc, infoPtr->hFont);
2359 /* select the doted pen (for drawing the focus box) */
2360 hPen = CreatePen(PS_DOT, 1, 0);
2361 hOldPen = SelectObject(hdc, hPen);
2363 /* select transparent brush (for drawing the focus box) */
2364 SelectObject(hdc, GetStockObject(NULL_BRUSH));
2366 switch (LVS_TYPEMASK & lStyle)
2368 case LVS_LIST:
2369 LISTVIEW_RefreshList(hwnd, hdc);
2370 break;
2371 case LVS_REPORT:
2372 LISTVIEW_RefreshReport(hwnd, hdc);
2373 break;
2374 case LVS_SMALLICON:
2375 LISTVIEW_RefreshIcon(hwnd, hdc, TRUE);
2376 break;
2377 case LVS_ICON:
2378 LISTVIEW_RefreshIcon(hwnd, hdc, FALSE);
2381 /* unselect objects */
2382 SelectObject(hdc, hOldFont);
2383 SelectObject(hdc, hOldPen);
2385 /* delete pen */
2386 DeleteObject(hPen);
2390 /***
2391 * DESCRIPTION:
2392 * Calculates the approximate width and height of a given number of items.
2394 * PARAMETER(S):
2395 * [I] HWND : window handle
2396 * [I] INT : number of items
2397 * [I] INT : width
2398 * [I] INT : height
2400 * RETURN:
2401 * Returns a DWORD. The width in the low word and the height in high word.
2403 static LRESULT LISTVIEW_ApproximateViewRect(HWND hwnd, INT nItemCount,
2404 WORD wWidth, WORD wHeight)
2406 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2407 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2408 INT nItemCountPerColumn = 1;
2409 INT nColumnCount = 0;
2410 DWORD dwViewRect = 0;
2412 if (nItemCount == -1)
2413 nItemCount = GETITEMCOUNT(infoPtr);
2415 if (lStyle & LVS_LIST)
2417 if (wHeight == 0xFFFF)
2419 /* use current height */
2420 wHeight = infoPtr->rcList.bottom;
2423 if (wHeight < infoPtr->nItemHeight)
2425 wHeight = infoPtr->nItemHeight;
2428 if (nItemCount > 0)
2430 if (infoPtr->nItemHeight > 0)
2432 nItemCountPerColumn = wHeight / infoPtr->nItemHeight;
2433 if (nItemCountPerColumn == 0)
2434 nItemCountPerColumn = 1;
2436 if (nItemCount % nItemCountPerColumn != 0)
2437 nColumnCount = nItemCount / nItemCountPerColumn;
2438 else
2439 nColumnCount = nItemCount / nItemCountPerColumn + 1;
2443 /* Microsoft padding magic */
2444 wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2;
2445 wWidth = nColumnCount * infoPtr->nItemWidth + 2;
2447 dwViewRect = MAKELONG(wWidth, wHeight);
2449 else if (lStyle & LVS_REPORT)
2451 /* TO DO */
2453 else if (lStyle & LVS_SMALLICON)
2455 /* TO DO */
2457 else if (lStyle & LVS_ICON)
2459 /* TO DO */
2462 return dwViewRect;
2465 /***
2466 * DESCRIPTION:
2467 * Arranges listview items in icon display mode.
2469 * PARAMETER(S):
2470 * [I] HWND : window handle
2471 * [I] INT : alignment code
2473 * RETURN:
2474 * SUCCESS : TRUE
2475 * FAILURE : FALSE
2477 static LRESULT LISTVIEW_Arrange(HWND hwnd, INT nAlignCode)
2479 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2480 BOOL bResult = FALSE;
2482 if (((LVS_TYPEMASK & lStyle) == LVS_ICON) ||
2483 ((LVS_TYPEMASK & lStyle) == LVS_SMALLICON))
2485 switch (nAlignCode)
2487 case LVA_ALIGNLEFT:
2488 /* TO DO */
2489 break;
2490 case LVA_ALIGNTOP:
2491 /* TO DO */
2492 break;
2493 case LVA_DEFAULT:
2494 /* TO DO */
2495 break;
2496 case LVA_SNAPTOGRID:
2497 /* TO DO */
2498 break;
2502 return bResult;
2505 /* << LISTVIEW_CreateDragImage >> */
2507 /***
2508 * DESCRIPTION:
2509 * Removes all listview items and subitems.
2511 * PARAMETER(S):
2512 * [I] HWND : window handle
2514 * RETURN:
2515 * SUCCESS : TRUE
2516 * FAILURE : FALSE
2518 static LRESULT LISTVIEW_DeleteAllItems(HWND hwnd)
2520 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2521 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2522 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2523 LISTVIEW_ITEM *lpItem;
2524 LISTVIEW_SUBITEM *lpSubItem;
2525 NMLISTVIEW nmlv;
2526 BOOL bSuppress;
2527 BOOL bResult = FALSE;
2528 INT i;
2529 INT j;
2530 HDPA hdpaSubItems;
2532 TRACE(listview, "(hwnd=%x,)\n", hwnd);
2534 if (GETITEMCOUNT(infoPtr) > 0)
2536 /* initialize memory */
2537 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2539 /* send LVN_DELETEALLITEMS notification */
2540 nmlv.hdr.hwndFrom = hwnd;
2541 nmlv.hdr.idFrom = lCtrlId;
2542 nmlv.hdr.code = LVN_DELETEALLITEMS;
2543 nmlv.iItem = -1;
2545 /* verify if subsequent LVN_DELETEITEM notifications should be
2546 suppressed */
2547 bSuppress = ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2549 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2551 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
2552 if (hdpaSubItems != NULL)
2554 for (j = 1; j < hdpaSubItems->nItemCount; j++)
2556 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, j);
2557 if (lpSubItem != NULL)
2559 /* free subitem string */
2560 if ((lpSubItem->pszText != NULL) &&
2561 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2563 COMCTL32_Free(lpSubItem->pszText);
2566 /* free subitem */
2567 COMCTL32_Free(lpSubItem);
2571 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2572 if (lpItem != NULL)
2574 if (bSuppress == FALSE)
2576 /* send LVN_DELETEITEM notification */
2577 nmlv.hdr.code = LVN_DELETEITEM;
2578 nmlv.iItem = i;
2579 nmlv.lParam = lpItem->lParam;
2580 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2583 /* free item string */
2584 if ((lpItem->pszText != NULL) &&
2585 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2587 COMCTL32_Free(lpItem->pszText);
2590 /* free item */
2591 COMCTL32_Free(lpItem);
2594 DPA_Destroy(hdpaSubItems);
2598 /* reinitialize listview memory */
2599 bResult = DPA_DeleteAllPtrs(infoPtr->hdpaItems);
2601 /* align items (set position of each item) */
2602 switch (lStyle & LVS_TYPEMASK)
2604 case LVS_ICON:
2605 case LVS_SMALLICON:
2606 if (lStyle & LVS_ALIGNLEFT)
2608 LISTVIEW_AlignLeft(hwnd);
2610 else
2612 LISTVIEW_AlignTop(hwnd);
2614 break;
2617 LISTVIEW_SetScroll(hwnd, lStyle);
2619 /* invalidate client area (optimization needed) */
2620 InvalidateRect(hwnd, NULL, TRUE);
2623 return bResult;
2626 /***
2627 * DESCRIPTION:
2628 * Removes a column from the listview control.
2630 * PARAMETER(S):
2631 * [I] HWND : window handle
2632 * [I] INT : column index
2634 * RETURN:
2635 * SUCCESS : TRUE
2636 * FAILURE : FALSE
2638 static LRESULT LISTVIEW_DeleteColumn(HWND hwnd, INT nColumn)
2640 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2641 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2642 BOOL bResult = FALSE;
2644 if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) != FALSE)
2646 bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
2648 /* reset scroll parameters */
2649 if ((lStyle & LVS_TYPEMASK) == LVS_REPORT)
2651 LISTVIEW_SetViewInfo(hwnd, lStyle);
2652 LISTVIEW_SetScroll(hwnd, lStyle);
2655 /* refresh client area */
2656 InvalidateRect(hwnd, NULL, FALSE);
2659 return bResult;
2662 /***
2663 * DESCRIPTION:
2664 * Removes an item from the listview control.
2666 * PARAMETER(S):
2667 * [I] HWND : window handle
2668 * [I] INT : item index
2670 * RETURN:
2671 * SUCCESS : TRUE
2672 * FAILURE : FALSE
2674 static LRESULT LISTVIEW_DeleteItem(HWND hwnd, INT nItem)
2676 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2677 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2678 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2679 NMLISTVIEW nmlv;
2680 BOOL bResult = FALSE;
2681 HDPA hdpaSubItems;
2682 LISTVIEW_ITEM *lpItem;
2683 LISTVIEW_SUBITEM *lpSubItem;
2684 INT i;
2686 TRACE(listview, "(hwnd=%x,nItem=%d)\n", hwnd, nItem);
2688 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
2690 /* initialize memory */
2691 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2693 hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem);
2694 if (hdpaSubItems != NULL)
2696 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2698 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2699 if (lpSubItem != NULL)
2701 /* free item string */
2702 if ((lpSubItem->pszText != NULL) &&
2703 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2705 COMCTL32_Free(lpSubItem->pszText);
2708 /* free item */
2709 COMCTL32_Free(lpSubItem);
2713 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2714 if (lpItem != NULL)
2716 /* send LVN_DELETEITEM notification */
2717 nmlv.hdr.hwndFrom = hwnd;
2718 nmlv.hdr.idFrom = lCtrlId;
2719 nmlv.hdr.code = LVN_DELETEITEM;
2720 nmlv.iItem = nItem;
2721 nmlv.lParam = lpItem->lParam;
2722 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId,
2723 (LPARAM)&nmlv);
2725 /* free item string */
2726 if ((lpItem->pszText != NULL) &&
2727 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2729 COMCTL32_Free(lpItem->pszText);
2732 /* free item */
2733 COMCTL32_Free(lpItem);
2736 bResult = DPA_Destroy(hdpaSubItems);
2739 /* align items (set position of each item) */
2740 switch(lStyle & LVS_TYPEMASK)
2742 case LVS_ICON:
2743 case LVS_SMALLICON:
2744 if (lStyle & LVS_ALIGNLEFT)
2746 LISTVIEW_AlignLeft(hwnd);
2748 else
2750 LISTVIEW_AlignTop(hwnd);
2752 break;
2755 LISTVIEW_SetScroll(hwnd, lStyle);
2757 /* refresh client area */
2758 InvalidateRect(hwnd, NULL, TRUE);
2761 return bResult;
2764 /* LISTVIEW_EditLabel */
2766 /***
2767 * DESCRIPTION:
2768 * Ensures the specified item is visible, scrolling into view if necessary.
2770 * PARAMETER(S):
2771 * [I] HWND : window handle
2772 * [I] INT : item index
2773 * [I] BOOL : partially or entirely visible
2775 * RETURN:
2776 * SUCCESS : TRUE
2777 * FAILURE : FALSE
2779 static BOOL LISTVIEW_EnsureVisible(HWND hwnd, INT nItem, BOOL bPartial)
2781 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2782 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2783 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2784 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
2785 INT nHScrollPos = 0;
2786 INT nVScrollPos = 0;
2787 INT nScrollPosHeight = 0;
2788 INT nScrollPosWidth = 0;
2789 RECT rcItem;
2790 BOOL bResult = FALSE;
2792 /* ALWAYS bPartial == FALSE, FOR NOW! */
2794 rcItem.left = LVIR_BOUNDS;
2795 if (LISTVIEW_GetItemRect(hwnd, nItem, &rcItem) != FALSE)
2797 if (rcItem.left < infoPtr->rcList.left)
2799 /* scroll left */
2800 switch (LVS_TYPEMASK & lStyle)
2802 case LVS_LIST:
2803 rcItem.left += infoPtr->rcList.left;
2804 nScrollPosWidth = infoPtr->nItemWidth;
2805 break;
2807 case LVS_SMALLICON:
2808 case LVS_ICON:
2809 nScrollPosWidth = max(1, nListWidth / 10);
2810 rcItem.left += infoPtr->rcList.left;
2811 break;
2814 if (rcItem.left % nScrollPosWidth == 0)
2816 nHScrollPos = rcItem.left / nScrollPosWidth;
2818 else
2820 nHScrollPos = rcItem.left / nScrollPosWidth - 1;
2823 else if (rcItem.right > infoPtr->rcList.right)
2825 /* scroll right */
2826 switch (LVS_TYPEMASK & lStyle)
2828 case LVS_LIST:
2829 rcItem.right -= infoPtr->rcList.right;
2830 nScrollPosWidth = infoPtr->nItemWidth;
2831 break;
2833 case LVS_SMALLICON:
2834 case LVS_ICON:
2835 nScrollPosWidth = max(1, nListWidth / 10);
2836 rcItem.right -= infoPtr->rcList.right;
2837 break;
2840 if (rcItem.right % nScrollPosWidth == 0)
2842 nHScrollPos = rcItem.right / nScrollPosWidth;
2844 else
2846 nHScrollPos = rcItem.right / nScrollPosWidth + 1;
2850 if (rcItem.top < infoPtr->rcList.top)
2852 /* scroll up */
2853 switch (LVS_TYPEMASK & lStyle)
2855 case LVS_REPORT:
2856 rcItem.top -= infoPtr->rcList.top;
2857 nScrollPosHeight = infoPtr->nItemHeight;
2858 break;
2860 case LVS_SMALLICON:
2861 case LVS_ICON:
2862 nScrollPosHeight = max(1, nListHeight / 10);
2863 rcItem.top += infoPtr->rcList.top;
2864 break;
2867 if (rcItem.top % nScrollPosHeight == 0)
2869 nVScrollPos = rcItem.top / nScrollPosHeight;
2871 else
2873 nVScrollPos = rcItem.top / nScrollPosHeight - 1;
2876 else if (rcItem.bottom > infoPtr->rcList.bottom)
2878 switch (LVS_TYPEMASK & lStyle)
2880 case LVS_REPORT:
2881 rcItem.bottom -= infoPtr->rcList.bottom;
2882 nScrollPosHeight = infoPtr->nItemHeight;
2883 break;
2885 case LVS_SMALLICON:
2886 case LVS_ICON:
2887 nScrollPosHeight = max(1, nListHeight / 10);
2888 rcItem.bottom -= infoPtr->rcList.bottom;
2889 break;
2892 if (rcItem.bottom % nScrollPosHeight == 0)
2894 nVScrollPos = rcItem.bottom / nScrollPosHeight;
2896 else
2898 nVScrollPos = rcItem.bottom / nScrollPosHeight + 1;
2902 bResult = LISTVIEW_ScrollView(hwnd, nHScrollPos, nVScrollPos);
2905 return bResult;
2908 /***
2909 * DESCRIPTION:
2910 * Searches for an item with specific characteristics.
2912 * PARAMETER(S):
2913 * [I] HWND : window handle
2914 * [I] INT : base item index
2915 * [I] LPLVFINDINFO : item information to look for
2917 * RETURN:
2918 * SUCCESS : index of item
2919 * FAILURE : -1
2921 static LRESULT LISTVIEW_FindItem(HWND hwnd, INT nStart,
2922 LPLVFINDINFO lpFindInfo)
2924 FIXME (listview, "empty stub!\n");
2926 return -1;
2929 /***
2930 * DESCRIPTION:
2931 * Retrieves the background color of the listview control.
2933 * PARAMETER(S):
2934 * [I] HWND : window handle
2936 * RETURN:
2937 * COLORREF associated with the background.
2939 static LRESULT LISTVIEW_GetBkColor(HWND hwnd)
2941 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2943 return infoPtr->clrBk;
2946 /***
2947 * DESCRIPTION:
2948 * Retrieves the background image of the listview control.
2950 * PARAMETER(S):
2951 * [I] HWND : window handle
2952 * [O] LPLVMKBIMAGE : background image attributes
2954 * RETURN:
2955 * SUCCESS : TRUE
2956 * FAILURE : FALSE`
2958 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
2959 /* { */
2960 /* FIXME (listview, "empty stub!\n"); */
2961 /* return FALSE; */
2962 /* } */
2964 /***
2965 * DESCRIPTION:
2966 * Retrieves the callback mask.
2968 * PARAMETER(S):
2969 * [I] HWND : window handle
2971 * RETURN:
2972 * Value of mask
2974 static UINT LISTVIEW_GetCallbackMask(HWND hwnd)
2976 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2978 return infoPtr->uCallbackMask;
2981 /***
2982 * DESCRIPTION:
2983 * Retrieves column attributes.
2985 * PARAMETER(S):
2986 * [I] HWND : window handle
2987 * [I] INT : column index
2988 * [IO] LPLVCOLUMNA : column information
2990 * RETURN:
2991 * SUCCESS : TRUE
2992 * FAILURE : FALSE
2994 static LRESULT LISTVIEW_GetColumnA(HWND hwnd, INT nItem,
2995 LPLVCOLUMNA lpColumn)
2997 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2998 HDITEMA hdi;
2999 BOOL bResult = FALSE;
3001 if (lpColumn != NULL)
3003 /* initialize memory */
3004 ZeroMemory(&hdi, sizeof(HDITEMA));
3006 if (lpColumn->mask & LVCF_FMT)
3008 hdi.mask |= HDI_FORMAT;
3011 if (lpColumn->mask & LVCF_WIDTH)
3013 hdi.mask |= HDI_WIDTH;
3016 if (lpColumn->mask & LVCF_TEXT)
3018 hdi.mask |= (HDI_TEXT | HDI_FORMAT);
3021 if (lpColumn->mask & LVCF_IMAGE)
3023 hdi.mask |= HDI_IMAGE;
3026 if (lpColumn->mask & LVCF_ORDER)
3028 hdi.mask |= HDI_ORDER;
3031 bResult = Header_GetItemA(infoPtr->hwndHeader, nItem, &hdi);
3032 if (bResult != FALSE)
3034 if (lpColumn->mask & LVCF_FMT)
3036 lpColumn->fmt = 0;
3038 if (hdi.fmt & HDF_LEFT)
3040 lpColumn->fmt |= LVCFMT_LEFT;
3042 else if (hdi.fmt & HDF_RIGHT)
3044 lpColumn->fmt |= LVCFMT_RIGHT;
3046 else if (hdi.fmt & HDF_CENTER)
3048 lpColumn->fmt |= LVCFMT_CENTER;
3051 if (hdi.fmt & HDF_IMAGE)
3053 lpColumn->fmt |= LVCFMT_COL_HAS_IMAGES;
3057 if (lpColumn->mask & LVCF_WIDTH)
3059 lpColumn->cx = hdi.cxy;
3062 if ((lpColumn->mask & LVCF_TEXT) && (lpColumn->pszText) && (hdi.pszText))
3064 lstrcpynA (lpColumn->pszText, hdi.pszText, lpColumn->cchTextMax);
3067 if (lpColumn->mask & LVCF_IMAGE)
3069 lpColumn->iImage = hdi.iImage;
3072 if (lpColumn->mask & LVCF_ORDER)
3074 lpColumn->iOrder = hdi.iOrder;
3079 return bResult;
3082 /* LISTVIEW_GetColumnW */
3083 /* LISTVIEW_GetColumnOrderArray */
3085 /***
3086 * DESCRIPTION:
3087 * Retrieves the column width.
3089 * PARAMETER(S):
3090 * [I] HWND : window handle
3091 * [I] int : column index
3093 * RETURN:
3094 * SUCCESS : column width
3095 * FAILURE : zero
3097 static LRESULT LISTVIEW_GetColumnWidth(HWND hwnd, INT nColumn)
3099 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3100 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3101 HDITEMA hdi;
3102 INT nColumnWidth = 0;
3104 switch (LVS_TYPEMASK & lStyle)
3106 case LVS_LIST:
3107 nColumnWidth = infoPtr->nItemWidth;
3108 break;
3110 case LVS_REPORT:
3111 /* get column width from header */
3112 ZeroMemory(&hdi, sizeof(HDITEMA));
3113 hdi.mask = HDI_WIDTH;
3114 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdi) != FALSE)
3116 nColumnWidth = hdi.cxy;
3118 break;
3121 return nColumnWidth;
3124 /***
3125 * DESCRIPTION:
3126 * In list or report display mode, retrieves the number of items that can fit
3127 * vertically in the visible area. In icon or small icon display mode,
3128 * retrieves the total number of visible items.
3130 * PARAMETER(S):
3131 * [I] HWND : window handle
3133 * RETURN:
3134 * Number of fully visible items.
3136 static LRESULT LISTVIEW_GetCountPerPage(HWND hwnd)
3138 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3139 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3140 INT nItemCount = 0;
3142 switch (LVS_TYPEMASK & lStyle)
3144 case LVS_LIST:
3145 if (infoPtr->rcList.right / infoPtr->nItemWidth)
3147 nItemCount = infoPtr->nCountPerRow * infoPtr->nCountPerColumn;
3149 break;
3151 case LVS_REPORT:
3152 nItemCount = infoPtr->nCountPerColumn;
3153 break;
3155 case LVS_SMALLICON:
3156 case LVS_ICON:
3157 nItemCount = GETITEMCOUNT(infoPtr);
3158 break;
3161 return nItemCount;
3164 /* LISTVIEW_GetEditControl */
3165 /* LISTVIEW_GetExtendedListViewStyle */
3167 /***
3168 * DESCRIPTION:
3169 * Retrieves the handle to the header control.
3171 * PARAMETER(S):
3172 * [I] HWND : window handle
3174 * RETURN:
3175 * Header handle.
3177 static LRESULT LISTVIEW_GetHeader(HWND hwnd)
3179 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3181 return infoPtr->hwndHeader;
3184 /* LISTVIEW_GetHotCursor */
3185 /* LISTVIEW_GetHotItem */
3186 /* LISTVIEW_GetHoverTime */
3188 /***
3189 * DESCRIPTION:
3190 * Retrieves an image list handle.
3192 * PARAMETER(S):
3193 * [I] HWND : window handle
3194 * [I] INT : image list identifier
3196 * RETURN:
3197 * SUCCESS : image list handle
3198 * FAILURE : NULL
3200 static LRESULT LISTVIEW_GetImageList(HWND hwnd, INT nImageList)
3202 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3203 HIMAGELIST himl = NULL;
3205 switch (nImageList)
3207 case LVSIL_NORMAL:
3208 himl = infoPtr->himlNormal;
3209 break;
3210 case LVSIL_SMALL:
3211 himl = infoPtr->himlSmall;
3212 break;
3213 case LVSIL_STATE:
3214 himl = infoPtr->himlState;
3215 break;
3218 return (LRESULT)himl;
3221 /* LISTVIEW_GetISearchString */
3223 /***
3224 * DESCRIPTION:
3225 * Retrieves item attributes.
3227 * PARAMETER(S):
3228 * [I] HWND : window handle
3229 * [IO] LPLVITEMA : item info
3231 * RETURN:
3232 * SUCCESS : TRUE
3233 * FAILURE : FALSE
3235 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem)
3237 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3238 LISTVIEW_ITEM *lpItem;
3239 LISTVIEW_SUBITEM *lpSubItem;
3240 HDPA hdpaSubItems;
3241 BOOL bResult = FALSE;
3243 TRACE(listview, "(hwnd=%x,lpLVItem=%p)\n", hwnd, lpLVItem);
3245 if (lpLVItem != NULL)
3247 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
3249 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
3250 if (hdpaSubItems != NULL)
3252 if (lpLVItem->iSubItem == 0)
3254 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3255 if (lpItem != NULL)
3257 bResult = TRUE;
3259 /* retrieve valid data */
3260 if (lpLVItem->mask & LVIF_STATE)
3262 lpLVItem->state = lpItem->state & lpLVItem->stateMask;
3265 if (lpLVItem->mask & LVIF_TEXT)
3267 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
3269 lpLVItem->pszText = LPSTR_TEXTCALLBACKA;
3271 else
3273 bResult = Str_GetPtrA(lpItem->pszText, lpLVItem->pszText,
3274 lpLVItem->cchTextMax);
3278 if (lpLVItem->mask & LVIF_IMAGE)
3280 lpLVItem->iImage = lpItem->iImage;
3283 if (lpLVItem->mask & LVIF_PARAM)
3285 lpLVItem->lParam = lpItem->lParam;
3288 if (lpLVItem->mask & LVIF_INDENT)
3290 lpLVItem->iIndent = lpItem->iIndent;
3294 else
3296 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems,
3297 lpLVItem->iSubItem);
3298 if (lpSubItem != NULL)
3300 bResult = TRUE;
3302 if (lpLVItem->mask & LVIF_TEXT)
3304 if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
3306 lpLVItem->pszText = LPSTR_TEXTCALLBACKA;
3308 else
3310 bResult = Str_GetPtrA(lpSubItem->pszText, lpLVItem->pszText,
3311 lpLVItem->cchTextMax);
3315 if (lpLVItem->mask & LVIF_IMAGE)
3317 lpLVItem->iImage = lpSubItem->iImage;
3325 return bResult;
3328 /* LISTVIEW_GetItemW */
3329 /* LISTVIEW_GetHotCursor */
3330 /* LISTVIEW_GetHotItem */
3331 /* LISTVIEW_GetHoverTime> */
3333 /***
3334 * DESCRIPTION:
3335 * Retrieves the number of items in the listview control.
3337 * PARAMETER(S):
3338 * [I] HWND : window handle
3340 * RETURN:
3341 * Number of items.
3343 static LRESULT LISTVIEW_GetItemCount(HWND hwnd)
3345 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3347 return GETITEMCOUNT(infoPtr);
3350 /***
3351 * DESCRIPTION:
3352 * Retrieves the position (upper-left) of the listview control item.
3354 * PARAMETER(S):
3355 * [I] HWND : window handle
3356 * [I] INT : item index
3357 * [O] LPPOINT : coordinate information
3359 * RETURN:
3360 * SUCCESS : TRUE
3361 * FAILURE : FALSE
3363 static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem,
3364 LPPOINT lpptPosition)
3366 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3367 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3368 BOOL bResult = FALSE;
3369 HDPA hdpaSubItems;
3370 LISTVIEW_ITEM *lpItem;
3371 INT nRow;
3373 TRACE(listview, "(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd, nItem,
3374 lpptPosition);
3376 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
3377 (lpptPosition != NULL))
3379 switch (LVS_TYPEMASK & lStyle)
3381 case LVS_LIST:
3382 bResult = TRUE;
3383 nItem = nItem - ListView_GetTopIndex(hwnd);
3384 if (nItem < 0)
3386 nRow = nItem % infoPtr->nCountPerColumn;
3387 if (nRow == 0)
3389 lpptPosition->x = (nItem / infoPtr->nCountPerColumn *
3390 infoPtr->nItemWidth);
3391 lpptPosition->y = 0;
3393 else
3395 lpptPosition->x = ((nItem / infoPtr->nCountPerColumn - 1) *
3396 infoPtr->nItemWidth);
3397 lpptPosition->y = ((nRow + infoPtr->nCountPerColumn) *
3398 infoPtr->nItemHeight);
3401 else
3403 lpptPosition->x = (nItem / infoPtr->nCountPerColumn *
3404 infoPtr->nItemWidth);
3405 lpptPosition->y = (nItem % infoPtr->nCountPerColumn *
3406 infoPtr->nItemHeight);
3408 break;
3410 case LVS_REPORT:
3411 bResult = TRUE;
3412 lpptPosition->x = REPORT_MARGINX;
3413 lpptPosition->y = ((nItem - ListView_GetTopIndex(hwnd)) *
3414 infoPtr->nItemHeight) + infoPtr->rcList.top;
3415 break;
3417 case LVS_SMALLICON:
3418 case LVS_ICON:
3419 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
3420 if (hdpaSubItems != NULL)
3422 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3423 if (lpItem != NULL)
3425 bResult = TRUE;
3426 lpptPosition->x = lpItem->ptPosition.x;
3427 lpptPosition->y = lpItem->ptPosition.y;
3430 break;
3434 return bResult;
3437 /***
3438 * DESCRIPTION:
3439 * Retrieves the bounding rectangle for a listview control item.
3441 * PARAMETER(S):
3442 * [I] HWND : window handle
3443 * [I] INT : item index
3444 * [IO] LPRECT : bounding rectangle coordinates
3446 * RETURN:
3447 * SUCCESS : TRUE
3448 * FAILURE : FALSE
3450 static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc)
3452 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3453 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3454 BOOL bResult = FALSE;
3455 POINT ptOrigin;
3456 POINT ptItem;
3457 HDC hdc;
3458 HFONT hOldFont;
3459 INT nMaxWidth;
3460 INT nLabelWidth;
3461 TEXTMETRICA tm;
3463 TRACE(listview, "(hwnd=%x,nItem=%d,lprc=%p)\n", hwnd, nItem, lprc);
3465 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL))
3467 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) != FALSE)
3469 switch(lprc->left)
3471 case LVIR_ICON:
3472 switch (LVS_TYPEMASK & lStyle)
3474 case LVS_ICON:
3475 if (infoPtr->himlNormal != NULL)
3477 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3479 bResult = TRUE;
3480 lprc->left = ptItem.x + ptOrigin.x;
3481 lprc->top = ptItem.y + ptOrigin.y;
3482 lprc->right = lprc->left + infoPtr->iconSize.cx;
3483 lprc->bottom = (lprc->top + infoPtr->iconSize.cy +
3484 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
3487 break;
3489 case LVS_SMALLICON:
3490 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3492 bResult = TRUE;
3493 lprc->left = ptItem.x + ptOrigin.x;
3494 lprc->top = ptItem.y + ptOrigin.y;
3495 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3497 if (infoPtr->himlState != NULL)
3499 lprc->left += infoPtr->iconSize.cx;
3502 if (infoPtr->himlSmall != NULL)
3504 lprc->right = lprc->left + infoPtr->iconSize.cx;
3506 else
3508 lprc->right = lprc->left;
3511 break;
3513 case LVS_REPORT:
3514 case LVS_LIST:
3515 bResult = TRUE;
3516 lprc->left = ptItem.x;
3517 lprc->top = ptItem.y;
3518 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3520 if (infoPtr->himlState != NULL)
3522 lprc->left += infoPtr->iconSize.cx;
3525 if (infoPtr->himlSmall != NULL)
3527 lprc->right = lprc->left + infoPtr->iconSize.cx;
3529 else
3531 lprc->right = lprc->left;
3533 break;
3535 break;
3537 case LVIR_LABEL:
3538 switch (LVS_TYPEMASK & lStyle)
3540 case LVS_ICON:
3541 if (infoPtr->himlNormal != NULL)
3543 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3545 bResult = TRUE;
3546 lprc->left = ptItem.x + ptOrigin.x;
3547 lprc->top = (ptItem.y + ptOrigin.y + infoPtr->iconSize.cy +
3548 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
3549 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3550 if (infoPtr->iconSpacing.cx - nLabelWidth > 1)
3552 lprc->left += (infoPtr->iconSpacing.cx - nLabelWidth) / 2;
3553 lprc->right = lprc->left + nLabelWidth;
3555 else
3557 lprc->left += 1;
3558 lprc->right = lprc->left + infoPtr->iconSpacing.cx - 1;
3561 hdc = GetDC(hwnd);
3562 hOldFont = SelectObject(hdc, infoPtr->hFont);
3563 GetTextMetricsA(hdc, &tm);
3564 lprc->bottom = lprc->top + tm.tmHeight + HEIGHT_PADDING;
3565 SelectObject(hdc, hOldFont);
3566 ReleaseDC(hwnd, hdc);
3569 break;
3571 case LVS_SMALLICON:
3572 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3574 bResult = TRUE;
3575 nMaxWidth = lprc->left = ptItem.x + ptOrigin.x;
3576 lprc->top = ptItem.y + ptOrigin.y;
3577 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3579 if (infoPtr->himlState != NULL)
3581 lprc->left += infoPtr->iconSize.cx;
3584 if (infoPtr->himlSmall != NULL)
3586 lprc->left += infoPtr->iconSize.cx;
3589 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3590 if (lprc->left + nLabelWidth < nMaxWidth + infoPtr->nItemWidth)
3592 lprc->right = lprc->left + nLabelWidth;
3594 else
3596 lprc->right = nMaxWidth + infoPtr->nItemWidth;
3599 break;
3601 case LVS_REPORT:
3602 case LVS_LIST:
3603 bResult = TRUE;
3604 lprc->left = ptItem.x;
3605 lprc->top = ptItem.y;
3606 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3608 if (infoPtr->himlState != NULL)
3610 lprc->left += infoPtr->iconSize.cx;
3613 if (infoPtr->himlSmall != NULL)
3615 lprc->left += infoPtr->iconSize.cx;
3618 lprc->right = lprc->left + LISTVIEW_GetLabelWidth(hwnd, nItem);
3619 break;
3621 break;
3623 case LVIR_BOUNDS:
3624 switch (LVS_TYPEMASK & lStyle)
3626 case LVS_ICON:
3627 if (infoPtr->himlNormal != NULL)
3629 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3631 bResult = TRUE;
3632 lprc->left = ptItem.x + ptOrigin.x;
3633 lprc->top = ptItem.y + ptOrigin.y;
3634 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
3635 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
3638 break;
3640 case LVS_SMALLICON:
3641 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3643 bResult = TRUE;
3644 lprc->left = ptItem.x +ptOrigin.x;
3645 lprc->right = lprc->left;
3646 lprc->top = ptItem.y + ptOrigin.y;
3647 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3649 if (infoPtr->himlState != NULL)
3651 lprc->right += infoPtr->iconSize.cx;
3654 if (infoPtr->himlSmall != NULL)
3656 lprc->right += infoPtr->iconSize.cx;
3659 lprc->right += LISTVIEW_GetLabelWidth(hwnd, nItem);
3661 break;
3663 case LVS_REPORT:
3664 case LVS_LIST:
3665 bResult = TRUE;
3666 lprc->left = ptItem.x;
3667 lprc->right = lprc->left;
3668 lprc->top = ptItem.y;
3669 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3671 if (infoPtr->himlState != NULL)
3673 lprc->right += infoPtr->iconSize.cx;
3676 if (infoPtr->himlSmall != NULL)
3678 lprc->right += infoPtr->iconSize.cx;
3681 lprc->right += LISTVIEW_GetLabelWidth(hwnd, nItem);
3682 break;
3684 break;
3686 case LVIR_SELECTBOUNDS:
3687 switch (LVS_TYPEMASK & lStyle)
3689 case LVS_ICON:
3690 if (infoPtr->himlNormal != NULL)
3692 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3694 bResult = TRUE;
3695 lprc->left = ptItem.x + ptOrigin.x;
3696 lprc->top = ptItem.y + ptOrigin.y;
3697 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
3698 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
3701 break;
3703 case LVS_SMALLICON:
3704 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3706 bResult = TRUE;
3707 lprc->left = ptItem.x + ptOrigin.x;
3708 lprc->top = ptItem.y + ptOrigin.y;
3709 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3711 if (infoPtr->himlState != NULL)
3713 lprc->left += infoPtr->iconSize.cx;
3716 lprc->right = lprc->left;
3718 if (infoPtr->himlSmall != NULL)
3720 lprc->right += infoPtr->iconSize.cx;
3723 lprc->right += LISTVIEW_GetLabelWidth(hwnd, nItem);
3725 break;
3727 case LVS_REPORT:
3728 case LVS_LIST:
3729 bResult = TRUE;
3730 lprc->left = ptItem.x;
3731 lprc->top = ptItem.y;
3732 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3734 if (infoPtr->himlState != NULL)
3736 lprc->left += infoPtr->iconSize.cx;
3739 lprc->right = lprc->left;
3741 if (infoPtr->himlSmall != NULL)
3743 lprc->right += infoPtr->iconSize.cx;
3746 lprc->right += LISTVIEW_GetLabelWidth(hwnd, nItem);
3747 break;
3749 break;
3754 return bResult;
3757 /***
3758 * DESCRIPTION:
3759 * Retrieves the width of a label.
3761 * PARAMETER(S):
3762 * [I] HWND : window handle
3764 * RETURN:
3765 * SUCCESS : string width (in pixels)
3766 * FAILURE : zero
3769 static INT LISTVIEW_GetLabelWidth(HWND hwnd, INT nItem)
3771 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3772 LISTVIEW_ITEM *lpItem;
3773 HDPA hdpaSubItems;
3774 INT nLabelWidth = 0;
3776 TRACE(listview, "(hwnd=%x,nItem=%d)\n", hwnd, nItem);
3778 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
3779 if (hdpaSubItems != NULL)
3781 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3782 if (lpItem != NULL)
3784 CHAR szDispText[DISP_TEXT_SIZE];
3785 LPSTR pszDispText = NULL;
3786 pszDispText = szDispText;
3787 LISTVIEW_GetItemDispInfo(hwnd, nItem, lpItem, NULL, NULL, &pszDispText,
3788 DISP_TEXT_SIZE);
3789 nLabelWidth = ListView_GetStringWidthA(hwnd, pszDispText);
3793 return nLabelWidth;
3796 /***
3797 * DESCRIPTION:
3798 * Retrieves the spacing between listview control items.
3800 * PARAMETER(S):
3801 * [I] HWND : window handle
3802 * [I] BOOL : flag for small or large icon
3804 * RETURN:
3805 * Horizontal + vertical spacing
3807 static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall)
3809 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3810 LONG lResult;
3812 if (bSmall == FALSE)
3814 lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
3816 else
3818 /* TODO: need to store width of smallicon item */
3819 lResult = MAKELONG(0, infoPtr->nItemHeight);
3822 return lResult;
3825 /***
3826 * DESCRIPTION:
3827 * Retrieves the state of a listview control item.
3829 * PARAMETER(S):
3830 * [I] HWND : window handle
3831 * [I] INT : item index
3832 * [I] UINT : state mask
3834 * RETURN:
3835 * State specified by the mask.
3837 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask)
3839 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3840 LVITEMA lvItem;
3841 UINT uState = 0;
3843 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
3845 ZeroMemory(&lvItem, sizeof(LVITEMA));
3846 lvItem.iItem = nItem;
3847 lvItem.stateMask = uMask;
3848 lvItem.mask = LVIF_STATE;
3849 if (ListView_GetItemA(hwnd, &lvItem) != FALSE)
3851 uState = lvItem.state;
3855 return uState;
3858 /***
3859 * DESCRIPTION:
3860 * Retrieves the text of a listview control item or subitem.
3862 * PARAMETER(S):
3863 * [I] HWND : window handle
3864 * [I] INT : item index
3865 * [IO] LPLVITEMA : item information
3867 * RETURN:
3868 * None
3870 static LRESULT LISTVIEW_GetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
3872 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3873 LISTVIEW_ITEM *lpItem;
3874 LISTVIEW_SUBITEM *lpSubItem;
3875 HDPA hdpaSubItems;
3876 INT nLength = 0;
3878 if (lpLVItem != NULL)
3880 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
3882 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
3883 if (hdpaSubItems != NULL)
3885 if (lpLVItem->iSubItem == 0)
3887 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3888 if (lpItem != NULL)
3890 if (lpLVItem->mask & LVIF_TEXT)
3892 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
3894 lpLVItem->pszText = LPSTR_TEXTCALLBACKA;
3896 else
3898 nLength = Str_GetPtrA(lpItem->pszText, lpLVItem->pszText,
3899 lpLVItem->cchTextMax);
3904 else
3906 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems,
3907 lpLVItem->iSubItem);
3908 if (lpSubItem != NULL)
3910 if (lpLVItem->mask & LVIF_TEXT)
3912 if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
3914 lpLVItem->pszText = LPSTR_TEXTCALLBACKA;
3916 else
3918 nLength = Str_GetPtrA(lpSubItem->pszText, lpLVItem->pszText,
3919 lpLVItem->cchTextMax);
3928 return nLength;
3931 /***
3932 * DESCRIPTION:
3933 * Searches for an item based on properties + relationships.
3935 * PARAMETER(S):
3936 * [I] HWND : window handle
3937 * [I] INT : starting search item index
3938 * [I] UINT : relationship flag
3940 * RETURN:
3941 * SUCCESS : item index
3942 * FAILURE : -1
3944 static LRESULT LISTVIEW_GetNextItem(HWND hwnd, INT iStart, UINT uFlags)
3946 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
3947 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3948 LISTVIEW_ITEM *lpItem;
3949 UINT style_mask = LVS_TYPEMASK & lStyle;
3950 UINT uMask = 0;
3951 INT nItems = GETITEMCOUNT(infoPtr);
3952 INT iIndex = iStart;
3953 INT eIndex = nItems - 1;
3954 INT sIndex = 0;
3955 INT delta = 1;
3957 INT nCountPerColumn = max((infoPtr->rcList.bottom - infoPtr->rcList.top) /
3958 infoPtr->nItemHeight, 1);
3959 INT nCountPerRow = max((infoPtr->rcList.right - infoPtr->rcList.left) /
3960 infoPtr->nItemWidth, 1);
3962 if(uFlags & LVNI_ABOVE) /* moving upwards from iStart */
3964 if(style_mask == LVS_LIST || style_mask == LVS_REPORT)
3965 delta = -1;
3966 else
3968 if(lStyle & LVS_ALIGNLEFT)
3970 sIndex = iStart - (iStart % nCountPerColumn);
3971 delta = -1;
3973 else
3974 delta = -nCountPerRow;
3977 else if(uFlags & LVNI_BELOW) /* moving downwards from iStart */
3979 if(style_mask == LVS_SMALLICON || style_mask == LVS_ICON)
3981 if (lStyle & LVS_ALIGNLEFT)
3982 eIndex = iStart + (nCountPerColumn - (iStart % nCountPerColumn) - 1);
3983 else
3984 delta = nCountPerRow;
3987 else if(uFlags & LVNI_TOLEFT) /* moving to the left of iStart */
3989 if(style_mask == LVS_LIST)
3990 delta = -infoPtr->nCountPerColumn;
3991 else if(style_mask == LVS_SMALLICON || style_mask == LVS_ICON)
3993 if(style_mask & LVS_ALIGNLEFT)
3994 delta = -nCountPerColumn;
3995 else
3997 sIndex = iStart - (iStart % nCountPerRow);
3998 delta = -1;
4001 else if(style_mask == LVS_REPORT)
4002 return -1;
4004 else if(uFlags & LVNI_TORIGHT) /* moving to the right of iStart */
4006 if(style_mask == LVS_LIST)
4007 delta = infoPtr->nCountPerColumn;
4008 else if(style_mask == LVS_ICON || style_mask == LVS_SMALLICON)
4010 if(lStyle & LVS_ALIGNLEFT)
4011 delta = nCountPerColumn;
4012 else
4013 eIndex = iStart + (nCountPerRow - (iStart % nCountPerRow) - 1);
4015 else if(style_mask == LVS_REPORT)
4016 return -1;
4019 /* perform come bounds checking before entering the main loop */
4020 if(sIndex < 0) sIndex = 0;
4021 if(eIndex > (nItems - 1)) eIndex = (nItems - 1);
4023 /* build uMask, the mask we are searching for */
4024 if(uFlags & LVNI_CUT) uMask|=LVIS_CUT;
4025 if(uFlags & LVNI_DROPHILITED) uMask|=LVIS_DROPHILITED;
4026 if(uFlags & LVNI_FOCUSED) uMask|=LVIS_FOCUSED;
4027 if(uFlags & LVNI_SELECTED) uMask|=LVIS_SELECTED;
4029 while(TRUE) /* searching loop */
4031 iIndex+=delta;
4033 if((iIndex < sIndex) || (iIndex > eIndex))
4034 break;
4036 /* see if flags match */
4037 if(!uMask || (LISTVIEW_GetItemState(hwnd, iIndex, uMask) == uMask))
4038 return iIndex;
4040 return -1;
4043 /* LISTVIEW_GetNumberOfWorkAreas */
4045 /***
4046 * DESCRIPTION:
4047 * Retrieves the origin coordinates when in icon or small icon display mode.
4049 * PARAMETER(S):
4050 * [I] HWND : window handle
4051 * [O] LPPOINT : coordinate information
4053 * RETURN:
4054 * SUCCESS : TRUE
4055 * FAILURE : FALSE
4057 static LRESULT LISTVIEW_GetOrigin(HWND hwnd, LPPOINT lpptOrigin)
4059 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4060 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4061 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
4062 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
4063 BOOL bResult = FALSE;
4065 TRACE(listview, "(hwnd=%x,lpptOrigin=%p)\n", hwnd, lpptOrigin);
4067 switch (LVS_TYPEMASK & lStyle)
4069 case LVS_ICON:
4070 case LVS_SMALLICON:
4071 if ((lStyle & WS_HSCROLL) != 0)
4073 lpptOrigin->x = -GetScrollPos(hwnd, SB_HORZ) * nListWidth / 10;
4075 else
4077 lpptOrigin->x = 0;
4080 if ((lStyle & WS_VSCROLL) != 0)
4082 lpptOrigin->y = -GetScrollPos(hwnd, SB_VERT) * nListHeight / 10;
4084 else
4086 lpptOrigin->y = 0;
4089 bResult = TRUE;
4090 break;
4093 return bResult;
4096 /***
4097 * DESCRIPTION:
4098 * Retrieves the number of items that are marked as selected.
4100 * PARAMETER(S):
4101 * [I] HWND : window handle
4103 * RETURN:
4104 * Number of items selected.
4106 static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd)
4108 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4109 INT nSelectedCount = 0;
4110 INT i;
4112 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4114 if (ListView_GetItemState(hwnd, i, LVIS_SELECTED) & LVIS_SELECTED)
4116 nSelectedCount++;
4120 return nSelectedCount;
4123 /***
4124 * DESCRIPTION:
4125 * Retrieves item index that marks the start of a multiple selection.
4127 * PARAMETER(S):
4128 * [I] HWND : window handle
4130 * RETURN:
4131 * Index number or -1 if there is no selection mark.
4133 static LRESULT LISTVIEW_GetSelectionMark(HWND hwnd)
4135 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4137 return infoPtr->nSelectionMark;
4140 /***
4141 * DESCRIPTION:
4142 * Retrieves the width of a string.
4144 * PARAMETER(S):
4145 * [I] HWND : window handle
4147 * RETURN:
4148 * SUCCESS : string width (in pixels)
4149 * FAILURE : zero
4151 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText)
4153 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4154 HFONT hFont, hOldFont;
4155 SIZE stringSize;
4156 HDC hdc;
4158 ZeroMemory(&stringSize, sizeof(SIZE));
4159 if (lpszText != NULL)
4161 hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
4162 hdc = GetDC(hwnd);
4163 hOldFont = SelectObject(hdc, hFont);
4164 GetTextExtentPointA(hdc, lpszText, lstrlenA(lpszText), &stringSize);
4165 SelectObject(hdc, hOldFont);
4166 ReleaseDC(hwnd, hdc);
4169 return stringSize.cx;
4172 /***
4173 * DESCRIPTION:
4174 * Retrieves the text backgound color.
4176 * PARAMETER(S):
4177 * [I] HWND : window handle
4179 * RETURN:
4180 * COLORREF associated with the the background.
4182 static LRESULT LISTVIEW_GetTextBkColor(HWND hwnd)
4184 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4186 return infoPtr->clrTextBk;
4189 /***
4190 * DESCRIPTION:
4191 * Retrieves the text color.
4193 * PARAMETER(S):
4194 * [I] HWND : window handle
4196 * RETURN:
4197 * COLORREF associated with the text.
4199 static LRESULT LISTVIEW_GetTextColor(HWND hwnd)
4201 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4203 return infoPtr->clrText;
4206 /***
4207 * DESCRIPTION:
4208 * Set the bounding rectangle of all the items.
4210 * PARAMETER(S):
4211 * [I] HWND : window handle
4212 * [I] LPRECT : bounding rectangle
4214 * RETURN:
4215 * SUCCESS : TRUE
4216 * FAILURE : FALSE
4218 static LRESULT LISTVIEW_SetViewRect(HWND hwnd, LPRECT lprcView)
4220 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4221 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4222 BOOL bResult = FALSE;
4224 TRACE(listview, "(hwnd=%x,lprcView->left=%d,lprcView->top=%d,lprcView->right=%d,lprcView->bottom=%d)\n", hwnd, lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
4226 if (lprcView != NULL)
4228 switch (lStyle & LVS_TYPEMASK)
4230 case LVS_ICON:
4231 case LVS_SMALLICON:
4232 bResult = TRUE;
4233 infoPtr->rcView.left = lprcView->left;
4234 infoPtr->rcView.top = lprcView->top;
4235 infoPtr->rcView.right = lprcView->right;
4236 infoPtr->rcView.bottom = lprcView->bottom;
4237 break;
4241 return bResult;
4244 /***
4245 * DESCRIPTION:
4246 * Retrieves the bounding rectangle of all the items.
4248 * PARAMETER(S):
4249 * [I] HWND : window handle
4250 * [O] LPRECT : bounding rectangle
4252 * RETURN:
4253 * SUCCESS : TRUE
4254 * FAILURE : FALSE
4256 static LRESULT LISTVIEW_GetViewRect(HWND hwnd, LPRECT lprcView)
4258 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4259 BOOL bResult = FALSE;
4260 POINT ptOrigin;
4262 TRACE(listview, "(hwnd=%x,lprcView=%p)\n", hwnd, lprcView);
4264 if (lprcView != NULL)
4266 bResult = LISTVIEW_GetOrigin(hwnd, &ptOrigin);
4267 if (bResult != FALSE)
4269 lprcView->left = infoPtr->rcView.left + ptOrigin.x;
4270 lprcView->top = infoPtr->rcView.top + ptOrigin.y;
4271 lprcView->right = infoPtr->rcView.right + ptOrigin.x;
4272 lprcView->bottom = infoPtr->rcView.bottom + ptOrigin.y;
4275 TRACE(listview, "(lprcView->left=%d,lprcView->top=%d,lprcView->right=%d,lprcView->bottom=%d)\n", lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
4279 return bResult;
4282 /***
4283 * DESCRIPTION:
4284 * Determines which section of the item was selected (if any).
4286 * PARAMETER(S):
4287 * [I] HWND : window handle
4288 * [IO] LPLVHITTESTINFO : hit test information
4290 * RETURN:
4291 * SUCCESS : item index
4292 * FAILURE : -1
4294 static INT LISTVIEW_HitTestItem(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4296 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4297 RECT rcItem;
4298 INT i;
4300 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4302 rcItem.left = LVIR_BOUNDS;
4303 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4305 rcItem.left = LVIR_ICON;
4306 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4308 if ((lpHitTestInfo->pt.x >= rcItem.left) &&
4309 (lpHitTestInfo->pt.x <= rcItem.right) &&
4310 (lpHitTestInfo->pt.y >= rcItem.top) &&
4311 (lpHitTestInfo->pt.y <= rcItem.bottom))
4313 lpHitTestInfo->flags = LVHT_ONITEMICON | LVHT_ONITEM;
4314 lpHitTestInfo->iItem = i;
4315 lpHitTestInfo->iSubItem = 0;
4316 return i;
4320 rcItem.left = LVIR_LABEL;
4321 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4323 if ((lpHitTestInfo->pt.x >= rcItem.left) &&
4324 (lpHitTestInfo->pt.x <= rcItem.right) &&
4325 (lpHitTestInfo->pt.y >= rcItem.top) &&
4326 (lpHitTestInfo->pt.y <= rcItem.bottom))
4328 lpHitTestInfo->flags = LVHT_ONITEMLABEL | LVHT_ONITEM;
4329 lpHitTestInfo->iItem = i;
4330 lpHitTestInfo->iSubItem = 0;
4331 return i;
4335 lpHitTestInfo->flags = LVHT_ONITEMSTATEICON | LVHT_ONITEM;
4336 lpHitTestInfo->iItem = i;
4337 lpHitTestInfo->iSubItem = 0;
4338 return i;
4342 lpHitTestInfo->flags = LVHT_NOWHERE;
4344 return -1;
4347 /***
4348 * DESCRIPTION:
4349 * Determines wich listview item is located at the specified position.
4351 * PARAMETER(S):
4352 * [I] HWND : window handle
4353 * [IO} LPLVHITTESTINFO : hit test information
4355 * RETURN:
4356 * SUCCESS : item index
4357 * FAILURE : -1
4359 static LRESULT LISTVIEW_HitTest(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4361 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4362 INT nItem = -1;
4364 lpHitTestInfo->flags = 0;
4365 if (infoPtr->rcList.left > lpHitTestInfo->pt.x)
4367 lpHitTestInfo->flags = LVHT_TOLEFT;
4369 else if (infoPtr->rcList.right < lpHitTestInfo->pt.x)
4371 lpHitTestInfo->flags = LVHT_TORIGHT;
4374 if (infoPtr->rcList.top > lpHitTestInfo->pt.y)
4376 lpHitTestInfo->flags |= LVHT_ABOVE;
4378 else if (infoPtr->rcList.bottom < lpHitTestInfo->pt.y)
4380 lpHitTestInfo->flags |= LVHT_BELOW;
4383 if (lpHitTestInfo->flags == 0)
4385 nItem = LISTVIEW_HitTestItem(hwnd, lpHitTestInfo);
4388 return nItem;
4391 /***
4392 * DESCRIPTION:
4393 * Inserts a new column.
4395 * PARAMETER(S):
4396 * [I] HWND : window handle
4397 * [I] INT : column index
4398 * [I] LPLVCOLUMNA : column information
4400 * RETURN:
4401 * SUCCESS : new column index
4402 * FAILURE : -1
4404 static LRESULT LISTVIEW_InsertColumnA(HWND hwnd, INT nColumn,
4405 LPLVCOLUMNA lpColumn)
4407 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4408 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4409 HDITEMA hdi;
4410 INT nNewColumn = -1;
4412 TRACE(listview,"(hwnd=%x,nColumn=%d,lpColumn=%p)\n",hwnd, nColumn, lpColumn);
4414 if (lpColumn != NULL)
4416 /* initialize memory */
4417 ZeroMemory(&hdi, sizeof(HDITEMA));
4419 if (lpColumn->mask & LVCF_FMT)
4421 /* format member is valid */
4422 hdi.mask |= HDI_FORMAT;
4424 /* set text alignment (leftmost column must be left-aligned) */
4425 if (nColumn == 0)
4427 hdi.fmt |= HDF_LEFT;
4429 else
4431 if (lpColumn->fmt & LVCFMT_LEFT)
4433 hdi.fmt |= HDF_LEFT;
4435 else if (lpColumn->fmt & LVCFMT_RIGHT)
4437 hdi.fmt |= HDF_RIGHT;
4439 else if (lpColumn->fmt & LVCFMT_CENTER)
4441 hdi.fmt |= HDF_CENTER;
4445 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
4447 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
4448 /* ??? */
4451 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
4453 /* ??? */
4456 if (lpColumn->fmt & LVCFMT_IMAGE)
4458 hdi.fmt |= HDF_IMAGE;
4459 hdi.iImage = I_IMAGECALLBACK;
4463 if (lpColumn->mask & LVCF_WIDTH)
4465 hdi.mask |= HDI_WIDTH;
4466 hdi.cxy = lpColumn->cx;
4469 if (lpColumn->mask & LVCF_TEXT)
4471 hdi.mask |= HDI_TEXT | HDI_FORMAT;
4472 hdi.pszText = lpColumn->pszText;
4473 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
4474 hdi.fmt |= HDF_STRING;
4477 if (lpColumn->mask & LVCF_IMAGE)
4479 hdi.mask |= HDI_IMAGE;
4480 hdi.iImage = lpColumn->iImage;
4483 if (lpColumn->mask & LVCF_ORDER)
4485 hdi.mask |= HDI_ORDER;
4486 hdi.iOrder = lpColumn->iOrder;
4489 /* insert item in header control */
4490 nNewColumn = SendMessageA(infoPtr->hwndHeader, HDM_INSERTITEMA,
4491 (WPARAM)nColumn, (LPARAM)&hdi);
4493 LISTVIEW_SetScroll(hwnd, lStyle);
4494 InvalidateRect(hwnd, NULL, FALSE);
4497 return nNewColumn;
4500 /* LISTVIEW_InsertColumnW */
4502 /***
4503 * DESCRIPTION:
4504 * Inserts a new item in the listview control.
4506 * PARAMETER(S):
4507 * [I] HWND : window handle
4508 * [I] LPLVITEMA : item information
4510 * RETURN:
4511 * SUCCESS : new item index
4512 * FAILURE : -1
4514 static LRESULT LISTVIEW_InsertItemA(HWND hwnd, LPLVITEMA lpLVItem)
4516 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4517 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4518 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
4519 NMLISTVIEW nmlv;
4520 INT nItem = -1;
4521 HDPA hdpaSubItems;
4522 LISTVIEW_ITEM *lpItem = NULL;
4524 TRACE(listview, "(hwnd=%x,lpLVItem=%p)\n", hwnd, lpLVItem);
4526 if (lpLVItem != NULL)
4528 /* make sure it's not a subitem; cannot insert a subitem */
4529 if (lpLVItem->iSubItem == 0)
4531 lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM));
4532 if (lpItem != NULL)
4534 ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
4535 if (LISTVIEW_InitItem(hwnd, lpItem, lpLVItem) != FALSE)
4537 /* insert item in listview control data structure */
4538 hdpaSubItems = DPA_Create(8);
4539 if (hdpaSubItems != NULL)
4541 nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem);
4542 if (nItem != -1)
4544 nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpLVItem->iItem,
4545 hdpaSubItems);
4546 if (nItem != -1)
4548 /* manage item focus */
4549 if (lpLVItem->mask & LVIF_STATE)
4551 if (lpLVItem->stateMask & LVIS_FOCUSED)
4553 LISTVIEW_SetItemFocus(hwnd, nItem);
4557 /* send LVN_INSERTITEM notification */
4558 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
4559 nmlv.hdr.hwndFrom = hwnd;
4560 nmlv.hdr.idFrom = lCtrlId;
4561 nmlv.hdr.code = LVN_INSERTITEM;
4562 nmlv.iItem = nItem;
4563 nmlv.lParam = lpItem->lParam;;
4564 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
4566 /* align items (set position of each item) */
4567 switch (lStyle & LVS_TYPEMASK)
4569 case LVS_ICON:
4570 case LVS_SMALLICON:
4571 if (lStyle & LVS_ALIGNLEFT)
4573 LISTVIEW_AlignLeft(hwnd);
4575 else
4577 LISTVIEW_AlignTop(hwnd);
4579 break;
4582 LISTVIEW_SetScroll(hwnd, lStyle);
4583 /* refresh client area */
4584 InvalidateRect(hwnd, NULL, FALSE);
4593 /* free memory if unsuccessful */
4594 if ((nItem == -1) && (lpItem != NULL))
4596 COMCTL32_Free(lpItem);
4599 return nItem;
4602 /* LISTVIEW_InsertItemW */
4604 /***
4605 * DESCRIPTION:
4606 * Redraws a range of items.
4608 * PARAMETER(S):
4609 * [I] HWND : window handle
4610 * [I] INT : first item
4611 * [I] INT : last item
4613 * RETURN:
4614 * SUCCESS : TRUE
4615 * FAILURE : FALSE
4617 static LRESULT LISTVIEW_RedrawItems(HWND hwnd, INT nFirst, INT nLast)
4619 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4620 BOOL bResult = FALSE;
4621 RECT rc;
4623 if (nFirst <= nLast)
4625 if ((nFirst >= 0) && (nFirst < GETITEMCOUNT(infoPtr)))
4627 if ((nLast >= 0) && (nLast < GETITEMCOUNT(infoPtr)))
4629 /* bResult = */
4630 InvalidateRect(hwnd, &rc, FALSE);
4635 return bResult;
4638 /* LISTVIEW_Scroll */
4640 /***
4641 * DESCRIPTION:
4642 * Sets the background color.
4644 * PARAMETER(S):
4645 * [I] HWND : window handle
4646 * [I] COLORREF : background color
4648 * RETURN:
4649 * SUCCESS : TRUE
4650 * FAILURE : FALSE
4652 static LRESULT LISTVIEW_SetBkColor(HWND hwnd, COLORREF clrBk)
4654 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4656 infoPtr->clrBk = clrBk;
4657 InvalidateRect(hwnd, NULL, TRUE);
4659 return TRUE;
4662 /***
4663 * DESCRIPTION:
4664 * Sets the callback mask. This mask will be used when the parent
4665 * window stores state information (some or all).
4667 * PARAMETER(S):
4668 * [I] HWND : window handle
4669 * [I] UINT : state mask
4671 * RETURN:
4672 * SUCCESS : TRUE
4673 * FAILURE : FALSE
4675 static BOOL LISTVIEW_SetCallbackMask(HWND hwnd, UINT uMask)
4677 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4679 infoPtr->uCallbackMask = uMask;
4681 return TRUE;
4684 /***
4685 * DESCRIPTION:
4686 * Sets the attributes of a header item.
4688 * PARAMETER(S):
4689 * [I] HWND : window handle
4690 * [I] INT : column index
4691 * [I] LPLVCOLUMNA : column attributes
4693 * RETURN:
4694 * SUCCESS : TRUE
4695 * FAILURE : FALSE
4697 static LRESULT LISTVIEW_SetColumnA(HWND hwnd, INT nColumn,
4698 LPLVCOLUMNA lpColumn)
4700 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4701 BOOL bResult = FALSE;
4702 HDITEMA hdi;
4704 if ((lpColumn != NULL) && (nColumn >= 0) &&
4705 (nColumn < Header_GetItemCount(infoPtr->hwndHeader)))
4707 /* initialize memory */
4708 ZeroMemory(&hdi, sizeof(HDITEMA));
4710 if (lpColumn->mask & LVCF_FMT)
4712 /* format member is valid */
4713 hdi.mask |= HDI_FORMAT;
4715 /* set text alignment (leftmost column must be left-aligned) */
4716 if (nColumn == 0)
4718 hdi.fmt |= HDF_LEFT;
4720 else
4722 if (lpColumn->fmt & LVCFMT_LEFT)
4724 hdi.fmt |= HDF_LEFT;
4726 else if (lpColumn->fmt & LVCFMT_RIGHT)
4728 hdi.fmt |= HDF_RIGHT;
4730 else if (lpColumn->fmt & LVCFMT_CENTER)
4732 hdi.fmt |= HDF_CENTER;
4736 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
4738 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
4741 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
4743 hdi.fmt |= HDF_IMAGE;
4746 if (lpColumn->fmt & LVCFMT_IMAGE)
4748 hdi.fmt |= HDF_IMAGE;
4749 hdi.iImage = I_IMAGECALLBACK;
4753 if (lpColumn->mask & LVCF_WIDTH)
4755 hdi.mask |= HDI_WIDTH;
4756 hdi.cxy = lpColumn->cx;
4759 if (lpColumn->mask & LVCF_TEXT)
4761 hdi.mask |= HDI_TEXT | HDI_FORMAT;
4762 hdi.pszText = lpColumn->pszText;
4763 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
4764 hdi.fmt |= HDF_STRING;
4767 if (lpColumn->mask & LVCF_IMAGE)
4769 hdi.mask |= HDI_IMAGE;
4770 hdi.iImage = lpColumn->iImage;
4773 if (lpColumn->mask & LVCF_ORDER)
4775 hdi.mask |= HDI_ORDER;
4776 hdi.iOrder = lpColumn->iOrder;
4779 /* set header item attributes */
4780 bResult = Header_SetItemA(infoPtr->hwndHeader, nColumn, &hdi);
4783 return bResult;
4786 /***
4787 * DESCRIPTION:
4788 * Sets the width of a column
4790 * PARAMETERS:
4791 * [I] HWND : window handle
4792 * [I] INT : column index
4793 * [I] INT : column width
4795 * RETURN:
4796 * SUCCESS : TRUE
4797 * FAILURE : FALSE
4799 static LRESULT LISTVIEW_SetColumnWidth(HWND hwnd, INT iCol, INT cx)
4801 LISTVIEW_INFO *infoPtr;
4802 HDITEMA hdi;
4803 LRESULT lret;
4804 LONG lStyle;
4806 /* set column width only if in report mode */
4807 lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4808 if ((lStyle & LVS_TYPEMASK) != LVS_REPORT)
4809 return (FALSE);
4811 /* make sure we can get the listview info */
4812 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
4813 return (FALSE);
4814 if (!infoPtr->hwndHeader) /* make sure we have a header */
4815 return (FALSE);
4818 * FIXME: currently ignoring LVSCW_AUTOSIZE (-1) and
4819 * LVSCV_AUTOSIZE_USEHEADER (-2)
4821 if (cx < 0)
4822 return (FALSE);
4824 hdi.mask = HDI_WIDTH;
4825 hdi.cxy = cx;
4827 /* call header to update the column change */
4828 lret = Header_SetItemA(infoPtr->hwndHeader, (WPARAM)iCol, (LPARAM)&hdi);
4830 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd, LVS_REPORT);
4832 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
4834 return lret;
4837 /***
4838 * DESCRIPTION:
4839 * Sets image lists.
4841 * PARAMETER(S):
4842 * [I] HWND : window handle
4843 * [I] INT : image list type
4844 * [I] HIMAGELIST : image list handle
4846 * RETURN:
4847 * SUCCESS : old image list
4848 * FAILURE : NULL
4850 static LRESULT LISTVIEW_SetImageList(HWND hwnd, INT nType, HIMAGELIST himl)
4852 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4853 HIMAGELIST himlTemp = 0;
4855 switch (nType)
4857 case LVSIL_NORMAL:
4858 himlTemp = infoPtr->himlNormal;
4859 infoPtr->himlNormal = himl;
4860 return (LRESULT)himlTemp;
4862 case LVSIL_SMALL:
4863 himlTemp = infoPtr->himlSmall;
4864 infoPtr->himlSmall = himl;
4865 return (LRESULT)himlTemp;
4867 case LVSIL_STATE:
4868 himlTemp = infoPtr->himlState;
4869 infoPtr->himlState = himl;
4870 return (LRESULT)himlTemp;
4873 return (LRESULT)NULL;
4877 /***
4878 * DESCRIPTION:
4879 * Sets the attributes of an item.
4881 * PARAMETER(S):
4882 * [I] HWND : window handle
4883 * [I] LPLVITEM : item information
4885 * RETURN:
4886 * SUCCESS : TRUE
4887 * FAILURE : FALSE
4889 static LRESULT LISTVIEW_SetItemA(HWND hwnd, LPLVITEMA lpLVItem)
4891 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4892 BOOL bResult = FALSE;
4894 if (lpLVItem != NULL)
4896 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
4898 if (lpLVItem->iSubItem == 0)
4900 bResult = LISTVIEW_SetItem(hwnd, lpLVItem);
4902 else
4904 bResult = LISTVIEW_SetSubItem(hwnd, lpLVItem);
4910 return bResult;
4913 /* LISTVIEW_SetItemW */
4915 /***
4916 * DESCRIPTION:
4917 * Preallocates memory.
4919 * PARAMETER(S):
4920 * [I] HWND : window handle
4921 * [I] INT : item count (prjected number of items)
4923 * RETURN:
4924 * None
4926 static VOID LISTVIEW_SetItemCount(HWND hwnd, INT nItemCount)
4928 FIXME (listview, "empty stub!\n");
4931 /***
4932 * DESCRIPTION:
4933 * Sets the position of an item.
4935 * PARAMETER(S):
4936 * [I] HWND : window handle
4937 * [I] INT : item index
4938 * [I] INT : x coordinate
4939 * [I] INT : y coordinate
4941 * RETURN:
4942 * SUCCESS : TRUE
4943 * FAILURE : FALSE
4945 static BOOL LISTVIEW_SetItemPosition(HWND hwnd, INT nItem,
4946 INT nPosX, INT nPosY)
4948 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4949 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4950 LISTVIEW_ITEM *lpItem;
4951 HDPA hdpaSubItems;
4952 BOOL bResult = FALSE;
4954 TRACE(listview, "(hwnd=%x,nItem=%d,X=%d,Y=%d)\n", hwnd, nItem, nPosX, nPosY);
4956 if ((nItem >= 0) || (nItem < GETITEMCOUNT(infoPtr)))
4958 switch (lStyle & LVS_TYPEMASK)
4960 case LVS_ICON:
4961 case LVS_SMALLICON:
4962 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
4963 if (hdpaSubItems != NULL)
4965 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
4966 if (lpItem != NULL)
4968 bResult = TRUE;
4969 lpItem->ptPosition.x = nPosX;
4970 lpItem->ptPosition.y = nPosY;
4973 break;
4977 return bResult;
4980 /***
4981 * DESCRIPTION:
4982 * Sets the state of one or many items.
4984 * PARAMETER(S):
4985 * [I] HWND : window handle
4986 * [I]INT : item index
4987 * [I] LPLVITEM : item or subitem info
4989 * RETURN:
4990 * SUCCESS : TRUE
4991 * FAILURE : FALSE
4993 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
4995 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4996 BOOL bResult = FALSE;
4997 LVITEMA lvItem;
4998 INT i;
5000 if (nItem == -1)
5002 bResult = TRUE;
5003 ZeroMemory(&lvItem, sizeof(LVITEMA));
5004 lvItem.mask = LVIF_STATE;
5005 lvItem.state = lpLVItem->state;
5006 lvItem.stateMask = lpLVItem->stateMask;
5008 /* apply to all items */
5009 for (i = 0; i< GETITEMCOUNT(infoPtr); i++)
5011 lvItem.iItem = i;
5012 if (ListView_SetItemA(hwnd, &lvItem) == FALSE)
5014 bResult = FALSE;
5018 else
5020 ZeroMemory(&lvItem, sizeof(LVITEMA));
5021 lvItem.mask = LVIF_STATE;
5022 lvItem.state = lpLVItem->state;
5023 lvItem.stateMask = lpLVItem->stateMask;
5024 lvItem.iItem = nItem;
5025 bResult = ListView_SetItemA(hwnd, &lvItem);
5028 return bResult;
5031 /***
5032 * DESCRIPTION:
5033 * Sets the text of an item or subitem.
5035 * PARAMETER(S):
5036 * [I] HWND : window handle
5037 * [I] INT : item index
5038 * [I] LPLVITEMA : item or subitem info
5040 * RETURN:
5041 * SUCCESS : TRUE
5042 * FAILURE : FALSE
5044 static BOOL LISTVIEW_SetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5046 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5047 BOOL bResult = FALSE;
5048 LVITEMA lvItem;
5050 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5052 ZeroMemory(&lvItem, sizeof(LVITEMA));
5053 lvItem.mask = LVIF_TEXT;
5054 lvItem.pszText = lpLVItem->pszText;
5055 lvItem.iItem = nItem;
5056 lvItem.iSubItem = lpLVItem->iSubItem;
5057 bResult = ListView_SetItemA(hwnd, &lvItem);
5060 return bResult;
5063 /***
5064 * DESCRIPTION:
5065 * Sets the text background color.
5067 * PARAMETER(S):
5068 * [I] HWND : window handle
5069 * [I] COLORREF : text background color
5071 * RETURN:
5072 * SUCCESS : TRUE
5073 * FAILURE : FALSE
5075 static LRESULT LISTVIEW_SetTextBkColor(HWND hwnd, COLORREF clrTextBk)
5077 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5079 infoPtr->clrTextBk = clrTextBk;
5080 InvalidateRect(hwnd, NULL, TRUE);
5082 return TRUE;
5085 /***
5086 * DESCRIPTION:
5087 * Sets the text foreground color.
5089 * PARAMETER(S):
5090 * [I] HWND : window handle
5091 * [I] COLORREF : text color
5093 * RETURN:
5094 * SUCCESS : TRUE
5095 * FAILURE : FALSE
5097 static LRESULT LISTVIEW_SetTextColor (HWND hwnd, COLORREF clrText)
5099 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5101 infoPtr->clrText = clrText;
5102 InvalidateRect(hwnd, NULL, TRUE);
5104 return TRUE;
5107 /***
5108 * DESCRIPTION:
5109 * Sorts the listview items.
5111 * PARAMETER(S):
5112 * [I] HWND : window handle
5114 * RETURN:
5115 * SUCCESS : TRUE
5116 * FAILURE : FALSE
5118 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam)
5120 FIXME (listview, "empty stub!\n");
5122 return TRUE;
5125 /***
5126 * DESCRIPTION:
5127 * Updates an items or rearranges the listview control.
5129 * PARAMETER(S):
5130 * [I] HWND : window handle
5131 * [I] INT : item index
5133 * RETURN:
5134 * SUCCESS : TRUE
5135 * FAILURE : FALSE
5137 static LRESULT LISTVIEW_Update(HWND hwnd, INT nItem)
5139 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5140 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5141 BOOL bResult = FALSE;
5142 RECT rc;
5144 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5146 bResult = TRUE;
5148 /* rearrange with default alignment style */
5149 if ((lStyle & LVS_AUTOARRANGE) && (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
5150 ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON)))
5152 ListView_Arrange(hwnd, 0);
5154 else
5156 /* get item bounding rectangle */
5157 rc.left = LVIR_BOUNDS;
5158 ListView_GetItemRect(hwnd, nItem, &rc);
5159 InvalidateRect(hwnd, &rc, FALSE);
5163 return bResult;
5166 /***
5167 * DESCRIPTION:
5168 * Creates the listview control.
5170 * PARAMETER(S):
5171 * [I] HWND : window handle
5173 * RETURN:
5174 * Zero
5176 static LRESULT LISTVIEW_Create(HWND hwnd, WPARAM wParam, LPARAM lParam)
5178 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5179 LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam;
5180 LOGFONTA logFont;
5182 /* initialize info pointer */
5183 ZeroMemory(infoPtr, sizeof(LISTVIEW_INFO));
5185 /* determine the type of structures to use */
5186 infoPtr->notifyFormat = SendMessageA(GetParent(hwnd), WM_NOTIFYFORMAT,
5187 (WPARAM)hwnd, (LPARAM)NF_QUERY);
5188 if (infoPtr->notifyFormat != NFR_ANSI)
5190 FIXME (listview, "ANSI notify format is NOT used\n");
5193 /* initialize color information */
5194 infoPtr->clrBk = GetSysColor(COLOR_WINDOW);
5195 infoPtr->clrText = GetSysColor(COLOR_WINDOWTEXT);
5196 infoPtr->clrTextBk = GetSysColor(COLOR_WINDOW);
5198 /* set default values */
5199 infoPtr->uCallbackMask = 0;
5200 infoPtr->nFocusedItem = -1;
5201 infoPtr->nSelectionMark = -1;
5202 infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING);
5203 infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING);
5204 ZeroMemory(&infoPtr->rcList, sizeof(RECT));
5206 /* get default font (icon title) */
5207 SystemParametersInfoA(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
5208 infoPtr->hDefaultFont = CreateFontIndirectA(&logFont);
5209 infoPtr->hFont = infoPtr->hDefaultFont;
5211 /* create header */
5212 infoPtr->hwndHeader = CreateWindowA(WC_HEADERA, (LPCSTR)NULL,
5213 WS_CHILD | HDS_HORZ | HDS_BUTTONS,
5214 0, 0, 0, 0, hwnd, (HMENU)0,
5215 lpcs->hInstance, NULL);
5217 /* set header font */
5218 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont,
5219 (LPARAM)TRUE);
5222 switch (lpcs->style & LVS_TYPEMASK)
5224 case LVS_ICON:
5225 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
5226 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
5227 break;
5229 case LVS_REPORT:
5230 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
5231 case LVS_SMALLICON:
5232 case LVS_LIST:
5233 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
5234 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
5235 break;
5238 /* display unsupported listview window styles */
5239 LISTVIEW_UnsupportedStyles(lpcs->style);
5241 /* allocate memory for the data structure */
5242 infoPtr->hdpaItems = DPA_Create(10);
5244 /* initialize size of items */
5245 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd, lpcs->style);
5246 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd, lpcs->style);
5248 return 0;
5251 /***
5252 * DESCRIPTION:
5253 * Erases the background of the listview control.
5255 * PARAMETER(S):
5256 * [I] HWND : window handle
5257 * [I] WPARAM : device context handle
5258 * [I] LPARAM : not used
5260 * RETURN:
5261 * SUCCESS : TRUE
5262 * FAILURE : FALSE
5264 static LRESULT LISTVIEW_EraseBackground(HWND hwnd, WPARAM wParam,
5265 LPARAM lParam)
5267 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5268 BOOL bResult;
5270 if (infoPtr->clrBk == CLR_NONE)
5272 bResult = SendMessageA(GetParent(hwnd), WM_ERASEBKGND, wParam, lParam);
5274 else
5276 RECT rc;
5277 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
5278 GetClientRect(hwnd, &rc);
5279 FillRect((HDC)wParam, &rc, hBrush);
5280 DeleteObject(hBrush);
5281 bResult = TRUE;
5284 return bResult;
5287 /***
5288 * DESCRIPTION:
5289 * Retrieves the listview control font.
5291 * PARAMETER(S):
5292 * [I] HWND : window handle
5294 * RETURN:
5295 * Font handle.
5297 static LRESULT LISTVIEW_GetFont(HWND hwnd)
5299 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5301 return infoPtr->hFont;
5304 /***
5305 * DESCRIPTION:
5306 * Performs vertical scrolling.
5308 * PARAMETER(S):
5309 * [I] HWND : window handle
5310 * [I] INT : scroll code
5311 * [I] INT : scroll position
5312 * [I] HWND : scrollbar control window handle
5314 * RETURN:
5315 * Zero
5317 static LRESULT LISTVIEW_VScroll(HWND hwnd, INT nScrollCode, INT nScroll,
5318 HWND hScrollWnd)
5320 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5321 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5322 INT nScrollPosInc = 0;
5323 INT nScrollPos;
5324 INT nMinRange;
5325 INT nMaxRange;
5327 GetScrollRange(hwnd, SB_VERT, &nMinRange, &nMaxRange);
5328 nScrollPos = GetScrollPos(hwnd, SB_VERT);
5330 switch (nScrollCode)
5332 case SB_LINEUP:
5333 if (nScrollPos > nMinRange)
5335 nScrollPosInc = -1;
5337 break;
5339 case SB_LINEDOWN:
5340 if (nScrollPos < nMaxRange)
5342 nScrollPosInc = 1;
5344 break;
5346 case SB_PAGEUP:
5347 switch (LVS_TYPEMASK & lStyle)
5349 case LVS_REPORT:
5350 if (nScrollPos > nMinRange + infoPtr->nCountPerColumn)
5352 nScrollPosInc = -infoPtr->nCountPerColumn;
5354 else
5356 nScrollPosInc = nMinRange - nScrollPos;
5358 break;
5360 case LVS_SMALLICON:
5361 case LVS_ICON:
5362 if (nScrollPos > nMinRange + 10)
5364 nScrollPosInc = -10;
5366 else
5368 nScrollPosInc = nMinRange - nScrollPos;
5370 break;
5372 break;
5374 case SB_PAGEDOWN:
5375 switch (LVS_TYPEMASK & lStyle)
5377 case LVS_REPORT:
5378 if (nScrollPos < nMaxRange - infoPtr->nCountPerColumn)
5380 nScrollPosInc = infoPtr->nCountPerColumn;
5382 else
5384 nScrollPosInc = nMaxRange - nScrollPos;
5386 break;
5388 case LVS_SMALLICON:
5389 case LVS_ICON:
5390 if (nScrollPos < nMaxRange - 10)
5392 nScrollPosInc = 10;
5394 else
5396 nScrollPosInc = nMaxRange - nScrollPos;
5398 break;
5400 break;
5402 case SB_THUMBPOSITION:
5403 nScrollPosInc = nScroll - nScrollPos;
5404 break;
5407 if (nScrollPosInc != 0)
5409 LISTVIEW_ScrollView(hwnd, 0, nScrollPosInc);
5412 return 0;
5416 /***
5417 * DESCRIPTION:
5418 * Performs horizontal scrolling.
5420 * PARAMETER(S):
5421 * [I] HWND : window handle
5422 * [I] INT : scroll code
5423 * [I] INT : scroll position
5424 * [I] HWND : scrollbar control window handle
5426 * RETURN:
5427 * Zero
5429 static LRESULT LISTVIEW_HScroll(HWND hwnd, INT nScrollCode,
5430 INT nScroll, HWND hScrollWnd)
5432 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5433 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5434 INT nScrollPosInc = 0;
5435 INT nScrollPos;
5436 INT nMinRange;
5437 INT nMaxRange;
5439 GetScrollRange(hwnd, SB_HORZ, &nMinRange, &nMaxRange);
5440 nScrollPos = GetScrollPos(hwnd, SB_HORZ);
5442 switch (nScrollCode)
5444 case SB_LINELEFT:
5445 if (nScrollPos > nMinRange)
5447 nScrollPosInc = -1;
5449 break;
5451 case SB_LINERIGHT:
5452 if (nScrollPos < nMaxRange)
5454 nScrollPosInc = 1;
5456 break;
5458 case SB_PAGELEFT:
5459 switch (LVS_TYPEMASK & lStyle)
5461 case LVS_LIST:
5462 if (nScrollPos > nMinRange + infoPtr->nCountPerRow)
5464 nScrollPosInc = -infoPtr->nCountPerRow;
5466 else
5468 nScrollPosInc = nMinRange - nScrollPos;
5470 break;
5472 case LVS_REPORT:
5473 case LVS_SMALLICON:
5474 case LVS_ICON:
5475 if (nScrollPos > nMinRange + 10)
5477 nScrollPosInc = -10;
5479 else
5481 nScrollPosInc = nMinRange - nScrollPos;
5483 break;
5485 break;
5487 case SB_PAGERIGHT:
5488 switch (LVS_TYPEMASK & lStyle)
5490 case LVS_LIST:
5491 if (nScrollPos < nMaxRange - infoPtr->nCountPerRow)
5493 nScrollPosInc = infoPtr->nCountPerRow;
5495 else
5497 nScrollPosInc = nMaxRange - nScrollPos;
5499 break;
5501 case LVS_REPORT:
5502 case LVS_SMALLICON:
5503 case LVS_ICON:
5504 if (nScrollPos < nMaxRange - 10)
5506 nScrollPosInc = 10;
5508 else
5510 nScrollPosInc = nMaxRange - nScrollPos;
5512 break;
5514 break;
5516 case SB_THUMBPOSITION:
5517 nScrollPosInc = nScroll - nScrollPos;
5518 break;
5521 if (nScrollPosInc != 0)
5523 LISTVIEW_ScrollView(hwnd, nScrollPosInc, 0);
5526 return 0;
5529 /***
5530 * DESCRIPTION:
5531 * ???
5533 * PARAMETER(S):
5534 * [I] HWND : window handle
5535 * [I] INT : virtual key
5536 * [I] LONG : key data
5538 * RETURN:
5539 * Zero
5541 static LRESULT LISTVIEW_KeyDown(HWND hwnd, INT nVirtualKey, LONG lKeyData)
5543 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5544 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5545 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5546 INT nCountPerColumn;
5547 INT nCountPerRow;
5548 HWND hwndParent = GetParent(hwnd);
5549 NMLVKEYDOWN nmKeyDown;
5550 NMHDR nmh;
5552 /* send LVN_KEYDOWN notification */
5553 ZeroMemory(&nmKeyDown, sizeof(NMLVKEYDOWN));
5554 nmKeyDown.hdr.hwndFrom = hwnd;
5555 nmKeyDown.hdr.idFrom = nCtrlId;
5556 nmKeyDown.hdr.code = LVN_KEYDOWN;
5557 nmKeyDown.wVKey = nVirtualKey;
5558 nmKeyDown.flags = 0;
5559 SendMessageA(hwndParent, WM_NOTIFY, (WPARAM)nCtrlId, (LPARAM)&nmKeyDown);
5561 /* initialize */
5562 nmh.hwndFrom = hwnd;
5563 nmh.idFrom = nCtrlId;
5565 switch (nVirtualKey)
5567 case VK_RETURN:
5568 if ((GETITEMCOUNT(infoPtr) > 0) && (infoPtr->nFocusedItem != -1))
5570 /* send NM_RETURN notification */
5571 nmh.code = NM_RETURN;
5572 ListView_Notify(hwndParent, nCtrlId, &nmh);
5574 /* send LVN_ITEMACTIVATE notification */
5575 nmh.code = LVN_ITEMACTIVATE;
5576 ListView_Notify(hwndParent, nCtrlId, &nmh);
5578 break;
5580 case VK_HOME:
5581 if (GETITEMCOUNT(infoPtr) > 0)
5583 LISTVIEW_KeySelection(hwnd, 0);
5585 break;
5587 case VK_END:
5588 if (GETITEMCOUNT(infoPtr) > 0)
5590 LISTVIEW_KeySelection(hwnd, GETITEMCOUNT(infoPtr) - 1);
5592 break;
5594 case VK_LEFT:
5595 switch (LVS_TYPEMASK & lStyle)
5597 case LVS_LIST:
5598 if (infoPtr->nFocusedItem >= infoPtr->nCountPerColumn)
5600 LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem -
5601 infoPtr->nCountPerColumn);
5603 break;
5605 case LVS_SMALLICON:
5606 case LVS_ICON:
5607 if (lStyle & LVS_ALIGNLEFT)
5609 nCountPerColumn = max((infoPtr->rcList.bottom - infoPtr->rcList.top) /
5610 infoPtr->nItemHeight, 1);
5611 if (infoPtr->nFocusedItem >= nCountPerColumn)
5613 LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem - nCountPerColumn);
5616 else
5618 nCountPerRow = max((infoPtr->rcList.right - infoPtr->rcList.left) /
5619 infoPtr->nItemWidth, 1);
5620 if (infoPtr->nFocusedItem % nCountPerRow != 0)
5622 LISTVIEW_SetSelection(hwnd, infoPtr->nFocusedItem - 1);
5625 break;
5627 break;
5629 case VK_UP:
5630 switch (LVS_TYPEMASK & lStyle)
5632 case LVS_LIST:
5633 case LVS_REPORT:
5634 if (infoPtr->nFocusedItem > 0)
5636 LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem - 1);
5638 break;
5640 default:
5641 if (lStyle & LVS_ALIGNLEFT)
5643 nCountPerColumn = max((infoPtr->rcList.bottom - infoPtr->rcList.top) /
5644 infoPtr->nItemHeight, 1);
5645 if (infoPtr->nFocusedItem % nCountPerColumn != 0)
5647 LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem - 1);
5650 else
5652 nCountPerRow = max((infoPtr->rcList.right - infoPtr->rcList.left) /
5653 infoPtr->nItemWidth, 1);
5654 if (infoPtr->nFocusedItem >= nCountPerRow)
5656 LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem - nCountPerRow);
5660 break;
5662 case VK_RIGHT:
5663 switch (LVS_TYPEMASK & lStyle)
5665 case LVS_LIST:
5666 if (infoPtr->nFocusedItem < GETITEMCOUNT(infoPtr) -
5667 infoPtr->nCountPerColumn)
5669 LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem +
5670 infoPtr->nCountPerColumn);
5672 break;
5674 case LVS_ICON:
5675 case LVS_SMALLICON:
5676 if (lStyle & LVS_ALIGNLEFT)
5678 nCountPerColumn = max((infoPtr->rcList.bottom - infoPtr->rcList.top) /
5679 infoPtr->nItemHeight, 1);
5680 if (infoPtr->nFocusedItem < GETITEMCOUNT(infoPtr) - nCountPerColumn)
5682 LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem + nCountPerColumn);
5685 else
5687 nCountPerRow = max((infoPtr->rcList.right - infoPtr->rcList.left) /
5688 infoPtr->nItemWidth, 1);
5689 if ((infoPtr->nFocusedItem % nCountPerRow != nCountPerRow - 1) &&
5690 (infoPtr->nFocusedItem < GETITEMCOUNT(infoPtr) - 1))
5692 LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem + 1);
5696 break;
5698 case VK_DOWN:
5699 switch (LVS_TYPEMASK & lStyle)
5701 case LVS_LIST:
5702 case LVS_REPORT:
5703 if (infoPtr->nFocusedItem < GETITEMCOUNT(infoPtr) - 1)
5705 LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem + 1);
5707 break;
5709 case LVS_SMALLICON:
5710 case LVS_ICON:
5711 if (lStyle & LVS_ALIGNLEFT)
5713 nCountPerColumn = max((infoPtr->rcList.bottom - infoPtr->rcList.top) /
5714 infoPtr->nItemHeight, 1);
5715 if (infoPtr->nFocusedItem % nCountPerColumn != nCountPerColumn - 1)
5717 LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem + 1);
5720 else
5722 nCountPerRow = max((infoPtr->rcList.right - infoPtr->rcList.left) /
5723 infoPtr->nItemWidth, 1);
5724 if (infoPtr->nFocusedItem < GETITEMCOUNT(infoPtr) - nCountPerRow)
5726 LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem + nCountPerRow);
5730 break;
5732 case VK_PRIOR:
5733 break;
5735 case VK_NEXT:
5736 break;
5739 /* refresh client area */
5740 InvalidateRect(hwnd, NULL, TRUE);
5742 return 0;
5745 /***
5746 * DESCRIPTION:
5747 * Kills the focus.
5749 * PARAMETER(S):
5750 * [I] HWND : window handle
5752 * RETURN:
5753 * Zero
5755 static LRESULT LISTVIEW_KillFocus(HWND hwnd)
5757 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5758 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5759 NMHDR nmh;
5761 /* send NM_KILLFOCUS notification */
5762 nmh.hwndFrom = hwnd;
5763 nmh.idFrom = nCtrlId;
5764 nmh.code = NM_KILLFOCUS;
5765 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5767 /* set window focus flag */
5768 infoPtr->bFocus = FALSE;
5770 return 0;
5773 /***
5774 * DESCRIPTION:
5775 * Processes double click messages (left mouse button).
5777 * PARAMETER(S):
5778 * [I] HWND : window handle
5779 * [I] WORD : key flag
5780 * [I] WORD : x coordinate
5781 * [I] WORD : y coordinate
5783 * RETURN:
5784 * Zero
5786 static LRESULT LISTVIEW_LButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
5787 WORD wPosY)
5789 LONG nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5790 NMHDR nmh;
5792 TRACE(listview, "(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
5794 /* send NM_DBLCLK notification */
5795 nmh.hwndFrom = hwnd;
5796 nmh.idFrom = nCtrlId;
5797 nmh.code = NM_DBLCLK;
5798 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5800 /* send LVN_ITEMACTIVATE notification */
5801 nmh.code = LVN_ITEMACTIVATE;
5802 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5804 return 0;
5807 /***
5808 * DESCRIPTION:
5809 * Processes mouse down messages (left mouse button).
5811 * PARAMETER(S):
5812 * [I] HWND : window handle
5813 * [I] WORD : key flag
5814 * [I] WORD : x coordinate
5815 * [I] WORD : y coordinate
5817 * RETURN:
5818 * Zero
5820 static LRESULT LISTVIEW_LButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
5821 WORD wPosY)
5823 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5824 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5825 static BOOL bGroupSelect = TRUE;
5826 NMHDR nmh;
5827 INT nItem;
5829 TRACE(listview, "(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
5831 /* send NM_RELEASEDCAPTURE notification */
5832 nmh.hwndFrom = hwnd;
5833 nmh.idFrom = nCtrlId;
5834 nmh.code = NM_RELEASEDCAPTURE;
5835 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5837 if (infoPtr->bFocus == FALSE)
5839 SetFocus(hwnd);
5842 /* set left button down flag */
5843 infoPtr->bLButtonDown = TRUE;
5845 nItem = LISTVIEW_MouseSelection(hwnd, wPosX, wPosY);
5846 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5848 if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
5850 if (bGroupSelect != FALSE)
5852 LISTVIEW_AddGroupSelection(hwnd, nItem);
5854 else
5856 LISTVIEW_AddSelection(hwnd, nItem);
5859 else if (wKey & MK_CONTROL)
5861 bGroupSelect = LISTVIEW_ToggleSelection(hwnd, nItem);
5863 else if (wKey & MK_SHIFT)
5865 LISTVIEW_SetGroupSelection(hwnd, nItem);
5867 else
5869 LISTVIEW_SetSelection(hwnd, nItem);
5872 else
5874 /* remove all selections */
5875 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
5878 InvalidateRect(hwnd, NULL, TRUE);
5880 return 0;
5883 /***
5884 * DESCRIPTION:
5885 * Processes mouse up messages (left mouse button).
5887 * PARAMETER(S):
5888 * [I] HWND : window handle
5889 * [I] WORD : key flag
5890 * [I] WORD : x coordinate
5891 * [I] WORD : y coordinate
5893 * RETURN:
5894 * Zero
5896 static LRESULT LISTVIEW_LButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
5897 WORD wPosY)
5899 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5901 TRACE(listview, "(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
5903 if (infoPtr->bLButtonDown != FALSE)
5905 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5906 NMHDR nmh;
5908 /* send NM_CLICK notification */
5909 nmh.hwndFrom = hwnd;
5910 nmh.idFrom = nCtrlId;
5911 nmh.code = NM_CLICK;
5912 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5914 /* set left button flag */
5915 infoPtr->bLButtonDown = FALSE;
5918 return 0;
5921 /***
5922 * DESCRIPTION:
5923 * Creates the listview control (called before WM_CREATE).
5925 * PARAMETER(S):
5926 * [I] HWND : window handle
5927 * [I] WPARAM : unhandled
5928 * [I] LPARAM : widow creation info
5930 * RETURN:
5931 * Zero
5933 static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
5935 LISTVIEW_INFO *infoPtr;
5937 TRACE(listview, "(hwnd=%x,wParam=%x,lParam=%lx)\n", hwnd, wParam, lParam);
5939 /* allocate memory for info structure */
5940 infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc(sizeof(LISTVIEW_INFO));
5941 SetWindowLongA(hwnd, 0, (LONG)infoPtr);
5942 if (infoPtr == NULL)
5944 ERR(listview, "could not allocate info memory!\n");
5945 return 0;
5948 if ((LISTVIEW_INFO *)GetWindowLongA(hwnd, 0) != infoPtr)
5950 ERR(listview, "pointer assignment error!\n");
5951 return 0;
5954 return DefWindowProcA(hwnd, WM_NCCREATE, wParam, lParam);
5957 /***
5958 * DESCRIPTION:
5959 * Destroys the listview control (called after WM_DESTROY).
5961 * PARAMETER(S):
5962 * [I] HWND : window handle
5964 * RETURN:
5965 * Zero
5967 static LRESULT LISTVIEW_NCDestroy(HWND hwnd)
5969 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5971 TRACE(listview, "(hwnd=%x)\n", hwnd);
5973 /* delete all items */
5974 LISTVIEW_DeleteAllItems(hwnd);
5976 /* destroy data structure */
5977 DPA_Destroy(infoPtr->hdpaItems);
5979 /* destroy font */
5980 infoPtr->hFont = (HFONT)0;
5981 if (infoPtr->hDefaultFont)
5983 DeleteObject(infoPtr->hDefaultFont);
5986 /* free listview info pointer*/
5987 COMCTL32_Free(infoPtr);
5989 return 0;
5992 /***
5993 * DESCRIPTION:
5994 * Handles notifications from children.
5996 * PARAMETER(S):
5997 * [I] HWND : window handle
5998 * [I] INT : control identifier
5999 * [I] LPNMHDR : notification information
6001 * RETURN:
6002 * Zero
6004 static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh)
6006 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6008 if (lpnmh->hwndFrom == infoPtr->hwndHeader)
6010 /* handle notification from header control */
6011 if (lpnmh->code == HDN_ENDTRACKA)
6013 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd, LVS_REPORT);
6014 InvalidateRect(hwnd, NULL, TRUE);
6018 return 0;
6021 /***
6022 * DESCRIPTION:
6023 * Determines the type of structure to use.
6025 * PARAMETER(S):
6026 * [I] HWND : window handle of the sender
6027 * [I] HWND : listview window handle
6028 * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
6030 * RETURN:
6031 * Zero
6033 static LRESULT LISTVIEW_NotifyFormat(HWND hwndFrom, HWND hwnd, INT nCommand)
6035 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6037 if (nCommand == NF_REQUERY)
6039 /* determine the type of structure to use */
6040 infoPtr->notifyFormat = SendMessageA(hwndFrom, WM_NOTIFYFORMAT,
6041 (WPARAM)hwnd, (LPARAM)NF_QUERY);
6042 if (infoPtr->notifyFormat == NFR_UNICODE)
6044 FIXME (listview, "NO support for unicode structures");
6048 return 0;
6051 /***
6052 * DESCRIPTION:
6053 * Paints/Repaints the listview control.
6055 * PARAMETER(S):
6056 * [I] HWND : window handle
6057 * [I] HDC : device context handle
6059 * RETURN:
6060 * Zero
6062 static LRESULT LISTVIEW_Paint(HWND hwnd, HDC hdc)
6064 PAINTSTRUCT ps;
6066 TRACE(listview, "(hwnd=%x,hdc=%x)\n", hwnd, hdc);
6068 if (hdc == 0)
6070 hdc = BeginPaint(hwnd, &ps);
6071 LISTVIEW_Refresh(hwnd, hdc);
6072 EndPaint(hwnd, &ps);
6074 else
6076 LISTVIEW_Refresh(hwnd, hdc);
6079 return 0;
6082 /***
6083 * DESCRIPTION:
6084 * Processes double click messages (right mouse button).
6086 * PARAMETER(S):
6087 * [I] HWND : window handle
6088 * [I] WORD : key flag
6089 * [I] WORD : x coordinate
6090 * [I] WORD : y coordinate
6092 * RETURN:
6093 * Zero
6095 static LRESULT LISTVIEW_RButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
6096 WORD wPosY)
6098 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6099 NMHDR nmh;
6101 TRACE(listview, "(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6103 /* send NM_RELEASEDCAPTURE notification */
6104 nmh.hwndFrom = hwnd;
6105 nmh.idFrom = nCtrlId;
6106 nmh.code = NM_RELEASEDCAPTURE;
6107 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6109 /* send NM_RDBLCLK notification */
6110 nmh.code = NM_RDBLCLK;
6111 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6113 return 0;
6116 /***
6117 * DESCRIPTION:
6118 * Processes mouse down messages (right mouse button).
6120 * PARAMETER(S):
6121 * [I] HWND : window handle
6122 * [I] WORD : key flag
6123 * [I] WORD : x coordinate
6124 * [I] WORD : y coordinate
6126 * RETURN:
6127 * Zero
6129 static LRESULT LISTVIEW_RButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
6130 WORD wPosY)
6132 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6133 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6134 NMHDR nmh;
6135 INT nItem;
6137 TRACE(listview, "(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6139 /* send NM_RELEASEDCAPTURE notification */
6140 nmh.hwndFrom = hwnd;
6141 nmh.idFrom = nCtrlId;
6142 nmh.code = NM_RELEASEDCAPTURE;
6143 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6145 /* make sure the listview control window has the focus */
6146 if (infoPtr->bFocus == FALSE)
6148 SetFocus(hwnd);
6151 /* set right button down flag */
6152 infoPtr->bRButtonDown = TRUE;
6154 /* determine the index of the selected item */
6155 nItem = LISTVIEW_MouseSelection(hwnd, wPosX, wPosY);
6156 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
6158 if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)))
6160 LISTVIEW_SetSelection(hwnd, nItem);
6163 else
6165 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
6168 return 0;
6171 /***
6172 * DESCRIPTION:
6173 * Processes mouse up messages (right mouse button).
6175 * PARAMETER(S):
6176 * [I] HWND : window handle
6177 * [I] WORD : key flag
6178 * [I] WORD : x coordinate
6179 * [I] WORD : y coordinate
6181 * RETURN:
6182 * Zero
6184 static LRESULT LISTVIEW_RButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
6185 WORD wPosY)
6187 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6188 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6189 NMHDR nmh;
6191 TRACE(listview, "(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6193 if (infoPtr->bRButtonDown != FALSE)
6195 /* send NM_RClICK notification */
6196 ZeroMemory(&nmh, sizeof(NMHDR));
6197 nmh.hwndFrom = hwnd;
6198 nmh.idFrom = nCtrlId;
6199 nmh.code = NM_RCLICK;
6200 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6202 /* set button flag */
6203 infoPtr->bRButtonDown = FALSE;
6206 return 0;
6209 /***
6210 * DESCRIPTION:
6211 * Sets the focus.
6213 * PARAMETER(S):
6214 * [I] HWND : window handle
6215 * [I] HWND : window handle of previously focused window
6217 * RETURN:
6218 * Zero
6220 static LRESULT LISTVIEW_SetFocus(HWND hwnd, HWND hwndLoseFocus)
6222 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6223 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6224 NMHDR nmh;
6226 /* send NM_SETFOCUS notification */
6227 nmh.hwndFrom = hwnd;
6228 nmh.idFrom = nCtrlId;
6229 nmh.code = NM_SETFOCUS;
6230 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6232 /* set window focus flag */
6233 infoPtr->bFocus = TRUE;
6235 return 0;
6238 /***
6239 * DESCRIPTION:
6240 * Sets the font.
6242 * PARAMETER(S):
6243 * [I] HWND : window handle
6244 * [I] HFONT : font handle
6245 * [I] WORD : redraw flag
6247 * RETURN:
6248 * Zero
6250 static LRESULT LISTVIEW_SetFont(HWND hwnd, HFONT hFont, WORD fRedraw)
6252 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6253 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6255 TRACE(listview, "(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd, hFont, fRedraw);
6257 if (hFont == 0)
6259 infoPtr->hFont = infoPtr->hDefaultFont;
6261 else
6263 infoPtr->hFont = hFont;
6266 if ((LVS_TYPEMASK & lStyle ) == LVS_REPORT)
6268 /* set header font */
6269 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont,
6270 MAKELPARAM(fRedraw, 0));
6273 /* invalidate listview control client area */
6274 InvalidateRect(hwnd, NULL, TRUE);
6276 if (fRedraw != FALSE)
6278 UpdateWindow(hwnd);
6281 return 0;
6284 /***
6285 * DESCRIPTION:
6286 * Resizes the listview control. This function processes WM_SIZE
6287 * messages. At this time, the width and height are not used.
6289 * PARAMETER(S):
6290 * [I] HWND : window handle
6291 * [I] WORD : new width
6292 * [I] WORD : new height
6294 * RETURN:
6295 * Zero
6297 static LRESULT LISTVIEW_Size(HWND hwnd, int Width, int Height)
6299 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6301 TRACE(listview, "(hwnd=%x,width=%d,height=%d)\n",hwnd, Width, Height);
6303 LISTVIEW_SetSize(hwnd, lStyle, -1, -1);
6304 switch (lStyle & LVS_TYPEMASK)
6306 case LVS_LIST:
6307 case LVS_REPORT:
6308 LISTVIEW_SetViewInfo(hwnd, lStyle);
6309 break;
6311 case LVS_ICON:
6312 case LVS_SMALLICON:
6313 if (lStyle & LVS_ALIGNLEFT)
6315 LISTVIEW_AlignLeft(hwnd);
6317 else
6319 LISTVIEW_AlignTop(hwnd);
6321 break;
6324 LISTVIEW_SetScroll(hwnd, lStyle);
6326 /* invalidate + erase background */
6327 InvalidateRect(hwnd, NULL, TRUE);
6329 return 0;
6332 /***
6333 * DESCRIPTION:
6334 * Sets the size information for a given style.
6336 * PARAMETER(S):
6337 * [I] HWND : window handle
6338 * [I] LONG : window style
6339 * [I] WORD : new width
6340 * [I] WORD : new height
6342 * RETURN:
6343 * Zero
6345 static VOID LISTVIEW_SetSize(HWND hwnd, LONG lStyle, LONG lWidth, LONG lHeight)
6347 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6348 HDLAYOUT hl;
6349 WINDOWPOS wp;
6350 RECT rcList;
6352 GetClientRect(hwnd, &rcList);
6353 if (lWidth == -1)
6355 infoPtr->rcList.left = max(rcList.left, 0);
6356 infoPtr->rcList.right = max(rcList.right, 0);
6358 else
6360 infoPtr->rcList.left = max(rcList.left, 0);
6361 infoPtr->rcList.right = infoPtr->rcList.left + max(lWidth, 0);
6364 if (lHeight == -1)
6366 infoPtr->rcList.top = max(rcList.top, 0);
6367 infoPtr->rcList.bottom = max(rcList.bottom, 0);
6369 else
6371 infoPtr->rcList.top = max(rcList.top, 0);
6372 infoPtr->rcList.bottom = infoPtr->rcList.top + max(lHeight, 0);
6375 switch (lStyle & LVS_TYPEMASK)
6377 case LVS_LIST:
6378 if ((lStyle & WS_HSCROLL) == 0)
6380 INT nHScrollHeight;
6381 nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
6382 if (infoPtr->rcList.bottom > nHScrollHeight)
6384 infoPtr->rcList.bottom -= nHScrollHeight;
6387 break;
6389 case LVS_REPORT:
6390 hl.prc = &rcList;
6391 hl.pwpos = &wp;
6392 Header_Layout(infoPtr->hwndHeader, &hl);
6393 infoPtr->rcList.top = max(wp.cy, 0);
6394 break;
6398 /***
6399 * DESCRIPTION:
6400 * Processes WM_STYLECHANGED messages.
6402 * PARAMETER(S):
6403 * [I] HWND : window handle
6404 * [I] WPARAM : window style type (normal or extended)
6405 * [I] LPSTYLESTRUCT : window style information
6407 * RETURN:
6408 * Zero
6410 static INT LISTVIEW_StyleChanged(HWND hwnd, WPARAM wStyleType,
6411 LPSTYLESTRUCT lpss)
6413 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6414 RECT rcList = infoPtr->rcList;
6415 HDLAYOUT hl;
6416 WINDOWPOS wp;
6418 TRACE(listview, "(hwnd=%x,styletype=%x,stylestruct=%p)\n",
6419 hwnd, wStyleType, lpss);
6421 if (wStyleType == GWL_STYLE)
6423 if ((lpss->styleOld & WS_HSCROLL) != 0)
6425 ShowScrollBar(hwnd, SB_HORZ, FALSE);
6428 if ((lpss->styleOld & WS_VSCROLL) != 0)
6430 ShowScrollBar(hwnd, SB_VERT, FALSE);
6433 if ((LVS_TYPEMASK & lpss->styleOld) == LVS_REPORT)
6435 /* remove header */
6436 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
6439 switch (lpss->styleNew & LVS_TYPEMASK)
6441 case LVS_ICON:
6442 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
6443 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
6444 LISTVIEW_SetSize(hwnd, lpss->styleNew, -1, -1);
6445 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd, lpss->styleNew);
6446 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd, lpss->styleNew);
6447 if (lpss->styleNew & LVS_ALIGNLEFT)
6449 LISTVIEW_AlignLeft(hwnd);
6451 else
6453 LISTVIEW_AlignTop(hwnd);
6455 break;
6457 case LVS_REPORT:
6458 hl.prc = &rcList;
6459 hl.pwpos = &wp;
6460 Header_Layout(infoPtr->hwndHeader, &hl);
6461 SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx,
6462 wp.cy, wp.flags);
6463 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
6464 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6465 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6466 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd, lpss->styleNew);
6467 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd, lpss->styleNew);
6468 LISTVIEW_SetSize(hwnd, lpss->styleNew, -1, -1);
6469 LISTVIEW_SetViewInfo(hwnd, lpss->styleNew);
6470 break;
6472 case LVS_LIST:
6473 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6474 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6475 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd, lpss->styleNew);
6476 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd, lpss->styleNew);
6477 LISTVIEW_SetSize(hwnd, lpss->styleNew, -1, -1);
6478 LISTVIEW_SetViewInfo(hwnd, lpss->styleNew);
6479 break;
6481 case LVS_SMALLICON:
6482 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6483 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6484 LISTVIEW_SetSize(hwnd, lpss->styleNew, -1, -1);
6485 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd, lpss->styleNew);
6486 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd, lpss->styleNew);
6487 if (lpss->styleNew & LVS_ALIGNLEFT)
6489 LISTVIEW_AlignLeft(hwnd);
6491 else
6493 LISTVIEW_AlignTop(hwnd);
6495 break;
6498 LISTVIEW_SetScroll(hwnd, lpss->styleNew);
6500 /* print unsupported styles */
6501 LISTVIEW_UnsupportedStyles(lpss->styleNew);
6503 /* invalidate client area */
6504 InvalidateRect(hwnd, NULL, TRUE);
6507 return 0;
6510 /***
6511 * DESCRIPTION:
6512 * Window procedure of the listview control.
6514 * PARAMETER(S):
6515 * [I] HWND :
6516 * [I] UINT :
6517 * [I] WPARAM :
6518 * [I] LPARAM :
6520 * RETURN:
6523 LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
6524 LPARAM lParam)
6526 switch (uMsg)
6528 case LVM_APPROXIMATEVIEWRECT:
6529 return LISTVIEW_ApproximateViewRect(hwnd, (INT)wParam,
6530 LOWORD(lParam), HIWORD(lParam));
6531 case LVM_ARRANGE:
6532 return LISTVIEW_Arrange(hwnd, (INT)wParam);
6534 /* case LVM_CREATEDRAGIMAGE: */
6536 case LVM_DELETEALLITEMS:
6537 return LISTVIEW_DeleteAllItems(hwnd);
6539 case LVM_DELETECOLUMN:
6540 return LISTVIEW_DeleteColumn(hwnd, (INT)wParam);
6542 case LVM_DELETEITEM:
6543 return LISTVIEW_DeleteItem(hwnd, (INT)wParam);
6545 /* case LVM_EDITLABEL: */
6547 case LVM_ENSUREVISIBLE:
6548 return LISTVIEW_EnsureVisible(hwnd, (INT)wParam, (BOOL)lParam);
6550 case LVM_FINDITEMA:
6551 return LISTVIEW_FindItem(hwnd, (INT)wParam, (LPLVFINDINFO)lParam);
6553 case LVM_GETBKCOLOR:
6554 return LISTVIEW_GetBkColor(hwnd);
6556 /* case LVM_GETBKIMAGE: */
6558 case LVM_GETCALLBACKMASK:
6559 return LISTVIEW_GetCallbackMask(hwnd);
6561 case LVM_GETCOLUMNA:
6562 return LISTVIEW_GetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
6564 /* case LVM_GETCOLUMNW: */
6565 /* case LVM_GETCOLUMNORDERARRAY: */
6567 case LVM_GETCOLUMNWIDTH:
6568 return LISTVIEW_GetColumnWidth(hwnd, (INT)wParam);
6570 case LVM_GETCOUNTPERPAGE:
6571 return LISTVIEW_GetCountPerPage(hwnd);
6573 /* case LVM_GETEDITCONTROL: */
6574 /* case LVM_GETEXTENDEDLISTVIEWSTYLE: */
6576 case LVM_GETHEADER:
6577 return LISTVIEW_GetHeader(hwnd);
6579 /* case LVM_GETHOTCURSOR: */
6580 /* case LVM_GETHOTITEM: */
6581 /* case LVM_GETHOVERTIME: */
6583 case LVM_GETIMAGELIST:
6584 return LISTVIEW_GetImageList(hwnd, (INT)wParam);
6586 /* case LVM_GETISEARCHSTRING: */
6588 case LVM_GETITEMA:
6589 return LISTVIEW_GetItemA(hwnd, (LPLVITEMA)lParam);
6591 /* case LVM_GETITEMW: */
6593 case LVM_GETITEMCOUNT:
6594 return LISTVIEW_GetItemCount(hwnd);
6596 case LVM_GETITEMPOSITION:
6597 return LISTVIEW_GetItemPosition(hwnd, (INT)wParam, (LPPOINT)lParam);
6599 case LVM_GETITEMRECT:
6600 return LISTVIEW_GetItemRect(hwnd, (INT)wParam, (LPRECT)lParam);
6602 case LVM_GETITEMSPACING:
6603 return LISTVIEW_GetItemSpacing(hwnd, (BOOL)wParam);
6605 case LVM_GETITEMSTATE:
6606 return LISTVIEW_GetItemState(hwnd, (INT)wParam, (UINT)lParam);
6608 case LVM_GETITEMTEXTA:
6609 LISTVIEW_GetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
6610 break;
6612 /* case LVM_GETITEMTEXTW: */
6614 case LVM_GETNEXTITEM:
6615 return LISTVIEW_GetNextItem(hwnd, (INT)wParam, LOWORD(lParam));
6617 /* case LVM_GETNUMBEROFWORKAREAS: */
6619 case LVM_GETORIGIN:
6620 return LISTVIEW_GetOrigin(hwnd, (LPPOINT)lParam);
6622 case LVM_GETSELECTEDCOUNT:
6623 return LISTVIEW_GetSelectedCount(hwnd);
6625 case LVM_GETSELECTIONMARK:
6626 return LISTVIEW_GetSelectionMark(hwnd);
6628 case LVM_GETSTRINGWIDTHA:
6629 return LISTVIEW_GetStringWidthA (hwnd, (LPCSTR)lParam);
6631 /* case LVM_GETSTRINGWIDTHW: */
6632 /* case LVM_GETSUBITEMRECT: */
6634 case LVM_GETTEXTBKCOLOR:
6635 return LISTVIEW_GetTextBkColor(hwnd);
6637 case LVM_GETTEXTCOLOR:
6638 return LISTVIEW_GetTextColor(hwnd);
6640 /* case LVM_GETTOOLTIPS: */
6642 case LVM_GETTOPINDEX:
6643 return LISTVIEW_GetTopIndex(hwnd);
6645 /* case LVM_GETUNICODEFORMAT: */
6647 case LVM_GETVIEWRECT:
6648 return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam);
6650 /* case LVM_GETWORKAREAS: */
6652 case LVM_HITTEST:
6653 return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam);
6655 case LVM_INSERTCOLUMNA:
6656 return LISTVIEW_InsertColumnA(hwnd, (INT)wParam,
6657 (LPLVCOLUMNA)lParam);
6659 /* case LVM_INSERTCOLUMNW: */
6661 case LVM_INSERTITEMA:
6662 return LISTVIEW_InsertItemA(hwnd, (LPLVITEMA)lParam);
6664 /* case LVM_INSERTITEMW: */
6666 case LVM_REDRAWITEMS:
6667 return LISTVIEW_RedrawItems(hwnd, (INT)wParam, (INT)lParam);
6669 /* case LVM_SCROLL: */
6670 /* return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); */
6672 case LVM_SETBKCOLOR:
6673 return LISTVIEW_SetBkColor(hwnd, (COLORREF)lParam);
6675 /* case LVM_SETBKIMAGE: */
6677 case LVM_SETCALLBACKMASK:
6678 return LISTVIEW_SetCallbackMask(hwnd, (UINT)wParam);
6680 case LVM_SETCOLUMNA:
6681 return LISTVIEW_SetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
6683 /* case LVM_SETCOLUMNW: */
6684 /* case LVM_SETCOLUMNORDERARRAY: */
6686 case LVM_SETCOLUMNWIDTH:
6687 return LISTVIEW_SetColumnWidth(hwnd, (INT)wParam, (INT)lParam);
6689 /* case LVM_SETEXTENDEDLISTVIEWSTYLE: */
6690 /* case LVM_SETHOTCURSOR: */
6691 /* case LVM_SETHOTITEM: */
6692 /* case LVM_SETHOVERTIME: */
6693 /* case LVM_SETICONSPACING: */
6695 case LVM_SETIMAGELIST:
6696 return LISTVIEW_SetImageList(hwnd, (INT)wParam, (HIMAGELIST)lParam);
6698 case LVM_SETITEMA:
6699 return LISTVIEW_SetItemA(hwnd, (LPLVITEMA)lParam);
6701 /* case LVM_SETITEMW: */
6703 case LVM_SETITEMCOUNT:
6704 LISTVIEW_SetItemCount(hwnd, (INT)wParam);
6705 break;
6707 case LVM_SETITEMPOSITION:
6708 return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, (INT)LOWORD(lParam),
6709 (INT)HIWORD(lParam));
6711 /* case LVM_SETITEMPOSITION: */
6713 case LVM_SETITEMSTATE:
6714 return LISTVIEW_SetItemState(hwnd, (INT)wParam, (LPLVITEMA)lParam);
6716 case LVM_SETITEMTEXTA:
6717 return LISTVIEW_SetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
6719 /* case LVM_SETSELECTIONMARK: */
6721 case LVM_SETTEXTBKCOLOR:
6722 return LISTVIEW_SetTextBkColor(hwnd, (COLORREF)lParam);
6724 case LVM_SETTEXTCOLOR:
6725 return LISTVIEW_SetTextColor(hwnd, (COLORREF)lParam);
6727 /* case LVM_SETTOOLTIPS: */
6728 /* case LVM_SETUNICODEFORMAT: */
6729 /* case LVM_SETWORKAREAS: */
6731 case LVM_SORTITEMS:
6732 return LISTVIEW_SortItems(hwnd, wParam, lParam);
6734 /* case LVM_SUBITEMHITTEST: */
6736 case LVM_UPDATE:
6737 return LISTVIEW_Update(hwnd, (INT)wParam);
6739 /* case WM_CHAR: */
6740 /* case WM_COMMAND: */
6742 case WM_CREATE:
6743 return LISTVIEW_Create(hwnd, wParam, lParam);
6745 case WM_ERASEBKGND:
6746 return LISTVIEW_EraseBackground(hwnd, wParam, lParam);
6748 case WM_GETDLGCODE:
6749 return DLGC_WANTTAB | DLGC_WANTARROWS;
6751 case WM_GETFONT:
6752 return LISTVIEW_GetFont(hwnd);
6754 case WM_HSCROLL:
6755 return LISTVIEW_HScroll(hwnd, (INT)LOWORD(wParam),
6756 (INT)HIWORD(wParam), (HWND)lParam);
6758 case WM_KEYDOWN:
6759 return LISTVIEW_KeyDown(hwnd, (INT)wParam, (LONG)lParam);
6761 case WM_KILLFOCUS:
6762 return LISTVIEW_KillFocus(hwnd);
6764 case WM_LBUTTONDBLCLK:
6765 return LISTVIEW_LButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
6766 HIWORD(lParam));
6768 case WM_LBUTTONDOWN:
6769 return LISTVIEW_LButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
6770 HIWORD(lParam));
6771 case WM_LBUTTONUP:
6772 return LISTVIEW_LButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
6773 HIWORD(lParam));
6775 /* case WM_MOUSEMOVE: */
6776 /* return LISTVIEW_MouseMove (hwnd, wParam, lParam); */
6778 case WM_NCCREATE:
6779 return LISTVIEW_NCCreate(hwnd, wParam, lParam);
6781 case WM_NCDESTROY:
6782 return LISTVIEW_NCDestroy(hwnd);
6784 case WM_NOTIFY:
6785 return LISTVIEW_Notify(hwnd, (INT)wParam, (LPNMHDR)lParam);
6787 case WM_NOTIFYFORMAT:
6788 return LISTVIEW_NotifyFormat(hwnd, (HWND)wParam, (INT)lParam);
6790 case WM_PAINT:
6791 return LISTVIEW_Paint(hwnd, (HDC)wParam);
6793 case WM_RBUTTONDBLCLK:
6794 return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
6795 HIWORD(lParam));
6797 case WM_RBUTTONDOWN:
6798 return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
6799 HIWORD(lParam));
6801 case WM_RBUTTONUP:
6802 return LISTVIEW_RButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
6803 HIWORD(lParam));
6805 case WM_SETFOCUS:
6806 return LISTVIEW_SetFocus(hwnd, (HWND)wParam);
6808 case WM_SETFONT:
6809 return LISTVIEW_SetFont(hwnd, (HFONT)wParam, (WORD)lParam);
6811 /* case WM_SETREDRAW: */
6813 case WM_SIZE:
6814 return LISTVIEW_Size(hwnd, (int)SLOWORD(lParam), (int)SHIWORD(lParam));
6816 case WM_STYLECHANGED:
6817 return LISTVIEW_StyleChanged(hwnd, wParam, (LPSTYLESTRUCT)lParam);
6819 /* case WM_TIMER: */
6821 case WM_VSCROLL:
6822 return LISTVIEW_VScroll(hwnd, (INT)LOWORD(wParam),
6823 (INT)HIWORD(wParam), (HWND)lParam);
6825 /* case WM_WINDOWPOSCHANGED: */
6826 /* case WM_WININICHANGE: */
6828 default:
6829 if (uMsg >= WM_USER)
6831 ERR(listview, "unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam,
6832 lParam);
6835 /* call default window procedure */
6836 return DefWindowProcA(hwnd, uMsg, wParam, lParam);
6839 return 0;
6842 /***
6843 * DESCRIPTION:
6844 * Registers the window class.
6846 * PARAMETER(S):
6847 * None
6849 * RETURN:
6850 * None
6852 VOID LISTVIEW_Register(VOID)
6854 WNDCLASSA wndClass;
6856 if (!GlobalFindAtomA(WC_LISTVIEWA))
6858 ZeroMemory(&wndClass, sizeof(WNDCLASSA));
6859 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
6860 wndClass.lpfnWndProc = (WNDPROC)LISTVIEW_WindowProc;
6861 wndClass.cbClsExtra = 0;
6862 wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *);
6863 wndClass.hCursor = LoadCursorA(0, IDC_ARROWA);
6864 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
6865 wndClass.lpszClassName = WC_LISTVIEWA;
6866 RegisterClassA(&wndClass);
6870 /***
6871 * DESCRIPTION:
6872 * Unregisters the window class.
6874 * PARAMETER(S):
6875 * None
6877 * RETURN:
6878 * None
6880 VOID LISTVIEW_Unregister(VOID)
6882 if (GlobalFindAtomA(WC_LISTVIEWA))
6884 UnregisterClassA(WC_LISTVIEWA, (HINSTANCE)NULL);