4 * Copyright 1998, 1999 Eric Kohl
5 * Copyright 1999 Luc Tourangeau
6 * Copyright 2000 Jason Mawdsley
7 * Copyright 2001 Codeweavers Inc.
8 * Copyright 2002 Dimitrie O. Paun
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 * Listview control implementation.
28 * 1. No horizontal scrolling when header is larger than the client area.
29 * 2. Drawing optimizations.
30 * 3. Hot item handling.
33 * LISTVIEW_Notify : most notifications from children (editbox and header)
36 * LISTVIEW_SetItemCount : not completed for non OWNERDATA
38 * Advanced functionality:
39 * LISTVIEW_GetNumberOfWorkAreas : not implemented
40 * LISTVIEW_GetISearchString : not implemented
41 * LISTVIEW_GetBkImage : not implemented
42 * LISTVIEW_SetBkImage : not implemented
43 * LISTVIEW_GetColumnOrderArray : simple hack only
44 * LISTVIEW_SetColumnOrderArray : simple hack only
45 * LISTVIEW_Arrange : empty stub
46 * LISTVIEW_ApproximateViewRect : incomplete
47 * LISTVIEW_Update : not completed
49 * Known differences in message stream from native control (not known if
50 * these differences cause problems):
51 * LVM_INSERTITEM issues LVM_SETITEMSTATE and LVM_SETITEM in certain cases.
52 * LVM_SETITEM does not always issue LVN_ITEMCHANGING/LVN_ITEMCHANGED.
53 * WM_PAINT does LVN_GETDISPINFO in item order 0->n, native does n->0.
54 * WM_SETREDRAW(True) native does LVN_GETDISPINFO for all items and
55 * does *not* invoke DefWindowProc
56 * WM_CREATE does not issue WM_QUERYUISTATE and associated registry
57 * processing for "USEDOUBLECLICKTIME".
62 #include "wine/port.h"
74 #include "wine/debug.h"
76 WINE_DEFAULT_DEBUG_CHANNEL(listview
);
78 /* Some definitions for inline edit control */
80 typedef struct tagLV_INTHIT
83 DWORD distance
; /* distance to closest item */
84 INT iDistItem
; /* item number that is closest */
85 } LV_INTHIT
, *LPLV_INTHIT
;
88 typedef struct tagLISTVIEW_SUBITEM
95 typedef struct tagLISTVIEW_ITEM
106 typedef struct tagLISTVIEW_SELECTION
110 } LISTVIEW_SELECTION
;
112 typedef struct tagLISTVIEW_INFO
118 HIMAGELIST himlNormal
;
119 HIMAGELIST himlSmall
;
120 HIMAGELIST himlState
;
124 HDPA hdpaSelectionRanges
;
139 INT ntmHeight
; /* from GetTextMetrics from above font */
140 INT ntmAveCharWidth
; /* from GetTextMetrics from above font */
142 DWORD dwExStyle
; /* extended listview style */
144 PFNLVCOMPARE pfnCompare
;
151 INT nColumnCount
; /* the number of columns in this control */
153 DWORD lastKeyPressTimestamp
; /* Added */
154 WPARAM charCode
; /* Added */
155 INT nSearchParamLength
; /* Added */
156 WCHAR szSearchParam
[ MAX_PATH
]; /* Added */
160 DEFINE_COMMON_NOTIFICATIONS(LISTVIEW_INFO
, hwndSelf
);
166 /* Internal interface to LISTVIEW_HScroll and LISTVIEW_VScroll */
167 #define SB_INTERNAL_UP -1
168 #define SB_INTERNAL_DOWN -2
169 #define SB_INTERNAL_RIGHT -3
170 #define SB_INTERNAL_LEFT -4
172 /* maximum size of a label */
173 #define DISP_TEXT_SIZE 512
175 /* padding for items in list and small icon display modes */
176 #define WIDTH_PADDING 12
178 /* padding for items in list, report and small icon display modes */
179 #define HEIGHT_PADDING 1
181 /* offset of items in report display mode */
182 #define REPORT_MARGINX 2
184 /* padding for icon in large icon display mode
185 * ICON_TOP_PADDING_NOTHITABLE - space between top of box and area
186 * that HITTEST will see.
187 * ICON_TOP_PADDING_HITABLE - spacing between above and icon.
188 * ICON_TOP_PADDING - sum of the two above.
189 * ICON_BOTTOM_PADDING - between bottom of icon and top of text
190 * LABEL_VERT_OFFSET - between bottom of text and end of box
192 #define ICON_TOP_PADDING_NOTHITABLE 2
193 #define ICON_TOP_PADDING_HITABLE 2
194 #define ICON_TOP_PADDING ICON_TOP_PADDING_NOTHITABLE + ICON_TOP_PADDING_HITABLE
195 #define ICON_BOTTOM_PADDING 4
196 #define LABEL_VERT_OFFSET 10
198 /* default label width for items in list and small icon display modes */
199 #define DEFAULT_LABEL_WIDTH 40
201 /* default column width for items in list display mode */
202 #define DEFAULT_COLUMN_WIDTH 128
204 /* Size of "line" scroll for V & H scrolls */
205 #define LISTVIEW_SCROLL_ICON_LINE_SIZE 37
207 /* Padding betwen image and label */
208 #define IMAGE_PADDING 2
210 /* Padding behind the label */
211 #define TRAILING_PADDING 5
213 /* Border for the icon caption */
214 #define CAPTION_BORDER 2
218 /* retrieve the number of items in the listview */
219 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
220 #define HDM_INSERTITEMT(isW) ( (isW) ? HDM_INSERTITEMW : HDM_INSERTITEMA )
224 * forward declarations
226 static LRESULT
LISTVIEW_GetItemT(LISTVIEW_INFO
*, LPLVITEMW
, BOOL
, BOOL
);
227 static INT
LISTVIEW_SuperHitTestItem(LISTVIEW_INFO
*, LPLV_INTHIT
, BOOL
);
228 static INT
LISTVIEW_HitTestItem(LISTVIEW_INFO
*, LPLVHITTESTINFO
, BOOL
);
229 static INT
LISTVIEW_GetCountPerRow(LISTVIEW_INFO
*);
230 static INT
LISTVIEW_GetCountPerColumn(LISTVIEW_INFO
*);
231 static VOID
LISTVIEW_AlignLeft(LISTVIEW_INFO
*);
232 static VOID
LISTVIEW_AlignTop(LISTVIEW_INFO
*);
233 static VOID
LISTVIEW_AddGroupSelection(LISTVIEW_INFO
*, INT
);
234 static VOID
LISTVIEW_AddSelection(LISTVIEW_INFO
*, INT
);
235 static BOOL
LISTVIEW_AddSubItemT(LISTVIEW_INFO
*, LPLVITEMW
, BOOL
);
236 static INT
LISTVIEW_FindInsertPosition(HDPA
, INT
);
237 static INT
LISTVIEW_GetItemHeight(LISTVIEW_INFO
*);
238 static BOOL
LISTVIEW_GetItemBoundBox(LISTVIEW_INFO
*, INT
, LPRECT
);
239 static BOOL
LISTVIEW_GetItemPosition(LISTVIEW_INFO
*, INT
, LPPOINT
);
240 static LRESULT
LISTVIEW_GetItemRect(LISTVIEW_INFO
*, INT
, LPRECT
);
241 static LRESULT
LISTVIEW_GetSubItemRect(LISTVIEW_INFO
*, INT
, INT
, INT
, LPRECT
);
242 static INT
LISTVIEW_GetItemWidth(LISTVIEW_INFO
*);
243 static INT
LISTVIEW_GetLabelWidth(LISTVIEW_INFO
*, INT
);
244 static LRESULT
LISTVIEW_GetOrigin(LISTVIEW_INFO
*, LPPOINT
);
245 static INT
LISTVIEW_CalculateWidth(LISTVIEW_INFO
*, INT
);
246 static LISTVIEW_SUBITEM
* LISTVIEW_GetSubItem(HDPA
, INT
);
247 static LRESULT
LISTVIEW_GetViewRect(LISTVIEW_INFO
*, LPRECT
);
248 static BOOL
LISTVIEW_InitItemT(LISTVIEW_INFO
*, LISTVIEW_ITEM
*, LPLVITEMW
, BOOL
);
249 static BOOL
LISTVIEW_InitSubItemT(LISTVIEW_INFO
*, LISTVIEW_SUBITEM
*, LPLVITEMW
, BOOL
);
250 static INT
LISTVIEW_MouseSelection(LISTVIEW_INFO
*, POINT
);
251 static BOOL
LISTVIEW_RemoveColumn(HDPA
, INT
);
252 static BOOL
LISTVIEW_RemoveSubItem(HDPA
, INT
);
253 static VOID
LISTVIEW_SetGroupSelection(LISTVIEW_INFO
*, INT
);
254 static BOOL
LISTVIEW_SetItemT(LISTVIEW_INFO
*, LPLVITEMW
, BOOL
);
255 static BOOL
LISTVIEW_SetItemFocus(LISTVIEW_INFO
*, INT
);
256 static BOOL
LISTVIEW_SetItemPosition(LISTVIEW_INFO
*, INT
, LONG
, LONG
);
257 static VOID
LISTVIEW_UpdateScroll(LISTVIEW_INFO
*);
258 static VOID
LISTVIEW_SetSelection(LISTVIEW_INFO
*, INT
);
259 static BOOL
LISTVIEW_UpdateSize(LISTVIEW_INFO
*);
260 static BOOL
LISTVIEW_SetSubItemT(LISTVIEW_INFO
*, LPLVITEMW
, BOOL
);
261 static LRESULT
LISTVIEW_SetViewRect(LISTVIEW_INFO
*, LPRECT
);
262 static BOOL
LISTVIEW_ToggleSelection(LISTVIEW_INFO
*, INT
);
263 static VOID
LISTVIEW_UnsupportedStyles(LONG
);
264 static HWND
LISTVIEW_EditLabelT(LISTVIEW_INFO
*, INT
, BOOL
);
265 static LRESULT
LISTVIEW_Command(LISTVIEW_INFO
*, WPARAM
, LPARAM
);
266 static LRESULT
LISTVIEW_SortItems(LISTVIEW_INFO
*, PFNLVCOMPARE
, LPARAM
);
267 static LRESULT
LISTVIEW_GetStringWidthT(LISTVIEW_INFO
*, LPCWSTR
, BOOL
);
268 static INT
LISTVIEW_ProcessLetterKeys(LISTVIEW_INFO
*, WPARAM
, LPARAM
);
269 static BOOL
LISTVIEW_KeySelection(LISTVIEW_INFO
*, INT
);
270 static LRESULT
LISTVIEW_GetItemState(LISTVIEW_INFO
*, INT
, UINT
);
271 static LRESULT
LISTVIEW_SetItemState(LISTVIEW_INFO
*, INT
, LPLVITEMW
);
272 static BOOL
LISTVIEW_IsSelected(LISTVIEW_INFO
*, INT
);
273 static VOID
LISTVIEW_RemoveSelectionRange(LISTVIEW_INFO
*, INT
, INT
);
274 static void LISTVIEW_FillBackground(LISTVIEW_INFO
*, HDC
, LPRECT
);
275 static void LISTVIEW_UpdateLargeItemLabelRect (LISTVIEW_INFO
*, int, RECT
*);
276 static LRESULT
LISTVIEW_GetColumnT(LISTVIEW_INFO
*, INT
, LPLVCOLUMNW
, BOOL
);
277 static LRESULT
LISTVIEW_VScroll(LISTVIEW_INFO
*, INT
, SHORT
, HWND
);
278 static LRESULT
LISTVIEW_HScroll(LISTVIEW_INFO
*, INT
, SHORT
, HWND
);
279 static INT
LISTVIEW_GetTopIndex(LISTVIEW_INFO
*);
280 static BOOL
LISTVIEW_EnsureVisible(LISTVIEW_INFO
*, INT
, BOOL
);
281 static HWND
CreateEditLabelT(LISTVIEW_INFO
*, LPCWSTR
, DWORD
, INT
, INT
, INT
, INT
, BOOL
);
283 /******** Defines that LISTVIEW_ProcessLetterKeys uses ****************/
284 #define KEY_DELAY 450
286 #define COUNTOF(array) (sizeof(array)/sizeof(array[0]))
288 static inline BOOL
is_textW(LPCWSTR text
)
290 return text
!= NULL
&& text
!= LPSTR_TEXTCALLBACKW
;
293 static inline BOOL
is_textT(LPCWSTR text
, BOOL isW
)
295 /* we can ignore isW since LPSTR_TEXTCALLBACKW == LPSTR_TEXTCALLBACKA */
296 return is_textW(text
);
299 static inline int textlenT(LPCWSTR text
, BOOL isW
)
301 return !is_textT(text
, isW
) ? 0 :
302 isW
? lstrlenW(text
) : lstrlenA((LPCSTR
)text
);
305 static inline void textcpynT(LPWSTR dest
, BOOL isDestW
, LPCWSTR src
, BOOL isSrcW
, INT max
)
308 if (isSrcW
) lstrcpynW(dest
, src
, max
);
309 else MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)src
, -1, dest
, max
);
311 if (isSrcW
) WideCharToMultiByte(CP_ACP
, 0, src
, -1, (LPSTR
)dest
, max
, NULL
, NULL
);
312 else lstrcpynA((LPSTR
)dest
, (LPCSTR
)src
, max
);
315 static inline LPCSTR
debugstr_t(LPCWSTR text
, BOOL isW
)
317 return isW
? debugstr_w(text
) : debugstr_a((LPCSTR
)text
);
320 static inline LPCSTR
debugstr_tn(LPCWSTR text
, BOOL isW
, INT n
)
322 return isW
? debugstr_wn(text
, n
) : debugstr_an((LPCSTR
)text
, n
);
325 static inline LPCSTR
lv_dmp_str(LPCWSTR text
, BOOL isW
, INT n
)
327 return debugstr_tn(text
, isW
, min(n
, textlenT(text
, isW
)));
330 static inline LPWSTR
textdupTtoW(LPCWSTR text
, BOOL isW
)
332 LPWSTR wstr
= (LPWSTR
)text
;
334 TRACE("(text=%s, isW=%d)\n", debugstr_t(text
, isW
), isW
);
337 INT len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)text
, -1, NULL
, 0);
338 wstr
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
339 if (wstr
) MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)text
, -1, wstr
, len
);
341 TRACE(" wstr=%s\n", debugstr_w(wstr
));
345 static inline void textfreeT(LPWSTR wstr
, BOOL isW
)
347 if (!isW
&& wstr
) HeapFree(GetProcessHeap(), 0, wstr
);
351 * dest is a pointer to a Unicode string
352 * src is a pointer to a string (Unicode if isW, ANSI if !isW)
354 static inline BOOL
textsetptrT(LPWSTR
*dest
, LPWSTR src
, BOOL isW
)
356 LPWSTR pszText
= textdupTtoW(src
, isW
);
358 if (*dest
== LPSTR_TEXTCALLBACKW
) *dest
= NULL
;
359 bResult
= Str_SetPtrW(dest
, pszText
);
360 textfreeT(pszText
, isW
);
364 static inline LRESULT
CallWindowProcT(WNDPROC proc
, HWND hwnd
, UINT uMsg
,
365 WPARAM wParam
, LPARAM lParam
, BOOL isW
)
368 return CallWindowProcW(proc
, hwnd
, uMsg
, wParam
, lParam
);
370 return CallWindowProcA(proc
, hwnd
, uMsg
, wParam
, lParam
);
373 static inline BOOL
notify(LISTVIEW_INFO
*infoPtr
, INT code
, LPNMHDR pnmh
)
375 pnmh
->hwndFrom
= infoPtr
->hwndSelf
;
376 pnmh
->idFrom
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_ID
);
378 return (BOOL
)SendMessageW(GetParent(infoPtr
->hwndSelf
), WM_NOTIFY
,
379 (WPARAM
)pnmh
->idFrom
, (LPARAM
)pnmh
);
382 static inline void notify_itemactivate(LISTVIEW_INFO
*infoPtr
)
384 hwnd_notify(infoPtr
->hwndSelf
, LVN_ITEMACTIVATE
);
387 static inline BOOL
listview_notify(LISTVIEW_INFO
*infoPtr
, INT code
, LPNMLISTVIEW plvnm
)
389 return notify(infoPtr
, code
, (LPNMHDR
)plvnm
);
392 static int tabNotification
[] = {
393 LVN_BEGINLABELEDITW
, LVN_BEGINLABELEDITA
,
394 LVN_ENDLABELEDITW
, LVN_ENDLABELEDITA
,
395 LVN_GETDISPINFOW
, LVN_GETDISPINFOA
,
396 LVN_SETDISPINFOW
, LVN_SETDISPINFOA
,
397 LVN_ODFINDITEMW
, LVN_ODFINDITEMA
,
398 LVN_GETINFOTIPW
, LVN_GETINFOTIPA
,
402 static int get_ansi_notification(INT unicodeNotificationCode
)
404 int *pTabNotif
= tabNotification
;
405 while (*pTabNotif
&& (unicodeNotificationCode
!= *pTabNotif
++));
406 if (*pTabNotif
) return *pTabNotif
;
407 ERR("unknown notification %x\n", unicodeNotificationCode
);
408 return unicodeNotificationCode
;
412 Send notification. depends on dispinfoW having same
413 structure as dispinfoA.
414 infoPtr : listview struct
415 notificationCode : *Unicode* notification code
416 pdi : dispinfo structure (can be unicode or ansi)
417 isW : TRUE if dispinfo is Unicode
419 static BOOL
dispinfo_notifyT(LISTVIEW_INFO
*infoPtr
, INT notificationCode
, LPNMLVDISPINFOW pdi
, BOOL isW
)
421 BOOL bResult
= FALSE
;
422 BOOL convertToAnsi
= FALSE
, convertToUnicode
= FALSE
;
424 INT cchTempBufMax
= 0, savCchTextMax
= 0;
425 LPWSTR pszTempBuf
= NULL
, savPszText
= NULL
;
427 TRACE("(code=%x, pdi=%p, isW=%d)\n", notificationCode
, pdi
, isW
);
428 TRACE(" notifyFormat=%s\n",
429 infoPtr
->notifyFormat
== NFR_UNICODE
? "NFR_UNICODE" :
430 infoPtr
->notifyFormat
== NFR_ANSI
? "NFR_ANSI" : "(not set)");
431 if (infoPtr
->notifyFormat
== NFR_ANSI
)
432 realNotifCode
= get_ansi_notification(notificationCode
);
434 realNotifCode
= notificationCode
;
436 if (is_textT(pdi
->item
.pszText
, isW
))
438 if (isW
&& infoPtr
->notifyFormat
== NFR_ANSI
)
439 convertToAnsi
= TRUE
;
440 if (!isW
&& infoPtr
->notifyFormat
== NFR_UNICODE
)
441 convertToUnicode
= TRUE
;
444 if (convertToAnsi
|| convertToUnicode
)
446 TRACE(" we have to convert the text to the correct format\n");
447 if (notificationCode
!= LVN_GETDISPINFOW
)
448 { /* length of existing text */
449 cchTempBufMax
= convertToUnicode
?
450 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pdi
->item
.pszText
, -1, NULL
, 0):
451 WideCharToMultiByte(CP_ACP
, 0, pdi
->item
.pszText
, -1, NULL
, 0, NULL
, NULL
);
454 cchTempBufMax
= pdi
->item
.cchTextMax
;
456 pszTempBuf
= HeapAlloc(GetProcessHeap(), 0,
457 (convertToUnicode
? sizeof(WCHAR
) : sizeof(CHAR
)) * cchTempBufMax
);
458 if (!pszTempBuf
) return FALSE
;
459 if (convertToUnicode
)
460 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pdi
->item
.pszText
, -1,
461 pszTempBuf
, cchTempBufMax
);
463 WideCharToMultiByte(CP_ACP
, 0, pdi
->item
.pszText
, -1, (LPSTR
) pszTempBuf
,
464 cchTempBufMax
, NULL
, NULL
);
465 TRACE(" text=%s\n", debugstr_t(pszTempBuf
, convertToUnicode
));
466 savCchTextMax
= pdi
->item
.cchTextMax
;
467 savPszText
= pdi
->item
.pszText
;
468 pdi
->item
.pszText
= pszTempBuf
;
469 pdi
->item
.cchTextMax
= cchTempBufMax
;
472 bResult
= notify(infoPtr
, realNotifCode
, (LPNMHDR
)pdi
);
474 if (convertToUnicode
|| convertToAnsi
)
475 { /* convert back result */
476 TRACE(" returned text=%s\n", debugstr_t(pdi
->item
.pszText
, convertToUnicode
));
477 if (convertToUnicode
) /* note : pointer can be changed by app ! */
478 WideCharToMultiByte(CP_ACP
, 0, pdi
->item
.pszText
, -1, (LPSTR
) savPszText
,
479 savCchTextMax
, NULL
, NULL
);
481 MultiByteToWideChar(CP_ACP
, 0, (LPSTR
) pdi
->item
.pszText
, -1,
482 savPszText
, savCchTextMax
);
483 pdi
->item
.pszText
= savPszText
; /* restores our buffer */
484 pdi
->item
.cchTextMax
= savCchTextMax
;
485 HeapFree(GetProcessHeap(), 0, pszTempBuf
);
490 static inline LRESULT
LISTVIEW_GetItemW(LISTVIEW_INFO
*infoPtr
, LPLVITEMW lpLVItem
, BOOL internal
)
492 return LISTVIEW_GetItemT(infoPtr
, lpLVItem
, internal
, TRUE
);
495 static inline int lstrncmpiW(LPCWSTR s1
, LPCWSTR s2
, int n
)
499 n
= min(min(n
, strlenW(s1
)), strlenW(s2
));
500 res
= CompareStringW(LOCALE_USER_DEFAULT
, NORM_IGNORECASE
, s1
, n
, s2
, n
);
501 return res
? res
- 2 : res
;
504 static char* debuglvitem_t(LPLVITEMW lpLVItem
, BOOL isW
)
506 static int index
= 0;
507 static char buffers
[20][256];
508 char* buf
= buffers
[index
++ % 20];
509 if (lpLVItem
== NULL
) return "(null)";
510 snprintf(buf
, 256, "{mask=%x, iItem=%d, iSubItem=%d, state=%x, stateMask=%x,"
511 " pszText=%s, cchTextMax=%d, iImage=%d, lParam=%lx, iIndent=%d}",
512 lpLVItem
->mask
, lpLVItem
->iItem
, lpLVItem
->iSubItem
,
513 lpLVItem
->state
, lpLVItem
->stateMask
,
514 lpLVItem
->pszText
== LPSTR_TEXTCALLBACKW
? "(callback)" :
515 lv_dmp_str(lpLVItem
->pszText
, isW
, 80),
516 lpLVItem
->cchTextMax
, lpLVItem
->iImage
, lpLVItem
->lParam
,
521 static char* debuglvcolumn_t(LPLVCOLUMNW lpColumn
, BOOL isW
)
523 static int index
= 0;
524 static char buffers
[20][256];
525 char* buf
= buffers
[index
++ % 20];
526 if (lpColumn
== NULL
) return "(null)";
527 snprintf(buf
, 256, "{mask=%x, fmt=%x, cx=%d,"
528 " pszText=%s, cchTextMax=%d, iSubItem=%d}",
529 lpColumn
->mask
, lpColumn
->fmt
, lpColumn
->cx
,
530 lpColumn
->mask
& LVCF_TEXT
? lpColumn
->pszText
== LPSTR_TEXTCALLBACKW
? "(callback)" :
531 lv_dmp_str(lpColumn
->pszText
, isW
, 80): "",
532 lpColumn
->mask
& LVCF_TEXT
? lpColumn
->cchTextMax
: 0, lpColumn
->iSubItem
);
536 static void LISTVIEW_DumpListview(LISTVIEW_INFO
*iP
, INT line
)
538 DWORD dwStyle
= GetWindowLongW (iP
->hwndSelf
, GWL_STYLE
);
539 TRACE("listview %08x at line %d, clrBk=0x%06lx, clrText=0x%06lx, clrTextBk=0x%06lx, ItemHeight=%d, ItemWidth=%d, Style=0x%08lx\n",
540 iP
->hwndSelf
, line
, iP
->clrBk
, iP
->clrText
, iP
->clrTextBk
,
541 iP
->nItemHeight
, iP
->nItemWidth
, dwStyle
);
542 TRACE("listview %08x at line %d, himlNor=%p, himlSml=%p, himlState=%p, Focused=%d, Hot=%d, exStyle=0x%08lx\n",
543 iP
->hwndSelf
, line
, iP
->himlNormal
, iP
->himlSmall
, iP
->himlState
,
544 iP
->nFocusedItem
, iP
->nHotItem
, iP
->dwExStyle
);
545 TRACE("listview %08x at line %d, ntmH=%d, icSz.cx=%ld, icSz.cy=%ld, icSp.cx=%ld, icSp.cy=%ld\n",
546 iP
->hwndSelf
, line
, iP
->ntmHeight
, iP
->iconSize
.cx
, iP
->iconSize
.cy
,
547 iP
->iconSpacing
.cx
, iP
->iconSpacing
.cy
);
551 LISTVIEW_SendCustomDrawNotify (LISTVIEW_INFO
*infoPtr
, DWORD dwDrawStage
, HDC hdc
,
554 NMLVCUSTOMDRAW nmcdhdr
;
557 TRACE("(dwDrawStage=%lx, hdc=%x, rc=?)\n", dwDrawStage
, hdc
);
559 nmcd
= & nmcdhdr
.nmcd
;
560 nmcd
->hdr
.hwndFrom
= infoPtr
->hwndSelf
;
561 nmcd
->hdr
.idFrom
= GetWindowLongW( infoPtr
->hwndSelf
, GWL_ID
);
562 nmcd
->hdr
.code
= NM_CUSTOMDRAW
;
563 nmcd
->dwDrawStage
= dwDrawStage
;
565 nmcd
->rc
.left
= rc
.left
;
566 nmcd
->rc
.right
= rc
.right
;
567 nmcd
->rc
.bottom
= rc
.bottom
;
568 nmcd
->rc
.top
= rc
.top
;
569 nmcd
->dwItemSpec
= 0;
570 nmcd
->uItemState
= 0;
571 nmcd
->lItemlParam
= 0;
572 nmcdhdr
.clrText
= infoPtr
->clrText
;
573 nmcdhdr
.clrTextBk
= infoPtr
->clrBk
;
575 return (BOOL
)SendMessageW (GetParent (infoPtr
->hwndSelf
), WM_NOTIFY
,
576 (WPARAM
) nmcd
->hdr
.idFrom
, (LPARAM
)&nmcdhdr
);
580 LISTVIEW_SendCustomDrawItemNotify (LISTVIEW_INFO
*infoPtr
, HDC hdc
,
581 UINT iItem
, UINT iSubItem
,
584 NMLVCUSTOMDRAW nmcdhdr
;
586 DWORD dwDrawStage
,dwItemSpec
;
592 ZeroMemory(&item
,sizeof(item
));
594 item
.mask
= LVIF_PARAM
;
595 ListView_GetItemW(infoPtr
->hwndSelf
,&item
);
597 dwDrawStage
=CDDS_ITEM
| uItemDrawState
;
601 if (LISTVIEW_IsSelected(infoPtr
,iItem
)) uItemState
|=CDIS_SELECTED
;
602 if (iItem
==infoPtr
->nFocusedItem
) uItemState
|=CDIS_FOCUS
;
603 if (iItem
==infoPtr
->nHotItem
) uItemState
|=CDIS_HOT
;
605 itemRect
.left
= LVIR_BOUNDS
;
606 LISTVIEW_GetItemRect(infoPtr
, iItem
, &itemRect
);
608 nmcd
= & nmcdhdr
.nmcd
;
609 nmcd
->hdr
.hwndFrom
= infoPtr
->hwndSelf
;
610 nmcd
->hdr
.idFrom
= GetWindowLongW( infoPtr
->hwndSelf
, GWL_ID
);
611 nmcd
->hdr
.code
= NM_CUSTOMDRAW
;
612 nmcd
->dwDrawStage
= dwDrawStage
;
614 nmcd
->rc
.left
= itemRect
.left
;
615 nmcd
->rc
.right
= itemRect
.right
;
616 nmcd
->rc
.bottom
= itemRect
.bottom
;
617 nmcd
->rc
.top
= itemRect
.top
;
618 nmcd
->dwItemSpec
= dwItemSpec
;
619 nmcd
->uItemState
= uItemState
;
620 nmcd
->lItemlParam
= item
.lParam
;
621 nmcdhdr
.clrText
= infoPtr
->clrText
;
622 nmcdhdr
.clrTextBk
= infoPtr
->clrBk
;
623 nmcdhdr
.iSubItem
=iSubItem
;
625 TRACE("drawstage=%lx hdc=%x item=%lx, itemstate=%x, lItemlParam=%lx\n",
626 nmcd
->dwDrawStage
, nmcd
->hdc
, nmcd
->dwItemSpec
,
627 nmcd
->uItemState
, nmcd
->lItemlParam
);
629 retval
=SendMessageW (GetParent (infoPtr
->hwndSelf
), WM_NOTIFY
,
630 (WPARAM
)nmcd
->hdr
.idFrom
, (LPARAM
)&nmcdhdr
);
632 infoPtr
->clrText
=nmcdhdr
.clrText
;
633 infoPtr
->clrBk
=nmcdhdr
.clrTextBk
;
634 return (BOOL
) retval
;
638 /*************************************************************************
639 * LISTVIEW_ProcessLetterKeys
641 * Processes keyboard messages generated by pressing the letter keys
643 * What this does is perform a case insensitive search from the
644 * current position with the following quirks:
645 * - If two chars or more are pressed in quick succession we search
646 * for the corresponding string (e.g. 'abc').
647 * - If there is a delay we wipe away the current search string and
648 * restart with just that char.
649 * - If the user keeps pressing the same character, whether slowly or
650 * fast, so that the search string is entirely composed of this
651 * character ('aaaaa' for instance), then we search for first item
652 * that starting with that character.
653 * - If the user types the above character in quick succession, then
654 * we must also search for the corresponding string ('aaaaa'), and
655 * go to that string if there is a match.
658 * [I] hwnd : handle to the window
659 * [I] charCode : the character code, the actual character
660 * [I] keyData : key data
668 * - The current implementation has a list of characters it will
669 * accept and it ignores averything else. In particular it will
670 * ignore accentuated characters which seems to match what
671 * Windows does. But I'm not sure it makes sense to follow
673 * - We don't sound a beep when the search fails.
677 * TREEVIEW_ProcessLetterKeys
679 static INT
LISTVIEW_ProcessLetterKeys(LISTVIEW_INFO
*infoPtr
, WPARAM charCode
, LPARAM keyData
)
685 WCHAR buffer
[MAX_PATH
];
686 DWORD timestamp
,elapsed
;
688 /* simple parameter checking */
689 if (!charCode
|| !keyData
)
695 /* only allow the valid WM_CHARs through */
696 if (!isalnum(charCode
) &&
697 charCode
!= '.' && charCode
!= '`' && charCode
!= '!' &&
698 charCode
!= '@' && charCode
!= '#' && charCode
!= '$' &&
699 charCode
!= '%' && charCode
!= '^' && charCode
!= '&' &&
700 charCode
!= '*' && charCode
!= '(' && charCode
!= ')' &&
701 charCode
!= '-' && charCode
!= '_' && charCode
!= '+' &&
702 charCode
!= '=' && charCode
!= '\\'&& charCode
!= ']' &&
703 charCode
!= '}' && charCode
!= '[' && charCode
!= '{' &&
704 charCode
!= '/' && charCode
!= '?' && charCode
!= '>' &&
705 charCode
!= '<' && charCode
!= ',' && charCode
!= '~')
708 nSize
=GETITEMCOUNT(infoPtr
);
709 /* if there's one item or less, there is no where to go */
713 /* compute how much time elapsed since last keypress */
714 timestamp
=GetTickCount();
715 if (timestamp
> infoPtr
->lastKeyPressTimestamp
) {
716 elapsed
=timestamp
-infoPtr
->lastKeyPressTimestamp
;
718 elapsed
=infoPtr
->lastKeyPressTimestamp
-timestamp
;
721 /* update the search parameters */
722 infoPtr
->lastKeyPressTimestamp
=timestamp
;
723 if (elapsed
< KEY_DELAY
) {
724 if (infoPtr
->nSearchParamLength
< COUNTOF(infoPtr
->szSearchParam
)) {
725 infoPtr
->szSearchParam
[infoPtr
->nSearchParamLength
++]=charCode
;
727 if (infoPtr
->charCode
!= charCode
) {
728 infoPtr
->charCode
=charCode
=0;
731 infoPtr
->charCode
=charCode
;
732 infoPtr
->szSearchParam
[0]=charCode
;
733 infoPtr
->nSearchParamLength
=1;
734 /* Redundant with the 1 char string */
738 /* and search from the current position */
740 if (infoPtr
->nFocusedItem
>= 0) {
741 endidx
=infoPtr
->nFocusedItem
;
743 /* if looking for single character match,
744 * then we must always move forward
746 if (infoPtr
->nSearchParamLength
== 1)
760 ZeroMemory(&item
, sizeof(item
));
761 item
.mask
= LVIF_TEXT
;
764 item
.pszText
= buffer
;
765 item
.cchTextMax
= COUNTOF(buffer
);
766 ListView_GetItemW(infoPtr
->hwndSelf
, &item
);
768 /* check for a match */
769 if (lstrncmpiW(item
.pszText
,infoPtr
->szSearchParam
,infoPtr
->nSearchParamLength
) == 0) {
772 } else if ( (charCode
!= 0) && (nItem
== -1) && (nItem
!= infoPtr
->nFocusedItem
) &&
773 (lstrncmpiW(item
.pszText
,infoPtr
->szSearchParam
,1) == 0) ) {
774 /* This would work but we must keep looking for a longer match */
778 } while (idx
!= endidx
);
781 if (LISTVIEW_KeySelection(infoPtr
, nItem
)) {
782 /* refresh client area */
783 InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
);
784 UpdateWindow(infoPtr
->hwndSelf
);
791 /*************************************************************************
792 * LISTVIEW_UpdateHeaderSize [Internal]
794 * Function to resize the header control
797 * hwnd [I] handle to a window
798 * nNewScrollPos [I] Scroll Pos to Set
805 static VOID
LISTVIEW_UpdateHeaderSize(LISTVIEW_INFO
*infoPtr
, INT nNewScrollPos
)
810 GetWindowRect(infoPtr
->hwndHeader
, &winRect
);
811 point
[0].x
= winRect
.left
;
812 point
[0].y
= winRect
.top
;
813 point
[1].x
= winRect
.right
;
814 point
[1].y
= winRect
.bottom
;
816 MapWindowPoints(HWND_DESKTOP
, infoPtr
->hwndSelf
, point
, 2);
817 point
[0].x
= -nNewScrollPos
;
818 point
[1].x
+= nNewScrollPos
;
820 SetWindowPos(infoPtr
->hwndHeader
,0,
821 point
[0].x
,point
[0].y
,point
[1].x
,point
[1].y
,
822 SWP_NOZORDER
| SWP_NOACTIVATE
);
827 * Update the scrollbars. This functions should be called whenever
828 * the content, size or view changes.
831 * [I] infoPtr : valid pointer to the listview structure
836 static VOID
LISTVIEW_UpdateScroll(LISTVIEW_INFO
*infoPtr
)
838 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
839 UINT uView
= lStyle
& LVS_TYPEMASK
;
840 INT nListHeight
= infoPtr
->rcList
.bottom
- infoPtr
->rcList
.top
;
841 INT nListWidth
= infoPtr
->rcList
.right
- infoPtr
->rcList
.left
;
842 SCROLLINFO scrollInfo
;
844 if (lStyle
& LVS_NOSCROLL
) return;
846 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
847 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
849 if (uView
== LVS_LIST
)
851 /* update horizontal scrollbar */
853 INT nCountPerColumn
= LISTVIEW_GetCountPerColumn(infoPtr
);
854 INT nCountPerRow
= LISTVIEW_GetCountPerRow(infoPtr
);
855 INT nNumOfItems
= GETITEMCOUNT(infoPtr
);
857 scrollInfo
.nMax
= nNumOfItems
/ nCountPerColumn
;
858 TRACE("items=%d, perColumn=%d, perRow=%d\n",
859 nNumOfItems
, nCountPerColumn
, nCountPerRow
);
860 if((nNumOfItems
% nCountPerColumn
) == 0)
864 scrollInfo
.nPos
= ListView_GetTopIndex(infoPtr
->hwndSelf
) / nCountPerColumn
;
865 scrollInfo
.nPage
= nCountPerRow
;
866 scrollInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
868 SetScrollInfo(infoPtr
->hwndSelf
, SB_HORZ
, &scrollInfo
, TRUE
);
869 ShowScrollBar(infoPtr
->hwndSelf
, SB_VERT
, FALSE
);
871 else if (uView
== LVS_REPORT
)
875 /* update vertical scrollbar */
877 scrollInfo
.nMax
= GETITEMCOUNT(infoPtr
) - 1;
878 scrollInfo
.nPos
= ListView_GetTopIndex(infoPtr
->hwndSelf
);
879 scrollInfo
.nPage
= LISTVIEW_GetCountPerColumn(infoPtr
);
880 scrollInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
881 test
= (scrollInfo
.nMin
>= scrollInfo
.nMax
- max((INT
)scrollInfo
.nPage
- 1, 0));
882 TRACE("LVS_REPORT Vert. nMax=%d, nPage=%d, test=%d\n",
883 scrollInfo
.nMax
, scrollInfo
.nPage
, test
);
884 SetScrollInfo(infoPtr
->hwndSelf
, SB_VERT
, &scrollInfo
, TRUE
);
885 ShowScrollBar(infoPtr
->hwndSelf
, SB_VERT
, (test
) ? FALSE
: TRUE
);
887 /* update horizontal scrollbar */
888 nListWidth
= infoPtr
->rcList
.right
- infoPtr
->rcList
.left
;
889 if (GetScrollInfo(infoPtr
->hwndSelf
, SB_HORZ
, &scrollInfo
) == FALSE
890 || GETITEMCOUNT(infoPtr
) == 0)
895 scrollInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
896 scrollInfo
.nPage
= nListWidth
;
897 scrollInfo
.nMax
= max(infoPtr
->nItemWidth
, 0)-1;
898 test
= (scrollInfo
.nMin
>= scrollInfo
.nMax
- max((INT
)scrollInfo
.nPage
- 1, 0));
899 TRACE("LVS_REPORT Horz. nMax=%d, nPage=%d, test=%d\n",
900 scrollInfo
.nMax
, scrollInfo
.nPage
, test
);
901 SetScrollInfo(infoPtr
->hwndSelf
, SB_HORZ
, &scrollInfo
, TRUE
);
902 ShowScrollBar(infoPtr
->hwndSelf
, SB_HORZ
, (test
) ? FALSE
: TRUE
);
904 /* Update the Header Control */
905 scrollInfo
.fMask
= SIF_POS
;
906 GetScrollInfo(infoPtr
->hwndSelf
, SB_HORZ
, &scrollInfo
);
907 LISTVIEW_UpdateHeaderSize(infoPtr
, scrollInfo
.nPos
);
914 if (LISTVIEW_GetViewRect(infoPtr
, &rcView
))
916 INT nViewWidth
= rcView
.right
- rcView
.left
;
917 INT nViewHeight
= rcView
.bottom
- rcView
.top
;
919 /* Update Horizontal Scrollbar */
920 scrollInfo
.fMask
= SIF_POS
;
921 if (GetScrollInfo(infoPtr
->hwndSelf
, SB_HORZ
, &scrollInfo
) == FALSE
922 || GETITEMCOUNT(infoPtr
) == 0)
926 scrollInfo
.nMax
= max(nViewWidth
, 0)-1;
928 scrollInfo
.nPage
= nListWidth
;
929 scrollInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
930 TRACE("LVS_ICON/SMALLICON Horz.\n");
931 SetScrollInfo(infoPtr
->hwndSelf
, SB_HORZ
, &scrollInfo
, TRUE
);
933 /* Update Vertical Scrollbar */
934 nListHeight
= infoPtr
->rcList
.bottom
- infoPtr
->rcList
.top
;
935 scrollInfo
.fMask
= SIF_POS
;
936 if (GetScrollInfo(infoPtr
->hwndSelf
, SB_VERT
, &scrollInfo
) == FALSE
937 || GETITEMCOUNT(infoPtr
) == 0)
941 scrollInfo
.nMax
= max(nViewHeight
,0)-1;
943 scrollInfo
.nPage
= nListHeight
;
944 scrollInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
945 TRACE("LVS_ICON/SMALLICON Vert.\n");
946 SetScrollInfo(infoPtr
->hwndSelf
, SB_VERT
, &scrollInfo
, TRUE
);
953 * Prints a message for unsupported window styles.
954 * A kind of TODO list for window styles.
957 * [I] LONG : window style
962 static VOID
LISTVIEW_UnsupportedStyles(LONG lStyle
)
964 if ((LVS_TYPESTYLEMASK
& lStyle
) == LVS_NOSCROLL
)
965 FIXME(" LVS_NOSCROLL\n");
967 if (lStyle
& LVS_NOLABELWRAP
)
968 FIXME(" LVS_NOLABELWRAP\n");
970 if (!(lStyle
& LVS_SHAREIMAGELISTS
))
971 FIXME(" !LVS_SHAREIMAGELISTS\n");
973 if (lStyle
& LVS_SORTASCENDING
)
974 FIXME(" LVS_SORTASCENDING\n");
976 if (lStyle
& LVS_SORTDESCENDING
)
977 FIXME(" LVS_SORTDESCENDING\n");
982 * Aligns the items with the top edge of the window.
985 * [I] infoPtr : valid pointer to the listview structure
990 static VOID
LISTVIEW_AlignTop(LISTVIEW_INFO
*infoPtr
)
992 UINT uView
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
993 INT nListWidth
= infoPtr
->rcList
.right
- infoPtr
->rcList
.left
;
996 INT i
, off_x
=0, off_y
=0;
998 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
1000 /* Since SetItemPosition uses upper-left of icon, and for
1001 style=LVS_ICON the icon is not left adjusted, get the offset */
1002 if (uView
== LVS_ICON
)
1004 off_y
= ICON_TOP_PADDING
;
1005 off_x
= (infoPtr
->iconSpacing
.cx
- infoPtr
->iconSize
.cx
) / 2;
1009 ZeroMemory(&rcView
, sizeof(RECT
));
1010 TRACE("Icon off.x=%d, off.y=%d, left=%d, right=%d\n",
1012 infoPtr
->rcList
.left
, infoPtr
->rcList
.right
);
1014 if (nListWidth
> infoPtr
->nItemWidth
)
1016 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
1018 if ((ptItem
.x
-off_x
) + infoPtr
->nItemWidth
> nListWidth
)
1021 ptItem
.y
+= infoPtr
->nItemHeight
;
1024 LISTVIEW_SetItemPosition(infoPtr
, i
, ptItem
.x
, ptItem
.y
);
1025 ptItem
.x
+= infoPtr
->nItemWidth
;
1026 rcView
.right
= max(rcView
.right
, ptItem
.x
);
1029 rcView
.right
-= off_x
;
1030 rcView
.bottom
= (ptItem
.y
-off_y
) + infoPtr
->nItemHeight
;
1034 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
1036 LISTVIEW_SetItemPosition(infoPtr
, i
, ptItem
.x
, ptItem
.y
);
1037 ptItem
.y
+= infoPtr
->nItemHeight
;
1040 rcView
.right
= infoPtr
->nItemWidth
;
1041 rcView
.bottom
= ptItem
.y
-off_y
;
1044 LISTVIEW_SetViewRect(infoPtr
, &rcView
);
1050 * Aligns the items with the left edge of the window.
1053 * [I] infoPtr : valid pointer to the listview structure
1058 static VOID
LISTVIEW_AlignLeft(LISTVIEW_INFO
*infoPtr
)
1060 UINT uView
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
1061 INT nListHeight
= infoPtr
->rcList
.bottom
- infoPtr
->rcList
.top
;
1064 INT i
, off_x
=0, off_y
=0;
1066 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
1068 /* Since SetItemPosition uses upper-left of icon, and for
1069 style=LVS_ICON the icon is not left adjusted, get the offset */
1070 if (uView
== LVS_ICON
)
1072 off_y
= ICON_TOP_PADDING
;
1073 off_x
= (infoPtr
->iconSpacing
.cx
- infoPtr
->iconSize
.cx
) / 2;
1077 ZeroMemory(&rcView
, sizeof(RECT
));
1078 TRACE("Icon off.x=%d, off.y=%d\n", off_x
, off_y
);
1080 if (nListHeight
> infoPtr
->nItemHeight
)
1082 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
1084 if (ptItem
.y
+ infoPtr
->nItemHeight
> nListHeight
)
1087 ptItem
.x
+= infoPtr
->nItemWidth
;
1090 LISTVIEW_SetItemPosition(infoPtr
, i
, ptItem
.x
, ptItem
.y
);
1091 ptItem
.y
+= infoPtr
->nItemHeight
;
1092 rcView
.bottom
= max(rcView
.bottom
, ptItem
.y
);
1095 rcView
.right
= ptItem
.x
+ infoPtr
->nItemWidth
;
1099 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
1101 LISTVIEW_SetItemPosition(infoPtr
, i
, ptItem
.x
, ptItem
.y
);
1102 ptItem
.x
+= infoPtr
->nItemWidth
;
1105 rcView
.bottom
= infoPtr
->nItemHeight
;
1106 rcView
.right
= ptItem
.x
;
1109 LISTVIEW_SetViewRect(infoPtr
, &rcView
);
1115 * Set the bounding rectangle of all the items.
1118 * [I] infoPtr : valid pointer to the listview structure
1119 * [I] LPRECT : bounding rectangle
1125 static LRESULT
LISTVIEW_SetViewRect(LISTVIEW_INFO
*infoPtr
, LPRECT lprcView
)
1127 BOOL bResult
= FALSE
;
1129 TRACE("(left=%d, top=%d, right=%d, bottom=%d)\n",
1130 lprcView
->left
, lprcView
->top
, lprcView
->right
, lprcView
->bottom
);
1132 if (lprcView
!= NULL
)
1135 infoPtr
->rcView
.left
= lprcView
->left
;
1136 infoPtr
->rcView
.top
= lprcView
->top
;
1137 infoPtr
->rcView
.right
= lprcView
->right
;
1138 infoPtr
->rcView
.bottom
= lprcView
->bottom
;
1146 * Retrieves the bounding rectangle of all the items.
1149 * [I] infoPtr : valid pointer to the listview structure
1150 * [O] LPRECT : bounding rectangle
1156 static LRESULT
LISTVIEW_GetViewRect(LISTVIEW_INFO
*infoPtr
, LPRECT lprcView
)
1158 BOOL bResult
= FALSE
;
1161 TRACE("(lprcView=%p)\n", lprcView
);
1163 if (lprcView
!= NULL
)
1165 bResult
= LISTVIEW_GetOrigin(infoPtr
, &ptOrigin
);
1168 lprcView
->left
= infoPtr
->rcView
.left
+ ptOrigin
.x
;
1169 lprcView
->top
= infoPtr
->rcView
.top
+ ptOrigin
.y
;
1170 lprcView
->right
= infoPtr
->rcView
.right
+ ptOrigin
.x
;
1171 lprcView
->bottom
= infoPtr
->rcView
.bottom
+ ptOrigin
.y
;
1174 TRACE("(left=%d, top=%d, right=%d, bottom=%d)\n",
1175 lprcView
->left
, lprcView
->top
, lprcView
->right
, lprcView
->bottom
);
1183 * Retrieves the subitem pointer associated with the subitem index.
1186 * [I] HDPA : DPA handle for a specific item
1187 * [I] INT : index of subitem
1190 * SUCCESS : subitem pointer
1193 static LISTVIEW_SUBITEM
* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems
,
1196 LISTVIEW_SUBITEM
*lpSubItem
;
1199 for (i
= 1; i
< hdpaSubItems
->nItemCount
; i
++)
1201 lpSubItem
= (LISTVIEW_SUBITEM
*) DPA_GetPtr(hdpaSubItems
, i
);
1202 if (lpSubItem
!= NULL
)
1204 if (lpSubItem
->iSubItem
== nSubItem
)
1216 * Calculates the width of an item.
1219 * [I] infoPtr : valid pointer to the listview structure
1220 * [I] LONG : window style
1223 * Returns item width.
1225 static INT
LISTVIEW_GetItemWidth(LISTVIEW_INFO
*infoPtr
)
1227 LONG style
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
1228 UINT uView
= style
& LVS_TYPEMASK
;
1229 INT nHeaderItemCount
;
1237 if (uView
== LVS_ICON
)
1239 nItemWidth
= infoPtr
->iconSpacing
.cx
;
1241 else if (uView
== LVS_REPORT
)
1243 /* calculate width of header */
1244 nHeaderItemCount
= Header_GetItemCount(infoPtr
->hwndHeader
);
1245 for (i
= 0; i
< nHeaderItemCount
; i
++)
1247 if (Header_GetItemRect(infoPtr
->hwndHeader
, i
, &rcHeaderItem
) != 0)
1249 nItemWidth
+= (rcHeaderItem
.right
- rcHeaderItem
.left
);
1253 else /* for LVS_SMALLICON and LVS_LIST */
1255 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
1257 nLabelWidth
= LISTVIEW_GetLabelWidth(infoPtr
, i
);
1258 nItemWidth
= max(nItemWidth
, nLabelWidth
);
1261 /* default label size */
1262 if (GETITEMCOUNT(infoPtr
) == 0)
1264 nItemWidth
= DEFAULT_COLUMN_WIDTH
;
1268 if (nItemWidth
== 0)
1270 nItemWidth
= DEFAULT_LABEL_WIDTH
;
1275 nItemWidth
+= WIDTH_PADDING
;
1277 if (infoPtr
->himlSmall
!= NULL
)
1279 nItemWidth
+= infoPtr
->iconSize
.cx
;
1282 if (infoPtr
->himlState
!= NULL
)
1284 nItemWidth
+= infoPtr
->iconSize
.cx
;
1286 nItemWidth
= max(DEFAULT_COLUMN_WIDTH
, nItemWidth
);
1292 /* nItemWidth Cannot be Zero */
1300 * Calculates the width of a specific item.
1303 * [I] infoPtr : valid pointer to the listview structure
1304 * [I] LPSTR : string
1307 * Returns the width of an item width a specified string.
1309 static INT
LISTVIEW_CalculateWidth(LISTVIEW_INFO
*infoPtr
, INT nItem
)
1311 UINT uView
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
1312 INT nHeaderItemCount
;
1319 if (uView
== LVS_ICON
)
1321 nItemWidth
= infoPtr
->iconSpacing
.cx
;
1323 else if (uView
== LVS_REPORT
)
1325 /* calculate width of header */
1326 nHeaderItemCount
= Header_GetItemCount(infoPtr
->hwndHeader
);
1327 for (i
= 0; i
< nHeaderItemCount
; i
++)
1329 if (Header_GetItemRect(infoPtr
->hwndHeader
, i
, &rcHeaderItem
) != 0)
1331 nItemWidth
+= (rcHeaderItem
.right
- rcHeaderItem
.left
);
1337 /* get width of string */
1338 nItemWidth
= LISTVIEW_GetLabelWidth(infoPtr
, nItem
);
1340 /* default label size */
1341 if (GETITEMCOUNT(infoPtr
) == 0)
1343 nItemWidth
= DEFAULT_COLUMN_WIDTH
;
1347 if (nItemWidth
== 0)
1349 nItemWidth
= DEFAULT_LABEL_WIDTH
;
1354 nItemWidth
+= WIDTH_PADDING
;
1356 if (infoPtr
->himlSmall
!= NULL
)
1358 nItemWidth
+= infoPtr
->iconSize
.cx
;
1361 if (infoPtr
->himlState
!= NULL
)
1363 nItemWidth
+= infoPtr
->iconSize
.cx
;
1374 * Retrieves and saves important text metrics info for the current
1378 * [I] infoPtr : valid pointer to the listview structure
1381 static VOID
LISTVIEW_SaveTextMetrics(LISTVIEW_INFO
*infoPtr
)
1384 HDC hdc
= GetDC(infoPtr
->hwndSelf
);
1385 HFONT hOldFont
= SelectObject(hdc
, infoPtr
->hFont
);
1386 INT oldHeight
, oldACW
;
1388 GetTextMetricsW(hdc
, &tm
);
1390 oldHeight
= infoPtr
->ntmHeight
;
1391 oldACW
= infoPtr
->ntmAveCharWidth
;
1392 infoPtr
->ntmHeight
= tm
.tmHeight
;
1393 infoPtr
->ntmAveCharWidth
= tm
.tmAveCharWidth
;
1395 SelectObject(hdc
, hOldFont
);
1396 ReleaseDC(infoPtr
->hwndSelf
, hdc
);
1397 TRACE("tmHeight old=%d,new=%d; tmAveCharWidth old=%d,new=%d\n",
1398 oldHeight
, infoPtr
->ntmHeight
, oldACW
, infoPtr
->ntmAveCharWidth
);
1404 * Calculates the height of an item.
1407 * [I] infoPtr : valid pointer to the listview structure
1410 * Returns item height.
1412 static INT
LISTVIEW_GetItemHeight(LISTVIEW_INFO
*infoPtr
)
1414 UINT uView
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
1415 INT nItemHeight
= 0;
1417 if (uView
== LVS_ICON
)
1419 nItemHeight
= infoPtr
->iconSpacing
.cy
;
1423 if(infoPtr
->himlState
|| infoPtr
->himlSmall
)
1424 nItemHeight
= max(infoPtr
->ntmHeight
, infoPtr
->iconSize
.cy
) + HEIGHT_PADDING
;
1426 nItemHeight
= infoPtr
->ntmHeight
;
1433 static void LISTVIEW_PrintSelectionRanges(LISTVIEW_INFO
*infoPtr
)
1435 LISTVIEW_SELECTION
*selection
;
1436 INT topSelection
= infoPtr
->hdpaSelectionRanges
->nItemCount
;
1439 TRACE("Selections are:\n");
1440 for (i
= 0; i
< topSelection
; i
++)
1442 selection
= DPA_GetPtr(infoPtr
->hdpaSelectionRanges
,i
);
1443 TRACE(" %lu - %lu\n",selection
->lower
,selection
->upper
);
1449 * A compare function for selection ranges
1452 * [I] LPVOID : Item 1;
1453 * [I] LPVOID : Item 2;
1454 * [I] LPARAM : flags
1457 * >0 : if Item 1 > Item 2
1458 * <0 : if Item 2 > Item 1
1459 * 0 : if Item 1 == Item 2
1461 static INT CALLBACK
LISTVIEW_CompareSelectionRanges(LPVOID range1
, LPVOID range2
,
1464 int l1
= ((LISTVIEW_SELECTION
*)(range1
))->lower
;
1465 int l2
= ((LISTVIEW_SELECTION
*)(range2
))->lower
;
1466 int u1
= ((LISTVIEW_SELECTION
*)(range1
))->upper
;
1467 int u2
= ((LISTVIEW_SELECTION
*)(range2
))->upper
;
1481 * Adds a selection range.
1484 * [I] infoPtr : valid pointer to the listview structure
1485 * [I] INT : lower item index
1486 * [I] INT : upper item index
1491 static VOID
LISTVIEW_AddSelectionRange(LISTVIEW_INFO
*infoPtr
, INT lItem
, INT uItem
)
1493 LISTVIEW_SELECTION
*selection
;
1494 INT topSelection
= infoPtr
->hdpaSelectionRanges
->nItemCount
;
1495 BOOL lowerzero
= FALSE
;
1497 selection
= (LISTVIEW_SELECTION
*)COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION
));
1498 selection
->lower
= lItem
;
1499 selection
->upper
= uItem
;
1501 TRACE("Add range %i - %i\n", lItem
, uItem
);
1504 LISTVIEW_SELECTION
*checkselection
,*checkselection2
;
1505 INT index
,mergeindex
;
1507 /* find overlapping selections */
1508 /* we want to catch adjacent ranges so expand our range by 1 */
1511 if (selection
->lower
== 0)
1516 index
= DPA_Search(infoPtr
->hdpaSelectionRanges
, selection
, 0,
1517 LISTVIEW_CompareSelectionRanges
,
1519 selection
->upper
--;
1523 selection
->lower
++;
1527 checkselection
= DPA_GetPtr(infoPtr
->hdpaSelectionRanges
,index
);
1528 TRACE("Merge with index %i (%lu - %lu)\n",index
,checkselection
->lower
,
1529 checkselection
->upper
);
1531 checkselection
->lower
= min(selection
->lower
,checkselection
->lower
);
1532 checkselection
->upper
= max(selection
->upper
,checkselection
->upper
);
1534 TRACE("New range (%lu - %lu)\n", checkselection
->lower
,
1535 checkselection
->upper
);
1537 COMCTL32_Free(selection
);
1539 /* merge now common selection ranges in the lower group*/
1542 checkselection
->upper
++;
1543 if (checkselection
->lower
== 0)
1546 checkselection
->lower
--;
1548 TRACE("search lower range (%lu - %lu)\n", checkselection
->lower
,
1549 checkselection
->upper
);
1551 /* not sorted yet */
1552 mergeindex
= DPA_Search(infoPtr
->hdpaSelectionRanges
, checkselection
, 0,
1553 LISTVIEW_CompareSelectionRanges
, 0,
1556 checkselection
->upper
--;
1560 checkselection
->lower
++;
1562 if (mergeindex
>=0 && mergeindex
!= index
)
1564 TRACE("Merge with index %i\n",mergeindex
);
1565 checkselection2
= DPA_GetPtr(infoPtr
->hdpaSelectionRanges
,
1567 checkselection
->lower
= min(checkselection
->lower
,
1568 checkselection2
->lower
);
1569 checkselection
->upper
= max(checkselection
->upper
,
1570 checkselection2
->upper
);
1571 COMCTL32_Free(checkselection2
);
1572 DPA_DeletePtr(infoPtr
->hdpaSelectionRanges
,mergeindex
);
1576 while (mergeindex
> -1 && mergeindex
<index
);
1578 /* merge now common selection ranges in the upper group*/
1581 checkselection
->upper
++;
1582 if (checkselection
->lower
== 0)
1585 checkselection
->lower
--;
1587 TRACE("search upper range %i (%lu - %lu)\n",index
,
1588 checkselection
->lower
, checkselection
->upper
);
1590 /* not sorted yet */
1591 mergeindex
= DPA_Search(infoPtr
->hdpaSelectionRanges
, checkselection
,
1593 LISTVIEW_CompareSelectionRanges
, 0,
1596 checkselection
->upper
--;
1600 checkselection
->lower
++;
1602 if (mergeindex
>=0 && mergeindex
!=index
)
1604 TRACE("Merge with index %i\n",mergeindex
);
1605 checkselection2
= DPA_GetPtr(infoPtr
->hdpaSelectionRanges
,
1607 checkselection
->lower
= min(checkselection
->lower
,
1608 checkselection2
->lower
);
1609 checkselection
->upper
= max(checkselection
->upper
,
1610 checkselection2
->upper
);
1611 COMCTL32_Free(checkselection2
);
1612 DPA_DeletePtr(infoPtr
->hdpaSelectionRanges
,mergeindex
);
1615 while (mergeindex
> -1);
1620 index
= DPA_Search(infoPtr
->hdpaSelectionRanges
, selection
, 0,
1621 LISTVIEW_CompareSelectionRanges
, 0,
1624 TRACE("Insert before index %i\n",index
);
1627 DPA_InsertPtr(infoPtr
->hdpaSelectionRanges
,index
,selection
);
1632 DPA_InsertPtr(infoPtr
->hdpaSelectionRanges
,0,selection
);
1637 DPA_Sort(infoPtr
->hdpaSelectionRanges
,LISTVIEW_CompareSelectionRanges
,0);
1638 LISTVIEW_PrintSelectionRanges(infoPtr
);
1643 * check if a specified index is selected.
1646 * [I] infoPtr : valid pointer to the listview structure
1647 * [I] INT : item index
1652 static BOOL
LISTVIEW_IsSelected(LISTVIEW_INFO
*infoPtr
, INT nItem
)
1654 LISTVIEW_SELECTION selection
;
1657 selection
.upper
= nItem
;
1658 selection
.lower
= nItem
;
1660 index
= DPA_Search(infoPtr
->hdpaSelectionRanges
, &selection
, 0,
1661 LISTVIEW_CompareSelectionRanges
,
1671 * Removes all selection ranges
1674 * [I] infoPtr : valid pointer to the listview structure
1680 static LRESULT
LISTVIEW_RemoveAllSelections(LISTVIEW_INFO
*infoPtr
)
1682 LISTVIEW_SELECTION
*selection
;
1688 ZeroMemory(&item
,sizeof(item
));
1689 item
.stateMask
= LVIS_SELECTED
;
1693 selection
= DPA_GetPtr(infoPtr
->hdpaSelectionRanges
,0);
1696 TRACE("Removing %lu to %lu\n",selection
->lower
, selection
->upper
);
1697 for (i
= selection
->lower
; i
<=selection
->upper
; i
++)
1698 LISTVIEW_SetItemState(infoPtr
,i
,&item
);
1699 LISTVIEW_RemoveSelectionRange(infoPtr
,selection
->lower
,selection
->upper
);
1702 while (infoPtr
->hdpaSelectionRanges
->nItemCount
>0);
1710 * Removes a range selections.
1713 * [I] infoPtr : valid pointer to the listview structure
1714 * [I] INT : lower item index
1715 * [I] INT : upper item index
1720 static VOID
LISTVIEW_RemoveSelectionRange(LISTVIEW_INFO
*infoPtr
, INT lItem
, INT uItem
)
1722 LISTVIEW_SELECTION removeselection
,*checkselection
;
1725 removeselection
.lower
= lItem
;
1726 removeselection
.upper
= uItem
;
1728 TRACE("Remove range %lu - %lu\n",removeselection
.lower
,removeselection
.upper
);
1729 LISTVIEW_PrintSelectionRanges(infoPtr
);
1731 index
= DPA_Search(infoPtr
->hdpaSelectionRanges
, &removeselection
, 0,
1732 LISTVIEW_CompareSelectionRanges
,
1739 checkselection
= DPA_GetPtr(infoPtr
->hdpaSelectionRanges
,
1742 TRACE("Matches range index %i (%lu-%lu)\n",index
,checkselection
->lower
,
1743 checkselection
->upper
);
1746 if ((checkselection
->upper
== removeselection
.upper
) &&
1747 (checkselection
->lower
== removeselection
.lower
))
1749 DPA_DeletePtr(infoPtr
->hdpaSelectionRanges
,index
);
1752 /* case 2: engulf */
1753 else if (((checkselection
->upper
< removeselection
.upper
) &&
1754 (checkselection
->lower
> removeselection
.lower
))||
1755 ((checkselection
->upper
<= removeselection
.upper
) &&
1756 (checkselection
->lower
> removeselection
.lower
)) ||
1757 ((checkselection
->upper
< removeselection
.upper
) &&
1758 (checkselection
->lower
>= removeselection
.lower
)))
1761 DPA_DeletePtr(infoPtr
->hdpaSelectionRanges
,index
);
1762 /* do it again because others may also get caught */
1764 LISTVIEW_RemoveSelectionRange(infoPtr
,lItem
,uItem
);
1766 /* case 3: overlap upper */
1767 else if ((checkselection
->upper
< removeselection
.upper
) &&
1768 (checkselection
->lower
< removeselection
.lower
))
1770 checkselection
->upper
= removeselection
.lower
- 1;
1772 LISTVIEW_RemoveSelectionRange(infoPtr
,lItem
,uItem
);
1774 /* case 4: overlap lower */
1775 else if ((checkselection
->upper
> removeselection
.upper
) &&
1776 (checkselection
->lower
> removeselection
.lower
))
1778 checkselection
->lower
= removeselection
.upper
+ 1;
1780 LISTVIEW_RemoveSelectionRange(infoPtr
,lItem
,uItem
);
1782 /* case 5: fully internal */
1783 else if (checkselection
->upper
== removeselection
.upper
)
1784 checkselection
->upper
= removeselection
.lower
- 1;
1785 else if (checkselection
->lower
== removeselection
.lower
)
1786 checkselection
->lower
= removeselection
.upper
+ 1;
1789 /* bisect the range */
1790 LISTVIEW_SELECTION
*newselection
;
1792 newselection
= (LISTVIEW_SELECTION
*)
1793 COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION
));
1794 newselection
-> lower
= checkselection
->lower
;
1795 newselection
-> upper
= removeselection
.lower
- 1;
1796 checkselection
-> lower
= removeselection
.upper
+ 1;
1797 DPA_InsertPtr(infoPtr
->hdpaSelectionRanges
,index
,newselection
);
1799 DPA_Sort(infoPtr
->hdpaSelectionRanges
,LISTVIEW_CompareSelectionRanges
,0);
1801 LISTVIEW_PrintSelectionRanges(infoPtr
);
1806 * Updates the various indices after an item has been inserted or deleted.
1809 * [I] infoPtr : valid pointer to the listview structure
1810 * [I] INT : item index
1811 * [I] INT : Direction of shift, +1 or -1.
1816 static VOID
LISTVIEW_ShiftIndices(LISTVIEW_INFO
*infoPtr
, INT nItem
, INT direction
)
1818 LISTVIEW_SELECTION selection
,*checkselection
;
1821 TRACE("Shifting %iu, %i steps\n",nItem
,direction
);
1823 selection
.upper
= nItem
;
1824 selection
.lower
= nItem
;
1826 index
= DPA_Search(infoPtr
->hdpaSelectionRanges
, &selection
, 0,
1827 LISTVIEW_CompareSelectionRanges
,
1828 0,DPAS_SORTED
|DPAS_INSERTAFTER
);
1830 while ((index
< infoPtr
->hdpaSelectionRanges
->nItemCount
)&&(index
!= -1))
1832 checkselection
= DPA_GetPtr(infoPtr
->hdpaSelectionRanges
,index
);
1833 if ((checkselection
->lower
>= nItem
)&&
1834 ((int)(checkselection
->lower
+ direction
) >= 0))
1835 checkselection
->lower
+= direction
;
1836 if ((checkselection
->upper
>= nItem
)&&
1837 ((int)(checkselection
->upper
+ direction
) >= 0))
1838 checkselection
->upper
+= direction
;
1842 /* Note that the following will fail if direction != +1 and -1 */
1843 if (infoPtr
->nSelectionMark
> nItem
)
1844 infoPtr
->nSelectionMark
+= direction
;
1845 else if (infoPtr
->nSelectionMark
== nItem
)
1848 infoPtr
->nSelectionMark
+= direction
;
1849 else if (infoPtr
->nSelectionMark
>= GETITEMCOUNT(infoPtr
))
1850 infoPtr
->nSelectionMark
= GETITEMCOUNT(infoPtr
) - 1;
1853 if (infoPtr
->nFocusedItem
> nItem
)
1854 infoPtr
->nFocusedItem
+= direction
;
1855 else if (infoPtr
->nFocusedItem
== nItem
)
1858 infoPtr
->nFocusedItem
+= direction
;
1861 if (infoPtr
->nFocusedItem
>= GETITEMCOUNT(infoPtr
))
1862 infoPtr
->nFocusedItem
= GETITEMCOUNT(infoPtr
) - 1;
1863 if (infoPtr
->nFocusedItem
>= 0)
1864 LISTVIEW_SetItemFocus(infoPtr
, infoPtr
->nFocusedItem
);
1867 /* But we are not supposed to modify nHotItem! */
1873 * Adds a block of selections.
1876 * [I] infoPtr : valid pointer to the listview structure
1877 * [I] INT : item index
1882 static VOID
LISTVIEW_AddGroupSelection(LISTVIEW_INFO
*infoPtr
, INT nItem
)
1884 INT nFirst
= min(infoPtr
->nSelectionMark
, nItem
);
1885 INT nLast
= max(infoPtr
->nSelectionMark
, nItem
);
1892 ZeroMemory(&item
,sizeof(item
));
1893 item
.stateMask
= LVIS_SELECTED
;
1894 item
.state
= LVIS_SELECTED
;
1896 for (i
= nFirst
; i
<= nLast
; i
++)
1897 LISTVIEW_SetItemState(infoPtr
,i
,&item
);
1899 LISTVIEW_SetItemFocus(infoPtr
, nItem
);
1900 infoPtr
->nSelectionMark
= nItem
;
1906 * Adds a single selection.
1909 * [I] infoPtr : valid pointer to the listview structure
1910 * [I] INT : item index
1915 static VOID
LISTVIEW_AddSelection(LISTVIEW_INFO
*infoPtr
, INT nItem
)
1919 ZeroMemory(&item
,sizeof(item
));
1920 item
.state
= LVIS_SELECTED
;
1921 item
.stateMask
= LVIS_SELECTED
;
1923 LISTVIEW_SetItemState(infoPtr
,nItem
,&item
);
1925 LISTVIEW_SetItemFocus(infoPtr
, nItem
);
1926 infoPtr
->nSelectionMark
= nItem
;
1931 * Selects or unselects an item.
1934 * [I] infoPtr : valid pointer to the listview structure
1935 * [I] INT : item index
1941 static BOOL
LISTVIEW_ToggleSelection(LISTVIEW_INFO
*infoPtr
, INT nItem
)
1946 ZeroMemory(&item
,sizeof(item
));
1947 item
.stateMask
= LVIS_SELECTED
;
1949 if (LISTVIEW_IsSelected(infoPtr
,nItem
))
1951 LISTVIEW_SetItemState(infoPtr
,nItem
,&item
);
1956 item
.state
= LVIS_SELECTED
;
1957 LISTVIEW_SetItemState(infoPtr
,nItem
,&item
);
1961 LISTVIEW_SetItemFocus(infoPtr
, nItem
);
1962 infoPtr
->nSelectionMark
= nItem
;
1969 * Selects items based on view coordinates.
1972 * [I] infoPtr : valid pointer to the listview structure
1973 * [I] RECT : selection rectangle
1978 static VOID
LISTVIEW_SetSelectionRect(LISTVIEW_INFO
*infoPtr
, RECT rcSelRect
)
1984 ZeroMemory(&item
,sizeof(item
));
1985 item
.stateMask
= LVIS_SELECTED
;
1987 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
1989 LISTVIEW_GetItemPosition(infoPtr
, i
, &ptItem
);
1991 if (PtInRect(&rcSelRect
, ptItem
))
1992 item
.state
= LVIS_SELECTED
;
1995 LISTVIEW_SetItemState(infoPtr
,i
,&item
);
2001 * Sets a single group selection.
2004 * [I] infoPtr : valid pointer to the listview structure
2005 * [I] INT : item index
2010 static VOID
LISTVIEW_SetGroupSelection(LISTVIEW_INFO
*infoPtr
, INT nItem
)
2012 UINT uView
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
2015 ZeroMemory(&item
,sizeof(item
));
2016 item
.stateMask
= LVIS_SELECTED
;
2018 if ((uView
== LVS_LIST
) || (uView
== LVS_REPORT
))
2023 if (infoPtr
->nSelectionMark
== -1)
2025 infoPtr
->nSelectionMark
= nFirst
= nLast
= nItem
;
2029 nFirst
= min(infoPtr
->nSelectionMark
, nItem
);
2030 nLast
= max(infoPtr
->nSelectionMark
, nItem
);
2033 for (i
= 0; i
<= GETITEMCOUNT(infoPtr
); i
++)
2035 if ((i
< nFirst
) || (i
> nLast
))
2038 item
.state
= LVIS_SELECTED
;
2039 LISTVIEW_SetItemState(infoPtr
,i
,&item
);
2047 LISTVIEW_GetItemBoundBox(infoPtr
, nItem
, &rcItem
);
2048 LISTVIEW_GetItemBoundBox(infoPtr
, infoPtr
->nSelectionMark
, &rcSelMark
);
2049 rcSel
.left
= min(rcSelMark
.left
, rcItem
.left
);
2050 rcSel
.top
= min(rcSelMark
.top
, rcItem
.top
);
2051 rcSel
.right
= max(rcSelMark
.right
, rcItem
.right
);
2052 rcSel
.bottom
= max(rcSelMark
.bottom
, rcItem
.bottom
);
2053 LISTVIEW_SetSelectionRect(infoPtr
, rcSel
);
2054 TRACE("item %d (%d,%d)-(%d,%d), mark %d (%d,%d)-(%d,%d), sel (%d,%d)-(%d,%d)\n",
2055 nItem
, rcItem
.left
, rcItem
.top
, rcItem
.right
, rcItem
.bottom
,
2056 infoPtr
->nSelectionMark
,
2057 rcSelMark
.left
, rcSelMark
.top
, rcSelMark
.right
, rcSelMark
.bottom
,
2058 rcSel
.left
, rcSel
.top
, rcSel
.right
, rcSel
.bottom
);
2062 LISTVIEW_SetItemFocus(infoPtr
, nItem
);
2067 * Manages the item focus.
2070 * [I] infoPtr : valid pointer to the listview structure
2071 * [I] INT : item index
2074 * TRUE : focused item changed
2075 * FALSE : focused item has NOT changed
2077 static BOOL
LISTVIEW_SetItemFocus(LISTVIEW_INFO
*infoPtr
, INT nItem
)
2079 BOOL bResult
= FALSE
;
2082 if (infoPtr
->nFocusedItem
!= nItem
)
2084 if (infoPtr
->nFocusedItem
>= 0)
2086 INT oldFocus
= infoPtr
->nFocusedItem
;
2088 infoPtr
->nFocusedItem
= -1;
2089 ZeroMemory(&lvItem
, sizeof(lvItem
));
2090 lvItem
.stateMask
= LVIS_FOCUSED
;
2091 LISTVIEW_SetItemState(infoPtr
, oldFocus
, &lvItem
);
2095 lvItem
.state
= LVIS_FOCUSED
;
2096 lvItem
.stateMask
= LVIS_FOCUSED
;
2097 LISTVIEW_SetItemState(infoPtr
, nItem
, &lvItem
);
2099 infoPtr
->nFocusedItem
= nItem
;
2100 LISTVIEW_EnsureVisible(infoPtr
, nItem
, FALSE
);
2108 * Sets a single selection.
2111 * [I] infoPtr : valid pointer to the listview structure
2112 * [I] INT : item index
2117 static VOID
LISTVIEW_SetSelection(LISTVIEW_INFO
*infoPtr
, INT nItem
)
2121 ZeroMemory(&lvItem
, sizeof(lvItem
));
2122 lvItem
.stateMask
= LVIS_FOCUSED
;
2123 LISTVIEW_SetItemState(infoPtr
, infoPtr
->nFocusedItem
, &lvItem
);
2125 LISTVIEW_RemoveAllSelections(infoPtr
);
2127 lvItem
.state
= LVIS_FOCUSED
|LVIS_SELECTED
;
2128 lvItem
.stateMask
= LVIS_FOCUSED
|LVIS_SELECTED
;
2129 LISTVIEW_SetItemState(infoPtr
, nItem
, &lvItem
);
2131 infoPtr
->nFocusedItem
= nItem
;
2132 infoPtr
->nSelectionMark
= nItem
;
2137 * Set selection(s) with keyboard.
2140 * [I] infoPtr : valid pointer to the listview structure
2141 * [I] INT : item index
2144 * SUCCESS : TRUE (needs to be repainted)
2145 * FAILURE : FALSE (nothing has changed)
2147 static BOOL
LISTVIEW_KeySelection(LISTVIEW_INFO
*infoPtr
, INT nItem
)
2149 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
2150 WORD wShift
= HIWORD(GetKeyState(VK_SHIFT
));
2151 WORD wCtrl
= HIWORD(GetKeyState(VK_CONTROL
));
2152 BOOL bResult
= FALSE
;
2154 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
2156 if (lStyle
& LVS_SINGLESEL
)
2159 LISTVIEW_SetSelection(infoPtr
, nItem
);
2160 ListView_EnsureVisible(infoPtr
->hwndSelf
, nItem
, FALSE
);
2167 LISTVIEW_SetGroupSelection(infoPtr
, nItem
);
2171 bResult
= LISTVIEW_SetItemFocus(infoPtr
, nItem
);
2176 LISTVIEW_SetSelection(infoPtr
, nItem
);
2177 ListView_EnsureVisible(infoPtr
->hwndSelf
, nItem
, FALSE
);
2187 * Called when the mouse is being actively tracked and has hovered for a specified
2191 * [I] infoPtr : valid pointer to the listview structure
2192 * [I] fwKeys : key indicator
2193 * [I] pts : mouse position
2196 * 0 if the message was processed, non-zero if there was an error
2199 * LVS_EX_TRACKSELECT: An item is automatically selected when the cursor remains
2200 * over the item for a certain period of time.
2203 static LRESULT
LISTVIEW_MouseHover(LISTVIEW_INFO
*infoPtr
, WORD fwKyes
, POINTS pts
)
2205 POINT pt
= { pts
.x
, pts
.y
};
2207 if(infoPtr
->dwExStyle
& LVS_EX_TRACKSELECT
) {
2208 /* FIXME: select the item under the cursor */
2209 LISTVIEW_MouseSelection(infoPtr
, pt
);
2217 * Called whenever WM_MOUSEMOVE is received.
2220 * [I] infoPtr : valid pointer to the listview structure
2221 * [I] fwKeys : key indicator
2222 * [I] pts : mouse position
2225 * 0 if the message is processed, non-zero if there was an error
2227 static LRESULT
LISTVIEW_MouseMove(LISTVIEW_INFO
*infoPtr
, WORD fwKeys
, POINTS pts
)
2229 TRACKMOUSEEVENT trackinfo
;
2231 /* see if we are supposed to be tracking mouse hovering */
2232 if(infoPtr
->dwExStyle
& LVS_EX_TRACKSELECT
) {
2233 /* fill in the trackinfo struct */
2234 trackinfo
.cbSize
= sizeof(TRACKMOUSEEVENT
);
2235 trackinfo
.dwFlags
= TME_QUERY
;
2236 trackinfo
.hwndTrack
= infoPtr
->hwndSelf
;
2237 trackinfo
.dwHoverTime
= infoPtr
->dwHoverTime
;
2239 /* see if we are already tracking this hwnd */
2240 _TrackMouseEvent(&trackinfo
);
2242 if(!(trackinfo
.dwFlags
& TME_HOVER
)) {
2243 trackinfo
.dwFlags
= TME_HOVER
;
2245 /* call TRACKMOUSEEVENT so we receive WM_MOUSEHOVER messages */
2246 _TrackMouseEvent(&trackinfo
);
2255 * Selects an item based on coordinates.
2258 * [I] infoPtr : valid pointer to the listview structure
2259 * [I] pt : mouse click ccordinates
2262 * SUCCESS : item index
2265 static INT
LISTVIEW_MouseSelection(LISTVIEW_INFO
*infoPtr
, POINT pt
)
2267 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
2268 INT i
, topindex
, bottomindex
;
2271 topindex
= LISTVIEW_GetTopIndex(infoPtr
);
2272 if ((lStyle
& LVS_TYPEMASK
) == LVS_REPORT
) {
2273 bottomindex
= topindex
+ LISTVIEW_GetCountPerColumn(infoPtr
) + 1;
2274 bottomindex
= min(bottomindex
, GETITEMCOUNT(infoPtr
));
2276 bottomindex
= GETITEMCOUNT(infoPtr
);
2279 for (i
= topindex
; i
< bottomindex
; i
++)
2281 rcItem
.left
= LVIR_SELECTBOUNDS
;
2282 if (LISTVIEW_GetItemRect(infoPtr
, i
, &rcItem
))
2284 if (PtInRect(&rcItem
, pt
)) return i
;
2296 * [IO] HDPA : dynamic pointer array handle
2297 * [I] INT : column index (subitem index)
2303 static BOOL
LISTVIEW_RemoveColumn(HDPA hdpaItems
, INT nSubItem
)
2305 BOOL bResult
= TRUE
;
2309 for (i
= 0; i
< hdpaItems
->nItemCount
; i
++)
2311 hdpaSubItems
= (HDPA
)DPA_GetPtr(hdpaItems
, i
);
2312 if (hdpaSubItems
!= NULL
)
2314 if (!LISTVIEW_RemoveSubItem(hdpaSubItems
, nSubItem
))
2326 * Removes a subitem at a given position.
2329 * [IO] HDPA : dynamic pointer array handle
2330 * [I] INT : subitem index
2336 static BOOL
LISTVIEW_RemoveSubItem(HDPA hdpaSubItems
, INT nSubItem
)
2338 LISTVIEW_SUBITEM
*lpSubItem
;
2341 for (i
= 1; i
< hdpaSubItems
->nItemCount
; i
++)
2343 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, i
);
2344 if (lpSubItem
!= NULL
)
2346 if (lpSubItem
->iSubItem
== nSubItem
)
2349 if (is_textW(lpSubItem
->pszText
))
2350 COMCTL32_Free(lpSubItem
->pszText
);
2353 COMCTL32_Free(lpSubItem
);
2355 /* free dpa memory */
2356 if (DPA_DeletePtr(hdpaSubItems
, i
) == NULL
)
2359 else if (lpSubItem
->iSubItem
> nSubItem
)
2369 * Compares the item information.
2372 * [I] LISTVIEW_ITEM *: destination item
2373 * [I] LPLVITEM : source item
2374 * [I] isW : TRUE if lpLVItem is Unicode, FALSE it it's ANSI
2377 * SUCCCESS : TRUE (EQUAL)
2378 * FAILURE : FALSE (NOT EQUAL)
2380 static UINT
LISTVIEW_GetItemChangesT(LISTVIEW_ITEM
*lpItem
, LPLVITEMW lpLVItem
, BOOL isW
)
2384 if ((lpItem
!= NULL
) && (lpLVItem
!= NULL
))
2386 if (lpLVItem
->mask
& LVIF_STATE
)
2388 if ((lpItem
->state
& lpLVItem
->stateMask
) !=
2389 (lpLVItem
->state
& lpLVItem
->stateMask
))
2390 uChanged
|= LVIF_STATE
;
2393 if (lpLVItem
->mask
& LVIF_IMAGE
)
2395 if (lpItem
->iImage
!= lpLVItem
->iImage
)
2396 uChanged
|= LVIF_IMAGE
;
2399 if (lpLVItem
->mask
& LVIF_PARAM
)
2401 if (lpItem
->lParam
!= lpLVItem
->lParam
)
2402 uChanged
|= LVIF_PARAM
;
2405 if (lpLVItem
->mask
& LVIF_INDENT
)
2407 if (lpItem
->iIndent
!= lpLVItem
->iIndent
)
2408 uChanged
|= LVIF_INDENT
;
2411 if (lpLVItem
->mask
& LVIF_TEXT
)
2413 if (lpLVItem
->pszText
== LPSTR_TEXTCALLBACKW
)
2415 if (lpItem
->pszText
!= LPSTR_TEXTCALLBACKW
)
2416 uChanged
|= LVIF_TEXT
;
2420 if (lpItem
->pszText
== LPSTR_TEXTCALLBACKW
)
2422 uChanged
|= LVIF_TEXT
;
2426 if (lpLVItem
->pszText
)
2428 if (lpItem
->pszText
)
2430 LPWSTR pszText
= textdupTtoW(lpLVItem
->pszText
, isW
);
2431 if (pszText
&& strcmpW(pszText
, lpItem
->pszText
))
2432 uChanged
|= LVIF_TEXT
;
2433 textfreeT(pszText
, isW
);
2437 uChanged
|= LVIF_TEXT
;
2442 if (lpItem
->pszText
)
2443 uChanged
|= LVIF_TEXT
;
2454 * Initializes item attributes.
2457 * [I] infoPtr : valid pointer to the listview structure
2458 * [O] LISTVIEW_ITEM *: destination item
2459 * [I] LPLVITEM : source item
2460 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
2466 static BOOL
LISTVIEW_InitItemT(LISTVIEW_INFO
*infoPtr
, LISTVIEW_ITEM
*lpItem
,
2467 LPLVITEMW lpLVItem
, BOOL isW
)
2469 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
2470 BOOL bResult
= FALSE
;
2472 if ((lpItem
!= NULL
) && (lpLVItem
!= NULL
))
2476 if (lpLVItem
->mask
& LVIF_STATE
)
2478 lpItem
->state
&= ~lpLVItem
->stateMask
;
2479 lpItem
->state
|= (lpLVItem
->state
& lpLVItem
->stateMask
);
2482 if (lpLVItem
->mask
& LVIF_IMAGE
)
2483 lpItem
->iImage
= lpLVItem
->iImage
;
2485 if (lpLVItem
->mask
& LVIF_PARAM
)
2486 lpItem
->lParam
= lpLVItem
->lParam
;
2488 if (lpLVItem
->mask
& LVIF_INDENT
)
2489 lpItem
->iIndent
= lpLVItem
->iIndent
;
2491 if (lpLVItem
->mask
& LVIF_TEXT
)
2493 if (lpLVItem
->pszText
== LPSTR_TEXTCALLBACKW
)
2495 if ((lStyle
& LVS_SORTASCENDING
) || (lStyle
& LVS_SORTDESCENDING
))
2498 if (is_textW(lpItem
->pszText
))
2499 COMCTL32_Free(lpItem
->pszText
);
2501 lpItem
->pszText
= LPSTR_TEXTCALLBACKW
;
2504 bResult
= textsetptrT(&lpItem
->pszText
, lpLVItem
->pszText
, isW
);
2513 * Initializes subitem attributes.
2515 * NOTE: The documentation specifies that the operation fails if the user
2516 * tries to set the indent of a subitem.
2519 * [I] infoPtr : valid pointer to the listview structure
2520 * [O] LISTVIEW_SUBITEM *: destination subitem
2521 * [I] LPLVITEM : source subitem
2522 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
2528 static BOOL
LISTVIEW_InitSubItemT(LISTVIEW_INFO
*infoPtr
, LISTVIEW_SUBITEM
*lpSubItem
,
2529 LPLVITEMW lpLVItem
, BOOL isW
)
2531 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
2532 BOOL bResult
= FALSE
;
2534 TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem
, isW
), isW
);
2536 if ((lpSubItem
!= NULL
) && (lpLVItem
!= NULL
))
2538 if (!(lpLVItem
->mask
& LVIF_INDENT
))
2542 lpSubItem
->iSubItem
= lpLVItem
->iSubItem
;
2544 if (lpLVItem
->mask
& LVIF_IMAGE
)
2545 lpSubItem
->iImage
= lpLVItem
->iImage
;
2547 if (lpLVItem
->mask
& LVIF_TEXT
)
2549 if (lpLVItem
->pszText
== LPSTR_TEXTCALLBACKW
)
2551 if ((lStyle
& LVS_SORTASCENDING
) || (lStyle
& LVS_SORTDESCENDING
))
2554 if (is_textW(lpSubItem
->pszText
))
2555 COMCTL32_Free(lpSubItem
->pszText
);
2557 lpSubItem
->pszText
= LPSTR_TEXTCALLBACKW
;
2560 bResult
= textsetptrT(&lpSubItem
->pszText
, lpLVItem
->pszText
, isW
);
2570 * Adds a subitem at a given position (column index).
2573 * [I] infoPtr : valid pointer to the listview structure
2574 * [I] LPLVITEM : new subitem atttributes
2575 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
2581 static BOOL
LISTVIEW_AddSubItemT(LISTVIEW_INFO
*infoPtr
, LPLVITEMW lpLVItem
, BOOL isW
)
2583 LISTVIEW_SUBITEM
*lpSubItem
= NULL
;
2584 BOOL bResult
= FALSE
;
2586 INT nPosition
, nItem
;
2587 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
2589 TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem
, isW
), isW
);
2591 if (lStyle
& LVS_OWNERDATA
)
2594 if (lpLVItem
!= NULL
)
2596 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
);
2597 if (hdpaSubItems
!= NULL
)
2599 lpSubItem
= (LISTVIEW_SUBITEM
*)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM
));
2600 if (lpSubItem
!= NULL
)
2602 ZeroMemory(lpSubItem
, sizeof(LISTVIEW_SUBITEM
));
2603 if (LISTVIEW_InitSubItemT(infoPtr
, lpSubItem
, lpLVItem
, isW
))
2605 nPosition
= LISTVIEW_FindInsertPosition(hdpaSubItems
,
2606 lpSubItem
->iSubItem
);
2607 nItem
= DPA_InsertPtr(hdpaSubItems
, nPosition
, lpSubItem
);
2608 if (nItem
!= -1) bResult
= TRUE
;
2614 /* cleanup if unsuccessful */
2615 if (!bResult
&& lpSubItem
) COMCTL32_Free(lpSubItem
);
2622 * Finds the dpa insert position (array index).
2625 * [I] infoPtr : valid pointer to the listview structure
2626 * [I] INT : subitem index
2632 static INT
LISTVIEW_FindInsertPosition(HDPA hdpaSubItems
, INT nSubItem
)
2634 LISTVIEW_SUBITEM
*lpSubItem
;
2637 for (i
= 1; i
< hdpaSubItems
->nItemCount
; i
++)
2639 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, i
);
2640 if (lpSubItem
&& lpSubItem
->iSubItem
> nSubItem
)
2644 return hdpaSubItems
->nItemCount
;
2649 * Retrieves a listview subitem at a given position (column index).
2652 * [I] infoPtr : valid pointer to the listview structure
2653 * [I] INT : subitem index
2659 static LISTVIEW_SUBITEM
* LISTVIEW_GetSubItem(HDPA hdpaSubItems
, INT nSubItem
)
2661 LISTVIEW_SUBITEM
*lpSubItem
;
2664 for (i
= 1; i
< hdpaSubItems
->nItemCount
; i
++)
2666 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, i
);
2667 if (lpSubItem
!= NULL
)
2669 if (lpSubItem
->iSubItem
== nSubItem
)
2671 else if (lpSubItem
->iSubItem
> nSubItem
)
2681 * Sets item attributes.
2684 * [I] infoPtr : valid pointer to the listview structure
2685 * [I] LPLVITEM : new item atttributes
2686 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
2692 static BOOL
LISTVIEW_SetMainItemT(LISTVIEW_INFO
*infoPtr
, LPLVITEMW lpLVItem
, BOOL isW
)
2694 BOOL bResult
= FALSE
;
2696 LISTVIEW_ITEM
*lpItem
;
2698 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
2700 UINT uView
= lStyle
& LVS_TYPEMASK
;
2704 TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem
, isW
), isW
);
2706 if (lStyle
& LVS_OWNERDATA
)
2708 if ((lpLVItem
->iSubItem
== 0)&&(lpLVItem
->mask
== LVIF_STATE
))
2712 ZeroMemory(&itm
, sizeof(itm
));
2713 itm
.mask
= LVIF_STATE
| LVIF_PARAM
;
2714 itm
.stateMask
= LVIS_FOCUSED
| LVIS_SELECTED
;
2715 itm
.iItem
= lpLVItem
->iItem
;
2717 ListView_GetItemW(infoPtr
->hwndSelf
, &itm
);
2720 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
2721 nmlv
.uNewState
= lpLVItem
->state
;
2722 nmlv
.uOldState
= itm
.state
;
2723 nmlv
.uChanged
= LVIF_STATE
;
2724 nmlv
.lParam
= itm
.lParam
;
2725 nmlv
.iItem
= lpLVItem
->iItem
;
2727 if ((itm
.state
& lpLVItem
->stateMask
) !=
2728 (lpLVItem
->state
& lpLVItem
->stateMask
))
2731 * As per MSDN LVN_ITEMCHANGING notifications are _NOT_ sent
2732 * by LVS_OWERNDATA list controls
2734 if (lpLVItem
->stateMask
& LVIS_FOCUSED
)
2736 if (lpLVItem
->state
& LVIS_FOCUSED
)
2737 infoPtr
->nFocusedItem
= lpLVItem
->iItem
;
2738 else if (infoPtr
->nFocusedItem
== lpLVItem
->iItem
)
2739 infoPtr
->nFocusedItem
= -1;
2741 if (lpLVItem
->stateMask
& LVIS_SELECTED
)
2743 if (lpLVItem
->state
& LVIS_SELECTED
)
2745 if (lStyle
& LVS_SINGLESEL
) LISTVIEW_RemoveAllSelections(infoPtr
);
2746 LISTVIEW_AddSelectionRange(infoPtr
,lpLVItem
->iItem
,lpLVItem
->iItem
);
2749 LISTVIEW_RemoveSelectionRange(infoPtr
,lpLVItem
->iItem
,
2753 listview_notify(infoPtr
, LVN_ITEMCHANGED
, &nmlv
);
2755 rcItem
.left
= LVIR_BOUNDS
;
2756 LISTVIEW_GetItemRect(infoPtr
, lpLVItem
->iItem
, &rcItem
);
2757 if (!infoPtr
->bIsDrawing
)
2758 InvalidateRect(infoPtr
->hwndSelf
, &rcItem
, TRUE
);
2765 if (lpLVItem
!= NULL
)
2767 if (lpLVItem
->iSubItem
== 0)
2769 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
);
2770 if (hdpaSubItems
!= NULL
&& hdpaSubItems
!= (HDPA
)-1)
2772 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, lpLVItem
->iSubItem
);
2775 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
2776 nmlv
.lParam
= lpItem
->lParam
;
2777 uChanged
= LISTVIEW_GetItemChangesT(lpItem
, lpLVItem
, isW
);
2780 if (uChanged
& LVIF_STATE
)
2782 nmlv
.uNewState
= lpLVItem
->state
& lpLVItem
->stateMask
;
2783 nmlv
.uOldState
= lpItem
->state
& lpLVItem
->stateMask
;
2785 if (nmlv
.uNewState
& LVIS_SELECTED
)
2788 * This is redundant if called through SetSelection
2790 * however is required if the used directly calls SetItem
2791 * to set the selection.
2793 if (lStyle
& LVS_SINGLESEL
)
2794 LISTVIEW_RemoveAllSelections(infoPtr
);
2796 LISTVIEW_AddSelectionRange(infoPtr
,lpLVItem
->iItem
,
2799 else if (lpLVItem
->stateMask
& LVIS_SELECTED
)
2801 LISTVIEW_RemoveSelectionRange(infoPtr
,lpLVItem
->iItem
,
2804 if (nmlv
.uNewState
& LVIS_FOCUSED
)
2807 * This is a fun hoop to jump to try to catch if
2808 * the user is calling us directly to call focus or if
2809 * this function is being called as a result of a
2810 * SetItemFocus call.
2812 if (infoPtr
->nFocusedItem
>= 0)
2813 LISTVIEW_SetItemFocus(infoPtr
, lpLVItem
->iItem
);
2817 nmlv
.uChanged
= uChanged
;
2818 nmlv
.iItem
= lpLVItem
->iItem
;
2819 nmlv
.lParam
= lpItem
->lParam
;
2820 /* send LVN_ITEMCHANGING notification */
2821 listview_notify(infoPtr
, LVN_ITEMCHANGING
, &nmlv
);
2823 /* copy information */
2824 bResult
= LISTVIEW_InitItemT(infoPtr
, lpItem
, lpLVItem
, isW
);
2826 /* if LVS_LIST or LVS_SMALLICON, update the width of the items
2827 based on the width of the items text */
2828 if((uView
== LVS_LIST
) || (uView
== LVS_SMALLICON
))
2830 item_width
= LISTVIEW_GetStringWidthT(infoPtr
, lpItem
->pszText
, TRUE
);
2832 if(item_width
> infoPtr
->nItemWidth
)
2833 infoPtr
->nItemWidth
= item_width
;
2836 /* send LVN_ITEMCHANGED notification */
2837 listview_notify(infoPtr
, LVN_ITEMCHANGED
, &nmlv
);
2846 rcItem
.left
= LVIR_BOUNDS
;
2847 LISTVIEW_GetItemRect(infoPtr
, lpLVItem
->iItem
, &rcItem
);
2848 if (!infoPtr
->bIsDrawing
)
2849 InvalidateRect(infoPtr
->hwndSelf
, &rcItem
, TRUE
);
2861 * Sets subitem attributes.
2864 * [I] infoPtr : valid pointer to the listview structure
2865 * [I] LPLVITEM : new subitem atttributes
2866 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
2872 static BOOL
LISTVIEW_SetSubItemT(LISTVIEW_INFO
*infoPtr
, LPLVITEMW lpLVItem
, BOOL isW
)
2874 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
2875 BOOL bResult
= FALSE
;
2877 LISTVIEW_SUBITEM
*lpSubItem
;
2880 TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem
, isW
), isW
);
2882 if (lStyle
& LVS_OWNERDATA
)
2885 if (lpLVItem
!= NULL
)
2887 if (lpLVItem
->iSubItem
> 0)
2889 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
);
2890 if (hdpaSubItems
!= NULL
)
2892 /* set subitem only if column is present */
2893 if (Header_GetItemCount(infoPtr
->hwndHeader
) > lpLVItem
->iSubItem
)
2895 lpSubItem
= LISTVIEW_GetSubItem(hdpaSubItems
, lpLVItem
->iSubItem
);
2896 if (lpSubItem
!= NULL
)
2897 bResult
= LISTVIEW_InitSubItemT(infoPtr
, lpSubItem
, lpLVItem
, isW
);
2899 bResult
= LISTVIEW_AddSubItemT(infoPtr
, lpLVItem
, isW
);
2901 rcItem
.left
= LVIR_BOUNDS
;
2902 LISTVIEW_GetItemRect(infoPtr
, lpLVItem
->iItem
, &rcItem
);
2903 InvalidateRect(infoPtr
->hwndSelf
, &rcItem
, FALSE
);
2914 * Sets item attributes.
2917 * [I] infoPtr : valid pointer to the listview structure
2918 * [I] LPLVITEM : new item atttributes
2919 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
2925 static BOOL
LISTVIEW_SetItemT(LISTVIEW_INFO
*infoPtr
, LPLVITEMW lpLVItem
, BOOL isW
)
2928 if (!lpLVItem
|| lpLVItem
->iItem
< 0 ||
2929 lpLVItem
->iItem
>=GETITEMCOUNT(infoPtr
))
2931 if (lpLVItem
->iSubItem
== 0)
2932 return LISTVIEW_SetMainItemT(infoPtr
, lpLVItem
, isW
);
2934 return LISTVIEW_SetSubItemT(infoPtr
, lpLVItem
, isW
);
2939 * Retrieves the index of the item at coordinate (0, 0) of the client area.
2942 * [I] infoPtr : valid pointer to the listview structure
2947 static INT
LISTVIEW_GetTopIndex(LISTVIEW_INFO
*infoPtr
)
2949 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
2950 UINT uView
= lStyle
& LVS_TYPEMASK
;
2952 SCROLLINFO scrollInfo
;
2954 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
2955 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
2956 scrollInfo
.fMask
= SIF_POS
;
2958 if (uView
== LVS_LIST
)
2960 if ((lStyle
& WS_HSCROLL
) && GetScrollInfo(infoPtr
->hwndSelf
, SB_HORZ
, &scrollInfo
))
2961 nItem
= scrollInfo
.nPos
* LISTVIEW_GetCountPerColumn(infoPtr
);
2963 else if (uView
== LVS_REPORT
)
2965 if ((lStyle
& WS_VSCROLL
) && GetScrollInfo(infoPtr
->hwndSelf
, SB_VERT
, &scrollInfo
))
2966 nItem
= scrollInfo
.nPos
;
2977 * [I] infoPtr : valid pointer to the listview structure
2978 * [I] HDC : device context handle
2979 * [I] INT : item index
2980 * [I] INT : subitem index
2981 * [I] RECT * : clipping rectangle
2986 static VOID
LISTVIEW_DrawSubItem(LISTVIEW_INFO
*infoPtr
, HDC hdc
, INT nItem
, INT nSubItem
,
2987 RECT rcItem
, BOOL Selected
)
2989 WCHAR szDispText
[DISP_TEXT_SIZE
];
2992 UINT textoutOptions
= ETO_CLIPPED
| ETO_OPAQUE
;
2995 INT nLabelWidth
= 0;
2997 TRACE("(hdc=%x, nItem=%d, nSubItem=%d)\n", hdc
,
3000 /* get information needed for drawing the item */
3001 ZeroMemory(&lvItem
, sizeof(lvItem
));
3002 lvItem
.mask
= LVIF_TEXT
;
3003 lvItem
.iItem
= nItem
;
3004 lvItem
.iSubItem
= nSubItem
;
3005 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
3006 lvItem
.pszText
= szDispText
;
3007 *lvItem
.pszText
= '\0';
3008 LISTVIEW_GetItemW(infoPtr
, &lvItem
, TRUE
);
3009 TRACE(" lvItem=%s\n", debuglvitem_t(&lvItem
, TRUE
));
3011 ZeroMemory(&lvColumn
, sizeof(lvColumn
));
3012 lvColumn
.mask
= LVCF_FMT
;
3013 LISTVIEW_GetColumnT(infoPtr
, nSubItem
, &lvColumn
, TRUE
);
3014 textLeft
= rcItem
.left
;
3015 TRACE("lvColumn.fmt=%d\n", lvColumn
.fmt
);
3016 if (lvColumn
.fmt
!= LVCFMT_LEFT
)
3018 if ((nLabelWidth
= LISTVIEW_GetStringWidthT(infoPtr
, lvItem
.pszText
, TRUE
)))
3020 if (lvColumn
.fmt
== LVCFMT_RIGHT
)
3021 textLeft
= rcItem
.right
- nLabelWidth
;
3023 textLeft
= rcItem
.left
+ (rcItem
.right
-rcItem
.left
-nLabelWidth
)/2;
3028 /* redraw the background of the item */
3030 if(infoPtr
->nColumnCount
== (nSubItem
+ 1))
3031 rcTemp
.right
= infoPtr
->rcList
.right
;
3033 rcTemp
.right
+= WIDTH_PADDING
;
3035 LISTVIEW_FillBackground(infoPtr
, hdc
, &rcTemp
);
3037 /* set item colors */
3038 if (ListView_GetItemState(infoPtr
->hwndSelf
,nItem
,LVIS_SELECTED
) && Selected
)
3040 if (infoPtr
->bFocus
)
3042 SetBkColor(hdc
, comctl32_color
.clrHighlight
);
3043 SetTextColor(hdc
, comctl32_color
.clrHighlightText
);
3047 SetBkColor(hdc
, comctl32_color
.clr3dFace
);
3048 SetTextColor(hdc
, comctl32_color
.clrBtnText
);
3053 if ( (infoPtr
->clrTextBk
== CLR_DEFAULT
) || (infoPtr
->clrTextBk
== CLR_NONE
) )
3055 SetBkMode(hdc
, TRANSPARENT
);
3056 textoutOptions
&= ~ETO_OPAQUE
;
3060 SetBkMode(hdc
, OPAQUE
);
3061 SetBkColor(hdc
, infoPtr
->clrTextBk
);
3064 SetTextColor(hdc
, infoPtr
->clrText
);
3067 TRACE("drawing text %s, l=%d, t=%d, rect=(%d,%d)-(%d,%d)\n",
3068 debugstr_w(lvItem
.pszText
), textLeft
, rcItem
.top
,
3069 rcItem
.left
, rcItem
.top
, rcItem
.right
, rcItem
.bottom
);
3070 ExtTextOutW(hdc
, textLeft
, rcItem
.top
, textoutOptions
,
3071 &rcItem
, lvItem
.pszText
, lstrlenW(lvItem
.pszText
), NULL
);
3075 /* fill in the gap */
3077 if (nSubItem
< Header_GetItemCount(infoPtr
->hwndHeader
)-1)
3079 CopyRect(&rec
,&rcItem
);
3080 rec
.left
= rec
.right
;
3081 rec
.right
= rec
.left
+REPORT_MARGINX
;
3082 ExtTextOutW(hdc
, rec
.left
, rec
.top
, textoutOptions
,
3083 &rec
, NULL
, 0, NULL
);
3085 CopyRect(&rec
,&rcItem
);
3086 rec
.right
= rec
.left
;
3087 rec
.left
= rec
.left
- REPORT_MARGINX
;
3088 ExtTextOutW(hdc
, rec
.left
, rec
.top
, textoutOptions
,
3089 &rec
, NULL
, 0, NULL
);
3099 * [I] infoPtr : valid pointer to the listview structure
3100 * [I] HDC : device context handle
3101 * [I] INT : item index
3102 * [I] RECT * : clipping rectangle
3107 static VOID
LISTVIEW_DrawItem(LISTVIEW_INFO
*infoPtr
, HDC hdc
, INT nItem
, RECT rcItem
, BOOL FullSelect
, RECT
* SuggestedFocus
)
3109 WCHAR szDispText
[DISP_TEXT_SIZE
];
3114 DWORD dwTextColor
,dwTextX
;
3115 BOOL bImage
= FALSE
;
3117 UINT textoutOptions
= ETO_OPAQUE
| ETO_CLIPPED
;
3120 TRACE("(hdc=%x, nItem=%d)\n", hdc
, nItem
);
3123 /* get information needed for drawing the item */
3124 ZeroMemory(&lvItem
, sizeof(lvItem
));
3125 lvItem
.mask
= LVIF_TEXT
| LVIF_IMAGE
| LVIF_STATE
| LVIF_INDENT
;
3126 lvItem
.stateMask
= LVIS_SELECTED
| LVIS_STATEIMAGEMASK
;
3127 lvItem
.iItem
= nItem
;
3128 lvItem
.iSubItem
= 0;
3129 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
3130 lvItem
.pszText
= szDispText
;
3131 *lvItem
.pszText
= '\0';
3132 LISTVIEW_GetItemW(infoPtr
, &lvItem
, TRUE
);
3133 TRACE(" lvItem=%s\n", debuglvitem_t(&lvItem
, TRUE
));
3135 /* redraw the background of the item */
3137 if(infoPtr
->nColumnCount
== (nItem
+ 1))
3138 rcTemp
.right
= infoPtr
->rcList
.right
;
3140 rcTemp
.right
+=WIDTH_PADDING
;
3142 LISTVIEW_FillBackground(infoPtr
, hdc
, &rcTemp
);
3145 if (lvItem
.iIndent
>0 && infoPtr
->iconSize
.cx
> 0)
3147 rcItem
.left
+= infoPtr
->iconSize
.cx
* lvItem
.iIndent
;
3150 SuggestedFocus
->left
+= infoPtr
->iconSize
.cx
* lvItem
.iIndent
;
3154 if (infoPtr
->himlState
!= NULL
)
3156 UINT uStateImage
= (lvItem
.state
& LVIS_STATEIMAGEMASK
) >> 12;
3157 if (uStateImage
> 0)
3159 ImageList_Draw(infoPtr
->himlState
, uStateImage
- 1, hdc
, rcItem
.left
,
3160 rcItem
.top
, ILD_NORMAL
);
3163 rcItem
.left
+= infoPtr
->iconSize
.cx
;
3165 SuggestedFocus
->left
+= infoPtr
->iconSize
.cx
;
3170 if (infoPtr
->himlSmall
!= NULL
)
3172 if ((lvItem
.state
& LVIS_SELECTED
) && (infoPtr
->bFocus
) &&
3175 ImageList_SetBkColor(infoPtr
->himlSmall
, CLR_NONE
);
3176 ImageList_Draw(infoPtr
->himlSmall
, lvItem
.iImage
, hdc
, rcItem
.left
,
3177 rcItem
.top
, ILD_SELECTED
);
3179 else if (lvItem
.iImage
>=0)
3181 ImageList_SetBkColor(infoPtr
->himlSmall
, CLR_NONE
);
3182 ImageList_Draw(infoPtr
->himlSmall
, lvItem
.iImage
, hdc
, rcItem
.left
,
3183 rcItem
.top
, ILD_NORMAL
);
3186 rcItem
.left
+= infoPtr
->iconSize
.cx
;
3189 SuggestedFocus
->left
+= infoPtr
->iconSize
.cx
;
3193 /* Don't bother painting item being edited */
3194 if (infoPtr
->bEditing
&& lvItem
.state
& LVIS_FOCUSED
&& !FullSelect
)
3197 if ((lvItem
.state
& LVIS_SELECTED
) && (infoPtr
->bFocus
))
3199 /* set item colors */
3200 dwBkColor
= SetBkColor(hdc
, comctl32_color
.clrHighlight
);
3201 dwTextColor
= SetTextColor(hdc
, comctl32_color
.clrHighlightText
);
3202 /* set raster mode */
3203 nMixMode
= SetROP2(hdc
, R2_XORPEN
);
3205 else if ((GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_SHOWSELALWAYS
) &&
3206 (lvItem
.state
& LVIS_SELECTED
) && (!infoPtr
->bFocus
))
3208 dwBkColor
= SetBkColor(hdc
, comctl32_color
.clr3dFace
);
3209 dwTextColor
= SetTextColor(hdc
, comctl32_color
.clrBtnText
);
3210 /* set raster mode */
3211 nMixMode
= SetROP2(hdc
, R2_COPYPEN
);
3215 /* set item colors */
3216 if ( (infoPtr
->clrTextBk
== CLR_DEFAULT
) || (infoPtr
->clrTextBk
== CLR_NONE
) )
3218 dwBkColor
= GetBkColor(hdc
);
3219 iBkMode
= SetBkMode(hdc
, TRANSPARENT
);
3220 textoutOptions
&= ~ETO_OPAQUE
;
3224 dwBkColor
= SetBkColor(hdc
, infoPtr
->clrTextBk
);
3225 iBkMode
= SetBkMode(hdc
, OPAQUE
);
3228 dwTextColor
= SetTextColor(hdc
, infoPtr
->clrText
);
3229 /* set raster mode */
3230 nMixMode
= SetROP2(hdc
, R2_COPYPEN
);
3233 nLabelWidth
= LISTVIEW_GetStringWidthT(infoPtr
, lvItem
.pszText
, TRUE
);
3234 if (rcItem
.left
+ nLabelWidth
< rcItem
.right
)
3237 rcItem
.right
= rcItem
.left
+ nLabelWidth
+ TRAILING_PADDING
;
3239 rcItem
.right
+= IMAGE_PADDING
;
3243 dwTextX
= rcItem
.left
+ 1;
3245 dwTextX
+= IMAGE_PADDING
;
3247 if (lvItem
.pszText
) {
3248 TRACE("drawing text rect=(%d,%d)-(%d,%d)\n",
3249 rcItem
.left
, rcItem
.top
, rcItem
.right
, rcItem
.bottom
);
3250 ExtTextOutW(hdc
, dwTextX
, rcItem
.top
, textoutOptions
,
3251 &rcItem
, lvItem
.pszText
, lstrlenW(lvItem
.pszText
), NULL
);
3254 if ((FullSelect
)&&(Header_GetItemCount(infoPtr
->hwndHeader
) > 1))
3256 /* fill in the gap */
3258 CopyRect(&rec
,&rcItem
);
3259 rec
.left
= rec
.right
;
3260 rec
.right
= rec
.left
+REPORT_MARGINX
;
3261 ExtTextOutW(hdc
, rec
.left
, rec
.top
, textoutOptions
,
3262 &rec
, NULL
, 0, NULL
);
3266 CopyRect(SuggestedFocus
,&rcItem
);
3270 SetROP2(hdc
, R2_COPYPEN
);
3271 SetBkColor(hdc
, dwBkColor
);
3272 SetTextColor(hdc
, dwTextColor
);
3274 SetBkMode(hdc
, iBkMode
);
3280 * Draws an item when in large icon display mode.
3283 * [I] infoPtr : valid pointer to the listview structure
3284 * [I] HDC : device context handle
3285 * [I] INT : item index
3286 * [I] RECT : clipping rectangle
3287 * [O] RECT * : The text rectangle about which to draw the focus
3292 static VOID
LISTVIEW_DrawLargeItem(LISTVIEW_INFO
*infoPtr
, HDC hdc
, INT nItem
, RECT rcItem
,
3293 RECT
*SuggestedFocus
)
3295 WCHAR szDispText
[DISP_TEXT_SIZE
] = { '\0' };
3297 UINT uFormat
= DT_TOP
| DT_CENTER
| DT_WORDBREAK
| DT_NOPREFIX
|
3299 /* Maintain this format in line with the one in LISTVIEW_UpdateLargeItemLabelRect*/
3302 TRACE("(hdc=%x, nItem=%d, left=%d, top=%d, right=%d, bottom=%d)\n",
3303 hdc
, nItem
, rcItem
.left
, rcItem
.top
, rcItem
.right
, rcItem
.bottom
);
3305 /* get information needed for drawing the item */
3306 ZeroMemory(&lvItem
, sizeof(lvItem
));
3307 lvItem
.mask
= LVIF_TEXT
| LVIF_IMAGE
| LVIF_STATE
;
3308 lvItem
.stateMask
= LVIS_SELECTED
| LVIS_FOCUSED
;
3309 lvItem
.iItem
= nItem
;
3310 lvItem
.iSubItem
= 0;
3311 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
3312 lvItem
.pszText
= szDispText
;
3313 *lvItem
.pszText
= '\0';
3314 LISTVIEW_GetItemW(infoPtr
, &lvItem
, FALSE
);
3315 TRACE(" lvItem=%s\n", debuglvitem_t(&lvItem
, TRUE
));
3317 /* redraw the background of the item */
3319 if(infoPtr
->nColumnCount
== (nItem
+ 1))
3320 rcTemp
.right
= infoPtr
->rcList
.right
;
3322 rcTemp
.right
+=WIDTH_PADDING
;
3323 /* The comment doesn't say WIDTH_PADDING applies to large icons */
3325 TRACE("background rect (%d,%d)-(%d,%d)\n",
3326 rcTemp
.left
, rcTemp
.top
, rcTemp
.right
, rcTemp
.bottom
);
3328 LISTVIEW_FillBackground(infoPtr
, hdc
, &rcTemp
);
3331 /* Figure out text colours etc. depending on state
3332 * At least the following states exist; there may be more.
3333 * Many items may be selected
3334 * At most one item may have the focus
3335 * The application may not actually be active currently
3336 * 1. The item is not selected in any way
3337 * 2. The cursor is flying over the icon or text and the text is being
3338 * expanded because it is not fully displayed currently.
3339 * 3. The item is selected and is focussed, i.e. the user has not clicked
3340 * in the blank area of the window, and the window (or application?)
3341 * still has the focus.
3342 * 4. As 3 except that a different window has the focus
3343 * 5. The item is the selected item of all the items, but the user has
3344 * clicked somewhere else on the window.
3345 * Only a few of these are handled currently. In particular 2 is not yet
3346 * handled since we do not support the functionality currently (or at least
3347 * we didn't when I wrote this)
3350 if (lvItem
.state
& LVIS_SELECTED
)
3352 /* set item colors */
3353 SetBkColor(hdc
, comctl32_color
.clrHighlight
);
3354 SetTextColor(hdc
, comctl32_color
.clrHighlightText
);
3355 SetBkMode (hdc
, OPAQUE
);
3356 /* set raster mode */
3357 SetROP2(hdc
, R2_XORPEN
);
3358 /* When exactly is it in XOR? while being dragged? */
3362 /* set item colors */
3363 if ( (infoPtr
->clrTextBk
== CLR_DEFAULT
) || (infoPtr
->clrTextBk
== CLR_NONE
) )
3365 SetBkMode(hdc
, TRANSPARENT
);
3369 SetBkMode(hdc
, OPAQUE
);
3370 SetBkColor(hdc
, infoPtr
->clrTextBk
);
3373 SetTextColor(hdc
, infoPtr
->clrText
);
3374 /* set raster mode */
3375 SetROP2(hdc
, R2_COPYPEN
);
3378 /* In cases 2,3 and 5 (see above) the full text is displayed, with word
3379 * wrapping and long words split.
3380 * In cases 1 and 4 only a portion of the text is displayed with word
3381 * wrapping and both word and end ellipsis. (I don't yet know about path
3384 uFormat
|= ( (lvItem
.state
& LVIS_FOCUSED
) && infoPtr
->bFocus
) ?
3387 DT_WORD_ELLIPSIS
| DT_END_ELLIPSIS
;
3390 if (infoPtr
->himlNormal
!= NULL
)
3392 if (lvItem
.iImage
>= 0)
3394 ImageList_Draw (infoPtr
->himlNormal
, lvItem
.iImage
, hdc
, rcItem
.left
,
3396 (lvItem
.state
& LVIS_SELECTED
) ? ILD_SELECTED
: ILD_NORMAL
);
3400 /* Draw the text below the icon */
3402 /* Don't bother painting item being edited */
3403 if ((infoPtr
->bEditing
&& (lvItem
.state
& LVIS_FOCUSED
)) ||
3404 !lstrlenW(lvItem
.pszText
))
3406 SetRectEmpty(SuggestedFocus
);
3410 /* Since rcItem.left is left point of icon, compute left point of item box */
3411 rcItem
.left
-= ((infoPtr
->nItemWidth
- infoPtr
->iconSize
.cx
) / 2);
3412 rcItem
.right
= rcItem
.left
+ infoPtr
->nItemWidth
;
3413 rcItem
.bottom
= rcItem
.top
+ infoPtr
->nItemHeight
;
3414 TRACE("bound box for text+icon (%d,%d)-(%d,%d), iS.cx=%ld, nItemWidth=%d\n",
3415 rcItem
.left
, rcItem
.top
, rcItem
.right
, rcItem
.bottom
,
3416 infoPtr
->iconSize
.cx
, infoPtr
->nItemWidth
);
3417 TRACE("rcList (%d,%d)-(%d,%d), rcView (%d,%d)-(%d,%d)\n",
3418 infoPtr
->rcList
.left
, infoPtr
->rcList
.top
,
3419 infoPtr
->rcList
.right
, infoPtr
->rcList
.bottom
,
3420 infoPtr
->rcView
.left
, infoPtr
->rcView
.top
,
3421 infoPtr
->rcView
.right
, infoPtr
->rcView
.bottom
);
3423 InflateRect(&rcItem
, -(2*CAPTION_BORDER
), 0);
3424 rcItem
.top
+= infoPtr
->iconSize
.cy
+ ICON_BOTTOM_PADDING
;
3429 /* I am sure of most of the uFormat values. However I am not sure about
3430 * whether we need or do not need the following:
3431 * DT_EXTERNALLEADING, DT_INTERNAL, DT_CALCRECT, DT_NOFULLWIDTHCHARBREAK,
3432 * DT_PATH_ELLIPSIS, DT_RTLREADING,
3433 * We certainly do not need
3434 * DT_BOTTOM, DT_VCENTER, DT_MODIFYSTRING, DT_LEFT, DT_RIGHT, DT_PREFIXONLY,
3435 * DT_SINGLELINE, DT_TABSTOP, DT_EXPANDTABS
3438 /* If the text is being drawn without clipping (i.e. the full text) then we
3439 * need to jump through a few hoops to ensure that it all gets displayed and
3440 * that the background is complete
3442 if (uFormat
& DT_NOCLIP
)
3445 HBRUSH hBrush
= CreateSolidBrush(GetBkColor (hdc
));
3446 int dx
, dy
, old_wid
, new_wid
;
3447 DrawTextW (hdc
, lvItem
.pszText
, -1, &rcItem
, uFormat
| DT_CALCRECT
);
3448 /* Microsoft, in their great wisdom, have decided that the rectangle
3449 * returned by DrawText on DT_CALCRECT will only guarantee the dimension,
3450 * not the location. So we have to do the centring ourselves (and take
3451 * responsibility for agreeing off-by-one consistency with them).
3453 old_wid
= rcItem
.right
-rcItem
.left
;
3454 new_wid
= rcBack
.right
- rcBack
.left
;
3455 dx
= rcBack
.left
- rcItem
.left
+ (new_wid
-old_wid
)/2;
3456 dy
= rcBack
.top
- rcItem
.top
;
3457 OffsetRect (&rcItem
, dx
, dy
);
3458 FillRect(hdc
, &rcItem
, hBrush
);
3459 DeleteObject(hBrush
);
3461 /* else ? What if we are losing the focus? will we not get a complete
3464 DrawTextW (hdc
, lvItem
.pszText
, -1, &rcItem
, uFormat
);
3466 CopyRect(SuggestedFocus
, &rcItem
);
3471 * Draws listview items when in report display mode.
3474 * [I] infoPtr : valid pointer to the listview structure
3475 * [I] HDC : device context handle
3480 static VOID
LISTVIEW_RefreshReport(LISTVIEW_INFO
*infoPtr
, HDC hdc
, DWORD cdmode
)
3482 SCROLLINFO scrollInfo
;
3483 INT nDrawPosY
= infoPtr
->rcList
.top
;
3485 RECT rcItem
, rcTemp
;
3490 DWORD cditemmode
= CDRF_DODEFAULT
;
3491 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
3495 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
3496 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
3497 scrollInfo
.fMask
= SIF_POS
;
3499 nItem
= ListView_GetTopIndex(infoPtr
->hwndSelf
);
3501 /* add 1 for displaying a partial item at the bottom */
3502 nLast
= nItem
+ LISTVIEW_GetCountPerColumn(infoPtr
) + 1;
3503 nLast
= min(nLast
, GETITEMCOUNT(infoPtr
));
3505 /* send cache hint notification */
3506 if (lStyle
& LVS_OWNERDATA
)
3510 nmlv
.hdr
.hwndFrom
= infoPtr
->hwndSelf
;
3511 nmlv
.hdr
.idFrom
= GetWindowLongW(infoPtr
->hwndSelf
,GWL_ID
);
3512 nmlv
.hdr
.code
= LVN_ODCACHEHINT
;
3516 SendMessageW(GetParent(infoPtr
->hwndSelf
), WM_NOTIFY
, (WPARAM
)nmlv
.hdr
.idFrom
,
3520 nColumnCount
= Header_GetItemCount(infoPtr
->hwndHeader
);
3521 infoPtr
->nColumnCount
= nColumnCount
; /* update nColumnCount */
3522 FullSelected
= infoPtr
->dwExStyle
& LVS_EX_FULLROWSELECT
;
3524 /* clear the background of any part of the control that doesn't contain items */
3525 SubtractRect(&rcTemp
, &infoPtr
->rcList
, &infoPtr
->rcView
);
3526 LISTVIEW_FillBackground(infoPtr
, hdc
, &rcTemp
);
3528 /* nothing to draw */
3529 if(GETITEMCOUNT(infoPtr
) == 0)
3532 /* Get scroll bar info once before loop */
3533 GetScrollInfo(infoPtr
->hwndSelf
, SB_HORZ
, &scrollInfo
);
3534 scrollOffset
= scrollInfo
.nPos
;
3536 for (; nItem
< nLast
; nItem
++)
3538 RECT SuggestedFocusRect
;
3541 if (lStyle
& LVS_OWNERDRAWFIXED
)
3543 UINT uID
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_ID
);
3548 TRACE("Owner Drawn\n");
3549 dis
.CtlType
= ODT_LISTVIEW
;
3552 dis
.itemAction
= ODA_DRAWENTIRE
;
3555 if (LISTVIEW_IsSelected(infoPtr
,nItem
)) dis
.itemState
|=ODS_SELECTED
;
3556 if (nItem
==infoPtr
->nFocusedItem
) dis
.itemState
|=ODS_FOCUS
;
3558 dis
.hwndItem
= infoPtr
->hwndSelf
;
3561 Header_GetItemRect(infoPtr
->hwndHeader
, nColumnCount
-1, &br
);
3563 dis
.rcItem
.left
= -scrollOffset
;
3564 dis
.rcItem
.right
= max(dis
.rcItem
.left
, br
.right
- scrollOffset
);
3565 dis
.rcItem
.top
= nDrawPosY
;
3566 dis
.rcItem
.bottom
= dis
.rcItem
.top
+ infoPtr
->nItemHeight
;
3568 ZeroMemory(&item
,sizeof(item
));
3570 item
.mask
= LVIF_PARAM
;
3571 ListView_GetItemW(infoPtr
->hwndSelf
, &item
);
3573 dis
.itemData
= item
.lParam
;
3575 if (SendMessageW(GetParent(infoPtr
->hwndSelf
),WM_DRAWITEM
,(WPARAM
)uID
,(LPARAM
)&dis
))
3577 nDrawPosY
+= infoPtr
->nItemHeight
;
3586 Header_GetItemRect(infoPtr
->hwndHeader
, 0, &ir
);
3587 Header_GetItemRect(infoPtr
->hwndHeader
, nColumnCount
-1, &br
);
3589 ir
.left
+= REPORT_MARGINX
;
3590 ir
.right
= max(ir
.left
, br
.right
- REPORT_MARGINX
);
3592 ir
.bottom
= ir
.top
+ infoPtr
->nItemHeight
;
3594 CopyRect(&SuggestedFocusRect
,&ir
);
3597 for (j
= 0; j
< nColumnCount
; j
++)
3599 if (cdmode
& CDRF_NOTIFYITEMDRAW
)
3600 cditemmode
= LISTVIEW_SendCustomDrawItemNotify (infoPtr
, hdc
, nItem
, j
,
3602 if (cditemmode
& CDRF_SKIPDEFAULT
)
3605 Header_GetItemRect(infoPtr
->hwndHeader
, j
, &rcItem
);
3607 rcItem
.left
+= REPORT_MARGINX
;
3608 rcItem
.right
= max(rcItem
.left
, rcItem
.right
- REPORT_MARGINX
);
3609 rcItem
.top
= nDrawPosY
;
3610 rcItem
.bottom
= rcItem
.top
+ infoPtr
->nItemHeight
;
3612 /* Offset the Scroll Bar Pos */
3613 rcItem
.left
-= scrollOffset
;
3614 rcItem
.right
-= scrollOffset
;
3618 LISTVIEW_DrawItem(infoPtr
, hdc
, nItem
, rcItem
, FullSelected
,
3619 &SuggestedFocusRect
);
3623 LISTVIEW_DrawSubItem(infoPtr
, hdc
, nItem
, j
, rcItem
, FullSelected
);
3626 if (cditemmode
& CDRF_NOTIFYPOSTPAINT
)
3627 LISTVIEW_SendCustomDrawItemNotify(infoPtr
, hdc
, nItem
, 0,
3628 CDDS_ITEMPOSTPAINT
);
3633 if (LISTVIEW_GetItemState(infoPtr
,nItem
,LVIS_FOCUSED
) && infoPtr
->bFocus
)
3636 if (FullSelected
&& LISTVIEW_GetItemState(infoPtr
,nItem
,LVIS_SELECTED
))
3637 rop
= SetROP2(hdc
, R2_XORPEN
);
3639 Rectangle(hdc
, SuggestedFocusRect
.left
, SuggestedFocusRect
.top
,
3640 SuggestedFocusRect
.right
,SuggestedFocusRect
.bottom
);
3643 SetROP2(hdc
, R2_COPYPEN
);
3645 nDrawPosY
+= infoPtr
->nItemHeight
;
3651 * Retrieves the number of items that can fit vertically in the client area.
3654 * [I] infoPtr : valid pointer to the listview structure
3657 * Number of items per row.
3659 static INT
LISTVIEW_GetCountPerRow(LISTVIEW_INFO
*infoPtr
)
3661 UINT uView
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
3662 INT nListWidth
= infoPtr
->rcList
.right
- infoPtr
->rcList
.left
;
3663 INT nCountPerRow
= 1;
3667 if (uView
!= LVS_REPORT
)
3669 nCountPerRow
= nListWidth
/ infoPtr
->nItemWidth
;
3670 if (nCountPerRow
== 0) nCountPerRow
= 1;
3674 return nCountPerRow
;
3679 * Retrieves the number of items that can fit horizontally in the client
3683 * [I] infoPtr : valid pointer to the listview structure
3686 * Number of items per column.
3688 static INT
LISTVIEW_GetCountPerColumn(LISTVIEW_INFO
*infoPtr
)
3690 INT nListHeight
= infoPtr
->rcList
.bottom
- infoPtr
->rcList
.top
;
3691 INT nCountPerColumn
= 1;
3693 if (nListHeight
> 0)
3695 TRACE("rcList=(%d,%d)-(%d,%d), nItemHeight=%d, CYHSCROLL=%d\n",
3696 infoPtr
->rcList
.left
,infoPtr
->rcList
.top
,
3697 infoPtr
->rcList
.right
,infoPtr
->rcList
.bottom
,
3698 infoPtr
->nItemHeight
,
3699 GetSystemMetrics(SM_CYHSCROLL
));
3700 nCountPerColumn
= nListHeight
/ infoPtr
->nItemHeight
;
3701 if (nCountPerColumn
== 0) nCountPerColumn
= 1;
3704 return nCountPerColumn
;
3709 * Retrieves the number of columns needed to display all the items when in
3710 * list display mode.
3713 * [I] infoPtr : valid pointer to the listview structure
3716 * Number of columns.
3718 static INT
LISTVIEW_GetColumnCount(LISTVIEW_INFO
*infoPtr
)
3720 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
3721 INT nColumnCount
= 0;
3723 if ((lStyle
& LVS_TYPEMASK
) == LVS_LIST
)
3725 nColumnCount
= infoPtr
->rcList
.right
/ infoPtr
->nItemWidth
;
3726 if (infoPtr
->rcList
.right
% infoPtr
->nItemWidth
) nColumnCount
++;
3729 return nColumnCount
;
3735 * Draws listview items when in list display mode.
3738 * [I] infoPtr : valid pointer to the listview structure
3739 * [I] HDC : device context handle
3744 static VOID
LISTVIEW_RefreshList(LISTVIEW_INFO
*infoPtr
, HDC hdc
, DWORD cdmode
)
3746 RECT rcItem
, FocusRect
, rcTemp
;
3750 INT nCountPerColumn
;
3751 INT nItemWidth
= infoPtr
->nItemWidth
;
3752 INT nItemHeight
= infoPtr
->nItemHeight
;
3753 DWORD cditemmode
= CDRF_DODEFAULT
;
3755 /* get number of fully visible columns */
3756 nColumnCount
= LISTVIEW_GetColumnCount(infoPtr
);
3757 infoPtr
->nColumnCount
= nColumnCount
;
3758 nCountPerColumn
= LISTVIEW_GetCountPerColumn(infoPtr
);
3759 nItem
= ListView_GetTopIndex(infoPtr
->hwndSelf
);
3760 TRACE("nColumnCount=%d, nCountPerColumn=%d, start item=%d\n",
3761 nColumnCount
, nCountPerColumn
, nItem
);
3763 /* paint the background of the control that doesn't contain any items */
3764 SubtractRect(&rcTemp
, &infoPtr
->rcList
, &infoPtr
->rcView
);
3765 LISTVIEW_FillBackground(infoPtr
, hdc
, &rcTemp
);
3767 /* nothing to draw, return here */
3768 if(GETITEMCOUNT(infoPtr
) == 0)
3771 for (i
= 0; i
< nColumnCount
; i
++)
3773 for (j
= 0; j
< nCountPerColumn
; j
++, nItem
++)
3775 if (nItem
>= GETITEMCOUNT(infoPtr
))
3778 if (cdmode
& CDRF_NOTIFYITEMDRAW
)
3779 cditemmode
= LISTVIEW_SendCustomDrawItemNotify (infoPtr
, hdc
, nItem
, 0,
3781 if (cditemmode
& CDRF_SKIPDEFAULT
)
3784 rcItem
.top
= j
* nItemHeight
;
3785 rcItem
.left
= i
* nItemWidth
;
3786 rcItem
.bottom
= rcItem
.top
+ nItemHeight
;
3787 rcItem
.right
= rcItem
.left
+ nItemWidth
;
3788 LISTVIEW_DrawItem(infoPtr
, hdc
, nItem
, rcItem
, FALSE
, &FocusRect
);
3792 if (LISTVIEW_GetItemState(infoPtr
,nItem
,LVIS_FOCUSED
) && infoPtr
->bFocus
)
3793 Rectangle(hdc
, FocusRect
.left
, FocusRect
.top
,
3794 FocusRect
.right
,FocusRect
.bottom
);
3796 if (cditemmode
& CDRF_NOTIFYPOSTPAINT
)
3797 LISTVIEW_SendCustomDrawItemNotify(infoPtr
, hdc
, nItem
, 0,
3798 CDDS_ITEMPOSTPAINT
);
3806 * Draws listview items when in icon or small icon display mode.
3809 * [I] infoPtr : valid pointer to the listview structure
3810 * [I] HDC : device context handle
3815 static VOID
LISTVIEW_RefreshIcon(LISTVIEW_INFO
*infoPtr
, HDC hdc
, BOOL bSmall
, DWORD cdmode
)
3819 RECT rcItem
, SuggestedFocus
, rcTemp
;
3821 DWORD cditemmode
= CDRF_DODEFAULT
;
3824 infoPtr
->nColumnCount
= 1; /* set this to an arbitrary value to prevent */
3825 /* DrawItem from erasing the incorrect background area */
3827 /* paint the background of the control that doesn't contain any items */
3828 SubtractRect(&rcTemp
, &infoPtr
->rcList
, &infoPtr
->rcView
);
3829 LISTVIEW_FillBackground(infoPtr
, hdc
, &rcTemp
);
3831 /* nothing to draw, return here */
3832 if(GETITEMCOUNT(infoPtr
) == 0)
3835 LISTVIEW_GetOrigin(infoPtr
, &ptOrigin
);
3836 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
3838 if (cdmode
& CDRF_NOTIFYITEMDRAW
)
3839 cditemmode
= LISTVIEW_SendCustomDrawItemNotify (infoPtr
, hdc
, i
, 0,
3841 if (cditemmode
& CDRF_SKIPDEFAULT
)
3844 LISTVIEW_GetItemPosition(infoPtr
, i
, &ptPosition
);
3845 ptPosition
.x
+= ptOrigin
.x
;
3846 ptPosition
.y
+= ptOrigin
.y
;
3848 if (ptPosition
.y
+ infoPtr
->nItemHeight
> infoPtr
->rcList
.top
)
3850 if (ptPosition
.x
+ infoPtr
->nItemWidth
> infoPtr
->rcList
.left
)
3852 if (ptPosition
.y
< infoPtr
->rcList
.bottom
)
3854 if (ptPosition
.x
< infoPtr
->rcList
.right
)
3856 rcItem
.top
= ptPosition
.y
;
3857 rcItem
.left
= ptPosition
.x
;
3858 rcItem
.bottom
= rcItem
.top
+ infoPtr
->nItemHeight
;
3859 rcItem
.right
= rcItem
.left
+ infoPtr
->nItemWidth
;
3861 LISTVIEW_DrawItem(infoPtr
, hdc
, i
, rcItem
, FALSE
, &SuggestedFocus
);
3863 LISTVIEW_DrawLargeItem(infoPtr
, hdc
, i
, rcItem
, &SuggestedFocus
);
3867 if (LISTVIEW_GetItemState(infoPtr
,i
,LVIS_FOCUSED
) &&
3868 infoPtr
->bFocus
&& !IsRectEmpty(&SuggestedFocus
))
3869 Rectangle(hdc
, SuggestedFocus
.left
, SuggestedFocus
.top
,
3870 SuggestedFocus
.right
,SuggestedFocus
.bottom
);
3875 if (cditemmode
& CDRF_NOTIFYPOSTPAINT
)
3876 LISTVIEW_SendCustomDrawItemNotify(infoPtr
, hdc
, i
, 0,
3877 CDDS_ITEMPOSTPAINT
);
3883 * Draws listview items.
3886 * [I] infoPtr : valid pointer to the listview structure
3887 * [I] HDC : device context handle
3892 static VOID
LISTVIEW_Refresh(LISTVIEW_INFO
*infoPtr
, HDC hdc
)
3894 UINT uView
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
3900 infoPtr
->bIsDrawing
= TRUE
;
3901 LISTVIEW_DumpListview (infoPtr
, __LINE__
);
3903 GetClientRect(infoPtr
->hwndSelf
, &rect
);
3904 cdmode
= LISTVIEW_SendCustomDrawNotify(infoPtr
,CDDS_PREPAINT
,hdc
,rect
);
3906 if (cdmode
== CDRF_SKIPDEFAULT
) return;
3909 hOldFont
= SelectObject(hdc
, infoPtr
->hFont
);
3911 /* select the dotted pen (for drawing the focus box) */
3912 hPen
= CreatePen(PS_ALTERNATE
, 1, 0);
3913 hOldPen
= SelectObject(hdc
, hPen
);
3915 /* select transparent brush (for drawing the focus box) */
3916 SelectObject(hdc
, GetStockObject(NULL_BRUSH
));
3919 if (uView
== LVS_LIST
)
3920 LISTVIEW_RefreshList(infoPtr
, hdc
, cdmode
);
3921 else if (uView
== LVS_REPORT
)
3922 LISTVIEW_RefreshReport(infoPtr
, hdc
, cdmode
);
3923 else if (uView
== LVS_SMALLICON
)
3924 LISTVIEW_RefreshIcon(infoPtr
, hdc
, TRUE
, cdmode
);
3925 else if (uView
== LVS_ICON
)
3926 LISTVIEW_RefreshIcon(infoPtr
, hdc
, FALSE
, cdmode
);
3928 /* unselect objects */
3929 SelectObject(hdc
, hOldFont
);
3930 SelectObject(hdc
, hOldPen
);
3935 if (cdmode
& CDRF_NOTIFYPOSTPAINT
)
3936 LISTVIEW_SendCustomDrawNotify(infoPtr
, CDDS_POSTPAINT
, hdc
, rect
);
3938 infoPtr
->bIsDrawing
= FALSE
;
3944 * Calculates the approximate width and height of a given number of items.
3947 * [I] infoPtr : valid pointer to the listview structure
3948 * [I] INT : number of items
3953 * Returns a DWORD. The width in the low word and the height in high word.
3955 static LRESULT
LISTVIEW_ApproximateViewRect(LISTVIEW_INFO
*infoPtr
, INT nItemCount
,
3956 WORD wWidth
, WORD wHeight
)
3958 UINT uView
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
3959 INT nItemCountPerColumn
= 1;
3960 INT nColumnCount
= 0;
3961 DWORD dwViewRect
= 0;
3963 if (nItemCount
== -1)
3964 nItemCount
= GETITEMCOUNT(infoPtr
);
3966 if (uView
== LVS_LIST
)
3968 if (wHeight
== 0xFFFF)
3970 /* use current height */
3971 wHeight
= infoPtr
->rcList
.bottom
- infoPtr
->rcList
.top
;
3974 if (wHeight
< infoPtr
->nItemHeight
)
3975 wHeight
= infoPtr
->nItemHeight
;
3979 if (infoPtr
->nItemHeight
> 0)
3981 nItemCountPerColumn
= wHeight
/ infoPtr
->nItemHeight
;
3982 if (nItemCountPerColumn
== 0)
3983 nItemCountPerColumn
= 1;
3985 if (nItemCount
% nItemCountPerColumn
!= 0)
3986 nColumnCount
= nItemCount
/ nItemCountPerColumn
;
3988 nColumnCount
= nItemCount
/ nItemCountPerColumn
+ 1;
3992 /* Microsoft padding magic */
3993 wHeight
= nItemCountPerColumn
* infoPtr
->nItemHeight
+ 2;
3994 wWidth
= nColumnCount
* infoPtr
->nItemWidth
+ 2;
3996 dwViewRect
= MAKELONG(wWidth
, wHeight
);
3998 else if (uView
== LVS_REPORT
)
3999 FIXME("uView == LVS_REPORT: not implemented\n");
4000 else if (uView
== LVS_SMALLICON
)
4001 FIXME("uView == LVS_SMALLICON: not implemented\n");
4002 else if (uView
== LVS_ICON
)
4003 FIXME("uView == LVS_ICON: not implemented\n");
4010 * Arranges listview items in icon display mode.
4013 * [I] infoPtr : valid pointer to the listview structure
4014 * [I] INT : alignment code
4020 static LRESULT
LISTVIEW_Arrange(LISTVIEW_INFO
*infoPtr
, INT nAlignCode
)
4022 UINT uView
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
4023 BOOL bResult
= FALSE
;
4025 if ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
))
4030 FIXME("nAlignCode=LVA_ALIGNLEFT: not implemented\n");
4033 FIXME("nAlignCode=LVA_ALIGNTOP: not implemented\n");
4036 FIXME("nAlignCode=LVA_DEFAULT: not implemented\n");
4038 case LVA_SNAPTOGRID
:
4039 FIXME("nAlignCode=LVA_SNAPTOGRID: not implemented\n");
4047 /* << LISTVIEW_CreateDragImage >> */
4052 * Removes all listview items and subitems.
4055 * [I] infoPtr : valid pointer to the listview structure
4061 static LRESULT
LISTVIEW_DeleteAllItems(LISTVIEW_INFO
*infoPtr
)
4063 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
4064 UINT uView
= lStyle
& LVS_TYPEMASK
;
4065 LISTVIEW_ITEM
*lpItem
;
4066 LISTVIEW_SUBITEM
*lpSubItem
;
4069 BOOL bResult
= FALSE
;
4074 LISTVIEW_RemoveAllSelections(infoPtr
);
4075 infoPtr
->nSelectionMark
=-1;
4076 infoPtr
->nFocusedItem
=-1;
4077 /* But we are supposed to leave nHotItem as is! */
4079 if (lStyle
& LVS_OWNERDATA
)
4081 infoPtr
->hdpaItems
->nItemCount
= 0;
4082 InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
);
4086 if (GETITEMCOUNT(infoPtr
) > 0)
4090 /* send LVN_DELETEALLITEMS notification */
4091 /* verify if subsequent LVN_DELETEITEM notifications should be
4093 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
4095 bSuppress
= listview_notify(infoPtr
, LVN_DELETEALLITEMS
, &nmlv
);
4097 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
4099 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, i
);
4100 if (hdpaSubItems
!= NULL
)
4102 for (j
= 1; j
< hdpaSubItems
->nItemCount
; j
++)
4104 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, j
);
4105 if (lpSubItem
!= NULL
)
4107 /* free subitem string */
4108 if (is_textW(lpSubItem
->pszText
))
4109 COMCTL32_Free(lpSubItem
->pszText
);
4112 COMCTL32_Free(lpSubItem
);
4116 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
4121 /* send LVN_DELETEITEM notification */
4123 nmlv
.lParam
= lpItem
->lParam
;
4124 listview_notify(infoPtr
, LVN_DELETEITEM
, &nmlv
);
4127 /* free item string */
4128 if (is_textW(lpItem
->pszText
))
4129 COMCTL32_Free(lpItem
->pszText
);
4132 COMCTL32_Free(lpItem
);
4135 DPA_Destroy(hdpaSubItems
);
4139 /* reinitialize listview memory */
4140 bResult
= DPA_DeleteAllPtrs(infoPtr
->hdpaItems
);
4142 /* align items (set position of each item) */
4143 if ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
))
4145 if (lStyle
& LVS_ALIGNLEFT
)
4147 LISTVIEW_AlignLeft(infoPtr
);
4151 LISTVIEW_AlignTop(infoPtr
);
4155 LISTVIEW_UpdateScroll(infoPtr
);
4157 /* invalidate client area (optimization needed) */
4158 InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
);
4166 * Removes a column from the listview control.
4169 * [I] infoPtr : valid pointer to the listview structure
4170 * [I] INT : column index
4176 static LRESULT
LISTVIEW_DeleteColumn(LISTVIEW_INFO
*infoPtr
, INT nColumn
)
4178 UINT uView
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
4179 UINT uOwnerData
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_OWNERDATA
;
4180 BOOL bResult
= FALSE
;
4182 if (Header_DeleteItem(infoPtr
->hwndHeader
, nColumn
))
4184 bResult
= uOwnerData
? TRUE
: LISTVIEW_RemoveColumn(infoPtr
->hdpaItems
, nColumn
);
4186 /* Need to reset the item width when deleting a column */
4187 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(infoPtr
);
4189 /* reset scroll parameters */
4190 if (uView
== LVS_REPORT
)
4192 /* update scrollbar(s) */
4193 LISTVIEW_UpdateScroll(infoPtr
);
4195 /* refresh client area */
4196 InvalidateRect(infoPtr
->hwndSelf
, NULL
, FALSE
);
4205 * Removes an item from the listview control.
4208 * [I] infoPtr : valid pointer to the listview structure
4209 * [I] INT : item index
4215 static LRESULT
LISTVIEW_DeleteItem(LISTVIEW_INFO
*infoPtr
, INT nItem
)
4217 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
4218 UINT uView
= lStyle
& LVS_TYPEMASK
;
4219 LONG lCtrlId
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_ID
);
4221 BOOL bResult
= FALSE
;
4223 LISTVIEW_ITEM
*lpItem
;
4224 LISTVIEW_SUBITEM
*lpSubItem
;
4228 TRACE("(nItem=%d)\n", nItem
);
4231 /* First, send LVN_DELETEITEM notification. */
4232 memset(&nmlv
, 0, sizeof (NMLISTVIEW
));
4233 nmlv
.hdr
.hwndFrom
= infoPtr
->hwndSelf
;
4234 nmlv
.hdr
.idFrom
= lCtrlId
;
4235 nmlv
.hdr
.code
= LVN_DELETEITEM
;
4237 SendMessageW(GetParent(infoPtr
->hwndSelf
), WM_NOTIFY
, (WPARAM
)lCtrlId
,
4241 /* remove it from the selection range */
4242 ZeroMemory(&item
,sizeof(item
));
4243 item
.stateMask
= LVIS_SELECTED
;
4244 LISTVIEW_SetItemState(infoPtr
,nItem
,&item
);
4246 if (lStyle
& LVS_OWNERDATA
)
4248 infoPtr
->hdpaItems
->nItemCount
--;
4249 InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
);
4253 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
4255 /* initialize memory */
4256 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
4258 hdpaSubItems
= (HDPA
)DPA_DeletePtr(infoPtr
->hdpaItems
, nItem
);
4259 if (hdpaSubItems
!= NULL
)
4261 for (i
= 1; i
< hdpaSubItems
->nItemCount
; i
++)
4263 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, i
);
4264 if (lpSubItem
!= NULL
)
4266 /* free item string */
4267 if (is_textW(lpSubItem
->pszText
))
4268 COMCTL32_Free(lpSubItem
->pszText
);
4271 COMCTL32_Free(lpSubItem
);
4275 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
4278 /* free item string */
4279 if (is_textW(lpItem
->pszText
))
4280 COMCTL32_Free(lpItem
->pszText
);
4283 COMCTL32_Free(lpItem
);
4286 bResult
= DPA_Destroy(hdpaSubItems
);
4289 LISTVIEW_ShiftIndices(infoPtr
,nItem
,-1);
4291 /* align items (set position of each item) */
4292 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
4294 if (lStyle
& LVS_ALIGNLEFT
)
4295 LISTVIEW_AlignLeft(infoPtr
);
4297 LISTVIEW_AlignTop(infoPtr
);
4300 LISTVIEW_UpdateScroll(infoPtr
);
4302 /* refresh client area */
4303 InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
);
4312 * Callback implementation for editlabel control
4315 * [I] infoPtr : valid pointer to the listview structure
4316 * [I] pszText : modified text
4317 * [I] isW : TRUE if psxText is Unicode, FALSE if it's ANSI
4323 static BOOL
LISTVIEW_EndEditLabelT(LISTVIEW_INFO
*infoPtr
, LPWSTR pszText
, BOOL isW
)
4325 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
4326 NMLVDISPINFOW dispInfo
;
4327 LISTVIEW_ITEM
*lpItem
;
4329 LISTVIEW_ITEM lvItemRef
;
4331 BOOL bResult
= TRUE
;
4332 INT nItem
= infoPtr
->nEditLabelItem
;
4334 TRACE("(pszText=%s, nItem=%d, isW=%d)\n", debugstr_t(pszText
, isW
), nItem
, isW
);
4336 infoPtr
->bEditing
= FALSE
;
4337 if (!(lStyle
& LVS_OWNERDATA
))
4339 if (!(hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
)))
4342 if (!(lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0)))
4347 ZeroMemory(&lvItemRef
,sizeof(LISTVIEW_ITEM
));
4348 ZeroMemory(&item
,sizeof(item
));
4351 item
.mask
= LVIF_PARAM
| LVIF_STATE
;
4352 ListView_GetItemW(infoPtr
->hwndSelf
, &item
);
4353 lvItemRef
.state
= item
.state
;
4354 lvItemRef
.iImage
= item
.iImage
;
4355 lvItemRef
.lParam
= item
.lParam
;
4356 lpItem
= &lvItemRef
;
4359 ZeroMemory(&dispInfo
, sizeof(dispInfo
));
4360 dispInfo
.item
.mask
= 0;
4361 dispInfo
.item
.iItem
= nItem
;
4362 dispInfo
.item
.state
= lpItem
->state
;
4363 dispInfo
.item
.stateMask
= 0;
4364 dispInfo
.item
.pszText
= pszText
;
4365 dispInfo
.item
.cchTextMax
= textlenT(pszText
, isW
);
4366 dispInfo
.item
.iImage
= lpItem
->iImage
;
4367 dispInfo
.item
.lParam
= lpItem
->lParam
;
4369 /* Do we need to update the Item Text */
4370 if(dispinfo_notifyT(infoPtr
, LVN_ENDLABELEDITW
, &dispInfo
, isW
))
4371 if (lpItem
->pszText
!= LPSTR_TEXTCALLBACKW
&& !(lStyle
& LVS_OWNERDATA
))
4372 bResult
= textsetptrT(&lpItem
->pszText
, pszText
, isW
);
4379 * Begin in place editing of specified list view item
4382 * [I] infoPtr : valid pointer to the listview structure
4383 * [I] INT : item index
4384 * [I] isW : TRUE if it's a Unicode req, FALSE if ASCII
4390 static HWND
LISTVIEW_EditLabelT(LISTVIEW_INFO
*infoPtr
, INT nItem
, BOOL isW
)
4392 NMLVDISPINFOW dispInfo
;
4394 LISTVIEW_ITEM
*lpItem
;
4397 WCHAR szDispText
[DISP_TEXT_SIZE
];
4399 LISTVIEW_ITEM lvItemRef
;
4400 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
4402 if (~GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_EDITLABELS
)
4405 infoPtr
->nEditLabelItem
= nItem
;
4407 TRACE("(nItem=%d, isW=%d)\n", nItem
, isW
);
4409 /* Is the EditBox still there, if so remove it */
4410 if(infoPtr
->hwndEdit
!= 0)
4412 SetFocus(infoPtr
->hwndSelf
);
4413 infoPtr
->hwndEdit
= 0;
4416 LISTVIEW_SetSelection(infoPtr
, nItem
);
4417 LISTVIEW_SetItemFocus(infoPtr
, nItem
);
4419 if (!(lStyle
& LVS_OWNERDATA
))
4421 if (NULL
== (hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
)))
4424 if (NULL
== (lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0)))
4430 ZeroMemory(&lvItemRef
,sizeof(LISTVIEW_ITEM
));
4431 ZeroMemory(&item
, sizeof(item
));
4434 item
.mask
= LVIF_PARAM
| LVIF_STATE
;
4435 ListView_GetItemW(infoPtr
->hwndSelf
, &item
);
4436 lvItemRef
.iImage
= item
.iImage
;
4437 lvItemRef
.state
= item
.state
;
4438 lvItemRef
.lParam
= item
.lParam
;
4439 lpItem
= &lvItemRef
;
4442 /* get information needed for drawing the item */
4443 ZeroMemory(&lvItem
, sizeof(lvItem
));
4444 lvItem
.mask
= LVIF_TEXT
;
4445 lvItem
.iItem
= nItem
;
4446 lvItem
.iSubItem
= 0;
4447 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
4448 lvItem
.pszText
= szDispText
;
4449 *lvItem
.pszText
= '\0';
4450 LISTVIEW_GetItemT(infoPtr
, &lvItem
, FALSE
, isW
);
4452 ZeroMemory(&dispInfo
, sizeof(dispInfo
));
4453 dispInfo
.item
.mask
= 0;
4454 dispInfo
.item
.iItem
= nItem
;
4455 dispInfo
.item
.state
= lpItem
->state
;
4456 dispInfo
.item
.stateMask
= 0;
4457 dispInfo
.item
.pszText
= lvItem
.pszText
;
4458 dispInfo
.item
.cchTextMax
= lstrlenW(lvItem
.pszText
);
4459 dispInfo
.item
.iImage
= lpItem
->iImage
;
4460 dispInfo
.item
.lParam
= lpItem
->lParam
;
4462 if (dispinfo_notifyT(infoPtr
, LVN_BEGINLABELEDITW
, &dispInfo
, isW
))
4465 rect
.left
= LVIR_LABEL
;
4466 if (!LISTVIEW_GetItemRect(infoPtr
, nItem
, &rect
))
4469 if (!(hedit
= CreateEditLabelT(infoPtr
, szDispText
, WS_VISIBLE
,
4470 rect
.left
-2, rect
.top
-1, 0, rect
.bottom
- rect
.top
+2, isW
)))
4473 infoPtr
->hwndEdit
= hedit
;
4475 ShowWindow(infoPtr
->hwndEdit
,SW_NORMAL
);
4476 infoPtr
->bEditing
= TRUE
;
4477 SetFocus(infoPtr
->hwndEdit
);
4478 SendMessageW(infoPtr
->hwndEdit
, EM_SETSEL
, 0, -1);
4479 return infoPtr
->hwndEdit
;
4485 * Ensures the specified item is visible, scrolling into view if necessary.
4488 * [I] infoPtr : valid pointer to the listview structure
4489 * [I] INT : item index
4490 * [I] BOOL : partially or entirely visible
4496 static BOOL
LISTVIEW_EnsureVisible(LISTVIEW_INFO
*infoPtr
, INT nItem
, BOOL bPartial
)
4498 UINT uView
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
4499 INT nScrollPosHeight
= 0;
4500 INT nScrollPosWidth
= 0;
4501 SCROLLINFO scrollInfo
;
4503 BOOL bRedraw
= FALSE
;
4505 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
4506 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
4507 scrollInfo
.fMask
= SIF_POS
;
4509 /* ALWAYS bPartial == FALSE, FOR NOW! */
4511 rcItem
.left
= LVIR_BOUNDS
;
4512 if (LISTVIEW_GetItemRect(infoPtr
, nItem
, &rcItem
))
4514 if (rcItem
.left
< infoPtr
->rcList
.left
)
4516 if (GetScrollInfo(infoPtr
->hwndSelf
, SB_HORZ
, &scrollInfo
))
4520 if (uView
== LVS_LIST
)
4522 nScrollPosWidth
= infoPtr
->nItemWidth
;
4523 rcItem
.left
+= infoPtr
->rcList
.left
;
4525 else if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
4527 nScrollPosWidth
= 1;
4528 rcItem
.left
+= infoPtr
->rcList
.left
;
4531 /* When in LVS_REPORT view, the scroll position should
4533 if (nScrollPosWidth
!= 0)
4535 if (rcItem
.left
% nScrollPosWidth
== 0)
4536 scrollInfo
.nPos
+= rcItem
.left
/ nScrollPosWidth
;
4538 scrollInfo
.nPos
+= rcItem
.left
/ nScrollPosWidth
- 1;
4540 SetScrollInfo(infoPtr
->hwndSelf
, SB_HORZ
, &scrollInfo
, TRUE
);
4544 else if (rcItem
.right
> infoPtr
->rcList
.right
)
4546 if (GetScrollInfo(infoPtr
->hwndSelf
, SB_HORZ
, &scrollInfo
))
4550 if (uView
== LVS_LIST
)
4552 rcItem
.right
-= infoPtr
->rcList
.right
;
4553 nScrollPosWidth
= infoPtr
->nItemWidth
;
4555 else if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
4557 rcItem
.right
-= infoPtr
->rcList
.right
;
4558 nScrollPosWidth
= 1;
4561 /* When in LVS_REPORT view, the scroll position should
4563 if (nScrollPosWidth
!= 0)
4565 if (rcItem
.right
% nScrollPosWidth
== 0)
4566 scrollInfo
.nPos
+= rcItem
.right
/ nScrollPosWidth
;
4568 scrollInfo
.nPos
+= rcItem
.right
/ nScrollPosWidth
+ 1;
4570 SetScrollInfo(infoPtr
->hwndSelf
, SB_HORZ
, &scrollInfo
, TRUE
);
4575 if (rcItem
.top
< infoPtr
->rcList
.top
)
4579 if (GetScrollInfo(infoPtr
->hwndSelf
, SB_VERT
, &scrollInfo
))
4581 if (uView
== LVS_REPORT
)
4583 rcItem
.top
-= infoPtr
->rcList
.top
;
4584 nScrollPosHeight
= infoPtr
->nItemHeight
;
4586 else if ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
))
4588 nScrollPosHeight
= 1;
4589 rcItem
.top
+= infoPtr
->rcList
.top
;
4592 if (rcItem
.top
% nScrollPosHeight
== 0)
4593 scrollInfo
.nPos
+= rcItem
.top
/ nScrollPosHeight
;
4595 scrollInfo
.nPos
+= rcItem
.top
/ nScrollPosHeight
- 1;
4597 SetScrollInfo(infoPtr
->hwndSelf
, SB_VERT
, &scrollInfo
, TRUE
);
4600 else if (rcItem
.bottom
> infoPtr
->rcList
.bottom
)
4604 if (GetScrollInfo(infoPtr
->hwndSelf
, SB_VERT
, &scrollInfo
))
4606 if (uView
== LVS_REPORT
)
4608 rcItem
.bottom
-= infoPtr
->rcList
.bottom
;
4609 nScrollPosHeight
= infoPtr
->nItemHeight
;
4611 else if ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
))
4613 nScrollPosHeight
= 1;
4614 rcItem
.bottom
-= infoPtr
->rcList
.bottom
;
4617 if (rcItem
.bottom
% nScrollPosHeight
== 0)
4618 scrollInfo
.nPos
+= rcItem
.bottom
/ nScrollPosHeight
;
4620 scrollInfo
.nPos
+= rcItem
.bottom
/ nScrollPosHeight
+ 1;
4622 SetScrollInfo(infoPtr
->hwndSelf
, SB_VERT
, &scrollInfo
, TRUE
);
4628 InvalidateRect(infoPtr
->hwndSelf
,NULL
,TRUE
);
4634 * Retrieves the nearest item, given a position and a direction.
4637 * [I] infoPtr : valid pointer to the listview structure
4638 * [I] POINT : start position
4639 * [I] UINT : direction
4642 * Item index if successdful, -1 otherwise.
4644 static INT
LISTVIEW_GetNearestItem(LISTVIEW_INFO
*infoPtr
, POINT pt
, UINT vkDirection
)
4650 TRACE("point %ld,%ld, direction %s\n", pt
.x
, pt
.y
,
4651 (vkDirection
== VK_DOWN
) ? "VK_DOWN" :
4652 ((vkDirection
== VK_UP
) ? "VK_UP" :
4653 ((vkDirection
== VK_LEFT
) ? "VK_LEFT" : "VK_RIGHT")));
4655 if (LISTVIEW_GetViewRect(infoPtr
, &rcView
))
4657 ZeroMemory(&lvIntHit
, sizeof(lvIntHit
));
4658 LISTVIEW_GetOrigin(infoPtr
, &lvIntHit
.ht
.pt
);
4659 lvIntHit
.ht
.pt
.x
+= pt
.x
;
4660 lvIntHit
.ht
.pt
.y
+= pt
.y
;
4662 if (vkDirection
== VK_DOWN
)
4663 lvIntHit
.ht
.pt
.y
+= infoPtr
->nItemHeight
;
4664 else if (vkDirection
== VK_UP
)
4665 lvIntHit
.ht
.pt
.y
-= infoPtr
->nItemHeight
;
4666 else if (vkDirection
== VK_LEFT
)
4667 lvIntHit
.ht
.pt
.x
-= infoPtr
->nItemWidth
;
4668 else if (vkDirection
== VK_RIGHT
)
4669 lvIntHit
.ht
.pt
.x
+= infoPtr
->nItemWidth
;
4671 if (!PtInRect(&rcView
, lvIntHit
.ht
.pt
))
4675 nItem
= LISTVIEW_SuperHitTestItem(infoPtr
, &lvIntHit
, TRUE
);
4676 return nItem
== -1 ? lvIntHit
.iDistItem
: nItem
;
4685 * Searches for an item with specific characteristics.
4688 * [I] hwnd : window handle
4689 * [I] nStart : base item index
4690 * [I] lpFindInfo : item information to look for
4693 * SUCCESS : index of item
4696 static LRESULT
LISTVIEW_FindItemW(LISTVIEW_INFO
*infoPtr
, INT nStart
,
4697 LPLVFINDINFOW lpFindInfo
)
4700 WCHAR szDispText
[DISP_TEXT_SIZE
] = { '\0' };
4704 INT nLast
= GETITEMCOUNT(infoPtr
);
4706 if ((nItem
>= -1) && (lpFindInfo
!= NULL
))
4708 ZeroMemory(&lvItem
, sizeof(lvItem
));
4710 if (lpFindInfo
->flags
& LVFI_PARAM
)
4712 lvItem
.mask
|= LVIF_PARAM
;
4715 if (lpFindInfo
->flags
& (LVFI_STRING
| LVFI_PARTIAL
))
4717 lvItem
.mask
|= LVIF_TEXT
;
4718 lvItem
.pszText
= szDispText
;
4719 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
4722 if (lpFindInfo
->flags
& LVFI_WRAP
)
4725 if (lpFindInfo
->flags
& LVFI_NEARESTXY
)
4727 ptItem
.x
= lpFindInfo
->pt
.x
;
4728 ptItem
.y
= lpFindInfo
->pt
.y
;
4733 while (nItem
< nLast
)
4735 if (lpFindInfo
->flags
& LVFI_NEARESTXY
)
4737 nItem
= LISTVIEW_GetNearestItem(infoPtr
, ptItem
,
4738 lpFindInfo
->vkDirection
);
4741 /* get position of the new item index */
4742 if (!ListView_GetItemPosition(infoPtr
->hwndSelf
, nItem
, &ptItem
))
4753 lvItem
.iItem
= nItem
;
4754 lvItem
.iSubItem
= 0;
4755 if (LISTVIEW_GetItemW(infoPtr
, &lvItem
, TRUE
))
4757 if (lvItem
.mask
& LVIF_TEXT
)
4759 if (lpFindInfo
->flags
& LVFI_PARTIAL
)
4761 if (strstrW(lvItem
.pszText
, lpFindInfo
->psz
) == NULL
)
4766 if (lstrcmpW(lvItem
.pszText
, lpFindInfo
->psz
) != 0)
4771 if (lvItem
.mask
& LVIF_PARAM
)
4773 if (lpFindInfo
->lParam
!= lvItem
.lParam
)
4799 * Searches for an item with specific characteristics.
4802 * [I] hwnd : window handle
4803 * [I] nStart : base item index
4804 * [I] lpFindInfo : item information to look for
4807 * SUCCESS : index of item
4810 static LRESULT
LISTVIEW_FindItemA(LISTVIEW_INFO
*infoPtr
, INT nStart
,
4811 LPLVFINDINFOA lpFindInfo
)
4813 BOOL hasText
= lpFindInfo
->flags
& (LVFI_STRING
| LVFI_PARTIAL
);
4817 memcpy(&fiw
, lpFindInfo
, sizeof(fiw
));
4818 if (hasText
) fiw
.psz
= textdupTtoW((LPCWSTR
)lpFindInfo
->psz
, FALSE
);
4819 res
= LISTVIEW_FindItemW(infoPtr
, nStart
, &fiw
);
4820 if (hasText
) textfreeT((LPWSTR
)fiw
.psz
, FALSE
);
4826 * Retrieves the background image of the listview control.
4829 * [I] infoPtr : valid pointer to the listview structure
4830 * [O] LPLVMKBIMAGE : background image attributes
4836 /* static LRESULT LISTVIEW_GetBkImage(LISTVIEW_INFO *infoPtr, LPLVBKIMAGE lpBkImage) */
4838 /* FIXME (listview, "empty stub!\n"); */
4844 * Retrieves the callback mask.
4847 * [I] infoPtr : valid pointer to the listview structure
4852 static UINT
LISTVIEW_GetCallbackMask(LISTVIEW_INFO
*infoPtr
)
4854 return infoPtr
->uCallbackMask
;
4859 * Retrieves column attributes.
4862 * [I] infoPtr : valid pointer to the listview structure
4863 * [I] INT : column index
4864 * [IO] LPLVCOLUMNW : column information
4865 * [I] isW : if TRUE, then lpColumn is a LPLVCOLUMNW
4866 * otherwise it is in fact a LPLVCOLUMNA
4872 static LRESULT
LISTVIEW_GetColumnT(LISTVIEW_INFO
*infoPtr
, INT nItem
, LPLVCOLUMNW lpColumn
, BOOL isW
)
4875 BOOL bResult
= FALSE
;
4877 if (lpColumn
!= NULL
)
4880 /* initialize memory */
4881 ZeroMemory(&hdi
, sizeof(hdi
));
4883 if (lpColumn
->mask
& LVCF_FMT
)
4884 hdi
.mask
|= HDI_FORMAT
;
4886 if (lpColumn
->mask
& LVCF_WIDTH
)
4887 hdi
.mask
|= HDI_WIDTH
;
4889 if (lpColumn
->mask
& LVCF_TEXT
)
4891 hdi
.mask
|= HDI_TEXT
;
4892 hdi
.cchTextMax
= lpColumn
->cchTextMax
;
4893 hdi
.pszText
= lpColumn
->pszText
;
4896 if (lpColumn
->mask
& LVCF_IMAGE
)
4897 hdi
.mask
|= HDI_IMAGE
;
4899 if (lpColumn
->mask
& LVCF_ORDER
)
4900 hdi
.mask
|= HDI_ORDER
;
4903 bResult
= Header_GetItemW(infoPtr
->hwndHeader
, nItem
, &hdi
);
4905 bResult
= Header_GetItemA(infoPtr
->hwndHeader
, nItem
, &hdi
);
4909 if (lpColumn
->mask
& LVCF_FMT
)
4913 if (hdi
.fmt
& HDF_LEFT
)
4914 lpColumn
->fmt
|= LVCFMT_LEFT
;
4915 else if (hdi
.fmt
& HDF_RIGHT
)
4916 lpColumn
->fmt
|= LVCFMT_RIGHT
;
4917 else if (hdi
.fmt
& HDF_CENTER
)
4918 lpColumn
->fmt
|= LVCFMT_CENTER
;
4920 if (hdi
.fmt
& HDF_IMAGE
)
4921 lpColumn
->fmt
|= LVCFMT_COL_HAS_IMAGES
;
4923 if (hdi
.fmt
& HDF_BITMAP_ON_RIGHT
)
4924 lpColumn
->fmt
|= LVCFMT_BITMAP_ON_RIGHT
;
4927 if (lpColumn
->mask
& LVCF_WIDTH
)
4928 lpColumn
->cx
= hdi
.cxy
;
4930 if (lpColumn
->mask
& LVCF_IMAGE
)
4931 lpColumn
->iImage
= hdi
.iImage
;
4933 if (lpColumn
->mask
& LVCF_ORDER
)
4934 lpColumn
->iOrder
= hdi
.iOrder
;
4936 TRACE("(col=%d, lpColumn=%s, isW=%d)\n",
4937 nItem
, debuglvcolumn_t(lpColumn
, isW
), isW
);
4946 static LRESULT
LISTVIEW_GetColumnOrderArray(LISTVIEW_INFO
*infoPtr
, INT iCount
, LPINT lpiArray
)
4953 /* FIXME: little hack */
4954 for (i
= 0; i
< iCount
; i
++)
4962 * Retrieves the column width.
4965 * [I] infoPtr : valid pointer to the listview structure
4966 * [I] int : column index
4969 * SUCCESS : column width
4972 static LRESULT
LISTVIEW_GetColumnWidth(LISTVIEW_INFO
*infoPtr
, INT nColumn
)
4974 UINT uView
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
4975 INT nColumnWidth
= 0;
4978 if (uView
== LVS_LIST
)
4980 nColumnWidth
= infoPtr
->nItemWidth
;
4982 else if (uView
== LVS_REPORT
)
4984 /* get column width from header */
4985 ZeroMemory(&hdi
, sizeof(hdi
));
4986 hdi
.mask
= HDI_WIDTH
;
4987 if (Header_GetItemW(infoPtr
->hwndHeader
, nColumn
, &hdi
))
4988 nColumnWidth
= hdi
.cxy
;
4991 return nColumnWidth
;
4996 * In list or report display mode, retrieves the number of items that can fit
4997 * vertically in the visible area. In icon or small icon display mode,
4998 * retrieves the total number of visible items.
5001 * [I] infoPtr : valid pointer to the listview structure
5004 * Number of fully visible items.
5006 static LRESULT
LISTVIEW_GetCountPerPage(LISTVIEW_INFO
*infoPtr
)
5008 UINT uView
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
5011 if (uView
== LVS_LIST
)
5013 if (infoPtr
->rcList
.right
> infoPtr
->nItemWidth
)
5015 nItemCount
= LISTVIEW_GetCountPerRow(infoPtr
) *
5016 LISTVIEW_GetCountPerColumn(infoPtr
);
5019 else if (uView
== LVS_REPORT
)
5021 nItemCount
= LISTVIEW_GetCountPerColumn(infoPtr
);
5025 nItemCount
= GETITEMCOUNT(infoPtr
);
5034 * Retrieves an image list handle.
5037 * [I] infoPtr : valid pointer to the listview structure
5038 * [I] INT : image list identifier
5041 * SUCCESS : image list handle
5044 static LRESULT
LISTVIEW_GetImageList(LISTVIEW_INFO
*infoPtr
, INT nImageList
)
5046 HIMAGELIST himl
= NULL
;
5051 himl
= infoPtr
->himlNormal
;
5054 himl
= infoPtr
->himlSmall
;
5057 himl
= infoPtr
->himlState
;
5061 return (LRESULT
)himl
;
5064 /* LISTVIEW_GetISearchString */
5068 * Retrieves item attributes.
5071 * [I] hwnd : window handle
5072 * [IO] lpLVItem : item info
5073 * [I] internal : if true then we will use tricks that avoid copies
5074 * but are not compatible with the regular interface
5075 * [I] isW : if TRUE, then lpLVItem is a LPLVITEMW,
5076 * if FALSE, the lpLVItem is a LPLVITEMA.
5082 static LRESULT
LISTVIEW_GetItemT(LISTVIEW_INFO
*infoPtr
, LPLVITEMW lpLVItem
, BOOL internal
, BOOL isW
)
5084 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
5085 NMLVDISPINFOW dispInfo
;
5086 LISTVIEW_SUBITEM
*lpSubItem
;
5087 LISTVIEW_ITEM
*lpItem
;
5090 INT
* piImage
= (INT
*)&null
;
5091 LPWSTR
* ppszText
= (LPWSTR
*)&null
;
5092 LPARAM
* plParam
= (LPARAM
*)&null
;
5094 if (internal
&& !isW
)
5096 ERR("We can't have internal non-Unicode GetItem!\n");
5100 /* In the following:
5101 * lpLVItem describes the information requested by the user
5102 * lpItem/lpSubItem is what we have
5103 * dispInfo is a structure we use to request the missing
5104 * information from the application
5107 TRACE("(lpLVItem=%s, internal=%d, isW=%d)\n",
5108 debuglvitem_t(lpLVItem
, isW
), internal
, isW
);
5110 if ((lpLVItem
== NULL
) || (lpLVItem
->iItem
< 0) ||
5111 (lpLVItem
->iItem
>= GETITEMCOUNT(infoPtr
)))
5114 ZeroMemory(&dispInfo
, sizeof(dispInfo
));
5116 if (lStyle
& LVS_OWNERDATA
)
5118 if (lpLVItem
->mask
& ~LVIF_STATE
)
5120 memcpy(&dispInfo
.item
, lpLVItem
, sizeof(LVITEMW
));
5121 dispinfo_notifyT(infoPtr
, LVN_GETDISPINFOW
, &dispInfo
, isW
);
5122 memcpy(lpLVItem
, &dispInfo
.item
, sizeof(LVITEMW
));
5123 TRACE(" getdispinfo(1):lpLVItem=%s\n", debuglvitem_t(lpLVItem
, isW
));
5126 if ((lpLVItem
->mask
& LVIF_STATE
)&&(lpLVItem
->iSubItem
== 0))
5128 lpLVItem
->state
= 0;
5129 if (infoPtr
->nFocusedItem
== lpLVItem
->iItem
)
5130 lpLVItem
->state
|= LVIS_FOCUSED
;
5131 if (LISTVIEW_IsSelected(infoPtr
,lpLVItem
->iItem
))
5132 lpLVItem
->state
|= LVIS_SELECTED
;
5138 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
);
5139 if (hdpaSubItems
== NULL
) return FALSE
;
5141 if ( (lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0)) == NULL
)
5144 ZeroMemory(&dispInfo
.item
, sizeof(LVITEMW
));
5145 if (lpLVItem
->iSubItem
== 0)
5147 piImage
=&lpItem
->iImage
;
5148 ppszText
=&lpItem
->pszText
;
5149 plParam
=&lpItem
->lParam
;
5150 if ((lpLVItem
->mask
& LVIF_STATE
) && infoPtr
->uCallbackMask
)
5152 dispInfo
.item
.mask
|= LVIF_STATE
;
5153 dispInfo
.item
.stateMask
= infoPtr
->uCallbackMask
;
5158 lpSubItem
= LISTVIEW_GetSubItemPtr(hdpaSubItems
, lpLVItem
->iSubItem
);
5159 if (lpSubItem
!= NULL
)
5161 piImage
=&lpSubItem
->iImage
;
5162 ppszText
=&lpSubItem
->pszText
;
5166 if ((lpLVItem
->mask
& LVIF_IMAGE
) && (*piImage
==I_IMAGECALLBACK
))
5168 dispInfo
.item
.mask
|= LVIF_IMAGE
;
5171 if ((lpLVItem
->mask
& LVIF_TEXT
) && !is_textW(*ppszText
))
5173 dispInfo
.item
.mask
|= LVIF_TEXT
;
5174 dispInfo
.item
.pszText
= lpLVItem
->pszText
;
5175 dispInfo
.item
.cchTextMax
= lpLVItem
->cchTextMax
;
5176 if (dispInfo
.item
.pszText
&& lpLVItem
->cchTextMax
> 0)
5177 *dispInfo
.item
.pszText
= '\0';
5178 if (dispInfo
.item
.pszText
&& (*ppszText
== NULL
))
5179 *dispInfo
.item
.pszText
= '\0';
5182 if (dispInfo
.item
.mask
!= 0)
5184 /* We don't have all the requested info, query the application */
5185 dispInfo
.item
.iItem
= lpLVItem
->iItem
;
5186 dispInfo
.item
.iSubItem
= lpLVItem
->iSubItem
;
5187 dispInfo
.item
.lParam
= lpItem
->lParam
;
5188 dispinfo_notifyT(infoPtr
, LVN_GETDISPINFOW
, &dispInfo
, isW
);
5189 TRACE(" getdispinfo(2):lpLVItem=%s\n", debuglvitem_t(&dispInfo
.item
, isW
));
5192 if (dispInfo
.item
.mask
& LVIF_IMAGE
)
5194 lpLVItem
->iImage
= dispInfo
.item
.iImage
;
5195 if ((dispInfo
.item
.mask
& LVIF_DI_SETITEM
) && (*piImage
==I_IMAGECALLBACK
))
5196 *piImage
= dispInfo
.item
.iImage
;
5198 else if (lpLVItem
->mask
& LVIF_IMAGE
)
5200 lpLVItem
->iImage
= *piImage
;
5203 if (dispInfo
.item
.mask
& LVIF_PARAM
)
5205 lpLVItem
->lParam
= dispInfo
.item
.lParam
;
5206 if (dispInfo
.item
.mask
& LVIF_DI_SETITEM
)
5207 *plParam
= dispInfo
.item
.lParam
;
5209 else if (lpLVItem
->mask
& LVIF_PARAM
)
5210 lpLVItem
->lParam
= lpItem
->lParam
;
5212 if (dispInfo
.item
.mask
& LVIF_TEXT
)
5214 if ((dispInfo
.item
.mask
& LVIF_DI_SETITEM
) && *ppszText
)
5215 textsetptrT(ppszText
, dispInfo
.item
.pszText
, isW
);
5217 /* If lpLVItem->pszText==dispInfo.item.pszText a copy is unnecessary, but */
5218 /* some apps give a new pointer in ListView_Notify so we can't be sure. */
5219 if (lpLVItem
->pszText
!= dispInfo
.item
.pszText
)
5220 textcpynT(lpLVItem
->pszText
, isW
, dispInfo
.item
.pszText
, isW
, lpLVItem
->cchTextMax
);
5223 else if (lpLVItem
->mask
& LVIF_TEXT
)
5225 if (internal
) lpLVItem
->pszText
= *ppszText
;
5226 else textcpynT(lpLVItem
->pszText
, isW
, *ppszText
, TRUE
, lpLVItem
->cchTextMax
);
5229 if (lpLVItem
->iSubItem
== 0)
5231 if (dispInfo
.item
.mask
& LVIF_STATE
)
5233 lpLVItem
->state
= lpItem
->state
;
5234 lpLVItem
->state
&= ~dispInfo
.item
.stateMask
;
5235 lpLVItem
->state
|= (dispInfo
.item
.state
& dispInfo
.item
.stateMask
);
5237 lpLVItem
->state
&= ~LVIS_SELECTED
;
5238 if ((dispInfo
.item
.stateMask
& LVIS_SELECTED
) &&
5239 LISTVIEW_IsSelected(infoPtr
,dispInfo
.item
.iItem
))
5240 lpLVItem
->state
|= LVIS_SELECTED
;
5242 else if (lpLVItem
->mask
& LVIF_STATE
)
5244 lpLVItem
->state
= lpItem
->state
& lpLVItem
->stateMask
;
5246 lpLVItem
->state
&= ~LVIS_SELECTED
;
5247 if ((lpLVItem
->stateMask
& LVIS_SELECTED
) &&
5248 LISTVIEW_IsSelected(infoPtr
,lpLVItem
->iItem
))
5249 lpLVItem
->state
|= LVIS_SELECTED
;
5252 if (lpLVItem
->mask
& LVIF_PARAM
)
5253 lpLVItem
->lParam
= lpItem
->lParam
;
5255 if (lpLVItem
->mask
& LVIF_INDENT
)
5256 lpLVItem
->iIndent
= lpItem
->iIndent
;
5265 * Retrieves the rectangle enclosing the item icon and text.
5268 * [I] infoPtr : valid pointer to the listview structure
5269 * [I] INT : item index
5270 * [O] LPRECT : coordinate information
5276 static BOOL
LISTVIEW_GetItemBoundBox(LISTVIEW_INFO
*infoPtr
, INT nItem
, LPRECT lpRect
)
5278 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
5279 UINT uView
= lStyle
& LVS_TYPEMASK
;
5280 BOOL bResult
= FALSE
;
5282 LISTVIEW_ITEM
*lpItem
;
5283 INT nCountPerColumn
;
5286 TRACE("(nItem=%d,lpRect=%p)\n", nItem
, lpRect
);
5288 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)) &&
5291 if (uView
== LVS_LIST
)
5294 nItem
= nItem
- ListView_GetTopIndex(infoPtr
->hwndSelf
);
5295 nCountPerColumn
= LISTVIEW_GetCountPerColumn(infoPtr
);
5298 nRow
= nItem
% nCountPerColumn
;
5301 lpRect
->left
= nItem
/ nCountPerColumn
* infoPtr
->nItemWidth
;
5306 lpRect
->left
= (nItem
/ nCountPerColumn
-1) * infoPtr
->nItemWidth
;
5307 lpRect
->top
= (nRow
+ nCountPerColumn
) * infoPtr
->nItemHeight
;
5312 lpRect
->left
= nItem
/ nCountPerColumn
* infoPtr
->nItemWidth
;
5313 lpRect
->top
= nItem
% nCountPerColumn
* infoPtr
->nItemHeight
;
5316 else if (uView
== LVS_REPORT
)
5319 lpRect
->left
= REPORT_MARGINX
;
5320 lpRect
->top
= ((nItem
- ListView_GetTopIndex(infoPtr
->hwndSelf
)) *
5321 infoPtr
->nItemHeight
) + infoPtr
->rcList
.top
;
5323 if (!(lStyle
& LVS_NOSCROLL
))
5325 SCROLLINFO scrollInfo
;
5326 /* Adjust position by scrollbar offset */
5327 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
5328 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
5329 scrollInfo
.fMask
= SIF_POS
;
5330 GetScrollInfo(infoPtr
->hwndSelf
, SB_HORZ
, &scrollInfo
);
5331 lpRect
->left
-= scrollInfo
.nPos
;
5334 else /* either LVS_ICON or LVS_SMALLICON */
5336 if ((hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
)))
5338 if ((lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0)))
5341 lpRect
->left
= lpItem
->ptPosition
.x
;
5342 lpRect
->top
= lpItem
->ptPosition
.y
;
5347 lpRect
->right
= lpRect
->left
+ infoPtr
->nItemWidth
;
5348 lpRect
->bottom
= lpRect
->top
+ infoPtr
->nItemHeight
;
5349 TRACE("result %s: (%d,%d)-(%d,%d)\n", bResult
? "TRUE" : "FALSE",
5350 lpRect
->left
, lpRect
->top
, lpRect
->right
, lpRect
->bottom
);
5356 * Retrieves the position (upper-left) of the listview control item.
5357 * Note that for LVS_ICON style, the upper-left is that of the icon
5358 * and not the bounding box.
5361 * [I] infoPtr : valid pointer to the listview structure
5362 * [I] INT : item index
5363 * [O] LPPOINT : coordinate information
5369 static BOOL
LISTVIEW_GetItemPosition(LISTVIEW_INFO
*infoPtr
, INT nItem
, LPPOINT lpptPosition
)
5371 UINT uView
= GetWindowLongA(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
5372 BOOL bResult
= FALSE
;
5375 TRACE("(nItem=%d, lpptPosition=%p)\n", nItem
, lpptPosition
);
5377 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)) &&
5378 (lpptPosition
!= NULL
))
5380 bResult
= LISTVIEW_GetItemBoundBox(infoPtr
, nItem
, &rcBounding
);
5381 lpptPosition
->x
= rcBounding
.left
;
5382 lpptPosition
->y
= rcBounding
.top
;
5383 if (uView
== LVS_ICON
)
5385 lpptPosition
->y
+= ICON_TOP_PADDING
;
5386 lpptPosition
->x
+= (infoPtr
->iconSpacing
.cx
- infoPtr
->iconSize
.cx
) / 2;
5388 TRACE("result %s (%ld,%ld)\n", bResult
? "TRUE" : "FALSE",
5389 lpptPosition
->x
, lpptPosition
->y
);
5395 * Update the bounding rectangle around the text under a large icon.
5396 * This depends on whether it has the focus or not.
5397 * On entry the rectangle's top, left and right should be set.
5398 * On return the bottom will also be set and the width may have been
5402 * [I] infoPtr : pointer to the listview structure
5403 * [I] nItem : the item for which we are calculating this
5404 * [I] rect : the rectangle to be updated
5406 * This appears to be weird, even in the Microsoft implementation.
5408 static void LISTVIEW_UpdateLargeItemLabelRect (LISTVIEW_INFO
*infoPtr
, int nItem
, RECT
*rect
)
5410 HDC hdc
= GetDC (infoPtr
->hwndSelf
);
5411 HFONT hOldFont
= SelectObject (hdc
, infoPtr
->hFont
);
5413 if (infoPtr
->bFocus
&& infoPtr
->nFocusedItem
== nItem
)
5415 /* We (aim to) display the full text. In Windows 95 it appears to
5416 * calculate the size assuming the specified font and then it draws
5417 * the text in that region with the specified font except scaled to
5418 * 10 point (or the height of the system font or ...). Thus if the
5419 * window has 24 point Helvetica the highlit rectangle will be
5420 * taller than the text and if it is 7 point Helvetica then the text
5422 * For now we will simply say that it is the correct size to display
5423 * the text in the specified font.
5426 lvItem
.mask
= LVIF_TEXT
;
5427 lvItem
.iItem
= nItem
;
5428 lvItem
.iSubItem
= 0;
5429 /* We will specify INTERNAL and so will receive back a const
5430 * pointer to the text, rather than specifying a buffer to which
5433 LISTVIEW_GetItemW (infoPtr
, &lvItem
, TRUE
);
5434 DrawTextW (hdc
, lvItem
.pszText
, -1, rect
, DT_CALCRECT
|
5435 DT_NOCLIP
| DT_EDITCONTROL
| DT_TOP
| DT_CENTER
|
5436 DT_WORDBREAK
| DT_NOPREFIX
);
5437 /* Maintain this DT_* list in line with LISTVIEW_DrawLargeItem */
5441 /* As far as I can see the text region seems to be trying to be
5442 * "tall enough for two lines of text". Once again (comctl32.dll ver
5443 * 5.81?) it measures this on the basis of the selected font and then
5444 * draws it with the same font except in 10 point size. This can lead
5445 * to more or less than the two rows appearing.
5446 * Question; are we supposed to be including DT_EXTERNALLEADING?
5447 * Question; should the width be shrunk to the space required to
5448 * display the two lines?
5450 rect
->bottom
= rect
->top
+ 2 * infoPtr
->ntmHeight
;
5453 SelectObject (hdc
, hOldFont
);
5454 ReleaseDC (infoPtr
->hwndSelf
, hdc
);
5459 * Retrieves the bounding rectangle for a listview control item.
5462 * [I] infoPtr : valid pointer to the listview structure
5463 * [I] INT : item index
5464 * [IO] LPRECT : bounding rectangle coordinates
5465 * lprc->left specifies the portion of the item for which the bounding
5466 * rectangle will be retrieved.
5468 * LVIR_BOUNDS Returns the bounding rectangle of the entire item,
5469 * including the icon and label.
5470 * LVIR_ICON Returns the bounding rectangle of the icon or small icon.
5471 * LVIR_LABEL Returns the bounding rectangle of the item text.
5472 * LVIR_SELECTBOUNDS Returns the union of the LVIR_ICON and LVIR_LABEL
5473 * rectangles, but excludes columns in report view.
5480 * Note that the bounding rectangle of the label in the LVS_ICON view depends
5481 * upon whether the window has the focus currently and on whether the item
5482 * is the one with the focus. Ensure that the control's record of which
5483 * item has the focus agrees with the items' records.
5485 static LRESULT
LISTVIEW_GetItemRect(LISTVIEW_INFO
*infoPtr
, INT nItem
, LPRECT lprc
)
5487 UINT uView
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
5488 BOOL bResult
= FALSE
;
5497 TRACE("(nItem=%d, lprc=%p)\n", nItem
, lprc
);
5499 if (uView
& LVS_REPORT
)
5501 ZeroMemory(&lvItem
, sizeof(lvItem
));
5502 lvItem
.mask
= LVIF_INDENT
;
5503 lvItem
.iItem
= nItem
;
5504 lvItem
.iSubItem
= 0;
5505 LISTVIEW_GetItemW(infoPtr
, &lvItem
, TRUE
);
5508 if (lvItem
.iIndent
>0 && infoPtr
->iconSize
.cx
> 0)
5509 nIndent
= infoPtr
->iconSize
.cx
* lvItem
.iIndent
;
5516 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)) && (lprc
!= NULL
))
5521 if (!LISTVIEW_GetItemPosition(infoPtr
, nItem
, &ptItem
)) break;
5522 if (uView
== LVS_ICON
)
5524 if (infoPtr
->himlNormal
!= NULL
)
5526 if (LISTVIEW_GetOrigin(infoPtr
, &ptOrigin
))
5529 lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
5530 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
5531 lprc
->right
= lprc
->left
+ infoPtr
->iconSize
.cx
;
5532 lprc
->bottom
= (lprc
->top
+ infoPtr
->iconSize
.cy
+
5533 ICON_BOTTOM_PADDING
+ ICON_TOP_PADDING
);
5537 else if (uView
== LVS_SMALLICON
)
5539 if (LISTVIEW_GetOrigin(infoPtr
, &ptOrigin
))
5542 lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
5543 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
5544 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
5546 if (infoPtr
->himlState
!= NULL
)
5547 lprc
->left
+= infoPtr
->iconSize
.cx
;
5549 if (infoPtr
->himlSmall
!= NULL
)
5550 lprc
->right
= lprc
->left
+ infoPtr
->iconSize
.cx
;
5552 lprc
->right
= lprc
->left
;
5558 lprc
->left
= ptItem
.x
;
5559 if (uView
& LVS_REPORT
)
5560 lprc
->left
+= nIndent
;
5561 lprc
->top
= ptItem
.y
;
5562 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
5564 if (infoPtr
->himlState
!= NULL
)
5565 lprc
->left
+= infoPtr
->iconSize
.cx
;
5567 if (infoPtr
->himlSmall
!= NULL
)
5568 lprc
->right
= lprc
->left
+ infoPtr
->iconSize
.cx
;
5570 lprc
->right
= lprc
->left
;
5575 if (!LISTVIEW_GetItemPosition(infoPtr
, nItem
, &ptItem
)) break;
5576 if (uView
== LVS_ICON
)
5578 if (infoPtr
->himlNormal
!= NULL
)
5580 if (LISTVIEW_GetOrigin(infoPtr
, &ptOrigin
))
5583 lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
5584 lprc
->top
= (ptItem
.y
+ ptOrigin
.y
+ infoPtr
->iconSize
.cy
+
5585 ICON_BOTTOM_PADDING
);
5586 nLabelWidth
= LISTVIEW_GetLabelWidth(infoPtr
, nItem
);
5587 if (infoPtr
->iconSpacing
.cx
- nLabelWidth
> 1)
5589 lprc
->left
+= (infoPtr
->iconSpacing
.cx
- nLabelWidth
) / 2;
5590 lprc
->right
= lprc
->left
+ nLabelWidth
;
5595 lprc
->right
= lprc
->left
+ infoPtr
->iconSpacing
.cx
- 1;
5596 LISTVIEW_UpdateLargeItemLabelRect (infoPtr
, nItem
, lprc
);
5598 lprc
->bottom
= lprc
->top
+ infoPtr
->ntmHeight
+ HEIGHT_PADDING
;
5602 else if (uView
== LVS_SMALLICON
)
5604 if (LISTVIEW_GetOrigin(infoPtr
, &ptOrigin
))
5607 nLeftPos
= lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
5608 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
5609 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
5611 if (infoPtr
->himlState
!= NULL
)
5612 lprc
->left
+= infoPtr
->iconSize
.cx
;
5614 if (infoPtr
->himlSmall
!= NULL
)
5615 lprc
->left
+= infoPtr
->iconSize
.cx
;
5617 nLabelWidth
= LISTVIEW_GetLabelWidth(infoPtr
, nItem
);
5618 nLabelWidth
+= TRAILING_PADDING
;
5619 if (lprc
->left
+ nLabelWidth
< nLeftPos
+ infoPtr
->nItemWidth
)
5620 lprc
->right
= lprc
->left
+ nLabelWidth
;
5622 lprc
->right
= nLeftPos
+ infoPtr
->nItemWidth
;
5628 if (uView
== LVS_REPORT
)
5629 nLeftPos
= lprc
->left
= ptItem
.x
+ nIndent
;
5631 nLeftPos
= lprc
->left
= ptItem
.x
;
5632 lprc
->top
= ptItem
.y
;
5633 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
5635 if (infoPtr
->himlState
!= NULL
)
5636 lprc
->left
+= infoPtr
->iconSize
.cx
;
5638 if (infoPtr
->himlSmall
!= NULL
)
5639 lprc
->left
+= infoPtr
->iconSize
.cx
;
5641 if (uView
!= LVS_REPORT
)
5643 nLabelWidth
= LISTVIEW_GetLabelWidth(infoPtr
, nItem
);
5644 nLabelWidth
+= TRAILING_PADDING
;
5645 if (infoPtr
->himlSmall
)
5646 nLabelWidth
+= IMAGE_PADDING
;
5649 nLabelWidth
= LISTVIEW_GetColumnWidth(infoPtr
, 0)-lprc
->left
;
5650 if (lprc
->left
+ nLabelWidth
< nLeftPos
+ infoPtr
->nItemWidth
)
5651 lprc
->right
= lprc
->left
+ nLabelWidth
;
5653 lprc
->right
= nLeftPos
+ infoPtr
->nItemWidth
;
5658 if (!LISTVIEW_GetItemBoundBox(infoPtr
, nItem
, &rcInternal
)) break;
5659 ptItem
.x
= rcInternal
.left
;
5660 ptItem
.y
= rcInternal
.top
;
5661 if (uView
== LVS_ICON
)
5663 if (infoPtr
->himlNormal
!= NULL
)
5665 if (LISTVIEW_GetOrigin(infoPtr
, &ptOrigin
))
5668 INT text_left
, text_right
, icon_left
, text_pos_x
;
5669 /* for style LVS_ICON bounds
5670 * left = min(icon.left, text.left)
5671 * right = max(icon.right, text.right)
5672 * top = boundbox.top + NOTHITABLE
5673 * bottom = text.bottom + 1
5676 icon_left
= text_left
= ptItem
.x
;
5678 /* Correct ptItem to icon upper-left */
5679 icon_left
+= (infoPtr
->nItemWidth
- infoPtr
->iconSize
.cx
)/2;
5680 ptItem
.y
+= ICON_TOP_PADDING
;
5682 /* Compute the label left and right */
5683 nLabelWidth
= LISTVIEW_GetLabelWidth(infoPtr
, nItem
);
5684 text_pos_x
= infoPtr
->iconSpacing
.cx
- 2*CAPTION_BORDER
- nLabelWidth
;
5687 text_left
+= text_pos_x
/ 2;
5688 text_right
= text_left
+ nLabelWidth
+ 2*CAPTION_BORDER
;
5693 text_right
= text_left
+ infoPtr
->iconSpacing
.cx
- 1;
5696 /* Compute rectangle w/o the text height */
5697 lprc
->left
= min(icon_left
, text_left
) + ptOrigin
.x
;
5698 lprc
->right
= max(icon_left
+ infoPtr
->iconSize
.cx
,
5699 text_right
) + ptOrigin
.x
;
5700 lprc
->top
= ptItem
.y
+ ptOrigin
.y
- ICON_TOP_PADDING_HITABLE
;
5701 lprc
->bottom
= lprc
->top
+ ICON_TOP_PADDING_HITABLE
5702 + infoPtr
->iconSize
.cy
+ 1
5703 + ICON_BOTTOM_PADDING
;
5705 CopyRect (&label_rect
, lprc
);
5706 label_rect
.top
= lprc
->bottom
;
5707 LISTVIEW_UpdateLargeItemLabelRect (infoPtr
, nItem
, &label_rect
);
5708 UnionRect (lprc
, lprc
, &label_rect
);
5712 else if (uView
== LVS_SMALLICON
)
5714 if (LISTVIEW_GetOrigin(infoPtr
, &ptOrigin
))
5717 lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
5718 lprc
->right
= lprc
->left
;
5719 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
5720 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
5721 if (infoPtr
->himlState
!= NULL
)
5722 lprc
->right
+= infoPtr
->iconSize
.cx
;
5723 if (infoPtr
->himlSmall
!= NULL
)
5724 lprc
->right
+= infoPtr
->iconSize
.cx
;
5726 nLabelWidth
= LISTVIEW_GetLabelWidth(infoPtr
, nItem
);
5727 nLabelWidth
+= TRAILING_PADDING
;
5728 if (infoPtr
->himlSmall
)
5729 nLabelWidth
+= IMAGE_PADDING
;
5730 if (lprc
->right
+ nLabelWidth
< lprc
->left
+ infoPtr
->nItemWidth
)
5731 lprc
->right
+= nLabelWidth
;
5733 lprc
->right
= lprc
->left
+ infoPtr
->nItemWidth
;
5739 lprc
->left
= ptItem
.x
;
5740 if (!(infoPtr
->dwExStyle
&LVS_EX_FULLROWSELECT
) && uView
&LVS_REPORT
)
5741 lprc
->left
+= nIndent
;
5742 lprc
->right
= lprc
->left
;
5743 lprc
->top
= ptItem
.y
;
5744 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
5746 if ((infoPtr
->dwExStyle
& LVS_EX_FULLROWSELECT
) || (uView
== LVS_REPORT
))
5749 int nColumnCount
= Header_GetItemCount(infoPtr
->hwndHeader
);
5750 Header_GetItemRect(infoPtr
->hwndHeader
, nColumnCount
-1, &br
);
5752 lprc
->right
= max(lprc
->left
, br
.right
- REPORT_MARGINX
);
5756 if (infoPtr
->himlState
!= NULL
)
5757 lprc
->right
+= infoPtr
->iconSize
.cx
;
5759 if (infoPtr
->himlSmall
!= NULL
)
5760 lprc
->right
+= infoPtr
->iconSize
.cx
;
5762 nLabelWidth
= LISTVIEW_GetLabelWidth(infoPtr
, nItem
);
5763 nLabelWidth
+= TRAILING_PADDING
;
5764 if (lprc
->right
+ nLabelWidth
< lprc
->left
+ infoPtr
->nItemWidth
)
5765 lprc
->right
+= nLabelWidth
;
5767 lprc
->right
= lprc
->left
+ infoPtr
->nItemWidth
;
5772 case LVIR_SELECTBOUNDS
:
5773 if (!LISTVIEW_GetItemPosition(infoPtr
, nItem
, &ptItem
)) break;
5774 if (uView
== LVS_ICON
)
5776 if (infoPtr
->himlNormal
!= NULL
)
5778 if (LISTVIEW_GetOrigin(infoPtr
, &ptOrigin
))
5781 lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
5782 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
5783 lprc
->right
= lprc
->left
+ infoPtr
->iconSpacing
.cx
;
5784 lprc
->bottom
= lprc
->top
+ infoPtr
->iconSpacing
.cy
;
5788 else if (uView
== LVS_SMALLICON
)
5790 if (LISTVIEW_GetOrigin(infoPtr
, &ptOrigin
))
5793 nLeftPos
= lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
5794 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
5795 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
5797 if (infoPtr
->himlState
!= NULL
)
5798 lprc
->left
+= infoPtr
->iconSize
.cx
;
5800 lprc
->right
= lprc
->left
;
5802 if (infoPtr
->himlSmall
!= NULL
)
5803 lprc
->right
+= infoPtr
->iconSize
.cx
;
5805 nLabelWidth
= LISTVIEW_GetLabelWidth(infoPtr
, nItem
);
5806 nLabelWidth
+= TRAILING_PADDING
;
5807 if (lprc
->right
+ nLabelWidth
< nLeftPos
+ infoPtr
->nItemWidth
)
5808 lprc
->right
+= nLabelWidth
;
5810 lprc
->right
= nLeftPos
+ infoPtr
->nItemWidth
;
5816 if (!(infoPtr
->dwExStyle
&LVS_EX_FULLROWSELECT
) && (uView
&LVS_REPORT
))
5817 nLeftPos
= lprc
->left
= ptItem
.x
+ nIndent
;
5819 nLeftPos
= lprc
->left
= ptItem
.x
;
5820 lprc
->top
= ptItem
.y
;
5821 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
5823 if (infoPtr
->himlState
!= NULL
)
5824 lprc
->left
+= infoPtr
->iconSize
.cx
;
5826 lprc
->right
= lprc
->left
;
5828 if (infoPtr
->dwExStyle
& LVS_EX_FULLROWSELECT
)
5831 int nColumnCount
= Header_GetItemCount(infoPtr
->hwndHeader
);
5832 Header_GetItemRect(infoPtr
->hwndHeader
, nColumnCount
-1, &br
);
5834 lprc
->right
= max(lprc
->left
, br
.right
- REPORT_MARGINX
);
5838 if (infoPtr
->himlSmall
!= NULL
)
5839 lprc
->right
+= infoPtr
->iconSize
.cx
;
5841 nLabelWidth
= LISTVIEW_GetLabelWidth(infoPtr
, nItem
);
5842 nLabelWidth
+= TRAILING_PADDING
;
5843 if (infoPtr
->himlSmall
)
5844 nLabelWidth
+= IMAGE_PADDING
;
5845 if (lprc
->right
+ nLabelWidth
< nLeftPos
+ infoPtr
->nItemWidth
)
5846 lprc
->right
+= nLabelWidth
;
5848 lprc
->right
= nLeftPos
+ infoPtr
->nItemWidth
;
5853 TRACE("result %s (%d,%d)-(%d,%d)\n",
5854 (bResult
) ? "TRUE" : "FALSE",
5855 lprc
->left
, lprc
->top
, lprc
->right
, lprc
->bottom
);
5858 TRACE("result %s (%d,%d)-(%d,%d)\n", bResult
? "TRUE" : "FALSE",
5859 lprc
->left
, lprc
->top
, lprc
->right
, lprc
->bottom
);
5865 static LRESULT
LISTVIEW_GetSubItemRect(LISTVIEW_INFO
*infoPtr
, INT nItem
, INT nSubItem
, INT
5868 UINT uView
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
5871 TRACE("(nItem=%d, nSubItem=%d lprc=%p)\n", nItem
, nSubItem
,
5874 if (!(uView
& LVS_REPORT
))
5877 if (flags
& LVIR_ICON
)
5879 FIXME("Unimplemented LVIR_ICON\n");
5884 int top
= min(infoPtr
->nColumnCount
, nSubItem
- 1);
5886 LISTVIEW_GetItemRect(infoPtr
,nItem
,lprc
);
5887 for (count
= 0; count
< top
; count
++)
5888 lprc
->left
+= LISTVIEW_GetColumnWidth(infoPtr
,count
);
5890 lprc
->right
= LISTVIEW_GetColumnWidth(infoPtr
,(nSubItem
-1)) +
5899 * Retrieves the width of a label.
5902 * [I] infoPtr : valid pointer to the listview structure
5905 * SUCCESS : string width (in pixels)
5908 static INT
LISTVIEW_GetLabelWidth(LISTVIEW_INFO
*infoPtr
, INT nItem
)
5910 WCHAR szDispText
[DISP_TEXT_SIZE
] = { '\0' };
5911 INT nLabelWidth
= 0;
5914 TRACE("(nItem=%d)\n", nItem
);
5916 ZeroMemory(&lvItem
, sizeof(lvItem
));
5917 lvItem
.mask
= LVIF_TEXT
;
5918 lvItem
.iItem
= nItem
;
5919 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
5920 lvItem
.pszText
= szDispText
;
5921 if (LISTVIEW_GetItemW(infoPtr
, &lvItem
, TRUE
))
5922 nLabelWidth
= LISTVIEW_GetStringWidthT(infoPtr
, lvItem
.pszText
, TRUE
);
5929 * Retrieves the spacing between listview control items.
5932 * [I] infoPtr : valid pointer to the listview structure
5933 * [I] BOOL : flag for small or large icon
5936 * Horizontal + vertical spacing
5938 static LRESULT
LISTVIEW_GetItemSpacing(LISTVIEW_INFO
*infoPtr
, BOOL bSmall
)
5944 lResult
= MAKELONG(infoPtr
->iconSpacing
.cx
, infoPtr
->iconSpacing
.cy
);
5948 LONG style
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
5949 if ((style
& LVS_TYPEMASK
) == LVS_ICON
)
5950 lResult
= MAKELONG(DEFAULT_COLUMN_WIDTH
, GetSystemMetrics(SM_CXSMICON
)+HEIGHT_PADDING
);
5952 lResult
= MAKELONG(infoPtr
->nItemWidth
, infoPtr
->nItemHeight
);
5959 * Retrieves the state of a listview control item.
5962 * [I] infoPtr : valid pointer to the listview structure
5963 * [I] INT : item index
5964 * [I] UINT : state mask
5967 * State specified by the mask.
5969 static LRESULT
LISTVIEW_GetItemState(LISTVIEW_INFO
*infoPtr
, INT nItem
, UINT uMask
)
5974 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
5976 ZeroMemory(&lvItem
, sizeof(lvItem
));
5977 lvItem
.iItem
= nItem
;
5978 lvItem
.stateMask
= uMask
;
5979 lvItem
.mask
= LVIF_STATE
;
5980 if (LISTVIEW_GetItemW(infoPtr
, &lvItem
, TRUE
))
5981 uState
= lvItem
.state
;
5989 * Retrieves the text of a listview control item or subitem.
5992 * [I] hwnd : window handle
5993 * [I] nItem : item index
5994 * [IO] lpLVItem : item information
5995 * [I] isW : TRUE if lpLVItem is Unicode
5998 * SUCCESS : string length
6001 static LRESULT
LISTVIEW_GetItemTextT(LISTVIEW_INFO
*infoPtr
, INT nItem
, LPLVITEMW lpLVItem
, BOOL isW
)
6005 if (lpLVItem
!= NULL
)
6007 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
6009 lpLVItem
->mask
= LVIF_TEXT
;
6010 lpLVItem
->iItem
= nItem
;
6011 if (LISTVIEW_GetItemT(infoPtr
, lpLVItem
, FALSE
, isW
))
6012 nLength
= textlenT(lpLVItem
->pszText
, isW
);
6021 * Searches for an item based on properties + relationships.
6024 * [I] infoPtr : valid pointer to the listview structure
6025 * [I] INT : item index
6026 * [I] INT : relationship flag
6029 * SUCCESS : item index
6032 static LRESULT
LISTVIEW_GetNextItem(LISTVIEW_INFO
*infoPtr
, INT nItem
, UINT uFlags
)
6034 UINT uView
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
6036 LVFINDINFOW lvFindInfo
;
6037 INT nCountPerColumn
;
6040 if ((nItem
>= -1) && (nItem
< GETITEMCOUNT(infoPtr
)))
6042 ZeroMemory(&lvFindInfo
, sizeof(lvFindInfo
));
6044 if (uFlags
& LVNI_CUT
)
6047 if (uFlags
& LVNI_DROPHILITED
)
6048 uMask
|= LVIS_DROPHILITED
;
6050 if (uFlags
& LVNI_FOCUSED
)
6051 uMask
|= LVIS_FOCUSED
;
6053 if (uFlags
& LVNI_SELECTED
)
6054 uMask
|= LVIS_SELECTED
;
6056 if (uFlags
& LVNI_ABOVE
)
6058 if ((uView
== LVS_LIST
) || (uView
== LVS_REPORT
))
6063 if ((ListView_GetItemState(infoPtr
->hwndSelf
, nItem
, uMask
) & uMask
) == uMask
)
6069 lvFindInfo
.flags
= LVFI_NEARESTXY
;
6070 lvFindInfo
.vkDirection
= VK_UP
;
6071 ListView_GetItemPosition(infoPtr
->hwndSelf
, nItem
, &lvFindInfo
.pt
);
6072 while ((nItem
= ListView_FindItemW(infoPtr
->hwndSelf
, nItem
, &lvFindInfo
)) != -1)
6074 if ((ListView_GetItemState(infoPtr
->hwndSelf
, nItem
, uMask
) & uMask
) == uMask
)
6079 else if (uFlags
& LVNI_BELOW
)
6081 if ((uView
== LVS_LIST
) || (uView
== LVS_REPORT
))
6083 while (nItem
< GETITEMCOUNT(infoPtr
))
6086 if ((ListView_GetItemState(infoPtr
->hwndSelf
, nItem
, uMask
) & uMask
) == uMask
)
6092 lvFindInfo
.flags
= LVFI_NEARESTXY
;
6093 lvFindInfo
.vkDirection
= VK_DOWN
;
6094 ListView_GetItemPosition(infoPtr
->hwndSelf
, nItem
, &lvFindInfo
.pt
);
6095 while ((nItem
= ListView_FindItemW(infoPtr
->hwndSelf
, nItem
, &lvFindInfo
)) != -1)
6097 if ((ListView_GetItemState(infoPtr
->hwndSelf
, nItem
, uMask
) & uMask
) == uMask
)
6102 else if (uFlags
& LVNI_TOLEFT
)
6104 if (uView
== LVS_LIST
)
6106 nCountPerColumn
= LISTVIEW_GetCountPerColumn(infoPtr
);
6107 while (nItem
- nCountPerColumn
>= 0)
6109 nItem
-= nCountPerColumn
;
6110 if ((ListView_GetItemState(infoPtr
->hwndSelf
, nItem
, uMask
) & uMask
) == uMask
)
6114 else if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
6116 lvFindInfo
.flags
= LVFI_NEARESTXY
;
6117 lvFindInfo
.vkDirection
= VK_LEFT
;
6118 ListView_GetItemPosition(infoPtr
->hwndSelf
, nItem
, &lvFindInfo
.pt
);
6119 while ((nItem
= ListView_FindItemW(infoPtr
->hwndSelf
, nItem
, &lvFindInfo
)) != -1)
6121 if ((ListView_GetItemState(infoPtr
->hwndSelf
, nItem
, uMask
) & uMask
) == uMask
)
6126 else if (uFlags
& LVNI_TORIGHT
)
6128 if (uView
== LVS_LIST
)
6130 nCountPerColumn
= LISTVIEW_GetCountPerColumn(infoPtr
);
6131 while (nItem
+ nCountPerColumn
< GETITEMCOUNT(infoPtr
))
6133 nItem
+= nCountPerColumn
;
6134 if ((ListView_GetItemState(infoPtr
->hwndSelf
, nItem
, uMask
) & uMask
) == uMask
)
6138 else if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
6140 lvFindInfo
.flags
= LVFI_NEARESTXY
;
6141 lvFindInfo
.vkDirection
= VK_RIGHT
;
6142 ListView_GetItemPosition(infoPtr
->hwndSelf
, nItem
, &lvFindInfo
.pt
);
6143 while ((nItem
= ListView_FindItemW(infoPtr
->hwndSelf
, nItem
, &lvFindInfo
)) != -1)
6145 if ((ListView_GetItemState(infoPtr
->hwndSelf
, nItem
, uMask
) & uMask
) == uMask
)
6154 /* search by index */
6155 for (i
= nItem
; i
< GETITEMCOUNT(infoPtr
); i
++)
6157 if ((ListView_GetItemState(infoPtr
->hwndSelf
, i
, uMask
) & uMask
) == uMask
)
6166 /* LISTVIEW_GetNumberOfWorkAreas */
6170 * Retrieves the origin coordinates when in icon or small icon display mode.
6173 * [I] infoPtr : valid pointer to the listview structure
6174 * [O] LPPOINT : coordinate information
6180 static LRESULT
LISTVIEW_GetOrigin(LISTVIEW_INFO
*infoPtr
, LPPOINT lpptOrigin
)
6182 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
6183 UINT uView
= lStyle
& LVS_TYPEMASK
;
6184 BOOL bResult
= FALSE
;
6186 TRACE("(lpptOrigin=%p)\n", lpptOrigin
);
6188 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
6190 SCROLLINFO scrollInfo
;
6191 ZeroMemory(lpptOrigin
, sizeof(POINT
));
6192 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
6193 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
6195 if (lStyle
& WS_HSCROLL
)
6197 scrollInfo
.fMask
= SIF_POS
;
6198 if (GetScrollInfo(infoPtr
->hwndSelf
, SB_HORZ
, &scrollInfo
))
6199 lpptOrigin
->x
= -scrollInfo
.nPos
;
6202 if (lStyle
& WS_VSCROLL
)
6204 scrollInfo
.fMask
= SIF_POS
;
6205 if (GetScrollInfo(infoPtr
->hwndSelf
, SB_VERT
, &scrollInfo
))
6206 lpptOrigin
->y
= -scrollInfo
.nPos
;
6211 TRACE("(pt=(%ld,%ld))\n", lpptOrigin
->x
, lpptOrigin
->y
);
6220 * Retrieves the number of items that are marked as selected.
6223 * [I] infoPtr : valid pointer to the listview structure
6226 * Number of items selected.
6228 static LRESULT
LISTVIEW_GetSelectedCount(LISTVIEW_INFO
*infoPtr
)
6231 INT nSelectedCount
= 0;
6234 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
6236 if (ListView_GetItemState(infoPtr
->hwndSelf
, i
, LVIS_SELECTED
) & LVIS_SELECTED
)
6240 return nSelectedCount
;
6245 * Retrieves the width of a string.
6248 * [I] hwnd : window handle
6249 * [I] lpszText : text string to process
6250 * [I] isW : TRUE if lpszText is Unicode, FALSE otherwise
6253 * SUCCESS : string width (in pixels)
6256 static LRESULT
LISTVIEW_GetStringWidthT(LISTVIEW_INFO
*infoPtr
, LPCWSTR lpszText
, BOOL isW
)
6258 if (is_textT(lpszText
, isW
))
6260 HFONT hFont
= infoPtr
->hFont
? infoPtr
->hFont
: infoPtr
->hDefaultFont
;
6261 HDC hdc
= GetDC(infoPtr
->hwndSelf
);
6262 HFONT hOldFont
= SelectObject(hdc
, hFont
);
6264 ZeroMemory(&stringSize
, sizeof(SIZE
));
6266 GetTextExtentPointW(hdc
, lpszText
, lstrlenW(lpszText
), &stringSize
);
6268 GetTextExtentPointA(hdc
, (LPCSTR
)lpszText
, lstrlenA((LPCSTR
)lpszText
), &stringSize
);
6269 SelectObject(hdc
, hOldFont
);
6270 ReleaseDC(infoPtr
->hwndSelf
, hdc
);
6271 return stringSize
.cx
;
6278 * Retrieves the text backgound color.
6281 * [I] infoPtr : valid pointer to the listview structure
6284 * COLORREF associated with the the background.
6286 static LRESULT
LISTVIEW_GetTextBkColor(LISTVIEW_INFO
*infoPtr
)
6288 return infoPtr
->clrTextBk
;
6293 * Retrieves the text color.
6296 * [I] infoPtr : valid pointer to the listview structure
6299 * COLORREF associated with the text.
6301 static LRESULT
LISTVIEW_GetTextColor(LISTVIEW_INFO
*infoPtr
)
6303 return infoPtr
->clrText
;
6308 * Determines item if a hit or closest if not
6311 * [I] infoPtr : valid pointer to the listview structure
6312 * [IO] LPLV_INTHIT : hit test information
6313 * [I] subitem : fill out iSubItem.
6316 * SUCCESS : item index of hit
6319 static INT
LISTVIEW_SuperHitTestItem(LISTVIEW_INFO
*infoPtr
, LPLV_INTHIT lpInt
, BOOL subitem
)
6321 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
6322 UINT uView
= lStyle
& LVS_TYPEMASK
;
6323 INT i
,j
,topindex
,bottomindex
;
6324 RECT rcItem
,rcSubItem
;
6325 DWORD xterm
, yterm
, dist
;
6327 TRACE("(x=%ld, y=%ld)\n", lpInt
->ht
.pt
.x
, lpInt
->ht
.pt
.y
);
6329 topindex
= LISTVIEW_GetTopIndex(infoPtr
);
6330 if (uView
== LVS_REPORT
)
6332 bottomindex
= topindex
+ LISTVIEW_GetCountPerColumn(infoPtr
) + 1;
6333 bottomindex
= min(bottomindex
,GETITEMCOUNT(infoPtr
));
6337 bottomindex
= GETITEMCOUNT(infoPtr
);
6340 lpInt
->distance
= 0x7fffffff;
6341 lpInt
->iDistItem
= -1;
6343 for (i
= topindex
; i
< bottomindex
; i
++)
6345 rcItem
.left
= LVIR_BOUNDS
;
6346 if (LISTVIEW_GetItemRect(infoPtr
, i
, &rcItem
))
6348 if (PtInRect(&rcItem
, lpInt
->ht
.pt
))
6351 rcItem
.left
= LVIR_ICON
;
6352 if (LISTVIEW_GetItemRect(infoPtr
, i
, &rcItem
))
6354 if (PtInRect(&rcItem
, lpInt
->ht
.pt
))
6356 lpInt
->ht
.flags
= LVHT_ONITEMICON
;
6357 lpInt
->ht
.iItem
= i
;
6362 rcItem
.left
= LVIR_LABEL
;
6363 if (LISTVIEW_GetItemRect(infoPtr
, i
, &rcItem
))
6365 if (PtInRect(&rcItem
, lpInt
->ht
.pt
))
6367 lpInt
->ht
.flags
= LVHT_ONITEMLABEL
;
6368 lpInt
->ht
.iItem
= i
;
6373 lpInt
->ht
.flags
= LVHT_ONITEMSTATEICON
;
6374 lpInt
->ht
.iItem
= i
;
6378 lpInt
->ht
.iSubItem
= 0;
6379 rcSubItem
.right
= rcSubItem
.left
;
6380 for (j
= 0; j
< infoPtr
->nColumnCount
; j
++)
6382 rcSubItem
.left
= rcSubItem
.right
;
6383 rcSubItem
.right
+= LISTVIEW_GetColumnWidth(infoPtr
, j
);
6384 if (PtInRect(&rcSubItem
, lpInt
->ht
.pt
))
6386 lpInt
->ht
.iSubItem
= j
;
6396 * Now compute distance from point to center of boundary
6397 * box. Since we are only interested in the relative
6398 * distance, we can skip the nasty square root operation
6400 xterm
= rcItem
.left
+ (rcItem
.right
- rcItem
.left
)/2 - lpInt
->ht
.pt
.x
;
6401 yterm
= rcItem
.top
+ (rcItem
.bottom
- rcItem
.top
)/2 - lpInt
->ht
.pt
.y
;
6402 dist
= xterm
* xterm
+ yterm
* yterm
;
6403 if (dist
< lpInt
->distance
)
6405 lpInt
->distance
= dist
;
6406 lpInt
->iDistItem
= i
;
6412 lpInt
->ht
.flags
= LVHT_NOWHERE
;
6413 TRACE("no hit, closest item %d, distance %ld\n", lpInt
->iDistItem
, lpInt
->distance
);
6420 * Determines which section of the item was selected (if any).
6423 * [I] infoPtr : valid pointer to the listview structure
6424 * [IO] LPLVHITTESTINFO : hit test information
6425 * [I] subitem : fill out iSubItem.
6428 * SUCCESS : item index
6431 static INT
LISTVIEW_HitTestItem(LISTVIEW_INFO
*infoPtr
, LPLVHITTESTINFO lpHitTestInfo
, BOOL subitem
)
6434 LV_INTHIT lv_inthit
;
6436 TRACE("(x=%ld, y=%ld)\n", lpHitTestInfo
->pt
.x
,
6437 lpHitTestInfo
->pt
.y
);
6439 memcpy(&lv_inthit
, lpHitTestInfo
, sizeof(LVHITTESTINFO
));
6440 ret
= LISTVIEW_SuperHitTestItem(infoPtr
, &lv_inthit
, subitem
);
6441 memcpy(lpHitTestInfo
, &lv_inthit
, sizeof(LVHITTESTINFO
));
6447 * Determines which listview item is located at the specified position.
6450 * [I] infoPtr : valid pointer to the listview structure
6451 * [IO} LPLVHITTESTINFO : hit test information
6454 * SUCCESS : item index
6457 static LRESULT
LISTVIEW_HitTest(LISTVIEW_INFO
*infoPtr
, LPLVHITTESTINFO lpHitTestInfo
)
6461 lpHitTestInfo
->flags
= 0;
6463 if (infoPtr
->rcList
.left
> lpHitTestInfo
->pt
.x
)
6464 lpHitTestInfo
->flags
= LVHT_TOLEFT
;
6465 else if (infoPtr
->rcList
.right
< lpHitTestInfo
->pt
.x
)
6466 lpHitTestInfo
->flags
= LVHT_TORIGHT
;
6467 if (infoPtr
->rcList
.top
> lpHitTestInfo
->pt
.y
)
6468 lpHitTestInfo
->flags
|= LVHT_ABOVE
;
6469 else if (infoPtr
->rcList
.bottom
< lpHitTestInfo
->pt
.y
)
6470 lpHitTestInfo
->flags
|= LVHT_BELOW
;
6472 if (lpHitTestInfo
->flags
== 0)
6474 /* NOTE (mm 20001022): We must not allow iSubItem to be touched, for
6475 * an app might pass only a structure with space up to iItem!
6476 * (MS Office 97 does that for instance in the file open dialog)
6478 nItem
= LISTVIEW_HitTestItem(infoPtr
, lpHitTestInfo
, FALSE
);
6486 * Determines which listview subitem is located at the specified position.
6489 * [I] infoPtr : valid pointer to the listview structure
6490 * [IO} LPLVHITTESTINFO : hit test information
6493 * SUCCESS : item index
6496 static LRESULT
LISTVIEW_SubItemHitTest(LISTVIEW_INFO
*infoPtr
, LPLVHITTESTINFO lpHitTestInfo
)
6500 lpHitTestInfo
->flags
= 0;
6502 if (infoPtr
->rcList
.left
> lpHitTestInfo
->pt
.x
)
6503 lpHitTestInfo
->flags
= LVHT_TOLEFT
;
6504 else if (infoPtr
->rcList
.right
< lpHitTestInfo
->pt
.x
)
6505 lpHitTestInfo
->flags
= LVHT_TORIGHT
;
6506 if (infoPtr
->rcList
.top
> lpHitTestInfo
->pt
.y
)
6507 lpHitTestInfo
->flags
|= LVHT_ABOVE
;
6508 else if (infoPtr
->rcList
.bottom
< lpHitTestInfo
->pt
.y
)
6509 lpHitTestInfo
->flags
|= LVHT_BELOW
;
6511 if (lpHitTestInfo
->flags
== 0)
6512 nItem
= LISTVIEW_HitTestItem(infoPtr
, lpHitTestInfo
, TRUE
);
6519 * Inserts a new column.
6522 * [I] infoPtr : valid pointer to the listview structure
6523 * [I] INT : column index
6524 * [I] LPLVCOLUMNW : column information
6527 * SUCCESS : new column index
6530 static LRESULT
LISTVIEW_InsertColumnT(LISTVIEW_INFO
*infoPtr
, INT nColumn
,
6531 LPLVCOLUMNW lpColumn
, BOOL isW
)
6533 INT nNewColumn
= -1;
6536 TRACE("(nColumn=%d, lpColumn=%p)\n", nColumn
, lpColumn
);
6538 if (lpColumn
!= NULL
)
6540 /* initialize memory */
6541 ZeroMemory(&hdi
, sizeof(hdi
));
6543 if (lpColumn
->mask
& LVCF_FMT
)
6545 /* format member is valid */
6546 hdi
.mask
|= HDI_FORMAT
;
6548 /* set text alignment (leftmost column must be left-aligned) */
6551 hdi
.fmt
|= HDF_LEFT
;
6555 if (lpColumn
->fmt
& LVCFMT_LEFT
)
6557 hdi
.fmt
|= HDF_LEFT
;
6559 else if (lpColumn
->fmt
& LVCFMT_RIGHT
)
6561 hdi
.fmt
|= HDF_RIGHT
;
6563 else if (lpColumn
->fmt
& LVCFMT_CENTER
)
6565 hdi
.fmt
|= HDF_CENTER
;
6569 if (lpColumn
->fmt
& LVCFMT_BITMAP_ON_RIGHT
)
6571 hdi
.fmt
|= HDF_BITMAP_ON_RIGHT
;
6575 if (lpColumn
->fmt
& LVCFMT_COL_HAS_IMAGES
)
6580 if (lpColumn
->fmt
& LVCFMT_IMAGE
)
6582 hdi
.fmt
|= HDF_IMAGE
;
6583 hdi
.iImage
= I_IMAGECALLBACK
;
6587 if (lpColumn
->mask
& LVCF_WIDTH
)
6589 hdi
.mask
|= HDI_WIDTH
;
6590 if(lpColumn
->cx
== LVSCW_AUTOSIZE_USEHEADER
)
6592 /* make it fill the remainder of the controls width */
6597 ZeroMemory(&hdit
, sizeof(hdit
));
6599 /* get the width of every item except the current one */
6600 hdit
.mask
= HDI_WIDTH
;
6603 for(item_index
= 0; item_index
< (nColumn
- 1); item_index
++) {
6604 Header_GetItemW(infoPtr
->hwndHeader
, item_index
, (LPARAM
)(&hdit
));
6608 /* retrieve the layout of the header */
6609 GetClientRect(infoPtr
->hwndSelf
, &rcHeader
);
6610 /* GetWindowRect(infoPtr->hwndHeader, &rcHeader);*/
6611 TRACE("start cxy=%d left=%d right=%d\n", hdi
.cxy
, rcHeader
.left
, rcHeader
.right
);
6613 hdi
.cxy
= (rcHeader
.right
- rcHeader
.left
) - hdi
.cxy
;
6616 hdi
.cxy
= lpColumn
->cx
;
6619 if (lpColumn
->mask
& LVCF_TEXT
)
6621 hdi
.mask
|= HDI_TEXT
| HDI_FORMAT
;
6622 hdi
.pszText
= lpColumn
->pszText
;
6623 hdi
.cchTextMax
= textlenT(lpColumn
->pszText
, isW
);
6624 hdi
.fmt
|= HDF_STRING
;
6627 if (lpColumn
->mask
& LVCF_IMAGE
)
6629 hdi
.mask
|= HDI_IMAGE
;
6630 hdi
.iImage
= lpColumn
->iImage
;
6633 if (lpColumn
->mask
& LVCF_ORDER
)
6635 hdi
.mask
|= HDI_ORDER
;
6636 hdi
.iOrder
= lpColumn
->iOrder
;
6639 /* insert item in header control */
6640 nNewColumn
= SendMessageW(infoPtr
->hwndHeader
, HDM_INSERTITEMT(isW
),
6641 (WPARAM
)nColumn
, (LPARAM
)&hdi
);
6643 /* Need to reset the item width when inserting a new column */
6644 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(infoPtr
);
6646 LISTVIEW_UpdateScroll(infoPtr
);
6647 InvalidateRect(infoPtr
->hwndSelf
, NULL
, FALSE
);
6653 /* LISTVIEW_InsertCompare: callback routine for comparing pszText members of the LV_ITEMS
6654 in a LISTVIEW on insert. Passed to DPA_Sort in LISTVIEW_InsertItem.
6655 This function should only be used for inserting items into a sorted list (LVM_INSERTITEM)
6656 and not during the processing of a LVM_SORTITEMS message. Applications should provide
6657 their own sort proc. when sending LVM_SORTITEMS.
6660 (remarks on LVITEM: LVM_INSERTITEM will insert the new item in the proper sort postion...
6662 LVS_SORTXXX must be specified,
6663 LVS_OWNERDRAW is not set,
6664 <item>.pszText is not LPSTR_TEXTCALLBACK.
6666 (LVS_SORT* flags): "For the LVS_SORTASCENDING... styles, item indices
6667 are sorted based on item text..."
6669 static INT WINAPI
LISTVIEW_InsertCompare( LPVOID first
, LPVOID second
, LPARAM lParam
)
6671 LONG lStyle
= GetWindowLongW((HWND
) lParam
, GWL_STYLE
);
6672 LISTVIEW_ITEM
* lv_first
= (LISTVIEW_ITEM
*) DPA_GetPtr( (HDPA
)first
, 0 );
6673 LISTVIEW_ITEM
* lv_second
= (LISTVIEW_ITEM
*) DPA_GetPtr( (HDPA
)second
, 0 );
6674 INT cmpv
= lstrcmpW( lv_first
->pszText
, lv_second
->pszText
);
6675 /* if we're sorting descending, negate the return value */
6676 return (lStyle
& LVS_SORTDESCENDING
) ? -cmpv
: cmpv
;
6681 * Inserts a new item in the listview control.
6684 * [I] infoPtr : valid pointer to the listview structure
6685 * [I] LPLVITEMW : item information
6686 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
6689 * SUCCESS : new item index
6692 static LRESULT
LISTVIEW_InsertItemT(LISTVIEW_INFO
*infoPtr
, LPLVITEMW lpLVItem
, BOOL isW
)
6694 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
6695 UINT uView
= lStyle
& LVS_TYPEMASK
;
6699 LISTVIEW_ITEM
*lpItem
= NULL
;
6701 TRACE("(lpLVItem=%s, isW=%d)\n",
6702 debuglvitem_t(lpLVItem
, isW
), isW
);
6704 if (lStyle
& LVS_OWNERDATA
)
6706 nItem
= infoPtr
->hdpaItems
->nItemCount
;
6707 infoPtr
->hdpaItems
->nItemCount
++;
6711 if (lpLVItem
!= NULL
)
6713 /* make sure it's not a subitem; cannot insert a subitem */
6714 if (lpLVItem
->iSubItem
== 0)
6716 if ( (lpItem
= (LISTVIEW_ITEM
*)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM
))) )
6718 ZeroMemory(lpItem
, sizeof(LISTVIEW_ITEM
));
6719 if (LISTVIEW_InitItemT(infoPtr
, lpItem
, lpLVItem
, isW
))
6721 /* insert item in listview control data structure */
6722 if ( (hdpaSubItems
= DPA_Create(8)) )
6724 if ( (nItem
= DPA_InsertPtr(hdpaSubItems
, 0, lpItem
)) != -1)
6726 if ( ((lStyle
& LVS_SORTASCENDING
) || (lStyle
& LVS_SORTDESCENDING
))
6727 && !(lStyle
& LVS_OWNERDRAWFIXED
)
6728 && (LPSTR_TEXTCALLBACKW
!= lpLVItem
->pszText
) )
6730 /* Insert the item in the proper sort order based on the pszText
6731 member. See comments for LISTVIEW_InsertCompare() for greater detail */
6732 nItem
= DPA_InsertPtr( infoPtr
->hdpaItems
,
6733 GETITEMCOUNT( infoPtr
) + 1, hdpaSubItems
);
6734 DPA_Sort( infoPtr
->hdpaItems
, LISTVIEW_InsertCompare
, (LPARAM
)infoPtr
->hwndSelf
);
6735 nItem
= DPA_GetPtrIndex( infoPtr
->hdpaItems
, hdpaSubItems
);
6739 nItem
= DPA_InsertPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
,
6746 LISTVIEW_ShiftIndices(infoPtr
,nItem
,1);
6748 /* manage item focus */
6749 if (lpLVItem
->mask
& LVIF_STATE
)
6751 lpItem
->state
&= ~(LVIS_FOCUSED
|LVIS_SELECTED
);
6752 if (lpLVItem
->stateMask
& LVIS_SELECTED
)
6753 LISTVIEW_SetSelection(infoPtr
, nItem
);
6754 else if (lpLVItem
->stateMask
& LVIS_FOCUSED
)
6755 LISTVIEW_SetItemFocus(infoPtr
, nItem
);
6758 /* send LVN_INSERTITEM notification */
6759 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
6761 nmlv
.lParam
= lpItem
->lParam
;
6762 listview_notify(infoPtr
, LVN_INSERTITEM
, &nmlv
);
6764 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_LIST
))
6766 nItemWidth
= LISTVIEW_CalculateWidth(infoPtr
, lpLVItem
->iItem
);
6767 if (nItemWidth
> infoPtr
->nItemWidth
)
6768 infoPtr
->nItemWidth
= nItemWidth
;
6771 /* align items (set position of each item) */
6772 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
6774 if (lStyle
& LVS_ALIGNLEFT
)
6775 LISTVIEW_AlignLeft(infoPtr
);
6777 LISTVIEW_AlignTop(infoPtr
);
6780 LISTVIEW_UpdateScroll(infoPtr
);
6781 /* refresh client area */
6782 InvalidateRect(infoPtr
->hwndSelf
, NULL
, FALSE
);
6791 /* free memory if unsuccessful */
6792 if ((nItem
== -1) && (lpItem
!= NULL
))
6793 COMCTL32_Free(lpItem
);
6800 * Redraws a range of items.
6803 * [I] infoPtr : valid pointer to the listview structure
6804 * [I] INT : first item
6805 * [I] INT : last item
6811 static LRESULT
LISTVIEW_RedrawItems(LISTVIEW_INFO
*infoPtr
, INT nFirst
, INT nLast
)
6813 BOOL bResult
= FALSE
;
6817 if (nFirst
<= nLast
)
6819 if ((nFirst
>= 0) && (nFirst
< GETITEMCOUNT(infoPtr
)))
6821 if ((nLast
>= 0) && (nLast
< GETITEMCOUNT(infoPtr
)))
6823 for (i
= nFirst
; i
<= nLast
; i
++)
6825 rcItem
.left
= LVIR_BOUNDS
;
6826 LISTVIEW_GetItemRect(infoPtr
, i
, &rcItem
);
6827 InvalidateRect(infoPtr
->hwndSelf
, &rcItem
, TRUE
);
6838 * Scroll the content of a listview.
6841 * [I] infoPtr : valid pointer to the listview structure
6842 * [I] INT : horizontal scroll amount in pixels
6843 * [I] INT : vertical scroll amount in pixels
6850 * If the control is in report mode (LVS_REPORT) the control can
6851 * be scrolled only in line increments. "dy" will be rounded to the
6852 * nearest number of pixels that are a whole line. Ex: if line height
6853 * is 16 and an 8 is passed, the list will be scrolled by 16. If a 7
6854 * is passed the the scroll will be 0. (per MSDN 7/2002)
6856 * For: (per experimentaion with native control and CSpy ListView)
6857 * LVS_ICON dy=1 = 1 pixel (vertical only)
6859 * LVS_SMALLICON dy=1 = 1 pixel (vertical only)
6861 * LVS_LIST dx=1 = 1 column (horizontal only)
6862 * but will only scroll 1 column per message
6863 * no matter what the value.
6864 * dy must be 0 or FALSE returned.
6865 * LVS_REPORT dx=1 = 1 pixel
6869 static LRESULT
LISTVIEW_Scroll(LISTVIEW_INFO
*infoPtr
, INT dx
, INT dy
)
6871 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
6872 UINT uView
= lStyle
& LVS_TYPEMASK
;
6875 if (uView
== LVS_REPORT
)
6877 rows
= (abs(dy
) + infoPtr
->nItemHeight
/2) / infoPtr
->nItemHeight
;
6880 mode
= (dy
>0) ? SB_INTERNAL_DOWN
: SB_INTERNAL_UP
;
6881 for ( i
=0; i
<rows
; i
++)
6882 LISTVIEW_VScroll(infoPtr
, mode
, 0, 0);
6887 mode
= (dx
>0) ? SB_INTERNAL_RIGHT
: SB_INTERNAL_LEFT
;
6888 for ( i
=0; i
<abs(dx
); i
++)
6889 LISTVIEW_HScroll(infoPtr
, mode
, 0, 0);
6893 else if (uView
== LVS_ICON
)
6897 mode
= (dy
>0) ? SB_INTERNAL_DOWN
: SB_INTERNAL_UP
;
6898 for(i
=0; i
<abs(dy
); i
++)
6899 LISTVIEW_VScroll(infoPtr
, mode
, 0, 0);
6902 else if (uView
== LVS_SMALLICON
)
6906 mode
= (dy
>0) ? SB_INTERNAL_DOWN
: SB_INTERNAL_UP
;
6907 for(i
=0; i
<abs(dy
); i
++)
6908 LISTVIEW_VScroll(infoPtr
, mode
, 0, 0);
6911 else if (uView
== LVS_LIST
)
6913 if (dy
!= 0) return FALSE
;
6914 if (dx
== 0) return TRUE
;
6915 mode
= (dx
>0) ? SB_INTERNAL_RIGHT
: SB_INTERNAL_LEFT
;
6916 LISTVIEW_HScroll(infoPtr
, mode
, 0, 0);
6924 * Sets the background color.
6927 * [I] infoPtr : valid pointer to the listview structure
6928 * [I] COLORREF : background color
6934 static LRESULT
LISTVIEW_SetBkColor(LISTVIEW_INFO
*infoPtr
, COLORREF clrBk
)
6936 if(infoPtr
->clrBk
!=clrBk
){
6937 infoPtr
->clrBk
= clrBk
;
6938 InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
);
6944 /* LISTVIEW_SetBkImage */
6948 * Sets the callback mask. This mask will be used when the parent
6949 * window stores state information (some or all).
6952 * [I] infoPtr : valid pointer to the listview structure
6953 * [I] UINT : state mask
6959 static BOOL
LISTVIEW_SetCallbackMask(LISTVIEW_INFO
*infoPtr
, UINT uMask
)
6961 infoPtr
->uCallbackMask
= uMask
;
6968 * Sets the attributes of a header item.
6971 * [I] infoPtr : valid pointer to the listview structure
6972 * [I] INT : column index
6973 * [I] LPLVCOLUMNW : column attributes
6974 * [I] isW: if TRUE, the lpColumn is a LPLVCOLUMNW,
6975 * otherwise it is in fact a LPLVCOLUMNA
6981 static LRESULT
LISTVIEW_SetColumnT(LISTVIEW_INFO
*infoPtr
, INT nColumn
,
6982 LPLVCOLUMNW lpColumn
, BOOL isW
)
6984 BOOL bResult
= FALSE
;
6985 HDITEMW hdi
, hdiget
;
6987 if ((lpColumn
!= NULL
) && (nColumn
>= 0) &&
6988 (nColumn
< Header_GetItemCount(infoPtr
->hwndHeader
)))
6990 /* initialize memory */
6991 ZeroMemory(&hdi
, sizeof(hdi
));
6993 if (lpColumn
->mask
& LVCF_FMT
)
6995 /* format member is valid */
6996 hdi
.mask
|= HDI_FORMAT
;
6998 /* get current format first */
6999 hdiget
.mask
= HDI_FORMAT
;
7000 if (Header_GetItemW(infoPtr
->hwndHeader
, nColumn
, &hdiget
))
7001 /* preserve HDF_STRING if present */
7002 hdi
.fmt
= hdiget
.fmt
& HDF_STRING
;
7004 /* set text alignment (leftmost column must be left-aligned) */
7007 hdi
.fmt
|= HDF_LEFT
;
7011 if (lpColumn
->fmt
& LVCFMT_LEFT
)
7012 hdi
.fmt
|= HDF_LEFT
;
7013 else if (lpColumn
->fmt
& LVCFMT_RIGHT
)
7014 hdi
.fmt
|= HDF_RIGHT
;
7015 else if (lpColumn
->fmt
& LVCFMT_CENTER
)
7016 hdi
.fmt
|= HDF_CENTER
;
7019 if (lpColumn
->fmt
& LVCFMT_BITMAP_ON_RIGHT
)
7020 hdi
.fmt
|= HDF_BITMAP_ON_RIGHT
;
7022 if (lpColumn
->fmt
& LVCFMT_COL_HAS_IMAGES
)
7023 hdi
.fmt
|= HDF_IMAGE
;
7025 if (lpColumn
->fmt
& LVCFMT_IMAGE
)
7027 hdi
.fmt
|= HDF_IMAGE
;
7028 hdi
.iImage
= I_IMAGECALLBACK
;
7032 if (lpColumn
->mask
& LVCF_WIDTH
)
7034 hdi
.mask
|= HDI_WIDTH
;
7035 hdi
.cxy
= lpColumn
->cx
;
7038 if (lpColumn
->mask
& LVCF_TEXT
)
7040 hdi
.mask
|= HDI_TEXT
| HDI_FORMAT
;
7041 hdi
.pszText
= lpColumn
->pszText
;
7042 hdi
.cchTextMax
= textlenT(lpColumn
->pszText
, isW
);
7043 hdi
.fmt
|= HDF_STRING
;
7046 if (lpColumn
->mask
& LVCF_IMAGE
)
7048 hdi
.mask
|= HDI_IMAGE
;
7049 hdi
.iImage
= lpColumn
->iImage
;
7052 if (lpColumn
->mask
& LVCF_ORDER
)
7054 hdi
.mask
|= HDI_ORDER
;
7055 hdi
.iOrder
= lpColumn
->iOrder
;
7058 /* set header item attributes */
7060 bResult
= Header_SetItemW(infoPtr
->hwndHeader
, nColumn
, &hdi
);
7062 bResult
= Header_SetItemA(infoPtr
->hwndHeader
, nColumn
, &hdi
);
7070 * Sets the column order array
7073 * [I] infoPtr : valid pointer to the listview structure
7074 * [I] INT : number of elements in column order array
7075 * [I] INT : pointer to column order array
7081 static LRESULT
LISTVIEW_SetColumnOrderArray(LISTVIEW_INFO
*infoPtr
, INT iCount
, LPINT lpiArray
)
7083 FIXME("iCount %d lpiArray %p\n", iCount
, lpiArray
);
7094 * Sets the width of a column
7097 * [I] infoPtr : valid pointer to the listview structure
7098 * [I] INT : column index
7099 * [I] INT : column width
7105 static LRESULT
LISTVIEW_SetColumnWidth(LISTVIEW_INFO
*infoPtr
, INT iCol
, INT cx
)
7109 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
7110 UINT uView
= lStyle
& LVS_TYPEMASK
;
7115 WCHAR text_buffer
[DISP_TEXT_SIZE
];
7116 INT header_item_count
;
7121 WCHAR szDispText
[DISP_TEXT_SIZE
];
7123 if (!infoPtr
->hwndHeader
) /* make sure we have a header */
7126 /* set column width only if in report or list mode */
7127 if ((uView
!= LVS_REPORT
) && (uView
!= LVS_LIST
))
7130 TRACE("(iCol=%d, cx=%d\n", iCol
, cx
);
7132 /* take care of invalid cx values */
7133 if((uView
== LVS_REPORT
) && (cx
< -2))
7134 cx
= LVSCW_AUTOSIZE
;
7135 else if (uView
== LVS_LIST
&& (cx
< 1))
7138 /* resize all columns if in LVS_LIST mode */
7139 if(uView
== LVS_LIST
) {
7140 infoPtr
->nItemWidth
= cx
;
7141 InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
); /* force redraw of the listview */
7145 /* autosize based on listview items width */
7146 if(cx
== LVSCW_AUTOSIZE
)
7148 /* set the width of the column to the width of the widest item */
7149 if (iCol
== 0 || uView
== LVS_LIST
)
7152 for(item_index
= 0; item_index
< GETITEMCOUNT(infoPtr
); item_index
++)
7154 nLabelWidth
= LISTVIEW_GetLabelWidth(infoPtr
, item_index
);
7155 cx
= (nLabelWidth
>cx
)?nLabelWidth
:cx
;
7157 if (infoPtr
->himlSmall
)
7158 cx
+= infoPtr
->iconSize
.cx
+ IMAGE_PADDING
;
7162 ZeroMemory(&lvItem
, sizeof(lvItem
));
7163 lvItem
.iSubItem
= iCol
;
7164 lvItem
.mask
= LVIF_TEXT
;
7165 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
7166 lvItem
.pszText
= szDispText
;
7167 *lvItem
.pszText
= '\0';
7169 for(item_index
= 0; item_index
< GETITEMCOUNT(infoPtr
); item_index
++)
7171 lvItem
.iItem
= item_index
;
7172 LISTVIEW_GetItemT(infoPtr
, &lvItem
, FALSE
, TRUE
);
7173 nLabelWidth
= LISTVIEW_GetStringWidthT(infoPtr
, lvItem
.pszText
, TRUE
);
7174 cx
= (nLabelWidth
>cx
)?nLabelWidth
:cx
;
7177 cx
+= TRAILING_PADDING
;
7178 } /* autosize based on listview header width */
7179 else if(cx
== LVSCW_AUTOSIZE_USEHEADER
)
7181 header_item_count
= Header_GetItemCount(infoPtr
->hwndHeader
);
7183 /* if iCol is the last column make it fill the remainder of the controls width */
7184 if(iCol
== (header_item_count
- 1)) {
7185 /* get the width of every item except the current one */
7186 hdi
.mask
= HDI_WIDTH
;
7189 for(item_index
= 0; item_index
< (header_item_count
- 1); item_index
++) {
7190 Header_GetItemW(infoPtr
->hwndHeader
, item_index
, (LPARAM
)(&hdi
));
7194 /* retrieve the layout of the header */
7195 GetWindowRect(infoPtr
->hwndHeader
, &rcHeader
);
7197 cx
= (rcHeader
.right
- rcHeader
.left
) - cx
;
7201 /* Despite what the MS docs say, if this is not the last
7202 column, then MS resizes the column to the width of the
7203 largest text string in the column, including headers
7204 and items. This is different from LVSCW_AUTOSIZE in that
7205 LVSCW_AUTOSIZE ignores the header string length.
7208 /* retrieve header font */
7209 header_font
= SendMessageW(infoPtr
->hwndHeader
, WM_GETFONT
, 0L, 0L);
7211 /* retrieve header text */
7212 hdi
.mask
= HDI_TEXT
;
7213 hdi
.cchTextMax
= sizeof(text_buffer
)/sizeof(text_buffer
[0]);
7214 hdi
.pszText
= text_buffer
;
7216 Header_GetItemW(infoPtr
->hwndHeader
, iCol
, (LPARAM
)(&hdi
));
7218 /* determine the width of the text in the header */
7219 hdc
= GetDC(infoPtr
->hwndSelf
);
7220 old_font
= SelectObject(hdc
, header_font
); /* select the font into hdc */
7222 GetTextExtentPoint32W(hdc
, text_buffer
, lstrlenW(text_buffer
), &size
);
7224 SelectObject(hdc
, old_font
); /* restore the old font */
7225 ReleaseDC(infoPtr
->hwndSelf
, hdc
);
7227 ZeroMemory(&lvItem
, sizeof(lvItem
));
7228 lvItem
.iSubItem
= iCol
;
7229 lvItem
.mask
= LVIF_TEXT
;
7230 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
7231 lvItem
.pszText
= szDispText
;
7232 *lvItem
.pszText
= '\0';
7234 for(item_index
= 0; item_index
< GETITEMCOUNT(infoPtr
); item_index
++)
7236 lvItem
.iItem
= item_index
;
7237 LISTVIEW_GetItemT(infoPtr
, &lvItem
, FALSE
, TRUE
);
7238 nLabelWidth
= LISTVIEW_GetStringWidthT(infoPtr
, lvItem
.pszText
, TRUE
);
7239 nLabelWidth
+= TRAILING_PADDING
;
7240 /* While it is possible for subitems to have icons, even MS messes
7241 up the positioning, so I suspect no applications actually use
7243 if (item_index
== 0 && infoPtr
->himlSmall
)
7244 nLabelWidth
+= infoPtr
->iconSize
.cx
+ IMAGE_PADDING
;
7245 cx
= (nLabelWidth
>cx
)?nLabelWidth
:cx
;
7250 /* call header to update the column change */
7251 hdi
.mask
= HDI_WIDTH
;
7254 lret
= Header_SetItemW(infoPtr
->hwndHeader
, (WPARAM
)iCol
, (LPARAM
)&hdi
);
7256 InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
); /* force redraw of the listview */
7263 * Sets the extended listview style.
7266 * [I] infoPtr : valid pointer to the listview structure
7271 * SUCCESS : previous style
7274 static LRESULT
LISTVIEW_SetExtendedListViewStyle(LISTVIEW_INFO
*infoPtr
, DWORD dwMask
, DWORD dwStyle
)
7276 DWORD dwOldStyle
= infoPtr
->dwExStyle
;
7280 infoPtr
->dwExStyle
= (dwOldStyle
& ~dwMask
) | (dwStyle
& dwMask
);
7282 infoPtr
->dwExStyle
= dwStyle
;
7289 * Sets the new hot cursor used during hot tracking and hover selection.
7292 * [I] infoPtr : valid pointer to the listview structure
7293 * [I} hCurosr : the new hot cursor handle
7296 * Returns the previous hot cursor
7298 static HCURSOR
LISTVIEW_SetHotCursor(LISTVIEW_INFO
*infoPtr
, HCURSOR hCursor
)
7300 HCURSOR oldCursor
= infoPtr
->hHotCursor
;
7301 infoPtr
->hHotCursor
= hCursor
;
7308 * Sets the hot item index.
7311 * [I] infoPtr : valid pointer to the listview structure
7315 * SUCCESS : previous hot item index
7316 * FAILURE : -1 (no hot item)
7318 static LRESULT
LISTVIEW_SetHotItem(LISTVIEW_INFO
*infoPtr
, INT iIndex
)
7320 INT iOldIndex
= infoPtr
->nHotItem
;
7323 infoPtr
->nHotItem
= iIndex
;
7331 * Sets the amount of time the cursor must hover over an item before it is selected.
7334 * [I] infoPtr : valid pointer to the listview structure
7335 * [I] DWORD : dwHoverTime, if -1 the hover time is set to the default
7338 * Returns the previous hover time
7340 static LRESULT
LISTVIEW_SetHoverTime(LISTVIEW_INFO
*infoPtr
, DWORD dwHoverTime
)
7342 DWORD oldHoverTime
= infoPtr
->dwHoverTime
;
7344 infoPtr
->dwHoverTime
= dwHoverTime
;
7346 return oldHoverTime
;
7351 * Sets spacing for icons of LVS_ICON style.
7354 * [I] infoPtr : valid pointer to the listview structure
7355 * [I] DWORD : MAKELONG(cx, cy)
7358 * MAKELONG(oldcx, oldcy)
7360 static LRESULT
LISTVIEW_SetIconSpacing(LISTVIEW_INFO
*infoPtr
, DWORD spacing
)
7362 INT cy
= HIWORD(spacing
);
7363 INT cx
= LOWORD(spacing
);
7365 LONG lStyle
= GetWindowLongA(infoPtr
->hwndSelf
, GWL_STYLE
);
7366 UINT uView
= lStyle
& LVS_TYPEMASK
;
7368 oldspacing
= MAKELONG(infoPtr
->iconSpacing
.cx
, infoPtr
->iconSpacing
.cy
);
7369 if (cx
== -1) /* set to default */
7370 cx
= GetSystemMetrics(SM_CXICONSPACING
);
7371 if (cy
== -1) /* set to default */
7372 cy
= GetSystemMetrics(SM_CYICONSPACING
);
7375 infoPtr
->iconSpacing
.cx
= cx
;
7377 { /* if 0 then compute width */
7378 if (uView
== LVS_ICON
)
7379 FIXME("width computation not yet done\n");
7381 * Should scan each item and determine max width of
7382 * icon or label, then make that the width
7384 else /* FIXME: unknown computation for non LVS_ICON - this is a guess */
7385 infoPtr
->iconSpacing
.cx
= LISTVIEW_GetItemWidth(infoPtr
);
7388 infoPtr
->iconSpacing
.cy
= cy
;
7390 { /* if 0 then compute height */
7391 if (uView
== LVS_ICON
)
7392 infoPtr
->iconSpacing
.cy
= infoPtr
->iconSize
.cy
+ 2 * infoPtr
->ntmHeight
7393 + ICON_BOTTOM_PADDING
+ ICON_TOP_PADDING
+ LABEL_VERT_OFFSET
;
7394 /* FIXME. I don't think so; I think it is based on twice the ntmHeight */
7395 else /* FIXME: unknown computation for non LVS_ICON - this is a guess */
7396 infoPtr
->iconSpacing
.cy
= LISTVIEW_GetItemHeight(infoPtr
);
7399 TRACE("old=(%d,%d), new=(%ld,%ld), iconSize=(%ld,%ld), ntmH=%d\n",
7400 LOWORD(oldspacing
), HIWORD(oldspacing
),
7401 infoPtr
->iconSpacing
.cx
, infoPtr
->iconSpacing
.cy
,
7402 infoPtr
->iconSize
.cx
, infoPtr
->iconSize
.cy
,
7403 infoPtr
->ntmHeight
);
7405 /* these depend on the iconSpacing */
7406 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(infoPtr
);
7407 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(infoPtr
);
7417 * [I] infoPtr : valid pointer to the listview structure
7418 * [I] INT : image list type
7419 * [I] HIMAGELIST : image list handle
7422 * SUCCESS : old image list
7425 static HIMAGELIST
LISTVIEW_SetImageList(LISTVIEW_INFO
*infoPtr
, INT nType
, HIMAGELIST himl
)
7427 HIMAGELIST himlOld
= 0;
7429 UINT uView
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
7434 himlOld
= infoPtr
->himlNormal
;
7435 infoPtr
->himlNormal
= himl
;
7436 if(himl
&& (LVS_ICON
== uView
))
7439 ImageList_GetIconSize(himl
, &cx
, &cy
);
7440 TRACE("icon old size=(%ld,%ld), new size=(%d,%d)\n",
7441 infoPtr
->iconSize
.cx
, infoPtr
->iconSize
.cy
, cx
, cy
);
7442 infoPtr
->iconSize
.cx
= cx
;
7443 infoPtr
->iconSize
.cy
= cy
;
7444 LISTVIEW_SetIconSpacing(infoPtr
,0);
7449 himlOld
= infoPtr
->himlSmall
;
7450 infoPtr
->himlSmall
= himl
;
7454 himlOld
= infoPtr
->himlState
;
7455 infoPtr
->himlState
= himl
;
7456 ImageList_SetBkColor(infoPtr
->himlState
, CLR_NONE
);
7460 oldHeight
= infoPtr
->nItemHeight
;
7461 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(infoPtr
);
7462 if (infoPtr
->nItemHeight
!= oldHeight
)
7463 LISTVIEW_UpdateScroll(infoPtr
);
7470 * Preallocates memory (does *not* set the actual count of items !)
7473 * [I] infoPtr : valid pointer to the listview structure
7474 * [I] INT : item count (projected number of items to allocate)
7475 * [I] DWORD : update flags
7481 static BOOL
LISTVIEW_SetItemCount(LISTVIEW_INFO
*infoPtr
, INT nItems
, DWORD dwFlags
)
7483 TRACE("(nItems=%d, dwFlags=%lx)\n", nItems
, dwFlags
);
7485 if (GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_OWNERDATA
)
7487 int precount
,topvisible
;
7489 TRACE("LVS_OWNERDATA is set!\n");
7490 if (dwFlags
& (LVSICF_NOINVALIDATEALL
| LVSICF_NOSCROLL
))
7491 FIXME("flags %s %s not implemented\n",
7492 (dwFlags
& LVSICF_NOINVALIDATEALL
) ? "LVSICF_NOINVALIDATEALL"
7494 (dwFlags
& LVSICF_NOSCROLL
) ? "LVSICF_NOSCROLL" : "");
7497 * Internally remove all the selections.
7501 LISTVIEW_SELECTION
*selection
;
7502 selection
= DPA_GetPtr(infoPtr
->hdpaSelectionRanges
,0);
7504 LISTVIEW_RemoveSelectionRange(infoPtr
,selection
->lower
,
7507 while (infoPtr
->hdpaSelectionRanges
->nItemCount
>0);
7509 precount
= infoPtr
->hdpaItems
->nItemCount
;
7510 topvisible
= ListView_GetTopIndex(infoPtr
->hwndSelf
) +
7511 LISTVIEW_GetCountPerColumn(infoPtr
) + 1;
7513 infoPtr
->hdpaItems
->nItemCount
= nItems
;
7515 infoPtr
->nItemWidth
= max(LISTVIEW_GetItemWidth(infoPtr
),
7516 DEFAULT_COLUMN_WIDTH
);
7518 LISTVIEW_UpdateSize(infoPtr
);
7519 LISTVIEW_UpdateScroll(infoPtr
);
7521 if (min(precount
,infoPtr
->hdpaItems
->nItemCount
)<topvisible
)
7522 InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
);
7526 /* According to MSDN for non-LVS_OWNERDATA this is just
7527 * a performance issue. The control allocates its internal
7528 * data structures for the number of items specified. It
7529 * cuts down on the number of memory allocations. Therefore
7530 * we will just issue a WARN here
7532 WARN("for non-ownerdata performance option not implemented.\n");
7540 * Sets the position of an item.
7543 * [I] infoPtr : valid pointer to the listview structure
7544 * [I] INT : item index
7545 * [I] LONG : x coordinate
7546 * [I] LONG : y coordinate
7552 static BOOL
LISTVIEW_SetItemPosition(LISTVIEW_INFO
*infoPtr
, INT nItem
,
7553 LONG nPosX
, LONG nPosY
)
7555 UINT lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
7556 UINT uView
= lStyle
& LVS_TYPEMASK
;
7557 LISTVIEW_ITEM
*lpItem
;
7559 BOOL bResult
= FALSE
;
7561 TRACE("(nItem=%d, X=%ld, Y=%ld)\n", nItem
, nPosX
, nPosY
);
7563 if (lStyle
& LVS_OWNERDATA
)
7566 if ((nItem
>= 0) || (nItem
< GETITEMCOUNT(infoPtr
)))
7568 if ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
))
7570 if ( (hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
)) )
7572 if ( (lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0)) )
7576 orig
= lpItem
->ptPosition
;
7577 if ((nPosX
== -1) && (nPosY
== -1))
7579 /* This point value seems to be an undocumented feature. The
7580 * best guess is that it means either at the origin, or at
7581 * the true beginning of the list. I will assume the origin.
7584 if (!LISTVIEW_GetOrigin(infoPtr
, &pt1
))
7591 if (uView
== LVS_ICON
)
7593 nPosX
+= (infoPtr
->iconSpacing
.cx
- infoPtr
->iconSize
.cx
) / 2;
7594 nPosY
+= ICON_TOP_PADDING
;
7596 TRACE("requested special (-1,-1), set to origin (%ld,%ld)\n",
7600 lpItem
->ptPosition
.x
= nPosX
;
7601 lpItem
->ptPosition
.y
= nPosY
;
7602 if (uView
== LVS_ICON
)
7604 lpItem
->ptPosition
.y
-= ICON_TOP_PADDING
;
7605 lpItem
->ptPosition
.x
-= (infoPtr
->iconSpacing
.cx
- infoPtr
->iconSize
.cx
) / 2;
7606 if ((lpItem
->ptPosition
.y
< 0) || (lpItem
->ptPosition
.x
< 0))
7608 FIXME("failed orig (%ld,%ld), intent (%ld,%ld), is (%ld, %ld), setting neg to 0\n",
7609 orig
.x
, orig
.y
, nPosX
, nPosY
, lpItem
->ptPosition
.x
, lpItem
->ptPosition
.y
);
7612 if (lpItem->ptPosition.x < 0) lpItem->ptPosition.x = 0;
7613 if (lpItem->ptPosition.y < 0) lpItem->ptPosition.y = 0;
7618 TRACE("orig (%ld,%ld), intent (%ld,%ld), is (%ld,%ld)\n",
7619 orig
.x
, orig
.y
, nPosX
, nPosY
, lpItem
->ptPosition
.x
, lpItem
->ptPosition
.y
);
7632 * Sets the state of one or many items.
7635 * [I] infoPtr : valid pointer to the listview structure
7636 * [I]INT : item index
7637 * [I] LPLVITEM : item or subitem info
7643 static LRESULT
LISTVIEW_SetItemState(LISTVIEW_INFO
*infoPtr
, INT nItem
, LPLVITEMW lpLVItem
)
7645 BOOL bResult
= TRUE
;
7648 TRACE("(nItem=%d, lpLVItem=%s)\n",
7649 nItem
, debuglvitem_t(lpLVItem
, TRUE
));
7651 ZeroMemory(&lvItem
, sizeof(lvItem
));
7652 lvItem
.mask
= LVIF_STATE
;
7653 lvItem
.state
= lpLVItem
->state
;
7654 lvItem
.stateMask
= lpLVItem
->stateMask
;
7655 lvItem
.iItem
= nItem
;
7659 /* apply to all items */
7660 for (lvItem
.iItem
= 0; lvItem
.iItem
< GETITEMCOUNT(infoPtr
); lvItem
.iItem
++)
7661 if (!LISTVIEW_SetItemT(infoPtr
, &lvItem
, TRUE
)) bResult
= FALSE
;
7664 bResult
= LISTVIEW_SetItemT(infoPtr
, &lvItem
, TRUE
);
7671 * Sets the text of an item or subitem.
7674 * [I] hwnd : window handle
7675 * [I] nItem : item index
7676 * [I] lpLVItem : item or subitem info
7677 * [I] isW : TRUE if input is Unicode
7683 static BOOL
LISTVIEW_SetItemTextT(LISTVIEW_INFO
*infoPtr
, INT nItem
, LPLVITEMW lpLVItem
, BOOL isW
)
7685 BOOL bResult
= FALSE
;
7688 TRACE("(nItem=%d, lpLVItem=%s, isW=%d)\n",
7689 nItem
, debuglvitem_t(lpLVItem
, isW
), isW
);
7691 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
7693 ZeroMemory(&lvItem
, sizeof(LVITEMW
));
7694 lvItem
.mask
= LVIF_TEXT
;
7695 lvItem
.pszText
= lpLVItem
->pszText
;
7696 lvItem
.iItem
= nItem
;
7697 lvItem
.iSubItem
= lpLVItem
->iSubItem
;
7698 if(isW
) bResult
= ListView_SetItemW(infoPtr
->hwndSelf
, &lvItem
);
7699 else bResult
= ListView_SetItemA(infoPtr
->hwndSelf
, &lvItem
);
7707 * Set item index that marks the start of a multiple selection.
7710 * [I] infoPtr : valid pointer to the listview structure
7714 * Index number or -1 if there is no selection mark.
7716 static LRESULT
LISTVIEW_SetSelectionMark(LISTVIEW_INFO
*infoPtr
, INT nIndex
)
7718 INT nOldIndex
= infoPtr
->nSelectionMark
;
7720 TRACE("(nIndex=%d)\n", nIndex
);
7722 infoPtr
->nSelectionMark
= nIndex
;
7729 * Sets the text background color.
7732 * [I] infoPtr : valid pointer to the listview structure
7733 * [I] COLORREF : text background color
7739 static LRESULT
LISTVIEW_SetTextBkColor(LISTVIEW_INFO
*infoPtr
, COLORREF clrTextBk
)
7741 TRACE("(clrTextBk=%lx)\n", clrTextBk
);
7743 infoPtr
->clrTextBk
= clrTextBk
;
7744 InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
);
7751 * Sets the text foreground color.
7754 * [I] infoPtr : valid pointer to the listview structure
7755 * [I] COLORREF : text color
7761 static LRESULT
LISTVIEW_SetTextColor (LISTVIEW_INFO
*infoPtr
, COLORREF clrText
)
7763 TRACE("(clrText=%lx)\n", clrText
);
7765 infoPtr
->clrText
= clrText
;
7766 InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
);
7771 /* LISTVIEW_SetToolTips */
7772 /* LISTVIEW_SetUnicodeFormat */
7773 /* LISTVIEW_SetWorkAreas */
7777 * Callback internally used by LISTVIEW_SortItems()
7780 * [I] LPVOID : first LISTVIEW_ITEM to compare
7781 * [I] LPVOID : second LISTVIEW_ITEM to compare
7782 * [I] LPARAM : HWND of control
7785 * if first comes before second : negative
7786 * if first comes after second : positive
7787 * if first and second are equivalent : zero
7789 static INT WINAPI
LISTVIEW_CallBackCompare(LPVOID first
, LPVOID second
, LPARAM lParam
)
7791 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW((HWND
)lParam
, 0);
7792 LISTVIEW_ITEM
* lv_first
= (LISTVIEW_ITEM
*) DPA_GetPtr( (HDPA
)first
, 0 );
7793 LISTVIEW_ITEM
* lv_second
= (LISTVIEW_ITEM
*) DPA_GetPtr( (HDPA
)second
, 0 );
7795 /* Forward the call to the client defined callback */
7796 return (infoPtr
->pfnCompare
)( lv_first
->lParam
, lv_second
->lParam
, infoPtr
->lParamSort
);
7801 * Sorts the listview items.
7804 * [I] infoPtr : valid pointer to the listview structure
7805 * [I] WPARAM : application-defined value
7806 * [I] LPARAM : pointer to comparision callback
7812 static LRESULT
LISTVIEW_SortItems(LISTVIEW_INFO
*infoPtr
, PFNLVCOMPARE pfnCompare
, LPARAM lParamSort
)
7814 UINT lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
7815 HDPA hdpaSubItems
=NULL
;
7816 LISTVIEW_ITEM
*pLVItem
=NULL
;
7817 LPVOID selectionMarkItem
;
7820 TRACE("(pfnCompare=%p, lParamSort=%lx)\n", pfnCompare
, lParamSort
);
7822 if (lStyle
& LVS_OWNERDATA
) return FALSE
;
7824 if (!infoPtr
|| !infoPtr
->hdpaItems
) return FALSE
;
7826 nCount
= GETITEMCOUNT(infoPtr
);
7827 /* if there are 0 or 1 items, there is no need to sort */
7831 infoPtr
->pfnCompare
= pfnCompare
;
7832 infoPtr
->lParamSort
= lParamSort
;
7833 DPA_Sort(infoPtr
->hdpaItems
, LISTVIEW_CallBackCompare
, (LPARAM
)infoPtr
->hwndSelf
);
7835 /* Adjust selections and indices so that they are the way they should
7836 * be after the sort (otherwise, the list items move around, but
7837 * whatever is at the item's previous original position will be
7840 selectionMarkItem
=(infoPtr
->nSelectionMark
>=0)?DPA_GetPtr(infoPtr
->hdpaItems
, infoPtr
->nSelectionMark
):NULL
;
7841 for (i
=0; i
< nCount
; i
++)
7843 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, i
);
7844 pLVItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
7846 if (pLVItem
->state
& LVIS_SELECTED
)
7847 LISTVIEW_AddSelectionRange(infoPtr
, i
, i
);
7849 LISTVIEW_RemoveSelectionRange(infoPtr
, i
, i
);
7850 if (pLVItem
->state
& LVIS_FOCUSED
)
7851 infoPtr
->nFocusedItem
=i
;
7853 if (selectionMarkItem
!= NULL
)
7854 infoPtr
->nSelectionMark
= DPA_GetPtrIndex(infoPtr
->hdpaItems
, selectionMarkItem
);
7855 /* I believe nHotItem should be left alone, see LISTVIEW_ShiftIndices */
7857 /* align the items */
7858 LISTVIEW_AlignTop(infoPtr
);
7860 /* refresh the display */
7861 InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
);
7866 /* LISTVIEW_SubItemHitTest */
7870 * Updates an items or rearranges the listview control.
7873 * [I] infoPtr : valid pointer to the listview structure
7874 * [I] INT : item index
7880 static LRESULT
LISTVIEW_Update(LISTVIEW_INFO
*infoPtr
, INT nItem
)
7882 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
7883 BOOL bResult
= FALSE
;
7886 TRACE("(nItem=%d)\n", nItem
);
7888 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
7892 /* rearrange with default alignment style */
7893 if ((lStyle
& LVS_AUTOARRANGE
) && (((lStyle
& LVS_TYPEMASK
) == LVS_ICON
) ||
7894 ((lStyle
& LVS_TYPEMASK
) == LVS_SMALLICON
)))
7896 ListView_Arrange(infoPtr
->hwndSelf
, 0);
7900 /* get item bounding rectangle */
7901 ListView_GetItemRect(infoPtr
->hwndSelf
, nItem
, &rc
, LVIR_BOUNDS
);
7902 InvalidateRect(infoPtr
->hwndSelf
, &rc
, TRUE
);
7911 * Creates the listview control.
7914 * [I] hwnd : window handle
7915 * [I] lpcs : the create parameters
7921 static LRESULT
LISTVIEW_Create(HWND hwnd
, LPCREATESTRUCTW lpcs
)
7923 LISTVIEW_INFO
*infoPtr
;
7924 UINT uView
= lpcs
->style
& LVS_TYPEMASK
;
7927 TRACE("(lpcs=%p)\n", lpcs
);
7929 /* initialize info pointer */
7930 infoPtr
= (LISTVIEW_INFO
*)COMCTL32_Alloc(sizeof(LISTVIEW_INFO
));
7931 if (!infoPtr
) return -1;
7933 SetWindowLongW(hwnd
, 0, (LONG
)infoPtr
);
7934 ZeroMemory(infoPtr
, sizeof(LISTVIEW_INFO
));
7936 infoPtr
->hwndSelf
= hwnd
;
7937 /* determine the type of structures to use */
7938 infoPtr
->notifyFormat
= SendMessageW(GetParent(infoPtr
->hwndSelf
), WM_NOTIFYFORMAT
,
7939 (WPARAM
)infoPtr
->hwndSelf
, (LPARAM
)NF_QUERY
);
7941 /* initialize color information */
7942 infoPtr
->clrBk
= comctl32_color
.clrWindow
;
7943 infoPtr
->clrText
= comctl32_color
.clrWindowText
;
7944 infoPtr
->clrTextBk
= CLR_DEFAULT
;
7946 /* set default values */
7947 infoPtr
->uCallbackMask
= 0;
7948 infoPtr
->nFocusedItem
= -1;
7949 infoPtr
->nSelectionMark
= -1;
7950 infoPtr
->nHotItem
= -1;
7951 infoPtr
->iconSpacing
.cx
= GetSystemMetrics(SM_CXICONSPACING
);
7952 infoPtr
->iconSpacing
.cy
= GetSystemMetrics(SM_CYICONSPACING
);
7953 ZeroMemory(&infoPtr
->rcList
, sizeof(RECT
));
7954 infoPtr
->hwndEdit
= 0;
7955 infoPtr
->bEditing
= FALSE
;
7956 infoPtr
->nEditLabelItem
= -1;
7957 infoPtr
->bIsDrawing
= FALSE
;
7959 /* get default font (icon title) */
7960 SystemParametersInfoW(SPI_GETICONTITLELOGFONT
, 0, &logFont
, 0);
7961 infoPtr
->hDefaultFont
= CreateFontIndirectW(&logFont
);
7962 infoPtr
->hFont
= infoPtr
->hDefaultFont
;
7963 LISTVIEW_SaveTextMetrics(infoPtr
);
7966 infoPtr
->hwndHeader
= CreateWindowW(WC_HEADERW
, (LPCWSTR
)NULL
,
7967 WS_CHILD
| HDS_HORZ
| (DWORD
)((LVS_NOSORTHEADER
& lpcs
->style
)?0:HDS_BUTTONS
),
7968 0, 0, 0, 0, hwnd
, (HMENU
)0,
7969 lpcs
->hInstance
, NULL
);
7971 /* set header unicode format */
7972 SendMessageW(infoPtr
->hwndHeader
, HDM_SETUNICODEFORMAT
,(WPARAM
)TRUE
,(LPARAM
)NULL
);
7974 /* set header font */
7975 SendMessageW(infoPtr
->hwndHeader
, WM_SETFONT
, (WPARAM
)infoPtr
->hFont
,
7978 if (uView
== LVS_ICON
)
7980 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXICON
);
7981 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYICON
);
7983 else if (uView
== LVS_REPORT
)
7985 if (!(LVS_NOCOLUMNHEADER
& lpcs
->style
))
7987 ShowWindow(infoPtr
->hwndHeader
, SW_SHOWNORMAL
);
7991 /* set HDS_HIDDEN flag to hide the header bar */
7992 SetWindowLongW(infoPtr
->hwndHeader
, GWL_STYLE
,
7993 GetWindowLongW(infoPtr
->hwndHeader
, GWL_STYLE
) | HDS_HIDDEN
);
7997 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
7998 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
8002 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
8003 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
8006 /* display unsupported listview window styles */
8007 LISTVIEW_UnsupportedStyles(lpcs
->style
);
8009 /* allocate memory for the data structure */
8010 infoPtr
->hdpaItems
= DPA_Create(10);
8012 /* allocate memory for the selection ranges */
8013 infoPtr
->hdpaSelectionRanges
= DPA_Create(10);
8015 /* initialize size of items */
8016 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(infoPtr
);
8017 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(infoPtr
);
8019 /* initialize the hover time to -1(indicating the default system hover time) */
8020 infoPtr
->dwHoverTime
= -1;
8027 * Erases the background of the listview control.
8030 * [I] infoPtr : valid pointer to the listview structure
8031 * [I] WPARAM : device context handle
8032 * [I] LPARAM : not used
8038 static LRESULT
LISTVIEW_EraseBackground(LISTVIEW_INFO
*infoPtr
, WPARAM wParam
,
8043 TRACE("(wParam=%x, lParam=%lx)\n", wParam
, lParam
);
8045 if (infoPtr
->clrBk
== CLR_NONE
)
8047 bResult
= SendMessageW(GetParent(infoPtr
->hwndSelf
), WM_ERASEBKGND
, wParam
, lParam
);
8052 HBRUSH hBrush
= CreateSolidBrush(infoPtr
->clrBk
);
8053 GetClientRect(infoPtr
->hwndSelf
, &rc
);
8054 FillRect((HDC
)wParam
, &rc
, hBrush
);
8055 DeleteObject(hBrush
);
8063 static void LISTVIEW_FillBackground(LISTVIEW_INFO
*infoPtr
, HDC hdc
, LPRECT rc
)
8065 TRACE("(hdc=%x, rc=%p)\n", hdc
, rc
);
8067 if (infoPtr
->clrBk
!= CLR_NONE
)
8069 HBRUSH hBrush
= CreateSolidBrush(infoPtr
->clrBk
);
8070 FillRect(hdc
, rc
, hBrush
);
8071 DeleteObject(hBrush
);
8077 * Performs vertical scrolling.
8080 * [I] infoPtr : valid pointer to the listview structure
8081 * [I] INT : scroll code
8082 * [I] SHORT : current scroll position if scroll code is SB_THUMBPOSITION
8084 * [I] HWND : scrollbar control window handle
8090 * SB_LINEUP/SB_LINEDOWN:
8091 * for LVS_ICON, LVS_SMALLICON is 37 by experiment
8092 * for LVS_REPORT is 1 line --> infoPtr->nItemHeight
8093 * for LVS_LIST cannot occur ??? (implemented as LVS_REPORT)
8096 static LRESULT
LISTVIEW_VScroll(LISTVIEW_INFO
*infoPtr
, INT nScrollCode
, SHORT nCurrentPos
,
8099 UINT uView
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
8100 SCROLLINFO scrollInfo
;
8103 TRACE("(nScrollCode=%d, nCurrentPos=%d, hScrollWnd=%x)\n",
8104 nScrollCode
, nCurrentPos
, hScrollWnd
);
8106 SendMessageW(infoPtr
->hwndEdit
, WM_KILLFOCUS
, 0, 0);
8108 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
8109 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
8110 scrollInfo
.fMask
= SIF_PAGE
| SIF_POS
| SIF_RANGE
;
8112 is_an_icon
= ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
));
8114 if (GetScrollInfo(infoPtr
->hwndSelf
, SB_VERT
, &scrollInfo
))
8116 INT nOldScrollPos
= scrollInfo
.nPos
;
8117 switch (nScrollCode
)
8119 case SB_INTERNAL_UP
:
8120 if (scrollInfo
.nPos
> scrollInfo
.nMin
)
8124 case SB_INTERNAL_DOWN
:
8125 if (scrollInfo
.nPos
< scrollInfo
.nMax
)
8130 if (scrollInfo
.nPos
> scrollInfo
.nMin
)
8131 scrollInfo
.nPos
-= (is_an_icon
) ?
8132 LISTVIEW_SCROLL_ICON_LINE_SIZE
: infoPtr
->nItemHeight
;
8136 if (scrollInfo
.nPos
< scrollInfo
.nMax
)
8137 scrollInfo
.nPos
+= (is_an_icon
) ?
8138 LISTVIEW_SCROLL_ICON_LINE_SIZE
: infoPtr
->nItemHeight
;
8142 if (scrollInfo
.nPos
> scrollInfo
.nMin
)
8144 if (scrollInfo
.nPos
>= scrollInfo
.nPage
)
8145 scrollInfo
.nPos
-= scrollInfo
.nPage
;
8147 scrollInfo
.nPos
= scrollInfo
.nMin
;
8152 if (scrollInfo
.nPos
< scrollInfo
.nMax
)
8154 if (scrollInfo
.nPos
<= scrollInfo
.nMax
- scrollInfo
.nPage
)
8155 scrollInfo
.nPos
+= scrollInfo
.nPage
;
8157 scrollInfo
.nPos
= scrollInfo
.nMax
;
8161 case SB_THUMBPOSITION
:
8163 scrollInfo
.nPos
= nCurrentPos
;
8164 if (scrollInfo
.nPos
> scrollInfo
.nMax
)
8165 scrollInfo
.nPos
=scrollInfo
.nMax
;
8167 if (scrollInfo
.nPos
< scrollInfo
.nMin
)
8168 scrollInfo
.nPos
=scrollInfo
.nMin
;
8173 if (nOldScrollPos
!= scrollInfo
.nPos
)
8175 scrollInfo
.fMask
= SIF_POS
;
8176 SetScrollInfo(infoPtr
->hwndSelf
, SB_VERT
, &scrollInfo
, TRUE
);
8178 /* Get real position value, the value we set might have been changed
8179 * by SetScrollInfo (especially if we went too far.
8181 scrollInfo
.fMask
= SIF_POS
;
8182 GetScrollInfo(infoPtr
->hwndSelf
, SB_VERT
, &scrollInfo
);
8184 /* only if the scroll position really changed, do we update screen */
8185 if (nOldScrollPos
!= scrollInfo
.nPos
)
8187 if (IsWindowVisible(infoPtr
->hwndHeader
))
8189 RECT rListview
, rcHeader
, rDest
;
8190 GetClientRect(infoPtr
->hwndSelf
, &rListview
);
8191 GetWindowRect(infoPtr
->hwndHeader
, &rcHeader
);
8192 MapWindowPoints((HWND
) NULL
, infoPtr
->hwndSelf
, (LPPOINT
) &rcHeader
, 2);
8193 SubtractRect(&rDest
, &rListview
, &rcHeader
);
8194 InvalidateRect(infoPtr
->hwndSelf
, &rDest
, TRUE
);
8197 InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
);
8207 * Performs horizontal scrolling.
8210 * [I] infoPtr : valid pointer to the listview structure
8211 * [I] INT : scroll code
8212 * [I] SHORT : current scroll position if scroll code is SB_THUMBPOSITION
8214 * [I] HWND : scrollbar control window handle
8220 * SB_LINELEFT/SB_LINERIGHT:
8221 * for LVS_ICON, LVS_SMALLICON ??? (implemented as 1 pixel)
8222 * for LVS_REPORT is 1 pixel
8223 * for LVS_LIST is 1 column --> which is a 1 because the
8224 * scroll is based on columns not pixels
8227 static LRESULT
LISTVIEW_HScroll(LISTVIEW_INFO
*infoPtr
, INT nScrollCode
, SHORT nCurrentPos
,
8230 UINT uView
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
8231 SCROLLINFO scrollInfo
;
8234 TRACE("(nScrollCode=%d, nCurrentPos=%d, hScrollWnd=%x)\n",
8235 nScrollCode
, nCurrentPos
, hScrollWnd
);
8237 SendMessageW(infoPtr
->hwndEdit
, WM_KILLFOCUS
, 0, 0);
8239 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
8240 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
8241 scrollInfo
.fMask
= SIF_PAGE
| SIF_POS
| SIF_RANGE
;
8243 is_a_list
= (uView
== LVS_LIST
);
8245 if (GetScrollInfo(infoPtr
->hwndSelf
, SB_HORZ
, &scrollInfo
))
8247 INT nOldScrollPos
= scrollInfo
.nPos
;
8249 switch (nScrollCode
)
8251 case SB_INTERNAL_LEFT
:
8252 if (scrollInfo
.nPos
> scrollInfo
.nMin
)
8256 case SB_INTERNAL_RIGHT
:
8257 if (scrollInfo
.nPos
< scrollInfo
.nMax
)
8262 if (scrollInfo
.nPos
> scrollInfo
.nMin
)
8267 if (scrollInfo
.nPos
< scrollInfo
.nMax
)
8272 if (scrollInfo
.nPos
> scrollInfo
.nMin
)
8274 if (scrollInfo
.nPos
>= scrollInfo
.nPage
)
8275 scrollInfo
.nPos
-= scrollInfo
.nPage
;
8277 scrollInfo
.nPos
= scrollInfo
.nMin
;
8282 if (scrollInfo
.nPos
< scrollInfo
.nMax
)
8284 if (scrollInfo
.nPos
<= scrollInfo
.nMax
- scrollInfo
.nPage
)
8285 scrollInfo
.nPos
+= scrollInfo
.nPage
;
8287 scrollInfo
.nPos
= scrollInfo
.nMax
;
8291 case SB_THUMBPOSITION
:
8293 scrollInfo
.nPos
= nCurrentPos
;
8295 if (scrollInfo
.nPos
> scrollInfo
.nMax
)
8296 scrollInfo
.nPos
=scrollInfo
.nMax
;
8298 if (scrollInfo
.nPos
< scrollInfo
.nMin
)
8299 scrollInfo
.nPos
=scrollInfo
.nMin
;
8303 if (nOldScrollPos
!= scrollInfo
.nPos
)
8305 UINT uView
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
8306 scrollInfo
.fMask
= SIF_POS
;
8307 SetScrollInfo(infoPtr
->hwndSelf
, SB_HORZ
, &scrollInfo
, TRUE
);
8309 /* Get real position value, the value we set might have been changed
8310 * by SetScrollInfo (especially if we went too far.
8312 scrollInfo
.fMask
= SIF_POS
;
8313 GetScrollInfo(infoPtr
->hwndSelf
, SB_HORZ
, &scrollInfo
);
8314 if(uView
== LVS_REPORT
)
8316 LISTVIEW_UpdateHeaderSize(infoPtr
, scrollInfo
.nPos
);
8319 /* only if the scroll position really changed, do we update screen */
8320 if (nOldScrollPos
!= scrollInfo
.nPos
)
8321 InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
);
8328 static LRESULT
LISTVIEW_MouseWheel(LISTVIEW_INFO
*infoPtr
, INT wheelDelta
)
8330 UINT uView
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
8331 INT gcWheelDelta
= 0;
8332 UINT pulScrollLines
= 3;
8333 SCROLLINFO scrollInfo
;
8335 TRACE("(wheelDelta=%d)\n", wheelDelta
);
8337 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES
,0, &pulScrollLines
, 0);
8338 gcWheelDelta
-= wheelDelta
;
8340 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
8341 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
8342 scrollInfo
.fMask
= SIF_POS
| SIF_RANGE
;
8349 * listview should be scrolled by a multiple of 37 dependently on its dimension or its visible item number
8350 * should be fixed in the future.
8352 if (GetScrollInfo(infoPtr
->hwndSelf
, SB_VERT
, &scrollInfo
))
8353 LISTVIEW_VScroll(infoPtr
, SB_THUMBPOSITION
,
8354 scrollInfo
.nPos
+ (gcWheelDelta
< 0) ?
8355 LISTVIEW_SCROLL_ICON_LINE_SIZE
:
8356 -LISTVIEW_SCROLL_ICON_LINE_SIZE
, 0);
8360 if (abs(gcWheelDelta
) >= WHEEL_DELTA
&& pulScrollLines
)
8362 if (GetScrollInfo(infoPtr
->hwndSelf
, SB_VERT
, &scrollInfo
))
8364 int cLineScroll
= min(LISTVIEW_GetCountPerColumn(infoPtr
), pulScrollLines
);
8365 cLineScroll
*= (gcWheelDelta
/ WHEEL_DELTA
);
8366 LISTVIEW_VScroll(infoPtr
, SB_THUMBPOSITION
, scrollInfo
.nPos
+ cLineScroll
, 0);
8372 LISTVIEW_HScroll(infoPtr
, (gcWheelDelta
< 0) ? SB_LINELEFT
: SB_LINERIGHT
, 0, 0);
8383 * [I] infoPtr : valid pointer to the listview structure
8384 * [I] INT : virtual key
8385 * [I] LONG : key data
8390 static LRESULT
LISTVIEW_KeyDown(LISTVIEW_INFO
*infoPtr
, INT nVirtualKey
, LONG lKeyData
)
8392 UINT uView
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
8394 NMLVKEYDOWN nmKeyDown
;
8396 TRACE("(nVirtualKey=%d, lKeyData=%ld)\n", nVirtualKey
, lKeyData
);
8398 /* send LVN_KEYDOWN notification */
8399 nmKeyDown
.wVKey
= nVirtualKey
;
8400 nmKeyDown
.flags
= 0;
8401 notify(infoPtr
, LVN_KEYDOWN
, &nmKeyDown
.hdr
);
8403 switch (nVirtualKey
)
8406 if ((GETITEMCOUNT(infoPtr
) > 0) && (infoPtr
->nFocusedItem
!= -1))
8408 notify_return(infoPtr
);
8409 notify_itemactivate(infoPtr
);
8414 if (GETITEMCOUNT(infoPtr
) > 0)
8419 if (GETITEMCOUNT(infoPtr
) > 0)
8420 nItem
= GETITEMCOUNT(infoPtr
) - 1;
8424 nItem
= ListView_GetNextItem(infoPtr
->hwndSelf
, infoPtr
->nFocusedItem
, LVNI_TOLEFT
);
8428 nItem
= ListView_GetNextItem(infoPtr
->hwndSelf
, infoPtr
->nFocusedItem
, LVNI_ABOVE
);
8432 nItem
= ListView_GetNextItem(infoPtr
->hwndSelf
, infoPtr
->nFocusedItem
, LVNI_TORIGHT
);
8436 nItem
= ListView_GetNextItem(infoPtr
->hwndSelf
, infoPtr
->nFocusedItem
, LVNI_BELOW
);
8440 if (uView
== LVS_REPORT
)
8441 nItem
= infoPtr
->nFocusedItem
- LISTVIEW_GetCountPerColumn(infoPtr
);
8443 nItem
= infoPtr
->nFocusedItem
- LISTVIEW_GetCountPerColumn(infoPtr
)
8444 * LISTVIEW_GetCountPerRow(infoPtr
);
8445 if(nItem
< 0) nItem
= 0;
8449 if (uView
== LVS_REPORT
)
8450 nItem
= infoPtr
->nFocusedItem
+ LISTVIEW_GetCountPerColumn(infoPtr
);
8452 nItem
= infoPtr
->nFocusedItem
+ LISTVIEW_GetCountPerColumn(infoPtr
)
8453 * LISTVIEW_GetCountPerRow(infoPtr
);
8454 if(nItem
>= GETITEMCOUNT(infoPtr
)) nItem
= GETITEMCOUNT(infoPtr
) - 1;
8458 if ((nItem
!= -1) && (nItem
!= infoPtr
->nFocusedItem
))
8460 if (LISTVIEW_KeySelection(infoPtr
, nItem
))
8461 UpdateWindow(infoPtr
->hwndSelf
); /* update client area */
8472 * [I] infoPtr : valid pointer to the listview structure
8477 static LRESULT
LISTVIEW_KillFocus(LISTVIEW_INFO
*infoPtr
)
8479 UINT uView
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
8484 /* send NM_KILLFOCUS notification */
8485 notify_killfocus(infoPtr
);
8487 /* set window focus flag */
8488 infoPtr
->bFocus
= FALSE
;
8490 /* NEED drawing optimization ; redraw the selected items */
8491 if (uView
& LVS_REPORT
)
8493 nTop
= LISTVIEW_GetTopIndex(infoPtr
);
8495 LISTVIEW_GetCountPerColumn(infoPtr
) + 1;
8500 nBottom
= GETITEMCOUNT(infoPtr
);
8502 for (i
= nTop
; i
<nBottom
; i
++)
8504 if (LISTVIEW_IsSelected(infoPtr
,i
))
8507 rcItem
.left
= LVIR_BOUNDS
;
8508 LISTVIEW_GetItemRect(infoPtr
, i
, &rcItem
);
8509 InvalidateRect(infoPtr
->hwndSelf
, &rcItem
, FALSE
);
8518 * Processes double click messages (left mouse button).
8521 * [I] infoPtr : valid pointer to the listview structure
8522 * [I] wKey : key flag
8523 * [I] pts : mouse coordinate
8528 static LRESULT
LISTVIEW_LButtonDblClk(LISTVIEW_INFO
*infoPtr
, WORD wKey
, POINTS pts
)
8530 LVHITTESTINFO htInfo
;
8533 TRACE("(key=%hu, X=%hu, Y=%hu)\n", wKey
, pts
.x
, pts
.y
);
8535 htInfo
.pt
.x
= pts
.x
;
8536 htInfo
.pt
.y
= pts
.y
;
8538 /* send NM_DBLCLK notification */
8539 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
8540 if (LISTVIEW_HitTestItem(infoPtr
, &htInfo
, TRUE
) != -1)
8542 nmlv
.iItem
= htInfo
.iItem
;
8543 nmlv
.iSubItem
= htInfo
.iSubItem
;
8550 nmlv
.ptAction
.x
= pts
.x
;
8551 nmlv
.ptAction
.y
= pts
.y
;
8552 listview_notify(infoPtr
, NM_DBLCLK
, &nmlv
);
8555 /* To send the LVN_ITEMACTIVATE, it must be on an Item */
8556 if(nmlv
.iItem
!= -1)
8557 notify_itemactivate(infoPtr
);
8564 * Processes mouse down messages (left mouse button).
8567 * [I] infoPtr : valid pointer to the listview structure
8568 * [I] wKey : key flag
8569 * [I] pts : mouse coordinate
8574 static LRESULT
LISTVIEW_LButtonDown(LISTVIEW_INFO
*infoPtr
, WORD wKey
, POINTS pts
)
8576 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
8577 static BOOL bGroupSelect
= TRUE
;
8578 POINT pt
= { pts
.x
, pts
.y
};
8581 TRACE("(key=%hu, X=%hu, Y=%hu)\n", wKey
, pts
.x
, pts
.y
);
8583 /* send NM_RELEASEDCAPTURE notification */
8584 notify_releasedcapture(infoPtr
);
8586 if (!infoPtr
->bFocus
) SetFocus(infoPtr
->hwndSelf
);
8588 /* set left button down flag */
8589 infoPtr
->bLButtonDown
= TRUE
;
8591 nItem
= LISTVIEW_MouseSelection(infoPtr
, pt
);
8592 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
8594 if (lStyle
& LVS_SINGLESEL
)
8596 if ((LISTVIEW_GetItemState(infoPtr
, nItem
, LVIS_SELECTED
) & LVIS_SELECTED
)
8597 && infoPtr
->nEditLabelItem
== -1)
8598 infoPtr
->nEditLabelItem
= nItem
;
8600 LISTVIEW_SetSelection(infoPtr
, nItem
);
8604 if ((wKey
& MK_CONTROL
) && (wKey
& MK_SHIFT
))
8607 LISTVIEW_AddGroupSelection(infoPtr
, nItem
);
8609 LISTVIEW_AddSelection(infoPtr
, nItem
);
8611 else if (wKey
& MK_CONTROL
)
8613 bGroupSelect
= LISTVIEW_ToggleSelection(infoPtr
, nItem
);
8615 else if (wKey
& MK_SHIFT
)
8617 LISTVIEW_SetGroupSelection(infoPtr
, nItem
);
8622 (LISTVIEW_GetItemState(infoPtr
, nItem
, LVIS_SELECTED
) & LVIS_SELECTED
);
8624 /* set selection (clears other pre-existing selections) */
8625 LISTVIEW_SetSelection(infoPtr
, nItem
);
8627 if (was_selected
&& infoPtr
->nEditLabelItem
== -1)
8628 infoPtr
->nEditLabelItem
= nItem
;
8634 /* remove all selections */
8635 LISTVIEW_RemoveAllSelections(infoPtr
);
8638 /* redraw if we could have possibly selected something */
8639 if(!GETITEMCOUNT(infoPtr
)) InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
);
8646 * Processes mouse up messages (left mouse button).
8649 * [I] infoPtr : valid pointer to the listview structure
8650 * [I] wKey : key flag
8651 * [I] pts : mouse coordinate
8656 static LRESULT
LISTVIEW_LButtonUp(LISTVIEW_INFO
*infoPtr
, WORD wKey
, POINTS pts
)
8658 TRACE("(key=%hu, X=%hu, Y=%hu)\n", wKey
, pts
.x
, pts
.y
);
8660 if (infoPtr
->bLButtonDown
)
8662 LVHITTESTINFO lvHitTestInfo
;
8665 lvHitTestInfo
.pt
.x
= pts
.x
;
8666 lvHitTestInfo
.pt
.y
= pts
.y
;
8668 /* send NM_CLICK notification */
8669 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
8670 if (LISTVIEW_HitTestItem(infoPtr
, &lvHitTestInfo
, TRUE
) != -1)
8672 nmlv
.iItem
= lvHitTestInfo
.iItem
;
8673 nmlv
.iSubItem
= lvHitTestInfo
.iSubItem
;
8680 nmlv
.ptAction
.x
= pts
.x
;
8681 nmlv
.ptAction
.y
= pts
.y
;
8682 listview_notify(infoPtr
, NM_CLICK
, &nmlv
);
8684 /* set left button flag */
8685 infoPtr
->bLButtonDown
= FALSE
;
8687 if(infoPtr
->nEditLabelItem
!= -1)
8689 if(lvHitTestInfo
.iItem
== infoPtr
->nEditLabelItem
&& lvHitTestInfo
.flags
& LVHT_ONITEMLABEL
) {
8690 LISTVIEW_EditLabelT(infoPtr
, lvHitTestInfo
.iItem
, TRUE
);
8692 infoPtr
->nEditLabelItem
= -1;
8701 * Destroys the listview control (called after WM_DESTROY).
8704 * [I] infoPtr : valid pointer to the listview structure
8709 static LRESULT
LISTVIEW_NCDestroy(LISTVIEW_INFO
*infoPtr
)
8711 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
8715 /* delete all items */
8716 LISTVIEW_DeleteAllItems(infoPtr
);
8718 /* destroy data structure */
8719 DPA_Destroy(infoPtr
->hdpaItems
);
8720 DPA_Destroy(infoPtr
->hdpaSelectionRanges
);
8722 /* destroy image lists */
8723 if (!(lStyle
& LVS_SHAREIMAGELISTS
))
8726 /* FIXME: If the caller does a ImageList_Destroy and then we
8727 * do this code the area will be freed twice. Currently
8728 * this generates an "err:heap:HEAP_ValidateInUseArena
8729 * Heap xxxxxxxx: in-use arena yyyyyyyy next block
8730 * has PREV_FREE flag" sometimes.
8732 * We will leak the memory till we figure out how to fix
8734 if (infoPtr
->himlNormal
)
8735 ImageList_Destroy(infoPtr
->himlNormal
);
8736 if (infoPtr
->himlSmall
)
8737 ImageList_Destroy(infoPtr
->himlSmall
);
8738 if (infoPtr
->himlState
)
8739 ImageList_Destroy(infoPtr
->himlState
);
8744 infoPtr
->hFont
= (HFONT
)0;
8745 if (infoPtr
->hDefaultFont
)
8747 DeleteObject(infoPtr
->hDefaultFont
);
8750 /* free listview info pointer*/
8751 COMCTL32_Free(infoPtr
);
8753 SetWindowLongW(infoPtr
->hwndSelf
, 0, 0);
8759 * Handles notifications from children.
8762 * [I] infoPtr : valid pointer to the listview structure
8763 * [I] INT : control identifier
8764 * [I] LPNMHDR : notification information
8769 static LRESULT
LISTVIEW_Notify(LISTVIEW_INFO
*infoPtr
, INT nCtrlId
, LPNMHDR lpnmh
)
8771 TRACE("(nCtrlId=%d, lpnmh=%p)\n", nCtrlId
, lpnmh
);
8773 if (lpnmh
->hwndFrom
== infoPtr
->hwndHeader
)
8775 /* handle notification from header control */
8776 if (lpnmh
->code
== HDN_ENDTRACKW
)
8778 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(infoPtr
);
8779 InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
);
8781 else if(lpnmh
->code
== HDN_ITEMCLICKW
|| lpnmh
->code
== HDN_ITEMCLICKA
)
8783 /* Handle sorting by Header Column */
8786 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
8788 nmlv
.iSubItem
= ((LPNMHEADERW
)lpnmh
)->iItem
;
8789 listview_notify(infoPtr
, LVN_COLUMNCLICK
, &nmlv
);
8791 else if(lpnmh
->code
== NM_RELEASEDCAPTURE
)
8793 /* Idealy this should be done in HDN_ENDTRACKA
8794 * but since SetItemBounds in Header.c is called after
8795 * the notification is sent, it is neccessary to handle the
8796 * update of the scroll bar here (Header.c works fine as it is,
8797 * no need to disturb it)
8799 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(infoPtr
);
8800 LISTVIEW_UpdateScroll(infoPtr
);
8801 InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
);
8811 * Determines the type of structure to use.
8814 * [I] infoPtr : valid pointer to the listview structureof the sender
8815 * [I] HWND : listview window handle
8816 * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
8821 static LRESULT
LISTVIEW_NotifyFormat(LISTVIEW_INFO
*infoPtr
, HWND hwndFrom
, INT nCommand
)
8823 TRACE("(hwndFrom=%x, nCommand=%d)\n", hwndFrom
, nCommand
);
8825 if (nCommand
== NF_REQUERY
)
8826 infoPtr
->notifyFormat
= SendMessageW(hwndFrom
, WM_NOTIFYFORMAT
,
8827 (WPARAM
)infoPtr
->hwndSelf
, (LPARAM
)NF_QUERY
);
8833 * Paints/Repaints the listview control.
8836 * [I] infoPtr : valid pointer to the listview structure
8837 * [I] HDC : device context handle
8842 static LRESULT
LISTVIEW_Paint(LISTVIEW_INFO
*infoPtr
, HDC hdc
)
8846 TRACE("(hdc=%x)\n", hdc
);
8850 hdc
= BeginPaint(infoPtr
->hwndSelf
, &ps
);
8851 LISTVIEW_Refresh(infoPtr
, hdc
);
8852 EndPaint(infoPtr
->hwndSelf
, &ps
);
8856 LISTVIEW_Refresh(infoPtr
, hdc
);
8864 * Processes double click messages (right mouse button).
8867 * [I] infoPtr : valid pointer to the listview structure
8868 * [I] wKey : key flag
8869 * [I] pts : mouse coordinate
8874 static LRESULT
LISTVIEW_RButtonDblClk(LISTVIEW_INFO
*infoPtr
, WORD wKey
, POINTS pts
)
8876 TRACE("(key=%hu,X=%hu,Y=%hu)\n", wKey
, pts
.x
, pts
.y
);
8878 /* send NM_RELEASEDCAPTURE notification */
8879 notify_releasedcapture(infoPtr
);
8881 /* send NM_RDBLCLK notification */
8882 notify_rdblclk(infoPtr
);
8889 * Processes mouse down messages (right mouse button).
8892 * [I] infoPtr : valid pointer to the listview structure
8893 * [I] wKey : key flag
8894 * [I] pts : mouse coordinate
8899 static LRESULT
LISTVIEW_RButtonDown(LISTVIEW_INFO
*infoPtr
, WORD wKey
, POINTS pts
)
8903 LVHITTESTINFO lvHitTestInfo
;
8904 POINT pt
= { pts
.x
, pts
.y
};
8906 TRACE("(key=%hu,X=%hu,Y=%hu)\n", wKey
, pts
.x
, pts
.y
);
8908 /* send NM_RELEASEDCAPTURE notification */
8909 notify_releasedcapture(infoPtr
);
8911 /* make sure the listview control window has the focus */
8912 if (!infoPtr
->bFocus
) SetFocus(infoPtr
->hwndSelf
);
8914 /* set right button down flag */
8915 infoPtr
->bRButtonDown
= TRUE
;
8917 /* determine the index of the selected item */
8918 nItem
= LISTVIEW_MouseSelection(infoPtr
, pt
);
8919 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
8921 LISTVIEW_SetItemFocus(infoPtr
,nItem
);
8922 if (!((wKey
& MK_SHIFT
) || (wKey
& MK_CONTROL
)) &&
8923 !LISTVIEW_IsSelected(infoPtr
,nItem
))
8924 LISTVIEW_SetSelection(infoPtr
, nItem
);
8928 LISTVIEW_RemoveAllSelections(infoPtr
);
8931 lvHitTestInfo
.pt
.x
= pts
.x
;
8932 lvHitTestInfo
.pt
.y
= pts
.y
;
8934 /* Send NM_RClICK notification */
8935 ZeroMemory(&nmlv
, sizeof(nmlv
));
8936 if (LISTVIEW_HitTestItem(infoPtr
, &lvHitTestInfo
, TRUE
) != -1)
8938 nmlv
.iItem
= lvHitTestInfo
.iItem
;
8939 nmlv
.iSubItem
= lvHitTestInfo
.iSubItem
;
8946 nmlv
.ptAction
.x
= pts
.x
;
8947 nmlv
.ptAction
.y
= pts
.y
;
8948 listview_notify(infoPtr
, NM_RCLICK
, &nmlv
);
8955 * Processes mouse up messages (right mouse button).
8958 * [I] infoPtr : valid pointer to the listview structure
8959 * [I] wKey : key flag
8960 * [I] pts : mouse coordinate
8965 static LRESULT
LISTVIEW_RButtonUp(LISTVIEW_INFO
*infoPtr
, WORD wKey
, POINTS pts
)
8967 TRACE("(key=%hu,X=%hu,Y=%hu)\n", wKey
, pts
.x
, pts
.y
);
8969 if (infoPtr
->bRButtonDown
)
8971 POINT pt
= { pts
.x
, pts
.y
};
8973 /* set button flag */
8974 infoPtr
->bRButtonDown
= FALSE
;
8976 /* Change to screen coordinate for WM_CONTEXTMENU */
8977 ClientToScreen(infoPtr
->hwndSelf
, &pt
);
8979 /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
8980 SendMessageW(infoPtr
->hwndSelf
, WM_CONTEXTMENU
,
8981 (WPARAM
)infoPtr
->hwndSelf
, MAKELPARAM(pt
.x
, pt
.y
));
8993 * [I] infoPtr : valid pointer to the listview structure
8994 * [I] hwnd : window handle of window containing the cursor
8995 * [I] nHittest : hit-test code
8996 * [I] wMouseMsg : ideintifier of the mouse message
8999 * TRUE if cursor is set
9002 static BOOL
LISTVIEW_SetCursor(LISTVIEW_INFO
*infoPtr
, HWND hwnd
, UINT nHittest
, UINT wMouseMsg
)
9006 if(!(infoPtr
->dwExStyle
& LVS_EX_TRACKSELECT
)) return FALSE
;
9009 if (LISTVIEW_MouseSelection(infoPtr
, pt
) < 0) return FALSE
;
9011 SetCursor(infoPtr
->hHotCursor
);
9021 * [I] infoPtr : valid pointer to the listview structure
9022 * [I] infoPtr : valid pointer to the listview structureof previously focused window
9027 static LRESULT
LISTVIEW_SetFocus(LISTVIEW_INFO
*infoPtr
, HWND hwndLoseFocus
)
9029 TRACE("(hwndLoseFocus=%x)\n", hwndLoseFocus
);
9031 /* send NM_SETFOCUS notification */
9032 notify_setfocus(infoPtr
);
9034 /* set window focus flag */
9035 infoPtr
->bFocus
= TRUE
;
9037 UpdateWindow(infoPtr
->hwndSelf
);
9047 * [I] infoPtr : valid pointer to the listview structure
9048 * [I] HFONT : font handle
9049 * [I] WORD : redraw flag
9054 static LRESULT
LISTVIEW_SetFont(LISTVIEW_INFO
*infoPtr
, HFONT hFont
, WORD fRedraw
)
9056 UINT uView
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
) & LVS_TYPEMASK
;
9058 TRACE("(hfont=%x,redraw=%hu)\n", hFont
, fRedraw
);
9060 infoPtr
->hFont
= hFont
? hFont
: infoPtr
->hDefaultFont
;
9061 LISTVIEW_SaveTextMetrics(infoPtr
);
9063 if (uView
== LVS_REPORT
)
9065 /* set header font */
9066 SendMessageW(infoPtr
->hwndHeader
, WM_SETFONT
, (WPARAM
)hFont
,
9067 MAKELPARAM(fRedraw
, 0));
9070 /* invalidate listview control client area */
9071 InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
);
9073 if (fRedraw
) UpdateWindow(infoPtr
->hwndSelf
);
9080 * Message handling for WM_SETREDRAW.
9081 * For the Listview, it invalidates the entire window (the doc specifies otherwise)
9084 * [I] infoPtr : valid pointer to the listview structure
9085 * [I] bRedraw: state of redraw flag
9088 * DefWinProc return value
9090 static LRESULT
LISTVIEW_SetRedraw(LISTVIEW_INFO
*infoPtr
, BOOL bRedraw
)
9092 LRESULT lResult
= DefWindowProcW(infoPtr
->hwndSelf
, WM_SETREDRAW
, bRedraw
, 0);
9094 RedrawWindow(infoPtr
->hwndSelf
, NULL
, 0,
9095 RDW_INVALIDATE
| RDW_FRAME
| RDW_ERASE
| RDW_ALLCHILDREN
| RDW_ERASENOW
);
9101 * Resizes the listview control. This function processes WM_SIZE
9102 * messages. At this time, the width and height are not used.
9105 * [I] infoPtr : valid pointer to the listview structure
9106 * [I] WORD : new width
9107 * [I] WORD : new height
9112 static LRESULT
LISTVIEW_Size(LISTVIEW_INFO
*infoPtr
, int Width
, int Height
)
9114 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
9115 UINT uView
= lStyle
& LVS_TYPEMASK
;
9117 TRACE("(width=%d, height=%d)\n", Width
, Height
);
9119 if (LISTVIEW_UpdateSize(infoPtr
))
9121 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
9123 if (lStyle
& LVS_ALIGNLEFT
)
9124 LISTVIEW_AlignLeft(infoPtr
);
9126 LISTVIEW_AlignTop(infoPtr
);
9129 LISTVIEW_UpdateScroll(infoPtr
);
9131 /* invalidate client area + erase background */
9132 InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
);
9140 * Sets the size information.
9143 * [I] infoPtr : valid pointer to the listview structure
9146 * Zero if no size change
9149 static BOOL
LISTVIEW_UpdateSize(LISTVIEW_INFO
*infoPtr
)
9151 LONG lStyle
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_STYLE
);
9152 UINT uView
= lStyle
& LVS_TYPEMASK
;
9156 GetClientRect(infoPtr
->hwndSelf
, &rcList
);
9157 CopyRect(&rcOld
,&(infoPtr
->rcList
));
9158 infoPtr
->rcList
.left
= 0;
9159 infoPtr
->rcList
.right
= max(rcList
.right
- rcList
.left
, 1);
9160 infoPtr
->rcList
.top
= 0;
9161 infoPtr
->rcList
.bottom
= max(rcList
.bottom
- rcList
.top
, 1);
9163 if (uView
== LVS_LIST
)
9165 /* Apparently the "LIST" style is supposed to have the same
9166 * number of items in a column even if there is no scroll bar.
9167 * Since if a scroll bar already exists then the bottom is already
9168 * reduced, only reduce if the scroll bar does not currently exist.
9169 * The "2" is there to mimic the native control. I think it may be
9170 * related to either padding or edges. (GLA 7/2002)
9172 if (!(lStyle
& WS_HSCROLL
))
9174 INT nHScrollHeight
= GetSystemMetrics(SM_CYHSCROLL
);
9175 if (infoPtr
->rcList
.bottom
> nHScrollHeight
)
9176 infoPtr
->rcList
.bottom
-= (nHScrollHeight
+ 2);
9180 if (infoPtr
->rcList
.bottom
> 2)
9181 infoPtr
->rcList
.bottom
-= 2;
9184 else if (uView
== LVS_REPORT
)
9191 Header_Layout(infoPtr
->hwndHeader
, &hl
);
9193 SetWindowPos(wp
.hwnd
, wp
.hwndInsertAfter
, wp
.x
, wp
.y
, wp
.cx
, wp
.cy
, wp
.flags
);
9195 if (!(LVS_NOCOLUMNHEADER
& lStyle
))
9196 infoPtr
->rcList
.top
= max(wp
.cy
, 0);
9198 return (EqualRect(&rcOld
,&(infoPtr
->rcList
)));
9203 * Processes WM_STYLECHANGED messages.
9206 * [I] infoPtr : valid pointer to the listview structure
9207 * [I] WPARAM : window style type (normal or extended)
9208 * [I] LPSTYLESTRUCT : window style information
9213 static INT
LISTVIEW_StyleChanged(LISTVIEW_INFO
*infoPtr
, WPARAM wStyleType
,
9216 UINT uNewView
= lpss
->styleNew
& LVS_TYPEMASK
;
9217 UINT uOldView
= lpss
->styleOld
& LVS_TYPEMASK
;
9218 RECT rcList
= infoPtr
->rcList
;
9220 TRACE("(styletype=%x, styleOld=0x%08lx, styleNew=0x%08lx)\n",
9221 wStyleType
, lpss
->styleOld
, lpss
->styleNew
);
9223 if (wStyleType
== GWL_STYLE
)
9225 if (uOldView
== LVS_REPORT
)
9226 ShowWindow(infoPtr
->hwndHeader
, SW_HIDE
);
9228 if (((lpss
->styleOld
& WS_HSCROLL
) != 0)&&
9229 ((lpss
->styleNew
& WS_HSCROLL
) == 0))
9230 ShowScrollBar(infoPtr
->hwndSelf
, SB_HORZ
, FALSE
);
9232 if (((lpss
->styleOld
& WS_VSCROLL
) != 0)&&
9233 ((lpss
->styleNew
& WS_VSCROLL
) == 0))
9234 ShowScrollBar(infoPtr
->hwndSelf
, SB_VERT
, FALSE
);
9236 /* If switching modes, then start with no scroll bars and then
9239 if (uNewView
!= uOldView
)
9240 ShowScrollBar(infoPtr
->hwndSelf
, SB_BOTH
, FALSE
);
9242 if (uNewView
== LVS_ICON
)
9246 /* First readjust the iconSize and if necessary the iconSpacing */
9247 oldcx
= infoPtr
->iconSize
.cx
;
9248 oldcy
= infoPtr
->iconSize
.cy
;
9249 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXICON
);
9250 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYICON
);
9251 if (infoPtr
->himlNormal
!= NULL
)
9254 ImageList_GetIconSize(infoPtr
->himlNormal
, &cx
, &cy
);
9255 infoPtr
->iconSize
.cx
= cx
;
9256 infoPtr
->iconSize
.cy
= cy
;
9258 if ((infoPtr
->iconSize
.cx
!= oldcx
) || (infoPtr
->iconSize
.cy
!= oldcy
))
9260 TRACE("icon old size=(%d,%d), new size=(%ld,%ld)\n",
9261 oldcx
, oldcy
, infoPtr
->iconSize
.cx
, infoPtr
->iconSize
.cy
);
9262 LISTVIEW_SetIconSpacing(infoPtr
,0);
9265 /* Now update the full item width and height */
9266 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(infoPtr
);
9267 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(infoPtr
);
9268 if (lpss
->styleNew
& LVS_ALIGNLEFT
)
9269 LISTVIEW_AlignLeft(infoPtr
);
9271 LISTVIEW_AlignTop(infoPtr
);
9273 else if (uNewView
== LVS_REPORT
)
9280 Header_Layout(infoPtr
->hwndHeader
, &hl
);
9281 SetWindowPos(infoPtr
->hwndHeader
, infoPtr
->hwndSelf
, wp
.x
, wp
.y
, wp
.cx
, wp
.cy
,
9283 if (!(LVS_NOCOLUMNHEADER
& lpss
->styleNew
))
9284 ShowWindow(infoPtr
->hwndHeader
, SW_SHOWNORMAL
);
9286 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
9287 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
9288 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(infoPtr
);
9289 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(infoPtr
);
9291 else if (uNewView
== LVS_LIST
)
9293 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
9294 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
9295 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(infoPtr
);
9296 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(infoPtr
);
9300 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
9301 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
9302 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(infoPtr
);
9303 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(infoPtr
);
9304 if (lpss
->styleNew
& LVS_ALIGNLEFT
)
9305 LISTVIEW_AlignLeft(infoPtr
);
9307 LISTVIEW_AlignTop(infoPtr
);
9310 /* update the size of the client area */
9311 LISTVIEW_UpdateSize(infoPtr
);
9313 /* add scrollbars if needed */
9314 LISTVIEW_UpdateScroll(infoPtr
);
9316 /* invalidate client area + erase background */
9317 InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
);
9319 /* print the list of unsupported window styles */
9320 LISTVIEW_UnsupportedStyles(lpss
->styleNew
);
9323 /* If they change the view and we have an active edit control
9324 we will need to kill the control since the redraw will
9325 misplace the edit control.
9327 if (infoPtr
->bEditing
&&
9328 ((uNewView
& (LVS_ICON
|LVS_LIST
|LVS_SMALLICON
)) !=
9329 ((LVS_ICON
|LVS_LIST
|LVS_SMALLICON
) & uOldView
)))
9331 SendMessageW(infoPtr
->hwndEdit
, WM_KILLFOCUS
, 0, 0);
9339 * Window procedure of the listview control.
9342 static LRESULT WINAPI
9343 LISTVIEW_WindowProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
9345 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
9347 TRACE("(uMsg=%x wParam=%x lParam=%lx)\n", uMsg
, wParam
, lParam
);
9349 if (!infoPtr
&& (uMsg
!= WM_CREATE
))
9350 return DefWindowProcW(hwnd
, uMsg
, wParam
, lParam
);
9354 case LVM_APPROXIMATEVIEWRECT
:
9355 return LISTVIEW_ApproximateViewRect(infoPtr
, (INT
)wParam
,
9356 LOWORD(lParam
), HIWORD(lParam
));
9358 return LISTVIEW_Arrange(infoPtr
, (INT
)wParam
);
9360 /* case LVN_CANCELEDITLABEL */
9362 /* case LVM_CREATEDRAGIMAGE: */
9364 case LVM_DELETEALLITEMS
:
9365 return LISTVIEW_DeleteAllItems(infoPtr
);
9367 case LVM_DELETECOLUMN
:
9368 return LISTVIEW_DeleteColumn(infoPtr
, (INT
)wParam
);
9370 case LVM_DELETEITEM
:
9371 return LISTVIEW_DeleteItem(infoPtr
, (INT
)wParam
);
9373 case LVM_EDITLABELW
:
9374 return (LRESULT
)LISTVIEW_EditLabelT(infoPtr
, (INT
)wParam
, TRUE
);
9376 case LVM_EDITLABELA
:
9377 return (LRESULT
)LISTVIEW_EditLabelT(infoPtr
, (INT
)wParam
, FALSE
);
9379 /* case LVN_ENABLEGROUPVIEW: */
9381 case LVM_ENSUREVISIBLE
:
9382 return LISTVIEW_EnsureVisible(infoPtr
, (INT
)wParam
, (BOOL
)lParam
);
9385 return LISTVIEW_FindItemW(infoPtr
, (INT
)wParam
, (LPLVFINDINFOW
)lParam
);
9388 return LISTVIEW_FindItemA(infoPtr
, (INT
)wParam
, (LPLVFINDINFOA
)lParam
);
9390 case LVM_GETBKCOLOR
:
9391 return infoPtr
->clrBk
;
9393 /* case LVM_GETBKIMAGE: */
9395 case LVM_GETCALLBACKMASK
:
9396 return LISTVIEW_GetCallbackMask(infoPtr
);
9398 case LVM_GETCOLUMNA
:
9399 return LISTVIEW_GetColumnT(infoPtr
, (INT
)wParam
, (LPLVCOLUMNW
)lParam
, FALSE
);
9401 case LVM_GETCOLUMNW
:
9402 return LISTVIEW_GetColumnT(infoPtr
, (INT
)wParam
, (LPLVCOLUMNW
)lParam
, TRUE
);
9404 case LVM_GETCOLUMNORDERARRAY
:
9405 return LISTVIEW_GetColumnOrderArray(infoPtr
, (INT
)wParam
, (LPINT
)lParam
);
9407 case LVM_GETCOLUMNWIDTH
:
9408 return LISTVIEW_GetColumnWidth(infoPtr
, (INT
)wParam
);
9410 case LVM_GETCOUNTPERPAGE
:
9411 return LISTVIEW_GetCountPerPage(infoPtr
);
9413 case LVM_GETEDITCONTROL
:
9414 return (LRESULT
)infoPtr
->hwndEdit
;
9416 case LVM_GETEXTENDEDLISTVIEWSTYLE
:
9417 return infoPtr
->dwExStyle
;
9420 return (LRESULT
)infoPtr
->hwndHeader
;
9422 case LVM_GETHOTCURSOR
:
9423 return infoPtr
->hHotCursor
;
9425 case LVM_GETHOTITEM
:
9426 return infoPtr
->nHotItem
;
9428 case LVM_GETHOVERTIME
:
9429 return infoPtr
->dwHoverTime
;
9431 case LVM_GETIMAGELIST
:
9432 return LISTVIEW_GetImageList(infoPtr
, (INT
)wParam
);
9434 /* case LVN_GETINSERTMARK: */
9436 /* case LVN_GETINSERTMARKCOLOR: */
9438 /* case LVN_GETINSERTMARKRECT: */
9440 case LVM_GETISEARCHSTRINGA
:
9441 case LVM_GETISEARCHSTRINGW
:
9442 FIXME("LVM_GETISEARCHSTRING: unimplemented\n");
9446 return LISTVIEW_GetItemT(infoPtr
, (LPLVITEMW
)lParam
, FALSE
, FALSE
);
9449 return LISTVIEW_GetItemT(infoPtr
, (LPLVITEMW
)lParam
, FALSE
, TRUE
);
9451 case LVM_GETITEMCOUNT
:
9452 return GETITEMCOUNT(infoPtr
);
9454 case LVM_GETITEMPOSITION
:
9455 return LISTVIEW_GetItemPosition(infoPtr
, (INT
)wParam
, (LPPOINT
)lParam
);
9457 case LVM_GETITEMRECT
:
9458 return LISTVIEW_GetItemRect(infoPtr
, (INT
)wParam
, (LPRECT
)lParam
);
9460 case LVM_GETITEMSPACING
:
9461 return LISTVIEW_GetItemSpacing(infoPtr
, (BOOL
)wParam
);
9463 case LVM_GETITEMSTATE
:
9464 return LISTVIEW_GetItemState(infoPtr
, (INT
)wParam
, (UINT
)lParam
);
9466 case LVM_GETITEMTEXTA
:
9467 return LISTVIEW_GetItemTextT(infoPtr
, (INT
)wParam
, (LPLVITEMW
)lParam
, FALSE
);
9469 case LVM_GETITEMTEXTW
:
9470 return LISTVIEW_GetItemTextT(infoPtr
, (INT
)wParam
, (LPLVITEMW
)lParam
, TRUE
);
9472 case LVM_GETNEXTITEM
:
9473 return LISTVIEW_GetNextItem(infoPtr
, (INT
)wParam
, LOWORD(lParam
));
9475 case LVM_GETNUMBEROFWORKAREAS
:
9476 FIXME("LVM_GETNUMBEROFWORKAREAS: unimplemented\n");
9480 return LISTVIEW_GetOrigin(infoPtr
, (LPPOINT
)lParam
);
9482 /* case LVN_GETOUTLINECOLOR: */
9484 /* case LVM_GETSELECTEDCOLUMN: */
9486 case LVM_GETSELECTEDCOUNT
:
9487 return LISTVIEW_GetSelectedCount(infoPtr
);
9489 case LVM_GETSELECTIONMARK
:
9490 return infoPtr
->nSelectionMark
;
9492 case LVM_GETSTRINGWIDTHA
:
9493 return LISTVIEW_GetStringWidthT(infoPtr
, (LPCWSTR
)lParam
, FALSE
);
9495 case LVM_GETSTRINGWIDTHW
:
9496 return LISTVIEW_GetStringWidthT(infoPtr
, (LPCWSTR
)lParam
, TRUE
);
9498 case LVM_GETSUBITEMRECT
:
9499 return LISTVIEW_GetSubItemRect(infoPtr
, (UINT
)wParam
, ((LPRECT
)lParam
)->top
,
9500 ((LPRECT
)lParam
)->left
, (LPRECT
)lParam
);
9502 case LVM_GETTEXTBKCOLOR
:
9503 return LISTVIEW_GetTextBkColor(infoPtr
);
9505 case LVM_GETTEXTCOLOR
:
9506 return LISTVIEW_GetTextColor(infoPtr
);
9508 /* case LVN_GETTILEINFO: */
9510 /* case LVN_GETTILEVIEWINFO: */
9512 case LVM_GETTOOLTIPS
:
9513 FIXME("LVM_GETTOOLTIPS: unimplemented\n");
9516 case LVM_GETTOPINDEX
:
9517 return LISTVIEW_GetTopIndex(infoPtr
);
9519 /*case LVM_GETUNICODEFORMAT:
9520 FIXME("LVM_GETUNICODEFORMAT: unimplemented\n");
9523 case LVM_GETVIEWRECT
:
9524 return LISTVIEW_GetViewRect(infoPtr
, (LPRECT
)lParam
);
9526 case LVM_GETWORKAREAS
:
9527 FIXME("LVM_GETWORKAREAS: unimplemented\n");
9530 /* case LVN_HASGROUP: */
9533 return LISTVIEW_HitTest(infoPtr
, (LPLVHITTESTINFO
)lParam
);
9535 case LVM_INSERTCOLUMNA
:
9536 return LISTVIEW_InsertColumnT(infoPtr
, (INT
)wParam
, (LPLVCOLUMNW
)lParam
, FALSE
);
9538 case LVM_INSERTCOLUMNW
:
9539 return LISTVIEW_InsertColumnT(infoPtr
, (INT
)wParam
, (LPLVCOLUMNW
)lParam
, TRUE
);
9541 /* case LVN_INSERTGROUP: */
9543 /* case LVN_INSERTGROUPSORTED: */
9545 case LVM_INSERTITEMA
:
9546 return LISTVIEW_InsertItemT(infoPtr
, (LPLVITEMW
)lParam
, FALSE
);
9548 case LVM_INSERTITEMW
:
9549 return LISTVIEW_InsertItemT(infoPtr
, (LPLVITEMW
)lParam
, TRUE
);
9551 /* case LVN_INSERTMARKHITTEST: */
9553 /* case LVN_ISGROUPVIEWENABLED: */
9555 /* case LVN_MAPIDTOINDEX: */
9557 /* case LVN_INEDXTOID: */
9559 /* case LVN_MOVEGROUP: */
9561 /* case LVN_MOVEITEMTOGROUP: */
9563 case LVM_REDRAWITEMS
:
9564 return LISTVIEW_RedrawItems(infoPtr
, (INT
)wParam
, (INT
)lParam
);
9566 /* case LVN_REMOVEALLGROUPS: */
9568 /* case LVN_REMOVEGROUP: */
9571 return LISTVIEW_Scroll(infoPtr
, (INT
)wParam
, (INT
)lParam
);
9573 case LVM_SETBKCOLOR
:
9574 return LISTVIEW_SetBkColor(infoPtr
, (COLORREF
)lParam
);
9576 /* case LVM_SETBKIMAGE: */
9578 case LVM_SETCALLBACKMASK
:
9579 return LISTVIEW_SetCallbackMask(infoPtr
, (UINT
)wParam
);
9581 case LVM_SETCOLUMNA
:
9582 return LISTVIEW_SetColumnT(infoPtr
, (INT
)wParam
, (LPLVCOLUMNW
)lParam
, FALSE
);
9584 case LVM_SETCOLUMNW
:
9585 return LISTVIEW_SetColumnT(infoPtr
, (INT
)wParam
, (LPLVCOLUMNW
)lParam
, TRUE
);
9587 case LVM_SETCOLUMNORDERARRAY
:
9588 return LISTVIEW_SetColumnOrderArray(infoPtr
, (INT
)wParam
, (LPINT
)lParam
);
9590 case LVM_SETCOLUMNWIDTH
:
9591 return LISTVIEW_SetColumnWidth(infoPtr
, (INT
)wParam
, SLOWORD(lParam
));
9593 case LVM_SETEXTENDEDLISTVIEWSTYLE
:
9594 return LISTVIEW_SetExtendedListViewStyle(infoPtr
, (DWORD
)wParam
, (DWORD
)lParam
);
9596 /* case LVN_SETGROUPINFO: */
9598 /* case LVN_SETGROUPMETRICS: */
9600 case LVM_SETHOTCURSOR
:
9601 return LISTVIEW_SetHotCursor(infoPtr
, (HCURSOR
)lParam
);
9603 case LVM_SETHOTITEM
:
9604 return LISTVIEW_SetHotItem(infoPtr
, (INT
)wParam
);
9606 case LVM_SETHOVERTIME
:
9607 return LISTVIEW_SetHoverTime(infoPtr
, (DWORD
)wParam
);
9609 case LVM_SETICONSPACING
:
9610 return LISTVIEW_SetIconSpacing(infoPtr
, (DWORD
)lParam
);
9612 case LVM_SETIMAGELIST
:
9613 return (LRESULT
)LISTVIEW_SetImageList(infoPtr
, (INT
)wParam
, (HIMAGELIST
)lParam
);
9615 /* case LVN_SETINFOTIP: */
9617 /* case LVN_SETINSERTMARK: */
9619 /* case LVN_SETINSERTMARKCOLOR: */
9622 return LISTVIEW_SetItemT(infoPtr
, (LPLVITEMW
)lParam
, FALSE
);
9625 return LISTVIEW_SetItemT(infoPtr
, (LPLVITEMW
)lParam
, TRUE
);
9627 case LVM_SETITEMCOUNT
:
9628 return LISTVIEW_SetItemCount(infoPtr
, (INT
)wParam
, (DWORD
)lParam
);
9630 case LVM_SETITEMPOSITION
:
9631 return LISTVIEW_SetItemPosition(infoPtr
, (INT
)wParam
, (INT
)LOWORD(lParam
),
9632 (INT
)HIWORD(lParam
));
9634 case LVM_SETITEMPOSITION32
:
9635 return LISTVIEW_SetItemPosition(infoPtr
, (INT
)wParam
, ((POINT
*)lParam
)->x
,
9636 ((POINT
*)lParam
)->y
);
9638 case LVM_SETITEMSTATE
:
9639 return LISTVIEW_SetItemState(infoPtr
, (INT
)wParam
, (LPLVITEMW
)lParam
);
9641 case LVM_SETITEMTEXTA
:
9642 return LISTVIEW_SetItemTextT(infoPtr
, (INT
)wParam
, (LPLVITEMW
)lParam
, FALSE
);
9644 case LVM_SETITEMTEXTW
:
9645 return LISTVIEW_SetItemTextT(infoPtr
, (INT
)wParam
, (LPLVITEMW
)lParam
, TRUE
);
9647 /* case LVN_SETOUTLINECOLOR: */
9649 /* case LVN_SETSELECTEDCOLUMN: */
9651 case LVM_SETSELECTIONMARK
:
9652 return LISTVIEW_SetSelectionMark(infoPtr
, (INT
)lParam
);
9654 case LVM_SETTEXTBKCOLOR
:
9655 return LISTVIEW_SetTextBkColor(infoPtr
, (COLORREF
)lParam
);
9657 case LVM_SETTEXTCOLOR
:
9658 return LISTVIEW_SetTextColor(infoPtr
, (COLORREF
)lParam
);
9660 /* case LVN_SETTILEINFO: */
9662 /* case LVN_SETTILEVIEWINFO: */
9664 /* case LVN_SETTILEWIDTH: */
9666 /* case LVM_SETTOOLTIPS: */
9668 /* case LVM_SETUNICODEFORMAT: */
9670 /* case LVN_SETVIEW: */
9672 /* case LVM_SETWORKAREAS: */
9674 /* case LVN_SORTGROUPS: */
9677 return LISTVIEW_SortItems(infoPtr
, (PFNLVCOMPARE
)lParam
, (LPARAM
)wParam
);
9679 case LVM_SUBITEMHITTEST
:
9680 return LISTVIEW_SubItemHitTest(infoPtr
, (LPLVHITTESTINFO
)lParam
);
9683 return LISTVIEW_Update(infoPtr
, (INT
)wParam
);
9686 return LISTVIEW_ProcessLetterKeys( infoPtr
, wParam
, lParam
);
9689 return LISTVIEW_Command(infoPtr
, wParam
, lParam
);
9692 return LISTVIEW_Create(hwnd
, (LPCREATESTRUCTW
)lParam
);
9695 return LISTVIEW_EraseBackground(infoPtr
, wParam
, lParam
);
9698 return DLGC_WANTCHARS
| DLGC_WANTARROWS
;
9701 return infoPtr
->hFont
;
9704 if (SLOWORD(wParam
) < 0) return 0; /* validate not internal codes */
9705 return LISTVIEW_HScroll(infoPtr
, (INT
)LOWORD(wParam
),
9706 (INT
)HIWORD(wParam
), (HWND
)lParam
);
9709 return LISTVIEW_KeyDown(infoPtr
, (INT
)wParam
, (LONG
)lParam
);
9712 return LISTVIEW_KillFocus(infoPtr
);
9714 case WM_LBUTTONDBLCLK
:
9715 return LISTVIEW_LButtonDblClk(infoPtr
, (WORD
)wParam
, MAKEPOINTS(lParam
));
9717 case WM_LBUTTONDOWN
:
9718 return LISTVIEW_LButtonDown(infoPtr
, (WORD
)wParam
, MAKEPOINTS(lParam
));
9721 return LISTVIEW_LButtonUp(infoPtr
, (WORD
)wParam
, MAKEPOINTS(lParam
));
9724 return LISTVIEW_MouseMove (infoPtr
, (WORD
)wParam
, MAKEPOINTS(lParam
));
9727 return LISTVIEW_MouseHover(infoPtr
, (WORD
)wParam
, MAKEPOINTS(lParam
));
9730 return LISTVIEW_NCDestroy(infoPtr
);
9733 return LISTVIEW_Notify(infoPtr
, (INT
)wParam
, (LPNMHDR
)lParam
);
9735 case WM_NOTIFYFORMAT
:
9736 return LISTVIEW_NotifyFormat(infoPtr
, (HWND
)wParam
, (INT
)lParam
);
9739 return LISTVIEW_Paint(infoPtr
, (HDC
)wParam
);
9741 case WM_RBUTTONDBLCLK
:
9742 return LISTVIEW_RButtonDblClk(infoPtr
, (WORD
)wParam
, MAKEPOINTS(lParam
));
9744 case WM_RBUTTONDOWN
:
9745 return LISTVIEW_RButtonDown(infoPtr
, (WORD
)wParam
, MAKEPOINTS(lParam
));
9748 return LISTVIEW_RButtonUp(infoPtr
, (WORD
)wParam
, MAKEPOINTS(lParam
));
9751 return LISTVIEW_SetCursor(infoPtr
, (HWND
)wParam
, LOWORD(lParam
), HIWORD(lParam
));
9754 return LISTVIEW_SetFocus(infoPtr
, (HWND
)wParam
);
9757 return LISTVIEW_SetFont(infoPtr
, (HFONT
)wParam
, (WORD
)lParam
);
9760 return LISTVIEW_SetRedraw(infoPtr
, (BOOL
)wParam
);
9763 return LISTVIEW_Size(infoPtr
, (int)SLOWORD(lParam
), (int)SHIWORD(lParam
));
9765 case WM_STYLECHANGED
:
9766 return LISTVIEW_StyleChanged(infoPtr
, wParam
, (LPSTYLESTRUCT
)lParam
);
9768 case WM_SYSCOLORCHANGE
:
9769 COMCTL32_RefreshSysColors();
9772 /* case WM_TIMER: */
9775 if (SLOWORD(wParam
) < 0) return 0; /* validate not internal codes */
9776 return LISTVIEW_VScroll(infoPtr
, (INT
)LOWORD(wParam
),
9777 (INT
)HIWORD(wParam
), (HWND
)lParam
);
9780 if (wParam
& (MK_SHIFT
| MK_CONTROL
))
9781 return DefWindowProcW(hwnd
, uMsg
, wParam
, lParam
);
9782 return LISTVIEW_MouseWheel(infoPtr
, (short int)HIWORD(wParam
));
9784 case WM_WINDOWPOSCHANGED
:
9785 if (!(((WINDOWPOS
*)lParam
)->flags
& SWP_NOSIZE
)) {
9786 SetWindowPos(infoPtr
->hwndSelf
, 0, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
|
9787 SWP_NOZORDER
| SWP_NOMOVE
| SWP_NOSIZE
);
9788 LISTVIEW_UpdateSize(infoPtr
);
9789 LISTVIEW_UpdateScroll(infoPtr
);
9791 return DefWindowProcW(hwnd
, uMsg
, wParam
, lParam
);
9793 /* case WM_WININICHANGE: */
9796 if ((uMsg
>= WM_USER
) && (uMsg
< WM_APP
))
9797 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg
, wParam
, lParam
);
9799 /* call default window procedure */
9800 return DefWindowProcW(hwnd
, uMsg
, wParam
, lParam
);
9808 * Registers the window class.
9816 VOID
LISTVIEW_Register(void)
9820 ZeroMemory(&wndClass
, sizeof(WNDCLASSW
));
9821 wndClass
.style
= CS_GLOBALCLASS
| CS_DBLCLKS
;
9822 wndClass
.lpfnWndProc
= (WNDPROC
)LISTVIEW_WindowProc
;
9823 wndClass
.cbClsExtra
= 0;
9824 wndClass
.cbWndExtra
= sizeof(LISTVIEW_INFO
*);
9825 wndClass
.hCursor
= LoadCursorW(0, IDC_ARROWW
);
9826 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
9827 wndClass
.lpszClassName
= WC_LISTVIEWW
;
9828 RegisterClassW(&wndClass
);
9833 * Unregisters the window class.
9841 VOID
LISTVIEW_Unregister(void)
9843 UnregisterClassW(WC_LISTVIEWW
, (HINSTANCE
)NULL
);
9848 * Handle any WM_COMMAND messages
9854 static LRESULT
LISTVIEW_Command(LISTVIEW_INFO
*infoPtr
, WPARAM wParam
, LPARAM lParam
)
9856 switch (HIWORD(wParam
))
9861 * Adjust the edit window size
9864 HDC hdc
= GetDC(infoPtr
->hwndEdit
);
9865 HFONT hFont
, hOldFont
= 0;
9870 len
= GetWindowTextW(infoPtr
->hwndEdit
, buffer
, sizeof(buffer
)/sizeof(buffer
[0]));
9871 GetWindowRect(infoPtr
->hwndEdit
, &rect
);
9873 /* Select font to get the right dimension of the string */
9874 hFont
= SendMessageW(infoPtr
->hwndEdit
, WM_GETFONT
, 0, 0);
9877 hOldFont
= SelectObject(hdc
, hFont
);
9880 if (GetTextExtentPoint32W(hdc
, buffer
, lstrlenW(buffer
), &sz
))
9882 TEXTMETRICW textMetric
;
9884 /* Add Extra spacing for the next character */
9885 GetTextMetricsW(hdc
, &textMetric
);
9886 sz
.cx
+= (textMetric
.tmMaxCharWidth
* 2);
9894 rect
.bottom
- rect
.top
,
9895 SWP_DRAWFRAME
|SWP_NOMOVE
);
9898 SelectObject(hdc
, hOldFont
);
9900 ReleaseDC(infoPtr
->hwndSelf
, hdc
);
9906 return SendMessageW (GetParent (infoPtr
->hwndSelf
), WM_COMMAND
, wParam
, lParam
);
9915 * Subclassed edit control windproc function
9921 static LRESULT
EditLblWndProcT(HWND hwnd
, UINT uMsg
,
9922 WPARAM wParam
, LPARAM lParam
, BOOL isW
)
9924 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(GetParent(hwnd
), 0);
9925 static BOOL bIgnoreKillFocus
= FALSE
;
9926 BOOL cancel
= FALSE
;
9928 TRACE("(hwnd=%x, uMsg=%x, wParam=%x, lParam=%lx, isW=%d)\n",
9929 hwnd
, uMsg
, wParam
, lParam
, isW
);
9934 return DLGC_WANTARROWS
| DLGC_WANTALLKEYS
;
9937 if(bIgnoreKillFocus
) return TRUE
;
9942 WNDPROC editProc
= infoPtr
->EditWndProc
;
9943 infoPtr
->EditWndProc
= 0;
9944 SetWindowLongW(hwnd
, GWL_WNDPROC
, (LONG
)editProc
);
9945 return CallWindowProcT(editProc
, hwnd
, uMsg
, wParam
, lParam
, isW
);
9949 if (VK_ESCAPE
== (INT
)wParam
)
9954 else if (VK_RETURN
== (INT
)wParam
)
9958 return CallWindowProcT(infoPtr
->EditWndProc
, hwnd
, uMsg
, wParam
, lParam
, isW
);
9961 if (infoPtr
->bEditing
)
9963 LPWSTR buffer
= NULL
;
9967 DWORD len
= isW
? GetWindowTextLengthW(hwnd
) : GetWindowTextLengthA(hwnd
);
9971 if ( (buffer
= COMCTL32_Alloc((len
+1) * (isW
? sizeof(WCHAR
) : sizeof(CHAR
)))) )
9973 if (isW
) GetWindowTextW(hwnd
, buffer
, len
+1);
9974 else GetWindowTextA(hwnd
, (CHAR
*)buffer
, len
+1);
9978 /* Processing LVN_ENDLABELEDIT message could kill the focus */
9979 /* eg. Using a messagebox */
9980 bIgnoreKillFocus
= TRUE
;
9981 LISTVIEW_EndEditLabelT(infoPtr
, buffer
, isW
);
9983 if (buffer
) COMCTL32_Free(buffer
);
9985 bIgnoreKillFocus
= FALSE
;
9988 SendMessageW(hwnd
, WM_CLOSE
, 0, 0);
9994 * Subclassed edit control windproc function
10000 LRESULT CALLBACK
EditLblWndProcW(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
10002 return EditLblWndProcT(hwnd
, uMsg
, wParam
, lParam
, TRUE
);
10007 * Subclassed edit control windproc function
10013 LRESULT CALLBACK
EditLblWndProcA(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
10015 return EditLblWndProcT(hwnd
, uMsg
, wParam
, lParam
, FALSE
);
10020 * Creates a subclassed edit cotrol
10026 static HWND
CreateEditLabelT(LISTVIEW_INFO
*infoPtr
, LPCWSTR text
, DWORD style
,
10027 INT x
, INT y
, INT width
, INT height
, BOOL isW
)
10029 WCHAR editName
[5] = { 'E', 'd', 'i', 't', '\0' };
10034 TEXTMETRICW textMetric
;
10035 HINSTANCE hinst
= GetWindowLongW(infoPtr
->hwndSelf
, GWL_HINSTANCE
);
10037 TRACE("(text=%s, ..., isW=%d)\n", debugstr_t(text
, isW
), isW
);
10039 style
|= WS_CHILDWINDOW
|WS_CLIPSIBLINGS
|ES_LEFT
|WS_BORDER
;
10040 hdc
= GetDC(infoPtr
->hwndSelf
);
10042 /* Select the font to get appropriate metric dimensions */
10043 if(infoPtr
->hFont
!= 0)
10044 hOldFont
= SelectObject(hdc
, infoPtr
->hFont
);
10046 /*Get String Lenght in pixels */
10047 GetTextExtentPoint32W(hdc
, text
, lstrlenW(text
), &sz
);
10049 /*Add Extra spacing for the next character */
10050 GetTextMetricsW(hdc
, &textMetric
);
10051 sz
.cx
+= (textMetric
.tmMaxCharWidth
* 2);
10053 if(infoPtr
->hFont
!= 0)
10054 SelectObject(hdc
, hOldFont
);
10056 ReleaseDC(infoPtr
->hwndSelf
, hdc
);
10058 hedit
= CreateWindowW(editName
, text
, style
, x
, y
, sz
.cx
, height
, infoPtr
->hwndSelf
, 0, hinst
, 0);
10060 hedit
= CreateWindowA("Edit", (LPCSTR
)text
, style
, x
, y
, sz
.cx
, height
, infoPtr
->hwndSelf
, 0, hinst
, 0);
10062 if (!hedit
) return 0;
10064 infoPtr
->EditWndProc
= (WNDPROC
)
10065 (isW
? SetWindowLongW(hedit
, GWL_WNDPROC
, (LONG
)EditLblWndProcW
) :
10066 SetWindowLongA(hedit
, GWL_WNDPROC
, (LONG
)EditLblWndProcA
) );
10068 SendMessageW(hedit
, WM_SETFONT
, infoPtr
->hFont
, FALSE
);