ListView_GetItemRect already sets rc.left.
[wine/dcerpc.git] / dlls / comctl32 / listview.c
blobb6aca9166ff3bf97e2e296c79d06dcb1fabbcc20
1 /*
2 * Listview control
4 * Copyright 1998, 1999 Eric Kohl
5 * Copyright 1999 Luc Tourangeau
6 * Copyright 2000 Jason Mawdsley
8 * NOTES
9 * Listview control implementation.
11 * TODO:
12 * 1. No horizontal scrolling when header is larger than the client area.
13 * 2. Drawing optimizations.
14 * 3. Hot item handling.
16 * Notifications:
17 * LISTVIEW_Notify : most notifications from children (editbox and header)
19 * Data structure:
20 * LISTVIEW_SetItemCount : not completed for non OWNERDATA
22 * Unicode:
23 * LISTVIEW_SetItemW : no unicode support
24 * LISTVIEW_InsertItemW : no unicode support
25 * LISTVIEW_InsertColumnW : no unicode support
26 * LISTVIEW_GetColumnW : no unicode support
27 * LISTVIEW_SetColumnW : no unicode support
29 * Advanced functionality:
30 * LISTVIEW_GetNumberOfWorkAreas : not implemented
31 * LISTVIEW_GetHotCursor : not implemented
32 * LISTVIEW_GetISearchString : not implemented
33 * LISTVIEW_GetBkImage : not implemented
34 * LISTVIEW_SetBkImage : not implemented
35 * LISTVIEW_GetColumnOrderArray : simple hack only
36 * LISTVIEW_SetColumnOrderArray : simple hack only
37 * LISTVIEW_Arrange : empty stub
38 * LISTVIEW_ApproximateViewRect : incomplete
39 * LISTVIEW_Scroll : not implemented
40 * LISTVIEW_Update : not completed
43 #include <ctype.h>
44 #include <string.h>
45 #include <stdlib.h>
47 #include "winbase.h"
48 #include "heap.h"
49 #include "commctrl.h"
50 #include "debugtools.h"
52 DEFAULT_DEBUG_CHANNEL(listview);
54 /* Some definitions for inline edit control */
55 typedef BOOL (*EditlblCallback)(HWND, LPSTR, DWORD);
57 typedef struct tagEDITLABEL_ITEM
59 WNDPROC EditWndProc;
60 DWORD param;
61 EditlblCallback EditLblCb;
62 } EDITLABEL_ITEM;
64 typedef struct tagLISTVIEW_SUBITEM
66 LPSTR pszText;
67 INT iImage;
68 INT iSubItem;
70 } LISTVIEW_SUBITEM;
72 typedef struct tagLISTVIEW_ITEM
74 UINT state;
75 LPSTR pszText;
76 INT iImage;
77 LPARAM lParam;
78 INT iIndent;
79 POINT ptPosition;
81 } LISTVIEW_ITEM;
83 typedef struct tagLISTVIEW_SELECTION
85 DWORD lower;
86 DWORD upper;
87 } LISTVIEW_SELECTION;
89 typedef struct tagLISTVIEW_INFO
91 COLORREF clrBk;
92 COLORREF clrText;
93 COLORREF clrTextBk;
94 HIMAGELIST himlNormal;
95 HIMAGELIST himlSmall;
96 HIMAGELIST himlState;
97 BOOL bLButtonDown;
98 BOOL bRButtonDown;
99 INT nFocusedItem;
100 HDPA hdpaSelectionRanges;
101 INT nItemHeight;
102 INT nItemWidth;
103 INT nSelectionMark;
104 INT nHotItem;
105 SHORT notifyFormat;
106 RECT rcList;
107 RECT rcView;
108 SIZE iconSize;
109 SIZE iconSpacing;
110 UINT uCallbackMask;
111 HWND hwndHeader;
112 HFONT hDefaultFont;
113 HFONT hFont;
114 BOOL bFocus;
115 DWORD dwExStyle; /* extended listview style */
116 HDPA hdpaItems;
117 PFNLVCOMPARE pfnCompare;
118 LPARAM lParamSort;
119 HWND hwndEdit;
120 INT nEditLabelItem;
121 EDITLABEL_ITEM *pedititem;
122 DWORD dwHoverTime;
123 INT nColumnCount; /* the number of columns in this control */
125 DWORD lastKeyPressTimestamp; /* Added */
126 WPARAM charCode; /* Added */
127 INT nSearchParamLength; /* Added */
128 CHAR szSearchParam[ MAX_PATH ]; /* Added */
129 } LISTVIEW_INFO;
132 * constants
135 /* maximum size of a label */
136 #define DISP_TEXT_SIZE 512
138 /* padding for items in list and small icon display modes */
139 #define WIDTH_PADDING 12
141 /* padding for items in list, report and small icon display modes */
142 #define HEIGHT_PADDING 1
144 /* offset of items in report display mode */
145 #define REPORT_MARGINX 2
147 /* padding for icon in large icon display mode */
148 #define ICON_TOP_PADDING 2
149 #define ICON_BOTTOM_PADDING 2
151 /* padding for label in large icon display mode */
152 #define LABEL_VERT_OFFSET 2
154 /* default label width for items in list and small icon display modes */
155 #define DEFAULT_LABEL_WIDTH 40
157 /* default column width for items in list display mode */
158 #define DEFAULT_COLUMN_WIDTH 96
160 /* Increment size of the horizontal scroll bar */
161 #define LISTVIEW_SCROLL_DIV_SIZE 10
163 /* Padding betwen image and label */
164 #define IMAGE_PADDING 2
166 /* Padding behind the label */
167 #define TRAILING_PADDING 5
169 /* Border for the icon caption */
170 #define CAPTION_BORDER 2
172 * macros
174 #define ListView_LVNotify(hwnd,lCtrlId,plvnm) \
175 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMLISTVIEW)(plvnm))
176 #define ListView_Notify(hwnd,lCtrlId,pnmh) \
177 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMHDR)(pnmh))
178 /* retrieve the number of items in the listview */
179 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
181 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
182 INT width, INT height, HWND parent, HINSTANCE hinst,
183 EditlblCallback EditLblCb, DWORD param);
186 * forward declarations
188 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem, BOOL internal);
189 static INT LISTVIEW_HitTestItem(HWND, LPLVHITTESTINFO, BOOL);
190 static INT LISTVIEW_GetCountPerRow(HWND);
191 static INT LISTVIEW_GetCountPerColumn(HWND);
192 static VOID LISTVIEW_AlignLeft(HWND);
193 static VOID LISTVIEW_AlignTop(HWND);
194 static VOID LISTVIEW_AddGroupSelection(HWND, INT);
195 static VOID LISTVIEW_AddSelection(HWND, INT);
196 static BOOL LISTVIEW_AddSubItem(HWND, LPLVITEMA);
197 static INT LISTVIEW_FindInsertPosition(HDPA, INT);
198 static INT LISTVIEW_GetItemHeight(HWND);
199 static BOOL LISTVIEW_GetItemPosition(HWND, INT, LPPOINT);
200 static LRESULT LISTVIEW_GetItemRect(HWND, INT, LPRECT);
201 static INT LISTVIEW_GetItemWidth(HWND);
202 static INT LISTVIEW_GetLabelWidth(HWND, INT);
203 static LRESULT LISTVIEW_GetOrigin(HWND, LPPOINT);
204 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem);
205 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA, INT);
206 static LRESULT LISTVIEW_GetViewRect(HWND, LPRECT);
207 static BOOL LISTVIEW_InitItem(HWND, LISTVIEW_ITEM *, LPLVITEMA);
208 static BOOL LISTVIEW_InitSubItem(HWND, LISTVIEW_SUBITEM *, LPLVITEMA);
209 static LRESULT LISTVIEW_MouseSelection(HWND, POINT);
210 static BOOL LISTVIEW_RemoveColumn(HDPA, INT);
211 static BOOL LISTVIEW_RemoveSubItem(HDPA, INT);
212 static VOID LISTVIEW_SetGroupSelection(HWND, INT);
213 static BOOL LISTVIEW_SetItem(HWND, LPLVITEMA);
214 static BOOL LISTVIEW_SetItemFocus(HWND, INT);
215 static BOOL LISTVIEW_SetItemPosition(HWND, INT, LONG, LONG);
216 static VOID LISTVIEW_UpdateScroll(HWND);
217 static VOID LISTVIEW_SetSelection(HWND, INT);
218 static VOID LISTVIEW_UpdateSize(HWND);
219 static BOOL LISTVIEW_SetSubItem(HWND, LPLVITEMA);
220 static LRESULT LISTVIEW_SetViewRect(HWND, LPRECT);
221 static BOOL LISTVIEW_ToggleSelection(HWND, INT);
222 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle);
223 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem);
224 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem);
225 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam);
226 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam);
227 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText);
228 static INT LISTVIEW_ProcessLetterKeys( HWND hwnd, WPARAM charCode, LPARAM keyData );
229 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem);
230 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask);
231 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem);
232 static BOOL LISTVIEW_IsSelected(HWND hwnd, INT nItem);
233 static VOID LISTVIEW_RemoveSelectionRange(HWND hwnd, INT lItem, INT uItem);
234 static void LISTVIEW_FillBackground(HWND hwnd, HDC hdc, LPRECT rc);
236 /******** Defines that LISTVIEW_ProcessLetterKeys uses ****************/
237 #define KEY_DELAY 450
240 static BOOL
241 LISTVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
242 RECT rc)
244 LISTVIEW_INFO *infoPtr;
245 NMLVCUSTOMDRAW nmcdhdr;
246 LPNMCUSTOMDRAW nmcd;
248 TRACE("drawstage:%lx hdc:%x\n", dwDrawStage, hdc);
250 infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
252 nmcd= & nmcdhdr.nmcd;
253 nmcd->hdr.hwndFrom = hwnd;
254 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
255 nmcd->hdr.code = NM_CUSTOMDRAW;
256 nmcd->dwDrawStage= dwDrawStage;
257 nmcd->hdc = hdc;
258 nmcd->rc.left = rc.left;
259 nmcd->rc.right = rc.right;
260 nmcd->rc.bottom = rc.bottom;
261 nmcd->rc.top = rc.top;
262 nmcd->dwItemSpec = 0;
263 nmcd->uItemState = 0;
264 nmcd->lItemlParam= 0;
265 nmcdhdr.clrText = infoPtr->clrText;
266 nmcdhdr.clrTextBk= infoPtr->clrBk;
268 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
269 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
272 static BOOL
273 LISTVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
274 UINT iItem, UINT iSubItem,
275 UINT uItemDrawState)
277 LISTVIEW_INFO *infoPtr;
278 NMLVCUSTOMDRAW nmcdhdr;
279 LPNMCUSTOMDRAW nmcd;
280 DWORD dwDrawStage,dwItemSpec;
281 UINT uItemState;
282 INT retval;
283 RECT itemRect;
284 LVITEMA item;
286 infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
288 ZeroMemory(&item,sizeof(LVITEMA));
289 item.iItem = iItem;
290 item.mask = LVIF_PARAM;
291 ListView_GetItemA(hwnd,&item);
293 dwDrawStage=CDDS_ITEM | uItemDrawState;
294 dwItemSpec=iItem;
295 uItemState=0;
297 if (LISTVIEW_IsSelected(hwnd,iItem)) uItemState|=CDIS_SELECTED;
298 if (iItem==infoPtr->nFocusedItem) uItemState|=CDIS_FOCUS;
299 if (iItem==infoPtr->nHotItem) uItemState|=CDIS_HOT;
301 itemRect.left = LVIR_BOUNDS;
302 LISTVIEW_GetItemRect(hwnd, iItem, &itemRect);
304 nmcd= & nmcdhdr.nmcd;
305 nmcd->hdr.hwndFrom = hwnd;
306 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
307 nmcd->hdr.code = NM_CUSTOMDRAW;
308 nmcd->dwDrawStage= dwDrawStage;
309 nmcd->hdc = hdc;
310 nmcd->rc.left = itemRect.left;
311 nmcd->rc.right = itemRect.right;
312 nmcd->rc.bottom = itemRect.bottom;
313 nmcd->rc.top = itemRect.top;
314 nmcd->dwItemSpec = dwItemSpec;
315 nmcd->uItemState = uItemState;
316 nmcd->lItemlParam= item.lParam;
317 nmcdhdr.clrText = infoPtr->clrText;
318 nmcdhdr.clrTextBk= infoPtr->clrBk;
319 nmcdhdr.iSubItem =iSubItem;
321 TRACE("drawstage:%lx hdc:%x item:%lx, itemstate:%x, lItemlParam:%lx\n",
322 nmcd->dwDrawStage, nmcd->hdc, nmcd->dwItemSpec,
323 nmcd->uItemState, nmcd->lItemlParam);
325 retval=SendMessageA (GetParent (hwnd), WM_NOTIFY,
326 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
328 infoPtr->clrText=nmcdhdr.clrText;
329 infoPtr->clrBk =nmcdhdr.clrTextBk;
330 return (BOOL) retval;
334 /*************************************************************************
335 * LISTVIEW_ProcessLetterKeys
337 * Processes keyboard messages generated by pressing the letter keys
338 * on the keyboard.
339 * What this does is perform a case insensitive search from the
340 * current position with the following quirks:
341 * - If two chars or more are pressed in quick succession we search
342 * for the corresponding string (e.g. 'abc').
343 * - If there is a delay we wipe away the current search string and
344 * restart with just that char.
345 * - If the user keeps pressing the same character, whether slowly or
346 * fast, so that the search string is entirely composed of this
347 * character ('aaaaa' for instance), then we search for first item
348 * that starting with that character.
349 * - If the user types the above character in quick succession, then
350 * we must also search for the corresponding string ('aaaaa'), and
351 * go to that string if there is a match.
353 * RETURNS
355 * Zero.
357 * BUGS
359 * - The current implementation has a list of characters it will
360 * accept and it ignores averything else. In particular it will
361 * ignore accentuated characters which seems to match what
362 * Windows does. But I'm not sure it makes sense to follow
363 * Windows there.
364 * - We don't sound a beep when the search fails.
366 * SEE ALSO
368 * TREEVIEW_ProcessLetterKeys
370 static INT LISTVIEW_ProcessLetterKeys(
371 HWND hwnd, /* handle to the window */
372 WPARAM charCode, /* the character code, the actual character */
373 LPARAM keyData /* key data */
376 LISTVIEW_INFO *infoPtr;
377 INT nItem;
378 INT nSize;
379 INT endidx,idx;
380 LVITEMA item;
381 CHAR buffer[MAX_PATH];
382 DWORD timestamp,elapsed;
384 /* simple parameter checking */
385 if (!hwnd || !charCode || !keyData)
386 return 0;
388 infoPtr=(LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
389 if (!infoPtr)
390 return 0;
392 /* only allow the valid WM_CHARs through */
393 if (!isalnum(charCode) &&
394 charCode != '.' && charCode != '`' && charCode != '!' &&
395 charCode != '@' && charCode != '#' && charCode != '$' &&
396 charCode != '%' && charCode != '^' && charCode != '&' &&
397 charCode != '*' && charCode != '(' && charCode != ')' &&
398 charCode != '-' && charCode != '_' && charCode != '+' &&
399 charCode != '=' && charCode != '\\'&& charCode != ']' &&
400 charCode != '}' && charCode != '[' && charCode != '{' &&
401 charCode != '/' && charCode != '?' && charCode != '>' &&
402 charCode != '<' && charCode != ',' && charCode != '~')
403 return 0;
405 nSize=GETITEMCOUNT(infoPtr);
406 /* if there's one item or less, there is no where to go */
407 if (nSize <= 1)
408 return 0;
410 /* compute how much time elapsed since last keypress */
411 timestamp=GetTickCount();
412 if (timestamp > infoPtr->lastKeyPressTimestamp) {
413 elapsed=timestamp-infoPtr->lastKeyPressTimestamp;
414 } else {
415 elapsed=infoPtr->lastKeyPressTimestamp-timestamp;
418 /* update the search parameters */
419 infoPtr->lastKeyPressTimestamp=timestamp;
420 if (elapsed < KEY_DELAY) {
421 if (infoPtr->nSearchParamLength < sizeof(infoPtr->szSearchParam)) {
422 infoPtr->szSearchParam[infoPtr->nSearchParamLength++]=charCode;
424 if (infoPtr->charCode != charCode) {
425 infoPtr->charCode=charCode=0;
427 } else {
428 infoPtr->charCode=charCode;
429 infoPtr->szSearchParam[0]=charCode;
430 infoPtr->nSearchParamLength=1;
431 /* Redundant with the 1 char string */
432 charCode=0;
435 /* and search from the current position */
436 nItem=-1;
437 if (infoPtr->nFocusedItem >= 0) {
438 endidx=infoPtr->nFocusedItem;
439 idx=endidx;
440 /* if looking for single character match,
441 * then we must always move forward
443 if (infoPtr->nSearchParamLength == 1)
444 idx++;
445 } else {
446 endidx=nSize;
447 idx=0;
449 do {
450 if (idx == nSize) {
451 if (endidx == nSize)
452 break;
453 idx=0;
456 /* get item */
457 ZeroMemory(&item, sizeof(item));
458 item.mask = LVIF_TEXT;
459 item.iItem = idx;
460 item.iSubItem = 0;
461 item.pszText = buffer;
462 item.cchTextMax = sizeof(buffer);
463 ListView_GetItemA( hwnd, &item );
465 /* check for a match */
466 if (strncasecmp(item.pszText,infoPtr->szSearchParam,infoPtr->nSearchParamLength) == 0) {
467 nItem=idx;
468 break;
469 } else if ( (charCode != 0) && (nItem == -1) && (nItem != infoPtr->nFocusedItem) &&
470 (strncasecmp(item.pszText,infoPtr->szSearchParam,1) == 0) ) {
471 /* This would work but we must keep looking for a longer match */
472 nItem=idx;
474 idx++;
475 } while (idx != endidx);
477 if (nItem != -1) {
478 if (LISTVIEW_KeySelection(hwnd, nItem) != FALSE) {
479 /* refresh client area */
480 InvalidateRect(hwnd, NULL, TRUE);
481 UpdateWindow(hwnd);
485 return 0;
488 /*************************************************************************
489 * LISTVIEW_UpdateHeaderSize [Internal]
491 * Function to resize the header control
493 * PARAMS
494 * hwnd [I] handle to a window
495 * nNewScrollPos [I] Scroll Pos to Set
497 * RETURNS
498 * nothing
500 * NOTES
502 static VOID LISTVIEW_UpdateHeaderSize(HWND hwnd, INT nNewScrollPos)
504 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
505 RECT winRect;
506 POINT point[2];
508 GetWindowRect(infoPtr->hwndHeader, &winRect);
509 point[0].x = winRect.left;
510 point[0].y = winRect.top;
511 point[1].x = winRect.right;
512 point[1].y = winRect.bottom;
514 MapWindowPoints(HWND_DESKTOP, hwnd, point, 2);
515 point[0].x = -(nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
516 point[1].x += (nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
518 SetWindowPos(infoPtr->hwndHeader,0,
519 point[0].x,point[0].y,point[1].x,point[1].y,
520 SWP_NOZORDER | SWP_NOACTIVATE);
523 /***
524 * DESCRIPTION:
525 * Update the scrollbars. This functions should be called whenever
526 * the content, size or view changes.
528 * PARAMETER(S):
529 * [I] HWND : window handle
531 * RETURN:
532 * None
534 static VOID LISTVIEW_UpdateScroll(HWND hwnd)
536 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
537 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
538 UINT uView = lStyle & LVS_TYPEMASK;
539 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
540 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
541 SCROLLINFO scrollInfo;
543 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
544 scrollInfo.cbSize = sizeof(SCROLLINFO);
546 if (uView == LVS_LIST)
548 /* update horizontal scrollbar */
550 INT nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
551 INT nCountPerRow = LISTVIEW_GetCountPerRow(hwnd);
552 INT nNumOfItems = GETITEMCOUNT(infoPtr);
554 scrollInfo.nMax = nNumOfItems / nCountPerColumn;
555 if((nNumOfItems % nCountPerColumn) == 0)
557 scrollInfo.nMax--;
559 scrollInfo.nPos = ListView_GetTopIndex(hwnd) / nCountPerColumn;
560 scrollInfo.nPage = nCountPerRow;
561 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
562 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
563 ShowScrollBar(hwnd, SB_VERT, FALSE);
565 else if (uView == LVS_REPORT)
567 /* update vertical scrollbar */
568 scrollInfo.nMin = 0;
569 scrollInfo.nMax = GETITEMCOUNT(infoPtr) - 1;
570 scrollInfo.nPos = ListView_GetTopIndex(hwnd);
571 scrollInfo.nPage = LISTVIEW_GetCountPerColumn(hwnd);
572 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
573 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
575 /* update horizontal scrollbar */
576 nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
577 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE
578 || GETITEMCOUNT(infoPtr) == 0)
580 scrollInfo.nPos = 0;
582 scrollInfo.nMin = 0;
583 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE ;
584 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
585 scrollInfo.nMax = max(infoPtr->nItemWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
586 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
588 /* Update the Header Control */
589 scrollInfo.fMask = SIF_POS;
590 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
591 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
594 else
596 RECT rcView;
598 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
600 INT nViewWidth = rcView.right - rcView.left;
601 INT nViewHeight = rcView.bottom - rcView.top;
603 /* Update Horizontal Scrollbar */
604 scrollInfo.fMask = SIF_POS;
605 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE
606 || GETITEMCOUNT(infoPtr) == 0)
608 scrollInfo.nPos = 0;
610 scrollInfo.nMax = max(nViewWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
611 scrollInfo.nMin = 0;
612 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
613 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
614 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
616 /* Update Vertical Scrollbar */
617 nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
618 scrollInfo.fMask = SIF_POS;
619 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) == FALSE
620 || GETITEMCOUNT(infoPtr) == 0)
622 scrollInfo.nPos = 0;
624 scrollInfo.nMax = max(nViewHeight / LISTVIEW_SCROLL_DIV_SIZE,0)-1;
625 scrollInfo.nMin = 0;
626 scrollInfo.nPage = nListHeight / LISTVIEW_SCROLL_DIV_SIZE;
627 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
628 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
633 /***
634 * DESCRIPTION:
635 * Prints a message for unsupported window styles.
636 * A kind of TODO list for window styles.
638 * PARAMETER(S):
639 * [I] LONG : window style
641 * RETURN:
642 * None
644 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle)
646 if ((LVS_TYPEMASK & lStyle) == LVS_EDITLABELS)
648 FIXME(" LVS_EDITLABELS\n");
651 if ((LVS_TYPEMASK & lStyle) == LVS_NOLABELWRAP)
653 FIXME(" LVS_NOLABELWRAP\n");
656 if ((LVS_TYPEMASK & lStyle) == LVS_NOSCROLL)
658 FIXME(" LVS_NOSCROLL\n");
661 if ((LVS_TYPEMASK & lStyle) == LVS_NOSORTHEADER)
663 FIXME(" LVS_NOSORTHEADER\n");
666 if ((LVS_TYPEMASK & lStyle) == LVS_OWNERDRAWFIXED)
668 FIXME(" LVS_OWNERDRAWFIXED\n");
671 if ((LVS_TYPEMASK & lStyle) == LVS_SHAREIMAGELISTS)
673 FIXME(" LVS_SHAREIMAGELISTS\n");
676 if ((LVS_TYPEMASK & lStyle) == LVS_SORTASCENDING)
678 FIXME(" LVS_SORTASCENDING\n");
681 if ((LVS_TYPEMASK & lStyle) == LVS_SORTDESCENDING)
683 FIXME(" LVS_SORTDESCENDING\n");
687 /***
688 * DESCRIPTION:
689 * Aligns the items with the top edge of the window.
691 * PARAMETER(S):
692 * [I] HWND : window handle
694 * RETURN:
695 * None
697 static VOID LISTVIEW_AlignTop(HWND hwnd)
699 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
700 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
701 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
702 POINT ptItem;
703 RECT rcView;
704 INT i;
706 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
708 ZeroMemory(&ptItem, sizeof(POINT));
709 ZeroMemory(&rcView, sizeof(RECT));
711 if (nListWidth > infoPtr->nItemWidth)
713 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
715 if (ptItem.x + infoPtr->nItemWidth > nListWidth)
717 ptItem.x = 0;
718 ptItem.y += infoPtr->nItemHeight;
721 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
722 ptItem.x += infoPtr->nItemWidth;
723 rcView.right = max(rcView.right, ptItem.x);
726 rcView.bottom = ptItem.y + infoPtr->nItemHeight;
728 else
730 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
732 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
733 ptItem.y += infoPtr->nItemHeight;
736 rcView.right = infoPtr->nItemWidth;
737 rcView.bottom = ptItem.y;
740 LISTVIEW_SetViewRect(hwnd, &rcView);
744 /***
745 * DESCRIPTION:
746 * Aligns the items with the left edge of the window.
748 * PARAMETER(S):
749 * [I] HWND : window handle
751 * RETURN:
752 * None
754 static VOID LISTVIEW_AlignLeft(HWND hwnd)
756 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
757 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
758 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
759 POINT ptItem;
760 RECT rcView;
761 INT i;
763 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
765 ZeroMemory(&ptItem, sizeof(POINT));
766 ZeroMemory(&rcView, sizeof(RECT));
768 if (nListHeight > infoPtr->nItemHeight)
770 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
772 if (ptItem.y + infoPtr->nItemHeight > nListHeight)
774 ptItem.y = 0;
775 ptItem.x += infoPtr->nItemWidth;
778 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
779 ptItem.y += infoPtr->nItemHeight;
780 rcView.bottom = max(rcView.bottom, ptItem.y);
783 rcView.right = ptItem.x + infoPtr->nItemWidth;
785 else
787 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
789 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
790 ptItem.x += infoPtr->nItemWidth;
793 rcView.bottom = infoPtr->nItemHeight;
794 rcView.right = ptItem.x;
797 LISTVIEW_SetViewRect(hwnd, &rcView);
801 /***
802 * DESCRIPTION:
803 * Set the bounding rectangle of all the items.
805 * PARAMETER(S):
806 * [I] HWND : window handle
807 * [I] LPRECT : bounding rectangle
809 * RETURN:
810 * SUCCESS : TRUE
811 * FAILURE : FALSE
813 static LRESULT LISTVIEW_SetViewRect(HWND hwnd, LPRECT lprcView)
815 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
816 BOOL bResult = FALSE;
818 TRACE("(hwnd=%x, left=%d, top=%d, right=%d, bottom=%d)\n", hwnd,
819 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
821 if (lprcView != NULL)
823 bResult = TRUE;
824 infoPtr->rcView.left = lprcView->left;
825 infoPtr->rcView.top = lprcView->top;
826 infoPtr->rcView.right = lprcView->right;
827 infoPtr->rcView.bottom = lprcView->bottom;
830 return bResult;
833 /***
834 * DESCRIPTION:
835 * Retrieves the bounding rectangle of all the items.
837 * PARAMETER(S):
838 * [I] HWND : window handle
839 * [O] LPRECT : bounding rectangle
841 * RETURN:
842 * SUCCESS : TRUE
843 * FAILURE : FALSE
845 static LRESULT LISTVIEW_GetViewRect(HWND hwnd, LPRECT lprcView)
847 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
848 BOOL bResult = FALSE;
849 POINT ptOrigin;
851 TRACE("(hwnd=%x, lprcView=%p)\n", hwnd, lprcView);
853 if (lprcView != NULL)
855 bResult = LISTVIEW_GetOrigin(hwnd, &ptOrigin);
856 if (bResult != FALSE)
858 lprcView->left = infoPtr->rcView.left + ptOrigin.x;
859 lprcView->top = infoPtr->rcView.top + ptOrigin.y;
860 lprcView->right = infoPtr->rcView.right + ptOrigin.x;
861 lprcView->bottom = infoPtr->rcView.bottom + ptOrigin.y;
864 TRACE("(left=%d, top=%d, right=%d, bottom=%d)\n",
865 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
868 return bResult;
871 /***
872 * DESCRIPTION:
873 * Retrieves the subitem pointer associated with the subitem index.
875 * PARAMETER(S):
876 * [I] HDPA : DPA handle for a specific item
877 * [I] INT : index of subitem
879 * RETURN:
880 * SUCCESS : subitem pointer
881 * FAILURE : NULL
883 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems,
884 INT nSubItem)
886 LISTVIEW_SUBITEM *lpSubItem;
887 INT i;
889 for (i = 1; i < hdpaSubItems->nItemCount; i++)
891 lpSubItem = (LISTVIEW_SUBITEM *) DPA_GetPtr(hdpaSubItems, i);
892 if (lpSubItem != NULL)
894 if (lpSubItem->iSubItem == nSubItem)
896 return lpSubItem;
901 return NULL;
904 /***
905 * DESCRIPTION:
906 * Calculates the width of an item.
908 * PARAMETER(S):
909 * [I] HWND : window handle
910 * [I] LONG : window style
912 * RETURN:
913 * Returns item width.
915 static INT LISTVIEW_GetItemWidth(HWND hwnd)
917 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
918 LONG style = GetWindowLongA(hwnd, GWL_STYLE);
919 UINT uView = style & LVS_TYPEMASK;
920 INT nHeaderItemCount;
921 RECT rcHeaderItem;
922 INT nItemWidth = 0;
923 INT nLabelWidth;
924 INT i;
926 TRACE("(hwnd=%x)\n", hwnd);
928 if (uView == LVS_ICON)
930 nItemWidth = infoPtr->iconSpacing.cx;
932 else if (uView == LVS_REPORT)
934 /* calculate width of header */
935 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
936 for (i = 0; i < nHeaderItemCount; i++)
938 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
940 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
944 else
946 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
948 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, i);
949 nItemWidth = max(nItemWidth, nLabelWidth);
952 /* default label size */
953 if (GETITEMCOUNT(infoPtr) == 0)
955 nItemWidth = DEFAULT_COLUMN_WIDTH;
957 else
959 if (nItemWidth == 0)
961 nItemWidth = DEFAULT_LABEL_WIDTH;
963 else
965 /* add padding */
966 nItemWidth += WIDTH_PADDING;
968 if (infoPtr->himlSmall != NULL)
970 nItemWidth += infoPtr->iconSize.cx;
973 if (infoPtr->himlState != NULL)
975 nItemWidth += infoPtr->iconSize.cx;
980 if(nItemWidth == 0)
982 /* nItemWidth Cannot be Zero */
983 nItemWidth = 1;
985 return nItemWidth;
988 /***
989 * DESCRIPTION:
990 * Calculates the width of a specific item.
992 * PARAMETER(S):
993 * [I] HWND : window handle
994 * [I] LPSTR : string
996 * RETURN:
997 * Returns the width of an item width a specified string.
999 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem)
1001 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1002 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
1003 INT nHeaderItemCount;
1004 RECT rcHeaderItem;
1005 INT nItemWidth = 0;
1006 INT i;
1008 TRACE("(hwnd=%x)\n", hwnd);
1010 if (uView == LVS_ICON)
1012 nItemWidth = infoPtr->iconSpacing.cx;
1014 else if (uView == LVS_REPORT)
1016 /* calculate width of header */
1017 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
1018 for (i = 0; i < nHeaderItemCount; i++)
1020 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
1022 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
1026 else
1028 /* get width of string */
1029 nItemWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
1031 /* default label size */
1032 if (GETITEMCOUNT(infoPtr) == 0)
1034 nItemWidth = DEFAULT_COLUMN_WIDTH;
1036 else
1038 if (nItemWidth == 0)
1040 nItemWidth = DEFAULT_LABEL_WIDTH;
1042 else
1044 /* add padding */
1045 nItemWidth += WIDTH_PADDING;
1047 if (infoPtr->himlSmall != NULL)
1049 nItemWidth += infoPtr->iconSize.cx;
1052 if (infoPtr->himlState != NULL)
1054 nItemWidth += infoPtr->iconSize.cx;
1060 return nItemWidth;
1063 /***
1064 * DESCRIPTION:
1065 * Calculates the height of an item.
1067 * PARAMETER(S):
1068 * [I] HWND : window handle
1069 * [I] LONG : window style
1071 * RETURN:
1072 * Returns item height.
1074 static INT LISTVIEW_GetItemHeight(HWND hwnd)
1076 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1077 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
1078 INT nItemHeight = 0;
1080 if (uView == LVS_ICON)
1082 nItemHeight = infoPtr->iconSpacing.cy;
1084 else
1086 TEXTMETRICA tm;
1087 HDC hdc = GetDC(hwnd);
1088 HFONT hOldFont = SelectObject(hdc, infoPtr->hFont);
1089 GetTextMetricsA(hdc, &tm);
1091 if(infoPtr->himlState || infoPtr->himlSmall)
1092 nItemHeight = max(tm.tmHeight, infoPtr->iconSize.cy) + HEIGHT_PADDING;
1093 else
1094 nItemHeight = tm.tmHeight;
1096 SelectObject(hdc, hOldFont);
1097 ReleaseDC(hwnd, hdc);
1100 return nItemHeight;
1104 static void LISTVIEW_PrintSelectionRanges(HWND hwnd)
1106 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1107 LISTVIEW_SELECTION *selection;
1108 INT topSelection = infoPtr->hdpaSelectionRanges->nItemCount;
1109 INT i;
1111 TRACE("Selections are:\n");
1112 for (i = 0; i < topSelection; i++)
1114 selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,i);
1115 TRACE(" %lu - %lu\n",selection->lower,selection->upper);
1119 /***
1120 * DESCRIPTION:
1121 * A compare function for selection ranges
1123 *PARAMETER(S)
1124 * [I] LPVOID : Item 1;
1125 * [I] LPVOID : Item 2;
1126 * [I] LPARAM : flags
1128 *RETURNS:
1129 * >0 : if Item 1 > Item 2
1130 * <0 : if Item 2 > Item 1
1131 * 0 : if Item 1 == Item 2
1133 static INT CALLBACK LISTVIEW_CompareSelectionRanges(LPVOID range1, LPVOID range2,
1134 LPARAM flags)
1136 int l1 = ((LISTVIEW_SELECTION*)(range1))->lower;
1137 int l2 = ((LISTVIEW_SELECTION*)(range2))->lower;
1138 int u1 = ((LISTVIEW_SELECTION*)(range1))->upper;
1139 int u2 = ((LISTVIEW_SELECTION*)(range2))->upper;
1140 int rc=0;
1142 if (u1 < l2)
1143 rc= -1;
1145 if (u2 < l1)
1146 rc= 1;
1148 return rc;
1152 * DESCRIPTION:
1153 * Adds a selection range.
1155 * PARAMETER(S):
1156 * [I] HWND : window handle
1157 * [I] INT : lower item index
1158 * [I] INT : upper item index
1160 * RETURN:
1161 * None
1163 static VOID LISTVIEW_AddSelectionRange(HWND hwnd, INT lItem, INT uItem)
1165 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1166 LISTVIEW_SELECTION *selection;
1167 INT topSelection = infoPtr->hdpaSelectionRanges->nItemCount;
1168 BOOL lowerzero=FALSE;
1170 selection = (LISTVIEW_SELECTION *)COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION));
1171 selection->lower = lItem;
1172 selection->upper = uItem;
1174 TRACE("Add range %i - %i\n",lItem,uItem);
1175 if (topSelection)
1177 LISTVIEW_SELECTION *checkselection,*checkselection2;
1178 INT index,mergeindex;
1180 /* find overlapping selections */
1181 /* we want to catch adjacent ranges so expand our range by 1 */
1183 selection->upper++;
1184 if (selection->lower == 0)
1185 lowerzero = TRUE;
1186 else
1187 selection->lower--;
1189 index = DPA_Search(infoPtr->hdpaSelectionRanges, selection, 0,
1190 LISTVIEW_CompareSelectionRanges,
1191 0,0);
1192 selection->upper --;
1193 if (lowerzero)
1194 lowerzero=FALSE;
1195 else
1196 selection->lower ++;
1198 if (index >=0)
1200 checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,index);
1201 TRACE("Merge with index %i (%lu - %lu)\n",index,checkselection->lower,
1202 checkselection->upper);
1204 checkselection->lower = min(selection->lower,checkselection->lower);
1205 checkselection->upper = max(selection->upper,checkselection->upper);
1207 TRACE("New range (%lu - %lu)\n", checkselection->lower,
1208 checkselection->upper);
1210 COMCTL32_Free(selection);
1212 /* merge now common selection ranges in the lower group*/
1215 checkselection->upper ++;
1216 if (checkselection->lower == 0)
1217 lowerzero = TRUE;
1218 else
1219 checkselection->lower --;
1221 TRACE("search lower range (%lu - %lu)\n", checkselection->lower,
1222 checkselection->upper);
1224 /* not sorted yet */
1225 mergeindex = DPA_Search(infoPtr->hdpaSelectionRanges, checkselection, 0,
1226 LISTVIEW_CompareSelectionRanges, 0,
1229 checkselection->upper --;
1230 if (lowerzero)
1231 lowerzero = FALSE;
1232 else
1233 checkselection->lower ++;
1235 if (mergeindex >=0 && mergeindex != index)
1237 TRACE("Merge with index %i\n",mergeindex);
1238 checkselection2 = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
1239 mergeindex);
1240 checkselection->lower = min(checkselection->lower,
1241 checkselection2->lower);
1242 checkselection->upper = max(checkselection->upper,
1243 checkselection2->upper);
1244 COMCTL32_Free(checkselection2);
1245 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,mergeindex);
1246 index --;
1249 while (mergeindex > -1 && mergeindex <index);
1251 /* merge now common selection ranges in the upper group*/
1254 checkselection->upper ++;
1255 if (checkselection->lower == 0)
1256 lowerzero = TRUE;
1257 else
1258 checkselection->lower --;
1260 TRACE("search upper range %i (%lu - %lu)\n",index,
1261 checkselection->lower, checkselection->upper);
1263 /* not sorted yet */
1264 mergeindex = DPA_Search(infoPtr->hdpaSelectionRanges, checkselection,
1265 index+1,
1266 LISTVIEW_CompareSelectionRanges, 0,
1269 checkselection->upper --;
1270 if (lowerzero)
1271 lowerzero = FALSE;
1272 else
1273 checkselection->lower ++;
1275 if (mergeindex >=0 && mergeindex !=index)
1277 TRACE("Merge with index %i\n",mergeindex);
1278 checkselection2 = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
1279 mergeindex);
1280 checkselection->lower = min(checkselection->lower,
1281 checkselection2->lower);
1282 checkselection->upper = max(checkselection->upper,
1283 checkselection2->upper);
1284 COMCTL32_Free(checkselection2);
1285 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,mergeindex);
1288 while (mergeindex > -1);
1290 else
1293 index = DPA_Search(infoPtr->hdpaSelectionRanges, selection, 0,
1294 LISTVIEW_CompareSelectionRanges, 0,
1295 DPAS_INSERTAFTER);
1297 TRACE("Insert before index %i\n",index);
1298 if (index == -1)
1299 index = 0;
1300 DPA_InsertPtr(infoPtr->hdpaSelectionRanges,index,selection);
1303 else
1305 DPA_InsertPtr(infoPtr->hdpaSelectionRanges,0,selection);
1308 * Incase of error
1310 DPA_Sort(infoPtr->hdpaSelectionRanges,LISTVIEW_CompareSelectionRanges,0);
1311 LISTVIEW_PrintSelectionRanges(hwnd);
1315 * DESCRIPTION:
1316 * check if a specified index is selected.
1318 * PARAMETER(S):
1319 * [I] HWND : window handle
1320 * [I] INT : item index
1322 * RETURN:
1323 * None
1325 static BOOL LISTVIEW_IsSelected(HWND hwnd, INT nItem)
1327 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1328 LISTVIEW_SELECTION selection;
1329 INT index;
1331 selection.upper = nItem;
1332 selection.lower = nItem;
1334 index = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, 0,
1335 LISTVIEW_CompareSelectionRanges,
1336 0,DPAS_SORTED);
1337 if (index != -1)
1338 return TRUE;
1339 else
1340 return FALSE;
1343 /***
1344 * DESCRIPTION:
1345 * Removes all selection ranges
1347 * Parameters(s):
1348 * HWND: window handle
1350 * RETURNS:
1351 * SUCCESS : TRUE
1352 * FAILURE : TRUE
1354 static LRESULT LISTVIEW_RemoveAllSelections(HWND hwnd)
1356 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1357 LISTVIEW_SELECTION *selection;
1358 INT i;
1359 LVITEMA item;
1361 TRACE("(0x%x)\n",hwnd);
1363 ZeroMemory(&item,sizeof(LVITEMA));
1364 item.stateMask = LVIS_SELECTED;
1368 selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,0);
1369 if (selection)
1371 TRACE("Removing %lu to %lu\n",selection->lower, selection->upper);
1372 for (i = selection->lower; i<=selection->upper; i++)
1373 LISTVIEW_SetItemState(hwnd,i,&item);
1374 LISTVIEW_RemoveSelectionRange(hwnd,selection->lower,selection->upper);
1377 while (infoPtr->hdpaSelectionRanges->nItemCount>0);
1379 TRACE("done\n");
1380 return TRUE;
1384 * DESCRIPTION:
1385 * Removes a range selections.
1387 * PARAMETER(S):
1388 * [I] HWND : window handle
1389 * [I] INT : lower item index
1390 * [I] INT : upper item index
1392 * RETURN:
1393 * None
1395 static VOID LISTVIEW_RemoveSelectionRange(HWND hwnd, INT lItem, INT uItem)
1397 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1398 LISTVIEW_SELECTION removeselection,*checkselection;
1399 INT index;
1401 removeselection.lower = lItem;
1402 removeselection.upper = uItem;
1404 TRACE("Remove range %lu - %lu\n",removeselection.lower,removeselection.upper);
1405 LISTVIEW_PrintSelectionRanges(hwnd);
1407 index = DPA_Search(infoPtr->hdpaSelectionRanges, &removeselection, 0,
1408 LISTVIEW_CompareSelectionRanges,
1409 0,0);
1411 if (index == -1)
1412 return;
1415 checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
1416 index);
1418 TRACE("Matches range index %i (%lu-%lu)\n",index,checkselection->lower,
1419 checkselection->upper);
1421 /* case 1: Same */
1422 if ((checkselection->upper == removeselection.upper) &&
1423 (checkselection->lower == removeselection.lower))
1425 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,index);
1426 TRACE("Case 1\n");
1428 /* case 2: engulf */
1429 else if (((checkselection->upper < removeselection.upper) &&
1430 (checkselection->lower > removeselection.lower))||
1431 ((checkselection->upper <= removeselection.upper) &&
1432 (checkselection->lower > removeselection.lower)) ||
1433 ((checkselection->upper < removeselection.upper) &&
1434 (checkselection->lower >= removeselection.lower)))
1437 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,index);
1438 /* do it again because others may also get caught */
1439 TRACE("Case 2\n");
1440 LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
1442 /* case 3: overlap upper */
1443 else if ((checkselection->upper < removeselection.upper) &&
1444 (checkselection->lower < removeselection.lower))
1446 checkselection->upper = removeselection.lower - 1;
1447 TRACE("Case 3\n");
1448 LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
1450 /* case 4: overlap lower */
1451 else if ((checkselection->upper > removeselection.upper) &&
1452 (checkselection->lower > removeselection.lower))
1454 checkselection->lower = removeselection.upper + 1;
1455 TRACE("Case 4\n");
1456 LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
1458 /* case 5: fully internal */
1459 else if (checkselection->upper == removeselection.upper)
1460 checkselection->upper = removeselection.lower - 1;
1461 else if (checkselection->lower == removeselection.lower)
1462 checkselection->lower = removeselection.upper + 1;
1463 else
1465 /* bisect the range */
1466 LISTVIEW_SELECTION *newselection;
1468 newselection = (LISTVIEW_SELECTION *)
1469 COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION));
1470 newselection -> lower = checkselection->lower;
1471 newselection -> upper = removeselection.lower - 1;
1472 checkselection -> lower = removeselection.upper + 1;
1473 DPA_InsertPtr(infoPtr->hdpaSelectionRanges,index,newselection);
1474 TRACE("Case 5\n");
1475 DPA_Sort(infoPtr->hdpaSelectionRanges,LISTVIEW_CompareSelectionRanges,0);
1477 LISTVIEW_PrintSelectionRanges(hwnd);
1481 * DESCRIPTION:
1482 * shifts all selection indexs starting with the indesx specified
1483 * in the direction specified.
1485 * PARAMETER(S):
1486 * [I] HWND : window handle
1487 * [I] INT : item index
1488 * [I] INT : amount and direction of shift
1490 * RETURN:
1491 * None
1493 static VOID LISTVIEW_ShiftSelections(HWND hwnd, INT nItem, INT direction)
1495 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1496 LISTVIEW_SELECTION selection,*checkselection;
1497 INT index;
1499 TRACE("Shifting %iu, %i steps\n",nItem,direction);
1501 selection.upper = nItem;
1502 selection.lower = nItem;
1504 index = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, 0,
1505 LISTVIEW_CompareSelectionRanges,
1506 0,DPAS_SORTED|DPAS_INSERTAFTER);
1508 while ((index < infoPtr->hdpaSelectionRanges->nItemCount)&&(index != -1))
1510 checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,index);
1511 if ((checkselection->lower >= nItem)&&
1512 (checkselection->lower + direction >= 0))
1513 checkselection->lower += direction;
1514 if ((checkselection->upper >= nItem)&&
1515 (checkselection->upper + direction >=0))
1516 checkselection->upper += direction;
1517 index ++;
1523 * DESCRIPTION:
1524 * Adds a block of selections.
1526 * PARAMETER(S):
1527 * [I] HWND : window handle
1528 * [I] INT : item index
1530 * RETURN:
1531 * None
1533 static VOID LISTVIEW_AddGroupSelection(HWND hwnd, INT nItem)
1535 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1536 INT nFirst = min(infoPtr->nSelectionMark, nItem);
1537 INT nLast = max(infoPtr->nSelectionMark, nItem);
1538 INT i;
1539 LVITEMA item;
1541 ZeroMemory(&item,sizeof(LVITEMA));
1542 item.stateMask = LVIS_SELECTED;
1543 item.state = LVIS_SELECTED;
1545 for (i = nFirst; i <= nLast; i++);
1547 LISTVIEW_SetItemState(hwnd,i,&item);
1550 LISTVIEW_SetItemFocus(hwnd, nItem);
1551 infoPtr->nSelectionMark = nItem;
1555 /***
1556 * DESCRIPTION:
1557 * Adds a single selection.
1559 * PARAMETER(S):
1560 * [I] HWND : window handle
1561 * [I] INT : item index
1563 * RETURN:
1564 * None
1566 static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem)
1568 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1569 LVITEMA item;
1571 ZeroMemory(&item,sizeof(LVITEMA));
1572 item.state = LVIS_SELECTED;
1573 item.stateMask = LVIS_SELECTED;
1575 LISTVIEW_SetItemState(hwnd,nItem,&item);
1577 LISTVIEW_SetItemFocus(hwnd, nItem);
1578 infoPtr->nSelectionMark = nItem;
1581 /***
1582 * DESCRIPTION:
1583 * Selects or unselects an item.
1585 * PARAMETER(S):
1586 * [I] HWND : window handle
1587 * [I] INT : item index
1589 * RETURN:
1590 * SELECT: TRUE
1591 * UNSELECT : FALSE
1593 static BOOL LISTVIEW_ToggleSelection(HWND hwnd, INT nItem)
1595 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1596 BOOL bResult;
1597 LVITEMA item;
1599 ZeroMemory(&item,sizeof(LVITEMA));
1600 item.stateMask = LVIS_SELECTED;
1602 if (LISTVIEW_IsSelected(hwnd,nItem))
1605 LISTVIEW_SetItemState(hwnd,nItem,&item);
1606 bResult = FALSE;
1608 else
1610 item.state = LVIS_SELECTED;
1611 LISTVIEW_SetItemState(hwnd,nItem,&item);
1612 bResult = TRUE;
1615 LISTVIEW_SetItemFocus(hwnd, nItem);
1616 infoPtr->nSelectionMark = nItem;
1618 return bResult;
1621 /***
1622 * DESCRIPTION:
1623 * Selects items based on view coordinates.
1625 * PARAMETER(S):
1626 * [I] HWND : window handle
1627 * [I] RECT : selection rectangle
1629 * RETURN:
1630 * None
1632 static VOID LISTVIEW_SetSelectionRect(HWND hwnd, RECT rcSelRect)
1634 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1635 POINT ptItem;
1636 INT i;
1637 LVITEMA item;
1639 ZeroMemory(&item,sizeof(LVITEMA));
1640 item.stateMask = LVIS_SELECTED;
1642 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
1644 LISTVIEW_GetItemPosition(hwnd, i, &ptItem);
1646 if (PtInRect(&rcSelRect, ptItem) != FALSE)
1648 item.state = LVIS_SELECTED;
1649 LISTVIEW_SetItemState(hwnd,i,&item);
1651 else
1653 item.state = 0;
1654 LISTVIEW_SetItemState(hwnd,i,&item);
1659 /***
1660 * DESCRIPTION:
1661 * Sets a single group selection.
1663 * PARAMETER(S):
1664 * [I] HWND : window handle
1665 * [I] INT : item index
1667 * RETURN:
1668 * None
1670 static VOID LISTVIEW_SetGroupSelection(HWND hwnd, INT nItem)
1672 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1673 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
1674 LVITEMA item;
1676 ZeroMemory(&item,sizeof(LVITEMA));
1677 item.stateMask = LVIS_SELECTED;
1679 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
1681 INT i;
1682 INT nFirst = min(infoPtr->nSelectionMark, nItem);
1683 INT nLast = max(infoPtr->nSelectionMark, nItem);
1685 for (i = 0; i <= GETITEMCOUNT(infoPtr); i++)
1687 if ((i < nFirst) || (i > nLast))
1689 item.state = 0;
1690 LISTVIEW_SetItemState(hwnd,i,&item);
1692 else
1694 item.state = LVIS_SELECTED;
1695 LISTVIEW_SetItemState(hwnd,i,&item);
1699 else
1701 POINT ptItem;
1702 POINT ptSelMark;
1703 RECT rcSel;
1704 LISTVIEW_GetItemPosition(hwnd, nItem, &ptItem);
1705 LISTVIEW_GetItemPosition(hwnd, infoPtr->nSelectionMark, &ptSelMark);
1706 rcSel.left = min(ptSelMark.x, ptItem.x);
1707 rcSel.top = min(ptSelMark.y, ptItem.y);
1708 rcSel.right = max(ptSelMark.x, ptItem.x) + infoPtr->nItemWidth;
1709 rcSel.bottom = max(ptSelMark.y, ptItem.y) + infoPtr->nItemHeight;
1710 LISTVIEW_SetSelectionRect(hwnd, rcSel);
1713 LISTVIEW_SetItemFocus(hwnd, nItem);
1716 /***
1717 * DESCRIPTION:
1718 * Manages the item focus.
1720 * PARAMETER(S):
1721 * [I] HWND : window handle
1722 * [I] INT : item index
1724 * RETURN:
1725 * TRUE : focused item changed
1726 * FALSE : focused item has NOT changed
1728 static BOOL LISTVIEW_SetItemFocus(HWND hwnd, INT nItem)
1730 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1731 BOOL bResult = FALSE;
1732 LVITEMA lvItem;
1734 if (infoPtr->nFocusedItem != nItem)
1736 if (infoPtr->nFocusedItem >= 0)
1738 INT oldFocus = infoPtr->nFocusedItem;
1739 bResult = TRUE;
1740 infoPtr->nFocusedItem = -1;
1741 ZeroMemory(&lvItem, sizeof(LVITEMA));
1742 lvItem.stateMask = LVIS_FOCUSED;
1743 ListView_SetItemState(hwnd, oldFocus, &lvItem);
1747 lvItem.state = LVIS_FOCUSED;
1748 lvItem.stateMask = LVIS_FOCUSED;
1749 ListView_SetItemState(hwnd, nItem, &lvItem);
1751 infoPtr->nFocusedItem = nItem;
1752 ListView_EnsureVisible(hwnd, nItem, FALSE);
1755 return bResult;
1758 /***
1759 * DESCRIPTION:
1760 * Sets a single selection.
1762 * PARAMETER(S):
1763 * [I] HWND : window handle
1764 * [I] INT : item index
1766 * RETURN:
1767 * None
1769 static VOID LISTVIEW_SetSelection(HWND hwnd, INT nItem)
1771 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1772 LVITEMA lvItem;
1774 ZeroMemory(&lvItem, sizeof(LVITEMA));
1775 lvItem.stateMask = LVIS_FOCUSED;
1776 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
1778 LISTVIEW_RemoveAllSelections(hwnd);
1780 lvItem.state = LVIS_FOCUSED|LVIS_SELECTED;
1781 lvItem.stateMask = LVIS_FOCUSED|LVIS_SELECTED;
1782 ListView_SetItemState(hwnd, nItem, &lvItem);
1784 infoPtr->nFocusedItem = nItem;
1785 infoPtr->nSelectionMark = nItem;
1788 /***
1789 * DESCRIPTION:
1790 * Set selection(s) with keyboard.
1792 * PARAMETER(S):
1793 * [I] HWND : window handle
1794 * [I] INT : item index
1796 * RETURN:
1797 * SUCCESS : TRUE (needs to be repainted)
1798 * FAILURE : FALSE (nothing has changed)
1800 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem)
1802 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1803 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1804 WORD wShift = HIWORD(GetKeyState(VK_SHIFT));
1805 WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL));
1806 BOOL bResult = FALSE;
1808 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
1810 if (lStyle & LVS_SINGLESEL)
1812 bResult = TRUE;
1813 LISTVIEW_SetSelection(hwnd, nItem);
1814 ListView_EnsureVisible(hwnd, nItem, FALSE);
1816 else
1818 if (wShift)
1820 bResult = TRUE;
1821 LISTVIEW_SetGroupSelection(hwnd, nItem);
1823 else if (wCtrl)
1825 bResult = LISTVIEW_SetItemFocus(hwnd, nItem);
1827 else
1829 bResult = TRUE;
1830 LISTVIEW_SetSelection(hwnd, nItem);
1831 ListView_EnsureVisible(hwnd, nItem, FALSE);
1836 return bResult;
1839 /***
1840 * DESCRIPTION:
1841 * Called when the mouse is being actively tracked and has hovered for a specified
1842 * amount of time
1844 * PARAMETER(S):
1845 * [I] HWND : window handle
1846 * [I] wParam : key indicator
1847 * [I] lParam : mouse position
1849 * RETURN:
1850 * 0 if the message was processed, non-zero if there was an error
1852 * INFO:
1853 * LVS_EX_TRACKSELECT: An item is automatically selected when the cursor remains
1854 * over the item for a certain period of time.
1857 static LRESULT LISTVIEW_MouseHover(HWND hwnd, WPARAM wParam, LPARAM lParam)
1859 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1860 POINT pt;
1862 pt.x = (INT)LOWORD(lParam);
1863 pt.y = (INT)HIWORD(lParam);
1865 if(infoPtr->dwExStyle & LVS_EX_TRACKSELECT) {
1866 /* select the item under the cursor */
1867 LISTVIEW_MouseSelection(hwnd, pt);
1870 return 0;
1873 /***
1874 * DESCRIPTION:
1875 * Called whenever WM_MOUSEMOVE is recieved.
1877 * PARAMETER(S):
1878 * [I] HWND : window handle
1879 * [I] wParam : key indicators
1880 * [I] lParam : cursor position
1882 * RETURN:
1883 * 0 if the message is processed, non-zero if there was an error
1885 static LRESULT LISTVIEW_MouseMove(HWND hwnd, WPARAM wParam, LPARAM lParam)
1887 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1888 TRACKMOUSEEVENT trackinfo;
1890 /* see if we are supposed to be tracking mouse hovering */
1891 if(infoPtr->dwExStyle & LVS_EX_TRACKSELECT) {
1892 /* fill in the trackinfo struct */
1893 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
1894 trackinfo.dwFlags = TME_QUERY;
1895 trackinfo.hwndTrack = hwnd;
1896 trackinfo.dwHoverTime = infoPtr->dwHoverTime;
1898 /* see if we are already tracking this hwnd */
1899 _TrackMouseEvent(&trackinfo);
1901 if(!(trackinfo.dwFlags & TME_HOVER)) {
1902 trackinfo.dwFlags = TME_HOVER;
1904 /* call TRACKMOUSEEVENT so we recieve WM_MOUSEHOVER messages */
1905 _TrackMouseEvent(&trackinfo);
1909 return 0;
1912 /***
1913 * DESCRIPTION:
1914 * Selects an item based on coordinates.
1916 * PARAMETER(S):
1917 * [I] HWND : window handle
1918 * [I] POINT : mouse click ccordinates
1920 * RETURN:
1921 * SUCCESS : item index
1922 * FAILURE : -1
1924 static LRESULT LISTVIEW_MouseSelection(HWND hwnd, POINT pt)
1926 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1927 RECT rcItem;
1928 INT i,topindex,bottomindex;
1929 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1930 UINT uView = lStyle & LVS_TYPEMASK;
1932 topindex = ListView_GetTopIndex(hwnd);
1933 if (uView == LVS_REPORT)
1935 bottomindex = topindex + LISTVIEW_GetCountPerColumn(hwnd) + 1;
1936 bottomindex = min(bottomindex,GETITEMCOUNT(infoPtr));
1938 else
1940 bottomindex = GETITEMCOUNT(infoPtr);
1943 for (i = topindex; i < bottomindex; i++)
1945 rcItem.left = LVIR_SELECTBOUNDS;
1946 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) == TRUE)
1948 if (PtInRect(&rcItem, pt) != FALSE)
1950 return i;
1955 return -1;
1958 /***
1959 * DESCRIPTION:
1960 * Removes a column.
1962 * PARAMETER(S):
1963 * [IO] HDPA : dynamic pointer array handle
1964 * [I] INT : column index (subitem index)
1966 * RETURN:
1967 * SUCCCESS : TRUE
1968 * FAILURE : FALSE
1970 static BOOL LISTVIEW_RemoveColumn(HDPA hdpaItems, INT nSubItem)
1972 BOOL bResult = TRUE;
1973 HDPA hdpaSubItems;
1974 INT i;
1976 for (i = 0; i < hdpaItems->nItemCount; i++)
1978 hdpaSubItems = (HDPA)DPA_GetPtr(hdpaItems, i);
1979 if (hdpaSubItems != NULL)
1981 if (LISTVIEW_RemoveSubItem(hdpaSubItems, nSubItem) == FALSE)
1983 bResult = FALSE;
1988 return bResult;
1991 /***
1992 * DESCRIPTION:
1993 * Removes a subitem at a given position.
1995 * PARAMETER(S):
1996 * [IO] HDPA : dynamic pointer array handle
1997 * [I] INT : subitem index
1999 * RETURN:
2000 * SUCCCESS : TRUE
2001 * FAILURE : FALSE
2003 static BOOL LISTVIEW_RemoveSubItem(HDPA hdpaSubItems, INT nSubItem)
2005 LISTVIEW_SUBITEM *lpSubItem;
2006 INT i;
2008 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2010 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2011 if (lpSubItem != NULL)
2013 if (lpSubItem->iSubItem == nSubItem)
2015 /* free string */
2016 if ((lpSubItem->pszText != NULL) &&
2017 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2019 COMCTL32_Free(lpSubItem->pszText);
2022 /* free item */
2023 COMCTL32_Free(lpSubItem);
2025 /* free dpa memory */
2026 if (DPA_DeletePtr(hdpaSubItems, i) == NULL)
2028 return FALSE;
2031 else if (lpSubItem->iSubItem > nSubItem)
2033 return TRUE;
2038 return TRUE;
2041 /***
2042 * DESCRIPTION:
2043 * Compares the item information.
2045 * PARAMETER(S):
2046 * [I] LISTVIEW_ITEM *: destination item
2047 * [I] LPLVITEM : source item
2049 * RETURN:
2050 * SUCCCESS : TRUE (EQUAL)
2051 * FAILURE : FALSE (NOT EQUAL)
2053 static UINT LISTVIEW_GetItemChanges(LISTVIEW_ITEM *lpItem, LPLVITEMA lpLVItem)
2055 UINT uChanged = 0;
2057 if ((lpItem != NULL) && (lpLVItem != NULL))
2059 if (lpLVItem->mask & LVIF_STATE)
2061 if ((lpItem->state & lpLVItem->stateMask) !=
2062 (lpLVItem->state & lpLVItem->stateMask))
2064 uChanged |= LVIF_STATE;
2068 if (lpLVItem->mask & LVIF_IMAGE)
2070 if (lpItem->iImage != lpLVItem->iImage)
2072 uChanged |= LVIF_IMAGE;
2076 if (lpLVItem->mask & LVIF_PARAM)
2078 if (lpItem->lParam != lpLVItem->lParam)
2080 uChanged |= LVIF_PARAM;
2084 if (lpLVItem->mask & LVIF_INDENT)
2086 if (lpItem->iIndent != lpLVItem->iIndent)
2088 uChanged |= LVIF_INDENT;
2092 if (lpLVItem->mask & LVIF_TEXT)
2094 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
2096 if (lpItem->pszText != LPSTR_TEXTCALLBACKA)
2098 uChanged |= LVIF_TEXT;
2101 else
2103 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
2105 uChanged |= LVIF_TEXT;
2107 else
2109 if (lpLVItem->pszText)
2111 if (lpItem->pszText)
2113 if (strcmp(lpLVItem->pszText, lpItem->pszText) != 0)
2115 uChanged |= LVIF_TEXT;
2118 else
2120 uChanged |= LVIF_TEXT;
2123 else
2125 if (lpItem->pszText)
2127 uChanged |= LVIF_TEXT;
2134 return uChanged;
2137 /***
2138 * DESCRIPTION:
2139 * Initializes item attributes.
2141 * PARAMETER(S):
2142 * [I] HWND : window handle
2143 * [O] LISTVIEW_ITEM *: destination item
2144 * [I] LPLVITEM : source item
2146 * RETURN:
2147 * SUCCCESS : TRUE
2148 * FAILURE : FALSE
2150 static BOOL LISTVIEW_InitItem(HWND hwnd, LISTVIEW_ITEM *lpItem,
2151 LPLVITEMA lpLVItem)
2153 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2154 BOOL bResult = FALSE;
2156 if ((lpItem != NULL) && (lpLVItem != NULL))
2158 bResult = TRUE;
2160 if (lpLVItem->mask & LVIF_STATE)
2162 lpItem->state &= ~lpLVItem->stateMask;
2163 lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
2166 if (lpLVItem->mask & LVIF_IMAGE)
2168 lpItem->iImage = lpLVItem->iImage;
2171 if (lpLVItem->mask & LVIF_PARAM)
2173 lpItem->lParam = lpLVItem->lParam;
2176 if (lpLVItem->mask & LVIF_INDENT)
2178 lpItem->iIndent = lpLVItem->iIndent;
2181 if (lpLVItem->mask & LVIF_TEXT)
2183 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
2185 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
2187 return FALSE;
2190 if ((lpItem->pszText != NULL) &&
2191 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2193 COMCTL32_Free(lpItem->pszText);
2196 lpItem->pszText = LPSTR_TEXTCALLBACKA;
2198 else
2200 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
2202 lpItem->pszText = NULL;
2205 bResult = Str_SetPtrA(&lpItem->pszText, lpLVItem->pszText);
2210 return bResult;
2213 /***
2214 * DESCRIPTION:
2215 * Initializes subitem attributes.
2217 * NOTE: The documentation specifies that the operation fails if the user
2218 * tries to set the indent of a subitem.
2220 * PARAMETER(S):
2221 * [I] HWND : window handle
2222 * [O] LISTVIEW_SUBITEM *: destination subitem
2223 * [I] LPLVITEM : source subitem
2225 * RETURN:
2226 * SUCCCESS : TRUE
2227 * FAILURE : FALSE
2229 static BOOL LISTVIEW_InitSubItem(HWND hwnd, LISTVIEW_SUBITEM *lpSubItem,
2230 LPLVITEMA lpLVItem)
2232 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2233 BOOL bResult = FALSE;
2235 if ((lpSubItem != NULL) && (lpLVItem != NULL))
2237 if (!(lpLVItem->mask & LVIF_INDENT))
2239 bResult = TRUE;
2241 lpSubItem->iSubItem = lpLVItem->iSubItem;
2243 if (lpLVItem->mask & LVIF_IMAGE)
2245 lpSubItem->iImage = lpLVItem->iImage;
2248 if (lpLVItem->mask & LVIF_TEXT)
2250 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
2252 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
2254 return FALSE;
2257 if ((lpSubItem->pszText != NULL) &&
2258 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2260 COMCTL32_Free(lpSubItem->pszText);
2263 lpSubItem->pszText = LPSTR_TEXTCALLBACKA;
2265 else
2267 if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
2269 lpSubItem->pszText = NULL;
2272 bResult = Str_SetPtrA(&lpSubItem->pszText, lpLVItem->pszText);
2278 return bResult;
2281 /***
2282 * DESCRIPTION:
2283 * Adds a subitem at a given position (column index).
2285 * PARAMETER(S):
2286 * [I] HWND : window handle
2287 * [I] LPLVITEM : new subitem atttributes
2289 * RETURN:
2290 * SUCCESS : TRUE
2291 * FAILURE : FALSE
2293 static BOOL LISTVIEW_AddSubItem(HWND hwnd, LPLVITEMA lpLVItem)
2295 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2296 LISTVIEW_SUBITEM *lpSubItem = NULL;
2297 BOOL bResult = FALSE;
2298 HDPA hdpaSubItems;
2299 INT nPosition, nItem;
2300 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2302 if (lStyle & LVS_OWNERDATA)
2303 return FALSE;
2305 if (lpLVItem != NULL)
2307 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
2308 if (hdpaSubItems != NULL)
2310 lpSubItem = (LISTVIEW_SUBITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM));
2311 if (lpSubItem != NULL)
2313 ZeroMemory(lpSubItem, sizeof(LISTVIEW_SUBITEM));
2314 if (LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem) != FALSE)
2316 nPosition = LISTVIEW_FindInsertPosition(hdpaSubItems,
2317 lpSubItem->iSubItem);
2318 nItem = DPA_InsertPtr(hdpaSubItems, nPosition, lpSubItem);
2319 if (nItem != -1)
2321 bResult = TRUE;
2328 /* cleanup if unsuccessful */
2329 if ((bResult == FALSE) && (lpSubItem != NULL))
2331 COMCTL32_Free(lpSubItem);
2334 return bResult;
2337 /***
2338 * DESCRIPTION:
2339 * Finds the dpa insert position (array index).
2341 * PARAMETER(S):
2342 * [I] HWND : window handle
2343 * [I] INT : subitem index
2345 * RETURN:
2346 * SUCCESS : TRUE
2347 * FAILURE : FALSE
2349 static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem)
2351 LISTVIEW_SUBITEM *lpSubItem;
2352 INT i;
2354 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2356 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2357 if (lpSubItem != NULL)
2359 if (lpSubItem->iSubItem > nSubItem)
2361 return i;
2366 return hdpaSubItems->nItemCount;
2369 /***
2370 * DESCRIPTION:
2371 * Retrieves a listview subitem at a given position (column index).
2373 * PARAMETER(S):
2374 * [I] HWND : window handle
2375 * [I] INT : subitem index
2377 * RETURN:
2378 * SUCCESS : TRUE
2379 * FAILURE : FALSE
2381 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem)
2383 LISTVIEW_SUBITEM *lpSubItem;
2384 INT i;
2386 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2388 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2389 if (lpSubItem != NULL)
2391 if (lpSubItem->iSubItem == nSubItem)
2393 return lpSubItem;
2395 else if (lpSubItem->iSubItem > nSubItem)
2397 return NULL;
2402 return NULL;
2405 /***
2406 * DESCRIPTION:
2407 * Sets item attributes.
2409 * PARAMETER(S):
2410 * [I] HWND : window handle
2411 * [I] LPLVITEM : new item atttributes
2413 * RETURN:
2414 * SUCCESS : TRUE
2415 * FAILURE : FALSE
2417 static BOOL LISTVIEW_SetItem(HWND hwnd, LPLVITEMA lpLVItem)
2419 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2420 BOOL bResult = FALSE;
2421 HDPA hdpaSubItems;
2422 LISTVIEW_ITEM *lpItem;
2423 NMLISTVIEW nmlv;
2424 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2425 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2426 UINT uChanged;
2427 UINT uView = lStyle & LVS_TYPEMASK;
2428 INT item_width;
2429 RECT rcItem;
2431 if (lStyle & LVS_OWNERDATA)
2433 if ((lpLVItem->iSubItem == 0)&&(lpLVItem->mask == LVIF_STATE))
2435 LVITEMA itm;
2437 ZeroMemory(&itm,sizeof(LVITEMA));
2438 itm.mask = LVIF_STATE | LVIF_PARAM;
2439 itm.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
2440 itm.iItem = lpLVItem->iItem;
2441 itm.iSubItem = 0;
2442 ListView_GetItemA(hwnd,&itm);
2445 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2446 nmlv.hdr.hwndFrom = hwnd;
2447 nmlv.hdr.idFrom = lCtrlId;
2448 nmlv.hdr.code = LVN_ITEMCHANGING;
2449 nmlv.uNewState = lpLVItem->state;
2450 nmlv.uOldState = itm.state;
2451 nmlv.uChanged = LVIF_STATE;
2452 nmlv.lParam = itm.lParam;
2453 nmlv.iItem = lpLVItem->iItem;
2455 if ((itm.state & lpLVItem->stateMask) !=
2456 (lpLVItem->state & lpLVItem->stateMask))
2458 /* send LVN_ITEMCHANGING notification */
2459 if (!ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv))
2461 if (lpLVItem->stateMask & LVIS_FOCUSED)
2463 if (lpLVItem->state & LVIS_FOCUSED)
2464 infoPtr->nFocusedItem = lpLVItem->iItem;
2465 else if (infoPtr->nFocusedItem == lpLVItem->iItem)
2466 infoPtr->nFocusedItem = -1;
2468 if (lpLVItem->stateMask & LVIS_SELECTED)
2470 if (lpLVItem->state & LVIS_SELECTED)
2472 if (lStyle & LVS_SINGLESEL)
2474 LISTVIEW_RemoveAllSelections(hwnd);
2476 LISTVIEW_AddSelectionRange(hwnd,lpLVItem->iItem,lpLVItem->iItem);
2478 else
2479 LISTVIEW_RemoveSelectionRange(hwnd,lpLVItem->iItem,
2480 lpLVItem->iItem);
2483 nmlv.hdr.code = LVN_ITEMCHANGED;
2485 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2487 rcItem.left = LVIR_BOUNDS;
2488 LISTVIEW_GetItemRect(hwnd, lpLVItem->iItem, &rcItem);
2489 InvalidateRect(hwnd, &rcItem, TRUE);
2492 return TRUE;
2494 return FALSE;
2497 if (lpLVItem != NULL)
2499 if (lpLVItem->iSubItem == 0)
2501 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
2502 if (hdpaSubItems != NULL && hdpaSubItems != (HDPA)-1)
2504 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem);
2505 if (lpItem != NULL)
2507 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2508 nmlv.hdr.hwndFrom = hwnd;
2509 nmlv.hdr.idFrom = lCtrlId;
2510 nmlv.hdr.code = LVN_ITEMCHANGING;
2511 nmlv.lParam = lpItem->lParam;
2512 uChanged = LISTVIEW_GetItemChanges(lpItem, lpLVItem);
2513 if (uChanged != 0)
2515 if (uChanged & LVIF_STATE)
2517 nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask;
2518 nmlv.uOldState = lpItem->state & lpLVItem->stateMask;
2520 if (nmlv.uNewState & LVIS_SELECTED)
2523 * This is redundant if called through SetSelection
2525 * however is required if the used directly calls SetItem
2526 * to set the selection.
2528 if (lStyle & LVS_SINGLESEL)
2530 LISTVIEW_RemoveAllSelections(hwnd);
2533 LISTVIEW_AddSelectionRange(hwnd,lpLVItem->iItem,
2534 lpLVItem->iItem);
2536 else if (lpLVItem->stateMask & LVIS_SELECTED)
2538 LISTVIEW_RemoveSelectionRange(hwnd,lpLVItem->iItem,
2539 lpLVItem->iItem);
2541 if (nmlv.uNewState & LVIS_FOCUSED)
2544 * This is a fun hoop to jump to try to catch if
2545 * the user is calling us directly to call focus or if
2546 * this function is being called as a result of a
2547 * SetItemFocus call.
2549 if (infoPtr->nFocusedItem >= 0)
2550 LISTVIEW_SetItemFocus(hwnd, lpLVItem->iItem);
2554 nmlv.uChanged = uChanged;
2555 nmlv.iItem = lpLVItem->iItem;
2556 nmlv.lParam = lpItem->lParam;
2557 /* send LVN_ITEMCHANGING notification */
2558 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2560 /* copy information */
2561 bResult = LISTVIEW_InitItem(hwnd, lpItem, lpLVItem);
2563 /* if LVS_LIST or LVS_SMALLICON, update the width of the items
2564 based on the width of the items text */
2565 if((uView == LVS_LIST) || (uView == LVS_SMALLICON))
2567 item_width = LISTVIEW_GetStringWidthA(hwnd, lpItem->pszText);
2569 if(item_width > infoPtr->nItemWidth)
2570 infoPtr->nItemWidth = item_width;
2573 /* send LVN_ITEMCHANGED notification */
2574 nmlv.hdr.code = LVN_ITEMCHANGED;
2575 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2577 else
2579 bResult = TRUE;
2582 if (uChanged)
2584 rcItem.left = LVIR_BOUNDS;
2585 LISTVIEW_GetItemRect(hwnd, lpLVItem->iItem, &rcItem);
2586 InvalidateRect(hwnd, &rcItem, TRUE);
2593 return bResult;
2596 /***
2597 * DESCRIPTION:
2598 * Sets subitem attributes.
2600 * PARAMETER(S):
2601 * [I] HWND : window handle
2602 * [I] LPLVITEM : new subitem atttributes
2604 * RETURN:
2605 * SUCCESS : TRUE
2606 * FAILURE : FALSE
2608 static BOOL LISTVIEW_SetSubItem(HWND hwnd, LPLVITEMA lpLVItem)
2610 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2611 BOOL bResult = FALSE;
2612 HDPA hdpaSubItems;
2613 LISTVIEW_SUBITEM *lpSubItem;
2614 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2615 RECT rcItem;
2617 if (lStyle & LVS_OWNERDATA)
2618 return FALSE;
2620 if (lpLVItem != NULL)
2622 if (lpLVItem->iSubItem > 0)
2624 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
2625 if (hdpaSubItems != NULL)
2627 /* set subitem only if column is present */
2628 if (Header_GetItemCount(infoPtr->hwndHeader) > lpLVItem->iSubItem)
2630 lpSubItem = LISTVIEW_GetSubItem(hdpaSubItems, lpLVItem->iSubItem);
2631 if (lpSubItem != NULL)
2633 bResult = LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem);
2635 else
2637 bResult = LISTVIEW_AddSubItem(hwnd, lpLVItem);
2640 rcItem.left = LVIR_BOUNDS;
2641 LISTVIEW_GetItemRect(hwnd, lpLVItem->iItem, &rcItem);
2642 InvalidateRect(hwnd, &rcItem, FALSE);
2648 return bResult;
2651 /***
2652 * DESCRIPTION:
2653 * Retrieves the index of the item at coordinate (0, 0) of the client area.
2655 * PARAMETER(S):
2656 * [I] HWND : window handle
2658 * RETURN:
2659 * item index
2661 static INT LISTVIEW_GetTopIndex(HWND hwnd)
2663 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2664 UINT uView = lStyle & LVS_TYPEMASK;
2665 INT nItem = 0;
2666 SCROLLINFO scrollInfo;
2668 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2669 scrollInfo.cbSize = sizeof(SCROLLINFO);
2670 scrollInfo.fMask = SIF_POS;
2672 if (uView == LVS_LIST)
2674 if (lStyle & WS_HSCROLL)
2676 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2678 nItem = scrollInfo.nPos * LISTVIEW_GetCountPerColumn(hwnd);
2682 else if (uView == LVS_REPORT)
2684 if (lStyle & WS_VSCROLL)
2686 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
2688 nItem = scrollInfo.nPos;
2693 return nItem;
2696 /***
2697 * DESCRIPTION:
2698 * Draws a subitem.
2700 * PARAMETER(S):
2701 * [I] HWND : window handle
2702 * [I] HDC : device context handle
2703 * [I] INT : item index
2704 * [I] INT : subitem index
2705 * [I] RECT * : clipping rectangle
2707 * RETURN:
2708 * None
2710 static VOID LISTVIEW_DrawSubItem(HWND hwnd, HDC hdc, INT nItem, INT nSubItem,
2711 RECT rcItem, BOOL Selected)
2713 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2714 CHAR szDispText[DISP_TEXT_SIZE];
2715 LVITEMA lvItem;
2716 UINT textoutOptions = ETO_CLIPPED | ETO_OPAQUE;
2717 RECT rcTemp;
2719 TRACE("(hwnd=%x, hdc=%x, nItem=%d, nSubItem=%d)\n", hwnd, hdc,
2720 nItem, nSubItem);
2722 /* get information needed for drawing the item */
2723 ZeroMemory(&lvItem, sizeof(LVITEMA));
2724 lvItem.mask = LVIF_TEXT;
2725 lvItem.iItem = nItem;
2726 lvItem.iSubItem = nSubItem;
2727 lvItem.cchTextMax = DISP_TEXT_SIZE;
2728 lvItem.pszText = szDispText;
2729 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
2731 /* redraw the background of the item */
2732 rcTemp = rcItem;
2733 if(infoPtr->nColumnCount == (nSubItem + 1))
2734 rcTemp.right = infoPtr->rcList.right;
2735 else
2736 rcTemp.right+=WIDTH_PADDING;
2738 LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
2740 /* set item colors */
2741 if (ListView_GetItemState(hwnd,nItem,LVIS_SELECTED) && Selected)
2743 if (infoPtr->bFocus)
2745 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
2746 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2748 else
2750 SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
2751 SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
2754 else
2756 if ( (infoPtr->clrTextBk == CLR_DEFAULT) || (infoPtr->clrTextBk == CLR_NONE) )
2758 SetBkMode(hdc, TRANSPARENT);
2759 textoutOptions &= ~ETO_OPAQUE;
2761 else
2763 SetBkMode(hdc, OPAQUE);
2764 SetBkColor(hdc, infoPtr->clrTextBk);
2767 SetTextColor(hdc, infoPtr->clrText);
2770 ExtTextOutA(hdc, rcItem.left, rcItem.top, textoutOptions,
2771 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
2773 if (Selected)
2775 /* fill in the gap */
2776 RECT rec;
2777 if (nSubItem < Header_GetItemCount(infoPtr->hwndHeader)-1)
2779 CopyRect(&rec,&rcItem);
2780 rec.left = rec.right;
2781 rec.right = rec.left+REPORT_MARGINX;
2782 ExtTextOutA(hdc, rec.left , rec.top, textoutOptions,
2783 &rec, NULL, 0, NULL);
2785 CopyRect(&rec,&rcItem);
2786 rec.right = rec.left;
2787 rec.left = rec.left - REPORT_MARGINX;
2788 ExtTextOutA(hdc, rec.left , rec.top, textoutOptions,
2789 &rec, NULL, 0, NULL);
2794 /***
2795 * DESCRIPTION:
2796 * Draws an item.
2798 * PARAMETER(S):
2799 * [I] HWND : window handle
2800 * [I] HDC : device context handle
2801 * [I] INT : item index
2802 * [I] RECT * : clipping rectangle
2804 * RETURN:
2805 * None
2807 static VOID LISTVIEW_DrawItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem, BOOL FullSelect, RECT* SuggestedFocus)
2809 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2810 CHAR szDispText[DISP_TEXT_SIZE];
2811 INT nLabelWidth;
2812 LVITEMA lvItem;
2813 INT nMixMode;
2814 DWORD dwBkColor;
2815 DWORD dwTextColor,dwTextX;
2816 BOOL bImage = FALSE;
2817 INT iBkMode = -1;
2818 UINT textoutOptions = ETO_OPAQUE | ETO_CLIPPED;
2819 RECT rcTemp;
2821 TRACE("(hwnd=%x, hdc=%x, nItem=%d)\n", hwnd, hdc, nItem);
2824 /* get information needed for drawing the item */
2825 ZeroMemory(&lvItem, sizeof(LVITEMA));
2826 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_INDENT;
2827 lvItem.stateMask = LVIS_SELECTED | LVIS_STATEIMAGEMASK;
2828 lvItem.iItem = nItem;
2829 lvItem.iSubItem = 0;
2830 lvItem.cchTextMax = DISP_TEXT_SIZE;
2831 lvItem.pszText = szDispText;
2832 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
2834 /* redraw the background of the item */
2835 rcTemp = rcItem;
2836 if(infoPtr->nColumnCount == (nItem + 1))
2837 rcTemp.right = infoPtr->rcList.right;
2838 else
2839 rcTemp.right+=WIDTH_PADDING;
2841 LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
2843 /* do indent */
2844 if (lvItem.iIndent>0 && infoPtr->iconSize.cx > 0)
2846 rcItem.left += infoPtr->iconSize.cx * lvItem.iIndent;
2848 if (SuggestedFocus)
2849 SuggestedFocus->left += infoPtr->iconSize.cx * lvItem.iIndent;
2852 /* state icons */
2853 if (infoPtr->himlState != NULL)
2855 UINT uStateImage = (lvItem.state & LVIS_STATEIMAGEMASK) >> 12;
2856 if (uStateImage > 0)
2858 ImageList_Draw(infoPtr->himlState, uStateImage - 1, hdc, rcItem.left,
2859 rcItem.top, ILD_NORMAL);
2862 rcItem.left += infoPtr->iconSize.cx;
2863 if (SuggestedFocus)
2864 SuggestedFocus->left += infoPtr->iconSize.cx;
2865 bImage = TRUE;
2868 /* small icons */
2869 if (infoPtr->himlSmall != NULL)
2871 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE) &&
2872 (lvItem.iImage>=0))
2874 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
2875 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
2876 rcItem.top, ILD_SELECTED);
2878 else if (lvItem.iImage>=0)
2880 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
2881 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
2882 rcItem.top, ILD_NORMAL);
2885 rcItem.left += infoPtr->iconSize.cx;
2887 if (SuggestedFocus)
2888 SuggestedFocus->left += infoPtr->iconSize.cx;
2889 bImage = TRUE;
2892 /* Don't bother painting item being edited */
2893 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED && !FullSelect)
2894 return;
2896 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
2898 /* set item colors */
2899 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
2900 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2901 /* set raster mode */
2902 nMixMode = SetROP2(hdc, R2_XORPEN);
2904 else if ((GetWindowLongA(hwnd, GWL_STYLE) & LVS_SHOWSELALWAYS) &&
2905 (lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus == FALSE))
2907 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
2908 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
2909 /* set raster mode */
2910 nMixMode = SetROP2(hdc, R2_COPYPEN);
2912 else
2914 /* set item colors */
2915 if ( (infoPtr->clrTextBk == CLR_DEFAULT) || (infoPtr->clrTextBk == CLR_NONE) )
2917 dwBkColor = GetBkColor(hdc);
2918 iBkMode = SetBkMode(hdc, TRANSPARENT);
2919 textoutOptions &= ~ETO_OPAQUE;
2921 else
2923 dwBkColor = SetBkColor(hdc, infoPtr->clrTextBk);
2924 iBkMode = SetBkMode(hdc, OPAQUE);
2927 dwTextColor = SetTextColor(hdc, infoPtr->clrText);
2928 /* set raster mode */
2929 nMixMode = SetROP2(hdc, R2_COPYPEN);
2932 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
2933 if (rcItem.left + nLabelWidth < rcItem.right)
2935 if (!FullSelect)
2936 rcItem.right = rcItem.left + nLabelWidth + TRAILING_PADDING;
2937 if (bImage)
2938 rcItem.right += IMAGE_PADDING;
2941 /* draw label */
2942 dwTextX = rcItem.left + 1;
2943 if (bImage)
2944 dwTextX += IMAGE_PADDING;
2946 if (lvItem.pszText)
2947 ExtTextOutA(hdc, dwTextX, rcItem.top, textoutOptions,
2948 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
2950 if ((FullSelect)&&(Header_GetItemCount(infoPtr->hwndHeader) > 1))
2952 /* fill in the gap */
2953 RECT rec;
2954 CopyRect(&rec,&rcItem);
2955 rec.left = rec.right;
2956 rec.right = rec.left+REPORT_MARGINX;
2957 ExtTextOutA(hdc, rec.left , rec.top, textoutOptions,
2958 &rec, NULL, 0, NULL);
2961 if (!FullSelect)
2962 CopyRect(SuggestedFocus,&rcItem);
2964 if (nMixMode != 0)
2966 SetROP2(hdc, R2_COPYPEN);
2967 SetBkColor(hdc, dwBkColor);
2968 SetTextColor(hdc, dwTextColor);
2969 if (iBkMode != -1)
2970 SetBkMode(hdc, iBkMode);
2974 /***
2975 * DESCRIPTION:
2976 * Draws an item when in large icon display mode.
2978 * PARAMETER(S):
2979 * [I] HWND : window handle
2980 * [I] HDC : device context handle
2981 * [I] LISTVIEW_ITEM * : item
2982 * [I] INT : item index
2983 * [I] RECT * : clipping rectangle
2985 * RETURN:
2986 * None
2988 static VOID LISTVIEW_DrawLargeItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem,
2989 RECT *SuggestedFocus)
2991 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2992 CHAR szDispText[DISP_TEXT_SIZE];
2993 INT nDrawPosX = rcItem.left;
2994 INT nLabelWidth, rcWidth;
2995 TEXTMETRICA tm;
2996 LVITEMA lvItem;
2997 UINT textoutOptions = ETO_CLIPPED | ETO_OPAQUE;
2998 RECT rcTemp;
3000 TRACE("(hwnd=%x, hdc=%x, nItem=%d, left=%d, top=%d, right=%d, \
3001 bottom=%d)\n", hwnd, hdc, nItem, rcItem.left, rcItem.top, rcItem.right,
3002 rcItem.bottom);
3004 /* get information needed for drawing the item */
3005 ZeroMemory(&lvItem, sizeof(LVITEMA));
3006 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
3007 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
3008 lvItem.iItem = nItem;
3009 lvItem.iSubItem = 0;
3010 lvItem.cchTextMax = DISP_TEXT_SIZE;
3011 lvItem.pszText = szDispText;
3012 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
3014 /* redraw the background of the item */
3015 rcTemp = rcItem;
3016 if(infoPtr->nColumnCount == (nItem + 1))
3017 rcTemp.right = infoPtr->rcList.right;
3018 else
3019 rcTemp.right+=WIDTH_PADDING;
3021 LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
3023 if (lvItem.state & LVIS_SELECTED)
3025 /* set item colors */
3026 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
3027 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
3028 /* set raster mode */
3029 SetROP2(hdc, R2_XORPEN);
3031 else
3033 /* set item colors */
3034 if ( (infoPtr->clrTextBk == CLR_DEFAULT) || (infoPtr->clrTextBk == CLR_NONE) )
3036 SetBkMode(hdc, TRANSPARENT);
3037 textoutOptions &= ~ETO_OPAQUE;
3039 else
3041 SetBkMode(hdc, OPAQUE);
3042 SetBkColor(hdc, infoPtr->clrTextBk);
3045 SetTextColor(hdc, infoPtr->clrText);
3046 /* set raster mode */
3047 SetROP2(hdc, R2_COPYPEN);
3050 if (infoPtr->himlNormal != NULL)
3052 rcItem.top += ICON_TOP_PADDING;
3053 nDrawPosX += (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
3054 if ((lvItem.state & LVIS_SELECTED) && (lvItem.iImage>=0))
3056 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
3057 rcItem.top, ILD_SELECTED);
3059 else if (lvItem.iImage>=0)
3061 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
3062 rcItem.top, ILD_NORMAL);
3066 /* Don't bother painting item being edited */
3067 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED)
3068 return;
3070 InflateRect(&rcItem, -(2*CAPTION_BORDER), 0);
3071 rcItem.top += infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
3072 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
3073 GetTextMetricsA(hdc, &tm);
3075 /* append an ellipse ('...') if the caption won't fit in the rect */
3076 rcWidth = max(0, rcItem.right - rcItem.left);
3077 if (nLabelWidth > rcWidth)
3079 INT i, len, eos, nCharsFit;
3080 /* give or take a couple, how many average sized chars would fit? */
3081 nCharsFit = tm.tmAveCharWidth > 0 ? (rcWidth/tm.tmAveCharWidth)+2 : 0;
3082 /* place the ellipse accordingly, without overrunning the buffer */
3083 len = strlen(szDispText);
3084 eos = min((nCharsFit > 1 && nCharsFit < len) ? nCharsFit+3 : len+2,
3085 sizeof(szDispText)-1);
3087 nLabelWidth = ListView_GetStringWidthA(hwnd, szDispText);
3088 while ((nLabelWidth > rcWidth) && (eos > 3))
3090 for (i = 1; i < 4; i++)
3091 szDispText[eos-i] = '.';
3092 /* shift the ellipse one char to the left for each iteration */
3093 szDispText[eos--] = '\0';
3094 nLabelWidth = ListView_GetStringWidthA(hwnd, szDispText);
3098 InflateRect(&rcItem, 2*CAPTION_BORDER, 0);
3099 nDrawPosX = infoPtr->iconSpacing.cx - 2*CAPTION_BORDER - nLabelWidth;
3100 if (nDrawPosX > 1)
3102 rcItem.left += nDrawPosX / 2;
3103 rcItem.right = rcItem.left + nLabelWidth + 2*CAPTION_BORDER;
3105 else
3107 rcItem.left += 1;
3108 rcItem.right = rcItem.left + infoPtr->iconSpacing.cx - 1;
3111 /* draw label */
3112 rcItem.bottom = rcItem.top + tm.tmHeight + HEIGHT_PADDING;
3114 ExtTextOutA(hdc, rcItem.left + CAPTION_BORDER, rcItem.top, textoutOptions,
3115 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
3118 CopyRect(SuggestedFocus,&rcItem);
3121 /***
3122 * DESCRIPTION:
3123 * Draws listview items when in report display mode.
3125 * PARAMETER(S):
3126 * [I] HWND : window handle
3127 * [I] HDC : device context handle
3129 * RETURN:
3130 * None
3132 static VOID LISTVIEW_RefreshReport(HWND hwnd, HDC hdc, DWORD cdmode)
3134 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
3135 SCROLLINFO scrollInfo;
3136 INT nDrawPosY = infoPtr->rcList.top;
3137 INT nColumnCount;
3138 RECT rcItem, rcTemp;
3139 INT j;
3140 INT nItem;
3141 INT nLast;
3142 BOOL FullSelected;
3143 DWORD cditemmode = CDRF_DODEFAULT;
3144 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3145 INT scrollOffset;
3147 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
3148 scrollInfo.cbSize = sizeof(SCROLLINFO);
3149 scrollInfo.fMask = SIF_POS;
3151 nItem = ListView_GetTopIndex(hwnd);
3153 /* add 1 for displaying a partial item at the bottom */
3154 nLast = nItem + LISTVIEW_GetCountPerColumn(hwnd) + 1;
3155 nLast = min(nLast, GETITEMCOUNT(infoPtr));
3157 /* send cache hint notification */
3158 if (GetWindowLongA(hwnd,GWL_STYLE) & LVS_OWNERDATA)
3160 NMLVCACHEHINT nmlv;
3162 nmlv.hdr.hwndFrom = hwnd;
3163 nmlv.hdr.idFrom = GetWindowLongA(hwnd,GWL_ID);
3164 nmlv.hdr.code = LVN_ODCACHEHINT;
3165 nmlv.iFrom = nItem;
3166 nmlv.iTo = nLast;
3168 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)nmlv.hdr.idFrom,
3169 (LPARAM)&nmlv);
3172 nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
3173 infoPtr->nColumnCount = nColumnCount; /* update nColumnCount */
3174 FullSelected = infoPtr->dwExStyle & LVS_EX_FULLROWSELECT;
3176 /* clear the background of any part of the control that doesn't contain items */
3177 SubtractRect(&rcTemp, &infoPtr->rcList, &infoPtr->rcView);
3178 LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
3180 /* nothing to draw */
3181 if(GETITEMCOUNT(infoPtr) == 0)
3182 return;
3184 /* Get scroll bar info once before loop */
3185 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
3186 scrollOffset = scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
3188 for (; nItem < nLast; nItem++)
3190 RECT SuggestedFocusRect;
3192 /* Do Owner Draw */
3193 if (lStyle & LVS_OWNERDRAWFIXED)
3195 UINT uID = GetWindowLongA( hwnd, GWL_ID);
3196 DRAWITEMSTRUCT dis;
3197 LVITEMA item;
3198 RECT br;
3200 TRACE("Owner Drawn\n");
3201 dis.CtlType = ODT_LISTVIEW;
3202 dis.CtlID = uID;
3203 dis.itemID = nItem;
3204 dis.itemAction = ODA_DRAWENTIRE;
3205 dis.itemState = 0;
3207 if (LISTVIEW_IsSelected(hwnd,nItem)) dis.itemState|=ODS_SELECTED;
3208 if (nItem==infoPtr->nFocusedItem) dis.itemState|=ODS_FOCUS;
3210 dis.hwndItem = hwnd;
3211 dis.hDC = hdc;
3213 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
3215 dis.rcItem.left = -scrollOffset;
3216 dis.rcItem.right = max(dis.rcItem.left, br.right - scrollOffset);
3217 dis.rcItem.top = nDrawPosY;
3218 dis.rcItem.bottom = dis.rcItem.top + infoPtr->nItemHeight;
3220 ZeroMemory(&item,sizeof(LVITEMA));
3221 item.iItem = nItem;
3222 item.mask = LVIF_PARAM;
3223 ListView_GetItemA(hwnd,&item);
3225 dis.itemData = item.lParam;
3227 if (SendMessageA(GetParent(hwnd),WM_DRAWITEM,(WPARAM)uID,(LPARAM)&dis))
3229 nDrawPosY += infoPtr->nItemHeight;
3230 continue;
3234 if (FullSelected)
3236 RECT ir,br;
3238 Header_GetItemRect(infoPtr->hwndHeader, 0, &ir);
3239 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
3241 ir.left += REPORT_MARGINX;
3242 ir.right = max(ir.left, br.right - REPORT_MARGINX);
3243 ir.top = nDrawPosY;
3244 ir.bottom = ir.top + infoPtr->nItemHeight;
3246 CopyRect(&SuggestedFocusRect,&ir);
3249 for (j = 0; j < nColumnCount; j++)
3251 if (cdmode & CDRF_NOTIFYITEMDRAW)
3252 cditemmode = LISTVIEW_SendCustomDrawItemNotify (hwnd, hdc, nItem, j,
3253 CDDS_ITEMPREPAINT);
3254 if (cditemmode & CDRF_SKIPDEFAULT)
3255 continue;
3257 Header_GetItemRect(infoPtr->hwndHeader, j, &rcItem);
3259 rcItem.left += REPORT_MARGINX;
3260 rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX);
3261 rcItem.top = nDrawPosY;
3262 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
3264 /* Offset the Scroll Bar Pos */
3265 rcItem.left -= scrollOffset;
3266 rcItem.right -= scrollOffset;
3268 if (j == 0)
3270 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem, FullSelected,
3271 &SuggestedFocusRect);
3273 else
3275 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, j, rcItem,
3276 FullSelected);
3279 if (cditemmode & CDRF_NOTIFYPOSTPAINT)
3280 LISTVIEW_SendCustomDrawItemNotify(hwnd, hdc, nItem, 0,
3281 CDDS_ITEMPOSTPAINT);
3284 * Draw Focus Rect
3286 if (LISTVIEW_GetItemState(hwnd,nItem,LVIS_FOCUSED) && infoPtr->bFocus)
3288 BOOL rop=FALSE;
3289 if (FullSelected && LISTVIEW_GetItemState(hwnd,nItem,LVIS_SELECTED))
3290 rop = SetROP2(hdc, R2_XORPEN);
3292 Rectangle(hdc, SuggestedFocusRect.left, SuggestedFocusRect.top,
3293 SuggestedFocusRect.right,SuggestedFocusRect.bottom);
3295 if (rop)
3296 SetROP2(hdc, R2_COPYPEN);
3298 nDrawPosY += infoPtr->nItemHeight;
3302 /***
3303 * DESCRIPTION:
3304 * Retrieves the number of items that can fit vertically in the client area.
3306 * PARAMETER(S):
3307 * [I] HWND : window handle
3309 * RETURN:
3310 * Number of items per row.
3312 static INT LISTVIEW_GetCountPerRow(HWND hwnd)
3314 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
3315 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3316 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
3317 INT nCountPerRow = 1;
3319 if (nListWidth > 0)
3321 if (uView == LVS_REPORT)
3323 nCountPerRow = 1;
3325 else
3327 nCountPerRow = nListWidth / infoPtr->nItemWidth;
3328 if (nCountPerRow == 0)
3330 nCountPerRow = 1;
3335 return nCountPerRow;
3338 /***
3339 * DESCRIPTION:
3340 * Retrieves the number of items that can fit horizontally in the client
3341 * area.
3343 * PARAMETER(S):
3344 * [I] HWND : window handle
3346 * RETURN:
3347 * Number of items per column.
3349 static INT LISTVIEW_GetCountPerColumn(HWND hwnd)
3351 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
3352 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
3353 INT nCountPerColumn = 1;
3355 if (nListHeight > 0)
3357 nCountPerColumn = nListHeight / infoPtr->nItemHeight;
3358 if (nCountPerColumn == 0)
3360 nCountPerColumn = 1;
3364 return nCountPerColumn;
3367 /***
3368 * DESCRIPTION:
3369 * Retrieves the number of columns needed to display all the items when in
3370 * list display mode.
3372 * PARAMETER(S):
3373 * [I] HWND : window handle
3375 * RETURN:
3376 * Number of columns.
3378 static INT LISTVIEW_GetColumnCount(HWND hwnd)
3380 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3381 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3382 INT nColumnCount = 0;
3384 if ((lStyle & LVS_TYPEMASK) == LVS_LIST)
3386 if (infoPtr->rcList.right % infoPtr->nItemWidth == 0)
3388 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth;
3390 else
3392 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth + 1;
3396 return nColumnCount;
3400 /***
3401 * DESCRIPTION:
3402 * Draws listview items when in list display mode.
3404 * PARAMETER(S):
3405 * [I] HWND : window handle
3406 * [I] HDC : device context handle
3408 * RETURN:
3409 * None
3411 static VOID LISTVIEW_RefreshList(HWND hwnd, HDC hdc, DWORD cdmode)
3413 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3414 RECT rcItem, FocusRect, rcTemp;
3415 INT i, j;
3416 INT nItem;
3417 INT nColumnCount;
3418 INT nCountPerColumn;
3419 INT nItemWidth = infoPtr->nItemWidth;
3420 INT nItemHeight = infoPtr->nItemHeight;
3421 DWORD cditemmode = CDRF_DODEFAULT;
3423 /* get number of fully visible columns */
3424 nColumnCount = LISTVIEW_GetColumnCount(hwnd);
3425 infoPtr->nColumnCount = nColumnCount;
3426 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
3427 nItem = ListView_GetTopIndex(hwnd);
3429 /* paint the background of the control that doesn't contain any items */
3430 SubtractRect(&rcTemp, &infoPtr->rcList, &infoPtr->rcView);
3431 LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
3433 /* nothing to draw, return here */
3434 if(GETITEMCOUNT(infoPtr) == 0)
3435 return;
3437 for (i = 0; i < nColumnCount; i++)
3439 for (j = 0; j < nCountPerColumn; j++, nItem++)
3441 if (nItem >= GETITEMCOUNT(infoPtr))
3442 return;
3444 if (cdmode & CDRF_NOTIFYITEMDRAW)
3445 cditemmode = LISTVIEW_SendCustomDrawItemNotify (hwnd, hdc, nItem, 0,
3446 CDDS_ITEMPREPAINT);
3447 if (cditemmode & CDRF_SKIPDEFAULT)
3448 continue;
3450 rcItem.top = j * nItemHeight;
3451 rcItem.left = i * nItemWidth;
3452 rcItem.bottom = rcItem.top + nItemHeight;
3453 rcItem.right = rcItem.left + nItemWidth;
3454 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem, FALSE, &FocusRect);
3456 * Draw Focus Rect
3458 if (LISTVIEW_GetItemState(hwnd,nItem,LVIS_FOCUSED) && infoPtr->bFocus)
3459 Rectangle(hdc, FocusRect.left, FocusRect.top,
3460 FocusRect.right,FocusRect.bottom);
3462 if (cditemmode & CDRF_NOTIFYPOSTPAINT)
3463 LISTVIEW_SendCustomDrawItemNotify(hwnd, hdc, nItem, 0,
3464 CDDS_ITEMPOSTPAINT);
3470 /***
3471 * DESCRIPTION:
3472 * Draws listview items when in icon or small icon display mode.
3474 * PARAMETER(S):
3475 * [I] HWND : window handle
3476 * [I] HDC : device context handle
3478 * RETURN:
3479 * None
3481 static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc, BOOL bSmall, DWORD cdmode)
3483 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3484 POINT ptPosition;
3485 POINT ptOrigin;
3486 RECT rcItem, SuggestedFocus, rcTemp;
3487 INT i;
3488 DWORD cditemmode = CDRF_DODEFAULT;
3490 infoPtr->nColumnCount = 1; /* set this to an arbitrary value to prevent */
3491 /* DrawItem from erasing the incorrect background area */
3493 /* paint the background of the control that doesn't contain any items */
3494 SubtractRect(&rcTemp, &infoPtr->rcList, &infoPtr->rcView);
3495 LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
3497 /* nothing to draw, return here */
3498 if(GETITEMCOUNT(infoPtr) == 0)
3499 return;
3501 LISTVIEW_GetOrigin(hwnd, &ptOrigin);
3502 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
3504 if (cdmode & CDRF_NOTIFYITEMDRAW)
3505 cditemmode = LISTVIEW_SendCustomDrawItemNotify (hwnd, hdc, i, 0,
3506 CDDS_ITEMPREPAINT);
3507 if (cditemmode & CDRF_SKIPDEFAULT)
3508 continue;
3510 LISTVIEW_GetItemPosition(hwnd, i, &ptPosition);
3511 ptPosition.x += ptOrigin.x;
3512 ptPosition.y += ptOrigin.y;
3514 if (ptPosition.y + infoPtr->nItemHeight > infoPtr->rcList.top)
3516 if (ptPosition.x + infoPtr->nItemWidth > infoPtr->rcList.left)
3518 if (ptPosition.y < infoPtr->rcList.bottom)
3520 if (ptPosition.x < infoPtr->rcList.right)
3522 rcItem.top = ptPosition.y;
3523 rcItem.left = ptPosition.x;
3524 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
3525 rcItem.right = rcItem.left + infoPtr->nItemWidth;
3526 if (bSmall == FALSE)
3528 LISTVIEW_DrawLargeItem(hwnd, hdc, i, rcItem, &SuggestedFocus);
3530 else
3532 LISTVIEW_DrawItem(hwnd, hdc, i, rcItem, FALSE, &SuggestedFocus);
3535 * Draw Focus Rect
3537 if (LISTVIEW_GetItemState(hwnd,i,LVIS_FOCUSED) &&
3538 infoPtr->bFocus)
3539 Rectangle(hdc, SuggestedFocus.left, SuggestedFocus.top,
3540 SuggestedFocus.right,SuggestedFocus.bottom);
3545 if (cditemmode & CDRF_NOTIFYPOSTPAINT)
3546 LISTVIEW_SendCustomDrawItemNotify(hwnd, hdc, i, 0,
3547 CDDS_ITEMPOSTPAINT);
3551 /***
3552 * DESCRIPTION:
3553 * Draws listview items.
3555 * PARAMETER(S):
3556 * [I] HWND : window handle
3557 * [I] HDC : device context handle
3559 * RETURN:
3560 * NoneX
3562 static VOID LISTVIEW_Refresh(HWND hwnd, HDC hdc)
3564 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3565 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3566 HFONT hOldFont;
3567 HPEN hPen, hOldPen;
3568 DWORD cdmode;
3569 RECT rect;
3571 GetClientRect(hwnd, &rect);
3572 cdmode = LISTVIEW_SendCustomDrawNotify(hwnd,CDDS_PREPAINT,hdc,rect);
3574 if (cdmode == CDRF_SKIPDEFAULT) return;
3576 /* select font */
3577 hOldFont = SelectObject(hdc, infoPtr->hFont);
3579 /* select the dotted pen (for drawing the focus box) */
3580 hPen = CreatePen(PS_ALTERNATE, 1, 0);
3581 hOldPen = SelectObject(hdc, hPen);
3583 /* select transparent brush (for drawing the focus box) */
3584 SelectObject(hdc, GetStockObject(NULL_BRUSH));
3586 if (uView == LVS_LIST)
3588 LISTVIEW_RefreshList(hwnd, hdc, cdmode);
3590 else if (uView == LVS_REPORT)
3592 LISTVIEW_RefreshReport(hwnd, hdc, cdmode);
3594 else if (uView == LVS_SMALLICON)
3596 LISTVIEW_RefreshIcon(hwnd, hdc, TRUE, cdmode);
3598 else if (uView == LVS_ICON)
3600 LISTVIEW_RefreshIcon(hwnd, hdc, FALSE, cdmode);
3603 /* unselect objects */
3604 SelectObject(hdc, hOldFont);
3605 SelectObject(hdc, hOldPen);
3607 /* delete pen */
3608 DeleteObject(hPen);
3610 if (cdmode & CDRF_NOTIFYPOSTPAINT)
3611 LISTVIEW_SendCustomDrawNotify(hwnd, CDDS_POSTPAINT, hdc, rect);
3615 /***
3616 * DESCRIPTION:
3617 * Calculates the approximate width and height of a given number of items.
3619 * PARAMETER(S):
3620 * [I] HWND : window handle
3621 * [I] INT : number of items
3622 * [I] INT : width
3623 * [I] INT : height
3625 * RETURN:
3626 * Returns a DWORD. The width in the low word and the height in high word.
3628 static LRESULT LISTVIEW_ApproximateViewRect(HWND hwnd, INT nItemCount,
3629 WORD wWidth, WORD wHeight)
3631 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3632 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3633 INT nItemCountPerColumn = 1;
3634 INT nColumnCount = 0;
3635 DWORD dwViewRect = 0;
3637 if (nItemCount == -1)
3639 nItemCount = GETITEMCOUNT(infoPtr);
3642 if (uView == LVS_LIST)
3644 if (wHeight == 0xFFFF)
3646 /* use current height */
3647 wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
3650 if (wHeight < infoPtr->nItemHeight)
3652 wHeight = infoPtr->nItemHeight;
3655 if (nItemCount > 0)
3657 if (infoPtr->nItemHeight > 0)
3659 nItemCountPerColumn = wHeight / infoPtr->nItemHeight;
3660 if (nItemCountPerColumn == 0)
3662 nItemCountPerColumn = 1;
3665 if (nItemCount % nItemCountPerColumn != 0)
3667 nColumnCount = nItemCount / nItemCountPerColumn;
3669 else
3671 nColumnCount = nItemCount / nItemCountPerColumn + 1;
3676 /* Microsoft padding magic */
3677 wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2;
3678 wWidth = nColumnCount * infoPtr->nItemWidth + 2;
3680 dwViewRect = MAKELONG(wWidth, wHeight);
3682 else if (uView == LVS_REPORT)
3684 /* TO DO */
3686 else if (uView == LVS_SMALLICON)
3688 /* TO DO */
3690 else if (uView == LVS_ICON)
3692 /* TO DO */
3695 return dwViewRect;
3698 /***
3699 * DESCRIPTION:
3700 * Arranges listview items in icon display mode.
3702 * PARAMETER(S):
3703 * [I] HWND : window handle
3704 * [I] INT : alignment code
3706 * RETURN:
3707 * SUCCESS : TRUE
3708 * FAILURE : FALSE
3710 static LRESULT LISTVIEW_Arrange(HWND hwnd, INT nAlignCode)
3712 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3713 BOOL bResult = FALSE;
3715 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
3717 switch (nAlignCode)
3719 case LVA_ALIGNLEFT:
3720 /* TO DO */
3721 break;
3722 case LVA_ALIGNTOP:
3723 /* TO DO */
3724 break;
3725 case LVA_DEFAULT:
3726 /* TO DO */
3727 break;
3728 case LVA_SNAPTOGRID:
3729 /* TO DO */
3730 break;
3734 return bResult;
3737 /* << LISTVIEW_CreateDragImage >> */
3740 /***
3741 * DESCRIPTION:
3742 * Removes all listview items and subitems.
3744 * PARAMETER(S):
3745 * [I] HWND : window handle
3747 * RETURN:
3748 * SUCCESS : TRUE
3749 * FAILURE : FALSE
3751 static LRESULT LISTVIEW_DeleteAllItems(HWND hwnd)
3753 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3754 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
3755 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3756 UINT uView = lStyle & LVS_TYPEMASK;
3757 LISTVIEW_ITEM *lpItem;
3758 LISTVIEW_SUBITEM *lpSubItem;
3759 NMLISTVIEW nmlv;
3760 BOOL bSuppress;
3761 BOOL bResult = FALSE;
3762 INT i;
3763 INT j;
3764 HDPA hdpaSubItems;
3766 TRACE("(hwnd=%x,)\n", hwnd);
3767 LISTVIEW_RemoveAllSelections(hwnd);
3769 if (lStyle & LVS_OWNERDATA)
3771 infoPtr->hdpaItems->nItemCount = 0;
3772 InvalidateRect(hwnd, NULL, TRUE);
3773 return TRUE;
3776 if (GETITEMCOUNT(infoPtr) > 0)
3778 /* initialize memory */
3779 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
3781 /* send LVN_DELETEALLITEMS notification */
3782 nmlv.hdr.hwndFrom = hwnd;
3783 nmlv.hdr.idFrom = lCtrlId;
3784 nmlv.hdr.code = LVN_DELETEALLITEMS;
3785 nmlv.iItem = -1;
3787 /* verify if subsequent LVN_DELETEITEM notifications should be
3788 suppressed */
3789 bSuppress = ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
3791 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
3793 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
3794 if (hdpaSubItems != NULL)
3796 for (j = 1; j < hdpaSubItems->nItemCount; j++)
3798 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, j);
3799 if (lpSubItem != NULL)
3801 /* free subitem string */
3802 if ((lpSubItem->pszText != NULL) &&
3803 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
3805 COMCTL32_Free(lpSubItem->pszText);
3808 /* free subitem */
3809 COMCTL32_Free(lpSubItem);
3813 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3814 if (lpItem != NULL)
3816 if (bSuppress == FALSE)
3818 /* send LVN_DELETEITEM notification */
3819 nmlv.hdr.code = LVN_DELETEITEM;
3820 nmlv.iItem = i;
3821 nmlv.lParam = lpItem->lParam;
3822 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
3825 /* free item string */
3826 if ((lpItem->pszText != NULL) &&
3827 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
3829 COMCTL32_Free(lpItem->pszText);
3832 /* free item */
3833 COMCTL32_Free(lpItem);
3836 DPA_Destroy(hdpaSubItems);
3840 /* reinitialize listview memory */
3841 bResult = DPA_DeleteAllPtrs(infoPtr->hdpaItems);
3843 /* align items (set position of each item) */
3844 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
3846 if (lStyle & LVS_ALIGNLEFT)
3848 LISTVIEW_AlignLeft(hwnd);
3850 else
3852 LISTVIEW_AlignTop(hwnd);
3856 LISTVIEW_UpdateScroll(hwnd);
3858 /* invalidate client area (optimization needed) */
3859 InvalidateRect(hwnd, NULL, TRUE);
3862 return bResult;
3865 /***
3866 * DESCRIPTION:
3867 * Removes a column from the listview control.
3869 * PARAMETER(S):
3870 * [I] HWND : window handle
3871 * [I] INT : column index
3873 * RETURN:
3874 * SUCCESS : TRUE
3875 * FAILURE : FALSE
3877 static LRESULT LISTVIEW_DeleteColumn(HWND hwnd, INT nColumn)
3879 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3880 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3881 UINT uOwnerData = GetWindowLongA(hwnd, GWL_STYLE) & LVS_OWNERDATA;
3882 BOOL bResult = FALSE;
3884 if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) != FALSE)
3886 if (!uOwnerData)
3887 bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
3889 /* Need to reset the item width when deleting a column */
3890 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
3892 /* reset scroll parameters */
3893 if (uView == LVS_REPORT)
3895 /* update scrollbar(s) */
3896 LISTVIEW_UpdateScroll(hwnd);
3898 /* refresh client area */
3899 InvalidateRect(hwnd, NULL, FALSE);
3903 return bResult;
3906 /***
3907 * DESCRIPTION:
3908 * Removes an item from the listview control.
3910 * PARAMETER(S):
3911 * [I] HWND : window handle
3912 * [I] INT : item index
3914 * RETURN:
3915 * SUCCESS : TRUE
3916 * FAILURE : FALSE
3918 static LRESULT LISTVIEW_DeleteItem(HWND hwnd, INT nItem)
3920 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3921 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3922 UINT uView = lStyle & LVS_TYPEMASK;
3923 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
3924 NMLISTVIEW nmlv;
3925 BOOL bResult = FALSE;
3926 HDPA hdpaSubItems;
3927 LISTVIEW_ITEM *lpItem;
3928 LISTVIEW_SUBITEM *lpSubItem;
3929 INT i;
3930 LVITEMA item;
3932 TRACE("(hwnd=%x,nItem=%d)\n", hwnd, nItem);
3934 /* remove it from the selection range */
3935 ZeroMemory(&item,sizeof(LVITEMA));
3936 item.stateMask = LVIS_SELECTED;
3937 LISTVIEW_SetItemState(hwnd,nItem,&item);
3939 LISTVIEW_ShiftSelections(hwnd,nItem,-1);
3941 if (lStyle & LVS_OWNERDATA)
3943 infoPtr->hdpaItems->nItemCount --;
3944 InvalidateRect(hwnd, NULL, TRUE);
3945 return TRUE;
3948 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
3950 /* initialize memory */
3951 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
3953 hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem);
3954 if (hdpaSubItems != NULL)
3956 for (i = 1; i < hdpaSubItems->nItemCount; i++)
3958 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
3959 if (lpSubItem != NULL)
3961 /* free item string */
3962 if ((lpSubItem->pszText != NULL) &&
3963 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
3965 COMCTL32_Free(lpSubItem->pszText);
3968 /* free item */
3969 COMCTL32_Free(lpSubItem);
3973 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3974 if (lpItem != NULL)
3976 /* send LVN_DELETEITEM notification */
3977 nmlv.hdr.hwndFrom = hwnd;
3978 nmlv.hdr.idFrom = lCtrlId;
3979 nmlv.hdr.code = LVN_DELETEITEM;
3980 nmlv.iItem = nItem;
3981 nmlv.lParam = lpItem->lParam;
3982 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId,
3983 (LPARAM)&nmlv);
3985 /* free item string */
3986 if ((lpItem->pszText != NULL) &&
3987 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
3989 COMCTL32_Free(lpItem->pszText);
3992 /* free item */
3993 COMCTL32_Free(lpItem);
3996 bResult = DPA_Destroy(hdpaSubItems);
3999 /* align items (set position of each item) */
4000 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4002 if (lStyle & LVS_ALIGNLEFT)
4004 LISTVIEW_AlignLeft(hwnd);
4006 else
4008 LISTVIEW_AlignTop(hwnd);
4012 /* If this item had focus change focus to next or previous item */
4013 if (GETITEMCOUNT(infoPtr) > 0)
4015 int sItem = nItem < GETITEMCOUNT(infoPtr) ? nItem : nItem - 1;
4016 if (infoPtr->nFocusedItem == nItem)
4017 LISTVIEW_SetItemFocus(hwnd, sItem);
4019 else
4020 infoPtr->nFocusedItem = -1;
4022 LISTVIEW_UpdateScroll(hwnd);
4024 /* refresh client area */
4025 InvalidateRect(hwnd, NULL, TRUE);
4028 return bResult;
4032 /***
4033 * DESCRIPTION:
4034 * Return edit control handle of current edit label
4036 * PARAMETER(S):
4037 * [I] HWND : window handle
4039 * RETURN:
4040 * SUCCESS : HWND
4041 * FAILURE : 0
4043 static LRESULT LISTVIEW_GetEditControl(HWND hwnd)
4045 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4046 return infoPtr->hwndEdit;
4050 /***
4051 * DESCRIPTION:
4052 * Callback implementation for editlabel control
4054 * PARAMETER(S):
4055 * [I] HWND : window handle
4056 * [I] LPSTR : modified text
4057 * [I] DWORD : item index
4059 * RETURN:
4060 * SUCCESS : TRUE
4061 * FAILURE : FALSE
4064 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem)
4066 NMLVDISPINFOA dispInfo;
4067 LISTVIEW_ITEM *lpItem;
4068 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
4069 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4070 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4071 HDPA hdpaSubItems;
4072 BOOL bUpdateItemText;
4073 LISTVIEW_ITEM lvItemRef;
4074 LVITEMA item;
4076 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
4078 if (!(lStyle & LVS_OWNERDATA))
4080 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
4081 return FALSE;
4083 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
4084 return FALSE;
4086 else
4088 ZeroMemory(&lvItemRef,sizeof(LISTVIEW_ITEM));
4089 ZeroMemory(&item,sizeof(LVITEMA));
4090 item.iItem = nItem;
4091 item.iSubItem = 0;
4092 item.mask = LVIF_PARAM | LVIF_STATE;
4093 ListView_GetItemA(hwnd,&item);
4094 lvItemRef.state = item.state;
4095 lvItemRef.iImage = item.iImage;
4096 lvItemRef.lParam = item.lParam;
4097 lpItem = &lvItemRef;
4100 dispInfo.hdr.hwndFrom = hwnd;
4101 dispInfo.hdr.idFrom = nCtrlId;
4102 dispInfo.hdr.code = LVN_ENDLABELEDITA;
4103 dispInfo.item.mask = 0;
4104 dispInfo.item.iItem = nItem;
4105 dispInfo.item.state = lpItem->state;
4106 dispInfo.item.stateMask = 0;
4107 dispInfo.item.pszText = pszText;
4108 dispInfo.item.cchTextMax = pszText ? strlen(pszText) : 0;
4109 dispInfo.item.iImage = lpItem->iImage;
4110 dispInfo.item.lParam = lpItem->lParam;
4111 infoPtr->hwndEdit = 0;
4113 bUpdateItemText = ListView_Notify(GetParent(hwnd), nCtrlId, &dispInfo);
4115 /* Do we need to update the Item Text */
4116 if(bUpdateItemText)
4118 if ((lpItem->pszText != LPSTR_TEXTCALLBACKA)&&(!(lStyle & LVS_OWNERDATA)))
4120 Str_SetPtrA(&lpItem->pszText, pszText);
4124 return TRUE;
4127 /***
4128 * DESCRIPTION:
4129 * Begin in place editing of specified list view item
4131 * PARAMETER(S):
4132 * [I] HWND : window handle
4133 * [I] INT : item index
4135 * RETURN:
4136 * SUCCESS : TRUE
4137 * FAILURE : FALSE
4140 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem)
4142 NMLVDISPINFOA dispInfo;
4143 RECT rect;
4144 LISTVIEW_ITEM *lpItem;
4145 HWND hedit;
4146 HINSTANCE hinst = GetWindowLongA(hwnd, GWL_HINSTANCE);
4147 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
4148 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4149 HDPA hdpaSubItems;
4150 CHAR szDispText[DISP_TEXT_SIZE];
4151 LVITEMA lvItem,item;
4152 LISTVIEW_ITEM lvItemRef;
4153 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4155 if (~GetWindowLongA(hwnd, GWL_STYLE) & LVS_EDITLABELS)
4156 return FALSE;
4158 /* Is the EditBox still there, if so remove it */
4159 if(infoPtr->hwndEdit != 0)
4161 SetFocus(hwnd);
4164 LISTVIEW_SetSelection(hwnd, nItem);
4165 LISTVIEW_SetItemFocus(hwnd, nItem);
4167 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
4168 if (!(lStyle & LVS_OWNERDATA))
4170 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
4171 return 0;
4173 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
4174 return 0;
4176 else
4178 ZeroMemory(&lvItemRef,sizeof(LISTVIEW_ITEM));
4179 ZeroMemory(&item,sizeof(LVITEMA));
4180 item.iItem = nItem;
4181 item.iSubItem = 0;
4182 item.mask = LVIF_PARAM | LVIF_STATE;
4183 ListView_GetItemA(hwnd,&item);
4184 lvItemRef.iImage = item.iImage;
4185 lvItemRef.state = item.state;
4186 lvItemRef.lParam = item.lParam;
4187 lpItem = &lvItemRef;
4190 /* get information needed for drawing the item */
4191 ZeroMemory(&lvItem, sizeof(LVITEMA));
4192 lvItem.mask = LVIF_TEXT;
4193 lvItem.iItem = nItem;
4194 lvItem.iSubItem = 0;
4195 lvItem.cchTextMax = DISP_TEXT_SIZE;
4196 lvItem.pszText = szDispText;
4197 ListView_GetItemA(hwnd, &lvItem);
4199 dispInfo.hdr.hwndFrom = hwnd;
4200 dispInfo.hdr.idFrom = nCtrlId;
4201 dispInfo.hdr.code = LVN_BEGINLABELEDITA;
4202 dispInfo.item.mask = 0;
4203 dispInfo.item.iItem = nItem;
4204 dispInfo.item.state = lpItem->state;
4205 dispInfo.item.stateMask = 0;
4206 dispInfo.item.pszText = lvItem.pszText;
4207 dispInfo.item.cchTextMax = strlen(lvItem.pszText);
4208 dispInfo.item.iImage = lpItem->iImage;
4209 dispInfo.item.lParam = lpItem->lParam;
4211 if (ListView_LVNotify(GetParent(hwnd), nCtrlId, &dispInfo))
4212 return 0;
4214 rect.left = LVIR_LABEL;
4215 if (!LISTVIEW_GetItemRect(hwnd, nItem, &rect))
4216 return 0;
4218 if (!(hedit = CreateEditLabel(szDispText , WS_VISIBLE,
4219 rect.left-2, rect.top-1, 0,
4220 rect.bottom - rect.top+2,
4221 hwnd, hinst, LISTVIEW_EndEditLabel, nItem)))
4222 return 0;
4224 infoPtr->hwndEdit = hedit;
4225 SetFocus(hedit);
4226 SendMessageA(hedit, EM_SETSEL, 0, -1);
4228 return hedit;
4232 /***
4233 * DESCRIPTION:
4234 * Ensures the specified item is visible, scrolling into view if necessary.
4236 * PARAMETER(S):
4237 * [I] HWND : window handle
4238 * [I] INT : item index
4239 * [I] BOOL : partially or entirely visible
4241 * RETURN:
4242 * SUCCESS : TRUE
4243 * FAILURE : FALSE
4245 static BOOL LISTVIEW_EnsureVisible(HWND hwnd, INT nItem, BOOL bPartial)
4247 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4248 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4249 INT nScrollPosHeight = 0;
4250 INT nScrollPosWidth = 0;
4251 SCROLLINFO scrollInfo;
4252 RECT rcItem;
4253 BOOL bRedraw = FALSE;
4255 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
4256 scrollInfo.cbSize = sizeof(SCROLLINFO);
4257 scrollInfo.fMask = SIF_POS;
4259 /* ALWAYS bPartial == FALSE, FOR NOW! */
4261 rcItem.left = LVIR_BOUNDS;
4262 if (LISTVIEW_GetItemRect(hwnd, nItem, &rcItem) != FALSE)
4264 if (rcItem.left < infoPtr->rcList.left)
4266 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4268 /* scroll left */
4269 bRedraw = TRUE;
4270 if (uView == LVS_LIST)
4272 nScrollPosWidth = infoPtr->nItemWidth;
4273 rcItem.left += infoPtr->rcList.left;
4275 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4277 nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
4278 rcItem.left += infoPtr->rcList.left;
4281 /* When in LVS_REPORT view, the scroll position should
4282 not be updated. */
4283 if (nScrollPosWidth != 0)
4285 if (rcItem.left % nScrollPosWidth == 0)
4287 scrollInfo.nPos += rcItem.left / nScrollPosWidth;
4289 else
4291 scrollInfo.nPos += rcItem.left / nScrollPosWidth - 1;
4294 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
4298 else if (rcItem.right > infoPtr->rcList.right)
4300 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4302 /* scroll right */
4303 bRedraw = TRUE;
4304 if (uView == LVS_LIST)
4306 rcItem.right -= infoPtr->rcList.right;
4307 nScrollPosWidth = infoPtr->nItemWidth;
4309 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4311 rcItem.right -= infoPtr->rcList.right;
4312 nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
4315 /* When in LVS_REPORT view, the scroll position should
4316 not be updated. */
4317 if (nScrollPosWidth != 0)
4319 if (rcItem.right % nScrollPosWidth == 0)
4321 scrollInfo.nPos += rcItem.right / nScrollPosWidth;
4323 else
4325 scrollInfo.nPos += rcItem.right / nScrollPosWidth + 1;
4328 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
4333 if (rcItem.top < infoPtr->rcList.top)
4335 /* scroll up */
4336 bRedraw = TRUE;
4337 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4339 if (uView == LVS_REPORT)
4341 rcItem.top -= infoPtr->rcList.top;
4342 nScrollPosHeight = infoPtr->nItemHeight;
4344 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
4346 nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
4347 rcItem.top += infoPtr->rcList.top;
4350 if (rcItem.top % nScrollPosHeight == 0)
4352 scrollInfo.nPos += rcItem.top / nScrollPosHeight;
4354 else
4356 scrollInfo.nPos += rcItem.top / nScrollPosHeight - 1;
4359 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
4362 else if (rcItem.bottom > infoPtr->rcList.bottom)
4364 /* scroll down */
4365 bRedraw = TRUE;
4366 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4368 if (uView == LVS_REPORT)
4370 rcItem.bottom -= infoPtr->rcList.bottom;
4371 nScrollPosHeight = infoPtr->nItemHeight;
4373 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
4375 nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
4376 rcItem.bottom -= infoPtr->rcList.bottom;
4379 if (rcItem.bottom % nScrollPosHeight == 0)
4381 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight;
4383 else
4385 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight + 1;
4388 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
4393 if(bRedraw)
4394 InvalidateRect(hwnd,NULL,TRUE);
4395 return TRUE;
4398 /***
4399 * DESCRIPTION:
4400 * Retrieves the nearest item, given a position and a direction.
4402 * PARAMETER(S):
4403 * [I] HWND : window handle
4404 * [I] POINT : start position
4405 * [I] UINT : direction
4407 * RETURN:
4408 * Item index if successdful, -1 otherwise.
4410 static INT LISTVIEW_GetNearestItem(HWND hwnd, POINT pt, UINT vkDirection)
4412 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4413 LVHITTESTINFO lvHitTestInfo;
4414 INT nItem = -1;
4415 RECT rcView;
4417 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
4419 ZeroMemory(&lvHitTestInfo, sizeof(LVHITTESTINFO));
4420 LISTVIEW_GetOrigin(hwnd, &lvHitTestInfo.pt);
4421 lvHitTestInfo.pt.x += pt.x;
4422 lvHitTestInfo.pt.y += pt.y;
4426 if (vkDirection == VK_DOWN)
4428 lvHitTestInfo.pt.y += infoPtr->nItemHeight;
4430 else if (vkDirection == VK_UP)
4432 lvHitTestInfo.pt.y -= infoPtr->nItemHeight;
4434 else if (vkDirection == VK_LEFT)
4436 lvHitTestInfo.pt.x -= infoPtr->nItemWidth;
4438 else if (vkDirection == VK_RIGHT)
4440 lvHitTestInfo.pt.x += infoPtr->nItemWidth;
4443 if (PtInRect(&rcView, lvHitTestInfo.pt) == FALSE)
4445 return -1;
4447 else
4449 nItem = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo, TRUE);
4453 while (nItem == -1);
4456 return nItem;
4459 /***
4460 * DESCRIPTION:
4461 * Searches for an item with specific characteristics.
4463 * PARAMETER(S):
4464 * [I] HWND : window handle
4465 * [I] INT : base item index
4466 * [I] LPLVFINDINFO : item information to look for
4468 * RETURN:
4469 * SUCCESS : index of item
4470 * FAILURE : -1
4472 static LRESULT LISTVIEW_FindItem(HWND hwnd, INT nStart,
4473 LPLVFINDINFO lpFindInfo)
4475 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4476 POINT ptItem;
4477 CHAR szDispText[DISP_TEXT_SIZE];
4478 LVITEMA lvItem;
4479 BOOL bWrap = FALSE;
4480 INT nItem = nStart;
4481 INT nLast = GETITEMCOUNT(infoPtr);
4483 if ((nItem >= -1) && (lpFindInfo != NULL))
4485 ZeroMemory(&lvItem, sizeof(LVITEMA));
4487 if (lpFindInfo->flags & LVFI_PARAM)
4489 lvItem.mask |= LVIF_PARAM;
4492 if (lpFindInfo->flags & LVFI_STRING)
4494 lvItem.mask |= LVIF_TEXT;
4495 lvItem.pszText = szDispText;
4496 lvItem.cchTextMax = DISP_TEXT_SIZE;
4499 if (lpFindInfo->flags & LVFI_PARTIAL)
4501 lvItem.mask |= LVIF_TEXT;
4502 lvItem.pszText = szDispText;
4503 lvItem.cchTextMax = DISP_TEXT_SIZE;
4506 if (lpFindInfo->flags & LVFI_WRAP)
4508 bWrap = TRUE;
4511 if (lpFindInfo->flags & LVFI_NEARESTXY)
4513 ptItem.x = lpFindInfo->pt.x;
4514 ptItem.y = lpFindInfo->pt.y;
4517 while (1)
4519 while (nItem < nLast)
4521 if (lpFindInfo->flags & LVFI_NEARESTXY)
4523 nItem = LISTVIEW_GetNearestItem(hwnd, ptItem,
4524 lpFindInfo->vkDirection);
4525 if (nItem != -1)
4527 /* get position of the new item index */
4528 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) == FALSE)
4529 return -1;
4531 else
4532 return -1;
4534 else
4536 nItem++;
4539 lvItem.iItem = nItem;
4540 lvItem.iSubItem = 0;
4541 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
4543 if (lvItem.mask & LVIF_TEXT)
4545 if (lpFindInfo->flags & LVFI_PARTIAL)
4547 if (strstr(lvItem.pszText, lpFindInfo->psz) == NULL)
4548 continue;
4550 else
4552 if (strcmp(lvItem.pszText, lpFindInfo->psz) != 0)
4553 continue;
4557 if (lvItem.mask & LVIF_PARAM)
4559 if (lpFindInfo->lParam != lvItem.lParam)
4560 continue;
4563 return nItem;
4567 if (bWrap != FALSE)
4569 nItem = -1;
4570 nLast = nStart + 1;
4571 bWrap = FALSE;
4573 else
4575 return -1;
4580 return -1;
4583 /***
4584 * DESCRIPTION:
4585 * Retrieves the background color of the listview control.
4587 * PARAMETER(S):
4588 * [I] HWND : window handle
4590 * RETURN:
4591 * COLORREF associated with the background.
4593 static LRESULT LISTVIEW_GetBkColor(HWND hwnd)
4595 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4597 return infoPtr->clrBk;
4600 /***
4601 * DESCRIPTION:
4602 * Retrieves the background image of the listview control.
4604 * PARAMETER(S):
4605 * [I] HWND : window handle
4606 * [O] LPLVMKBIMAGE : background image attributes
4608 * RETURN:
4609 * SUCCESS : TRUE
4610 * FAILURE : FALSE
4612 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
4613 /* { */
4614 /* FIXME (listview, "empty stub!\n"); */
4615 /* return FALSE; */
4616 /* } */
4618 /***
4619 * DESCRIPTION:
4620 * Retrieves the callback mask.
4622 * PARAMETER(S):
4623 * [I] HWND : window handle
4625 * RETURN:
4626 * Value of mask
4628 static UINT LISTVIEW_GetCallbackMask(HWND hwnd)
4630 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4632 return infoPtr->uCallbackMask;
4635 /***
4636 * DESCRIPTION:
4637 * Retrieves column attributes.
4639 * PARAMETER(S):
4640 * [I] HWND : window handle
4641 * [I] INT : column index
4642 * [IO] LPLVCOLUMNA : column information
4644 * RETURN:
4645 * SUCCESS : TRUE
4646 * FAILURE : FALSE
4648 static LRESULT LISTVIEW_GetColumnA(HWND hwnd, INT nItem, LPLVCOLUMNA lpColumn)
4650 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4651 HDITEMA hdi;
4652 BOOL bResult = FALSE;
4654 if (lpColumn != NULL)
4656 /* initialize memory */
4657 ZeroMemory(&hdi, sizeof(HDITEMA));
4659 if (lpColumn->mask & LVCF_FMT)
4661 hdi.mask |= HDI_FORMAT;
4664 if (lpColumn->mask & LVCF_WIDTH)
4666 hdi.mask |= HDI_WIDTH;
4669 if (lpColumn->mask & LVCF_TEXT)
4671 hdi.mask |= HDI_TEXT;
4672 hdi.cchTextMax = lpColumn->cchTextMax;
4673 hdi.pszText = lpColumn->pszText;
4676 if (lpColumn->mask & LVCF_IMAGE)
4678 hdi.mask |= HDI_IMAGE;
4681 if (lpColumn->mask & LVCF_ORDER)
4683 hdi.mask |= HDI_ORDER;
4686 bResult = Header_GetItemA(infoPtr->hwndHeader, nItem, &hdi);
4687 if (bResult != FALSE)
4689 if (lpColumn->mask & LVCF_FMT)
4691 lpColumn->fmt = 0;
4693 if (hdi.fmt & HDF_LEFT)
4695 lpColumn->fmt |= LVCFMT_LEFT;
4697 else if (hdi.fmt & HDF_RIGHT)
4699 lpColumn->fmt |= LVCFMT_RIGHT;
4701 else if (hdi.fmt & HDF_CENTER)
4703 lpColumn->fmt |= LVCFMT_CENTER;
4706 if (hdi.fmt & HDF_IMAGE)
4708 lpColumn->fmt |= LVCFMT_COL_HAS_IMAGES;
4711 if (hdi.fmt & HDF_BITMAP_ON_RIGHT)
4713 lpColumn->fmt |= LVCFMT_BITMAP_ON_RIGHT;
4717 if (lpColumn->mask & LVCF_WIDTH)
4719 lpColumn->cx = hdi.cxy;
4722 if (lpColumn->mask & LVCF_IMAGE)
4724 lpColumn->iImage = hdi.iImage;
4727 if (lpColumn->mask & LVCF_ORDER)
4729 lpColumn->iOrder = hdi.iOrder;
4734 return bResult;
4737 /* LISTVIEW_GetColumnW */
4740 static LRESULT LISTVIEW_GetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
4742 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
4743 INT i;
4745 if (!lpiArray)
4746 return FALSE;
4748 /* little hack */
4749 for (i = 0; i < iCount; i++)
4750 lpiArray[i] = i;
4752 return TRUE;
4755 /***
4756 * DESCRIPTION:
4757 * Retrieves the column width.
4759 * PARAMETER(S):
4760 * [I] HWND : window handle
4761 * [I] int : column index
4763 * RETURN:
4764 * SUCCESS : column width
4765 * FAILURE : zero
4767 static LRESULT LISTVIEW_GetColumnWidth(HWND hwnd, INT nColumn)
4769 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4770 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4771 INT nColumnWidth = 0;
4772 HDITEMA hdi;
4774 if (uView == LVS_LIST)
4776 nColumnWidth = infoPtr->nItemWidth;
4778 else if (uView == LVS_REPORT)
4780 /* get column width from header */
4781 ZeroMemory(&hdi, sizeof(HDITEMA));
4782 hdi.mask = HDI_WIDTH;
4783 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdi) != FALSE)
4785 nColumnWidth = hdi.cxy;
4789 return nColumnWidth;
4792 /***
4793 * DESCRIPTION:
4794 * In list or report display mode, retrieves the number of items that can fit
4795 * vertically in the visible area. In icon or small icon display mode,
4796 * retrieves the total number of visible items.
4798 * PARAMETER(S):
4799 * [I] HWND : window handle
4801 * RETURN:
4802 * Number of fully visible items.
4804 static LRESULT LISTVIEW_GetCountPerPage(HWND hwnd)
4806 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4807 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4808 INT nItemCount = 0;
4810 if (uView == LVS_LIST)
4812 if (infoPtr->rcList.right > infoPtr->nItemWidth)
4814 nItemCount = LISTVIEW_GetCountPerRow(hwnd) *
4815 LISTVIEW_GetCountPerColumn(hwnd);
4818 else if (uView == LVS_REPORT)
4820 nItemCount = LISTVIEW_GetCountPerColumn(hwnd);
4822 else
4824 nItemCount = GETITEMCOUNT(infoPtr);
4827 return nItemCount;
4830 /* LISTVIEW_GetEditControl */
4832 /***
4833 * DESCRIPTION:
4834 * Retrieves the extended listview style.
4836 * PARAMETERS:
4837 * [I] HWND : window handle
4839 * RETURN:
4840 * SUCCESS : previous style
4841 * FAILURE : 0
4843 static LRESULT LISTVIEW_GetExtendedListViewStyle(HWND hwnd)
4845 LISTVIEW_INFO *infoPtr;
4847 /* make sure we can get the listview info */
4848 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
4849 return (0);
4851 return (infoPtr->dwExStyle);
4854 /***
4855 * DESCRIPTION:
4856 * Retrieves the handle to the header control.
4858 * PARAMETER(S):
4859 * [I] HWND : window handle
4861 * RETURN:
4862 * Header handle.
4864 static LRESULT LISTVIEW_GetHeader(HWND hwnd)
4866 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4868 return infoPtr->hwndHeader;
4871 /* LISTVIEW_GetHotCursor */
4873 /***
4874 * DESCRIPTION:
4875 * Returns the time that the mouse cursor must hover over an item
4876 * before it is selected.
4878 * PARAMETER(S):
4879 * [I] HWND : window handle
4881 * RETURN:
4882 * Returns the previously set hover time or (DWORD)-1 to indicate that the
4883 * hover time is set to the default hover time.
4885 static LRESULT LISTVIEW_GetHoverTime(HWND hwnd)
4887 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4889 return infoPtr->dwHoverTime;
4892 /***
4893 * DESCRIPTION:
4894 * Retrieves an image list handle.
4896 * PARAMETER(S):
4897 * [I] HWND : window handle
4898 * [I] INT : image list identifier
4900 * RETURN:
4901 * SUCCESS : image list handle
4902 * FAILURE : NULL
4904 static LRESULT LISTVIEW_GetImageList(HWND hwnd, INT nImageList)
4906 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4907 HIMAGELIST himl = NULL;
4909 switch (nImageList)
4911 case LVSIL_NORMAL:
4912 himl = infoPtr->himlNormal;
4913 break;
4914 case LVSIL_SMALL:
4915 himl = infoPtr->himlSmall;
4916 break;
4917 case LVSIL_STATE:
4918 himl = infoPtr->himlState;
4919 break;
4922 return (LRESULT)himl;
4925 /* LISTVIEW_GetISearchString */
4927 /***
4928 * DESCRIPTION:
4929 * Retrieves item attributes.
4931 * PARAMETER(S):
4932 * [I] HWND : window handle
4933 * [IO] LPLVITEMA : item info
4934 * [I] internal : if true then we will use tricks that avoid copies
4935 * but are not compatible with the regular interface
4937 * RETURN:
4938 * SUCCESS : TRUE
4939 * FAILURE : FALSE
4941 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem, BOOL internal)
4943 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4944 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
4945 NMLVDISPINFOA dispInfo;
4946 LISTVIEW_SUBITEM *lpSubItem;
4947 LISTVIEW_ITEM *lpItem;
4948 INT* piImage;
4949 LPSTR* ppszText;
4950 HDPA hdpaSubItems;
4951 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4952 /* In the following:
4953 * lpLVItem describes the information requested by the user
4954 * lpItem/lpSubItem is what we have
4955 * dispInfo is a structure we use to request the missing
4956 * information from the application
4959 TRACE("(hwnd=%x, lpLVItem=%p)\n", hwnd, lpLVItem);
4961 if ((lpLVItem == NULL) ||
4962 (lpLVItem->iItem < 0) ||
4963 (lpLVItem->iItem >= GETITEMCOUNT(infoPtr))
4965 return FALSE;
4967 if (lStyle & LVS_OWNERDATA)
4969 if (lpLVItem->mask & ~LVIF_STATE)
4971 dispInfo.hdr.hwndFrom = hwnd;
4972 dispInfo.hdr.idFrom = lCtrlId;
4973 dispInfo.hdr.code = LVN_GETDISPINFOA;
4974 memcpy(&dispInfo.item,lpLVItem,sizeof(LVITEMA));
4976 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
4977 memcpy(lpLVItem,&dispInfo.item,sizeof(LVITEMA));
4980 if ((lpLVItem->mask & LVIF_STATE)&&(lpLVItem->iSubItem == 0))
4982 lpLVItem->state = 0;
4983 if (infoPtr->nFocusedItem == lpLVItem->iItem)
4984 lpLVItem->state |= LVIS_FOCUSED;
4985 if (LISTVIEW_IsSelected(hwnd,lpLVItem->iItem))
4986 lpLVItem->state |= LVIS_SELECTED;
4989 return TRUE;
4993 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
4994 if (hdpaSubItems == NULL)
4995 return FALSE;
4997 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
4998 if (lpItem == NULL)
4999 return FALSE;
5001 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
5002 if (lpLVItem->iSubItem == 0)
5004 piImage=&lpItem->iImage;
5005 ppszText=&lpItem->pszText;
5006 if ((infoPtr->uCallbackMask != 0) && (lpLVItem->mask & LVIF_STATE))
5008 dispInfo.item.mask |= LVIF_STATE;
5009 dispInfo.item.stateMask = infoPtr->uCallbackMask;
5012 else
5014 lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem);
5015 if (lpSubItem != NULL)
5017 piImage=&lpSubItem->iImage;
5018 ppszText=&lpSubItem->pszText;
5020 else
5022 piImage=NULL;
5023 ppszText=NULL;
5027 if ((lpLVItem->mask & LVIF_IMAGE) &&
5028 ((piImage==NULL) || (*piImage == I_IMAGECALLBACK)))
5030 dispInfo.item.mask |= LVIF_IMAGE;
5033 if ((lpLVItem->mask & LVIF_TEXT) &&
5034 ((ppszText==NULL) || (*ppszText == LPSTR_TEXTCALLBACKA)))
5036 dispInfo.item.mask |= LVIF_TEXT;
5037 dispInfo.item.pszText = lpLVItem->pszText;
5038 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
5041 if (dispInfo.item.mask != 0)
5043 /* We don't have all the requested info, query the application */
5044 dispInfo.hdr.hwndFrom = hwnd;
5045 dispInfo.hdr.idFrom = lCtrlId;
5046 dispInfo.hdr.code = LVN_GETDISPINFOA;
5047 dispInfo.item.iItem = lpLVItem->iItem;
5048 dispInfo.item.iSubItem = lpLVItem->iSubItem;
5049 dispInfo.item.lParam = lpItem->lParam;
5050 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
5053 if (dispInfo.item.mask & LVIF_IMAGE)
5055 lpLVItem->iImage = dispInfo.item.iImage;
5057 else if (lpLVItem->mask & LVIF_IMAGE)
5059 lpLVItem->iImage = *piImage;
5062 if (dispInfo.item.mask & LVIF_PARAM)
5064 lpLVItem->lParam = dispInfo.item.lParam;
5066 else if (lpLVItem->mask & LVIF_PARAM)
5068 lpLVItem->lParam = lpItem->lParam;
5071 if (dispInfo.item.mask & LVIF_TEXT)
5073 if ((dispInfo.item.mask & LVIF_DI_SETITEM) && (ppszText != NULL))
5075 Str_SetPtrA(ppszText, dispInfo.item.pszText);
5077 /* If lpLVItem->pszText==dispInfo.item.pszText a copy is unnecessary, but */
5078 /* some apps give a new pointer in ListView_Notify so we can't be sure. */
5079 if (lpLVItem->pszText!=dispInfo.item.pszText) {
5080 lstrcpynA(lpLVItem->pszText, dispInfo.item.pszText, lpLVItem->cchTextMax);
5083 else if (lpLVItem->mask & LVIF_TEXT)
5085 if (internal==TRUE)
5087 lpLVItem->pszText=*ppszText;
5088 } else {
5089 lstrcpynA(lpLVItem->pszText, *ppszText, lpLVItem->cchTextMax);
5093 if (lpLVItem->iSubItem == 0)
5095 if (dispInfo.item.mask & LVIF_STATE)
5097 lpLVItem->state = lpItem->state;
5098 lpLVItem->state &= ~dispInfo.item.stateMask;
5099 lpLVItem->state |= (dispInfo.item.state & dispInfo.item.stateMask);
5101 lpLVItem->state &= ~LVIS_SELECTED;
5102 if ((dispInfo.item.stateMask & LVIS_SELECTED) &&
5103 (LISTVIEW_IsSelected(hwnd,dispInfo.item.iItem)))
5104 lpLVItem->state |= LVIS_SELECTED;
5106 else if (lpLVItem->mask & LVIF_STATE)
5108 lpLVItem->state = lpItem->state & lpLVItem->stateMask;
5110 lpLVItem->state &= ~LVIS_SELECTED;
5111 if ((lpLVItem->stateMask & LVIS_SELECTED) &&
5112 (LISTVIEW_IsSelected(hwnd,lpLVItem->iItem)))
5113 lpLVItem->state |= LVIS_SELECTED;
5116 if (lpLVItem->mask & LVIF_PARAM)
5118 lpLVItem->lParam = lpItem->lParam;
5121 if (lpLVItem->mask & LVIF_INDENT)
5123 lpLVItem->iIndent = lpItem->iIndent;
5127 return TRUE;
5130 /* LISTVIEW_GetItemW */
5131 /* LISTVIEW_GetHotCursor */
5133 /***
5134 * DESCRIPTION:
5135 * Retrieves the index of the hot item.
5137 * PARAMETERS:
5138 * [I] HWND : window handle
5140 * RETURN:
5141 * SUCCESS : hot item index
5142 * FAILURE : -1 (no hot item)
5144 static LRESULT LISTVIEW_GetHotItem(HWND hwnd)
5146 LISTVIEW_INFO *infoPtr;
5148 /* make sure we can get the listview info */
5149 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5150 return (-1);
5152 return (infoPtr->nHotItem);
5155 /* LISTVIEW_GetHoverTime */
5157 /***
5158 * DESCRIPTION:
5159 * Retrieves the number of items in the listview control.
5161 * PARAMETER(S):
5162 * [I] HWND : window handle
5164 * RETURN:
5165 * Number of items.
5167 static LRESULT LISTVIEW_GetItemCount(HWND hwnd)
5169 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5171 return GETITEMCOUNT(infoPtr);
5174 /***
5175 * DESCRIPTION:
5176 * Retrieves the position (upper-left) of the listview control item.
5178 * PARAMETER(S):
5179 * [I] HWND : window handle
5180 * [I] INT : item index
5181 * [O] LPPOINT : coordinate information
5183 * RETURN:
5184 * SUCCESS : TRUE
5185 * FAILURE : FALSE
5187 static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem,
5188 LPPOINT lpptPosition)
5190 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5191 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5192 BOOL bResult = FALSE;
5193 HDPA hdpaSubItems;
5194 LISTVIEW_ITEM *lpItem;
5195 INT nCountPerColumn;
5196 INT nRow;
5198 TRACE("(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd, nItem,
5199 lpptPosition);
5201 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
5202 (lpptPosition != NULL))
5204 if (uView == LVS_LIST)
5206 bResult = TRUE;
5207 nItem = nItem - ListView_GetTopIndex(hwnd);
5208 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
5209 if (nItem < 0)
5211 nRow = nItem % nCountPerColumn;
5212 if (nRow == 0)
5214 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
5215 lpptPosition->y = 0;
5217 else
5219 lpptPosition->x = (nItem / nCountPerColumn -1) * infoPtr->nItemWidth;
5220 lpptPosition->y = (nRow + nCountPerColumn) * infoPtr->nItemHeight;
5223 else
5225 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
5226 lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight;
5229 else if (uView == LVS_REPORT)
5231 SCROLLINFO scrollInfo;
5232 bResult = TRUE;
5233 lpptPosition->x = REPORT_MARGINX;
5234 lpptPosition->y = ((nItem - ListView_GetTopIndex(hwnd)) *
5235 infoPtr->nItemHeight) + infoPtr->rcList.top;
5237 /* Adjust position by scrollbar offset */
5238 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
5239 scrollInfo.cbSize = sizeof(SCROLLINFO);
5240 scrollInfo.fMask = SIF_POS;
5241 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
5242 lpptPosition->x -= scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
5244 else
5246 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
5247 if (hdpaSubItems != NULL)
5249 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
5250 if (lpItem != NULL)
5252 bResult = TRUE;
5253 lpptPosition->x = lpItem->ptPosition.x;
5254 lpptPosition->y = lpItem->ptPosition.y;
5259 return bResult;
5262 /***
5263 * DESCRIPTION:
5264 * Retrieves the bounding rectangle for a listview control item.
5266 * PARAMETER(S):
5267 * [I] HWND : window handle
5268 * [I] INT : item index
5269 * [IO] LPRECT : bounding rectangle coordinates
5270 * lprc->left specifies the portion of the item for which the bounding
5271 * rectangle will be retrieved.
5273 * LVIR_BOUNDS Returns the bounding rectangle of the entire item,
5274 * including the icon and label.
5275 * LVIR_ICON Returns the bounding rectangle of the icon or small icon.
5276 * LVIR_LABEL Returns the bounding rectangle of the item text.
5277 * LVIR_SELECTBOUNDS Returns the union of the LVIR_ICON and LVIR_LABEL
5278 * rectangles, but excludes columns in report view.
5280 * RETURN:
5281 * SUCCESS : TRUE
5282 * FAILURE : FALSE
5284 static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc)
5286 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5287 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5288 BOOL bResult = FALSE;
5289 POINT ptOrigin;
5290 POINT ptItem;
5291 HDC hdc;
5292 HFONT hOldFont;
5293 INT nLeftPos;
5294 INT nLabelWidth;
5295 INT nIndent;
5296 TEXTMETRICA tm;
5297 LVITEMA lvItem;
5299 TRACE("(hwnd=%x, nItem=%d, lprc=%p)\n", hwnd, nItem, lprc);
5301 if (uView & LVS_REPORT)
5303 ZeroMemory(&lvItem, sizeof(LVITEMA));
5304 lvItem.mask = LVIF_INDENT;
5305 lvItem.iItem = nItem;
5306 lvItem.iSubItem = 0;
5307 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
5309 /* do indent */
5310 if (lvItem.iIndent>0 && infoPtr->iconSize.cx > 0)
5312 nIndent = infoPtr->iconSize.cx * lvItem.iIndent;
5314 else
5315 nIndent = 0;
5317 else
5318 nIndent = 0;
5320 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL))
5322 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) != FALSE)
5324 switch(lprc->left)
5326 case LVIR_ICON:
5327 if (uView == LVS_ICON)
5329 if (infoPtr->himlNormal != NULL)
5331 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5333 bResult = TRUE;
5334 lprc->left = ptItem.x + ptOrigin.x;
5335 lprc->top = ptItem.y + ptOrigin.y;
5336 lprc->right = lprc->left + infoPtr->iconSize.cx;
5337 lprc->bottom = (lprc->top + infoPtr->iconSize.cy +
5338 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
5342 else if (uView == LVS_SMALLICON)
5344 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5346 bResult = TRUE;
5347 lprc->left = ptItem.x + ptOrigin.x;
5348 lprc->top = ptItem.y + ptOrigin.y;
5349 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5351 if (infoPtr->himlState != NULL)
5352 lprc->left += infoPtr->iconSize.cx;
5354 if (infoPtr->himlSmall != NULL)
5355 lprc->right = lprc->left + infoPtr->iconSize.cx;
5356 else
5357 lprc->right = lprc->left;
5360 else
5362 bResult = TRUE;
5363 lprc->left = ptItem.x;
5364 if (uView & LVS_REPORT)
5365 lprc->left += nIndent;
5366 lprc->top = ptItem.y;
5367 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5369 if (infoPtr->himlState != NULL)
5371 lprc->left += infoPtr->iconSize.cx;
5374 if (infoPtr->himlSmall != NULL)
5376 lprc->right = lprc->left + infoPtr->iconSize.cx;
5378 else
5380 lprc->right = lprc->left;
5383 break;
5385 case LVIR_LABEL:
5386 if (uView == LVS_ICON)
5388 if (infoPtr->himlNormal != NULL)
5390 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5392 bResult = TRUE;
5393 lprc->left = ptItem.x + ptOrigin.x;
5394 lprc->top = (ptItem.y + ptOrigin.y + infoPtr->iconSize.cy +
5395 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
5396 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5397 if (infoPtr->iconSpacing.cx - nLabelWidth > 1)
5399 lprc->left += (infoPtr->iconSpacing.cx - nLabelWidth) / 2;
5400 lprc->right = lprc->left + nLabelWidth;
5402 else
5404 lprc->left += 1;
5405 lprc->right = lprc->left + infoPtr->iconSpacing.cx - 1;
5408 hdc = GetDC(hwnd);
5409 hOldFont = SelectObject(hdc, infoPtr->hFont);
5410 GetTextMetricsA(hdc, &tm);
5411 lprc->bottom = lprc->top + tm.tmHeight + HEIGHT_PADDING;
5412 SelectObject(hdc, hOldFont);
5413 ReleaseDC(hwnd, hdc);
5417 else if (uView == LVS_SMALLICON)
5419 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5421 bResult = TRUE;
5422 nLeftPos = lprc->left = ptItem.x + ptOrigin.x;
5423 lprc->top = ptItem.y + ptOrigin.y;
5424 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5426 if (infoPtr->himlState != NULL)
5428 lprc->left += infoPtr->iconSize.cx;
5431 if (infoPtr->himlSmall != NULL)
5433 lprc->left += infoPtr->iconSize.cx;
5436 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5437 nLabelWidth += TRAILING_PADDING;
5438 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5440 lprc->right = lprc->left + nLabelWidth;
5442 else
5444 lprc->right = nLeftPos + infoPtr->nItemWidth;
5448 else
5450 bResult = TRUE;
5451 if (uView & LVS_REPORT)
5452 nLeftPos = lprc->left = ptItem.x + nIndent;
5453 else
5454 nLeftPos = lprc->left = ptItem.x;
5455 lprc->top = ptItem.y;
5456 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5458 if (infoPtr->himlState != NULL)
5460 lprc->left += infoPtr->iconSize.cx;
5463 if (infoPtr->himlSmall != NULL)
5465 lprc->left += infoPtr->iconSize.cx;
5468 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5469 nLabelWidth += TRAILING_PADDING;
5470 if (infoPtr->himlSmall)
5471 nLabelWidth += IMAGE_PADDING;
5472 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5474 lprc->right = lprc->left + nLabelWidth;
5476 else
5478 lprc->right = nLeftPos + infoPtr->nItemWidth;
5481 break;
5483 case LVIR_BOUNDS:
5484 if (uView == LVS_ICON)
5486 if (infoPtr->himlNormal != NULL)
5488 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5490 bResult = TRUE;
5491 lprc->left = ptItem.x + ptOrigin.x;
5492 lprc->top = ptItem.y + ptOrigin.y;
5493 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
5494 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
5498 else if (uView == LVS_SMALLICON)
5500 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5502 bResult = TRUE;
5503 lprc->left = ptItem.x + ptOrigin.x;
5504 lprc->right = lprc->left;
5505 lprc->top = ptItem.y + ptOrigin.y;
5506 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5507 if (infoPtr->himlState != NULL)
5508 lprc->right += infoPtr->iconSize.cx;
5509 if (infoPtr->himlSmall != NULL)
5510 lprc->right += infoPtr->iconSize.cx;
5512 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5513 nLabelWidth += TRAILING_PADDING;
5514 if (infoPtr->himlSmall)
5515 nLabelWidth += IMAGE_PADDING;
5516 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
5518 lprc->right += nLabelWidth;
5520 else
5522 lprc->right = lprc->left + infoPtr->nItemWidth;
5526 else
5528 bResult = TRUE;
5529 lprc->left = ptItem.x;
5530 if (!(infoPtr->dwExStyle&LVS_EX_FULLROWSELECT) && uView&LVS_REPORT)
5531 lprc->left += nIndent;
5532 lprc->right = lprc->left;
5533 lprc->top = ptItem.y;
5534 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5536 if (infoPtr->dwExStyle & LVS_EX_FULLROWSELECT)
5538 RECT br;
5539 int nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
5540 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
5542 lprc->right = max(lprc->left, br.right - REPORT_MARGINX);
5544 else
5546 if (infoPtr->himlState != NULL)
5548 lprc->right += infoPtr->iconSize.cx;
5551 if (infoPtr->himlSmall != NULL)
5553 lprc->right += infoPtr->iconSize.cx;
5556 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5557 nLabelWidth += TRAILING_PADDING;
5558 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
5560 lprc->right += nLabelWidth;
5562 else
5564 lprc->right = lprc->left + infoPtr->nItemWidth;
5568 break;
5570 case LVIR_SELECTBOUNDS:
5571 if (uView == LVS_ICON)
5573 if (infoPtr->himlNormal != NULL)
5575 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5577 bResult = TRUE;
5578 lprc->left = ptItem.x + ptOrigin.x;
5579 lprc->top = ptItem.y + ptOrigin.y;
5580 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
5581 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
5585 else if (uView == LVS_SMALLICON)
5587 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
5589 bResult = TRUE;
5590 nLeftPos= lprc->left = ptItem.x + ptOrigin.x;
5591 lprc->top = ptItem.y + ptOrigin.y;
5592 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5594 if (infoPtr->himlState != NULL)
5596 lprc->left += infoPtr->iconSize.cx;
5599 lprc->right = lprc->left;
5601 if (infoPtr->himlSmall != NULL)
5603 lprc->right += infoPtr->iconSize.cx;
5606 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5607 nLabelWidth += TRAILING_PADDING;
5608 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5610 lprc->right += nLabelWidth;
5612 else
5614 lprc->right = nLeftPos + infoPtr->nItemWidth;
5618 else
5620 bResult = TRUE;
5621 if (!(infoPtr->dwExStyle&LVS_EX_FULLROWSELECT) && (uView&LVS_REPORT))
5622 nLeftPos = lprc->left = ptItem.x + nIndent;
5623 else
5624 nLeftPos = lprc->left = ptItem.x;
5625 lprc->top = ptItem.y;
5626 lprc->bottom = lprc->top + infoPtr->nItemHeight;
5628 if (infoPtr->himlState != NULL)
5630 lprc->left += infoPtr->iconSize.cx;
5633 lprc->right = lprc->left;
5635 if (infoPtr->dwExStyle & LVS_EX_FULLROWSELECT)
5637 RECT br;
5638 int nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
5639 Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
5641 lprc->right = max(lprc->left, br.right - REPORT_MARGINX);
5643 else
5645 if (infoPtr->himlSmall != NULL)
5647 lprc->right += infoPtr->iconSize.cx;
5650 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
5651 nLabelWidth += TRAILING_PADDING;
5652 if (infoPtr->himlSmall)
5653 nLabelWidth += IMAGE_PADDING;
5654 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
5656 lprc->right += nLabelWidth;
5658 else
5660 lprc->right = nLeftPos + infoPtr->nItemWidth;
5664 break;
5668 return bResult;
5671 /***
5672 * DESCRIPTION:
5673 * Retrieves the width of a label.
5675 * PARAMETER(S):
5676 * [I] HWND : window handle
5678 * RETURN:
5679 * SUCCESS : string width (in pixels)
5680 * FAILURE : zero
5682 static INT LISTVIEW_GetLabelWidth(HWND hwnd, INT nItem)
5684 CHAR szDispText[DISP_TEXT_SIZE];
5685 INT nLabelWidth = 0;
5686 LVITEMA lvItem;
5688 TRACE("(hwnd=%x, nItem=%d)\n", hwnd, nItem);
5690 ZeroMemory(&lvItem, sizeof(LVITEMA));
5691 lvItem.mask = LVIF_TEXT;
5692 lvItem.iItem = nItem;
5693 lvItem.cchTextMax = DISP_TEXT_SIZE;
5694 lvItem.pszText = szDispText;
5695 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
5697 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
5700 return nLabelWidth;
5703 /***
5704 * DESCRIPTION:
5705 * Retrieves the spacing between listview control items.
5707 * PARAMETER(S):
5708 * [I] HWND : window handle
5709 * [I] BOOL : flag for small or large icon
5711 * RETURN:
5712 * Horizontal + vertical spacing
5714 static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall)
5716 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5717 LONG lResult;
5719 if (bSmall == FALSE)
5721 lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
5723 else
5725 /* TODO: need to store width of smallicon item */
5726 lResult = MAKELONG(0, infoPtr->nItemHeight);
5729 return lResult;
5732 /***
5733 * DESCRIPTION:
5734 * Retrieves the state of a listview control item.
5736 * PARAMETER(S):
5737 * [I] HWND : window handle
5738 * [I] INT : item index
5739 * [I] UINT : state mask
5741 * RETURN:
5742 * State specified by the mask.
5744 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask)
5746 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5747 LVITEMA lvItem;
5748 UINT uState = 0;
5750 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5752 ZeroMemory(&lvItem, sizeof(LVITEMA));
5753 lvItem.iItem = nItem;
5754 lvItem.stateMask = uMask;
5755 lvItem.mask = LVIF_STATE;
5756 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
5758 uState = lvItem.state;
5762 return uState;
5765 /***
5766 * DESCRIPTION:
5767 * Retrieves the text of a listview control item or subitem.
5769 * PARAMETER(S):
5770 * [I] HWND : window handle
5771 * [I] INT : item index
5772 * [IO] LPLVITEMA : item information
5774 * RETURN:
5775 * SUCCESS : string length
5776 * FAILURE : 0
5778 static LRESULT LISTVIEW_GetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5780 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5781 INT nLength = 0;
5783 if (lpLVItem != NULL)
5785 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5787 lpLVItem->mask = LVIF_TEXT;
5788 lpLVItem->iItem = nItem;
5789 if (LISTVIEW_GetItemA(hwnd, lpLVItem, FALSE) != FALSE)
5791 nLength = lstrlenA(lpLVItem->pszText);
5796 return nLength;
5799 /***
5800 * DESCRIPTION:
5801 * Searches for an item based on properties + relationships.
5803 * PARAMETER(S):
5804 * [I] HWND : window handle
5805 * [I] INT : item index
5806 * [I] INT : relationship flag
5808 * RETURN:
5809 * SUCCESS : item index
5810 * FAILURE : -1
5812 static LRESULT LISTVIEW_GetNextItem(HWND hwnd, INT nItem, UINT uFlags)
5814 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5815 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5816 UINT uMask = 0;
5817 LVFINDINFO lvFindInfo;
5818 INT nCountPerColumn;
5819 INT i;
5821 if ((nItem >= -1) && (nItem < GETITEMCOUNT(infoPtr)))
5823 ZeroMemory(&lvFindInfo, sizeof(LVFINDINFO));
5825 if (uFlags & LVNI_CUT)
5826 uMask |= LVIS_CUT;
5828 if (uFlags & LVNI_DROPHILITED)
5829 uMask |= LVIS_DROPHILITED;
5831 if (uFlags & LVNI_FOCUSED)
5832 uMask |= LVIS_FOCUSED;
5834 if (uFlags & LVNI_SELECTED)
5835 uMask |= LVIS_SELECTED;
5837 if (uFlags & LVNI_ABOVE)
5839 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
5841 while (nItem >= 0)
5843 nItem--;
5844 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5845 return nItem;
5848 else
5850 lvFindInfo.flags = LVFI_NEARESTXY;
5851 lvFindInfo.vkDirection = VK_UP;
5852 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5853 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5855 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5856 return nItem;
5860 else if (uFlags & LVNI_BELOW)
5862 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
5864 while (nItem < GETITEMCOUNT(infoPtr))
5866 nItem++;
5867 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5868 return nItem;
5871 else
5873 lvFindInfo.flags = LVFI_NEARESTXY;
5874 lvFindInfo.vkDirection = VK_DOWN;
5875 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5876 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5878 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5879 return nItem;
5883 else if (uFlags & LVNI_TOLEFT)
5885 if (uView == LVS_LIST)
5887 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
5888 while (nItem - nCountPerColumn >= 0)
5890 nItem -= nCountPerColumn;
5891 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5892 return nItem;
5895 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
5897 lvFindInfo.flags = LVFI_NEARESTXY;
5898 lvFindInfo.vkDirection = VK_LEFT;
5899 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5900 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5902 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5903 return nItem;
5907 else if (uFlags & LVNI_TORIGHT)
5909 if (uView == LVS_LIST)
5911 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
5912 while (nItem + nCountPerColumn < GETITEMCOUNT(infoPtr))
5914 nItem += nCountPerColumn;
5915 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5916 return nItem;
5919 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
5921 lvFindInfo.flags = LVFI_NEARESTXY;
5922 lvFindInfo.vkDirection = VK_RIGHT;
5923 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
5924 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
5926 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
5927 return nItem;
5931 else
5933 nItem++;
5935 /* search by index */
5936 for (i = nItem; i < GETITEMCOUNT(infoPtr); i++)
5938 if ((ListView_GetItemState(hwnd, i, uMask) & uMask) == uMask)
5939 return i;
5944 return -1;
5947 /* LISTVIEW_GetNumberOfWorkAreas */
5949 /***
5950 * DESCRIPTION:
5951 * Retrieves the origin coordinates when in icon or small icon display mode.
5953 * PARAMETER(S):
5954 * [I] HWND : window handle
5955 * [O] LPPOINT : coordinate information
5957 * RETURN:
5958 * SUCCESS : TRUE
5959 * FAILURE : FALSE
5961 static LRESULT LISTVIEW_GetOrigin(HWND hwnd, LPPOINT lpptOrigin)
5963 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5964 UINT uView = lStyle & LVS_TYPEMASK;
5965 BOOL bResult = FALSE;
5967 TRACE("(hwnd=%x, lpptOrigin=%p)\n", hwnd, lpptOrigin);
5969 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
5971 SCROLLINFO scrollInfo;
5972 ZeroMemory(lpptOrigin, sizeof(POINT));
5973 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
5974 scrollInfo.cbSize = sizeof(SCROLLINFO);
5976 if (lStyle & WS_HSCROLL)
5978 scrollInfo.fMask = SIF_POS;
5979 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
5981 lpptOrigin->x = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
5985 if (lStyle & WS_VSCROLL)
5987 scrollInfo.fMask = SIF_POS;
5988 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
5990 lpptOrigin->y = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
5994 bResult = TRUE;
5997 return bResult;
6000 /***
6001 * DESCRIPTION:
6002 * Retrieves the number of items that are marked as selected.
6004 * PARAMETER(S):
6005 * [I] HWND : window handle
6007 * RETURN:
6008 * Number of items selected.
6010 static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd)
6012 /* REDO THIS */
6013 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6014 INT nSelectedCount = 0;
6015 INT i;
6017 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
6019 if (ListView_GetItemState(hwnd, i, LVIS_SELECTED) & LVIS_SELECTED)
6021 nSelectedCount++;
6025 return nSelectedCount;
6028 /***
6029 * DESCRIPTION:
6030 * Retrieves item index that marks the start of a multiple selection.
6032 * PARAMETER(S):
6033 * [I] HWND : window handle
6035 * RETURN:
6036 * Index number or -1 if there is no selection mark.
6038 static LRESULT LISTVIEW_GetSelectionMark(HWND hwnd)
6040 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6042 return infoPtr->nSelectionMark;
6045 /***
6046 * DESCRIPTION:
6047 * Retrieves the width of a string.
6049 * PARAMETER(S):
6050 * [I] HWND : window handle
6052 * RETURN:
6053 * SUCCESS : string width (in pixels)
6054 * FAILURE : zero
6056 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText)
6058 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6059 HFONT hFont, hOldFont;
6060 SIZE stringSize;
6061 HDC hdc;
6063 ZeroMemory(&stringSize, sizeof(SIZE));
6064 if (lpszText != NULL && lpszText != LPSTR_TEXTCALLBACKA)
6066 hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
6067 hdc = GetDC(hwnd);
6068 hOldFont = SelectObject(hdc, hFont);
6069 GetTextExtentPointA(hdc, lpszText, lstrlenA(lpszText), &stringSize);
6070 SelectObject(hdc, hOldFont);
6071 ReleaseDC(hwnd, hdc);
6074 return stringSize.cx;
6077 /***
6078 * DESCRIPTION:
6079 * Retrieves the text backgound color.
6081 * PARAMETER(S):
6082 * [I] HWND : window handle
6084 * RETURN:
6085 * COLORREF associated with the the background.
6087 static LRESULT LISTVIEW_GetTextBkColor(HWND hwnd)
6089 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
6091 return infoPtr->clrTextBk;
6094 /***
6095 * DESCRIPTION:
6096 * Retrieves the text color.
6098 * PARAMETER(S):
6099 * [I] HWND : window handle
6101 * RETURN:
6102 * COLORREF associated with the text.
6104 static LRESULT LISTVIEW_GetTextColor(HWND hwnd)
6106 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
6108 return infoPtr->clrText;
6111 /***
6112 * DESCRIPTION:
6113 * Determines which section of the item was selected (if any).
6115 * PARAMETER(S):
6116 * [I] HWND : window handle
6117 * [IO] LPLVHITTESTINFO : hit test information
6118 * [I] subitem : fill out iSubItem.
6120 * RETURN:
6121 * SUCCESS : item index
6122 * FAILURE : -1
6124 static INT LISTVIEW_HitTestItem(
6125 HWND hwnd, LPLVHITTESTINFO lpHitTestInfo, BOOL subitem
6127 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6128 RECT rcItem;
6129 INT i,topindex,bottomindex;
6130 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6131 UINT uView = lStyle & LVS_TYPEMASK;
6134 TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpHitTestInfo->pt.x,
6135 lpHitTestInfo->pt.y);
6137 topindex = ListView_GetTopIndex(hwnd);
6138 if (uView == LVS_REPORT)
6140 bottomindex = topindex + LISTVIEW_GetCountPerColumn(hwnd) + 1;
6141 bottomindex = min(bottomindex,GETITEMCOUNT(infoPtr));
6143 else
6145 bottomindex = GETITEMCOUNT(infoPtr);
6148 for (i = topindex; i < bottomindex; i++)
6150 rcItem.left = LVIR_BOUNDS;
6151 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
6153 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
6155 rcItem.left = LVIR_ICON;
6156 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
6158 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
6160 lpHitTestInfo->flags = LVHT_ONITEMICON;
6161 lpHitTestInfo->iItem = i;
6162 if (subitem) lpHitTestInfo->iSubItem = 0;
6163 return i;
6167 rcItem.left = LVIR_LABEL;
6168 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
6170 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
6172 lpHitTestInfo->flags = LVHT_ONITEMLABEL;
6173 lpHitTestInfo->iItem = i;
6174 if (subitem) lpHitTestInfo->iSubItem = 0;
6175 return i;
6179 lpHitTestInfo->flags = LVHT_ONITEMSTATEICON;
6180 lpHitTestInfo->iItem = i;
6181 if (subitem) lpHitTestInfo->iSubItem = 0;
6182 return i;
6187 lpHitTestInfo->flags = LVHT_NOWHERE;
6189 return -1;
6192 /***
6193 * DESCRIPTION:
6194 * Determines which listview item is located at the specified position.
6196 * PARAMETER(S):
6197 * [I] HWND : window handle
6198 * [IO} LPLVHITTESTINFO : hit test information
6200 * RETURN:
6201 * SUCCESS : item index
6202 * FAILURE : -1
6204 static LRESULT LISTVIEW_HitTest(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
6206 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6207 INT nItem = -1;
6209 lpHitTestInfo->flags = 0;
6211 if (infoPtr->rcList.left > lpHitTestInfo->pt.x)
6213 lpHitTestInfo->flags = LVHT_TOLEFT;
6215 else if (infoPtr->rcList.right < lpHitTestInfo->pt.x)
6217 lpHitTestInfo->flags = LVHT_TORIGHT;
6219 if (infoPtr->rcList.top > lpHitTestInfo->pt.y)
6221 lpHitTestInfo->flags |= LVHT_ABOVE;
6223 else if (infoPtr->rcList.bottom < lpHitTestInfo->pt.y)
6225 lpHitTestInfo->flags |= LVHT_BELOW;
6228 if (lpHitTestInfo->flags == 0)
6230 /* NOTE (mm 20001022): We must not allow iSubItem to be touched, for
6231 * an app might pass only a structure with space up to iItem!
6232 * (MS Office 97 does that for instance in the file open dialog)
6234 nItem = LISTVIEW_HitTestItem(hwnd, lpHitTestInfo, FALSE);
6237 return nItem;
6240 /***
6241 * DESCRIPTION:
6242 * Inserts a new column.
6244 * PARAMETER(S):
6245 * [I] HWND : window handle
6246 * [I] INT : column index
6247 * [I] LPLVCOLUMNA : column information
6249 * RETURN:
6250 * SUCCESS : new column index
6251 * FAILURE : -1
6253 static LRESULT LISTVIEW_InsertColumnA(HWND hwnd, INT nColumn,
6254 LPLVCOLUMNA lpColumn)
6256 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6257 HDITEMA hdi;
6258 INT nNewColumn = -1;
6260 TRACE("(hwnd=%x, nColumn=%d, lpColumn=%p)\n",hwnd, nColumn,
6261 lpColumn);
6263 if (lpColumn != NULL)
6265 /* initialize memory */
6266 ZeroMemory(&hdi, sizeof(HDITEMA));
6268 if (lpColumn->mask & LVCF_FMT)
6270 /* format member is valid */
6271 hdi.mask |= HDI_FORMAT;
6273 /* set text alignment (leftmost column must be left-aligned) */
6274 if (nColumn == 0)
6276 hdi.fmt |= HDF_LEFT;
6278 else
6280 if (lpColumn->fmt & LVCFMT_LEFT)
6282 hdi.fmt |= HDF_LEFT;
6284 else if (lpColumn->fmt & LVCFMT_RIGHT)
6286 hdi.fmt |= HDF_RIGHT;
6288 else if (lpColumn->fmt & LVCFMT_CENTER)
6290 hdi.fmt |= HDF_CENTER;
6294 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
6296 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
6297 /* ??? */
6300 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
6302 /* ??? */
6305 if (lpColumn->fmt & LVCFMT_IMAGE)
6307 hdi.fmt |= HDF_IMAGE;
6308 hdi.iImage = I_IMAGECALLBACK;
6312 if (lpColumn->mask & LVCF_WIDTH)
6314 hdi.mask |= HDI_WIDTH;
6315 hdi.cxy = lpColumn->cx;
6318 if (lpColumn->mask & LVCF_TEXT)
6320 hdi.mask |= HDI_TEXT | HDI_FORMAT;
6321 hdi.pszText = lpColumn->pszText;
6322 hdi.cchTextMax = ((lpColumn->pszText!=NULL) && (lpColumn->pszText!=LPSTR_TEXTCALLBACKA) ? strlen(lpColumn->pszText) : 0);
6323 hdi.fmt |= HDF_STRING;
6326 if (lpColumn->mask & LVCF_IMAGE)
6328 hdi.mask |= HDI_IMAGE;
6329 hdi.iImage = lpColumn->iImage;
6332 if (lpColumn->mask & LVCF_ORDER)
6334 hdi.mask |= HDI_ORDER;
6335 hdi.iOrder = lpColumn->iOrder;
6338 /* insert item in header control */
6339 nNewColumn = SendMessageA(infoPtr->hwndHeader, HDM_INSERTITEMA,
6340 (WPARAM)nColumn, (LPARAM)&hdi);
6342 /* Need to reset the item width when inserting a new column */
6343 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6345 LISTVIEW_UpdateScroll(hwnd);
6346 InvalidateRect(hwnd, NULL, FALSE);
6349 return nNewColumn;
6352 static LRESULT LISTVIEW_InsertColumnW(HWND hwnd, INT nColumn,
6353 LPLVCOLUMNW lpColumn)
6355 LVCOLUMNA lvca;
6356 LRESULT lres;
6358 memcpy(&lvca,lpColumn,sizeof(lvca));
6359 if (lpColumn->mask & LVCF_TEXT) {
6360 if (lpColumn->pszText == LPSTR_TEXTCALLBACKW)
6361 lvca.pszText = LPSTR_TEXTCALLBACKA;
6362 else
6363 lvca.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpColumn->pszText);
6365 lres = LISTVIEW_InsertColumnA(hwnd,nColumn,&lvca);
6366 if (lpColumn->mask & LVCF_TEXT) {
6367 if (lpColumn->pszText != LPSTR_TEXTCALLBACKW)
6368 HeapFree(GetProcessHeap(),0,lvca.pszText);
6370 return lres;
6373 /* LISTVIEW_InsertCompare: callback routine for comparing pszText members of the LV_ITEMS
6374 in a LISTVIEW on insert. Passed to DPA_Sort in LISTVIEW_InsertItem.
6375 This function should only be used for inserting items into a sorted list (LVM_INSERTITEM)
6376 and not during the processing of a LVM_SORTITEMS message. Applications should provide
6377 their own sort proc. when sending LVM_SORTITEMS.
6379 /* Platform SDK:
6380 (remarks on LVITEM: LVM_INSERTITEM will insert the new item in the proper sort postion...
6382 LVS_SORTXXX must be specified,
6383 LVS_OWNERDRAW is not set,
6384 <item>.pszText is not LPSTR_TEXTCALLBACK.
6386 (LVS_SORT* flags): "For the LVS_SORTASCENDING... styles, item indices
6387 are sorted based on item text..."
6389 static INT WINAPI LISTVIEW_InsertCompare( LPVOID first, LPVOID second, LPARAM lParam)
6391 HDPA hdpa_first = (HDPA) first;
6392 HDPA hdpa_second = (HDPA) second;
6393 LISTVIEW_ITEM* lv_first = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_first, 0 );
6394 LISTVIEW_ITEM* lv_second = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_second, 0 );
6395 LONG lStyle = GetWindowLongA((HWND) lParam, GWL_STYLE);
6396 INT cmpv = lstrcmpA( lv_first->pszText, lv_second->pszText );
6397 /* if we're sorting descending, negate the return value */
6398 return (lStyle & LVS_SORTDESCENDING) ? -cmpv : cmpv;
6401 /***
6402 * nESCRIPTION:
6403 * Inserts a new item in the listview control.
6405 * PARAMETER(S):
6406 * [I] HWND : window handle
6407 * [I] LPLVITEMA : item information
6409 * RETURN:
6410 * SUCCESS : new item index
6411 * FAILURE : -1
6413 static LRESULT LISTVIEW_InsertItemA(HWND hwnd, LPLVITEMA lpLVItem)
6415 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6416 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6417 UINT uView = lStyle & LVS_TYPEMASK;
6418 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
6419 NMLISTVIEW nmlv;
6420 INT nItem = -1;
6421 HDPA hdpaSubItems;
6422 INT nItemWidth = 0;
6423 LISTVIEW_ITEM *lpItem = NULL;
6425 TRACE("(hwnd=%x,lpLVItem=%p)\n", hwnd, lpLVItem);
6427 if (lStyle & LVS_OWNERDATA)
6429 nItem = infoPtr->hdpaItems->nItemCount;
6430 infoPtr->hdpaItems->nItemCount ++;
6431 return nItem;
6434 if (lpLVItem != NULL)
6436 /* make sure it's not a subitem; cannot insert a subitem */
6437 if (lpLVItem->iSubItem == 0)
6439 lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM));
6440 if (lpItem != NULL)
6442 ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
6443 if (LISTVIEW_InitItem(hwnd, lpItem, lpLVItem) != FALSE)
6445 /* insert item in listview control data structure */
6446 hdpaSubItems = DPA_Create(8);
6447 if (hdpaSubItems != NULL)
6449 nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem);
6450 if (nItem != -1)
6452 if ( ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
6453 && !(lStyle & LVS_OWNERDRAWFIXED)
6454 && (LPSTR_TEXTCALLBACKA != lpLVItem->pszText) )
6456 /* Insert the item in the proper sort order based on the pszText
6457 member. See comments for LISTVIEW_InsertCompare() for greater detail */
6458 nItem = DPA_InsertPtr( infoPtr->hdpaItems,
6459 GETITEMCOUNT( infoPtr ) + 1, hdpaSubItems );
6460 DPA_Sort( infoPtr->hdpaItems, LISTVIEW_InsertCompare, hwnd );
6461 nItem = DPA_GetPtrIndex( infoPtr->hdpaItems, hdpaSubItems );
6463 else
6465 nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpLVItem->iItem,
6466 hdpaSubItems);
6468 if (nItem != -1)
6470 LISTVIEW_ShiftSelections(hwnd,nItem,1);
6472 /* manage item focus */
6473 if (lpLVItem->mask & LVIF_STATE)
6475 lpItem->state &= ~(LVIS_FOCUSED|LVIS_SELECTED);
6476 if (lpLVItem->stateMask & LVIS_SELECTED)
6478 LISTVIEW_SetSelection(hwnd, nItem);
6480 else if (lpLVItem->stateMask & LVIS_FOCUSED)
6482 LISTVIEW_SetItemFocus(hwnd, nItem);
6486 /* send LVN_INSERTITEM notification */
6487 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
6488 nmlv.hdr.hwndFrom = hwnd;
6489 nmlv.hdr.idFrom = lCtrlId;
6490 nmlv.hdr.code = LVN_INSERTITEM;
6491 nmlv.iItem = nItem;
6492 nmlv.lParam = lpItem->lParam;;
6493 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
6495 if ((uView == LVS_SMALLICON) || (uView == LVS_LIST))
6497 nItemWidth = LISTVIEW_CalculateWidth(hwnd, lpLVItem->iItem);
6498 if (nItemWidth > infoPtr->nItemWidth)
6500 infoPtr->nItemWidth = nItemWidth;
6504 /* align items (set position of each item) */
6505 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
6507 if (lStyle & LVS_ALIGNLEFT)
6509 LISTVIEW_AlignLeft(hwnd);
6511 else
6513 LISTVIEW_AlignTop(hwnd);
6517 LISTVIEW_UpdateScroll(hwnd);
6518 /* refresh client area */
6519 InvalidateRect(hwnd, NULL, FALSE);
6528 /* free memory if unsuccessful */
6529 if ((nItem == -1) && (lpItem != NULL))
6531 COMCTL32_Free(lpItem);
6534 return nItem;
6537 static LRESULT LISTVIEW_InsertItemW(HWND hwnd, LPLVITEMW lpLVItem) {
6538 LVITEMA lvia;
6539 LRESULT lres;
6541 memcpy(&lvia,lpLVItem,sizeof(LVITEMA));
6542 if (lvia.mask & LVIF_TEXT) {
6543 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKW)
6544 lvia.pszText = LPSTR_TEXTCALLBACKA;
6545 else
6546 lvia.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpLVItem->pszText);
6548 lres = LISTVIEW_InsertItemA(hwnd, &lvia);
6549 if (lvia.mask & LVIF_TEXT) {
6550 if (lpLVItem->pszText != LPSTR_TEXTCALLBACKW)
6551 HeapFree(GetProcessHeap(),0,lvia.pszText);
6553 return lres;
6556 /* LISTVIEW_InsertItemW */
6558 /***
6559 * DESCRIPTION:
6560 * Redraws a range of items.
6562 * PARAMETER(S):
6563 * [I] HWND : window handle
6564 * [I] INT : first item
6565 * [I] INT : last item
6567 * RETURN:
6568 * SUCCESS : TRUE
6569 * FAILURE : FALSE
6571 static LRESULT LISTVIEW_RedrawItems(HWND hwnd, INT nFirst, INT nLast)
6573 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6574 BOOL bResult = FALSE;
6575 RECT rcItem;
6577 if (nFirst <= nLast)
6579 if ((nFirst >= 0) && (nFirst < GETITEMCOUNT(infoPtr)))
6581 if ((nLast >= 0) && (nLast < GETITEMCOUNT(infoPtr)))
6583 INT i;
6584 for (i = nFirst; i <= nLast; i++)
6586 rcItem.left = LVIR_BOUNDS;
6587 LISTVIEW_GetItemRect(hwnd, i, &rcItem);
6588 InvalidateRect(hwnd, &rcItem, TRUE);
6594 return bResult;
6597 /* LISTVIEW_Scroll */
6599 /***
6600 * DESCRIPTION:
6601 * Sets the background color.
6603 * PARAMETER(S):
6604 * [I] HWND : window handle
6605 * [I] COLORREF : background color
6607 * RETURN:
6608 * SUCCESS : TRUE
6609 * FAILURE : FALSE
6611 static LRESULT LISTVIEW_SetBkColor(HWND hwnd, COLORREF clrBk)
6613 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6615 infoPtr->clrBk = clrBk;
6616 InvalidateRect(hwnd, NULL, TRUE);
6618 return TRUE;
6621 /* LISTVIEW_SetBkImage */
6623 /***
6624 * DESCRIPTION:
6625 * Sets the callback mask. This mask will be used when the parent
6626 * window stores state information (some or all).
6628 * PARAMETER(S):
6629 * [I] HWND : window handle
6630 * [I] UINT : state mask
6632 * RETURN:
6633 * SUCCESS : TRUE
6634 * FAILURE : FALSE
6636 static BOOL LISTVIEW_SetCallbackMask(HWND hwnd, UINT uMask)
6638 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6640 infoPtr->uCallbackMask = uMask;
6642 return TRUE;
6645 /***
6646 * DESCRIPTION:
6647 * Sets the attributes of a header item.
6649 * PARAMETER(S):
6650 * [I] HWND : window handle
6651 * [I] INT : column index
6652 * [I] LPLVCOLUMNA : column attributes
6654 * RETURN:
6655 * SUCCESS : TRUE
6656 * FAILURE : FALSE
6658 static LRESULT LISTVIEW_SetColumnA(HWND hwnd, INT nColumn,
6659 LPLVCOLUMNA lpColumn)
6661 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6662 BOOL bResult = FALSE;
6663 HDITEMA hdi, hdiget;
6665 if ((lpColumn != NULL) && (nColumn >= 0) &&
6666 (nColumn < Header_GetItemCount(infoPtr->hwndHeader)))
6668 /* initialize memory */
6669 ZeroMemory(&hdi, sizeof(HDITEMA));
6671 if (lpColumn->mask & LVCF_FMT)
6673 /* format member is valid */
6674 hdi.mask |= HDI_FORMAT;
6676 /* get current format first */
6677 hdiget.mask = HDI_FORMAT;
6678 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdiget))
6679 /* preserve HDF_STRING if present */
6680 hdi.fmt = hdiget.fmt & HDF_STRING;
6682 /* set text alignment (leftmost column must be left-aligned) */
6683 if (nColumn == 0)
6685 hdi.fmt |= HDF_LEFT;
6687 else
6689 if (lpColumn->fmt & LVCFMT_LEFT)
6691 hdi.fmt |= HDF_LEFT;
6693 else if (lpColumn->fmt & LVCFMT_RIGHT)
6695 hdi.fmt |= HDF_RIGHT;
6697 else if (lpColumn->fmt & LVCFMT_CENTER)
6699 hdi.fmt |= HDF_CENTER;
6703 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
6705 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
6708 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
6710 hdi.fmt |= HDF_IMAGE;
6713 if (lpColumn->fmt & LVCFMT_IMAGE)
6715 hdi.fmt |= HDF_IMAGE;
6716 hdi.iImage = I_IMAGECALLBACK;
6720 if (lpColumn->mask & LVCF_WIDTH)
6722 hdi.mask |= HDI_WIDTH;
6723 hdi.cxy = lpColumn->cx;
6726 if (lpColumn->mask & LVCF_TEXT)
6728 hdi.mask |= HDI_TEXT | HDI_FORMAT;
6729 hdi.pszText = lpColumn->pszText;
6730 hdi.cchTextMax = ((lpColumn->pszText!=NULL) && (lpColumn->pszText!=LPSTR_TEXTCALLBACKA) ? strlen(lpColumn->pszText) : 0);
6731 hdi.fmt |= HDF_STRING;
6734 if (lpColumn->mask & LVCF_IMAGE)
6736 hdi.mask |= HDI_IMAGE;
6737 hdi.iImage = lpColumn->iImage;
6740 if (lpColumn->mask & LVCF_ORDER)
6742 hdi.mask |= HDI_ORDER;
6743 hdi.iOrder = lpColumn->iOrder;
6746 /* set header item attributes */
6747 bResult = Header_SetItemA(infoPtr->hwndHeader, nColumn, &hdi);
6750 return bResult;
6753 /* LISTVIEW_SetColumnW */
6755 /***
6756 * DESCRIPTION:
6757 * Sets the column order array
6759 * PARAMETERS:
6760 * [I] HWND : window handle
6761 * [I] INT : number of elements in column order array
6762 * [I] INT : pointer to column order array
6764 * RETURN:
6765 * SUCCESS : TRUE
6766 * FAILURE : FALSE
6768 static LRESULT LISTVIEW_SetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
6770 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
6772 FIXME("iCount %d lpiArray %p\n", iCount, lpiArray);
6774 if (!lpiArray)
6775 return FALSE;
6777 return TRUE;
6781 /***
6782 * DESCRIPTION:
6783 * Sets the width of a column
6785 * PARAMETERS:
6786 * [I] HWND : window handle
6787 * [I] INT : column index
6788 * [I] INT : column width
6790 * RETURN:
6791 * SUCCESS : TRUE
6792 * FAILURE : FALSE
6794 static LRESULT LISTVIEW_SetColumnWidth(HWND hwnd, INT iCol, INT cx)
6796 LISTVIEW_INFO *infoPtr;
6797 HDITEMA hdi;
6798 LRESULT lret;
6799 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6800 UINT uView = lStyle & LVS_TYPEMASK;
6801 HDC hdc;
6802 HFONT header_font;
6803 HFONT old_font;
6804 SIZE size;
6805 CHAR text_buffer[DISP_TEXT_SIZE];
6806 INT header_item_count;
6807 INT item_index;
6808 RECT rcHeader;
6811 /* make sure we can get the listview info */
6812 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
6813 return (FALSE);
6815 if (!infoPtr->hwndHeader) /* make sure we have a header */
6816 return (FALSE);
6818 /* set column width only if in report or list mode */
6819 if ((uView != LVS_REPORT) && (uView != LVS_LIST))
6820 return (FALSE);
6822 /* take care of invalid cx values */
6823 if((uView == LVS_REPORT) && (cx < -2))
6824 cx = LVSCW_AUTOSIZE;
6825 else if (uView == LVS_LIST && (cx < 1))
6826 return FALSE;
6828 /* resize all columns if in LVS_LIST mode */
6829 if(uView == LVS_LIST) {
6830 infoPtr->nItemWidth = cx;
6831 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
6832 return TRUE;
6835 /* autosize based on listview items width */
6836 if(cx == LVSCW_AUTOSIZE)
6838 /* set the width of the header to the width of the widest item */
6839 for(item_index = 0; item_index < GETITEMCOUNT(infoPtr); item_index++)
6841 if(cx < LISTVIEW_GetLabelWidth(hwnd, item_index))
6842 cx = LISTVIEW_GetLabelWidth(hwnd, item_index);
6844 } /* autosize based on listview header width */
6845 else if(cx == LVSCW_AUTOSIZE_USEHEADER)
6847 header_item_count = Header_GetItemCount(infoPtr->hwndHeader);
6849 /* if iCol is the last column make it fill the remainder of the controls width */
6850 if(iCol == (header_item_count - 1)) {
6851 /* get the width of every item except the current one */
6852 hdi.mask = HDI_WIDTH;
6853 cx = 0;
6855 for(item_index = 0; item_index < (header_item_count - 1); item_index++) {
6856 Header_GetItemA(infoPtr->hwndHeader, item_index, (LPARAM)(&hdi));
6857 cx+=hdi.cxy;
6860 /* retrieve the layout of the header */
6861 GetWindowRect(infoPtr->hwndHeader, &rcHeader);
6863 cx = (rcHeader.right - rcHeader.left) - cx;
6865 else
6867 /* retrieve header font */
6868 header_font = SendMessageA(infoPtr->hwndHeader, WM_GETFONT, 0L, 0L);
6870 /* retrieve header text */
6871 hdi.mask = HDI_TEXT;
6872 hdi.cchTextMax = sizeof(text_buffer);
6873 hdi.pszText = text_buffer;
6875 Header_GetItemA(infoPtr->hwndHeader, iCol, (LPARAM)(&hdi));
6877 /* determine the width of the text in the header */
6878 hdc = GetDC(hwnd);
6879 old_font = SelectObject(hdc, header_font); /* select the font into hdc */
6881 GetTextExtentPoint32A(hdc, text_buffer, strlen(text_buffer), &size);
6883 SelectObject(hdc, old_font); /* restore the old font */
6884 ReleaseDC(hwnd, hdc);
6886 /* set the width of this column to the width of the text */
6887 cx = size.cx;
6891 /* call header to update the column change */
6892 hdi.mask = HDI_WIDTH;
6894 hdi.cxy = cx;
6895 lret = Header_SetItemA(infoPtr->hwndHeader, (WPARAM)iCol, (LPARAM)&hdi);
6897 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
6899 return lret;
6902 /***
6903 * DESCRIPTION:
6904 * Sets the extended listview style.
6906 * PARAMETERS:
6907 * [I] HWND : window handle
6908 * [I] DWORD : mask
6909 * [I] DWORD : style
6911 * RETURN:
6912 * SUCCESS : previous style
6913 * FAILURE : 0
6915 static LRESULT LISTVIEW_SetExtendedListViewStyle(HWND hwnd, DWORD dwMask, DWORD dwStyle)
6917 LISTVIEW_INFO *infoPtr;
6918 DWORD dwOldStyle;
6920 /* make sure we can get the listview info */
6921 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
6922 return (0);
6924 /* store previous style */
6925 dwOldStyle = infoPtr->dwExStyle;
6927 /* set new style */
6928 if (dwMask)
6929 infoPtr->dwExStyle = (dwOldStyle & ~dwMask) | (dwStyle & dwMask);
6930 else
6931 infoPtr->dwExStyle = dwStyle;
6933 return (dwOldStyle);
6936 /* LISTVIEW_SetHotCursor */
6938 /***
6939 * DESCRIPTION:
6940 * Sets the hot item index.
6942 * PARAMETERS:
6943 * [I] HWND : window handle
6944 * [I] INT : index
6946 * RETURN:
6947 * SUCCESS : previous hot item index
6948 * FAILURE : -1 (no hot item)
6950 static LRESULT LISTVIEW_SetHotItem(HWND hwnd, INT iIndex)
6952 LISTVIEW_INFO *infoPtr;
6953 INT iOldIndex;
6955 /* make sure we can get the listview info */
6956 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
6957 return (-1);
6959 /* store previous index */
6960 iOldIndex = infoPtr->nHotItem;
6962 /* set new style */
6963 infoPtr->nHotItem = iIndex;
6965 return (iOldIndex);
6968 /***
6969 * DESCRIPTION:
6970 * Sets the amount of time the cursor must hover over an item before it is selected.
6972 * PARAMETER(S):
6973 * [I] HWND : window handle
6974 * [I] DWORD : dwHoverTime, if -1 the hover time is set to the default
6976 * RETURN:
6977 * Returns the previous hover time
6979 static LRESULT LISTVIEW_SetHoverTime(HWND hwnd, DWORD dwHoverTime)
6981 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6982 DWORD oldHoverTime = infoPtr->dwHoverTime;
6984 infoPtr->dwHoverTime = dwHoverTime;
6986 return oldHoverTime;
6989 /* LISTVIEW_SetIconSpacing */
6991 /***
6992 * DESCRIPTION:
6993 * Sets image lists.
6995 * PARAMETER(S):
6996 * [I] HWND : window handle
6997 * [I] INT : image list type
6998 * [I] HIMAGELIST : image list handle
7000 * RETURN:
7001 * SUCCESS : old image list
7002 * FAILURE : NULL
7004 static LRESULT LISTVIEW_SetImageList(HWND hwnd, INT nType, HIMAGELIST himl)
7006 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7007 HIMAGELIST himlOld = 0;
7008 INT oldHeight;
7010 switch (nType)
7012 case LVSIL_NORMAL:
7013 himlOld = infoPtr->himlNormal;
7014 infoPtr->himlNormal = himl;
7015 break;
7017 case LVSIL_SMALL:
7018 himlOld = infoPtr->himlSmall;
7019 infoPtr->himlSmall = himl;
7020 break;
7022 case LVSIL_STATE:
7023 himlOld = infoPtr->himlState;
7024 infoPtr->himlState = himl;
7025 ImageList_SetBkColor(infoPtr->himlState, CLR_NONE);
7026 break;
7029 oldHeight = infoPtr->nItemHeight;
7030 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7031 if (infoPtr->nItemHeight != oldHeight)
7032 LISTVIEW_UpdateScroll(hwnd);
7034 return (LRESULT)himlOld;
7038 /***
7039 * DESCRIPTION:
7040 * Sets the attributes of an item.
7042 * PARAMETER(S):
7043 * [I] HWND : window handle
7044 * [I] LPLVITEM : item information
7046 * RETURN:
7047 * SUCCESS : TRUE
7048 * FAILURE : FALSE
7050 static LRESULT LISTVIEW_SetItemA(HWND hwnd, LPLVITEMA lpLVItem)
7052 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7053 BOOL bResult = FALSE;
7055 if (lpLVItem != NULL)
7057 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
7059 if (lpLVItem->iSubItem == 0)
7061 bResult = LISTVIEW_SetItem(hwnd, lpLVItem);
7063 else
7065 bResult = LISTVIEW_SetSubItem(hwnd, lpLVItem);
7071 return bResult;
7074 /* LISTVIEW_SetItemW */
7076 /***
7077 * DESCRIPTION:
7078 * Preallocates memory (does *not* set the actual count of items !)
7080 * PARAMETER(S):
7081 * [I] HWND : window handle
7082 * [I] INT : item count (projected number of items to allocate)
7083 * [I] DWORD : update flags
7085 * RETURN:
7086 * SUCCESS : TRUE
7087 * FAILURE : FALSE
7089 static BOOL LISTVIEW_SetItemCount(HWND hwnd, INT nItems, DWORD dwFlags)
7091 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
7093 if (GetWindowLongA(hwnd, GWL_STYLE) & LVS_OWNERDATA)
7095 int precount,topvisible;
7096 TRACE("LVS_OWNERDATA is set!\n");
7099 * Internally remove all the selections.
7103 LISTVIEW_SELECTION *selection;
7104 selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,0);
7105 if (selection)
7106 LISTVIEW_RemoveSelectionRange(hwnd,selection->lower,
7107 selection->upper);
7109 while (infoPtr->hdpaSelectionRanges->nItemCount>0);
7111 precount = infoPtr->hdpaItems->nItemCount;
7112 topvisible = ListView_GetTopIndex(hwnd) +
7113 LISTVIEW_GetCountPerColumn(hwnd) + 1;
7115 infoPtr->hdpaItems->nItemCount = nItems;
7117 LISTVIEW_UpdateSize(hwnd);
7118 LISTVIEW_UpdateScroll(hwnd);
7119 if (min(precount,infoPtr->hdpaItems->nItemCount)<topvisible)
7120 InvalidateRect(hwnd, NULL, TRUE);
7122 else
7124 FIXME("setitemcount not done for non-ownerdata\n");
7127 return TRUE;
7130 /***
7131 * DESCRIPTION:
7132 * Sets the position of an item.
7134 * PARAMETER(S):
7135 * [I] HWND : window handle
7136 * [I] INT : item index
7137 * [I] LONG : x coordinate
7138 * [I] LONG : y coordinate
7140 * RETURN:
7141 * SUCCESS : TRUE
7142 * FAILURE : FALSE
7144 static BOOL LISTVIEW_SetItemPosition(HWND hwnd, INT nItem,
7145 LONG nPosX, LONG nPosY)
7147 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
7148 UINT lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7149 UINT uView = lStyle & LVS_TYPEMASK;
7150 LISTVIEW_ITEM *lpItem;
7151 HDPA hdpaSubItems;
7152 BOOL bResult = FALSE;
7154 TRACE("(hwnd=%x,nItem=%d,X=%ld,Y=%ld)\n", hwnd, nItem, nPosX, nPosY);
7156 if (lStyle & LVS_OWNERDATA)
7157 return FALSE;
7159 if ((nItem >= 0) || (nItem < GETITEMCOUNT(infoPtr)))
7161 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
7163 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
7164 if (hdpaSubItems != NULL)
7166 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
7167 if (lpItem != NULL)
7169 bResult = TRUE;
7170 lpItem->ptPosition.x = nPosX;
7171 lpItem->ptPosition.y = nPosY;
7177 return bResult;
7180 /***
7181 * DESCRIPTION:
7182 * Sets the state of one or many items.
7184 * PARAMETER(S):
7185 * [I] HWND : window handle
7186 * [I]INT : item index
7187 * [I] LPLVITEM : item or subitem info
7189 * RETURN:
7190 * SUCCESS : TRUE
7191 * FAILURE : FALSE
7193 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
7195 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7196 BOOL bResult = FALSE;
7197 LVITEMA lvItem;
7198 INT i;
7200 if (nItem == -1)
7202 bResult = TRUE;
7203 ZeroMemory(&lvItem, sizeof(LVITEMA));
7204 lvItem.mask = LVIF_STATE;
7205 lvItem.state = lpLVItem->state;
7206 lvItem.stateMask = lpLVItem->stateMask ;
7208 /* apply to all items */
7209 for (i = 0; i< GETITEMCOUNT(infoPtr); i++)
7211 lvItem.iItem = i;
7212 if (ListView_SetItemA(hwnd, &lvItem) == FALSE)
7214 bResult = FALSE;
7218 else
7220 ZeroMemory(&lvItem, sizeof(LVITEMA));
7221 lvItem.mask = LVIF_STATE;
7222 lvItem.state = lpLVItem->state;
7223 lvItem.stateMask = lpLVItem->stateMask;
7224 lvItem.iItem = nItem;
7225 bResult = ListView_SetItemA(hwnd, &lvItem);
7228 return bResult;
7231 /***
7232 * DESCRIPTION:
7233 * Sets the text of an item or subitem.
7235 * PARAMETER(S):
7236 * [I] HWND : window handle
7237 * [I] INT : item index
7238 * [I] LPLVITEMA : item or subitem info
7240 * RETURN:
7241 * SUCCESS : TRUE
7242 * FAILURE : FALSE
7244 static BOOL LISTVIEW_SetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
7246 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7247 BOOL bResult = FALSE;
7248 LVITEMA lvItem;
7250 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
7252 ZeroMemory(&lvItem, sizeof(LVITEMA));
7253 lvItem.mask = LVIF_TEXT;
7254 lvItem.pszText = lpLVItem->pszText;
7255 lvItem.iItem = nItem;
7256 lvItem.iSubItem = lpLVItem->iSubItem;
7257 bResult = ListView_SetItemA(hwnd, &lvItem);
7260 return bResult;
7263 /* LISTVIEW_SetItemTextW */
7265 /***
7266 * DESCRIPTION:
7267 * Set item index that marks the start of a multiple selection.
7269 * PARAMETER(S):
7270 * [I] HWND : window handle
7271 * [I] INT : index
7273 * RETURN:
7274 * Index number or -1 if there is no selection mark.
7276 static LRESULT LISTVIEW_SetSelectionMark(HWND hwnd, INT nIndex)
7278 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7279 INT nOldIndex = infoPtr->nSelectionMark;
7281 infoPtr->nSelectionMark = nIndex;
7283 return nOldIndex;
7286 /***
7287 * DESCRIPTION:
7288 * Sets the text background color.
7290 * PARAMETER(S):
7291 * [I] HWND : window handle
7292 * [I] COLORREF : text background color
7294 * RETURN:
7295 * SUCCESS : TRUE
7296 * FAILURE : FALSE
7298 static LRESULT LISTVIEW_SetTextBkColor(HWND hwnd, COLORREF clrTextBk)
7300 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7302 infoPtr->clrTextBk = clrTextBk;
7303 InvalidateRect(hwnd, NULL, TRUE);
7305 return TRUE;
7308 /***
7309 * DESCRIPTION:
7310 * Sets the text foreground color.
7312 * PARAMETER(S):
7313 * [I] HWND : window handle
7314 * [I] COLORREF : text color
7316 * RETURN:
7317 * SUCCESS : TRUE
7318 * FAILURE : FALSE
7320 static LRESULT LISTVIEW_SetTextColor (HWND hwnd, COLORREF clrText)
7322 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7324 infoPtr->clrText = clrText;
7325 InvalidateRect(hwnd, NULL, TRUE);
7327 return TRUE;
7330 /* LISTVIEW_SetToolTips */
7331 /* LISTVIEW_SetUnicodeFormat */
7332 /* LISTVIEW_SetWorkAreas */
7334 /***
7335 * DESCRIPTION:
7336 * Callback internally used by LISTVIEW_SortItems()
7338 * PARAMETER(S):
7339 * [I] LPVOID : first LISTVIEW_ITEM to compare
7340 * [I] LPVOID : second LISTVIEW_ITEM to compare
7341 * [I] LPARAM : HWND of control
7343 * RETURN:
7344 * if first comes before second : negative
7345 * if first comes after second : positive
7346 * if first and second are equivalent : zero
7348 static INT WINAPI LISTVIEW_CallBackCompare(
7349 LPVOID first,
7350 LPVOID second,
7351 LPARAM lParam)
7353 /* Forward the call to the client defined callback */
7354 INT rv;
7355 HWND hwnd = (HWND)lParam;
7356 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7357 HDPA hdpa_first = (HDPA) first;
7358 HDPA hdpa_second = (HDPA) second;
7359 LISTVIEW_ITEM* lv_first = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_first, 0 );
7360 LISTVIEW_ITEM* lv_second = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_second, 0 );
7362 rv = (infoPtr->pfnCompare)( lv_first->lParam , lv_second->lParam, infoPtr->lParamSort );
7364 return rv;
7367 /***
7368 * DESCRIPTION:
7369 * Sorts the listview items.
7371 * PARAMETER(S):
7372 * [I] HWND : window handle
7373 * [I] WPARAM : application-defined value
7374 * [I] LPARAM : pointer to comparision callback
7376 * RETURN:
7377 * SUCCESS : TRUE
7378 * FAILURE : FALSE
7380 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam)
7382 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7383 int nCount;
7384 UINT lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7386 if (lStyle & LVS_OWNERDATA)
7387 return FALSE;
7389 if (!infoPtr || !infoPtr->hdpaItems)
7390 return FALSE;
7392 nCount = GETITEMCOUNT(infoPtr);
7393 /* if there are 0 or 1 items, there is no need to sort */
7394 if (nCount > 1)
7396 infoPtr->pfnCompare = (PFNLVCOMPARE)lParam;
7397 infoPtr->lParamSort = (LPARAM)wParam;
7399 DPA_Sort(infoPtr->hdpaItems, LISTVIEW_CallBackCompare, hwnd);
7402 /* align the items */
7403 LISTVIEW_AlignTop(hwnd);
7405 /* refresh the display */
7406 InvalidateRect(hwnd, NULL, TRUE);
7408 return TRUE;
7411 /* LISTVIEW_SubItemHitTest */
7413 /***
7414 * DESCRIPTION:
7415 * Updates an items or rearranges the listview control.
7417 * PARAMETER(S):
7418 * [I] HWND : window handle
7419 * [I] INT : item index
7421 * RETURN:
7422 * SUCCESS : TRUE
7423 * FAILURE : FALSE
7425 static LRESULT LISTVIEW_Update(HWND hwnd, INT nItem)
7427 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7428 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7429 BOOL bResult = FALSE;
7430 RECT rc;
7432 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
7434 bResult = TRUE;
7436 /* rearrange with default alignment style */
7437 if ((lStyle & LVS_AUTOARRANGE) && (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
7438 ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON)))
7440 ListView_Arrange(hwnd, 0);
7442 else
7444 /* get item bounding rectangle */
7445 ListView_GetItemRect(hwnd, nItem, &rc, LVIR_BOUNDS);
7446 InvalidateRect(hwnd, &rc, TRUE);
7450 return bResult;
7453 /***
7454 * DESCRIPTION:
7455 * Creates the listview control.
7457 * PARAMETER(S):
7458 * [I] HWND : window handle
7460 * RETURN:
7461 * Zero
7463 static LRESULT LISTVIEW_Create(HWND hwnd, WPARAM wParam, LPARAM lParam)
7465 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7466 LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam;
7467 UINT uView = lpcs->style & LVS_TYPEMASK;
7468 LOGFONTA logFont;
7470 /* initialize info pointer */
7471 ZeroMemory(infoPtr, sizeof(LISTVIEW_INFO));
7473 /* determine the type of structures to use */
7474 infoPtr->notifyFormat = SendMessageA(GetParent(hwnd), WM_NOTIFYFORMAT,
7475 (WPARAM)hwnd, (LPARAM)NF_QUERY);
7476 if (infoPtr->notifyFormat != NFR_ANSI)
7478 FIXME("ANSI notify format is NOT used\n");
7481 /* initialize color information */
7482 infoPtr->clrBk = GetSysColor(COLOR_WINDOW);
7483 infoPtr->clrText = GetSysColor(COLOR_WINDOWTEXT);
7484 infoPtr->clrTextBk = CLR_DEFAULT;
7486 /* set default values */
7487 infoPtr->uCallbackMask = 0;
7488 infoPtr->nFocusedItem = -1;
7489 infoPtr->nSelectionMark = -1;
7490 infoPtr->nHotItem = -1;
7491 infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING);
7492 infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING);
7493 ZeroMemory(&infoPtr->rcList, sizeof(RECT));
7494 infoPtr->hwndEdit = 0;
7495 infoPtr->pedititem = NULL;
7496 infoPtr->nEditLabelItem = -1;
7498 /* get default font (icon title) */
7499 SystemParametersInfoA(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
7500 infoPtr->hDefaultFont = CreateFontIndirectA(&logFont);
7501 infoPtr->hFont = infoPtr->hDefaultFont;
7503 /* create header */
7504 infoPtr->hwndHeader = CreateWindowA(WC_HEADERA, (LPCSTR)NULL,
7505 WS_CHILD | HDS_HORZ | HDS_BUTTONS,
7506 0, 0, 0, 0, hwnd, (HMENU)0,
7507 lpcs->hInstance, NULL);
7509 /* set header font */
7510 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont,
7511 (LPARAM)TRUE);
7513 if (uView == LVS_ICON)
7515 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
7516 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
7518 else if (uView == LVS_REPORT)
7520 if (!(LVS_NOCOLUMNHEADER & lpcs->style))
7522 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
7524 else
7526 /* set HDS_HIDDEN flag to hide the header bar */
7527 SetWindowLongA(infoPtr->hwndHeader, GWL_STYLE,
7528 GetWindowLongA(infoPtr->hwndHeader, GWL_STYLE) | HDS_HIDDEN);
7532 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7533 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7535 else
7537 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7538 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7541 /* display unsupported listview window styles */
7542 LISTVIEW_UnsupportedStyles(lpcs->style);
7544 /* allocate memory for the data structure */
7545 infoPtr->hdpaItems = DPA_Create(10);
7547 /* allocate memory for the selection ranges */
7548 infoPtr->hdpaSelectionRanges = DPA_Create(10);
7550 /* initialize size of items */
7551 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7552 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7554 /* initialize the hover time to -1(indicating the default system hover time) */
7555 infoPtr->dwHoverTime = -1;
7557 return 0;
7560 /***
7561 * DESCRIPTION:
7562 * Erases the background of the listview control.
7564 * PARAMETER(S):
7565 * [I] HWND : window handle
7566 * [I] WPARAM : device context handle
7567 * [I] LPARAM : not used
7569 * RETURN:
7570 * SUCCESS : TRUE
7571 * FAILURE : FALSE
7573 static LRESULT LISTVIEW_EraseBackground(HWND hwnd, WPARAM wParam,
7574 LPARAM lParam)
7576 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7577 BOOL bResult;
7579 if (infoPtr->clrBk == CLR_NONE)
7581 bResult = SendMessageA(GetParent(hwnd), WM_ERASEBKGND, wParam, lParam);
7583 else
7585 RECT rc;
7586 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
7587 GetClientRect(hwnd, &rc);
7588 FillRect((HDC)wParam, &rc, hBrush);
7589 DeleteObject(hBrush);
7590 bResult = TRUE;
7593 return bResult;
7597 static void LISTVIEW_FillBackground(HWND hwnd, HDC hdc, LPRECT rc)
7599 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7601 if (infoPtr->clrBk != CLR_NONE)
7603 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
7604 FillRect(hdc, rc, hBrush);
7605 DeleteObject(hBrush);
7609 /***
7610 * DESCRIPTION:
7611 * Retrieves the listview control font.
7613 * PARAMETER(S):
7614 * [I] HWND : window handle
7616 * RETURN:
7617 * Font handle.
7619 static LRESULT LISTVIEW_GetFont(HWND hwnd)
7621 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7623 return infoPtr->hFont;
7626 /***
7627 * DESCRIPTION:
7628 * Performs vertical scrolling.
7630 * PARAMETER(S):
7631 * [I] HWND : window handle
7632 * [I] INT : scroll code
7633 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
7634 * or SB_THUMBTRACK.
7635 * [I] HWND : scrollbar control window handle
7637 * RETURN:
7638 * Zero
7640 static LRESULT LISTVIEW_VScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
7641 HWND hScrollWnd)
7643 SCROLLINFO scrollInfo;
7645 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7646 SendMessageA(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
7648 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
7649 scrollInfo.cbSize = sizeof(SCROLLINFO);
7650 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
7652 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
7654 INT nOldScrollPos = scrollInfo.nPos;
7655 switch (nScrollCode)
7657 case SB_LINEUP:
7658 if (scrollInfo.nPos > scrollInfo.nMin)
7660 scrollInfo.nPos--;
7662 break;
7664 case SB_LINEDOWN:
7665 if (scrollInfo.nPos < scrollInfo.nMax)
7667 scrollInfo.nPos++;
7669 break;
7671 case SB_PAGEUP:
7672 if (scrollInfo.nPos > scrollInfo.nMin)
7674 if (scrollInfo.nPos >= scrollInfo.nPage)
7676 scrollInfo.nPos -= scrollInfo.nPage;
7678 else
7680 scrollInfo.nPos = scrollInfo.nMin;
7683 break;
7685 case SB_PAGEDOWN:
7686 if (scrollInfo.nPos < scrollInfo.nMax)
7688 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
7690 scrollInfo.nPos += scrollInfo.nPage;
7692 else
7694 scrollInfo.nPos = scrollInfo.nMax;
7697 break;
7699 case SB_THUMBTRACK:
7700 scrollInfo.nPos = nCurrentPos;
7701 if (scrollInfo.nPos > scrollInfo.nMax)
7702 scrollInfo.nPos=scrollInfo.nMax;
7704 if (scrollInfo.nPos < scrollInfo.nMin)
7705 scrollInfo.nPos=scrollInfo.nMin;
7707 break;
7710 if (nOldScrollPos != scrollInfo.nPos)
7712 scrollInfo.fMask = SIF_POS;
7713 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
7714 InvalidateRect(hwnd, NULL, TRUE);
7718 return 0;
7721 /***
7722 * DESCRIPTION:
7723 * Performs horizontal scrolling.
7725 * PARAMETER(S):
7726 * [I] HWND : window handle
7727 * [I] INT : scroll code
7728 * [I] SHORT : current scroll position if scroll code is SB_THUMBPOSITION
7729 * or SB_THUMBTRACK.
7730 * [I] HWND : scrollbar control window handle
7732 * RETURN:
7733 * Zero
7735 static LRESULT LISTVIEW_HScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
7736 HWND hScrollWnd)
7738 SCROLLINFO scrollInfo;
7740 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7741 SendMessageA(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
7744 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
7745 scrollInfo.cbSize = sizeof(SCROLLINFO);
7746 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
7748 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
7750 INT nOldScrollPos = scrollInfo.nPos;
7752 switch (nScrollCode)
7754 case SB_LINELEFT:
7755 if (scrollInfo.nPos > scrollInfo.nMin)
7757 scrollInfo.nPos--;
7759 break;
7761 case SB_LINERIGHT:
7762 if (scrollInfo.nPos < scrollInfo.nMax)
7764 scrollInfo.nPos++;
7766 break;
7768 case SB_PAGELEFT:
7769 if (scrollInfo.nPos > scrollInfo.nMin)
7771 if (scrollInfo.nPos >= scrollInfo.nPage)
7773 scrollInfo.nPos -= scrollInfo.nPage;
7775 else
7777 scrollInfo.nPos = scrollInfo.nMin;
7780 break;
7782 case SB_PAGERIGHT:
7783 if (scrollInfo.nPos < scrollInfo.nMax)
7785 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
7787 scrollInfo.nPos += scrollInfo.nPage;
7789 else
7791 scrollInfo.nPos = scrollInfo.nMax;
7794 break;
7796 case SB_THUMBTRACK:
7797 scrollInfo.nPos = nCurrentPos;
7799 if (scrollInfo.nPos > scrollInfo.nMax)
7800 scrollInfo.nPos=scrollInfo.nMax;
7802 if (scrollInfo.nPos < scrollInfo.nMin)
7803 scrollInfo.nPos=scrollInfo.nMin;
7804 break;
7807 if (nOldScrollPos != scrollInfo.nPos)
7809 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
7810 scrollInfo.fMask = SIF_POS;
7811 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
7812 if(uView == LVS_REPORT)
7814 scrollInfo.fMask = SIF_POS;
7815 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
7816 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
7818 InvalidateRect(hwnd, NULL, TRUE);
7822 return 0;
7825 static LRESULT LISTVIEW_MouseWheel(HWND hwnd, INT wheelDelta)
7827 INT gcWheelDelta = 0;
7828 UINT pulScrollLines = 3;
7829 SCROLLINFO scrollInfo;
7831 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
7833 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
7834 gcWheelDelta -= wheelDelta;
7836 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
7837 scrollInfo.cbSize = sizeof(SCROLLINFO);
7838 scrollInfo.fMask = SIF_POS | SIF_RANGE;
7840 switch(uView)
7842 case LVS_ICON:
7843 case LVS_SMALLICON:
7845 * listview should be scrolled by a multiple of 37 dependently on its dimension or its visible item number
7846 * should be fixed in the future.
7848 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
7849 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + (gcWheelDelta < 0) ? 37 : -37, 0);
7850 break;
7852 case LVS_REPORT:
7853 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
7855 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
7857 int cLineScroll = min(LISTVIEW_GetCountPerColumn(hwnd), pulScrollLines);
7858 cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
7859 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + cLineScroll, 0);
7862 break;
7864 case LVS_LIST:
7865 LISTVIEW_HScroll(hwnd, (gcWheelDelta < 0) ? SB_LINELEFT : SB_LINERIGHT, 0, 0);
7866 break;
7868 return 0;
7871 /***
7872 * DESCRIPTION:
7873 * ???
7875 * PARAMETER(S):
7876 * [I] HWND : window handle
7877 * [I] INT : virtual key
7878 * [I] LONG : key data
7880 * RETURN:
7881 * Zero
7883 static LRESULT LISTVIEW_KeyDown(HWND hwnd, INT nVirtualKey, LONG lKeyData)
7885 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7886 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
7887 HWND hwndParent = GetParent(hwnd);
7888 NMLVKEYDOWN nmKeyDown;
7889 NMHDR nmh;
7890 INT nItem = -1;
7891 BOOL bRedraw = FALSE;
7892 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7893 UINT uView = lStyle & LVS_TYPEMASK;
7895 /* send LVN_KEYDOWN notification */
7896 ZeroMemory(&nmKeyDown, sizeof(NMLVKEYDOWN));
7897 nmKeyDown.hdr.hwndFrom = hwnd;
7898 nmKeyDown.hdr.idFrom = nCtrlId;
7899 nmKeyDown.hdr.code = LVN_KEYDOWN;
7900 nmKeyDown.wVKey = nVirtualKey;
7901 nmKeyDown.flags = 0;
7902 SendMessageA(hwndParent, WM_NOTIFY, (WPARAM)nCtrlId, (LPARAM)&nmKeyDown);
7904 /* initialize */
7905 nmh.hwndFrom = hwnd;
7906 nmh.idFrom = nCtrlId;
7908 switch (nVirtualKey)
7910 case VK_RETURN:
7911 if ((GETITEMCOUNT(infoPtr) > 0) && (infoPtr->nFocusedItem != -1))
7913 /* send NM_RETURN notification */
7914 nmh.code = NM_RETURN;
7915 ListView_Notify(hwndParent, nCtrlId, &nmh);
7917 /* send LVN_ITEMACTIVATE notification */
7918 nmh.code = LVN_ITEMACTIVATE;
7919 ListView_Notify(hwndParent, nCtrlId, &nmh);
7921 break;
7923 case VK_HOME:
7924 if (GETITEMCOUNT(infoPtr) > 0)
7926 nItem = 0;
7928 break;
7930 case VK_END:
7931 if (GETITEMCOUNT(infoPtr) > 0)
7933 nItem = GETITEMCOUNT(infoPtr) - 1;
7935 break;
7937 case VK_LEFT:
7938 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TOLEFT);
7939 break;
7941 case VK_UP:
7942 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_ABOVE);
7943 break;
7945 case VK_RIGHT:
7946 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TORIGHT);
7947 break;
7949 case VK_DOWN:
7950 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_BELOW);
7951 break;
7953 case VK_PRIOR:
7954 if (uView == LVS_REPORT)
7956 nItem = infoPtr->nFocusedItem - LISTVIEW_GetCountPerColumn(hwnd);
7958 else
7960 nItem = infoPtr->nFocusedItem - LISTVIEW_GetCountPerColumn(hwnd)
7961 * LISTVIEW_GetCountPerRow(hwnd);
7963 if(nItem < 0) nItem = 0;
7964 break;
7966 case VK_NEXT:
7967 if (uView == LVS_REPORT)
7969 nItem = infoPtr->nFocusedItem + LISTVIEW_GetCountPerColumn(hwnd);
7971 else
7973 nItem = infoPtr->nFocusedItem + LISTVIEW_GetCountPerColumn(hwnd)
7974 * LISTVIEW_GetCountPerRow(hwnd);
7976 if(nItem >= GETITEMCOUNT(infoPtr)) nItem = GETITEMCOUNT(infoPtr) - 1;
7977 break;
7980 if ((nItem != -1) && (nItem != infoPtr->nFocusedItem))
7982 bRedraw = LISTVIEW_KeySelection(hwnd, nItem);
7983 if (bRedraw != FALSE)
7985 /* refresh client area */
7986 UpdateWindow(hwnd);
7990 return 0;
7993 /***
7994 * DESCRIPTION:
7995 * Kills the focus.
7997 * PARAMETER(S):
7998 * [I] HWND : window handle
8000 * RETURN:
8001 * Zero
8003 static LRESULT LISTVIEW_KillFocus(HWND hwnd)
8005 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
8006 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8007 NMHDR nmh;
8008 INT i,nTop,nBottom;
8009 RECT rcItem;
8010 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8011 UINT uView = lStyle & LVS_TYPEMASK;
8013 TRACE("(hwnd=%x)\n", hwnd);
8015 /* send NM_KILLFOCUS notification */
8016 nmh.hwndFrom = hwnd;
8017 nmh.idFrom = nCtrlId;
8018 nmh.code = NM_KILLFOCUS;
8019 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8021 /* set window focus flag */
8022 infoPtr->bFocus = FALSE;
8024 /* NEED drawing optimization ; redraw the selected items */
8025 if (uView & LVS_REPORT)
8027 nTop = LISTVIEW_GetTopIndex(hwnd);
8028 nBottom = nTop +
8029 LISTVIEW_GetCountPerColumn(hwnd) + 1;
8031 else
8033 nTop = 0;
8034 nBottom = GETITEMCOUNT(infoPtr);
8036 for (i = nTop; i<nBottom; i++)
8038 if (LISTVIEW_IsSelected(hwnd,i))
8040 rcItem.left = LVIR_BOUNDS;
8041 LISTVIEW_GetItemRect(hwnd, i, &rcItem);
8042 InvalidateRect(hwnd, &rcItem, FALSE);
8046 return 0;
8049 /***
8050 * DESCRIPTION:
8051 * Processes double click messages (left mouse button).
8053 * PARAMETER(S):
8054 * [I] HWND : window handle
8055 * [I] WORD : key flag
8056 * [I] WORD : x coordinate
8057 * [I] WORD : y coordinate
8059 * RETURN:
8060 * Zero
8062 static LRESULT LISTVIEW_LButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
8063 WORD wPosY)
8065 LONG nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8066 LVHITTESTINFO htInfo;
8067 NMHDR nmh;
8068 NMLISTVIEW nmlv;
8069 INT ret;
8071 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8073 htInfo.pt.x = wPosX;
8074 htInfo.pt.y = wPosY;
8076 /* send NM_DBLCLK notification */
8077 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
8078 nmlv.hdr.hwndFrom = hwnd;
8079 nmlv.hdr.idFrom = nCtrlId;
8080 nmlv.hdr.code = NM_DBLCLK;
8081 ret = LISTVIEW_HitTestItem(hwnd, &htInfo, TRUE);
8082 if (ret != -1)
8084 nmlv.iItem = htInfo.iItem;
8085 nmlv.iSubItem = htInfo.iSubItem;
8087 else
8089 nmlv.iItem = -1;
8090 nmlv.iSubItem = 0;
8092 nmlv.ptAction.x = wPosX;
8093 nmlv.ptAction.y = wPosY;
8094 ListView_LVNotify(GetParent(hwnd), nCtrlId, &nmlv);
8097 /* To send the LVN_ITEMACTIVATE, it must be on an Item */
8098 if(ret != -1)
8100 /* send LVN_ITEMACTIVATE notification */
8101 nmh.hwndFrom = hwnd;
8102 nmh.idFrom = nCtrlId;
8103 nmh.code = LVN_ITEMACTIVATE;
8104 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8107 return 0;
8110 /***
8111 * DESCRIPTION:
8112 * Processes mouse down messages (left mouse button).
8114 * PARAMETER(S):
8115 * [I] HWND : window handle
8116 * [I] WORD : key flag
8117 * [I] WORD : x coordinate
8118 * [I] WORD : y coordinate
8120 * RETURN:
8121 * Zero
8123 static LRESULT LISTVIEW_LButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
8124 WORD wPosY)
8126 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8127 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8128 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8129 static BOOL bGroupSelect = TRUE;
8130 POINT ptPosition;
8131 NMHDR nmh;
8132 INT nItem;
8134 TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd, wKey, wPosX,
8135 wPosY);
8137 /* send NM_RELEASEDCAPTURE notification */
8138 nmh.hwndFrom = hwnd;
8139 nmh.idFrom = nCtrlId;
8140 nmh.code = NM_RELEASEDCAPTURE;
8141 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8143 if (infoPtr->bFocus == FALSE)
8145 SetFocus(hwnd);
8148 /* set left button down flag */
8149 infoPtr->bLButtonDown = TRUE;
8151 ptPosition.x = wPosX;
8152 ptPosition.y = wPosY;
8153 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
8154 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
8156 if (lStyle & LVS_SINGLESEL)
8158 if ((ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
8159 && infoPtr->nEditLabelItem == -1)
8161 infoPtr->nEditLabelItem = nItem;
8163 else
8165 LISTVIEW_SetSelection(hwnd, nItem);
8168 else
8170 if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
8172 if (bGroupSelect != FALSE)
8174 LISTVIEW_AddGroupSelection(hwnd, nItem);
8176 else
8178 LISTVIEW_AddSelection(hwnd, nItem);
8181 else if (wKey & MK_CONTROL)
8183 bGroupSelect = LISTVIEW_ToggleSelection(hwnd, nItem);
8185 else if (wKey & MK_SHIFT)
8187 LISTVIEW_SetGroupSelection(hwnd, nItem);
8189 else
8191 BOOL was_selected =
8192 (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED);
8194 /* set selection (clears other pre-existing selections) */
8195 LISTVIEW_SetSelection(hwnd, nItem);
8197 if (was_selected && infoPtr->nEditLabelItem == -1)
8199 infoPtr->nEditLabelItem = nItem;
8204 else
8206 /* remove all selections */
8207 LISTVIEW_RemoveAllSelections(hwnd);
8210 /* redraw if we could have possibly selected something */
8211 if(!GETITEMCOUNT(infoPtr)) InvalidateRect(hwnd, NULL, TRUE);
8213 return 0;
8216 /***
8217 * DESCRIPTION:
8218 * Processes mouse up messages (left mouse button).
8220 * PARAMETER(S):
8221 * [I] HWND : window handle
8222 * [I] WORD : key flag
8223 * [I] WORD : x coordinate
8224 * [I] WORD : y coordinate
8226 * RETURN:
8227 * Zero
8229 static LRESULT LISTVIEW_LButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
8230 WORD wPosY)
8232 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8234 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8236 if (infoPtr->bLButtonDown != FALSE)
8238 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8239 NMLISTVIEW nmlv;
8240 LVHITTESTINFO lvHitTestInfo;
8241 INT ret;
8243 lvHitTestInfo.pt.x = wPosX;
8244 lvHitTestInfo.pt.y = wPosY;
8246 /* send NM_CLICK notification */
8247 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
8248 nmlv.hdr.hwndFrom = hwnd;
8249 nmlv.hdr.idFrom = nCtrlId;
8250 nmlv.hdr.code = NM_CLICK;
8251 ret = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo, TRUE);
8252 if (ret != -1)
8254 nmlv.iItem = lvHitTestInfo.iItem;
8255 nmlv.iSubItem = lvHitTestInfo.iSubItem;
8257 else
8259 nmlv.iItem = -1;
8260 nmlv.iSubItem = 0;
8262 nmlv.ptAction.x = wPosX;
8263 nmlv.ptAction.y = wPosY;
8264 ListView_LVNotify(GetParent(hwnd), nCtrlId, &nmlv);
8267 /* set left button flag */
8268 infoPtr->bLButtonDown = FALSE;
8270 if(infoPtr->nEditLabelItem != -1)
8272 if(lvHitTestInfo.iItem == infoPtr->nEditLabelItem)
8274 LISTVIEW_EditLabelA(hwnd, lvHitTestInfo.iItem);
8276 infoPtr->nEditLabelItem = -1;
8280 return 0;
8283 /***
8284 * DESCRIPTION:
8285 * Creates the listview control (called before WM_CREATE).
8287 * PARAMETER(S):
8288 * [I] HWND : window handle
8289 * [I] WPARAM : unhandled
8290 * [I] LPARAM : widow creation info
8292 * RETURN:
8293 * Zero
8295 static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
8297 LISTVIEW_INFO *infoPtr;
8299 TRACE("(hwnd=%x,wParam=%x,lParam=%lx)\n", hwnd, wParam, lParam);
8301 /* allocate memory for info structure */
8302 infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc(sizeof(LISTVIEW_INFO));
8303 SetWindowLongA(hwnd, 0, (LONG)infoPtr);
8304 if (infoPtr == NULL)
8306 ERR("could not allocate info memory!\n");
8307 return 0;
8310 if ((LISTVIEW_INFO *)GetWindowLongA(hwnd, 0) != infoPtr)
8312 ERR("pointer assignment error!\n");
8313 return 0;
8316 return DefWindowProcA(hwnd, WM_NCCREATE, wParam, lParam);
8319 /***
8320 * DESCRIPTION:
8321 * Destroys the listview control (called after WM_DESTROY).
8323 * PARAMETER(S):
8324 * [I] HWND : window handle
8326 * RETURN:
8327 * Zero
8329 static LRESULT LISTVIEW_NCDestroy(HWND hwnd)
8331 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8333 TRACE("(hwnd=%x)\n", hwnd);
8335 /* delete all items */
8336 LISTVIEW_DeleteAllItems(hwnd);
8338 /* destroy data structure */
8339 DPA_Destroy(infoPtr->hdpaItems);
8340 DPA_Destroy(infoPtr->hdpaSelectionRanges);
8342 /* destroy font */
8343 infoPtr->hFont = (HFONT)0;
8344 if (infoPtr->hDefaultFont)
8346 DeleteObject(infoPtr->hDefaultFont);
8349 /* free listview info pointer*/
8350 COMCTL32_Free(infoPtr);
8352 SetWindowLongA(hwnd, 0, 0);
8353 return 0;
8356 /***
8357 * DESCRIPTION:
8358 * Handles notifications from children.
8360 * PARAMETER(S):
8361 * [I] HWND : window handle
8362 * [I] INT : control identifier
8363 * [I] LPNMHDR : notification information
8365 * RETURN:
8366 * Zero
8368 static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh)
8370 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8372 if (lpnmh->hwndFrom == infoPtr->hwndHeader)
8374 /* handle notification from header control */
8375 if (lpnmh->code == HDN_ENDTRACKA)
8377 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8378 InvalidateRect(hwnd, NULL, TRUE);
8380 else if(lpnmh->code == HDN_ITEMCLICKA)
8382 /* Handle sorting by Header Column */
8383 NMLISTVIEW nmlv;
8384 LPNMHEADERA pnmHeader = (LPNMHEADERA) lpnmh;
8385 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
8387 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
8388 nmlv.hdr.hwndFrom = hwnd;
8389 nmlv.hdr.idFrom = lCtrlId;
8390 nmlv.hdr.code = LVN_COLUMNCLICK;
8391 nmlv.iItem = -1;
8392 nmlv.iSubItem = pnmHeader->iItem;
8394 ListView_LVNotify(GetParent(hwnd),lCtrlId, &nmlv);
8397 else if(lpnmh->code == NM_RELEASEDCAPTURE)
8399 /* Idealy this should be done in HDN_ENDTRACKA
8400 * but since SetItemBounds in Header.c is called after
8401 * the notification is sent, it is neccessary to handle the
8402 * update of the scroll bar here (Header.c works fine as it is,
8403 * no need to disturb it)
8405 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8406 LISTVIEW_UpdateScroll(hwnd);
8407 InvalidateRect(hwnd, NULL, TRUE);
8412 return 0;
8415 /***
8416 * DESCRIPTION:
8417 * Determines the type of structure to use.
8419 * PARAMETER(S):
8420 * [I] HWND : window handle of the sender
8421 * [I] HWND : listview window handle
8422 * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
8424 * RETURN:
8425 * Zero
8427 static LRESULT LISTVIEW_NotifyFormat(HWND hwndFrom, HWND hwnd, INT nCommand)
8429 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8431 if (nCommand == NF_REQUERY)
8433 /* determine the type of structure to use */
8434 infoPtr->notifyFormat = SendMessageA(hwndFrom, WM_NOTIFYFORMAT,
8435 (WPARAM)hwnd, (LPARAM)NF_QUERY);
8436 if (infoPtr->notifyFormat == NFR_UNICODE)
8438 FIXME("NO support for unicode structures");
8442 return 0;
8445 /***
8446 * DESCRIPTION:
8447 * Paints/Repaints the listview control.
8449 * PARAMETER(S):
8450 * [I] HWND : window handle
8451 * [I] HDC : device context handle
8453 * RETURN:
8454 * Zero
8456 static LRESULT LISTVIEW_Paint(HWND hwnd, HDC hdc)
8458 PAINTSTRUCT ps;
8460 TRACE("(hwnd=%x,hdc=%x)\n", hwnd, hdc);
8462 if (hdc == 0)
8464 hdc = BeginPaint(hwnd, &ps);
8465 LISTVIEW_Refresh(hwnd, hdc);
8466 EndPaint(hwnd, &ps);
8468 else
8470 LISTVIEW_Refresh(hwnd, hdc);
8473 return 0;
8476 /***
8477 * DESCRIPTION:
8478 * Processes double click messages (right mouse button).
8480 * PARAMETER(S):
8481 * [I] HWND : window handle
8482 * [I] WORD : key flag
8483 * [I] WORD : x coordinate
8484 * [I] WORD : y coordinate
8486 * RETURN:
8487 * Zero
8489 static LRESULT LISTVIEW_RButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
8490 WORD wPosY)
8492 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8493 NMHDR nmh;
8495 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8497 /* send NM_RELEASEDCAPTURE notification */
8498 nmh.hwndFrom = hwnd;
8499 nmh.idFrom = nCtrlId;
8500 nmh.code = NM_RELEASEDCAPTURE;
8501 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8503 /* send NM_RDBLCLK notification */
8504 nmh.code = NM_RDBLCLK;
8505 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8507 return 0;
8510 /***
8511 * DESCRIPTION:
8512 * Processes mouse down messages (right mouse button).
8514 * PARAMETER(S):
8515 * [I] HWND : window handle
8516 * [I] WORD : key flag
8517 * [I] WORD : x coordinate
8518 * [I] WORD : y coordinate
8520 * RETURN:
8521 * Zero
8523 static LRESULT LISTVIEW_RButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
8524 WORD wPosY)
8526 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8527 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8528 POINT ptPosition;
8529 NMHDR nmh;
8530 INT nItem;
8532 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8534 /* send NM_RELEASEDCAPTURE notification */
8535 nmh.hwndFrom = hwnd;
8536 nmh.idFrom = nCtrlId;
8537 nmh.code = NM_RELEASEDCAPTURE;
8538 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8540 /* make sure the listview control window has the focus */
8541 if (infoPtr->bFocus == FALSE)
8543 SetFocus(hwnd);
8546 /* set right button down flag */
8547 infoPtr->bRButtonDown = TRUE;
8549 /* determine the index of the selected item */
8550 ptPosition.x = wPosX;
8551 ptPosition.y = wPosY;
8552 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
8553 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
8555 LISTVIEW_SetItemFocus(hwnd,nItem);
8556 if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)) &&
8557 !LISTVIEW_IsSelected(hwnd,nItem))
8559 LISTVIEW_SetSelection(hwnd, nItem);
8562 else
8564 LISTVIEW_RemoveAllSelections(hwnd);
8567 return 0;
8570 /***
8571 * DESCRIPTION:
8572 * Processes mouse up messages (right mouse button).
8574 * PARAMETER(S):
8575 * [I] HWND : window handle
8576 * [I] WORD : key flag
8577 * [I] WORD : x coordinate
8578 * [I] WORD : y coordinate
8580 * RETURN:
8581 * Zero
8583 static LRESULT LISTVIEW_RButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
8584 WORD wPosY)
8586 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8587 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8589 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
8591 if (infoPtr->bRButtonDown != FALSE)
8593 NMLISTVIEW nmlv;
8594 LVHITTESTINFO lvHitTestInfo;
8595 POINT pt;
8596 INT ret;
8598 lvHitTestInfo.pt.x = wPosX;
8599 lvHitTestInfo.pt.y = wPosY;
8601 /* Send NM_RClICK notification */
8602 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
8603 nmlv.hdr.hwndFrom = hwnd;
8604 nmlv.hdr.idFrom = nCtrlId;
8605 nmlv.hdr.code = NM_RCLICK;
8606 ret = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo, TRUE);
8607 if (ret != -1)
8609 nmlv.iItem = lvHitTestInfo.iItem;
8610 nmlv.iSubItem = lvHitTestInfo.iSubItem;
8612 else
8614 nmlv.iItem = -1;
8615 nmlv.iSubItem = 0;
8617 nmlv.ptAction.x = wPosX;
8618 nmlv.ptAction.y = wPosY;
8619 ListView_LVNotify(GetParent(hwnd), nCtrlId, &nmlv);
8621 pt.x = wPosX;
8622 pt.y = wPosY;
8624 /* set button flag */
8625 infoPtr->bRButtonDown = FALSE;
8627 /* Change to screen coordinate for WM_CONTEXTMENU */
8628 ClientToScreen(hwnd, &pt);
8630 /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
8631 SendMessageA( hwnd, WM_CONTEXTMENU, (WPARAM) hwnd, MAKELPARAM(pt.x, pt.y));
8634 return 0;
8637 /***
8638 * DESCRIPTION:
8639 * Sets the focus.
8641 * PARAMETER(S):
8642 * [I] HWND : window handle
8643 * [I] HWND : window handle of previously focused window
8645 * RETURN:
8646 * Zero
8648 static LRESULT LISTVIEW_SetFocus(HWND hwnd, HWND hwndLoseFocus)
8650 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8651 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
8652 NMHDR nmh;
8654 TRACE("(hwnd=%x, hwndLoseFocus=%x)\n", hwnd, hwndLoseFocus);
8656 /* send NM_SETFOCUS notification */
8657 nmh.hwndFrom = hwnd;
8658 nmh.idFrom = nCtrlId;
8659 nmh.code = NM_SETFOCUS;
8660 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
8662 /* set window focus flag */
8663 infoPtr->bFocus = TRUE;
8665 UpdateWindow(hwnd);
8667 return 0;
8670 /***
8671 * DESCRIPTION:
8672 * Sets the font.
8674 * PARAMETER(S):
8675 * [I] HWND : window handle
8676 * [I] HFONT : font handle
8677 * [I] WORD : redraw flag
8679 * RETURN:
8680 * Zero
8682 static LRESULT LISTVIEW_SetFont(HWND hwnd, HFONT hFont, WORD fRedraw)
8684 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8685 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
8687 TRACE("(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd, hFont, fRedraw);
8689 if (hFont == 0)
8691 infoPtr->hFont = infoPtr->hDefaultFont;
8693 else
8695 infoPtr->hFont = hFont;
8698 if (uView == LVS_REPORT)
8700 /* set header font */
8701 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont,
8702 MAKELPARAM(fRedraw, 0));
8705 /* invalidate listview control client area */
8706 InvalidateRect(hwnd, NULL, TRUE);
8708 if (fRedraw != FALSE)
8710 UpdateWindow(hwnd);
8713 return 0;
8716 /***
8717 * DESCRIPTION:
8718 * Message handling for WM_SETREDRAW.
8719 * For the Listview, it invalidates the entire window (the doc specifies otherwise)
8721 * PARAMETER(S):
8722 * [I] HWND : window handle
8723 * [I] bRedraw: state of redraw flag
8725 * RETURN:
8726 * DefWinProc return value
8728 static LRESULT LISTVIEW_SetRedraw(HWND hwnd, BOOL bRedraw)
8730 LRESULT lResult;
8731 lResult = DefWindowProcA(hwnd, WM_SETREDRAW, bRedraw, 0);
8732 if(bRedraw)
8734 RedrawWindow(hwnd, NULL, 0,
8735 RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN | RDW_ERASENOW);
8737 return lResult;
8740 /***
8741 * DESCRIPTION:
8742 * Resizes the listview control. This function processes WM_SIZE
8743 * messages. At this time, the width and height are not used.
8745 * PARAMETER(S):
8746 * [I] HWND : window handle
8747 * [I] WORD : new width
8748 * [I] WORD : new height
8750 * RETURN:
8751 * Zero
8753 static LRESULT LISTVIEW_Size(HWND hwnd, int Width, int Height)
8755 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8756 UINT uView = lStyle & LVS_TYPEMASK;
8758 TRACE("(hwnd=%x, width=%d, height=%d)\n",hwnd, Width, Height);
8760 LISTVIEW_UpdateSize(hwnd);
8762 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
8764 if (lStyle & LVS_ALIGNLEFT)
8766 LISTVIEW_AlignLeft(hwnd);
8768 else
8770 LISTVIEW_AlignTop(hwnd);
8774 LISTVIEW_UpdateScroll(hwnd);
8776 /* invalidate client area + erase background */
8777 InvalidateRect(hwnd, NULL, TRUE);
8779 return 0;
8782 /***
8783 * DESCRIPTION:
8784 * Sets the size information.
8786 * PARAMETER(S):
8787 * [I] HWND : window handle
8789 * RETURN:
8790 * Zero
8792 static VOID LISTVIEW_UpdateSize(HWND hwnd)
8794 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8795 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
8796 UINT uView = lStyle & LVS_TYPEMASK;
8797 RECT rcList;
8799 GetClientRect(hwnd, &rcList);
8800 infoPtr->rcList.left = 0;
8801 infoPtr->rcList.right = max(rcList.right - rcList.left, 1);
8802 infoPtr->rcList.top = 0;
8803 infoPtr->rcList.bottom = max(rcList.bottom - rcList.top, 1);
8805 if (uView == LVS_LIST)
8807 if (lStyle & WS_HSCROLL)
8809 INT nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
8810 if (infoPtr->rcList.bottom > nHScrollHeight)
8812 infoPtr->rcList.bottom -= nHScrollHeight;
8816 else if (uView == LVS_REPORT)
8818 HDLAYOUT hl;
8819 WINDOWPOS wp;
8821 hl.prc = &rcList;
8822 hl.pwpos = &wp;
8823 Header_Layout(infoPtr->hwndHeader, &hl);
8825 SetWindowPos(wp.hwnd, wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
8827 if (!(LVS_NOCOLUMNHEADER & lStyle))
8829 infoPtr->rcList.top = max(wp.cy, 0);
8834 /***
8835 * DESCRIPTION:
8836 * Processes WM_STYLECHANGED messages.
8838 * PARAMETER(S):
8839 * [I] HWND : window handle
8840 * [I] WPARAM : window style type (normal or extended)
8841 * [I] LPSTYLESTRUCT : window style information
8843 * RETURN:
8844 * Zero
8846 static INT LISTVIEW_StyleChanged(HWND hwnd, WPARAM wStyleType,
8847 LPSTYLESTRUCT lpss)
8849 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8850 UINT uNewView = lpss->styleNew & LVS_TYPEMASK;
8851 UINT uOldView = lpss->styleOld & LVS_TYPEMASK;
8852 RECT rcList = infoPtr->rcList;
8854 TRACE("(hwnd=%x, styletype=%x, stylestruct=%p)\n",
8855 hwnd, wStyleType, lpss);
8857 if (wStyleType == GWL_STYLE)
8859 if (uOldView == LVS_REPORT)
8861 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
8864 if ((lpss->styleOld & WS_HSCROLL) != 0)
8866 ShowScrollBar(hwnd, SB_HORZ, FALSE);
8869 if ((lpss->styleOld & WS_VSCROLL) != 0)
8871 ShowScrollBar(hwnd, SB_VERT, FALSE);
8874 if (uNewView == LVS_ICON)
8876 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
8877 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
8878 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8879 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8880 if (lpss->styleNew & LVS_ALIGNLEFT)
8882 LISTVIEW_AlignLeft(hwnd);
8884 else
8886 LISTVIEW_AlignTop(hwnd);
8889 else if (uNewView == LVS_REPORT)
8891 HDLAYOUT hl;
8892 WINDOWPOS wp;
8894 hl.prc = &rcList;
8895 hl.pwpos = &wp;
8896 Header_Layout(infoPtr->hwndHeader, &hl);
8897 SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, wp.cy,
8898 wp.flags);
8899 if (!(LVS_NOCOLUMNHEADER & lpss->styleNew))
8900 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
8902 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
8903 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
8904 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8905 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8907 else if (uNewView == LVS_LIST)
8909 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
8910 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
8911 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8912 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8914 else
8916 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
8917 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
8918 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
8919 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
8920 if (lpss->styleNew & LVS_ALIGNLEFT)
8922 LISTVIEW_AlignLeft(hwnd);
8924 else
8926 LISTVIEW_AlignTop(hwnd);
8930 /* update the size of the client area */
8931 LISTVIEW_UpdateSize(hwnd);
8933 /* add scrollbars if needed */
8934 LISTVIEW_UpdateScroll(hwnd);
8936 /* invalidate client area + erase background */
8937 InvalidateRect(hwnd, NULL, TRUE);
8939 /* print the list of unsupported window styles */
8940 LISTVIEW_UnsupportedStyles(lpss->styleNew);
8943 /* If they change the view and we have an active edit control
8944 we will need to kill the control since the redraw will
8945 misplace the edit control.
8947 if (infoPtr->hwndEdit &&
8948 ((uNewView & (LVS_ICON|LVS_LIST|LVS_SMALLICON)) !=
8949 ((LVS_ICON|LVS_LIST|LVS_SMALLICON) & uOldView)))
8951 SendMessageA(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
8954 return 0;
8957 /***
8958 * DESCRIPTION:
8959 * Window procedure of the listview control.
8962 static LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
8963 LPARAM lParam)
8965 TRACE("hwnd=%x uMsg=%x wParam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam);
8966 if (!GetWindowLongA(hwnd, 0) && (uMsg != WM_NCCREATE))
8967 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
8968 switch (uMsg)
8970 case LVM_APPROXIMATEVIEWRECT:
8971 return LISTVIEW_ApproximateViewRect(hwnd, (INT)wParam,
8972 LOWORD(lParam), HIWORD(lParam));
8973 case LVM_ARRANGE:
8974 return LISTVIEW_Arrange(hwnd, (INT)wParam);
8976 /* case LVM_CREATEDRAGIMAGE: */
8978 case LVM_DELETEALLITEMS:
8979 return LISTVIEW_DeleteAllItems(hwnd);
8981 case LVM_DELETECOLUMN:
8982 return LISTVIEW_DeleteColumn(hwnd, (INT)wParam);
8984 case LVM_DELETEITEM:
8985 return LISTVIEW_DeleteItem(hwnd, (INT)wParam);
8987 case LVM_EDITLABELW:
8988 case LVM_EDITLABELA:
8989 return LISTVIEW_EditLabelA(hwnd, (INT)wParam);
8991 case LVM_ENSUREVISIBLE:
8992 return LISTVIEW_EnsureVisible(hwnd, (INT)wParam, (BOOL)lParam);
8994 case LVM_FINDITEMA:
8995 return LISTVIEW_FindItem(hwnd, (INT)wParam, (LPLVFINDINFO)lParam);
8997 case LVM_GETBKCOLOR:
8998 return LISTVIEW_GetBkColor(hwnd);
9000 /* case LVM_GETBKIMAGE: */
9002 case LVM_GETCALLBACKMASK:
9003 return LISTVIEW_GetCallbackMask(hwnd);
9005 case LVM_GETCOLUMNA:
9006 return LISTVIEW_GetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
9008 /* case LVM_GETCOLUMNW: */
9010 case LVM_GETCOLUMNORDERARRAY:
9011 return LISTVIEW_GetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
9013 case LVM_GETCOLUMNWIDTH:
9014 return LISTVIEW_GetColumnWidth(hwnd, (INT)wParam);
9016 case LVM_GETCOUNTPERPAGE:
9017 return LISTVIEW_GetCountPerPage(hwnd);
9019 case LVM_GETEDITCONTROL:
9020 return LISTVIEW_GetEditControl(hwnd);
9022 case LVM_GETEXTENDEDLISTVIEWSTYLE:
9023 return LISTVIEW_GetExtendedListViewStyle(hwnd);
9025 case LVM_GETHEADER:
9026 return LISTVIEW_GetHeader(hwnd);
9028 /* case LVM_GETHOTCURSOR: */
9030 case LVM_GETHOTITEM:
9031 return LISTVIEW_GetHotItem(hwnd);
9033 case LVM_GETHOVERTIME:
9034 return LISTVIEW_GetHoverTime(hwnd);
9036 case LVM_GETIMAGELIST:
9037 return LISTVIEW_GetImageList(hwnd, (INT)wParam);
9039 /* case LVM_GETISEARCHSTRING: */
9041 case LVM_GETITEMA:
9042 return LISTVIEW_GetItemA(hwnd, (LPLVITEMA)lParam, FALSE);
9044 /* case LVM_GETITEMW: */
9046 case LVM_GETITEMCOUNT:
9047 return LISTVIEW_GetItemCount(hwnd);
9049 case LVM_GETITEMPOSITION:
9050 return LISTVIEW_GetItemPosition(hwnd, (INT)wParam, (LPPOINT)lParam);
9052 case LVM_GETITEMRECT:
9053 return LISTVIEW_GetItemRect(hwnd, (INT)wParam, (LPRECT)lParam);
9055 case LVM_GETITEMSPACING:
9056 return LISTVIEW_GetItemSpacing(hwnd, (BOOL)wParam);
9058 case LVM_GETITEMSTATE:
9059 return LISTVIEW_GetItemState(hwnd, (INT)wParam, (UINT)lParam);
9061 case LVM_GETITEMTEXTA:
9062 LISTVIEW_GetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
9063 break;
9065 /* case LVM_GETITEMTEXTW: */
9067 case LVM_GETNEXTITEM:
9068 return LISTVIEW_GetNextItem(hwnd, (INT)wParam, LOWORD(lParam));
9070 /* case LVM_GETNUMBEROFWORKAREAS: */
9072 case LVM_GETORIGIN:
9073 return LISTVIEW_GetOrigin(hwnd, (LPPOINT)lParam);
9075 case LVM_GETSELECTEDCOUNT:
9076 return LISTVIEW_GetSelectedCount(hwnd);
9078 case LVM_GETSELECTIONMARK:
9079 return LISTVIEW_GetSelectionMark(hwnd);
9081 case LVM_GETSTRINGWIDTHA:
9082 return LISTVIEW_GetStringWidthA (hwnd, (LPCSTR)lParam);
9084 /* case LVM_GETSTRINGWIDTHW: */
9085 /* case LVM_GETSUBITEMRECT: */
9087 case LVM_GETTEXTBKCOLOR:
9088 return LISTVIEW_GetTextBkColor(hwnd);
9090 case LVM_GETTEXTCOLOR:
9091 return LISTVIEW_GetTextColor(hwnd);
9093 /* case LVM_GETTOOLTIPS: */
9095 case LVM_GETTOPINDEX:
9096 return LISTVIEW_GetTopIndex(hwnd);
9098 /* case LVM_GETUNICODEFORMAT: */
9100 case LVM_GETVIEWRECT:
9101 return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam);
9103 /* case LVM_GETWORKAREAS: */
9105 case LVM_HITTEST:
9106 return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam);
9108 case LVM_INSERTCOLUMNA:
9109 return LISTVIEW_InsertColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
9111 case LVM_INSERTCOLUMNW:
9112 return LISTVIEW_InsertColumnW(hwnd, (INT)wParam, (LPLVCOLUMNW)lParam);
9114 case LVM_INSERTITEMA:
9115 return LISTVIEW_InsertItemA(hwnd, (LPLVITEMA)lParam);
9117 case LVM_INSERTITEMW:
9118 return LISTVIEW_InsertItemW(hwnd, (LPLVITEMW)lParam);
9120 case LVM_REDRAWITEMS:
9121 return LISTVIEW_RedrawItems(hwnd, (INT)wParam, (INT)lParam);
9123 /* case LVM_SCROLL: */
9124 /* return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); */
9126 case LVM_SETBKCOLOR:
9127 return LISTVIEW_SetBkColor(hwnd, (COLORREF)lParam);
9129 /* case LVM_SETBKIMAGE: */
9131 case LVM_SETCALLBACKMASK:
9132 return LISTVIEW_SetCallbackMask(hwnd, (UINT)wParam);
9134 case LVM_SETCOLUMNA:
9135 return LISTVIEW_SetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
9137 case LVM_SETCOLUMNW:
9138 FIXME("Unimplemented msg LVM_SETCOLUMNW\n");
9139 return 0;
9141 case LVM_SETCOLUMNORDERARRAY:
9142 return LISTVIEW_SetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
9144 case LVM_SETCOLUMNWIDTH:
9145 return LISTVIEW_SetColumnWidth(hwnd, (INT)wParam, SLOWORD(lParam));
9147 case LVM_SETEXTENDEDLISTVIEWSTYLE:
9148 return LISTVIEW_SetExtendedListViewStyle(hwnd, (DWORD)wParam, (DWORD)lParam);
9150 /* case LVM_SETHOTCURSOR: */
9152 case LVM_SETHOTITEM:
9153 return LISTVIEW_SetHotItem(hwnd, (INT)wParam);
9155 case LVM_SETHOVERTIME:
9156 return LISTVIEW_SetHoverTime(hwnd, (DWORD)wParam);
9158 /* case LVM_SETICONSPACING: */
9160 case LVM_SETIMAGELIST:
9161 return LISTVIEW_SetImageList(hwnd, (INT)wParam, (HIMAGELIST)lParam);
9163 case LVM_SETITEMA:
9164 return LISTVIEW_SetItemA(hwnd, (LPLVITEMA)lParam);
9166 /* case LVM_SETITEMW: */
9168 case LVM_SETITEMCOUNT:
9169 return LISTVIEW_SetItemCount(hwnd, (INT)wParam, (DWORD)lParam);
9171 case LVM_SETITEMPOSITION:
9172 return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, (INT)LOWORD(lParam),
9173 (INT)HIWORD(lParam));
9175 case LVM_SETITEMPOSITION32:
9176 return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, ((POINT*)lParam)->x,
9177 ((POINT*)lParam)->y);
9179 case LVM_SETITEMSTATE:
9180 return LISTVIEW_SetItemState(hwnd, (INT)wParam, (LPLVITEMA)lParam);
9182 case LVM_SETITEMTEXTA:
9183 return LISTVIEW_SetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
9185 /* case LVM_SETITEMTEXTW: */
9187 case LVM_SETSELECTIONMARK:
9188 return LISTVIEW_SetSelectionMark(hwnd, (INT)lParam);
9190 case LVM_SETTEXTBKCOLOR:
9191 return LISTVIEW_SetTextBkColor(hwnd, (COLORREF)lParam);
9193 case LVM_SETTEXTCOLOR:
9194 return LISTVIEW_SetTextColor(hwnd, (COLORREF)lParam);
9196 /* case LVM_SETTOOLTIPS: */
9197 /* case LVM_SETUNICODEFORMAT: */
9198 /* case LVM_SETWORKAREAS: */
9200 case LVM_SORTITEMS:
9201 return LISTVIEW_SortItems(hwnd, wParam, lParam);
9203 /* case LVM_SUBITEMHITTEST: */
9205 case LVM_UPDATE:
9206 return LISTVIEW_Update(hwnd, (INT)wParam);
9208 case WM_CHAR:
9209 return LISTVIEW_ProcessLetterKeys( hwnd, wParam, lParam );
9211 case WM_COMMAND:
9212 return LISTVIEW_Command(hwnd, wParam, lParam);
9214 case WM_CREATE:
9215 return LISTVIEW_Create(hwnd, wParam, lParam);
9217 case WM_ERASEBKGND:
9218 return LISTVIEW_EraseBackground(hwnd, wParam, lParam);
9220 case WM_GETDLGCODE:
9221 return DLGC_WANTCHARS | DLGC_WANTARROWS;
9223 case WM_GETFONT:
9224 return LISTVIEW_GetFont(hwnd);
9226 case WM_HSCROLL:
9227 return LISTVIEW_HScroll(hwnd, (INT)LOWORD(wParam),
9228 (INT)HIWORD(wParam), (HWND)lParam);
9230 case WM_KEYDOWN:
9231 return LISTVIEW_KeyDown(hwnd, (INT)wParam, (LONG)lParam);
9233 case WM_KILLFOCUS:
9234 return LISTVIEW_KillFocus(hwnd);
9236 case WM_LBUTTONDBLCLK:
9237 return LISTVIEW_LButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
9238 HIWORD(lParam));
9240 case WM_LBUTTONDOWN:
9241 return LISTVIEW_LButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
9242 HIWORD(lParam));
9243 case WM_LBUTTONUP:
9244 return LISTVIEW_LButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
9245 HIWORD(lParam));
9246 case WM_MOUSEMOVE:
9247 return LISTVIEW_MouseMove (hwnd, wParam, lParam);
9249 case WM_MOUSEHOVER:
9250 return LISTVIEW_MouseHover(hwnd, wParam, lParam);
9252 case WM_NCCREATE:
9253 return LISTVIEW_NCCreate(hwnd, wParam, lParam);
9255 case WM_NCDESTROY:
9256 return LISTVIEW_NCDestroy(hwnd);
9258 case WM_NOTIFY:
9259 return LISTVIEW_Notify(hwnd, (INT)wParam, (LPNMHDR)lParam);
9261 case WM_NOTIFYFORMAT:
9262 return LISTVIEW_NotifyFormat(hwnd, (HWND)wParam, (INT)lParam);
9264 case WM_PAINT:
9265 return LISTVIEW_Paint(hwnd, (HDC)wParam);
9267 case WM_RBUTTONDBLCLK:
9268 return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
9269 HIWORD(lParam));
9271 case WM_RBUTTONDOWN:
9272 return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
9273 HIWORD(lParam));
9275 case WM_RBUTTONUP:
9276 return LISTVIEW_RButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
9277 HIWORD(lParam));
9279 case WM_SETFOCUS:
9280 return LISTVIEW_SetFocus(hwnd, (HWND)wParam);
9282 case WM_SETFONT:
9283 return LISTVIEW_SetFont(hwnd, (HFONT)wParam, (WORD)lParam);
9285 case WM_SETREDRAW:
9286 return LISTVIEW_SetRedraw(hwnd, (BOOL)wParam);
9288 case WM_SIZE:
9289 return LISTVIEW_Size(hwnd, (int)SLOWORD(lParam), (int)SHIWORD(lParam));
9291 case WM_STYLECHANGED:
9292 return LISTVIEW_StyleChanged(hwnd, wParam, (LPSTYLESTRUCT)lParam);
9294 /* case WM_TIMER: */
9296 case WM_VSCROLL:
9297 return LISTVIEW_VScroll(hwnd, (INT)LOWORD(wParam),
9298 (INT)HIWORD(wParam), (HWND)lParam);
9300 case WM_MOUSEWHEEL:
9301 if (wParam & (MK_SHIFT | MK_CONTROL))
9302 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
9303 return LISTVIEW_MouseWheel(hwnd, (short int)HIWORD(wParam));/* case WM_WINDOWPOSCHANGED: */
9305 /* case WM_WININICHANGE: */
9307 default:
9308 if (uMsg >= WM_USER)
9310 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam,
9311 lParam);
9314 /* call default window procedure */
9315 return DefWindowProcA(hwnd, uMsg, wParam, lParam);
9318 return 0;
9321 /***
9322 * DESCRIPTION:
9323 * Registers the window class.
9325 * PARAMETER(S):
9326 * None
9328 * RETURN:
9329 * None
9331 VOID LISTVIEW_Register(void)
9333 WNDCLASSA wndClass;
9335 ZeroMemory(&wndClass, sizeof(WNDCLASSA));
9336 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
9337 wndClass.lpfnWndProc = (WNDPROC)LISTVIEW_WindowProc;
9338 wndClass.cbClsExtra = 0;
9339 wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *);
9340 wndClass.hCursor = LoadCursorA(0, IDC_ARROWA);
9341 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
9342 wndClass.lpszClassName = WC_LISTVIEWA;
9343 RegisterClassA(&wndClass);
9346 /***
9347 * DESCRIPTION:
9348 * Unregisters the window class.
9350 * PARAMETER(S):
9351 * None
9353 * RETURN:
9354 * None
9356 VOID LISTVIEW_Unregister(void)
9358 UnregisterClassA(WC_LISTVIEWA, (HINSTANCE)NULL);
9361 /***
9362 * DESCRIPTION:
9363 * Handle any WM_COMMAND messages
9365 * PARAMETER(S):
9367 * RETURN:
9369 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam)
9371 switch (HIWORD(wParam))
9373 case EN_UPDATE:
9376 * Adjust the edit window size
9378 char buffer[1024];
9379 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
9380 HDC hdc = GetDC(infoPtr->hwndEdit);
9381 HFONT hFont, hOldFont = 0;
9382 RECT rect;
9383 SIZE sz;
9384 int len;
9386 len = GetWindowTextA(infoPtr->hwndEdit, buffer, 1023);
9387 GetWindowRect(infoPtr->hwndEdit, &rect);
9389 /* Select font to get the right dimension of the string */
9390 hFont = SendMessageA(infoPtr->hwndEdit, WM_GETFONT, 0, 0);
9391 if(hFont != 0)
9393 hOldFont = SelectObject(hdc, hFont);
9396 if (GetTextExtentPoint32A(hdc, buffer, strlen(buffer), &sz))
9398 TEXTMETRICA textMetric;
9400 /* Add Extra spacing for the next character */
9401 GetTextMetricsA(hdc, &textMetric);
9402 sz.cx += (textMetric.tmMaxCharWidth * 2);
9404 SetWindowPos (
9405 infoPtr->hwndEdit,
9406 HWND_TOP,
9409 sz.cx,
9410 rect.bottom - rect.top,
9411 SWP_DRAWFRAME|SWP_NOMOVE);
9413 if(hFont != 0)
9415 SelectObject(hdc, hOldFont);
9418 ReleaseDC(hwnd, hdc);
9420 break;
9423 default:
9424 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
9427 return 0;
9431 /***
9432 * DESCRIPTION:
9433 * Subclassed edit control windproc function
9435 * PARAMETER(S):
9437 * RETURN:
9439 LRESULT CALLBACK EditLblWndProc(HWND hwnd, UINT uMsg,
9440 WPARAM wParam, LPARAM lParam)
9442 BOOL cancel = FALSE;
9443 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(GetParent(hwnd), 0);
9444 EDITLABEL_ITEM *einfo = infoPtr->pedititem;
9445 static BOOL bIgnoreKillFocus = FALSE;
9446 switch (uMsg)
9448 case WM_GETDLGCODE:
9449 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
9451 case WM_KILLFOCUS:
9452 if(bIgnoreKillFocus)
9454 return TRUE;
9456 break;
9458 case WM_DESTROY:
9460 WNDPROC editProc = einfo->EditWndProc;
9461 SetWindowLongA(hwnd, GWL_WNDPROC, (LONG)editProc);
9462 COMCTL32_Free(einfo);
9463 infoPtr->pedititem = NULL;
9464 return CallWindowProcA(editProc, hwnd, uMsg, wParam, lParam);
9467 case WM_KEYDOWN:
9468 if (VK_ESCAPE == (INT)wParam)
9470 cancel = TRUE;
9471 break;
9474 else if (VK_RETURN == (INT)wParam)
9475 break;
9477 default:
9478 return CallWindowProcA(einfo->EditWndProc, hwnd,
9479 uMsg, wParam, lParam);
9482 if (einfo->EditLblCb)
9484 char *buffer = NULL;
9487 if (!cancel)
9489 int len = 1 + GetWindowTextLengthA(hwnd);
9491 if (len > 1)
9493 if (NULL != (buffer = (char *)COMCTL32_Alloc(len*sizeof(char))))
9495 GetWindowTextA(hwnd, buffer, len);
9499 /* Processing LVN_ENDLABELEDIT message could kill the focus */
9500 /* eg. Using a messagebox */
9501 bIgnoreKillFocus = TRUE;
9502 einfo->EditLblCb(GetParent(hwnd), buffer, einfo->param);
9504 if (buffer)
9505 COMCTL32_Free(buffer);
9507 einfo->EditLblCb = NULL;
9508 bIgnoreKillFocus = FALSE;
9511 SendMessageA(hwnd, WM_CLOSE, 0, 0);
9512 return TRUE;
9516 /***
9517 * DESCRIPTION:
9518 * Creates a subclassed edit cotrol
9520 * PARAMETER(S):
9522 * RETURN:
9524 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
9525 INT width, INT height, HWND parent, HINSTANCE hinst,
9526 EditlblCallback EditLblCb, DWORD param)
9528 HWND hedit;
9529 SIZE sz;
9530 HDC hdc;
9531 HDC hOldFont=0;
9532 TEXTMETRICA textMetric;
9533 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(parent, 0);
9535 if (NULL == (infoPtr->pedititem = COMCTL32_Alloc(sizeof(EDITLABEL_ITEM))))
9536 return 0;
9538 style |= WS_CHILDWINDOW|WS_CLIPSIBLINGS|ES_LEFT|WS_BORDER;
9539 hdc = GetDC(parent);
9541 /* Select the font to get appropriate metric dimensions */
9542 if(infoPtr->hFont != 0)
9544 hOldFont = SelectObject(hdc, infoPtr->hFont);
9547 /*Get String Lenght in pixels */
9548 GetTextExtentPoint32A(hdc, text, strlen(text), &sz);
9550 /*Add Extra spacing for the next character */
9551 GetTextMetricsA(hdc, &textMetric);
9552 sz.cx += (textMetric.tmMaxCharWidth * 2);
9554 if(infoPtr->hFont != 0)
9556 SelectObject(hdc, hOldFont);
9559 ReleaseDC(parent, hdc);
9560 if (!(hedit = CreateWindowA("Edit", text, style, x, y, sz.cx, height,
9561 parent, 0, hinst, 0)))
9563 COMCTL32_Free(infoPtr->pedititem);
9564 return 0;
9567 infoPtr->pedititem->param = param;
9568 infoPtr->pedititem->EditLblCb = EditLblCb;
9569 infoPtr->pedititem->EditWndProc = (WNDPROC)SetWindowLongA(hedit,
9570 GWL_WNDPROC, (LONG) EditLblWndProc);
9572 SendMessageA(hedit, WM_SETFONT, infoPtr->hFont, FALSE);
9574 return hedit;