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_GetHotCursor : not implemented
41 * LISTVIEW_GetISearchString : not implemented
42 * LISTVIEW_GetBkImage : not implemented
43 * LISTVIEW_SetBkImage : not implemented
44 * LISTVIEW_GetColumnOrderArray : simple hack only
45 * LISTVIEW_SetColumnOrderArray : simple hack only
46 * LISTVIEW_Arrange : empty stub
47 * LISTVIEW_ApproximateViewRect : incomplete
48 * LISTVIEW_Scroll : not implemented
49 * LISTVIEW_Update : not completed
51 * Known differences in message stream from native control (not known if
52 * these differences cause problems):
53 * LVM_INSERTITEM issues LVM_SETITEMSTATE and LVM_SETITEM in certain cases.
54 * LVM_SETITEM does not always issue LVN_ITEMCHANGING/LVN_ITEMCHANGED.
55 * WM_PAINT does LVN_GETDISPINFO in item order 0->n, native does n->0.
56 * WM_SETREDRAW(True) native does LVN_GETDISPINFO for all items and
57 * does *not* invoke DefWindowProc
58 * WM_CREATE does not issue WM_QUERYUISTATE and associated registry
59 * processing for "USEDOUBLECLICKTIME".
71 #include "wine/debug.h"
73 WINE_DEFAULT_DEBUG_CHANNEL(listview
);
75 /* Some definitions for inline edit control */
76 typedef BOOL (*EditlblCallbackW
)(HWND
, LPWSTR
, DWORD
);
77 typedef BOOL (*EditlblCallbackA
)(HWND
, LPWSTR
, DWORD
);
79 typedef struct tagLV_INTHIT
82 DWORD distance
; /* distance to closest item */
83 INT iDistItem
; /* item number that is closest */
84 } LV_INTHIT
, *LPLV_INTHIT
;
87 typedef struct tagEDITLABEL_ITEM
91 EditlblCallbackW EditLblCb
;
94 typedef struct tagLISTVIEW_SUBITEM
101 typedef struct tagLISTVIEW_ITEM
112 typedef struct tagLISTVIEW_SELECTION
116 } LISTVIEW_SELECTION
;
118 typedef struct tagLISTVIEW_INFO
124 HIMAGELIST himlNormal
;
125 HIMAGELIST himlSmall
;
126 HIMAGELIST himlState
;
130 HDPA hdpaSelectionRanges
;
144 INT ntmHeight
; /* from GetTextMetrics from above font */
145 INT ntmAveCharWidth
; /* from GetTextMetrics from above font */
147 DWORD dwExStyle
; /* extended listview style */
149 PFNLVCOMPARE pfnCompare
;
153 EDITLABEL_ITEM
*pedititem
;
155 INT nColumnCount
; /* the number of columns in this control */
157 DWORD lastKeyPressTimestamp
; /* Added */
158 WPARAM charCode
; /* Added */
159 INT nSearchParamLength
; /* Added */
160 WCHAR szSearchParam
[ MAX_PATH
]; /* Added */
167 /* maximum size of a label */
168 #define DISP_TEXT_SIZE 512
170 /* padding for items in list and small icon display modes */
171 #define WIDTH_PADDING 12
173 /* padding for items in list, report and small icon display modes */
174 #define HEIGHT_PADDING 1
176 /* offset of items in report display mode */
177 #define REPORT_MARGINX 2
179 /* padding for icon in large icon display mode
180 * ICON_TOP_PADDING_NOTHITABLE - space between top of box and area
181 * that HITTEST will see.
182 * ICON_TOP_PADDING_HITABLE - spacing between above and icon.
183 * ICON_TOP_PADDING - sum of the two above.
184 * ICON_BOTTOM_PADDING - between bottom of icon and top of text
185 * LABEL_VERT_OFFSET - between bottom of text and end of box
187 #define ICON_TOP_PADDING_NOTHITABLE 2
188 #define ICON_TOP_PADDING_HITABLE 2
189 #define ICON_TOP_PADDING ICON_TOP_PADDING_NOTHITABLE + ICON_TOP_PADDING_HITABLE
190 #define ICON_BOTTOM_PADDING 4
191 #define LABEL_VERT_OFFSET 10
193 /* default label width for items in list and small icon display modes */
194 #define DEFAULT_LABEL_WIDTH 40
196 /* default column width for items in list display mode */
197 #define DEFAULT_COLUMN_WIDTH 96
199 /* Increment size of the horizontal scroll bar */
200 #define LISTVIEW_SCROLL_DIV_SIZE 10
202 /* Padding betwen image and label */
203 #define IMAGE_PADDING 2
205 /* Padding behind the label */
206 #define TRAILING_PADDING 5
208 /* Border for the icon caption */
209 #define CAPTION_BORDER 2
213 /* retrieve the number of items in the listview */
214 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
215 #define HDM_INSERTITEMT(isW) ( (isW) ? HDM_INSERTITEMW : HDM_INSERTITEMA )
217 HWND
CreateEditLabelT(LPCWSTR text
, DWORD style
, INT x
, INT y
,
218 INT width
, INT height
, HWND parent
, HINSTANCE hinst
,
219 EditlblCallbackW EditLblCb
, DWORD param
, BOOL isW
);
222 * forward declarations
224 static LRESULT
LISTVIEW_GetItemT(HWND hwnd
, LPLVITEMW lpLVItem
, BOOL internal
, BOOL isW
);
225 static INT
LISTVIEW_SuperHitTestItem(HWND
, LPLV_INTHIT
, BOOL
);
226 static INT
LISTVIEW_HitTestItem(HWND
, LPLVHITTESTINFO
, BOOL
);
227 static INT
LISTVIEW_GetCountPerRow(HWND
);
228 static INT
LISTVIEW_GetCountPerColumn(HWND
);
229 static VOID
LISTVIEW_AlignLeft(HWND
);
230 static VOID
LISTVIEW_AlignTop(HWND
);
231 static VOID
LISTVIEW_AddGroupSelection(HWND
, INT
);
232 static VOID
LISTVIEW_AddSelection(HWND
, INT
);
233 static BOOL
LISTVIEW_AddSubItemT(HWND
, LPLVITEMW
, BOOL
);
234 static INT
LISTVIEW_FindInsertPosition(HDPA
, INT
);
235 static INT
LISTVIEW_GetItemHeight(HWND
);
236 static BOOL
LISTVIEW_GetItemBoundBox(HWND
, INT
, LPRECT
);
237 static BOOL
LISTVIEW_GetItemPosition(HWND
, INT
, LPPOINT
);
238 static LRESULT
LISTVIEW_GetItemRect(HWND
, INT
, LPRECT
);
239 static INT
LISTVIEW_GetItemWidth(HWND
);
240 static INT
LISTVIEW_GetLabelWidth(HWND
, INT
);
241 static LRESULT
LISTVIEW_GetOrigin(HWND
, LPPOINT
);
242 static INT
LISTVIEW_CalculateWidth(HWND hwnd
, INT nItem
);
243 static LISTVIEW_SUBITEM
* LISTVIEW_GetSubItem(HDPA
, INT
);
244 static LRESULT
LISTVIEW_GetViewRect(HWND
, LPRECT
);
245 static BOOL
LISTVIEW_InitItemT(HWND
, LISTVIEW_ITEM
*, LPLVITEMW
, BOOL
);
246 static BOOL
LISTVIEW_InitSubItemT(HWND
, LISTVIEW_SUBITEM
*, LPLVITEMW
, BOOL
);
247 static LRESULT
LISTVIEW_MouseSelection(HWND
, POINT
);
248 static BOOL
LISTVIEW_RemoveColumn(HDPA
, INT
);
249 static BOOL
LISTVIEW_RemoveSubItem(HDPA
, INT
);
250 static VOID
LISTVIEW_SetGroupSelection(HWND
, INT
);
251 static BOOL
LISTVIEW_SetItemT(HWND
, LPLVITEMW
, BOOL
);
252 static BOOL
LISTVIEW_SetItemFocus(HWND
, INT
);
253 static BOOL
LISTVIEW_SetItemPosition(HWND
, INT
, LONG
, LONG
);
254 static VOID
LISTVIEW_UpdateScroll(HWND
);
255 static VOID
LISTVIEW_SetSelection(HWND
, INT
);
256 static VOID
LISTVIEW_UpdateSize(HWND
);
257 static BOOL
LISTVIEW_SetSubItemT(HWND
, LPLVITEMW
, BOOL
);
258 static LRESULT
LISTVIEW_SetViewRect(HWND
, LPRECT
);
259 static BOOL
LISTVIEW_ToggleSelection(HWND
, INT
);
260 static VOID
LISTVIEW_UnsupportedStyles(LONG lStyle
);
261 static HWND
LISTVIEW_EditLabelT(HWND hwnd
, INT nItem
, BOOL isW
);
262 static BOOL
LISTVIEW_EndEditLabelW(HWND hwnd
, LPWSTR pszText
, DWORD nItem
);
263 static BOOL
LISTVIEW_EndEditLabelA(HWND hwnd
, LPSTR pszText
, DWORD nItem
);
264 static LRESULT
LISTVIEW_Command(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
265 static LRESULT
LISTVIEW_SortItems(HWND hwnd
, PFNLVCOMPARE pfnCompare
, LPARAM lParamSort
);
266 static LRESULT
LISTVIEW_GetStringWidthT(HWND hwnd
, LPCWSTR lpszText
, BOOL isW
);
267 static INT
LISTVIEW_ProcessLetterKeys( HWND hwnd
, WPARAM charCode
, LPARAM keyData
);
268 static BOOL
LISTVIEW_KeySelection(HWND hwnd
, INT nItem
);
269 static LRESULT
LISTVIEW_GetItemState(HWND hwnd
, INT nItem
, UINT uMask
);
270 static LRESULT
LISTVIEW_SetItemState(HWND hwnd
, INT nItem
, LPLVITEMW lpLVItem
);
271 static BOOL
LISTVIEW_IsSelected(HWND hwnd
, INT nItem
);
272 static VOID
LISTVIEW_RemoveSelectionRange(HWND hwnd
, INT lItem
, INT uItem
);
273 static void LISTVIEW_FillBackground(HWND hwnd
, HDC hdc
, LPRECT rc
);
274 static void ListView_UpdateLargeItemLabelRect (HWND hwnd
, const LISTVIEW_INFO
* infoPtr
, int nItem
, RECT
*rect
);
276 /******** Defines that LISTVIEW_ProcessLetterKeys uses ****************/
277 #define KEY_DELAY 450
279 #define COUNTOF(array) (sizeof(array)/sizeof(array[0]))
281 static inline BOOL
is_textW(LPCWSTR text
)
283 return text
!= NULL
&& text
!= LPSTR_TEXTCALLBACKW
;
286 static inline BOOL
is_textT(LPCWSTR text
, BOOL isW
)
288 /* we can ignore isW since LPSTR_TEXTCALLBACKW == LPSTR_TEXTCALLBACKA */
289 return is_textW(text
);
292 static inline int textlenT(LPCWSTR text
, BOOL isW
)
294 return !is_textT(text
, isW
) ? 0 :
295 isW
? lstrlenW(text
) : lstrlenA((LPCSTR
)text
);
298 static inline void textcpynT(LPWSTR dest
, BOOL isDestW
, LPCWSTR src
, BOOL isSrcW
, INT max
)
301 if (isSrcW
) lstrcpynW(dest
, src
, max
);
302 else MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)src
, -1, dest
, max
);
304 if (isSrcW
) WideCharToMultiByte(CP_ACP
, 0, src
, -1, (LPSTR
)dest
, max
, NULL
, NULL
);
305 else lstrcpynA((LPSTR
)dest
, (LPCSTR
)src
, max
);
308 static inline LPCSTR
debugstr_t(LPCWSTR text
, BOOL isW
)
310 return isW
? debugstr_w(text
) : debugstr_a((LPCSTR
)text
);
313 static inline LPCSTR
debugstr_tn(LPCWSTR text
, BOOL isW
, INT n
)
315 return isW
? debugstr_wn(text
, n
) : debugstr_an((LPCSTR
)text
, n
);
318 static inline LPWSTR
textdupTtoW(LPCWSTR text
, BOOL isW
)
320 LPWSTR wstr
= (LPWSTR
)text
;
322 TRACE("(text=%s, isW=%d)\n", debugstr_t(text
, isW
), isW
);
325 INT len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)text
, -1, NULL
, 0);
326 wstr
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
327 if (wstr
) MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)text
, -1, wstr
, len
);
329 TRACE(" wstr=%s\n", debugstr_w(wstr
));
333 static inline void textfreeT(LPWSTR wstr
, BOOL isW
)
335 if (!isW
&& wstr
) HeapFree(GetProcessHeap(), 0, wstr
);
339 * dest is a pointer to a Unicode string
340 * src is a pointer to a string (Unicode if isW, ANSI if !isW)
342 static inline BOOL
textsetptrT(LPWSTR
*dest
, LPWSTR src
, BOOL isW
)
344 LPWSTR pszText
= textdupTtoW(src
, isW
);
346 if (*dest
== LPSTR_TEXTCALLBACKW
) *dest
= NULL
;
347 bResult
= Str_SetPtrW(dest
, pszText
);
348 textfreeT(pszText
, isW
);
352 static inline LRESULT
CallWindowProcT(WNDPROC proc
, HWND hwnd
, UINT uMsg
,
353 WPARAM wParam
, LPARAM lParam
, BOOL isW
)
356 return CallWindowProcW(proc
, hwnd
, uMsg
, wParam
, lParam
);
358 return CallWindowProcA(proc
, hwnd
, uMsg
, wParam
, lParam
);
361 static inline BOOL
notify(HWND self
, INT code
, LPNMHDR pnmh
)
363 pnmh
->hwndFrom
= self
;
364 pnmh
->idFrom
= GetWindowLongW(self
, GWL_ID
);
366 return (BOOL
)SendMessageW(GetParent(self
), WM_NOTIFY
,
367 (WPARAM
)pnmh
->idFrom
, (LPARAM
)pnmh
);
370 static inline BOOL
hdr_notify(HWND self
, INT code
)
373 return notify(self
, code
, &nmh
);
376 static inline BOOL
listview_notify(HWND self
, INT code
, LPNMLISTVIEW plvnm
)
378 return notify(self
, code
, (LPNMHDR
)plvnm
);
381 static int tabNotification
[] = {
382 LVN_BEGINLABELEDITW
, LVN_BEGINLABELEDITA
,
383 LVN_ENDLABELEDITW
, LVN_ENDLABELEDITA
,
384 LVN_GETDISPINFOW
, LVN_GETDISPINFOA
,
385 LVN_SETDISPINFOW
, LVN_SETDISPINFOA
,
386 LVN_ODFINDITEMW
, LVN_ODFINDITEMA
,
387 LVN_GETINFOTIPW
, LVN_GETINFOTIPA
,
391 static int get_ansi_notification(INT unicodeNotificationCode
)
393 int *pTabNotif
= tabNotification
;
394 while (*pTabNotif
&& (unicodeNotificationCode
!= *pTabNotif
++));
395 if (*pTabNotif
) return *pTabNotif
;
396 ERR("unknown notification %x\n", unicodeNotificationCode
);
397 return unicodeNotificationCode
;
401 Send notification. depends on dispinfoW having same
402 structure as dispinfoA.
403 self : listview handle
404 notificationCode : *Unicode* notification code
405 pdi : dispinfo structure (can be unicode or ansi)
406 isW : TRUE if dispinfo is Unicode
408 static BOOL
dispinfo_notifyT(HWND self
, INT notificationCode
, LPNMLVDISPINFOW pdi
, BOOL isW
)
410 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(self
, 0);
411 BOOL bResult
= FALSE
;
412 BOOL convertToAnsi
= FALSE
, convertToUnicode
= FALSE
;
414 INT cchTempBufMax
= 0, savCchTextMax
= 0;
415 LPWSTR pszTempBuf
= NULL
, savPszText
= NULL
;
417 TRACE("(self=%x, code=%x, pdi=%p, isW=%d)\n", self
, notificationCode
, pdi
, isW
);
418 TRACE(" notifyFormat=%s\n",
419 infoPtr
->notifyFormat
== NFR_UNICODE
? "NFR_UNICODE" :
420 infoPtr
->notifyFormat
== NFR_ANSI
? "NFR_ANSI" : "(not set)");
421 if (infoPtr
->notifyFormat
== NFR_ANSI
)
422 realNotifCode
= get_ansi_notification(notificationCode
);
424 realNotifCode
= notificationCode
;
426 if (is_textT(pdi
->item
.pszText
, isW
))
428 if (isW
&& infoPtr
->notifyFormat
== NFR_ANSI
)
429 convertToAnsi
= TRUE
;
430 if (!isW
&& infoPtr
->notifyFormat
== NFR_UNICODE
)
431 convertToUnicode
= TRUE
;
434 if (convertToAnsi
|| convertToUnicode
)
436 TRACE(" we have to convert the text to the correct format\n");
437 if (notificationCode
!= LVN_GETDISPINFOW
)
438 { /* length of existing text */
439 cchTempBufMax
= convertToUnicode
?
440 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pdi
->item
.pszText
, -1, NULL
, 0):
441 WideCharToMultiByte(CP_ACP
, 0, pdi
->item
.pszText
, -1, NULL
, 0, NULL
, NULL
);
444 cchTempBufMax
= pdi
->item
.cchTextMax
;
446 pszTempBuf
= HeapAlloc(GetProcessHeap(), 0,
447 (convertToUnicode
? sizeof(WCHAR
) : sizeof(CHAR
)) * cchTempBufMax
);
448 if (!pszTempBuf
) return FALSE
;
449 if (convertToUnicode
)
450 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pdi
->item
.pszText
, -1,
451 pszTempBuf
, cchTempBufMax
);
453 WideCharToMultiByte(CP_ACP
, 0, pdi
->item
.pszText
, -1, (LPSTR
) pszTempBuf
,
454 cchTempBufMax
, NULL
, NULL
);
455 TRACE(" text=%s\n", debugstr_t(pszTempBuf
, convertToUnicode
));
456 savCchTextMax
= pdi
->item
.cchTextMax
;
457 savPszText
= pdi
->item
.pszText
;
458 pdi
->item
.pszText
= pszTempBuf
;
459 pdi
->item
.cchTextMax
= cchTempBufMax
;
462 bResult
= notify(self
, realNotifCode
, (LPNMHDR
)pdi
);
464 if (convertToUnicode
|| convertToAnsi
)
465 { /* convert back result */
466 TRACE(" returned text=%s\n", debugstr_t(pdi
->item
.pszText
, convertToUnicode
));
467 if (convertToUnicode
) /* note : pointer can be changed by app ! */
468 WideCharToMultiByte(CP_ACP
, 0, pdi
->item
.pszText
, -1, (LPSTR
) savPszText
,
469 savCchTextMax
, NULL
, NULL
);
471 MultiByteToWideChar(CP_ACP
, 0, (LPSTR
) pdi
->item
.pszText
, -1,
472 savPszText
, savCchTextMax
);
473 pdi
->item
.pszText
= savPszText
; /* restores our buffer */
474 pdi
->item
.cchTextMax
= savCchTextMax
;
475 HeapFree(GetProcessHeap(), 0, pszTempBuf
);
480 static inline LRESULT
LISTVIEW_GetItemW(HWND hwnd
, LPLVITEMW lpLVItem
, BOOL internal
)
482 return LISTVIEW_GetItemT(hwnd
, lpLVItem
, internal
, TRUE
);
485 static inline int lstrncmpiW(LPCWSTR s1
, LPCWSTR s2
, int n
)
489 n
= min(min(n
, strlenW(s1
)), strlenW(s2
));
490 res
= CompareStringW(LOCALE_USER_DEFAULT
, NORM_IGNORECASE
, s1
, n
, s2
, n
);
491 return res
? res
- 2 : res
;
494 static char* debuglvitem_t(LPLVITEMW lpLVItem
, BOOL isW
)
496 static int index
= 0;
497 static char buffers
[20][256];
498 char* buf
= buffers
[index
++ % 20];
499 if (lpLVItem
== NULL
) return "(null)";
500 snprintf(buf
, 256, "{mask=%x, iItem=%d, iSubItem=%d, state=%x, stateMask=%x,"
501 " pszText=%s, cchTextMax=%d, iImage=%d, lParam=%lx, iIndent=%d}",
502 lpLVItem
->mask
, lpLVItem
->iItem
, lpLVItem
->iSubItem
,
503 lpLVItem
->state
, lpLVItem
->stateMask
,
504 lpLVItem
->pszText
== LPSTR_TEXTCALLBACKW
? "(callback)" :
505 debugstr_tn(lpLVItem
->pszText
, isW
, 80),
506 lpLVItem
->cchTextMax
, lpLVItem
->iImage
, lpLVItem
->lParam
,
511 static char* debuglvcolumn_t(LPLVCOLUMNW lpColumn
, BOOL isW
)
513 static int index
= 0;
514 static char buffers
[20][256];
515 char* buf
= buffers
[index
++ % 20];
516 if (lpColumn
== NULL
) return "(null)";
517 snprintf(buf
, 256, "{mask=%x, fmt=%x, cx=%d,"
518 " pszText=%s, cchTextMax=%d, iSubItem=%d}",
519 lpColumn
->mask
, lpColumn
->fmt
, lpColumn
->cx
,
520 lpColumn
->mask
& LVCF_TEXT
? lpColumn
->pszText
== LPSTR_TEXTCALLBACKW
? "(callback)" :
521 debugstr_tn(lpColumn
->pszText
, isW
, 80): "",
522 lpColumn
->mask
& LVCF_TEXT
? lpColumn
->cchTextMax
: 0, lpColumn
->iSubItem
);
526 static void LISTVIEW_DumpListview(LISTVIEW_INFO
*iP
, INT line
)
528 DWORD dwStyle
= GetWindowLongW (iP
->hwndSelf
, GWL_STYLE
);
529 TRACE("listview %08x at line %d, clrBk=0x%06lx, clrText=0x%06lx, clrTextBk=0x%06lx, ItemHeight=%d, ItemWidth=%d, Style=0x%08lx\n",
530 iP
->hwndSelf
, line
, iP
->clrBk
, iP
->clrText
, iP
->clrTextBk
,
531 iP
->nItemHeight
, iP
->nItemWidth
, dwStyle
);
532 TRACE("listview %08x at line %d, himlNor=%p, himlSml=%p, himlState=%p, Focused=%d, Hot=%d, exStyle=0x%08lx\n",
533 iP
->hwndSelf
, line
, iP
->himlNormal
, iP
->himlSmall
, iP
->himlState
,
534 iP
->nFocusedItem
, iP
->nHotItem
, iP
->dwExStyle
);
538 LISTVIEW_SendCustomDrawNotify (HWND hwnd
, DWORD dwDrawStage
, HDC hdc
,
541 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
542 NMLVCUSTOMDRAW nmcdhdr
;
545 TRACE("(hwnd=%x, dwDrawStage=%lx, hdc=%x, rc=?)\n", hwnd
, dwDrawStage
, hdc
);
547 nmcd
= & nmcdhdr
.nmcd
;
548 nmcd
->hdr
.hwndFrom
= hwnd
;
549 nmcd
->hdr
.idFrom
= GetWindowLongW( hwnd
, GWL_ID
);
550 nmcd
->hdr
.code
= NM_CUSTOMDRAW
;
551 nmcd
->dwDrawStage
= dwDrawStage
;
553 nmcd
->rc
.left
= rc
.left
;
554 nmcd
->rc
.right
= rc
.right
;
555 nmcd
->rc
.bottom
= rc
.bottom
;
556 nmcd
->rc
.top
= rc
.top
;
557 nmcd
->dwItemSpec
= 0;
558 nmcd
->uItemState
= 0;
559 nmcd
->lItemlParam
= 0;
560 nmcdhdr
.clrText
= infoPtr
->clrText
;
561 nmcdhdr
.clrTextBk
= infoPtr
->clrBk
;
563 return (BOOL
)SendMessageW (GetParent (hwnd
), WM_NOTIFY
,
564 (WPARAM
) GetWindowLongW( hwnd
, GWL_ID
), (LPARAM
)&nmcdhdr
);
568 LISTVIEW_SendCustomDrawItemNotify (HWND hwnd
, HDC hdc
,
569 UINT iItem
, UINT iSubItem
,
572 LISTVIEW_INFO
*infoPtr
;
573 NMLVCUSTOMDRAW nmcdhdr
;
575 DWORD dwDrawStage
,dwItemSpec
;
581 infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
583 ZeroMemory(&item
,sizeof(item
));
585 item
.mask
= LVIF_PARAM
;
586 ListView_GetItemW(hwnd
,&item
);
588 dwDrawStage
=CDDS_ITEM
| uItemDrawState
;
592 if (LISTVIEW_IsSelected(hwnd
,iItem
)) uItemState
|=CDIS_SELECTED
;
593 if (iItem
==infoPtr
->nFocusedItem
) uItemState
|=CDIS_FOCUS
;
594 if (iItem
==infoPtr
->nHotItem
) uItemState
|=CDIS_HOT
;
596 itemRect
.left
= LVIR_BOUNDS
;
597 LISTVIEW_GetItemRect(hwnd
, iItem
, &itemRect
);
599 nmcd
= & nmcdhdr
.nmcd
;
600 nmcd
->hdr
.hwndFrom
= hwnd
;
601 nmcd
->hdr
.idFrom
= GetWindowLongW( hwnd
, GWL_ID
);
602 nmcd
->hdr
.code
= NM_CUSTOMDRAW
;
603 nmcd
->dwDrawStage
= dwDrawStage
;
605 nmcd
->rc
.left
= itemRect
.left
;
606 nmcd
->rc
.right
= itemRect
.right
;
607 nmcd
->rc
.bottom
= itemRect
.bottom
;
608 nmcd
->rc
.top
= itemRect
.top
;
609 nmcd
->dwItemSpec
= dwItemSpec
;
610 nmcd
->uItemState
= uItemState
;
611 nmcd
->lItemlParam
= item
.lParam
;
612 nmcdhdr
.clrText
= infoPtr
->clrText
;
613 nmcdhdr
.clrTextBk
= infoPtr
->clrBk
;
614 nmcdhdr
.iSubItem
=iSubItem
;
616 TRACE("drawstage=%lx hdc=%x item=%lx, itemstate=%x, lItemlParam=%lx\n",
617 nmcd
->dwDrawStage
, nmcd
->hdc
, nmcd
->dwItemSpec
,
618 nmcd
->uItemState
, nmcd
->lItemlParam
);
620 retval
=SendMessageW (GetParent (hwnd
), WM_NOTIFY
,
621 (WPARAM
) GetWindowLongW( hwnd
, GWL_ID
), (LPARAM
)&nmcdhdr
);
623 infoPtr
->clrText
=nmcdhdr
.clrText
;
624 infoPtr
->clrBk
=nmcdhdr
.clrTextBk
;
625 return (BOOL
) retval
;
629 /*************************************************************************
630 * LISTVIEW_ProcessLetterKeys
632 * Processes keyboard messages generated by pressing the letter keys
634 * What this does is perform a case insensitive search from the
635 * current position with the following quirks:
636 * - If two chars or more are pressed in quick succession we search
637 * for the corresponding string (e.g. 'abc').
638 * - If there is a delay we wipe away the current search string and
639 * restart with just that char.
640 * - If the user keeps pressing the same character, whether slowly or
641 * fast, so that the search string is entirely composed of this
642 * character ('aaaaa' for instance), then we search for first item
643 * that starting with that character.
644 * - If the user types the above character in quick succession, then
645 * we must also search for the corresponding string ('aaaaa'), and
646 * go to that string if there is a match.
654 * - The current implementation has a list of characters it will
655 * accept and it ignores averything else. In particular it will
656 * ignore accentuated characters which seems to match what
657 * Windows does. But I'm not sure it makes sense to follow
659 * - We don't sound a beep when the search fails.
663 * TREEVIEW_ProcessLetterKeys
665 static INT
LISTVIEW_ProcessLetterKeys(
666 HWND hwnd
, /* handle to the window */
667 WPARAM charCode
, /* the character code, the actual character */
668 LPARAM keyData
/* key data */
671 LISTVIEW_INFO
*infoPtr
;
676 WCHAR buffer
[MAX_PATH
];
677 DWORD timestamp
,elapsed
;
679 /* simple parameter checking */
680 if (!hwnd
|| !charCode
|| !keyData
)
683 infoPtr
=(LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
687 /* only allow the valid WM_CHARs through */
688 if (!isalnum(charCode
) &&
689 charCode
!= '.' && charCode
!= '`' && charCode
!= '!' &&
690 charCode
!= '@' && charCode
!= '#' && charCode
!= '$' &&
691 charCode
!= '%' && charCode
!= '^' && charCode
!= '&' &&
692 charCode
!= '*' && charCode
!= '(' && charCode
!= ')' &&
693 charCode
!= '-' && charCode
!= '_' && charCode
!= '+' &&
694 charCode
!= '=' && charCode
!= '\\'&& charCode
!= ']' &&
695 charCode
!= '}' && charCode
!= '[' && charCode
!= '{' &&
696 charCode
!= '/' && charCode
!= '?' && charCode
!= '>' &&
697 charCode
!= '<' && charCode
!= ',' && charCode
!= '~')
700 nSize
=GETITEMCOUNT(infoPtr
);
701 /* if there's one item or less, there is no where to go */
705 /* compute how much time elapsed since last keypress */
706 timestamp
=GetTickCount();
707 if (timestamp
> infoPtr
->lastKeyPressTimestamp
) {
708 elapsed
=timestamp
-infoPtr
->lastKeyPressTimestamp
;
710 elapsed
=infoPtr
->lastKeyPressTimestamp
-timestamp
;
713 /* update the search parameters */
714 infoPtr
->lastKeyPressTimestamp
=timestamp
;
715 if (elapsed
< KEY_DELAY
) {
716 if (infoPtr
->nSearchParamLength
< COUNTOF(infoPtr
->szSearchParam
)) {
717 infoPtr
->szSearchParam
[infoPtr
->nSearchParamLength
++]=charCode
;
719 if (infoPtr
->charCode
!= charCode
) {
720 infoPtr
->charCode
=charCode
=0;
723 infoPtr
->charCode
=charCode
;
724 infoPtr
->szSearchParam
[0]=charCode
;
725 infoPtr
->nSearchParamLength
=1;
726 /* Redundant with the 1 char string */
730 /* and search from the current position */
732 if (infoPtr
->nFocusedItem
>= 0) {
733 endidx
=infoPtr
->nFocusedItem
;
735 /* if looking for single character match,
736 * then we must always move forward
738 if (infoPtr
->nSearchParamLength
== 1)
752 ZeroMemory(&item
, sizeof(item
));
753 item
.mask
= LVIF_TEXT
;
756 item
.pszText
= buffer
;
757 item
.cchTextMax
= COUNTOF(buffer
);
758 ListView_GetItemW( hwnd
, &item
);
760 /* check for a match */
761 if (lstrncmpiW(item
.pszText
,infoPtr
->szSearchParam
,infoPtr
->nSearchParamLength
) == 0) {
764 } else if ( (charCode
!= 0) && (nItem
== -1) && (nItem
!= infoPtr
->nFocusedItem
) &&
765 (lstrncmpiW(item
.pszText
,infoPtr
->szSearchParam
,1) == 0) ) {
766 /* This would work but we must keep looking for a longer match */
770 } while (idx
!= endidx
);
773 if (LISTVIEW_KeySelection(hwnd
, nItem
) != FALSE
) {
774 /* refresh client area */
775 InvalidateRect(hwnd
, NULL
, TRUE
);
783 /*************************************************************************
784 * LISTVIEW_UpdateHeaderSize [Internal]
786 * Function to resize the header control
789 * hwnd [I] handle to a window
790 * nNewScrollPos [I] Scroll Pos to Set
797 static VOID
LISTVIEW_UpdateHeaderSize(HWND hwnd
, INT nNewScrollPos
)
799 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
803 GetWindowRect(infoPtr
->hwndHeader
, &winRect
);
804 point
[0].x
= winRect
.left
;
805 point
[0].y
= winRect
.top
;
806 point
[1].x
= winRect
.right
;
807 point
[1].y
= winRect
.bottom
;
809 MapWindowPoints(HWND_DESKTOP
, hwnd
, point
, 2);
810 point
[0].x
= -(nNewScrollPos
* LISTVIEW_SCROLL_DIV_SIZE
);
811 point
[1].x
+= (nNewScrollPos
* LISTVIEW_SCROLL_DIV_SIZE
);
813 SetWindowPos(infoPtr
->hwndHeader
,0,
814 point
[0].x
,point
[0].y
,point
[1].x
,point
[1].y
,
815 SWP_NOZORDER
| SWP_NOACTIVATE
);
820 * Update the scrollbars. This functions should be called whenever
821 * the content, size or view changes.
824 * [I] HWND : window handle
829 static VOID
LISTVIEW_UpdateScroll(HWND hwnd
)
831 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
832 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
833 UINT uView
= lStyle
& LVS_TYPEMASK
;
834 INT nListHeight
= infoPtr
->rcList
.bottom
- infoPtr
->rcList
.top
;
835 INT nListWidth
= infoPtr
->rcList
.right
- infoPtr
->rcList
.left
;
836 SCROLLINFO scrollInfo
;
838 if (lStyle
& LVS_NOSCROLL
) return;
840 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
841 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
843 if (uView
== LVS_LIST
)
845 /* update horizontal scrollbar */
847 INT nCountPerColumn
= LISTVIEW_GetCountPerColumn(hwnd
);
848 INT nCountPerRow
= LISTVIEW_GetCountPerRow(hwnd
);
849 INT nNumOfItems
= GETITEMCOUNT(infoPtr
);
851 scrollInfo
.nMax
= nNumOfItems
/ nCountPerColumn
;
852 if((nNumOfItems
% nCountPerColumn
) == 0)
856 scrollInfo
.nPos
= ListView_GetTopIndex(hwnd
) / nCountPerColumn
;
857 scrollInfo
.nPage
= nCountPerRow
;
858 scrollInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
859 SetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
, TRUE
);
860 ShowScrollBar(hwnd
, SB_VERT
, FALSE
);
862 else if (uView
== LVS_REPORT
)
864 /* update vertical scrollbar */
866 scrollInfo
.nMax
= GETITEMCOUNT(infoPtr
) - 1;
867 scrollInfo
.nPos
= ListView_GetTopIndex(hwnd
);
868 scrollInfo
.nPage
= LISTVIEW_GetCountPerColumn(hwnd
);
869 scrollInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
870 SetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
, TRUE
);
872 /* update horizontal scrollbar */
873 nListWidth
= infoPtr
->rcList
.right
- infoPtr
->rcList
.left
;
874 if (GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
) == FALSE
875 || GETITEMCOUNT(infoPtr
) == 0)
880 scrollInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
881 scrollInfo
.nPage
= nListWidth
/ LISTVIEW_SCROLL_DIV_SIZE
;
882 scrollInfo
.nMax
= max(infoPtr
->nItemWidth
/ LISTVIEW_SCROLL_DIV_SIZE
, 0)-1;
883 SetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
, TRUE
);
885 /* Update the Header Control */
886 scrollInfo
.fMask
= SIF_POS
;
887 GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
);
888 LISTVIEW_UpdateHeaderSize(hwnd
, scrollInfo
.nPos
);
895 if (LISTVIEW_GetViewRect(hwnd
, &rcView
) != FALSE
)
897 INT nViewWidth
= rcView
.right
- rcView
.left
;
898 INT nViewHeight
= rcView
.bottom
- rcView
.top
;
900 /* Update Horizontal Scrollbar */
901 scrollInfo
.fMask
= SIF_POS
;
902 if (GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
) == FALSE
903 || GETITEMCOUNT(infoPtr
) == 0)
907 scrollInfo
.nMax
= max(nViewWidth
/ LISTVIEW_SCROLL_DIV_SIZE
, 0)-1;
909 scrollInfo
.nPage
= nListWidth
/ LISTVIEW_SCROLL_DIV_SIZE
;
910 scrollInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
911 SetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
, TRUE
);
913 /* Update Vertical Scrollbar */
914 nListHeight
= infoPtr
->rcList
.bottom
- infoPtr
->rcList
.top
;
915 scrollInfo
.fMask
= SIF_POS
;
916 if (GetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
) == FALSE
917 || GETITEMCOUNT(infoPtr
) == 0)
921 scrollInfo
.nMax
= max(nViewHeight
/ LISTVIEW_SCROLL_DIV_SIZE
,0)-1;
923 scrollInfo
.nPage
= nListHeight
/ LISTVIEW_SCROLL_DIV_SIZE
;
924 scrollInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
925 SetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
, TRUE
);
932 * Prints a message for unsupported window styles.
933 * A kind of TODO list for window styles.
936 * [I] LONG : window style
941 static VOID
LISTVIEW_UnsupportedStyles(LONG lStyle
)
943 if ((LVS_TYPESTYLEMASK
& lStyle
) == LVS_NOSCROLL
)
944 FIXME(" LVS_NOSCROLL\n");
946 if ((LVS_TYPESTYLEMASK
& lStyle
) == LVS_NOSORTHEADER
)
947 FIXME(" LVS_NOSORTHEADER\n");
949 if (lStyle
& LVS_EDITLABELS
)
950 FIXME(" LVS_EDITLABELS\n");
952 if (lStyle
& LVS_NOLABELWRAP
)
953 FIXME(" LVS_NOLABELWRAP\n");
955 if (lStyle
& LVS_SHAREIMAGELISTS
)
956 FIXME(" LVS_SHAREIMAGELISTS\n");
958 if (lStyle
& LVS_SORTASCENDING
)
959 FIXME(" LVS_SORTASCENDING\n");
961 if (lStyle
& LVS_SORTDESCENDING
)
962 FIXME(" LVS_SORTDESCENDING\n");
967 * Aligns the items with the top edge of the window.
970 * [I] HWND : window handle
975 static VOID
LISTVIEW_AlignTop(HWND hwnd
)
977 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
978 UINT uView
= GetWindowLongW(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
979 INT nListWidth
= infoPtr
->rcList
.right
- infoPtr
->rcList
.left
;
982 INT i
, off_x
=0, off_y
=0;
984 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
986 /* Since SetItemPosition uses upper-left of icon, and for
987 style=LVS_ICON the icon is not left adjusted, get the offset */
988 if (uView
== LVS_ICON
)
990 off_y
= ICON_TOP_PADDING
;
991 off_x
= (infoPtr
->iconSpacing
.cx
- infoPtr
->iconSize
.cx
) / 2;
995 ZeroMemory(&rcView
, sizeof(RECT
));
997 if (nListWidth
> infoPtr
->nItemWidth
)
999 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
1001 if (ptItem
.x
+ infoPtr
->nItemWidth
> nListWidth
)
1004 ptItem
.y
+= infoPtr
->nItemHeight
;
1007 LISTVIEW_SetItemPosition(hwnd
, i
, ptItem
.x
, ptItem
.y
);
1008 ptItem
.x
+= infoPtr
->nItemWidth
;
1009 rcView
.right
= max(rcView
.right
, ptItem
.x
);
1012 rcView
.bottom
= ptItem
.y
+ infoPtr
->nItemHeight
;
1016 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
1018 LISTVIEW_SetItemPosition(hwnd
, i
, ptItem
.x
, ptItem
.y
);
1019 ptItem
.y
+= infoPtr
->nItemHeight
;
1022 rcView
.right
= infoPtr
->nItemWidth
;
1023 rcView
.bottom
= ptItem
.y
;
1026 LISTVIEW_SetViewRect(hwnd
, &rcView
);
1032 * Aligns the items with the left edge of the window.
1035 * [I] HWND : window handle
1040 static VOID
LISTVIEW_AlignLeft(HWND hwnd
)
1042 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
1043 UINT uView
= GetWindowLongW(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
1044 INT nListHeight
= infoPtr
->rcList
.bottom
- infoPtr
->rcList
.top
;
1047 INT i
, off_x
=0, off_y
=0;
1049 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
1051 /* Since SetItemPosition uses upper-left of icon, and for
1052 style=LVS_ICON the icon is not left adjusted, get the offset */
1053 if (uView
== LVS_ICON
)
1055 off_y
= ICON_TOP_PADDING
;
1056 off_x
= (infoPtr
->iconSpacing
.cx
- infoPtr
->iconSize
.cx
) / 2;
1060 ZeroMemory(&rcView
, sizeof(RECT
));
1062 if (nListHeight
> infoPtr
->nItemHeight
)
1064 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
1066 if (ptItem
.y
+ infoPtr
->nItemHeight
> nListHeight
)
1069 ptItem
.x
+= infoPtr
->nItemWidth
;
1072 LISTVIEW_SetItemPosition(hwnd
, i
, ptItem
.x
, ptItem
.y
);
1073 ptItem
.y
+= infoPtr
->nItemHeight
;
1074 rcView
.bottom
= max(rcView
.bottom
, ptItem
.y
);
1077 rcView
.right
= ptItem
.x
+ infoPtr
->nItemWidth
;
1081 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
1083 LISTVIEW_SetItemPosition(hwnd
, i
, ptItem
.x
, ptItem
.y
);
1084 ptItem
.x
+= infoPtr
->nItemWidth
;
1087 rcView
.bottom
= infoPtr
->nItemHeight
;
1088 rcView
.right
= ptItem
.x
;
1091 LISTVIEW_SetViewRect(hwnd
, &rcView
);
1097 * Set the bounding rectangle of all the items.
1100 * [I] HWND : window handle
1101 * [I] LPRECT : bounding rectangle
1107 static LRESULT
LISTVIEW_SetViewRect(HWND hwnd
, LPRECT lprcView
)
1109 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
1110 BOOL bResult
= FALSE
;
1112 TRACE("(hwnd=%x, left=%d, top=%d, right=%d, bottom=%d)\n", hwnd
,
1113 lprcView
->left
, lprcView
->top
, lprcView
->right
, lprcView
->bottom
);
1115 if (lprcView
!= NULL
)
1118 infoPtr
->rcView
.left
= lprcView
->left
;
1119 infoPtr
->rcView
.top
= lprcView
->top
;
1120 infoPtr
->rcView
.right
= lprcView
->right
;
1121 infoPtr
->rcView
.bottom
= lprcView
->bottom
;
1129 * Retrieves the bounding rectangle of all the items.
1132 * [I] HWND : window handle
1133 * [O] LPRECT : bounding rectangle
1139 static LRESULT
LISTVIEW_GetViewRect(HWND hwnd
, LPRECT lprcView
)
1141 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
1142 BOOL bResult
= FALSE
;
1145 TRACE("(hwnd=%x, lprcView=%p)\n", hwnd
, lprcView
);
1147 if (lprcView
!= NULL
)
1149 bResult
= LISTVIEW_GetOrigin(hwnd
, &ptOrigin
);
1150 if (bResult
!= FALSE
)
1152 lprcView
->left
= infoPtr
->rcView
.left
+ ptOrigin
.x
;
1153 lprcView
->top
= infoPtr
->rcView
.top
+ ptOrigin
.y
;
1154 lprcView
->right
= infoPtr
->rcView
.right
+ ptOrigin
.x
;
1155 lprcView
->bottom
= infoPtr
->rcView
.bottom
+ ptOrigin
.y
;
1158 TRACE("(left=%d, top=%d, right=%d, bottom=%d)\n",
1159 lprcView
->left
, lprcView
->top
, lprcView
->right
, lprcView
->bottom
);
1167 * Retrieves the subitem pointer associated with the subitem index.
1170 * [I] HDPA : DPA handle for a specific item
1171 * [I] INT : index of subitem
1174 * SUCCESS : subitem pointer
1177 static LISTVIEW_SUBITEM
* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems
,
1180 LISTVIEW_SUBITEM
*lpSubItem
;
1183 for (i
= 1; i
< hdpaSubItems
->nItemCount
; i
++)
1185 lpSubItem
= (LISTVIEW_SUBITEM
*) DPA_GetPtr(hdpaSubItems
, i
);
1186 if (lpSubItem
!= NULL
)
1188 if (lpSubItem
->iSubItem
== nSubItem
)
1200 * Calculates the width of an item.
1203 * [I] HWND : window handle
1204 * [I] LONG : window style
1207 * Returns item width.
1209 static INT
LISTVIEW_GetItemWidth(HWND hwnd
)
1211 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
1212 LONG style
= GetWindowLongW(hwnd
, GWL_STYLE
);
1213 UINT uView
= style
& LVS_TYPEMASK
;
1214 INT nHeaderItemCount
;
1220 TRACE("(hwnd=%x)\n", hwnd
);
1222 if (uView
== LVS_ICON
)
1224 nItemWidth
= infoPtr
->iconSpacing
.cx
;
1226 else if (uView
== LVS_REPORT
)
1228 /* calculate width of header */
1229 nHeaderItemCount
= Header_GetItemCount(infoPtr
->hwndHeader
);
1230 for (i
= 0; i
< nHeaderItemCount
; i
++)
1232 if (Header_GetItemRect(infoPtr
->hwndHeader
, i
, &rcHeaderItem
) != 0)
1234 nItemWidth
+= (rcHeaderItem
.right
- rcHeaderItem
.left
);
1240 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
1242 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, i
);
1243 nItemWidth
= max(nItemWidth
, nLabelWidth
);
1246 /* default label size */
1247 if (GETITEMCOUNT(infoPtr
) == 0)
1249 nItemWidth
= DEFAULT_COLUMN_WIDTH
;
1253 if (nItemWidth
== 0)
1255 nItemWidth
= DEFAULT_LABEL_WIDTH
;
1260 nItemWidth
+= WIDTH_PADDING
;
1262 if (infoPtr
->himlSmall
!= NULL
)
1264 nItemWidth
+= infoPtr
->iconSize
.cx
;
1267 if (infoPtr
->himlState
!= NULL
)
1269 nItemWidth
+= infoPtr
->iconSize
.cx
;
1276 /* nItemWidth Cannot be Zero */
1284 * Calculates the width of a specific item.
1287 * [I] HWND : window handle
1288 * [I] LPSTR : string
1291 * Returns the width of an item width a specified string.
1293 static INT
LISTVIEW_CalculateWidth(HWND hwnd
, INT nItem
)
1295 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
1296 UINT uView
= GetWindowLongW(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
1297 INT nHeaderItemCount
;
1302 TRACE("(hwnd=%x)\n", hwnd
);
1304 if (uView
== LVS_ICON
)
1306 nItemWidth
= infoPtr
->iconSpacing
.cx
;
1308 else if (uView
== LVS_REPORT
)
1310 /* calculate width of header */
1311 nHeaderItemCount
= Header_GetItemCount(infoPtr
->hwndHeader
);
1312 for (i
= 0; i
< nHeaderItemCount
; i
++)
1314 if (Header_GetItemRect(infoPtr
->hwndHeader
, i
, &rcHeaderItem
) != 0)
1316 nItemWidth
+= (rcHeaderItem
.right
- rcHeaderItem
.left
);
1322 /* get width of string */
1323 nItemWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
1325 /* default label size */
1326 if (GETITEMCOUNT(infoPtr
) == 0)
1328 nItemWidth
= DEFAULT_COLUMN_WIDTH
;
1332 if (nItemWidth
== 0)
1334 nItemWidth
= DEFAULT_LABEL_WIDTH
;
1339 nItemWidth
+= WIDTH_PADDING
;
1341 if (infoPtr
->himlSmall
!= NULL
)
1343 nItemWidth
+= infoPtr
->iconSize
.cx
;
1346 if (infoPtr
->himlState
!= NULL
)
1348 nItemWidth
+= infoPtr
->iconSize
.cx
;
1359 * Retrieves and saves important text metrics info for the current
1363 * [I] HWND : window handle
1366 static VOID
LISTVIEW_SaveTextMetrics(HWND hwnd
)
1368 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
1370 HDC hdc
= GetDC(hwnd
);
1371 HFONT hOldFont
= SelectObject(hdc
, infoPtr
->hFont
);
1372 INT oldHeight
, oldACW
;
1374 GetTextMetricsW(hdc
, &tm
);
1376 oldHeight
= infoPtr
->ntmHeight
;
1377 oldACW
= infoPtr
->ntmAveCharWidth
;
1378 infoPtr
->ntmHeight
= tm
.tmHeight
;
1379 infoPtr
->ntmAveCharWidth
= tm
.tmAveCharWidth
;
1381 SelectObject(hdc
, hOldFont
);
1382 ReleaseDC(hwnd
, hdc
);
1383 TRACE("tmHeight old=%d,new=%d; tmAveCharWidth old=%d,new=%d\n",
1384 oldHeight
, infoPtr
->ntmHeight
, oldACW
, infoPtr
->ntmAveCharWidth
);
1390 * Calculates the height of an item.
1393 * [I] HWND : window handle
1396 * Returns item height.
1398 static INT
LISTVIEW_GetItemHeight(HWND hwnd
)
1400 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
1401 UINT uView
= GetWindowLongW(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
1402 INT nItemHeight
= 0;
1404 if (uView
== LVS_ICON
)
1406 nItemHeight
= infoPtr
->iconSpacing
.cy
;
1410 if(infoPtr
->himlState
|| infoPtr
->himlSmall
)
1411 nItemHeight
= max(infoPtr
->ntmHeight
, infoPtr
->iconSize
.cy
) + HEIGHT_PADDING
;
1413 nItemHeight
= infoPtr
->ntmHeight
;
1420 static void LISTVIEW_PrintSelectionRanges(HWND hwnd
)
1422 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
1423 LISTVIEW_SELECTION
*selection
;
1424 INT topSelection
= infoPtr
->hdpaSelectionRanges
->nItemCount
;
1427 TRACE("Selections are:\n");
1428 for (i
= 0; i
< topSelection
; i
++)
1430 selection
= DPA_GetPtr(infoPtr
->hdpaSelectionRanges
,i
);
1431 TRACE(" %lu - %lu\n",selection
->lower
,selection
->upper
);
1437 * A compare function for selection ranges
1440 * [I] LPVOID : Item 1;
1441 * [I] LPVOID : Item 2;
1442 * [I] LPARAM : flags
1445 * >0 : if Item 1 > Item 2
1446 * <0 : if Item 2 > Item 1
1447 * 0 : if Item 1 == Item 2
1449 static INT CALLBACK
LISTVIEW_CompareSelectionRanges(LPVOID range1
, LPVOID range2
,
1452 int l1
= ((LISTVIEW_SELECTION
*)(range1
))->lower
;
1453 int l2
= ((LISTVIEW_SELECTION
*)(range2
))->lower
;
1454 int u1
= ((LISTVIEW_SELECTION
*)(range1
))->upper
;
1455 int u2
= ((LISTVIEW_SELECTION
*)(range2
))->upper
;
1469 * Adds a selection range.
1472 * [I] HWND : window handle
1473 * [I] INT : lower item index
1474 * [I] INT : upper item index
1479 static VOID
LISTVIEW_AddSelectionRange(HWND hwnd
, INT lItem
, INT uItem
)
1481 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
1482 LISTVIEW_SELECTION
*selection
;
1483 INT topSelection
= infoPtr
->hdpaSelectionRanges
->nItemCount
;
1484 BOOL lowerzero
=FALSE
;
1486 selection
= (LISTVIEW_SELECTION
*)COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION
));
1487 selection
->lower
= lItem
;
1488 selection
->upper
= uItem
;
1490 TRACE("Add range %i - %i\n", lItem
, uItem
);
1493 LISTVIEW_SELECTION
*checkselection
,*checkselection2
;
1494 INT index
,mergeindex
;
1496 /* find overlapping selections */
1497 /* we want to catch adjacent ranges so expand our range by 1 */
1500 if (selection
->lower
== 0)
1505 index
= DPA_Search(infoPtr
->hdpaSelectionRanges
, selection
, 0,
1506 LISTVIEW_CompareSelectionRanges
,
1508 selection
->upper
--;
1512 selection
->lower
++;
1516 checkselection
= DPA_GetPtr(infoPtr
->hdpaSelectionRanges
,index
);
1517 TRACE("Merge with index %i (%lu - %lu)\n",index
,checkselection
->lower
,
1518 checkselection
->upper
);
1520 checkselection
->lower
= min(selection
->lower
,checkselection
->lower
);
1521 checkselection
->upper
= max(selection
->upper
,checkselection
->upper
);
1523 TRACE("New range (%lu - %lu)\n", checkselection
->lower
,
1524 checkselection
->upper
);
1526 COMCTL32_Free(selection
);
1528 /* merge now common selection ranges in the lower group*/
1531 checkselection
->upper
++;
1532 if (checkselection
->lower
== 0)
1535 checkselection
->lower
--;
1537 TRACE("search lower range (%lu - %lu)\n", checkselection
->lower
,
1538 checkselection
->upper
);
1540 /* not sorted yet */
1541 mergeindex
= DPA_Search(infoPtr
->hdpaSelectionRanges
, checkselection
, 0,
1542 LISTVIEW_CompareSelectionRanges
, 0,
1545 checkselection
->upper
--;
1549 checkselection
->lower
++;
1551 if (mergeindex
>=0 && mergeindex
!= index
)
1553 TRACE("Merge with index %i\n",mergeindex
);
1554 checkselection2
= DPA_GetPtr(infoPtr
->hdpaSelectionRanges
,
1556 checkselection
->lower
= min(checkselection
->lower
,
1557 checkselection2
->lower
);
1558 checkselection
->upper
= max(checkselection
->upper
,
1559 checkselection2
->upper
);
1560 COMCTL32_Free(checkselection2
);
1561 DPA_DeletePtr(infoPtr
->hdpaSelectionRanges
,mergeindex
);
1565 while (mergeindex
> -1 && mergeindex
<index
);
1567 /* merge now common selection ranges in the upper group*/
1570 checkselection
->upper
++;
1571 if (checkselection
->lower
== 0)
1574 checkselection
->lower
--;
1576 TRACE("search upper range %i (%lu - %lu)\n",index
,
1577 checkselection
->lower
, checkselection
->upper
);
1579 /* not sorted yet */
1580 mergeindex
= DPA_Search(infoPtr
->hdpaSelectionRanges
, checkselection
,
1582 LISTVIEW_CompareSelectionRanges
, 0,
1585 checkselection
->upper
--;
1589 checkselection
->lower
++;
1591 if (mergeindex
>=0 && mergeindex
!=index
)
1593 TRACE("Merge with index %i\n",mergeindex
);
1594 checkselection2
= DPA_GetPtr(infoPtr
->hdpaSelectionRanges
,
1596 checkselection
->lower
= min(checkselection
->lower
,
1597 checkselection2
->lower
);
1598 checkselection
->upper
= max(checkselection
->upper
,
1599 checkselection2
->upper
);
1600 COMCTL32_Free(checkselection2
);
1601 DPA_DeletePtr(infoPtr
->hdpaSelectionRanges
,mergeindex
);
1604 while (mergeindex
> -1);
1609 index
= DPA_Search(infoPtr
->hdpaSelectionRanges
, selection
, 0,
1610 LISTVIEW_CompareSelectionRanges
, 0,
1613 TRACE("Insert before index %i\n",index
);
1616 DPA_InsertPtr(infoPtr
->hdpaSelectionRanges
,index
,selection
);
1621 DPA_InsertPtr(infoPtr
->hdpaSelectionRanges
,0,selection
);
1626 DPA_Sort(infoPtr
->hdpaSelectionRanges
,LISTVIEW_CompareSelectionRanges
,0);
1627 LISTVIEW_PrintSelectionRanges(hwnd
);
1632 * check if a specified index is selected.
1635 * [I] HWND : window handle
1636 * [I] INT : item index
1641 static BOOL
LISTVIEW_IsSelected(HWND hwnd
, INT nItem
)
1643 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
1644 LISTVIEW_SELECTION selection
;
1647 selection
.upper
= nItem
;
1648 selection
.lower
= nItem
;
1650 index
= DPA_Search(infoPtr
->hdpaSelectionRanges
, &selection
, 0,
1651 LISTVIEW_CompareSelectionRanges
,
1661 * Removes all selection ranges
1664 * HWND: window handle
1670 static LRESULT
LISTVIEW_RemoveAllSelections(HWND hwnd
)
1672 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
1673 LISTVIEW_SELECTION
*selection
;
1677 TRACE("(0x%x)\n",hwnd
);
1679 ZeroMemory(&item
,sizeof(item
));
1680 item
.stateMask
= LVIS_SELECTED
;
1684 selection
= DPA_GetPtr(infoPtr
->hdpaSelectionRanges
,0);
1687 TRACE("Removing %lu to %lu\n",selection
->lower
, selection
->upper
);
1688 for (i
= selection
->lower
; i
<=selection
->upper
; i
++)
1689 LISTVIEW_SetItemState(hwnd
,i
,&item
);
1690 LISTVIEW_RemoveSelectionRange(hwnd
,selection
->lower
,selection
->upper
);
1693 while (infoPtr
->hdpaSelectionRanges
->nItemCount
>0);
1701 * Removes a range selections.
1704 * [I] HWND : window handle
1705 * [I] INT : lower item index
1706 * [I] INT : upper item index
1711 static VOID
LISTVIEW_RemoveSelectionRange(HWND hwnd
, INT lItem
, INT uItem
)
1713 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
1714 LISTVIEW_SELECTION removeselection
,*checkselection
;
1717 removeselection
.lower
= lItem
;
1718 removeselection
.upper
= uItem
;
1720 TRACE("Remove range %lu - %lu\n",removeselection
.lower
,removeselection
.upper
);
1721 LISTVIEW_PrintSelectionRanges(hwnd
);
1723 index
= DPA_Search(infoPtr
->hdpaSelectionRanges
, &removeselection
, 0,
1724 LISTVIEW_CompareSelectionRanges
,
1731 checkselection
= DPA_GetPtr(infoPtr
->hdpaSelectionRanges
,
1734 TRACE("Matches range index %i (%lu-%lu)\n",index
,checkselection
->lower
,
1735 checkselection
->upper
);
1738 if ((checkselection
->upper
== removeselection
.upper
) &&
1739 (checkselection
->lower
== removeselection
.lower
))
1741 DPA_DeletePtr(infoPtr
->hdpaSelectionRanges
,index
);
1744 /* case 2: engulf */
1745 else if (((checkselection
->upper
< removeselection
.upper
) &&
1746 (checkselection
->lower
> removeselection
.lower
))||
1747 ((checkselection
->upper
<= removeselection
.upper
) &&
1748 (checkselection
->lower
> removeselection
.lower
)) ||
1749 ((checkselection
->upper
< removeselection
.upper
) &&
1750 (checkselection
->lower
>= removeselection
.lower
)))
1753 DPA_DeletePtr(infoPtr
->hdpaSelectionRanges
,index
);
1754 /* do it again because others may also get caught */
1756 LISTVIEW_RemoveSelectionRange(hwnd
,lItem
,uItem
);
1758 /* case 3: overlap upper */
1759 else if ((checkselection
->upper
< removeselection
.upper
) &&
1760 (checkselection
->lower
< removeselection
.lower
))
1762 checkselection
->upper
= removeselection
.lower
- 1;
1764 LISTVIEW_RemoveSelectionRange(hwnd
,lItem
,uItem
);
1766 /* case 4: overlap lower */
1767 else if ((checkselection
->upper
> removeselection
.upper
) &&
1768 (checkselection
->lower
> removeselection
.lower
))
1770 checkselection
->lower
= removeselection
.upper
+ 1;
1772 LISTVIEW_RemoveSelectionRange(hwnd
,lItem
,uItem
);
1774 /* case 5: fully internal */
1775 else if (checkselection
->upper
== removeselection
.upper
)
1776 checkselection
->upper
= removeselection
.lower
- 1;
1777 else if (checkselection
->lower
== removeselection
.lower
)
1778 checkselection
->lower
= removeselection
.upper
+ 1;
1781 /* bisect the range */
1782 LISTVIEW_SELECTION
*newselection
;
1784 newselection
= (LISTVIEW_SELECTION
*)
1785 COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION
));
1786 newselection
-> lower
= checkselection
->lower
;
1787 newselection
-> upper
= removeselection
.lower
- 1;
1788 checkselection
-> lower
= removeselection
.upper
+ 1;
1789 DPA_InsertPtr(infoPtr
->hdpaSelectionRanges
,index
,newselection
);
1791 DPA_Sort(infoPtr
->hdpaSelectionRanges
,LISTVIEW_CompareSelectionRanges
,0);
1793 LISTVIEW_PrintSelectionRanges(hwnd
);
1798 * Updates the various indices after an item has been inserted or deleted.
1801 * [I] HWND : window handle
1802 * [I] INT : item index
1803 * [I] INT : Direction of shift, +1 or -1.
1808 static VOID
LISTVIEW_ShiftIndices(HWND hwnd
, INT nItem
, INT direction
)
1810 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
1811 LISTVIEW_SELECTION selection
,*checkselection
;
1814 TRACE("Shifting %iu, %i steps\n",nItem
,direction
);
1816 selection
.upper
= nItem
;
1817 selection
.lower
= nItem
;
1819 index
= DPA_Search(infoPtr
->hdpaSelectionRanges
, &selection
, 0,
1820 LISTVIEW_CompareSelectionRanges
,
1821 0,DPAS_SORTED
|DPAS_INSERTAFTER
);
1823 while ((index
< infoPtr
->hdpaSelectionRanges
->nItemCount
)&&(index
!= -1))
1825 checkselection
= DPA_GetPtr(infoPtr
->hdpaSelectionRanges
,index
);
1826 if ((checkselection
->lower
>= nItem
)&&
1827 (checkselection
->lower
+ direction
>= 0))
1828 checkselection
->lower
+= direction
;
1829 if ((checkselection
->upper
>= nItem
)&&
1830 (checkselection
->upper
+ direction
>=0))
1831 checkselection
->upper
+= direction
;
1835 /* Note that the following will fail if direction != +1 and -1 */
1836 if (infoPtr
->nSelectionMark
> nItem
)
1837 infoPtr
->nSelectionMark
+= direction
;
1838 else if (infoPtr
->nSelectionMark
== nItem
)
1841 infoPtr
->nSelectionMark
+= direction
;
1842 else if (infoPtr
->nSelectionMark
>= GETITEMCOUNT(infoPtr
))
1843 infoPtr
->nSelectionMark
= GETITEMCOUNT(infoPtr
) - 1;
1846 if (infoPtr
->nFocusedItem
> nItem
)
1847 infoPtr
->nFocusedItem
+= direction
;
1848 else if (infoPtr
->nFocusedItem
== nItem
)
1851 infoPtr
->nFocusedItem
+= direction
;
1854 if (infoPtr
->nFocusedItem
>= GETITEMCOUNT(infoPtr
))
1855 infoPtr
->nFocusedItem
= GETITEMCOUNT(infoPtr
) - 1;
1856 if (infoPtr
->nFocusedItem
>= 0)
1857 LISTVIEW_SetItemFocus(hwnd
, infoPtr
->nFocusedItem
);
1860 /* But we are not supposed to modify nHotItem! */
1866 * Adds a block of selections.
1869 * [I] HWND : window handle
1870 * [I] INT : item index
1875 static VOID
LISTVIEW_AddGroupSelection(HWND hwnd
, INT nItem
)
1877 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
1878 INT nFirst
= min(infoPtr
->nSelectionMark
, nItem
);
1879 INT nLast
= max(infoPtr
->nSelectionMark
, nItem
);
1886 ZeroMemory(&item
,sizeof(item
));
1887 item
.stateMask
= LVIS_SELECTED
;
1888 item
.state
= LVIS_SELECTED
;
1890 for (i
= nFirst
; i
<= nLast
; i
++)
1891 LISTVIEW_SetItemState(hwnd
,i
,&item
);
1893 LISTVIEW_SetItemFocus(hwnd
, nItem
);
1894 infoPtr
->nSelectionMark
= nItem
;
1900 * Adds a single selection.
1903 * [I] HWND : window handle
1904 * [I] INT : item index
1909 static VOID
LISTVIEW_AddSelection(HWND hwnd
, INT nItem
)
1911 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
1914 ZeroMemory(&item
,sizeof(item
));
1915 item
.state
= LVIS_SELECTED
;
1916 item
.stateMask
= LVIS_SELECTED
;
1918 LISTVIEW_SetItemState(hwnd
,nItem
,&item
);
1920 LISTVIEW_SetItemFocus(hwnd
, nItem
);
1921 infoPtr
->nSelectionMark
= nItem
;
1926 * Selects or unselects an item.
1929 * [I] HWND : window handle
1930 * [I] INT : item index
1936 static BOOL
LISTVIEW_ToggleSelection(HWND hwnd
, INT nItem
)
1938 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
1942 ZeroMemory(&item
,sizeof(item
));
1943 item
.stateMask
= LVIS_SELECTED
;
1945 if (LISTVIEW_IsSelected(hwnd
,nItem
))
1947 LISTVIEW_SetItemState(hwnd
,nItem
,&item
);
1952 item
.state
= LVIS_SELECTED
;
1953 LISTVIEW_SetItemState(hwnd
,nItem
,&item
);
1957 LISTVIEW_SetItemFocus(hwnd
, nItem
);
1958 infoPtr
->nSelectionMark
= nItem
;
1965 * Selects items based on view coordinates.
1968 * [I] HWND : window handle
1969 * [I] RECT : selection rectangle
1974 static VOID
LISTVIEW_SetSelectionRect(HWND hwnd
, RECT rcSelRect
)
1976 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
1981 ZeroMemory(&item
,sizeof(item
));
1982 item
.stateMask
= LVIS_SELECTED
;
1984 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
1986 LISTVIEW_GetItemPosition(hwnd
, i
, &ptItem
);
1988 if (PtInRect(&rcSelRect
, ptItem
) != FALSE
)
1989 item
.state
= LVIS_SELECTED
;
1992 LISTVIEW_SetItemState(hwnd
,i
,&item
);
1998 * Sets a single group selection.
2001 * [I] HWND : window handle
2002 * [I] INT : item index
2007 static VOID
LISTVIEW_SetGroupSelection(HWND hwnd
, INT nItem
)
2009 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
2010 UINT uView
= GetWindowLongW(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
2013 ZeroMemory(&item
,sizeof(item
));
2014 item
.stateMask
= LVIS_SELECTED
;
2016 if ((uView
== LVS_LIST
) || (uView
== LVS_REPORT
))
2021 if (infoPtr
->nSelectionMark
== -1)
2023 infoPtr
->nSelectionMark
= nFirst
= nLast
= nItem
;
2027 nFirst
= min(infoPtr
->nSelectionMark
, nItem
);
2028 nLast
= max(infoPtr
->nSelectionMark
, nItem
);
2031 for (i
= 0; i
<= GETITEMCOUNT(infoPtr
); i
++)
2033 if ((i
< nFirst
) || (i
> nLast
))
2036 item
.state
= LVIS_SELECTED
;
2037 LISTVIEW_SetItemState(hwnd
,i
,&item
);
2045 LISTVIEW_GetItemBoundBox(hwnd
, nItem
, &rcItem
);
2046 LISTVIEW_GetItemBoundBox(hwnd
, infoPtr
->nSelectionMark
, &rcSelMark
);
2047 rcSel
.left
= min(rcSelMark
.left
, rcItem
.left
);
2048 rcSel
.top
= min(rcSelMark
.top
, rcItem
.top
);
2049 rcSel
.right
= max(rcSelMark
.right
, rcItem
.right
);
2050 rcSel
.bottom
= max(rcSelMark
.bottom
, rcItem
.bottom
);
2051 LISTVIEW_SetSelectionRect(hwnd
, rcSel
);
2052 TRACE("item %d (%d,%d)-(%d,%d), mark %d (%d,%d)-(%d,%d), sel (%d,%d)-(%d,%d)\n",
2053 nItem
, rcItem
.left
, rcItem
.top
, rcItem
.right
, rcItem
.bottom
,
2054 infoPtr
->nSelectionMark
,
2055 rcSelMark
.left
, rcSelMark
.top
, rcSelMark
.right
, rcSelMark
.bottom
,
2056 rcSel
.left
, rcSel
.top
, rcSel
.right
, rcSel
.bottom
);
2060 LISTVIEW_SetItemFocus(hwnd
, nItem
);
2065 * Manages the item focus.
2068 * [I] HWND : window handle
2069 * [I] INT : item index
2072 * TRUE : focused item changed
2073 * FALSE : focused item has NOT changed
2075 static BOOL
LISTVIEW_SetItemFocus(HWND hwnd
, INT nItem
)
2077 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
2078 BOOL bResult
= FALSE
;
2081 if (infoPtr
->nFocusedItem
!= nItem
)
2083 if (infoPtr
->nFocusedItem
>= 0)
2085 INT oldFocus
= infoPtr
->nFocusedItem
;
2087 infoPtr
->nFocusedItem
= -1;
2088 ZeroMemory(&lvItem
, sizeof(lvItem
));
2089 lvItem
.stateMask
= LVIS_FOCUSED
;
2090 ListView_SetItemState(hwnd
, oldFocus
, &lvItem
);
2094 lvItem
.state
= LVIS_FOCUSED
;
2095 lvItem
.stateMask
= LVIS_FOCUSED
;
2096 ListView_SetItemState(hwnd
, nItem
, &lvItem
);
2098 infoPtr
->nFocusedItem
= nItem
;
2099 ListView_EnsureVisible(hwnd
, nItem
, FALSE
);
2107 * Sets a single selection.
2110 * [I] HWND : window handle
2111 * [I] INT : item index
2116 static VOID
LISTVIEW_SetSelection(HWND hwnd
, INT nItem
)
2118 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
2121 ZeroMemory(&lvItem
, sizeof(lvItem
));
2122 lvItem
.stateMask
= LVIS_FOCUSED
;
2123 ListView_SetItemState(hwnd
, infoPtr
->nFocusedItem
, &lvItem
);
2125 LISTVIEW_RemoveAllSelections(hwnd
);
2127 lvItem
.state
= LVIS_FOCUSED
|LVIS_SELECTED
;
2128 lvItem
.stateMask
= LVIS_FOCUSED
|LVIS_SELECTED
;
2129 ListView_SetItemState(hwnd
, nItem
, &lvItem
);
2131 infoPtr
->nFocusedItem
= nItem
;
2132 infoPtr
->nSelectionMark
= nItem
;
2137 * Set selection(s) with keyboard.
2140 * [I] HWND : window handle
2141 * [I] INT : item index
2144 * SUCCESS : TRUE (needs to be repainted)
2145 * FAILURE : FALSE (nothing has changed)
2147 static BOOL
LISTVIEW_KeySelection(HWND hwnd
, INT nItem
)
2149 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
2150 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
2151 WORD wShift
= HIWORD(GetKeyState(VK_SHIFT
));
2152 WORD wCtrl
= HIWORD(GetKeyState(VK_CONTROL
));
2153 BOOL bResult
= FALSE
;
2155 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
2157 if (lStyle
& LVS_SINGLESEL
)
2160 LISTVIEW_SetSelection(hwnd
, nItem
);
2161 ListView_EnsureVisible(hwnd
, nItem
, FALSE
);
2168 LISTVIEW_SetGroupSelection(hwnd
, nItem
);
2172 bResult
= LISTVIEW_SetItemFocus(hwnd
, nItem
);
2177 LISTVIEW_SetSelection(hwnd
, nItem
);
2178 ListView_EnsureVisible(hwnd
, nItem
, FALSE
);
2188 * Called when the mouse is being actively tracked and has hovered for a specified
2192 * [I] HWND : window handle
2193 * [I] wParam : key indicator
2194 * [I] lParam : mouse position
2197 * 0 if the message was processed, non-zero if there was an error
2200 * LVS_EX_TRACKSELECT: An item is automatically selected when the cursor remains
2201 * over the item for a certain period of time.
2204 static LRESULT
LISTVIEW_MouseHover(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2206 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
2209 pt
.x
= (INT
)LOWORD(lParam
);
2210 pt
.y
= (INT
)HIWORD(lParam
);
2212 if(infoPtr
->dwExStyle
& LVS_EX_TRACKSELECT
) {
2213 /* select the item under the cursor */
2214 LISTVIEW_MouseSelection(hwnd
, pt
);
2222 * Called whenever WM_MOUSEMOVE is received.
2225 * [I] HWND : window handle
2226 * [I] wParam : key indicators
2227 * [I] lParam : cursor position
2230 * 0 if the message is processed, non-zero if there was an error
2232 static LRESULT
LISTVIEW_MouseMove(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2234 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
2235 TRACKMOUSEEVENT trackinfo
;
2237 /* see if we are supposed to be tracking mouse hovering */
2238 if(infoPtr
->dwExStyle
& LVS_EX_TRACKSELECT
) {
2239 /* fill in the trackinfo struct */
2240 trackinfo
.cbSize
= sizeof(TRACKMOUSEEVENT
);
2241 trackinfo
.dwFlags
= TME_QUERY
;
2242 trackinfo
.hwndTrack
= hwnd
;
2243 trackinfo
.dwHoverTime
= infoPtr
->dwHoverTime
;
2245 /* see if we are already tracking this hwnd */
2246 _TrackMouseEvent(&trackinfo
);
2248 if(!(trackinfo
.dwFlags
& TME_HOVER
)) {
2249 trackinfo
.dwFlags
= TME_HOVER
;
2251 /* call TRACKMOUSEEVENT so we receive WM_MOUSEHOVER messages */
2252 _TrackMouseEvent(&trackinfo
);
2261 * Selects an item based on coordinates.
2264 * [I] HWND : window handle
2265 * [I] POINT : mouse click ccordinates
2268 * SUCCESS : item index
2271 static LRESULT
LISTVIEW_MouseSelection(HWND hwnd
, POINT pt
)
2273 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
2275 INT i
,topindex
,bottomindex
;
2276 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
2277 UINT uView
= lStyle
& LVS_TYPEMASK
;
2279 topindex
= ListView_GetTopIndex(hwnd
);
2280 if (uView
== LVS_REPORT
)
2282 bottomindex
= topindex
+ LISTVIEW_GetCountPerColumn(hwnd
) + 1;
2283 bottomindex
= min(bottomindex
,GETITEMCOUNT(infoPtr
));
2287 bottomindex
= GETITEMCOUNT(infoPtr
);
2290 for (i
= topindex
; i
< bottomindex
; i
++)
2292 rcItem
.left
= LVIR_SELECTBOUNDS
;
2293 if (LISTVIEW_GetItemRect(hwnd
, i
, &rcItem
) == TRUE
)
2295 if (PtInRect(&rcItem
, pt
) != FALSE
)
2310 * [IO] HDPA : dynamic pointer array handle
2311 * [I] INT : column index (subitem index)
2317 static BOOL
LISTVIEW_RemoveColumn(HDPA hdpaItems
, INT nSubItem
)
2319 BOOL bResult
= TRUE
;
2323 for (i
= 0; i
< hdpaItems
->nItemCount
; i
++)
2325 hdpaSubItems
= (HDPA
)DPA_GetPtr(hdpaItems
, i
);
2326 if (hdpaSubItems
!= NULL
)
2328 if (LISTVIEW_RemoveSubItem(hdpaSubItems
, nSubItem
) == FALSE
)
2340 * Removes a subitem at a given position.
2343 * [IO] HDPA : dynamic pointer array handle
2344 * [I] INT : subitem index
2350 static BOOL
LISTVIEW_RemoveSubItem(HDPA hdpaSubItems
, INT nSubItem
)
2352 LISTVIEW_SUBITEM
*lpSubItem
;
2355 for (i
= 1; i
< hdpaSubItems
->nItemCount
; i
++)
2357 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, i
);
2358 if (lpSubItem
!= NULL
)
2360 if (lpSubItem
->iSubItem
== nSubItem
)
2363 if (is_textW(lpSubItem
->pszText
))
2364 COMCTL32_Free(lpSubItem
->pszText
);
2367 COMCTL32_Free(lpSubItem
);
2369 /* free dpa memory */
2370 if (DPA_DeletePtr(hdpaSubItems
, i
) == NULL
)
2373 else if (lpSubItem
->iSubItem
> nSubItem
)
2383 * Compares the item information.
2386 * [I] LISTVIEW_ITEM *: destination item
2387 * [I] LPLVITEM : source item
2388 * [I] isW : TRUE if lpLVItem is Unicode, FALSE it it's ANSI
2391 * SUCCCESS : TRUE (EQUAL)
2392 * FAILURE : FALSE (NOT EQUAL)
2394 static UINT
LISTVIEW_GetItemChangesT(LISTVIEW_ITEM
*lpItem
, LPLVITEMW lpLVItem
, BOOL isW
)
2398 if ((lpItem
!= NULL
) && (lpLVItem
!= NULL
))
2400 if (lpLVItem
->mask
& LVIF_STATE
)
2402 if ((lpItem
->state
& lpLVItem
->stateMask
) !=
2403 (lpLVItem
->state
& lpLVItem
->stateMask
))
2404 uChanged
|= LVIF_STATE
;
2407 if (lpLVItem
->mask
& LVIF_IMAGE
)
2409 if (lpItem
->iImage
!= lpLVItem
->iImage
)
2410 uChanged
|= LVIF_IMAGE
;
2413 if (lpLVItem
->mask
& LVIF_PARAM
)
2415 if (lpItem
->lParam
!= lpLVItem
->lParam
)
2416 uChanged
|= LVIF_PARAM
;
2419 if (lpLVItem
->mask
& LVIF_INDENT
)
2421 if (lpItem
->iIndent
!= lpLVItem
->iIndent
)
2422 uChanged
|= LVIF_INDENT
;
2425 if (lpLVItem
->mask
& LVIF_TEXT
)
2427 if (lpLVItem
->pszText
== LPSTR_TEXTCALLBACKW
)
2429 if (lpItem
->pszText
!= LPSTR_TEXTCALLBACKW
)
2430 uChanged
|= LVIF_TEXT
;
2434 if (lpItem
->pszText
== LPSTR_TEXTCALLBACKW
)
2436 uChanged
|= LVIF_TEXT
;
2440 if (lpLVItem
->pszText
)
2442 if (lpItem
->pszText
)
2444 LPWSTR pszText
= textdupTtoW(lpLVItem
->pszText
, isW
);
2445 if (pszText
&& strcmpW(pszText
, lpItem
->pszText
))
2446 uChanged
|= LVIF_TEXT
;
2447 textfreeT(pszText
, isW
);
2451 uChanged
|= LVIF_TEXT
;
2456 if (lpItem
->pszText
)
2457 uChanged
|= LVIF_TEXT
;
2468 * Initializes item attributes.
2471 * [I] HWND : window handle
2472 * [O] LISTVIEW_ITEM *: destination item
2473 * [I] LPLVITEM : source item
2474 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
2480 static BOOL
LISTVIEW_InitItemT(HWND hwnd
, LISTVIEW_ITEM
*lpItem
,
2481 LPLVITEMW lpLVItem
, BOOL isW
)
2483 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
2484 BOOL bResult
= FALSE
;
2486 if ((lpItem
!= NULL
) && (lpLVItem
!= NULL
))
2490 if (lpLVItem
->mask
& LVIF_STATE
)
2492 lpItem
->state
&= ~lpLVItem
->stateMask
;
2493 lpItem
->state
|= (lpLVItem
->state
& lpLVItem
->stateMask
);
2496 if (lpLVItem
->mask
& LVIF_IMAGE
)
2497 lpItem
->iImage
= lpLVItem
->iImage
;
2499 if (lpLVItem
->mask
& LVIF_PARAM
)
2500 lpItem
->lParam
= lpLVItem
->lParam
;
2502 if (lpLVItem
->mask
& LVIF_INDENT
)
2503 lpItem
->iIndent
= lpLVItem
->iIndent
;
2505 if (lpLVItem
->mask
& LVIF_TEXT
)
2507 if (lpLVItem
->pszText
== LPSTR_TEXTCALLBACKW
)
2509 if ((lStyle
& LVS_SORTASCENDING
) || (lStyle
& LVS_SORTDESCENDING
))
2512 if (is_textW(lpItem
->pszText
))
2513 COMCTL32_Free(lpItem
->pszText
);
2515 lpItem
->pszText
= LPSTR_TEXTCALLBACKW
;
2518 bResult
= textsetptrT(&lpItem
->pszText
, lpLVItem
->pszText
, isW
);
2527 * Initializes subitem attributes.
2529 * NOTE: The documentation specifies that the operation fails if the user
2530 * tries to set the indent of a subitem.
2533 * [I] HWND : window handle
2534 * [O] LISTVIEW_SUBITEM *: destination subitem
2535 * [I] LPLVITEM : source subitem
2536 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
2542 static BOOL
LISTVIEW_InitSubItemT(HWND hwnd
, LISTVIEW_SUBITEM
*lpSubItem
,
2543 LPLVITEMW lpLVItem
, BOOL isW
)
2545 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
2546 BOOL bResult
= FALSE
;
2548 TRACE("(hwnd=%x, lpSubItem=%p, lpLVItem=%s, isW=%d)\n",
2549 hwnd
, lpSubItem
, debuglvitem_t(lpLVItem
, isW
), isW
);
2551 if ((lpSubItem
!= NULL
) && (lpLVItem
!= NULL
))
2553 if (!(lpLVItem
->mask
& LVIF_INDENT
))
2557 lpSubItem
->iSubItem
= lpLVItem
->iSubItem
;
2559 if (lpLVItem
->mask
& LVIF_IMAGE
)
2560 lpSubItem
->iImage
= lpLVItem
->iImage
;
2562 if (lpLVItem
->mask
& LVIF_TEXT
)
2564 if (lpLVItem
->pszText
== LPSTR_TEXTCALLBACKW
)
2566 if ((lStyle
& LVS_SORTASCENDING
) || (lStyle
& LVS_SORTDESCENDING
))
2569 if (is_textW(lpSubItem
->pszText
))
2570 COMCTL32_Free(lpSubItem
->pszText
);
2572 lpSubItem
->pszText
= LPSTR_TEXTCALLBACKW
;
2575 bResult
= textsetptrT(&lpSubItem
->pszText
, lpLVItem
->pszText
, isW
);
2585 * Adds a subitem at a given position (column index).
2588 * [I] HWND : window handle
2589 * [I] LPLVITEM : new subitem atttributes
2590 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
2596 static BOOL
LISTVIEW_AddSubItemT(HWND hwnd
, LPLVITEMW lpLVItem
, BOOL isW
)
2598 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
2599 LISTVIEW_SUBITEM
*lpSubItem
= NULL
;
2600 BOOL bResult
= FALSE
;
2602 INT nPosition
, nItem
;
2603 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
2605 TRACE("(hwnd=%x, lpLVItem=%s, isW=%d)\n", hwnd
, debuglvitem_t(lpLVItem
, isW
), isW
);
2607 if (lStyle
& LVS_OWNERDATA
)
2610 if (lpLVItem
!= NULL
)
2612 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
);
2613 if (hdpaSubItems
!= NULL
)
2615 lpSubItem
= (LISTVIEW_SUBITEM
*)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM
));
2616 if (lpSubItem
!= NULL
)
2618 ZeroMemory(lpSubItem
, sizeof(LISTVIEW_SUBITEM
));
2619 if (LISTVIEW_InitSubItemT(hwnd
, lpSubItem
, lpLVItem
, isW
))
2621 nPosition
= LISTVIEW_FindInsertPosition(hdpaSubItems
,
2622 lpSubItem
->iSubItem
);
2623 nItem
= DPA_InsertPtr(hdpaSubItems
, nPosition
, lpSubItem
);
2624 if (nItem
!= -1) bResult
= TRUE
;
2630 /* cleanup if unsuccessful */
2631 if (!bResult
&& lpSubItem
) COMCTL32_Free(lpSubItem
);
2638 * Finds the dpa insert position (array index).
2641 * [I] HWND : window handle
2642 * [I] INT : subitem index
2648 static INT
LISTVIEW_FindInsertPosition(HDPA hdpaSubItems
, INT nSubItem
)
2650 LISTVIEW_SUBITEM
*lpSubItem
;
2653 for (i
= 1; i
< hdpaSubItems
->nItemCount
; i
++)
2655 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, i
);
2656 if (lpSubItem
&& lpSubItem
->iSubItem
> nSubItem
)
2660 return hdpaSubItems
->nItemCount
;
2665 * Retrieves a listview subitem at a given position (column index).
2668 * [I] HWND : window handle
2669 * [I] INT : subitem index
2675 static LISTVIEW_SUBITEM
* LISTVIEW_GetSubItem(HDPA hdpaSubItems
, INT nSubItem
)
2677 LISTVIEW_SUBITEM
*lpSubItem
;
2680 for (i
= 1; i
< hdpaSubItems
->nItemCount
; i
++)
2682 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, i
);
2683 if (lpSubItem
!= NULL
)
2685 if (lpSubItem
->iSubItem
== nSubItem
)
2687 else if (lpSubItem
->iSubItem
> nSubItem
)
2697 * Sets item attributes.
2700 * [I] HWND : window handle
2701 * [I] LPLVITEM : new item atttributes
2702 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
2708 static BOOL
LISTVIEW_SetMainItemT(HWND hwnd
, LPLVITEMW lpLVItem
, BOOL isW
)
2710 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
2711 BOOL bResult
= FALSE
;
2713 LISTVIEW_ITEM
*lpItem
;
2715 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
2717 UINT uView
= lStyle
& LVS_TYPEMASK
;
2721 TRACE("(hwnd=%x, lpLVItem=%s, isW=%d)\n", hwnd
, debuglvitem_t(lpLVItem
, isW
), isW
);
2723 if (lStyle
& LVS_OWNERDATA
)
2725 if ((lpLVItem
->iSubItem
== 0)&&(lpLVItem
->mask
== LVIF_STATE
))
2729 ZeroMemory(&itm
, sizeof(itm
));
2730 itm
.mask
= LVIF_STATE
| LVIF_PARAM
;
2731 itm
.stateMask
= LVIS_FOCUSED
| LVIS_SELECTED
;
2732 itm
.iItem
= lpLVItem
->iItem
;
2734 ListView_GetItemW(hwnd
, &itm
);
2737 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
2738 nmlv
.uNewState
= lpLVItem
->state
;
2739 nmlv
.uOldState
= itm
.state
;
2740 nmlv
.uChanged
= LVIF_STATE
;
2741 nmlv
.lParam
= itm
.lParam
;
2742 nmlv
.iItem
= lpLVItem
->iItem
;
2744 if ((itm
.state
& lpLVItem
->stateMask
) !=
2745 (lpLVItem
->state
& lpLVItem
->stateMask
))
2747 /* send LVN_ITEMCHANGING notification */
2748 if (!listview_notify(hwnd
, LVN_ITEMCHANGING
, &nmlv
))
2750 if (lpLVItem
->stateMask
& LVIS_FOCUSED
)
2752 if (lpLVItem
->state
& LVIS_FOCUSED
)
2753 infoPtr
->nFocusedItem
= lpLVItem
->iItem
;
2754 else if (infoPtr
->nFocusedItem
== lpLVItem
->iItem
)
2755 infoPtr
->nFocusedItem
= -1;
2757 if (lpLVItem
->stateMask
& LVIS_SELECTED
)
2759 if (lpLVItem
->state
& LVIS_SELECTED
)
2761 if (lStyle
& LVS_SINGLESEL
) LISTVIEW_RemoveAllSelections(hwnd
);
2762 LISTVIEW_AddSelectionRange(hwnd
,lpLVItem
->iItem
,lpLVItem
->iItem
);
2765 LISTVIEW_RemoveSelectionRange(hwnd
,lpLVItem
->iItem
,
2769 listview_notify(hwnd
, LVN_ITEMCHANGED
, &nmlv
);
2771 rcItem
.left
= LVIR_BOUNDS
;
2772 LISTVIEW_GetItemRect(hwnd
, lpLVItem
->iItem
, &rcItem
);
2773 InvalidateRect(hwnd
, &rcItem
, TRUE
);
2781 if (lpLVItem
!= NULL
)
2783 if (lpLVItem
->iSubItem
== 0)
2785 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
);
2786 if (hdpaSubItems
!= NULL
&& hdpaSubItems
!= (HDPA
)-1)
2788 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, lpLVItem
->iSubItem
);
2791 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
2792 nmlv
.lParam
= lpItem
->lParam
;
2793 uChanged
= LISTVIEW_GetItemChangesT(lpItem
, lpLVItem
, isW
);
2796 if (uChanged
& LVIF_STATE
)
2798 nmlv
.uNewState
= lpLVItem
->state
& lpLVItem
->stateMask
;
2799 nmlv
.uOldState
= lpItem
->state
& lpLVItem
->stateMask
;
2801 if (nmlv
.uNewState
& LVIS_SELECTED
)
2804 * This is redundant if called through SetSelection
2806 * however is required if the used directly calls SetItem
2807 * to set the selection.
2809 if (lStyle
& LVS_SINGLESEL
)
2810 LISTVIEW_RemoveAllSelections(hwnd
);
2812 LISTVIEW_AddSelectionRange(hwnd
,lpLVItem
->iItem
,
2815 else if (lpLVItem
->stateMask
& LVIS_SELECTED
)
2817 LISTVIEW_RemoveSelectionRange(hwnd
,lpLVItem
->iItem
,
2820 if (nmlv
.uNewState
& LVIS_FOCUSED
)
2823 * This is a fun hoop to jump to try to catch if
2824 * the user is calling us directly to call focus or if
2825 * this function is being called as a result of a
2826 * SetItemFocus call.
2828 if (infoPtr
->nFocusedItem
>= 0)
2829 LISTVIEW_SetItemFocus(hwnd
, lpLVItem
->iItem
);
2833 nmlv
.uChanged
= uChanged
;
2834 nmlv
.iItem
= lpLVItem
->iItem
;
2835 nmlv
.lParam
= lpItem
->lParam
;
2836 /* send LVN_ITEMCHANGING notification */
2837 listview_notify(hwnd
, LVN_ITEMCHANGING
, &nmlv
);
2839 /* copy information */
2840 bResult
= LISTVIEW_InitItemT(hwnd
, lpItem
, lpLVItem
, isW
);
2842 /* if LVS_LIST or LVS_SMALLICON, update the width of the items
2843 based on the width of the items text */
2844 if((uView
== LVS_LIST
) || (uView
== LVS_SMALLICON
))
2846 item_width
= LISTVIEW_GetStringWidthT(hwnd
, lpItem
->pszText
, TRUE
);
2848 if(item_width
> infoPtr
->nItemWidth
)
2849 infoPtr
->nItemWidth
= item_width
;
2852 /* send LVN_ITEMCHANGED notification */
2853 listview_notify(hwnd
, LVN_ITEMCHANGED
, &nmlv
);
2862 rcItem
.left
= LVIR_BOUNDS
;
2863 LISTVIEW_GetItemRect(hwnd
, lpLVItem
->iItem
, &rcItem
);
2864 InvalidateRect(hwnd
, &rcItem
, TRUE
);
2876 * Sets subitem attributes.
2879 * [I] HWND : window handle
2880 * [I] LPLVITEM : new subitem atttributes
2881 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
2887 static BOOL
LISTVIEW_SetSubItemT(HWND hwnd
, LPLVITEMW lpLVItem
, BOOL isW
)
2889 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
2890 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
2891 BOOL bResult
= FALSE
;
2893 LISTVIEW_SUBITEM
*lpSubItem
;
2896 TRACE("(hwnd=%x, lpLVItem=%s, isW=%d)\n", hwnd
, debuglvitem_t(lpLVItem
, isW
), isW
);
2898 if (lStyle
& LVS_OWNERDATA
)
2901 if (lpLVItem
!= NULL
)
2903 if (lpLVItem
->iSubItem
> 0)
2905 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
);
2906 if (hdpaSubItems
!= NULL
)
2908 /* set subitem only if column is present */
2909 if (Header_GetItemCount(infoPtr
->hwndHeader
) > lpLVItem
->iSubItem
)
2911 lpSubItem
= LISTVIEW_GetSubItem(hdpaSubItems
, lpLVItem
->iSubItem
);
2912 if (lpSubItem
!= NULL
)
2913 bResult
= LISTVIEW_InitSubItemT(hwnd
, lpSubItem
, lpLVItem
, isW
);
2915 bResult
= LISTVIEW_AddSubItemT(hwnd
, lpLVItem
, isW
);
2917 rcItem
.left
= LVIR_BOUNDS
;
2918 LISTVIEW_GetItemRect(hwnd
, lpLVItem
->iItem
, &rcItem
);
2919 InvalidateRect(hwnd
, &rcItem
, FALSE
);
2930 * Sets item attributes.
2933 * [I] HWND : window handle
2934 * [I] LPLVITEM : new item atttributes
2935 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
2941 static BOOL
LISTVIEW_SetItemT(HWND hwnd
, LPLVITEMW lpLVItem
, BOOL isW
)
2943 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
2945 if (!lpLVItem
|| lpLVItem
->iItem
< 0 ||
2946 lpLVItem
->iItem
>=GETITEMCOUNT(infoPtr
))
2948 if (lpLVItem
->iSubItem
== 0)
2949 return LISTVIEW_SetMainItemT(hwnd
, lpLVItem
, isW
);
2951 return LISTVIEW_SetSubItemT(hwnd
, lpLVItem
, isW
);
2956 * Retrieves the index of the item at coordinate (0, 0) of the client area.
2959 * [I] HWND : window handle
2964 static INT
LISTVIEW_GetTopIndex(HWND hwnd
)
2966 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
2967 UINT uView
= lStyle
& LVS_TYPEMASK
;
2969 SCROLLINFO scrollInfo
;
2971 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
2972 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
2973 scrollInfo
.fMask
= SIF_POS
;
2975 if (uView
== LVS_LIST
)
2977 if ((lStyle
& WS_HSCROLL
) && GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
))
2978 nItem
= scrollInfo
.nPos
* LISTVIEW_GetCountPerColumn(hwnd
);
2980 else if (uView
== LVS_REPORT
)
2982 if ((lStyle
& WS_VSCROLL
) && GetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
))
2983 nItem
= scrollInfo
.nPos
;
2994 * [I] HWND : window handle
2995 * [I] HDC : device context handle
2996 * [I] INT : item index
2997 * [I] INT : subitem index
2998 * [I] RECT * : clipping rectangle
3003 static VOID
LISTVIEW_DrawSubItem(HWND hwnd
, HDC hdc
, INT nItem
, INT nSubItem
,
3004 RECT rcItem
, BOOL Selected
)
3006 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
3007 WCHAR szDispText
[DISP_TEXT_SIZE
];
3009 UINT textoutOptions
= ETO_CLIPPED
| ETO_OPAQUE
;
3012 TRACE("(hwnd=%x, hdc=%x, nItem=%d, nSubItem=%d)\n", hwnd
, hdc
,
3015 /* get information needed for drawing the item */
3016 ZeroMemory(&lvItem
, sizeof(lvItem
));
3017 lvItem
.mask
= LVIF_TEXT
;
3018 lvItem
.iItem
= nItem
;
3019 lvItem
.iSubItem
= nSubItem
;
3020 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
3021 lvItem
.pszText
= szDispText
;
3022 *lvItem
.pszText
= '\0';
3023 LISTVIEW_GetItemW(hwnd
, &lvItem
, TRUE
);
3024 TRACE(" lvItem=%s\n", debuglvitem_t(&lvItem
, TRUE
));
3026 /* redraw the background of the item */
3028 if(infoPtr
->nColumnCount
== (nSubItem
+ 1))
3029 rcTemp
.right
= infoPtr
->rcList
.right
;
3031 rcTemp
.right
+= WIDTH_PADDING
;
3033 LISTVIEW_FillBackground(hwnd
, hdc
, &rcTemp
);
3035 /* set item colors */
3036 if (ListView_GetItemState(hwnd
,nItem
,LVIS_SELECTED
) && Selected
)
3038 if (infoPtr
->bFocus
)
3040 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
3041 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
3045 SetBkColor(hdc
, GetSysColor(COLOR_3DFACE
));
3046 SetTextColor(hdc
, GetSysColor(COLOR_BTNTEXT
));
3051 if ( (infoPtr
->clrTextBk
== CLR_DEFAULT
) || (infoPtr
->clrTextBk
== CLR_NONE
) )
3053 SetBkMode(hdc
, TRANSPARENT
);
3054 textoutOptions
&= ~ETO_OPAQUE
;
3058 SetBkMode(hdc
, OPAQUE
);
3059 SetBkColor(hdc
, infoPtr
->clrTextBk
);
3062 SetTextColor(hdc
, infoPtr
->clrText
);
3065 ExtTextOutW(hdc
, rcItem
.left
, rcItem
.top
, textoutOptions
,
3066 &rcItem
, lvItem
.pszText
, lstrlenW(lvItem
.pszText
), NULL
);
3070 /* fill in the gap */
3072 if (nSubItem
< Header_GetItemCount(infoPtr
->hwndHeader
)-1)
3074 CopyRect(&rec
,&rcItem
);
3075 rec
.left
= rec
.right
;
3076 rec
.right
= rec
.left
+REPORT_MARGINX
;
3077 ExtTextOutW(hdc
, rec
.left
, rec
.top
, textoutOptions
,
3078 &rec
, NULL
, 0, NULL
);
3080 CopyRect(&rec
,&rcItem
);
3081 rec
.right
= rec
.left
;
3082 rec
.left
= rec
.left
- REPORT_MARGINX
;
3083 ExtTextOutW(hdc
, rec
.left
, rec
.top
, textoutOptions
,
3084 &rec
, NULL
, 0, NULL
);
3094 * [I] HWND : window handle
3095 * [I] HDC : device context handle
3096 * [I] INT : item index
3097 * [I] RECT * : clipping rectangle
3102 static VOID
LISTVIEW_DrawItem(HWND hwnd
, HDC hdc
, INT nItem
, RECT rcItem
, BOOL FullSelect
, RECT
* SuggestedFocus
)
3104 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
3105 WCHAR szDispText
[DISP_TEXT_SIZE
];
3110 DWORD dwTextColor
,dwTextX
;
3111 BOOL bImage
= FALSE
;
3113 UINT textoutOptions
= ETO_OPAQUE
| ETO_CLIPPED
;
3116 TRACE("(hwnd=%x, hdc=%x, nItem=%d)\n", hwnd
, hdc
, nItem
);
3119 /* get information needed for drawing the item */
3120 ZeroMemory(&lvItem
, sizeof(lvItem
));
3121 lvItem
.mask
= LVIF_TEXT
| LVIF_IMAGE
| LVIF_STATE
| LVIF_INDENT
;
3122 lvItem
.stateMask
= LVIS_SELECTED
| LVIS_STATEIMAGEMASK
;
3123 lvItem
.iItem
= nItem
;
3124 lvItem
.iSubItem
= 0;
3125 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
3126 lvItem
.pszText
= szDispText
;
3127 *lvItem
.pszText
= '\0';
3128 LISTVIEW_GetItemW(hwnd
, &lvItem
, TRUE
);
3129 TRACE(" lvItem=%s\n", debuglvitem_t(&lvItem
, TRUE
));
3131 /* redraw the background of the item */
3133 if(infoPtr
->nColumnCount
== (nItem
+ 1))
3134 rcTemp
.right
= infoPtr
->rcList
.right
;
3136 rcTemp
.right
+=WIDTH_PADDING
;
3138 LISTVIEW_FillBackground(hwnd
, hdc
, &rcTemp
);
3141 if (lvItem
.iIndent
>0 && infoPtr
->iconSize
.cx
> 0)
3143 rcItem
.left
+= infoPtr
->iconSize
.cx
* lvItem
.iIndent
;
3146 SuggestedFocus
->left
+= infoPtr
->iconSize
.cx
* lvItem
.iIndent
;
3150 if (infoPtr
->himlState
!= NULL
)
3152 UINT uStateImage
= (lvItem
.state
& LVIS_STATEIMAGEMASK
) >> 12;
3153 if (uStateImage
> 0)
3155 ImageList_Draw(infoPtr
->himlState
, uStateImage
- 1, hdc
, rcItem
.left
,
3156 rcItem
.top
, ILD_NORMAL
);
3159 rcItem
.left
+= infoPtr
->iconSize
.cx
;
3161 SuggestedFocus
->left
+= infoPtr
->iconSize
.cx
;
3166 if (infoPtr
->himlSmall
!= NULL
)
3168 if ((lvItem
.state
& LVIS_SELECTED
) && (infoPtr
->bFocus
!= FALSE
) &&
3171 ImageList_SetBkColor(infoPtr
->himlSmall
, CLR_NONE
);
3172 ImageList_Draw(infoPtr
->himlSmall
, lvItem
.iImage
, hdc
, rcItem
.left
,
3173 rcItem
.top
, ILD_SELECTED
);
3175 else if (lvItem
.iImage
>=0)
3177 ImageList_SetBkColor(infoPtr
->himlSmall
, CLR_NONE
);
3178 ImageList_Draw(infoPtr
->himlSmall
, lvItem
.iImage
, hdc
, rcItem
.left
,
3179 rcItem
.top
, ILD_NORMAL
);
3182 rcItem
.left
+= infoPtr
->iconSize
.cx
;
3185 SuggestedFocus
->left
+= infoPtr
->iconSize
.cx
;
3189 /* Don't bother painting item being edited */
3190 if (infoPtr
->hwndEdit
&& lvItem
.state
& LVIS_FOCUSED
&& !FullSelect
)
3193 if ((lvItem
.state
& LVIS_SELECTED
) && (infoPtr
->bFocus
!= FALSE
))
3195 /* set item colors */
3196 dwBkColor
= SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
3197 dwTextColor
= SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
3198 /* set raster mode */
3199 nMixMode
= SetROP2(hdc
, R2_XORPEN
);
3201 else if ((GetWindowLongW(hwnd
, GWL_STYLE
) & LVS_SHOWSELALWAYS
) &&
3202 (lvItem
.state
& LVIS_SELECTED
) && (infoPtr
->bFocus
== FALSE
))
3204 dwBkColor
= SetBkColor(hdc
, GetSysColor(COLOR_3DFACE
));
3205 dwTextColor
= SetTextColor(hdc
, GetSysColor(COLOR_BTNTEXT
));
3206 /* set raster mode */
3207 nMixMode
= SetROP2(hdc
, R2_COPYPEN
);
3211 /* set item colors */
3212 if ( (infoPtr
->clrTextBk
== CLR_DEFAULT
) || (infoPtr
->clrTextBk
== CLR_NONE
) )
3214 dwBkColor
= GetBkColor(hdc
);
3215 iBkMode
= SetBkMode(hdc
, TRANSPARENT
);
3216 textoutOptions
&= ~ETO_OPAQUE
;
3220 dwBkColor
= SetBkColor(hdc
, infoPtr
->clrTextBk
);
3221 iBkMode
= SetBkMode(hdc
, OPAQUE
);
3224 dwTextColor
= SetTextColor(hdc
, infoPtr
->clrText
);
3225 /* set raster mode */
3226 nMixMode
= SetROP2(hdc
, R2_COPYPEN
);
3229 nLabelWidth
= ListView_GetStringWidthW(hwnd
, lvItem
.pszText
);
3230 if (rcItem
.left
+ nLabelWidth
< rcItem
.right
)
3233 rcItem
.right
= rcItem
.left
+ nLabelWidth
+ TRAILING_PADDING
;
3235 rcItem
.right
+= IMAGE_PADDING
;
3239 dwTextX
= rcItem
.left
+ 1;
3241 dwTextX
+= IMAGE_PADDING
;
3244 ExtTextOutW(hdc
, dwTextX
, rcItem
.top
, textoutOptions
,
3245 &rcItem
, lvItem
.pszText
, lstrlenW(lvItem
.pszText
), NULL
);
3247 if ((FullSelect
)&&(Header_GetItemCount(infoPtr
->hwndHeader
) > 1))
3249 /* fill in the gap */
3251 CopyRect(&rec
,&rcItem
);
3252 rec
.left
= rec
.right
;
3253 rec
.right
= rec
.left
+REPORT_MARGINX
;
3254 ExtTextOutW(hdc
, rec
.left
, rec
.top
, textoutOptions
,
3255 &rec
, NULL
, 0, NULL
);
3259 CopyRect(SuggestedFocus
,&rcItem
);
3263 SetROP2(hdc
, R2_COPYPEN
);
3264 SetBkColor(hdc
, dwBkColor
);
3265 SetTextColor(hdc
, dwTextColor
);
3267 SetBkMode(hdc
, iBkMode
);
3273 * Draws an item when in large icon display mode.
3276 * [I] HWND : window handle
3277 * [I] HDC : device context handle
3278 * [I] INT : item index
3279 * [I] RECT : clipping rectangle
3280 * [O] RECT * : The text rectangle about which to draw the focus
3285 static VOID
LISTVIEW_DrawLargeItem(HWND hwnd
, HDC hdc
, INT nItem
, RECT rcItem
,
3286 RECT
*SuggestedFocus
)
3288 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
3289 WCHAR szDispText
[DISP_TEXT_SIZE
] = { '\0' };
3291 UINT uFormat
= DT_TOP
| DT_CENTER
| DT_WORDBREAK
| DT_NOPREFIX
|
3293 /* Maintain this format in line with the one in LISTVIEW_UpdateLargeItemLabelRect*/
3296 TRACE("(hwnd=%x, hdc=%x, nItem=%d, left=%d, top=%d, right=%d, bottom=%d)\n",
3297 hwnd
, hdc
, nItem
, rcItem
.left
, rcItem
.top
, rcItem
.right
, rcItem
.bottom
);
3299 /* get information needed for drawing the item */
3300 ZeroMemory(&lvItem
, sizeof(lvItem
));
3301 lvItem
.mask
= LVIF_TEXT
| LVIF_IMAGE
| LVIF_STATE
;
3302 lvItem
.stateMask
= LVIS_SELECTED
| LVIS_FOCUSED
;
3303 lvItem
.iItem
= nItem
;
3304 lvItem
.iSubItem
= 0;
3305 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
3306 lvItem
.pszText
= szDispText
;
3307 *lvItem
.pszText
= '\0';
3308 LISTVIEW_GetItemW(hwnd
, &lvItem
, FALSE
);
3309 TRACE(" lvItem=%s\n", debuglvitem_t(&lvItem
, TRUE
));
3311 /* redraw the background of the item */
3313 if(infoPtr
->nColumnCount
== (nItem
+ 1))
3314 rcTemp
.right
= infoPtr
->rcList
.right
;
3316 rcTemp
.right
+=WIDTH_PADDING
;
3317 /* The comment doesn't say WIDTH_PADDING applies to large icons */
3319 TRACE("background rect (%d,%d)-(%d,%d)\n",
3320 rcTemp
.left
, rcTemp
.top
, rcTemp
.right
, rcTemp
.bottom
);
3322 LISTVIEW_FillBackground(hwnd
, hdc
, &rcTemp
);
3325 /* Figure out text colours etc. depending on state
3326 * At least the following states exist; there may be more.
3327 * Many items may be selected
3328 * At most one item may have the focus
3329 * The application may not actually be active currently
3330 * 1. The item is not selected in any way
3331 * 2. The cursor is flying over the icon or text and the text is being
3332 * expanded because it is not fully displayed currently.
3333 * 3. The item is selected and is focussed, i.e. the user has not clicked
3334 * in the blank area of the window, and the window (or application?)
3335 * still has the focus.
3336 * 4. As 3 except that a different window has the focus
3337 * 5. The item is the selected item of all the items, but the user has
3338 * clicked somewhere else on the window.
3339 * Only a few of these are handled currently. In particular 2 is not yet
3340 * handled since we do not support the functionality currently (or at least
3341 * we didn't when I wrote this)
3344 if (lvItem
.state
& LVIS_SELECTED
)
3346 /* set item colors */
3347 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
3348 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
3349 SetBkMode (hdc
, OPAQUE
);
3350 /* set raster mode */
3351 SetROP2(hdc
, R2_XORPEN
);
3352 /* When exactly is it in XOR? while being dragged? */
3356 /* set item colors */
3357 if ( (infoPtr
->clrTextBk
== CLR_DEFAULT
) || (infoPtr
->clrTextBk
== CLR_NONE
) )
3359 SetBkMode(hdc
, TRANSPARENT
);
3363 SetBkMode(hdc
, OPAQUE
);
3364 SetBkColor(hdc
, infoPtr
->clrTextBk
);
3367 SetTextColor(hdc
, infoPtr
->clrText
);
3368 /* set raster mode */
3369 SetROP2(hdc
, R2_COPYPEN
);
3372 /* In cases 2,3 and 5 (see above) the full text is displayed, with word
3373 * wrapping and long words split.
3374 * In cases 1 and 4 only a portion of the text is displayed with word
3375 * wrapping and both word and end ellipsis. (I don't yet know about path
3378 uFormat
|= ( (lvItem
.state
& LVIS_FOCUSED
) && infoPtr
->bFocus
) ?
3381 DT_WORD_ELLIPSIS
| DT_END_ELLIPSIS
;
3384 if (infoPtr
->himlNormal
!= NULL
)
3386 if (lvItem
.iImage
>= 0)
3388 ImageList_Draw (infoPtr
->himlNormal
, lvItem
.iImage
, hdc
, rcItem
.left
,
3390 (lvItem
.state
& LVIS_SELECTED
) ? ILD_SELECTED
: ILD_NORMAL
);
3394 /* Draw the text below the icon */
3396 /* Don't bother painting item being edited */
3397 if ((infoPtr
->hwndEdit
&& (lvItem
.state
& LVIS_FOCUSED
)) ||
3398 !lstrlenW(lvItem
.pszText
))
3400 SetRectEmpty(SuggestedFocus
);
3404 /* Since rcItem.left is left point of icon, compute left point of item box */
3405 rcItem
.left
-= ((infoPtr
->nItemWidth
- infoPtr
->iconSize
.cx
) / 2);
3406 rcItem
.right
= rcItem
.left
+ infoPtr
->nItemWidth
;
3407 rcItem
.bottom
= rcItem
.top
+ infoPtr
->nItemHeight
;
3408 TRACE("bound box for text+icon (%d,%d)-(%d,%d), iS.cx=%ld, nItemWidth=%d\n",
3409 rcItem
.left
, rcItem
.top
, rcItem
.right
, rcItem
.bottom
,
3410 infoPtr
->iconSize
.cx
, infoPtr
->nItemWidth
);
3411 TRACE("rcList (%d,%d)-(%d,%d), rcView (%d,%d)-(%d,%d)\n",
3412 infoPtr
->rcList
.left
, infoPtr
->rcList
.top
,
3413 infoPtr
->rcList
.right
, infoPtr
->rcList
.bottom
,
3414 infoPtr
->rcView
.left
, infoPtr
->rcView
.top
,
3415 infoPtr
->rcView
.right
, infoPtr
->rcView
.bottom
);
3417 InflateRect(&rcItem
, -(2*CAPTION_BORDER
), 0);
3418 rcItem
.top
+= infoPtr
->iconSize
.cy
+ ICON_BOTTOM_PADDING
;
3423 /* I am sure of most of the uFormat values. However I am not sure about
3424 * whether we need or do not need the following:
3425 * DT_EXTERNALLEADING, DT_INTERNAL, DT_CALCRECT, DT_NOFULLWIDTHCHARBREAK,
3426 * DT_PATH_ELLIPSIS, DT_RTLREADING,
3427 * We certainly do not need
3428 * DT_BOTTOM, DT_VCENTER, DT_MODIFYSTRING, DT_LEFT, DT_RIGHT, DT_PREFIXONLY,
3429 * DT_SINGLELINE, DT_TABSTOP, DT_EXPANDTABS
3432 /* If the text is being drawn without clipping (i.e. the full text) then we
3433 * need to jump through a few hoops to ensure that it all gets displayed and
3434 * that the background is complete
3436 if (uFormat
& DT_NOCLIP
)
3439 HBRUSH hBrush
= CreateSolidBrush(GetBkColor (hdc
));
3440 int dx
, dy
, old_wid
, new_wid
;
3441 DrawTextW (hdc
, lvItem
.pszText
, -1, &rcItem
, uFormat
| DT_CALCRECT
);
3442 /* Microsoft, in their great wisdom, have decided that the rectangle
3443 * returned by DrawText on DT_CALCRECT will only guarantee the dimension,
3444 * not the location. So we have to do the centring ourselves (and take
3445 * responsibility for agreeing off-by-one consistency with them).
3447 old_wid
= rcItem
.right
-rcItem
.left
;
3448 new_wid
= rcBack
.right
- rcBack
.left
;
3449 dx
= rcBack
.left
- rcItem
.left
+ (new_wid
-old_wid
)/2;
3450 dy
= rcBack
.top
- rcItem
.top
;
3451 OffsetRect (&rcItem
, dx
, dy
);
3452 FillRect(hdc
, &rcItem
, hBrush
);
3453 DeleteObject(hBrush
);
3455 /* else ? What if we are losing the focus? will we not get a complete
3458 DrawTextW (hdc
, lvItem
.pszText
, -1, &rcItem
, uFormat
);
3460 CopyRect(SuggestedFocus
, &rcItem
);
3465 * Draws listview items when in report display mode.
3468 * [I] HWND : window handle
3469 * [I] HDC : device context handle
3474 static VOID
LISTVIEW_RefreshReport(HWND hwnd
, HDC hdc
, DWORD cdmode
)
3476 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
,0);
3477 SCROLLINFO scrollInfo
;
3478 INT nDrawPosY
= infoPtr
->rcList
.top
;
3480 RECT rcItem
, rcTemp
;
3485 DWORD cditemmode
= CDRF_DODEFAULT
;
3486 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
3489 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
3490 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
3491 scrollInfo
.fMask
= SIF_POS
;
3493 nItem
= ListView_GetTopIndex(hwnd
);
3495 /* add 1 for displaying a partial item at the bottom */
3496 nLast
= nItem
+ LISTVIEW_GetCountPerColumn(hwnd
) + 1;
3497 nLast
= min(nLast
, GETITEMCOUNT(infoPtr
));
3499 /* send cache hint notification */
3500 if (GetWindowLongW(hwnd
,GWL_STYLE
) & LVS_OWNERDATA
)
3504 nmlv
.hdr
.hwndFrom
= hwnd
;
3505 nmlv
.hdr
.idFrom
= GetWindowLongW(hwnd
,GWL_ID
);
3506 nmlv
.hdr
.code
= LVN_ODCACHEHINT
;
3510 SendMessageW(GetParent(hwnd
), WM_NOTIFY
, (WPARAM
)nmlv
.hdr
.idFrom
,
3514 nColumnCount
= Header_GetItemCount(infoPtr
->hwndHeader
);
3515 infoPtr
->nColumnCount
= nColumnCount
; /* update nColumnCount */
3516 FullSelected
= infoPtr
->dwExStyle
& LVS_EX_FULLROWSELECT
;
3518 /* clear the background of any part of the control that doesn't contain items */
3519 SubtractRect(&rcTemp
, &infoPtr
->rcList
, &infoPtr
->rcView
);
3520 LISTVIEW_FillBackground(hwnd
, hdc
, &rcTemp
);
3522 /* nothing to draw */
3523 if(GETITEMCOUNT(infoPtr
) == 0)
3526 /* Get scroll bar info once before loop */
3527 GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
);
3528 scrollOffset
= scrollInfo
.nPos
* LISTVIEW_SCROLL_DIV_SIZE
;
3530 for (; nItem
< nLast
; nItem
++)
3532 RECT SuggestedFocusRect
;
3535 if (lStyle
& LVS_OWNERDRAWFIXED
)
3537 UINT uID
= GetWindowLongW( hwnd
, GWL_ID
);
3542 TRACE("Owner Drawn\n");
3543 dis
.CtlType
= ODT_LISTVIEW
;
3546 dis
.itemAction
= ODA_DRAWENTIRE
;
3549 if (LISTVIEW_IsSelected(hwnd
,nItem
)) dis
.itemState
|=ODS_SELECTED
;
3550 if (nItem
==infoPtr
->nFocusedItem
) dis
.itemState
|=ODS_FOCUS
;
3552 dis
.hwndItem
= hwnd
;
3555 Header_GetItemRect(infoPtr
->hwndHeader
, nColumnCount
-1, &br
);
3557 dis
.rcItem
.left
= -scrollOffset
;
3558 dis
.rcItem
.right
= max(dis
.rcItem
.left
, br
.right
- scrollOffset
);
3559 dis
.rcItem
.top
= nDrawPosY
;
3560 dis
.rcItem
.bottom
= dis
.rcItem
.top
+ infoPtr
->nItemHeight
;
3562 ZeroMemory(&item
,sizeof(item
));
3564 item
.mask
= LVIF_PARAM
;
3565 ListView_GetItemW(hwnd
, &item
);
3567 dis
.itemData
= item
.lParam
;
3569 if (SendMessageW(GetParent(hwnd
),WM_DRAWITEM
,(WPARAM
)uID
,(LPARAM
)&dis
))
3571 nDrawPosY
+= infoPtr
->nItemHeight
;
3580 Header_GetItemRect(infoPtr
->hwndHeader
, 0, &ir
);
3581 Header_GetItemRect(infoPtr
->hwndHeader
, nColumnCount
-1, &br
);
3583 ir
.left
+= REPORT_MARGINX
;
3584 ir
.right
= max(ir
.left
, br
.right
- REPORT_MARGINX
);
3586 ir
.bottom
= ir
.top
+ infoPtr
->nItemHeight
;
3588 CopyRect(&SuggestedFocusRect
,&ir
);
3591 for (j
= 0; j
< nColumnCount
; j
++)
3593 if (cdmode
& CDRF_NOTIFYITEMDRAW
)
3594 cditemmode
= LISTVIEW_SendCustomDrawItemNotify (hwnd
, hdc
, nItem
, j
,
3596 if (cditemmode
& CDRF_SKIPDEFAULT
)
3599 Header_GetItemRect(infoPtr
->hwndHeader
, j
, &rcItem
);
3601 rcItem
.left
+= REPORT_MARGINX
;
3602 rcItem
.right
= max(rcItem
.left
, rcItem
.right
- REPORT_MARGINX
);
3603 rcItem
.top
= nDrawPosY
;
3604 rcItem
.bottom
= rcItem
.top
+ infoPtr
->nItemHeight
;
3606 /* Offset the Scroll Bar Pos */
3607 rcItem
.left
-= scrollOffset
;
3608 rcItem
.right
-= scrollOffset
;
3612 LISTVIEW_DrawItem(hwnd
, hdc
, nItem
, rcItem
, FullSelected
,
3613 &SuggestedFocusRect
);
3617 LISTVIEW_DrawSubItem(hwnd
, hdc
, nItem
, j
, rcItem
, FullSelected
);
3620 if (cditemmode
& CDRF_NOTIFYPOSTPAINT
)
3621 LISTVIEW_SendCustomDrawItemNotify(hwnd
, hdc
, nItem
, 0,
3622 CDDS_ITEMPOSTPAINT
);
3627 if (LISTVIEW_GetItemState(hwnd
,nItem
,LVIS_FOCUSED
) && infoPtr
->bFocus
)
3630 if (FullSelected
&& LISTVIEW_GetItemState(hwnd
,nItem
,LVIS_SELECTED
))
3631 rop
= SetROP2(hdc
, R2_XORPEN
);
3633 Rectangle(hdc
, SuggestedFocusRect
.left
, SuggestedFocusRect
.top
,
3634 SuggestedFocusRect
.right
,SuggestedFocusRect
.bottom
);
3637 SetROP2(hdc
, R2_COPYPEN
);
3639 nDrawPosY
+= infoPtr
->nItemHeight
;
3645 * Retrieves the number of items that can fit vertically in the client area.
3648 * [I] HWND : window handle
3651 * Number of items per row.
3653 static INT
LISTVIEW_GetCountPerRow(HWND hwnd
)
3655 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
,0);
3656 UINT uView
= GetWindowLongW(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
3657 INT nListWidth
= infoPtr
->rcList
.right
- infoPtr
->rcList
.left
;
3658 INT nCountPerRow
= 1;
3662 if (uView
!= LVS_REPORT
)
3664 nCountPerRow
= nListWidth
/ infoPtr
->nItemWidth
;
3665 if (nCountPerRow
== 0) nCountPerRow
= 1;
3669 return nCountPerRow
;
3674 * Retrieves the number of items that can fit horizontally in the client
3678 * [I] HWND : window handle
3681 * Number of items per column.
3683 static INT
LISTVIEW_GetCountPerColumn(HWND hwnd
)
3685 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
,0);
3686 INT nListHeight
= infoPtr
->rcList
.bottom
- infoPtr
->rcList
.top
;
3687 INT nCountPerColumn
= 1;
3689 if (nListHeight
> 0)
3691 nCountPerColumn
= nListHeight
/ infoPtr
->nItemHeight
;
3692 if (nCountPerColumn
== 0) nCountPerColumn
= 1;
3695 return nCountPerColumn
;
3700 * Retrieves the number of columns needed to display all the items when in
3701 * list display mode.
3704 * [I] HWND : window handle
3707 * Number of columns.
3709 static INT
LISTVIEW_GetColumnCount(HWND hwnd
)
3711 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
3712 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
3713 INT nColumnCount
= 0;
3715 if ((lStyle
& LVS_TYPEMASK
) == LVS_LIST
)
3717 nColumnCount
= infoPtr
->rcList
.right
/ infoPtr
->nItemWidth
;
3718 if (infoPtr
->rcList
.right
% infoPtr
->nItemWidth
) nColumnCount
++;
3721 return nColumnCount
;
3727 * Draws listview items when in list display mode.
3730 * [I] HWND : window handle
3731 * [I] HDC : device context handle
3736 static VOID
LISTVIEW_RefreshList(HWND hwnd
, HDC hdc
, DWORD cdmode
)
3738 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
3739 RECT rcItem
, FocusRect
, rcTemp
;
3743 INT nCountPerColumn
;
3744 INT nItemWidth
= infoPtr
->nItemWidth
;
3745 INT nItemHeight
= infoPtr
->nItemHeight
;
3746 DWORD cditemmode
= CDRF_DODEFAULT
;
3748 /* get number of fully visible columns */
3749 nColumnCount
= LISTVIEW_GetColumnCount(hwnd
);
3750 infoPtr
->nColumnCount
= nColumnCount
;
3751 nCountPerColumn
= LISTVIEW_GetCountPerColumn(hwnd
);
3752 nItem
= ListView_GetTopIndex(hwnd
);
3754 /* paint the background of the control that doesn't contain any items */
3755 SubtractRect(&rcTemp
, &infoPtr
->rcList
, &infoPtr
->rcView
);
3756 LISTVIEW_FillBackground(hwnd
, hdc
, &rcTemp
);
3758 /* nothing to draw, return here */
3759 if(GETITEMCOUNT(infoPtr
) == 0)
3762 for (i
= 0; i
< nColumnCount
; i
++)
3764 for (j
= 0; j
< nCountPerColumn
; j
++, nItem
++)
3766 if (nItem
>= GETITEMCOUNT(infoPtr
))
3769 if (cdmode
& CDRF_NOTIFYITEMDRAW
)
3770 cditemmode
= LISTVIEW_SendCustomDrawItemNotify (hwnd
, hdc
, nItem
, 0,
3772 if (cditemmode
& CDRF_SKIPDEFAULT
)
3775 rcItem
.top
= j
* nItemHeight
;
3776 rcItem
.left
= i
* nItemWidth
;
3777 rcItem
.bottom
= rcItem
.top
+ nItemHeight
;
3778 rcItem
.right
= rcItem
.left
+ nItemWidth
;
3779 LISTVIEW_DrawItem(hwnd
, hdc
, nItem
, rcItem
, FALSE
, &FocusRect
);
3783 if (LISTVIEW_GetItemState(hwnd
,nItem
,LVIS_FOCUSED
) && infoPtr
->bFocus
)
3784 Rectangle(hdc
, FocusRect
.left
, FocusRect
.top
,
3785 FocusRect
.right
,FocusRect
.bottom
);
3787 if (cditemmode
& CDRF_NOTIFYPOSTPAINT
)
3788 LISTVIEW_SendCustomDrawItemNotify(hwnd
, hdc
, nItem
, 0,
3789 CDDS_ITEMPOSTPAINT
);
3797 * Draws listview items when in icon or small icon display mode.
3800 * [I] HWND : window handle
3801 * [I] HDC : device context handle
3806 static VOID
LISTVIEW_RefreshIcon(HWND hwnd
, HDC hdc
, BOOL bSmall
, DWORD cdmode
)
3808 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
3811 RECT rcItem
, SuggestedFocus
, rcTemp
;
3813 DWORD cditemmode
= CDRF_DODEFAULT
;
3815 infoPtr
->nColumnCount
= 1; /* set this to an arbitrary value to prevent */
3816 /* DrawItem from erasing the incorrect background area */
3818 /* paint the background of the control that doesn't contain any items */
3819 SubtractRect(&rcTemp
, &infoPtr
->rcList
, &infoPtr
->rcView
);
3820 LISTVIEW_FillBackground(hwnd
, hdc
, &rcTemp
);
3822 /* nothing to draw, return here */
3823 if(GETITEMCOUNT(infoPtr
) == 0)
3826 LISTVIEW_GetOrigin(hwnd
, &ptOrigin
);
3827 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
3829 if (cdmode
& CDRF_NOTIFYITEMDRAW
)
3830 cditemmode
= LISTVIEW_SendCustomDrawItemNotify (hwnd
, hdc
, i
, 0,
3832 if (cditemmode
& CDRF_SKIPDEFAULT
)
3835 LISTVIEW_GetItemPosition(hwnd
, i
, &ptPosition
);
3836 ptPosition
.x
+= ptOrigin
.x
;
3837 ptPosition
.y
+= ptOrigin
.y
;
3839 if (ptPosition
.y
+ infoPtr
->nItemHeight
> infoPtr
->rcList
.top
)
3841 if (ptPosition
.x
+ infoPtr
->nItemWidth
> infoPtr
->rcList
.left
)
3843 if (ptPosition
.y
< infoPtr
->rcList
.bottom
)
3845 if (ptPosition
.x
< infoPtr
->rcList
.right
)
3847 rcItem
.top
= ptPosition
.y
;
3848 rcItem
.left
= ptPosition
.x
;
3849 rcItem
.bottom
= rcItem
.top
+ infoPtr
->nItemHeight
;
3850 rcItem
.right
= rcItem
.left
+ infoPtr
->nItemWidth
;
3852 LISTVIEW_DrawItem(hwnd
, hdc
, i
, rcItem
, FALSE
, &SuggestedFocus
);
3854 LISTVIEW_DrawLargeItem(hwnd
, hdc
, i
, rcItem
, &SuggestedFocus
);
3858 if (LISTVIEW_GetItemState(hwnd
,i
,LVIS_FOCUSED
) &&
3859 infoPtr
->bFocus
&& !IsRectEmpty(&SuggestedFocus
))
3860 Rectangle(hdc
, SuggestedFocus
.left
, SuggestedFocus
.top
,
3861 SuggestedFocus
.right
,SuggestedFocus
.bottom
);
3866 if (cditemmode
& CDRF_NOTIFYPOSTPAINT
)
3867 LISTVIEW_SendCustomDrawItemNotify(hwnd
, hdc
, i
, 0,
3868 CDDS_ITEMPOSTPAINT
);
3874 * Draws listview items.
3877 * [I] HWND : window handle
3878 * [I] HDC : device context handle
3883 static VOID
LISTVIEW_Refresh(HWND hwnd
, HDC hdc
)
3885 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
3886 UINT uView
= GetWindowLongW(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
3892 LISTVIEW_DumpListview (infoPtr
, __LINE__
);
3894 GetClientRect(hwnd
, &rect
);
3895 cdmode
= LISTVIEW_SendCustomDrawNotify(hwnd
,CDDS_PREPAINT
,hdc
,rect
);
3897 if (cdmode
== CDRF_SKIPDEFAULT
) return;
3900 hOldFont
= SelectObject(hdc
, infoPtr
->hFont
);
3902 /* select the dotted pen (for drawing the focus box) */
3903 hPen
= CreatePen(PS_ALTERNATE
, 1, 0);
3904 hOldPen
= SelectObject(hdc
, hPen
);
3906 /* select transparent brush (for drawing the focus box) */
3907 SelectObject(hdc
, GetStockObject(NULL_BRUSH
));
3909 if (uView
== LVS_LIST
)
3910 LISTVIEW_RefreshList(hwnd
, hdc
, cdmode
);
3911 else if (uView
== LVS_REPORT
)
3912 LISTVIEW_RefreshReport(hwnd
, hdc
, cdmode
);
3913 else if (uView
== LVS_SMALLICON
)
3914 LISTVIEW_RefreshIcon(hwnd
, hdc
, TRUE
, cdmode
);
3915 else if (uView
== LVS_ICON
)
3916 LISTVIEW_RefreshIcon(hwnd
, hdc
, FALSE
, cdmode
);
3918 /* unselect objects */
3919 SelectObject(hdc
, hOldFont
);
3920 SelectObject(hdc
, hOldPen
);
3925 if (cdmode
& CDRF_NOTIFYPOSTPAINT
)
3926 LISTVIEW_SendCustomDrawNotify(hwnd
, CDDS_POSTPAINT
, hdc
, rect
);
3932 * Calculates the approximate width and height of a given number of items.
3935 * [I] HWND : window handle
3936 * [I] INT : number of items
3941 * Returns a DWORD. The width in the low word and the height in high word.
3943 static LRESULT
LISTVIEW_ApproximateViewRect(HWND hwnd
, INT nItemCount
,
3944 WORD wWidth
, WORD wHeight
)
3946 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
3947 UINT uView
= GetWindowLongW(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
3948 INT nItemCountPerColumn
= 1;
3949 INT nColumnCount
= 0;
3950 DWORD dwViewRect
= 0;
3952 if (nItemCount
== -1)
3953 nItemCount
= GETITEMCOUNT(infoPtr
);
3955 if (uView
== LVS_LIST
)
3957 if (wHeight
== 0xFFFF)
3959 /* use current height */
3960 wHeight
= infoPtr
->rcList
.bottom
- infoPtr
->rcList
.top
;
3963 if (wHeight
< infoPtr
->nItemHeight
)
3964 wHeight
= infoPtr
->nItemHeight
;
3968 if (infoPtr
->nItemHeight
> 0)
3970 nItemCountPerColumn
= wHeight
/ infoPtr
->nItemHeight
;
3971 if (nItemCountPerColumn
== 0)
3972 nItemCountPerColumn
= 1;
3974 if (nItemCount
% nItemCountPerColumn
!= 0)
3975 nColumnCount
= nItemCount
/ nItemCountPerColumn
;
3977 nColumnCount
= nItemCount
/ nItemCountPerColumn
+ 1;
3981 /* Microsoft padding magic */
3982 wHeight
= nItemCountPerColumn
* infoPtr
->nItemHeight
+ 2;
3983 wWidth
= nColumnCount
* infoPtr
->nItemWidth
+ 2;
3985 dwViewRect
= MAKELONG(wWidth
, wHeight
);
3987 else if (uView
== LVS_REPORT
)
3988 FIXME("uView == LVS_REPORT: not implemented\n");
3989 else if (uView
== LVS_SMALLICON
)
3990 FIXME("uView == LVS_SMALLICON: not implemented\n");
3991 else if (uView
== LVS_ICON
)
3992 FIXME("uView == LVS_ICON: not implemented\n");
3999 * Arranges listview items in icon display mode.
4002 * [I] HWND : window handle
4003 * [I] INT : alignment code
4009 static LRESULT
LISTVIEW_Arrange(HWND hwnd
, INT nAlignCode
)
4011 UINT uView
= GetWindowLongW(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
4012 BOOL bResult
= FALSE
;
4014 if ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
))
4019 FIXME("nAlignCode=LVA_ALIGNLEFT: not implemented\n");
4022 FIXME("nAlignCode=LVA_ALIGNTOP: not implemented\n");
4025 FIXME("nAlignCode=LVA_DEFAULT: not implemented\n");
4027 case LVA_SNAPTOGRID
:
4028 FIXME("nAlignCode=LVA_SNAPTOGRID: not implemented\n");
4036 /* << LISTVIEW_CreateDragImage >> */
4041 * Removes all listview items and subitems.
4044 * [I] HWND : window handle
4050 static LRESULT
LISTVIEW_DeleteAllItems(HWND hwnd
)
4052 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
4053 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
4054 UINT uView
= lStyle
& LVS_TYPEMASK
;
4055 LISTVIEW_ITEM
*lpItem
;
4056 LISTVIEW_SUBITEM
*lpSubItem
;
4059 BOOL bResult
= FALSE
;
4062 TRACE("(hwnd=%x,)\n", hwnd
);
4064 LISTVIEW_RemoveAllSelections(hwnd
);
4065 infoPtr
->nSelectionMark
=-1;
4066 infoPtr
->nFocusedItem
=-1;
4067 /* But we are supposed to leave nHotItem as is! */
4069 if (lStyle
& LVS_OWNERDATA
)
4071 infoPtr
->hdpaItems
->nItemCount
= 0;
4072 InvalidateRect(hwnd
, NULL
, TRUE
);
4076 if (GETITEMCOUNT(infoPtr
) > 0)
4080 /* send LVN_DELETEALLITEMS notification */
4081 /* verify if subsequent LVN_DELETEITEM notifications should be
4083 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
4085 bSuppress
= listview_notify(hwnd
, LVN_DELETEALLITEMS
, &nmlv
);
4087 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
4089 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, i
);
4090 if (hdpaSubItems
!= NULL
)
4092 for (j
= 1; j
< hdpaSubItems
->nItemCount
; j
++)
4094 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, j
);
4095 if (lpSubItem
!= NULL
)
4097 /* free subitem string */
4098 if (is_textW(lpSubItem
->pszText
))
4099 COMCTL32_Free(lpSubItem
->pszText
);
4102 COMCTL32_Free(lpSubItem
);
4106 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
4111 /* send LVN_DELETEITEM notification */
4113 nmlv
.lParam
= lpItem
->lParam
;
4114 listview_notify(hwnd
, LVN_DELETEITEM
, &nmlv
);
4117 /* free item string */
4118 if (is_textW(lpItem
->pszText
))
4119 COMCTL32_Free(lpItem
->pszText
);
4122 COMCTL32_Free(lpItem
);
4125 DPA_Destroy(hdpaSubItems
);
4129 /* reinitialize listview memory */
4130 bResult
= DPA_DeleteAllPtrs(infoPtr
->hdpaItems
);
4132 /* align items (set position of each item) */
4133 if ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
))
4135 if (lStyle
& LVS_ALIGNLEFT
)
4137 LISTVIEW_AlignLeft(hwnd
);
4141 LISTVIEW_AlignTop(hwnd
);
4145 LISTVIEW_UpdateScroll(hwnd
);
4147 /* invalidate client area (optimization needed) */
4148 InvalidateRect(hwnd
, NULL
, TRUE
);
4156 * Removes a column from the listview control.
4159 * [I] HWND : window handle
4160 * [I] INT : column index
4166 static LRESULT
LISTVIEW_DeleteColumn(HWND hwnd
, INT nColumn
)
4168 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
4169 UINT uView
= GetWindowLongW(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
4170 UINT uOwnerData
= GetWindowLongW(hwnd
, GWL_STYLE
) & LVS_OWNERDATA
;
4171 BOOL bResult
= FALSE
;
4173 if (Header_DeleteItem(infoPtr
->hwndHeader
, nColumn
) != FALSE
)
4176 bResult
= LISTVIEW_RemoveColumn(infoPtr
->hdpaItems
, nColumn
);
4178 /* Need to reset the item width when deleting a column */
4179 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
4181 /* reset scroll parameters */
4182 if (uView
== LVS_REPORT
)
4184 /* update scrollbar(s) */
4185 LISTVIEW_UpdateScroll(hwnd
);
4187 /* refresh client area */
4188 InvalidateRect(hwnd
, NULL
, FALSE
);
4197 * Removes an item from the listview control.
4200 * [I] HWND : window handle
4201 * [I] INT : item index
4207 static LRESULT
LISTVIEW_DeleteItem(HWND hwnd
, INT nItem
)
4209 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
4210 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
4211 UINT uView
= lStyle
& LVS_TYPEMASK
;
4212 LONG lCtrlId
= GetWindowLongW(hwnd
, GWL_ID
);
4214 BOOL bResult
= FALSE
;
4216 LISTVIEW_ITEM
*lpItem
;
4217 LISTVIEW_SUBITEM
*lpSubItem
;
4221 TRACE("(hwnd=%x, nItem=%d)\n", hwnd
, nItem
);
4224 /* First, send LVN_DELETEITEM notification. */
4225 memset(&nmlv
, 0, sizeof (NMLISTVIEW
));
4226 nmlv
.hdr
.hwndFrom
= hwnd
;
4227 nmlv
.hdr
.idFrom
= lCtrlId
;
4228 nmlv
.hdr
.code
= LVN_DELETEITEM
;
4230 SendMessageW(GetParent(hwnd
), WM_NOTIFY
, (WPARAM
)lCtrlId
,
4234 /* remove it from the selection range */
4235 ZeroMemory(&item
,sizeof(item
));
4236 item
.stateMask
= LVIS_SELECTED
;
4237 LISTVIEW_SetItemState(hwnd
,nItem
,&item
);
4239 if (lStyle
& LVS_OWNERDATA
)
4241 infoPtr
->hdpaItems
->nItemCount
--;
4242 InvalidateRect(hwnd
, NULL
, TRUE
);
4246 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
4248 /* initialize memory */
4249 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
4251 hdpaSubItems
= (HDPA
)DPA_DeletePtr(infoPtr
->hdpaItems
, nItem
);
4252 if (hdpaSubItems
!= NULL
)
4254 for (i
= 1; i
< hdpaSubItems
->nItemCount
; i
++)
4256 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, i
);
4257 if (lpSubItem
!= NULL
)
4259 /* free item string */
4260 if (is_textW(lpSubItem
->pszText
))
4261 COMCTL32_Free(lpSubItem
->pszText
);
4264 COMCTL32_Free(lpSubItem
);
4268 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
4271 /* free item string */
4272 if (is_textW(lpItem
->pszText
))
4273 COMCTL32_Free(lpItem
->pszText
);
4276 COMCTL32_Free(lpItem
);
4279 bResult
= DPA_Destroy(hdpaSubItems
);
4282 LISTVIEW_ShiftIndices(hwnd
,nItem
,-1);
4284 /* align items (set position of each item) */
4285 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
4287 if (lStyle
& LVS_ALIGNLEFT
)
4288 LISTVIEW_AlignLeft(hwnd
);
4290 LISTVIEW_AlignTop(hwnd
);
4293 LISTVIEW_UpdateScroll(hwnd
);
4295 /* refresh client area */
4296 InvalidateRect(hwnd
, NULL
, TRUE
);
4305 * Return edit control handle of current edit label
4308 * [I] HWND : window handle
4314 static LRESULT
LISTVIEW_GetEditControl(HWND hwnd
)
4316 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
4317 return infoPtr
->hwndEdit
;
4323 * Callback implementation for editlabel control
4326 * [I] HWND : window handle
4327 * [I] LPSTR : modified text
4328 * [I] DWORD : item index
4329 * [I] isW : TRUE if psxText is Unicode, FALSE if it's ANSI
4335 static BOOL
LISTVIEW_EndEditLabelT(HWND hwnd
, LPWSTR pszText
, DWORD nItem
, BOOL isW
)
4337 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
4338 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
4339 NMLVDISPINFOW dispInfo
;
4340 LISTVIEW_ITEM
*lpItem
;
4342 LISTVIEW_ITEM lvItemRef
;
4344 BOOL bResult
= TRUE
;
4346 TRACE("(hwnd=%x, pszText=%s, nItem=%ld, isW=%d)\n", hwnd
, debugstr_t(pszText
, isW
), nItem
, isW
);
4348 if (!(lStyle
& LVS_OWNERDATA
))
4350 if (!(hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
)))
4353 if (!(lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0)))
4358 ZeroMemory(&lvItemRef
,sizeof(LISTVIEW_ITEM
));
4359 ZeroMemory(&item
,sizeof(item
));
4362 item
.mask
= LVIF_PARAM
| LVIF_STATE
;
4363 ListView_GetItemW(hwnd
, &item
);
4364 lvItemRef
.state
= item
.state
;
4365 lvItemRef
.iImage
= item
.iImage
;
4366 lvItemRef
.lParam
= item
.lParam
;
4367 lpItem
= &lvItemRef
;
4370 ZeroMemory(&dispInfo
, sizeof(dispInfo
));
4371 dispInfo
.item
.mask
= 0;
4372 dispInfo
.item
.iItem
= nItem
;
4373 dispInfo
.item
.state
= lpItem
->state
;
4374 dispInfo
.item
.stateMask
= 0;
4375 dispInfo
.item
.pszText
= pszText
;
4376 dispInfo
.item
.cchTextMax
= textlenT(pszText
, isW
);
4377 dispInfo
.item
.iImage
= lpItem
->iImage
;
4378 dispInfo
.item
.lParam
= lpItem
->lParam
;
4379 infoPtr
->hwndEdit
= 0;
4381 /* Do we need to update the Item Text */
4382 if(dispinfo_notifyT(hwnd
, LVN_ENDLABELEDITW
, &dispInfo
, isW
))
4383 if (lpItem
->pszText
!= LPSTR_TEXTCALLBACKW
&& !(lStyle
& LVS_OWNERDATA
))
4384 bResult
= textsetptrT(&lpItem
->pszText
, pszText
, isW
);
4391 * Callback implementation for editlabel control
4394 * [I] HWND : window handle
4395 * [I] LPSTR : modified text
4396 * [I] DWORD : item index
4402 static BOOL
LISTVIEW_EndEditLabelW(HWND hwnd
, LPWSTR pszText
, DWORD nItem
)
4404 return LISTVIEW_EndEditLabelT(hwnd
, pszText
, nItem
, TRUE
);
4409 * Callback implementation for editlabel control
4412 * [I] HWND : window handle
4413 * [I] LPSTR : modified text
4414 * [I] DWORD : item index
4420 static BOOL
LISTVIEW_EndEditLabelA(HWND hwnd
, LPSTR pszText
, DWORD nItem
)
4422 return LISTVIEW_EndEditLabelT(hwnd
, (LPWSTR
)pszText
, nItem
, FALSE
);
4427 * Begin in place editing of specified list view item
4430 * [I] HWND : window handle
4431 * [I] INT : item index
4432 * [I] isW : TRUE if it's a Unicode req, FALSE if ASCII
4438 static HWND
LISTVIEW_EditLabelT(HWND hwnd
, INT nItem
, BOOL isW
)
4440 NMLVDISPINFOW dispInfo
;
4442 LISTVIEW_ITEM
*lpItem
;
4444 HINSTANCE hinst
= GetWindowLongW(hwnd
, GWL_HINSTANCE
);
4445 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
4447 WCHAR szDispText
[DISP_TEXT_SIZE
];
4449 LISTVIEW_ITEM lvItemRef
;
4450 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
4452 if (~GetWindowLongW(hwnd
, GWL_STYLE
) & LVS_EDITLABELS
)
4455 /* Is the EditBox still there, if so remove it */
4456 if(infoPtr
->hwndEdit
!= 0)
4459 LISTVIEW_SetSelection(hwnd
, nItem
);
4460 LISTVIEW_SetItemFocus(hwnd
, nItem
);
4462 if (!(lStyle
& LVS_OWNERDATA
))
4464 if (NULL
== (hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
)))
4467 if (NULL
== (lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0)))
4473 ZeroMemory(&lvItemRef
,sizeof(LISTVIEW_ITEM
));
4474 ZeroMemory(&item
, sizeof(item
));
4477 item
.mask
= LVIF_PARAM
| LVIF_STATE
;
4478 ListView_GetItemW(hwnd
, &item
);
4479 lvItemRef
.iImage
= item
.iImage
;
4480 lvItemRef
.state
= item
.state
;
4481 lvItemRef
.lParam
= item
.lParam
;
4482 lpItem
= &lvItemRef
;
4485 /* get information needed for drawing the item */
4486 ZeroMemory(&lvItem
, sizeof(lvItem
));
4487 lvItem
.mask
= LVIF_TEXT
;
4488 lvItem
.iItem
= nItem
;
4489 lvItem
.iSubItem
= 0;
4490 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
4491 lvItem
.pszText
= szDispText
;
4492 *lvItem
.pszText
= '\0';
4493 LISTVIEW_GetItemT(hwnd
, &lvItem
, FALSE
, isW
);
4495 ZeroMemory(&dispInfo
, sizeof(dispInfo
));
4496 dispInfo
.item
.mask
= 0;
4497 dispInfo
.item
.iItem
= nItem
;
4498 dispInfo
.item
.state
= lpItem
->state
;
4499 dispInfo
.item
.stateMask
= 0;
4500 dispInfo
.item
.pszText
= lvItem
.pszText
;
4501 dispInfo
.item
.cchTextMax
= lstrlenW(lvItem
.pszText
);
4502 dispInfo
.item
.iImage
= lpItem
->iImage
;
4503 dispInfo
.item
.lParam
= lpItem
->lParam
;
4505 if (dispinfo_notifyT(hwnd
, LVN_BEGINLABELEDITW
, &dispInfo
, isW
))
4508 rect
.left
= LVIR_LABEL
;
4509 if (!LISTVIEW_GetItemRect(hwnd
, nItem
, &rect
))
4512 if (!(hedit
= CreateEditLabelT(szDispText
, WS_VISIBLE
,
4513 rect
.left
-2, rect
.top
-1, 0, rect
.bottom
- rect
.top
+2, hwnd
, hinst
,
4514 isW
? LISTVIEW_EndEditLabelW
: (EditlblCallbackW
)LISTVIEW_EndEditLabelA
,
4518 infoPtr
->hwndEdit
= hedit
;
4520 SendMessageW(hedit
, EM_SETSEL
, 0, -1);
4528 * Ensures the specified item is visible, scrolling into view if necessary.
4531 * [I] HWND : window handle
4532 * [I] INT : item index
4533 * [I] BOOL : partially or entirely visible
4539 static BOOL
LISTVIEW_EnsureVisible(HWND hwnd
, INT nItem
, BOOL bPartial
)
4541 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
4542 UINT uView
= GetWindowLongW(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
4543 INT nScrollPosHeight
= 0;
4544 INT nScrollPosWidth
= 0;
4545 SCROLLINFO scrollInfo
;
4547 BOOL bRedraw
= FALSE
;
4549 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
4550 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
4551 scrollInfo
.fMask
= SIF_POS
;
4553 /* ALWAYS bPartial == FALSE, FOR NOW! */
4555 rcItem
.left
= LVIR_BOUNDS
;
4556 if (LISTVIEW_GetItemRect(hwnd
, nItem
, &rcItem
) != FALSE
)
4558 if (rcItem
.left
< infoPtr
->rcList
.left
)
4560 if (GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
) != FALSE
)
4564 if (uView
== LVS_LIST
)
4566 nScrollPosWidth
= infoPtr
->nItemWidth
;
4567 rcItem
.left
+= infoPtr
->rcList
.left
;
4569 else if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
4571 nScrollPosWidth
= LISTVIEW_SCROLL_DIV_SIZE
;
4572 rcItem
.left
+= infoPtr
->rcList
.left
;
4575 /* When in LVS_REPORT view, the scroll position should
4577 if (nScrollPosWidth
!= 0)
4579 if (rcItem
.left
% nScrollPosWidth
== 0)
4580 scrollInfo
.nPos
+= rcItem
.left
/ nScrollPosWidth
;
4582 scrollInfo
.nPos
+= rcItem
.left
/ nScrollPosWidth
- 1;
4584 SetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
, TRUE
);
4588 else if (rcItem
.right
> infoPtr
->rcList
.right
)
4590 if (GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
) != FALSE
)
4594 if (uView
== LVS_LIST
)
4596 rcItem
.right
-= infoPtr
->rcList
.right
;
4597 nScrollPosWidth
= infoPtr
->nItemWidth
;
4599 else if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
4601 rcItem
.right
-= infoPtr
->rcList
.right
;
4602 nScrollPosWidth
= LISTVIEW_SCROLL_DIV_SIZE
;
4605 /* When in LVS_REPORT view, the scroll position should
4607 if (nScrollPosWidth
!= 0)
4609 if (rcItem
.right
% nScrollPosWidth
== 0)
4610 scrollInfo
.nPos
+= rcItem
.right
/ nScrollPosWidth
;
4612 scrollInfo
.nPos
+= rcItem
.right
/ nScrollPosWidth
+ 1;
4614 SetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
, TRUE
);
4619 if (rcItem
.top
< infoPtr
->rcList
.top
)
4623 if (GetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
) != FALSE
)
4625 if (uView
== LVS_REPORT
)
4627 rcItem
.top
-= infoPtr
->rcList
.top
;
4628 nScrollPosHeight
= infoPtr
->nItemHeight
;
4630 else if ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
))
4632 nScrollPosHeight
= LISTVIEW_SCROLL_DIV_SIZE
;
4633 rcItem
.top
+= infoPtr
->rcList
.top
;
4636 if (rcItem
.top
% nScrollPosHeight
== 0)
4637 scrollInfo
.nPos
+= rcItem
.top
/ nScrollPosHeight
;
4639 scrollInfo
.nPos
+= rcItem
.top
/ nScrollPosHeight
- 1;
4641 SetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
, TRUE
);
4644 else if (rcItem
.bottom
> infoPtr
->rcList
.bottom
)
4648 if (GetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
) != FALSE
)
4650 if (uView
== LVS_REPORT
)
4652 rcItem
.bottom
-= infoPtr
->rcList
.bottom
;
4653 nScrollPosHeight
= infoPtr
->nItemHeight
;
4655 else if ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
))
4657 nScrollPosHeight
= LISTVIEW_SCROLL_DIV_SIZE
;
4658 rcItem
.bottom
-= infoPtr
->rcList
.bottom
;
4661 if (rcItem
.bottom
% nScrollPosHeight
== 0)
4662 scrollInfo
.nPos
+= rcItem
.bottom
/ nScrollPosHeight
;
4664 scrollInfo
.nPos
+= rcItem
.bottom
/ nScrollPosHeight
+ 1;
4666 SetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
, TRUE
);
4672 InvalidateRect(hwnd
,NULL
,TRUE
);
4678 * Retrieves the nearest item, given a position and a direction.
4681 * [I] HWND : window handle
4682 * [I] POINT : start position
4683 * [I] UINT : direction
4686 * Item index if successdful, -1 otherwise.
4688 static INT
LISTVIEW_GetNearestItem(HWND hwnd
, POINT pt
, UINT vkDirection
)
4690 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
4695 TRACE("point %ld,%ld, direction %s\n", pt
.x
, pt
.y
,
4696 (vkDirection
== VK_DOWN
) ? "VK_DOWN" :
4697 ((vkDirection
== VK_UP
) ? "VK_UP" :
4698 ((vkDirection
== VK_LEFT
) ? "VK_LEFT" : "VK_RIGHT")));
4700 if (LISTVIEW_GetViewRect(hwnd
, &rcView
) != FALSE
)
4702 ZeroMemory(&lvIntHit
, sizeof(lvIntHit
));
4703 LISTVIEW_GetOrigin(hwnd
, &lvIntHit
.ht
.pt
);
4704 lvIntHit
.ht
.pt
.x
+= pt
.x
;
4705 lvIntHit
.ht
.pt
.y
+= pt
.y
;
4707 if (vkDirection
== VK_DOWN
)
4708 lvIntHit
.ht
.pt
.y
+= infoPtr
->nItemHeight
;
4709 else if (vkDirection
== VK_UP
)
4710 lvIntHit
.ht
.pt
.y
-= infoPtr
->nItemHeight
;
4711 else if (vkDirection
== VK_LEFT
)
4712 lvIntHit
.ht
.pt
.x
-= infoPtr
->nItemWidth
;
4713 else if (vkDirection
== VK_RIGHT
)
4714 lvIntHit
.ht
.pt
.x
+= infoPtr
->nItemWidth
;
4716 if (PtInRect(&rcView
, lvIntHit
.ht
.pt
) == FALSE
)
4720 nItem
= LISTVIEW_SuperHitTestItem(hwnd
, &lvIntHit
, TRUE
);
4721 return nItem
== -1 ? lvIntHit
.iDistItem
: nItem
;
4730 * Searches for an item with specific characteristics.
4733 * [I] hwnd : window handle
4734 * [I] nStart : base item index
4735 * [I] lpFindInfo : item information to look for
4738 * SUCCESS : index of item
4741 static LRESULT
LISTVIEW_FindItemW(HWND hwnd
, INT nStart
,
4742 LPLVFINDINFOW lpFindInfo
)
4744 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
4746 WCHAR szDispText
[DISP_TEXT_SIZE
] = { '\0' };
4750 INT nLast
= GETITEMCOUNT(infoPtr
);
4752 if ((nItem
>= -1) && (lpFindInfo
!= NULL
))
4754 ZeroMemory(&lvItem
, sizeof(lvItem
));
4756 if (lpFindInfo
->flags
& LVFI_PARAM
)
4758 lvItem
.mask
|= LVIF_PARAM
;
4761 if (lpFindInfo
->flags
& (LVFI_STRING
| LVFI_PARTIAL
))
4763 lvItem
.mask
|= LVIF_TEXT
;
4764 lvItem
.pszText
= szDispText
;
4765 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
4768 if (lpFindInfo
->flags
& LVFI_WRAP
)
4771 if (lpFindInfo
->flags
& LVFI_NEARESTXY
)
4773 ptItem
.x
= lpFindInfo
->pt
.x
;
4774 ptItem
.y
= lpFindInfo
->pt
.y
;
4779 while (nItem
< nLast
)
4781 if (lpFindInfo
->flags
& LVFI_NEARESTXY
)
4783 nItem
= LISTVIEW_GetNearestItem(hwnd
, ptItem
,
4784 lpFindInfo
->vkDirection
);
4787 /* get position of the new item index */
4788 if (ListView_GetItemPosition(hwnd
, nItem
, &ptItem
) == FALSE
)
4799 lvItem
.iItem
= nItem
;
4800 lvItem
.iSubItem
= 0;
4801 if (LISTVIEW_GetItemW(hwnd
, &lvItem
, TRUE
))
4803 if (lvItem
.mask
& LVIF_TEXT
)
4805 if (lpFindInfo
->flags
& LVFI_PARTIAL
)
4807 if (strstrW(lvItem
.pszText
, lpFindInfo
->psz
) == NULL
)
4812 if (lstrcmpW(lvItem
.pszText
, lpFindInfo
->psz
) != 0)
4817 if (lvItem
.mask
& LVIF_PARAM
)
4819 if (lpFindInfo
->lParam
!= lvItem
.lParam
)
4845 * Searches for an item with specific characteristics.
4848 * [I] hwnd : window handle
4849 * [I] nStart : base item index
4850 * [I] lpFindInfo : item information to look for
4853 * SUCCESS : index of item
4856 static LRESULT
LISTVIEW_FindItemA(HWND hwnd
, INT nStart
,
4857 LPLVFINDINFOA lpFindInfo
)
4859 BOOL hasText
= lpFindInfo
->flags
& (LVFI_STRING
| LVFI_PARTIAL
);
4863 memcpy(&fiw
, lpFindInfo
, sizeof(fiw
));
4864 if (hasText
) fiw
.psz
= textdupTtoW((LPCWSTR
)lpFindInfo
->psz
, FALSE
);
4865 res
= LISTVIEW_FindItemW(hwnd
, nStart
, &fiw
);
4866 if (hasText
) textfreeT((LPWSTR
)fiw
.psz
, FALSE
);
4872 * Retrieves the background color of the listview control.
4875 * [I] HWND : window handle
4878 * COLORREF associated with the background.
4880 static LRESULT
LISTVIEW_GetBkColor(HWND hwnd
)
4882 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
4884 return infoPtr
->clrBk
;
4889 * Retrieves the background image of the listview control.
4892 * [I] HWND : window handle
4893 * [O] LPLVMKBIMAGE : background image attributes
4899 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
4901 /* FIXME (listview, "empty stub!\n"); */
4907 * Retrieves the callback mask.
4910 * [I] HWND : window handle
4915 static UINT
LISTVIEW_GetCallbackMask(HWND hwnd
)
4917 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
4919 return infoPtr
->uCallbackMask
;
4924 * Retrieves column attributes.
4927 * [I] HWND : window handle
4928 * [I] INT : column index
4929 * [IO] LPLVCOLUMNW : column information
4930 * [I] isW : if TRUE, then lpColumn is a LPLVCOLUMNW
4931 * otherwise it is in fact a LPLVCOLUMNA
4937 static LRESULT
LISTVIEW_GetColumnT(HWND hwnd
, INT nItem
, LPLVCOLUMNW lpColumn
, BOOL isW
)
4939 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
4941 BOOL bResult
= FALSE
;
4943 if (lpColumn
!= NULL
)
4946 TRACE("(hwnd=%x, col=%d, lpColumn=%s, isW=%d)\n",
4947 hwnd
, nItem
, debuglvcolumn_t(lpColumn
, isW
), isW
);
4949 /* initialize memory */
4950 ZeroMemory(&hdi
, sizeof(hdi
));
4952 if (lpColumn
->mask
& LVCF_FMT
)
4953 hdi
.mask
|= HDI_FORMAT
;
4955 if (lpColumn
->mask
& LVCF_WIDTH
)
4956 hdi
.mask
|= HDI_WIDTH
;
4958 if (lpColumn
->mask
& LVCF_TEXT
)
4960 hdi
.mask
|= HDI_TEXT
;
4961 hdi
.cchTextMax
= lpColumn
->cchTextMax
;
4962 hdi
.pszText
= lpColumn
->pszText
;
4965 if (lpColumn
->mask
& LVCF_IMAGE
)
4966 hdi
.mask
|= HDI_IMAGE
;
4968 if (lpColumn
->mask
& LVCF_ORDER
)
4969 hdi
.mask
|= HDI_ORDER
;
4972 bResult
= Header_GetItemW(infoPtr
->hwndHeader
, nItem
, &hdi
);
4974 bResult
= Header_GetItemA(infoPtr
->hwndHeader
, nItem
, &hdi
);
4976 if (bResult
!= FALSE
)
4978 if (lpColumn
->mask
& LVCF_FMT
)
4982 if (hdi
.fmt
& HDF_LEFT
)
4983 lpColumn
->fmt
|= LVCFMT_LEFT
;
4984 else if (hdi
.fmt
& HDF_RIGHT
)
4985 lpColumn
->fmt
|= LVCFMT_RIGHT
;
4986 else if (hdi
.fmt
& HDF_CENTER
)
4987 lpColumn
->fmt
|= LVCFMT_CENTER
;
4989 if (hdi
.fmt
& HDF_IMAGE
)
4990 lpColumn
->fmt
|= LVCFMT_COL_HAS_IMAGES
;
4992 if (hdi
.fmt
& HDF_BITMAP_ON_RIGHT
)
4993 lpColumn
->fmt
|= LVCFMT_BITMAP_ON_RIGHT
;
4996 if (lpColumn
->mask
& LVCF_WIDTH
)
4997 lpColumn
->cx
= hdi
.cxy
;
4999 if (lpColumn
->mask
& LVCF_IMAGE
)
5000 lpColumn
->iImage
= hdi
.iImage
;
5002 if (lpColumn
->mask
& LVCF_ORDER
)
5003 lpColumn
->iOrder
= hdi
.iOrder
;
5011 static LRESULT
LISTVIEW_GetColumnOrderArray(HWND hwnd
, INT iCount
, LPINT lpiArray
)
5013 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0); */
5020 for (i
= 0; i
< iCount
; i
++)
5028 * Retrieves the column width.
5031 * [I] HWND : window handle
5032 * [I] int : column index
5035 * SUCCESS : column width
5038 static LRESULT
LISTVIEW_GetColumnWidth(HWND hwnd
, INT nColumn
)
5040 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
5041 UINT uView
= GetWindowLongW(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
5042 INT nColumnWidth
= 0;
5045 if (uView
== LVS_LIST
)
5047 nColumnWidth
= infoPtr
->nItemWidth
;
5049 else if (uView
== LVS_REPORT
)
5051 /* get column width from header */
5052 ZeroMemory(&hdi
, sizeof(hdi
));
5053 hdi
.mask
= HDI_WIDTH
;
5054 if (Header_GetItemW(infoPtr
->hwndHeader
, nColumn
, &hdi
) != FALSE
)
5055 nColumnWidth
= hdi
.cxy
;
5058 return nColumnWidth
;
5063 * In list or report display mode, retrieves the number of items that can fit
5064 * vertically in the visible area. In icon or small icon display mode,
5065 * retrieves the total number of visible items.
5068 * [I] HWND : window handle
5071 * Number of fully visible items.
5073 static LRESULT
LISTVIEW_GetCountPerPage(HWND hwnd
)
5075 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
5076 UINT uView
= GetWindowLongW(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
5079 if (uView
== LVS_LIST
)
5081 if (infoPtr
->rcList
.right
> infoPtr
->nItemWidth
)
5083 nItemCount
= LISTVIEW_GetCountPerRow(hwnd
) *
5084 LISTVIEW_GetCountPerColumn(hwnd
);
5087 else if (uView
== LVS_REPORT
)
5089 nItemCount
= LISTVIEW_GetCountPerColumn(hwnd
);
5093 nItemCount
= GETITEMCOUNT(infoPtr
);
5099 /* LISTVIEW_GetEditControl */
5103 * Retrieves the extended listview style.
5106 * [I] HWND : window handle
5109 * SUCCESS : previous style
5112 static LRESULT
LISTVIEW_GetExtendedListViewStyle(HWND hwnd
)
5114 LISTVIEW_INFO
*infoPtr
;
5116 /* make sure we can get the listview info */
5117 if (!(infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0)))
5120 return (infoPtr
->dwExStyle
);
5125 * Retrieves the handle to the header control.
5128 * [I] HWND : window handle
5133 static LRESULT
LISTVIEW_GetHeader(HWND hwnd
)
5135 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
5137 return infoPtr
->hwndHeader
;
5140 /* LISTVIEW_GetHotCursor */
5144 * Returns the time that the mouse cursor must hover over an item
5145 * before it is selected.
5148 * [I] HWND : window handle
5151 * Returns the previously set hover time or (DWORD)-1 to indicate that the
5152 * hover time is set to the default hover time.
5154 static LRESULT
LISTVIEW_GetHoverTime(HWND hwnd
)
5156 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
5158 return infoPtr
->dwHoverTime
;
5163 * Retrieves an image list handle.
5166 * [I] HWND : window handle
5167 * [I] INT : image list identifier
5170 * SUCCESS : image list handle
5173 static LRESULT
LISTVIEW_GetImageList(HWND hwnd
, INT nImageList
)
5175 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
5176 HIMAGELIST himl
= NULL
;
5181 himl
= infoPtr
->himlNormal
;
5184 himl
= infoPtr
->himlSmall
;
5187 himl
= infoPtr
->himlState
;
5191 return (LRESULT
)himl
;
5194 /* LISTVIEW_GetISearchString */
5198 * Retrieves item attributes.
5201 * [I] hwnd : window handle
5202 * [IO] lpLVItem : item info
5203 * [I] internal : if true then we will use tricks that avoid copies
5204 * but are not compatible with the regular interface
5205 * [I] isW : if TRUE, then lpLVItem is a LPLVITEMW,
5206 * if FALSE, the lpLVItem is a LPLVITEMA.
5212 static LRESULT
LISTVIEW_GetItemT(HWND hwnd
, LPLVITEMW lpLVItem
, BOOL internal
, BOOL isW
)
5214 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
5215 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
5216 NMLVDISPINFOW dispInfo
;
5217 LISTVIEW_SUBITEM
*lpSubItem
;
5218 LISTVIEW_ITEM
*lpItem
;
5221 INT
* piImage
= (INT
*)&null
;
5222 LPWSTR
* ppszText
= (LPWSTR
*)&null
;
5223 LPARAM
* plParam
= (LPARAM
*)&null
;
5225 if (internal
&& !isW
)
5227 ERR("We can't have internal non-Unicode GetItem!\n");
5231 /* In the following:
5232 * lpLVItem describes the information requested by the user
5233 * lpItem/lpSubItem is what we have
5234 * dispInfo is a structure we use to request the missing
5235 * information from the application
5238 TRACE("(hwnd=%x, lpLVItem=%s, internal=%d, isW=%d)\n",
5239 hwnd
, debuglvitem_t(lpLVItem
, isW
), internal
, isW
);
5241 if ((lpLVItem
== NULL
) || (lpLVItem
->iItem
< 0) ||
5242 (lpLVItem
->iItem
>= GETITEMCOUNT(infoPtr
)))
5245 ZeroMemory(&dispInfo
, sizeof(dispInfo
));
5247 if (lStyle
& LVS_OWNERDATA
)
5249 if (lpLVItem
->mask
& ~LVIF_STATE
)
5251 memcpy(&dispInfo
.item
, lpLVItem
, sizeof(LVITEMW
));
5252 dispinfo_notifyT(hwnd
, LVN_GETDISPINFOW
, &dispInfo
, isW
);
5253 memcpy(lpLVItem
, &dispInfo
.item
, sizeof(LVITEMW
));
5254 TRACE(" getdispinfo(1):lpLVItem=%s\n", debuglvitem_t(lpLVItem
, isW
));
5257 if ((lpLVItem
->mask
& LVIF_STATE
)&&(lpLVItem
->iSubItem
== 0))
5259 lpLVItem
->state
= 0;
5260 if (infoPtr
->nFocusedItem
== lpLVItem
->iItem
)
5261 lpLVItem
->state
|= LVIS_FOCUSED
;
5262 if (LISTVIEW_IsSelected(hwnd
,lpLVItem
->iItem
))
5263 lpLVItem
->state
|= LVIS_SELECTED
;
5269 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
);
5270 if (hdpaSubItems
== NULL
) return FALSE
;
5272 if ( (lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0)) == NULL
)
5275 ZeroMemory(&dispInfo
.item
, sizeof(LVITEMW
));
5276 if (lpLVItem
->iSubItem
== 0)
5278 piImage
=&lpItem
->iImage
;
5279 ppszText
=&lpItem
->pszText
;
5280 plParam
=&lpItem
->lParam
;
5281 if ((lpLVItem
->mask
& LVIF_STATE
) && infoPtr
->uCallbackMask
)
5283 dispInfo
.item
.mask
|= LVIF_STATE
;
5284 dispInfo
.item
.stateMask
= infoPtr
->uCallbackMask
;
5289 lpSubItem
= LISTVIEW_GetSubItemPtr(hdpaSubItems
, lpLVItem
->iSubItem
);
5290 if (lpSubItem
!= NULL
)
5292 piImage
=&lpSubItem
->iImage
;
5293 ppszText
=&lpSubItem
->pszText
;
5297 if ((lpLVItem
->mask
& LVIF_IMAGE
) && (*piImage
==I_IMAGECALLBACK
))
5299 dispInfo
.item
.mask
|= LVIF_IMAGE
;
5302 if ((lpLVItem
->mask
& LVIF_TEXT
) && !is_textW(*ppszText
))
5304 dispInfo
.item
.mask
|= LVIF_TEXT
;
5305 dispInfo
.item
.pszText
= lpLVItem
->pszText
;
5306 dispInfo
.item
.cchTextMax
= lpLVItem
->cchTextMax
;
5307 if (dispInfo
.item
.pszText
&& lpLVItem
->cchTextMax
> 0)
5308 *dispInfo
.item
.pszText
= '\0';
5309 if (dispInfo
.item
.pszText
&& (*ppszText
== NULL
))
5310 *dispInfo
.item
.pszText
= '\0';
5313 if (dispInfo
.item
.mask
!= 0)
5315 /* We don't have all the requested info, query the application */
5316 dispInfo
.item
.iItem
= lpLVItem
->iItem
;
5317 dispInfo
.item
.iSubItem
= lpLVItem
->iSubItem
;
5318 dispInfo
.item
.lParam
= lpItem
->lParam
;
5319 dispinfo_notifyT(hwnd
, LVN_GETDISPINFOW
, &dispInfo
, isW
);
5320 TRACE(" getdispinfo(2):lpLVItem=%s\n", debuglvitem_t(&dispInfo
.item
, isW
));
5323 if (dispInfo
.item
.mask
& LVIF_IMAGE
)
5325 lpLVItem
->iImage
= dispInfo
.item
.iImage
;
5326 if ((dispInfo
.item
.mask
& LVIF_DI_SETITEM
) && (*piImage
==I_IMAGECALLBACK
))
5327 *piImage
= dispInfo
.item
.iImage
;
5329 else if (lpLVItem
->mask
& LVIF_IMAGE
)
5331 lpLVItem
->iImage
= *piImage
;
5334 if (dispInfo
.item
.mask
& LVIF_PARAM
)
5336 lpLVItem
->lParam
= dispInfo
.item
.lParam
;
5337 if (dispInfo
.item
.mask
& LVIF_DI_SETITEM
)
5338 *plParam
= dispInfo
.item
.lParam
;
5340 else if (lpLVItem
->mask
& LVIF_PARAM
)
5341 lpLVItem
->lParam
= lpItem
->lParam
;
5343 if (dispInfo
.item
.mask
& LVIF_TEXT
)
5345 if ((dispInfo
.item
.mask
& LVIF_DI_SETITEM
) && *ppszText
)
5346 textsetptrT(ppszText
, dispInfo
.item
.pszText
, isW
);
5348 /* If lpLVItem->pszText==dispInfo.item.pszText a copy is unnecessary, but */
5349 /* some apps give a new pointer in ListView_Notify so we can't be sure. */
5350 if (lpLVItem
->pszText
!= dispInfo
.item
.pszText
)
5351 textcpynT(lpLVItem
->pszText
, isW
, dispInfo
.item
.pszText
, isW
, lpLVItem
->cchTextMax
);
5354 else if (lpLVItem
->mask
& LVIF_TEXT
)
5356 if (internal
) lpLVItem
->pszText
= *ppszText
;
5357 else textcpynT(lpLVItem
->pszText
, isW
, *ppszText
, TRUE
, lpLVItem
->cchTextMax
);
5360 if (lpLVItem
->iSubItem
== 0)
5362 if (dispInfo
.item
.mask
& LVIF_STATE
)
5364 lpLVItem
->state
= lpItem
->state
;
5365 lpLVItem
->state
&= ~dispInfo
.item
.stateMask
;
5366 lpLVItem
->state
|= (dispInfo
.item
.state
& dispInfo
.item
.stateMask
);
5368 lpLVItem
->state
&= ~LVIS_SELECTED
;
5369 if ((dispInfo
.item
.stateMask
& LVIS_SELECTED
) &&
5370 LISTVIEW_IsSelected(hwnd
,dispInfo
.item
.iItem
))
5371 lpLVItem
->state
|= LVIS_SELECTED
;
5373 else if (lpLVItem
->mask
& LVIF_STATE
)
5375 lpLVItem
->state
= lpItem
->state
& lpLVItem
->stateMask
;
5377 lpLVItem
->state
&= ~LVIS_SELECTED
;
5378 if ((lpLVItem
->stateMask
& LVIS_SELECTED
) &&
5379 LISTVIEW_IsSelected(hwnd
,lpLVItem
->iItem
))
5380 lpLVItem
->state
|= LVIS_SELECTED
;
5383 if (lpLVItem
->mask
& LVIF_PARAM
)
5384 lpLVItem
->lParam
= lpItem
->lParam
;
5386 if (lpLVItem
->mask
& LVIF_INDENT
)
5387 lpLVItem
->iIndent
= lpItem
->iIndent
;
5393 /* LISTVIEW_GetHotCursor */
5397 * Retrieves the index of the hot item.
5400 * [I] HWND : window handle
5403 * SUCCESS : hot item index
5404 * FAILURE : -1 (no hot item)
5406 static LRESULT
LISTVIEW_GetHotItem(HWND hwnd
)
5408 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
5410 return infoPtr
->nHotItem
;
5413 /* LISTVIEW_GetHoverTime */
5417 * Retrieves the number of items in the listview control.
5420 * [I] HWND : window handle
5425 static LRESULT
LISTVIEW_GetItemCount(HWND hwnd
)
5427 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
5429 return GETITEMCOUNT(infoPtr
);
5434 * Retrieves the rectangle enclosing the item icon and text.
5437 * [I] HWND : window handle
5438 * [I] INT : item index
5439 * [O] LPRECT : coordinate information
5445 static BOOL
LISTVIEW_GetItemBoundBox(HWND hwnd
, INT nItem
, LPRECT lpRect
)
5447 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
5448 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
5449 UINT uView
= lStyle
& LVS_TYPEMASK
;
5450 BOOL bResult
= FALSE
;
5452 LISTVIEW_ITEM
*lpItem
;
5453 INT nCountPerColumn
;
5456 TRACE("(hwnd=%x,nItem=%d,lpRect=%p)\n", hwnd
, nItem
, lpRect
);
5458 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)) &&
5461 if (uView
== LVS_LIST
)
5464 nItem
= nItem
- ListView_GetTopIndex(hwnd
);
5465 nCountPerColumn
= LISTVIEW_GetCountPerColumn(hwnd
);
5468 nRow
= nItem
% nCountPerColumn
;
5471 lpRect
->left
= nItem
/ nCountPerColumn
* infoPtr
->nItemWidth
;
5476 lpRect
->left
= (nItem
/ nCountPerColumn
-1) * infoPtr
->nItemWidth
;
5477 lpRect
->top
= (nRow
+ nCountPerColumn
) * infoPtr
->nItemHeight
;
5482 lpRect
->left
= nItem
/ nCountPerColumn
* infoPtr
->nItemWidth
;
5483 lpRect
->top
= nItem
% nCountPerColumn
* infoPtr
->nItemHeight
;
5486 else if (uView
== LVS_REPORT
)
5489 lpRect
->left
= REPORT_MARGINX
;
5490 lpRect
->top
= ((nItem
- ListView_GetTopIndex(hwnd
)) *
5491 infoPtr
->nItemHeight
) + infoPtr
->rcList
.top
;
5493 if (!(lStyle
& LVS_NOSCROLL
))
5495 SCROLLINFO scrollInfo
;
5496 /* Adjust position by scrollbar offset */
5497 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
5498 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
5499 scrollInfo
.fMask
= SIF_POS
;
5500 GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
);
5501 lpRect
->left
-= scrollInfo
.nPos
* LISTVIEW_SCROLL_DIV_SIZE
;
5504 else /* either LVS_ICON or LVS_SMALLICON */
5506 if ((hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
)))
5508 if ((lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0)))
5511 lpRect
->left
= lpItem
->ptPosition
.x
;
5512 lpRect
->top
= lpItem
->ptPosition
.y
;
5517 lpRect
->right
= lpRect
->left
+ infoPtr
->nItemWidth
;
5518 lpRect
->bottom
= lpRect
->top
+ infoPtr
->nItemHeight
;
5519 TRACE("result %s: (%d,%d)-(%d,%d)\n", bResult
? "TRUE" : "FALSE",
5520 lpRect
->left
, lpRect
->top
, lpRect
->right
, lpRect
->bottom
);
5526 * Retrieves the position (upper-left) of the listview control item.
5527 * Note that for LVS_ICON style, the upper-left is that of the icon
5528 * and not the bounding box.
5531 * [I] HWND : window handle
5532 * [I] INT : item index
5533 * [O] LPPOINT : coordinate information
5539 static BOOL
LISTVIEW_GetItemPosition(HWND hwnd
, INT nItem
, LPPOINT lpptPosition
)
5541 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5542 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
5543 BOOL bResult
= FALSE
;
5546 TRACE("(hwnd=%x, nItem=%d, lpptPosition=%p)\n", hwnd
, nItem
, lpptPosition
);
5548 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)) &&
5549 (lpptPosition
!= NULL
))
5551 bResult
= LISTVIEW_GetItemBoundBox(hwnd
, nItem
, &rcBounding
);
5552 lpptPosition
->x
= rcBounding
.left
;
5553 lpptPosition
->y
= rcBounding
.top
;
5554 if (uView
== LVS_ICON
)
5556 lpptPosition
->y
+= ICON_TOP_PADDING
;
5557 lpptPosition
->x
+= (infoPtr
->iconSpacing
.cx
- infoPtr
->iconSize
.cx
) / 2;
5559 TRACE("result %s (%ld,%ld)\n", bResult
? "TRUE" : "FALSE",
5560 lpptPosition
->x
, lpptPosition
->y
);
5566 * Update the bounding rectangle around the text under a large icon.
5567 * This depends on whether it has the focus or not.
5568 * On entry the rectangle's top, left and right should be set.
5569 * On return the bottom will also be set and the width may have been
5572 * This appears to be weird, even in the Microsoft implementation.
5575 static void ListView_UpdateLargeItemLabelRect (
5576 HWND hwnd
, /* The window of the listview */
5577 const LISTVIEW_INFO
*infoPtr
, /* The listview itself */
5578 int nItem
, /* The item for which we are calculating this */
5579 RECT
*rect
) /* The rectangle to be updated */
5581 HDC hdc
= GetDC (hwnd
);
5582 HFONT hOldFont
= SelectObject (hdc
, infoPtr
->hFont
);
5584 if (infoPtr
->bFocus
&& infoPtr
->nFocusedItem
== nItem
)
5586 /* We (aim to) display the full text. In Windows 95 it appears to
5587 * calculate the size assuming the specified font and then it draws
5588 * the text in that region with the specified font except scaled to
5589 * 10 point (or the height of the system font or ...). Thus if the
5590 * window has 24 point Helvetica the highlit rectangle will be
5591 * taller than the text and if it is 7 point Helvetica then the text
5593 * For now we will simply say that it is the correct size to display
5594 * the text in the specified font.
5597 lvItem
.mask
= LVIF_TEXT
;
5598 lvItem
.iItem
= nItem
;
5599 lvItem
.iSubItem
= 0;
5600 /* We will specify INTERNAL and so will receive back a const
5601 * pointer to the text, rather than specifying a buffer to which
5604 LISTVIEW_GetItemW (hwnd
, &lvItem
, TRUE
);
5605 DrawTextW (hdc
, lvItem
.pszText
, -1, rect
, DT_CALCRECT
|
5606 DT_NOCLIP
| DT_EDITCONTROL
| DT_TOP
| DT_CENTER
|
5607 DT_WORDBREAK
| DT_NOPREFIX
);
5608 /* Maintain this DT_* list in line with LISTVIEW_DrawLargeItem */
5612 /* As far as I can see the text region seems to be trying to be
5613 * "tall enough for two lines of text". Once again (comctl32.dll ver
5614 * 5.81?) it measures this on the basis of the selected font and then
5615 * draws it with the same font except in 10 point size. This can lead
5616 * to more or less than the two rows appearing.
5617 * Question; are we supposed to be including DT_EXTERNALLEADING?
5618 * Question; should the width be shrunk to the space required to
5619 * display the two lines?
5621 rect
->bottom
= rect
->top
+ 2 * infoPtr
->ntmHeight
;
5624 SelectObject (hdc
, hOldFont
);
5625 ReleaseDC (hwnd
, hdc
);
5630 * Retrieves the bounding rectangle for a listview control item.
5633 * [I] HWND : window handle
5634 * [I] INT : item index
5635 * [IO] LPRECT : bounding rectangle coordinates
5636 * lprc->left specifies the portion of the item for which the bounding
5637 * rectangle will be retrieved.
5639 * LVIR_BOUNDS Returns the bounding rectangle of the entire item,
5640 * including the icon and label.
5641 * LVIR_ICON Returns the bounding rectangle of the icon or small icon.
5642 * LVIR_LABEL Returns the bounding rectangle of the item text.
5643 * LVIR_SELECTBOUNDS Returns the union of the LVIR_ICON and LVIR_LABEL
5644 * rectangles, but excludes columns in report view.
5651 * Note that the bounding rectangle of the label in the LVS_ICON view depends
5652 * upon whether the window has the focus currently and on whether the item
5653 * is the one with the focus. Ensure that the control's record of which
5654 * item has the focus agrees with the items' records.
5656 static LRESULT
LISTVIEW_GetItemRect(HWND hwnd
, INT nItem
, LPRECT lprc
)
5658 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
5659 UINT uView
= GetWindowLongW(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
5660 BOOL bResult
= FALSE
;
5669 TRACE("(hwnd=%x, nItem=%d, lprc=%p)\n", hwnd
, nItem
, lprc
);
5671 if (uView
& LVS_REPORT
)
5673 ZeroMemory(&lvItem
, sizeof(lvItem
));
5674 lvItem
.mask
= LVIF_INDENT
;
5675 lvItem
.iItem
= nItem
;
5676 lvItem
.iSubItem
= 0;
5677 LISTVIEW_GetItemW(hwnd
, &lvItem
, TRUE
);
5680 if (lvItem
.iIndent
>0 && infoPtr
->iconSize
.cx
> 0)
5681 nIndent
= infoPtr
->iconSize
.cx
* lvItem
.iIndent
;
5688 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)) && (lprc
!= NULL
))
5693 if (!ListView_GetItemPosition(hwnd
, nItem
, &ptItem
)) break;
5694 if (uView
== LVS_ICON
)
5696 if (infoPtr
->himlNormal
!= NULL
)
5698 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
5701 lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
5702 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
5703 lprc
->right
= lprc
->left
+ infoPtr
->iconSize
.cx
;
5704 lprc
->bottom
= (lprc
->top
+ infoPtr
->iconSize
.cy
+
5705 ICON_BOTTOM_PADDING
+ ICON_TOP_PADDING
);
5709 else if (uView
== LVS_SMALLICON
)
5711 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
5714 lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
5715 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
5716 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
5718 if (infoPtr
->himlState
!= NULL
)
5719 lprc
->left
+= infoPtr
->iconSize
.cx
;
5721 if (infoPtr
->himlSmall
!= NULL
)
5722 lprc
->right
= lprc
->left
+ infoPtr
->iconSize
.cx
;
5724 lprc
->right
= lprc
->left
;
5730 lprc
->left
= ptItem
.x
;
5731 if (uView
& LVS_REPORT
)
5732 lprc
->left
+= nIndent
;
5733 lprc
->top
= ptItem
.y
;
5734 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
5736 if (infoPtr
->himlState
!= NULL
)
5737 lprc
->left
+= infoPtr
->iconSize
.cx
;
5739 if (infoPtr
->himlSmall
!= NULL
)
5740 lprc
->right
= lprc
->left
+ infoPtr
->iconSize
.cx
;
5742 lprc
->right
= lprc
->left
;
5747 if (!ListView_GetItemPosition(hwnd
, nItem
, &ptItem
)) break;
5748 if (uView
== LVS_ICON
)
5750 if (infoPtr
->himlNormal
!= NULL
)
5752 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
5755 lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
5756 lprc
->top
= (ptItem
.y
+ ptOrigin
.y
+ infoPtr
->iconSize
.cy
+
5757 ICON_BOTTOM_PADDING
);
5758 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
5759 if (infoPtr
->iconSpacing
.cx
- nLabelWidth
> 1)
5761 lprc
->left
+= (infoPtr
->iconSpacing
.cx
- nLabelWidth
) / 2;
5762 lprc
->right
= lprc
->left
+ nLabelWidth
;
5767 lprc
->right
= lprc
->left
+ infoPtr
->iconSpacing
.cx
- 1;
5768 ListView_UpdateLargeItemLabelRect (hwnd
, infoPtr
, nItem
, lprc
);
5773 else if (uView
== LVS_SMALLICON
)
5775 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
5778 nLeftPos
= lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
5779 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
5780 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
5782 if (infoPtr
->himlState
!= NULL
)
5783 lprc
->left
+= infoPtr
->iconSize
.cx
;
5785 if (infoPtr
->himlSmall
!= NULL
)
5786 lprc
->left
+= infoPtr
->iconSize
.cx
;
5788 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
5789 nLabelWidth
+= TRAILING_PADDING
;
5790 if (lprc
->left
+ nLabelWidth
< nLeftPos
+ infoPtr
->nItemWidth
)
5791 lprc
->right
= lprc
->left
+ nLabelWidth
;
5793 lprc
->right
= nLeftPos
+ infoPtr
->nItemWidth
;
5799 if (uView
== LVS_REPORT
)
5800 nLeftPos
= lprc
->left
= ptItem
.x
+ nIndent
;
5802 nLeftPos
= lprc
->left
= ptItem
.x
;
5803 lprc
->top
= ptItem
.y
;
5804 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
5806 if (infoPtr
->himlState
!= NULL
)
5807 lprc
->left
+= infoPtr
->iconSize
.cx
;
5809 if (infoPtr
->himlSmall
!= NULL
)
5810 lprc
->left
+= infoPtr
->iconSize
.cx
;
5812 if (uView
!= LVS_REPORT
)
5814 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
5815 nLabelWidth
+= TRAILING_PADDING
;
5816 if (infoPtr
->himlSmall
)
5817 nLabelWidth
+= IMAGE_PADDING
;
5820 nLabelWidth
= LISTVIEW_GetColumnWidth(hwnd
, 0)-lprc
->left
;
5821 if (lprc
->left
+ nLabelWidth
< nLeftPos
+ infoPtr
->nItemWidth
)
5822 lprc
->right
= lprc
->left
+ nLabelWidth
;
5824 lprc
->right
= nLeftPos
+ infoPtr
->nItemWidth
;
5829 if (!LISTVIEW_GetItemBoundBox(hwnd
, nItem
, &rcInternal
)) break;
5830 ptItem
.x
= rcInternal
.left
;
5831 ptItem
.y
= rcInternal
.top
;
5832 if (uView
== LVS_ICON
)
5834 if (infoPtr
->himlNormal
!= NULL
)
5836 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
5839 INT text_left
, text_right
, icon_left
, text_pos_x
;
5840 /* for style LVS_ICON bounds
5841 * left = min(icon.left, text.left)
5842 * right = max(icon.right, text.right)
5843 * top = boundbox.top + NOTHITABLE
5844 * bottom = text.bottom + 1
5847 icon_left
= text_left
= ptItem
.x
;
5849 /* Correct ptItem to icon upper-left */
5850 icon_left
+= (infoPtr
->nItemWidth
- infoPtr
->iconSize
.cx
)/2;
5851 ptItem
.y
+= ICON_TOP_PADDING
;
5853 /* Compute the label left and right */
5854 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
5855 text_pos_x
= infoPtr
->iconSpacing
.cx
- 2*CAPTION_BORDER
- nLabelWidth
;
5858 text_left
+= text_pos_x
/ 2;
5859 text_right
= text_left
+ nLabelWidth
+ 2*CAPTION_BORDER
;
5864 text_right
= text_left
+ infoPtr
->iconSpacing
.cx
- 1;
5867 /* Compute rectangle w/o the text height */
5868 lprc
->left
= min(icon_left
, text_left
) + ptOrigin
.x
;
5869 lprc
->right
= max(icon_left
+ infoPtr
->iconSize
.cx
,
5870 text_right
) + ptOrigin
.x
;
5871 lprc
->top
= ptItem
.y
+ ptOrigin
.y
- ICON_TOP_PADDING_HITABLE
;
5872 lprc
->bottom
= lprc
->top
+ ICON_TOP_PADDING_HITABLE
5873 + infoPtr
->iconSize
.cy
+ 1
5874 + ICON_BOTTOM_PADDING
;
5876 CopyRect (&label_rect
, lprc
);
5877 label_rect
.top
= lprc
->bottom
;
5878 ListView_UpdateLargeItemLabelRect (hwnd
, infoPtr
, nItem
, &label_rect
);
5879 UnionRect (lprc
, lprc
, &label_rect
);
5883 else if (uView
== LVS_SMALLICON
)
5885 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
5888 lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
5889 lprc
->right
= lprc
->left
;
5890 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
5891 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
5892 if (infoPtr
->himlState
!= NULL
)
5893 lprc
->right
+= infoPtr
->iconSize
.cx
;
5894 if (infoPtr
->himlSmall
!= NULL
)
5895 lprc
->right
+= infoPtr
->iconSize
.cx
;
5897 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
5898 nLabelWidth
+= TRAILING_PADDING
;
5899 if (infoPtr
->himlSmall
)
5900 nLabelWidth
+= IMAGE_PADDING
;
5901 if (lprc
->right
+ nLabelWidth
< lprc
->left
+ infoPtr
->nItemWidth
)
5902 lprc
->right
+= nLabelWidth
;
5904 lprc
->right
= lprc
->left
+ infoPtr
->nItemWidth
;
5910 lprc
->left
= ptItem
.x
;
5911 if (!(infoPtr
->dwExStyle
&LVS_EX_FULLROWSELECT
) && uView
&LVS_REPORT
)
5912 lprc
->left
+= nIndent
;
5913 lprc
->right
= lprc
->left
;
5914 lprc
->top
= ptItem
.y
;
5915 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
5917 if ((infoPtr
->dwExStyle
& LVS_EX_FULLROWSELECT
) || (uView
== LVS_REPORT
))
5920 int nColumnCount
= Header_GetItemCount(infoPtr
->hwndHeader
);
5921 Header_GetItemRect(infoPtr
->hwndHeader
, nColumnCount
-1, &br
);
5923 lprc
->right
= max(lprc
->left
, br
.right
- REPORT_MARGINX
);
5927 if (infoPtr
->himlState
!= NULL
)
5928 lprc
->right
+= infoPtr
->iconSize
.cx
;
5930 if (infoPtr
->himlSmall
!= NULL
)
5931 lprc
->right
+= infoPtr
->iconSize
.cx
;
5933 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
5934 nLabelWidth
+= TRAILING_PADDING
;
5935 if (lprc
->right
+ nLabelWidth
< lprc
->left
+ infoPtr
->nItemWidth
)
5936 lprc
->right
+= nLabelWidth
;
5938 lprc
->right
= lprc
->left
+ infoPtr
->nItemWidth
;
5943 case LVIR_SELECTBOUNDS
:
5944 if (!ListView_GetItemPosition(hwnd
, nItem
, &ptItem
)) break;
5945 if (uView
== LVS_ICON
)
5947 if (infoPtr
->himlNormal
!= NULL
)
5949 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
5952 lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
5953 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
5954 lprc
->right
= lprc
->left
+ infoPtr
->iconSpacing
.cx
;
5955 lprc
->bottom
= lprc
->top
+ infoPtr
->iconSpacing
.cy
;
5959 else if (uView
== LVS_SMALLICON
)
5961 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
5964 nLeftPos
= lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
5965 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
5966 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
5968 if (infoPtr
->himlState
!= NULL
)
5969 lprc
->left
+= infoPtr
->iconSize
.cx
;
5971 lprc
->right
= lprc
->left
;
5973 if (infoPtr
->himlSmall
!= NULL
)
5974 lprc
->right
+= infoPtr
->iconSize
.cx
;
5976 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
5977 nLabelWidth
+= TRAILING_PADDING
;
5978 if (lprc
->right
+ nLabelWidth
< nLeftPos
+ infoPtr
->nItemWidth
)
5979 lprc
->right
+= nLabelWidth
;
5981 lprc
->right
= nLeftPos
+ infoPtr
->nItemWidth
;
5987 if (!(infoPtr
->dwExStyle
&LVS_EX_FULLROWSELECT
) && (uView
&LVS_REPORT
))
5988 nLeftPos
= lprc
->left
= ptItem
.x
+ nIndent
;
5990 nLeftPos
= lprc
->left
= ptItem
.x
;
5991 lprc
->top
= ptItem
.y
;
5992 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
5994 if (infoPtr
->himlState
!= NULL
)
5995 lprc
->left
+= infoPtr
->iconSize
.cx
;
5997 lprc
->right
= lprc
->left
;
5999 if (infoPtr
->dwExStyle
& LVS_EX_FULLROWSELECT
)
6002 int nColumnCount
= Header_GetItemCount(infoPtr
->hwndHeader
);
6003 Header_GetItemRect(infoPtr
->hwndHeader
, nColumnCount
-1, &br
);
6005 lprc
->right
= max(lprc
->left
, br
.right
- REPORT_MARGINX
);
6009 if (infoPtr
->himlSmall
!= NULL
)
6010 lprc
->right
+= infoPtr
->iconSize
.cx
;
6012 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
6013 nLabelWidth
+= TRAILING_PADDING
;
6014 if (infoPtr
->himlSmall
)
6015 nLabelWidth
+= IMAGE_PADDING
;
6016 if (lprc
->right
+ nLabelWidth
< nLeftPos
+ infoPtr
->nItemWidth
)
6017 lprc
->right
+= nLabelWidth
;
6019 lprc
->right
= nLeftPos
+ infoPtr
->nItemWidth
;
6026 TRACE("result %s (%d,%d)-(%d,%d)\n", bResult
? "TRUE" : "FALSE",
6027 lprc
->left
, lprc
->top
, lprc
->right
, lprc
->bottom
);
6034 * Retrieves the width of a label.
6037 * [I] HWND : window handle
6040 * SUCCESS : string width (in pixels)
6043 static INT
LISTVIEW_GetLabelWidth(HWND hwnd
, INT nItem
)
6045 WCHAR szDispText
[DISP_TEXT_SIZE
] = { '\0' };
6046 INT nLabelWidth
= 0;
6049 TRACE("(hwnd=%x, nItem=%d)\n", hwnd
, nItem
);
6051 ZeroMemory(&lvItem
, sizeof(lvItem
));
6052 lvItem
.mask
= LVIF_TEXT
;
6053 lvItem
.iItem
= nItem
;
6054 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
6055 lvItem
.pszText
= szDispText
;
6056 if (LISTVIEW_GetItemW(hwnd
, &lvItem
, TRUE
))
6057 nLabelWidth
= ListView_GetStringWidthW(hwnd
, lvItem
.pszText
);
6064 * Retrieves the spacing between listview control items.
6067 * [I] HWND : window handle
6068 * [I] BOOL : flag for small or large icon
6071 * Horizontal + vertical spacing
6073 static LRESULT
LISTVIEW_GetItemSpacing(HWND hwnd
, BOOL bSmall
)
6075 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
6078 if (bSmall
== FALSE
)
6080 lResult
= MAKELONG(infoPtr
->iconSpacing
.cx
, infoPtr
->iconSpacing
.cy
);
6084 LONG style
= GetWindowLongW(hwnd
, GWL_STYLE
);
6085 if ((style
& LVS_TYPEMASK
) == LVS_ICON
)
6086 lResult
= MAKELONG(DEFAULT_COLUMN_WIDTH
, GetSystemMetrics(SM_CXSMICON
)+HEIGHT_PADDING
);
6088 lResult
= MAKELONG(infoPtr
->nItemWidth
, infoPtr
->nItemHeight
);
6095 * Retrieves the state of a listview control item.
6098 * [I] HWND : window handle
6099 * [I] INT : item index
6100 * [I] UINT : state mask
6103 * State specified by the mask.
6105 static LRESULT
LISTVIEW_GetItemState(HWND hwnd
, INT nItem
, UINT uMask
)
6107 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
6111 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
6113 ZeroMemory(&lvItem
, sizeof(lvItem
));
6114 lvItem
.iItem
= nItem
;
6115 lvItem
.stateMask
= uMask
;
6116 lvItem
.mask
= LVIF_STATE
;
6117 if (LISTVIEW_GetItemW(hwnd
, &lvItem
, TRUE
))
6118 uState
= lvItem
.state
;
6126 * Retrieves the text of a listview control item or subitem.
6129 * [I] hwnd : window handle
6130 * [I] nItem : item index
6131 * [IO] lpLVItem : item information
6132 * [I] isW : TRUE if lpLVItem is Unicode
6135 * SUCCESS : string length
6138 static LRESULT
LISTVIEW_GetItemTextT(HWND hwnd
, INT nItem
, LPLVITEMW lpLVItem
, BOOL isW
)
6140 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
6143 if (lpLVItem
!= NULL
)
6145 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
6147 lpLVItem
->mask
= LVIF_TEXT
;
6148 lpLVItem
->iItem
= nItem
;
6149 if (LISTVIEW_GetItemT(hwnd
, lpLVItem
, FALSE
, isW
))
6150 nLength
= textlenT(lpLVItem
->pszText
, isW
);
6159 * Searches for an item based on properties + relationships.
6162 * [I] HWND : window handle
6163 * [I] INT : item index
6164 * [I] INT : relationship flag
6167 * SUCCESS : item index
6170 static LRESULT
LISTVIEW_GetNextItem(HWND hwnd
, INT nItem
, UINT uFlags
)
6172 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
6173 UINT uView
= GetWindowLongW(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
6175 LVFINDINFOW lvFindInfo
;
6176 INT nCountPerColumn
;
6179 if ((nItem
>= -1) && (nItem
< GETITEMCOUNT(infoPtr
)))
6181 ZeroMemory(&lvFindInfo
, sizeof(lvFindInfo
));
6183 if (uFlags
& LVNI_CUT
)
6186 if (uFlags
& LVNI_DROPHILITED
)
6187 uMask
|= LVIS_DROPHILITED
;
6189 if (uFlags
& LVNI_FOCUSED
)
6190 uMask
|= LVIS_FOCUSED
;
6192 if (uFlags
& LVNI_SELECTED
)
6193 uMask
|= LVIS_SELECTED
;
6195 if (uFlags
& LVNI_ABOVE
)
6197 if ((uView
== LVS_LIST
) || (uView
== LVS_REPORT
))
6202 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
6208 lvFindInfo
.flags
= LVFI_NEARESTXY
;
6209 lvFindInfo
.vkDirection
= VK_UP
;
6210 ListView_GetItemPosition(hwnd
, nItem
, &lvFindInfo
.pt
);
6211 while ((nItem
= ListView_FindItemW(hwnd
, nItem
, &lvFindInfo
)) != -1)
6213 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
6218 else if (uFlags
& LVNI_BELOW
)
6220 if ((uView
== LVS_LIST
) || (uView
== LVS_REPORT
))
6222 while (nItem
< GETITEMCOUNT(infoPtr
))
6225 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
6231 lvFindInfo
.flags
= LVFI_NEARESTXY
;
6232 lvFindInfo
.vkDirection
= VK_DOWN
;
6233 ListView_GetItemPosition(hwnd
, nItem
, &lvFindInfo
.pt
);
6234 while ((nItem
= ListView_FindItemW(hwnd
, nItem
, &lvFindInfo
)) != -1)
6236 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
6241 else if (uFlags
& LVNI_TOLEFT
)
6243 if (uView
== LVS_LIST
)
6245 nCountPerColumn
= LISTVIEW_GetCountPerColumn(hwnd
);
6246 while (nItem
- nCountPerColumn
>= 0)
6248 nItem
-= nCountPerColumn
;
6249 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
6253 else if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
6255 lvFindInfo
.flags
= LVFI_NEARESTXY
;
6256 lvFindInfo
.vkDirection
= VK_LEFT
;
6257 ListView_GetItemPosition(hwnd
, nItem
, &lvFindInfo
.pt
);
6258 while ((nItem
= ListView_FindItemW(hwnd
, nItem
, &lvFindInfo
)) != -1)
6260 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
6265 else if (uFlags
& LVNI_TORIGHT
)
6267 if (uView
== LVS_LIST
)
6269 nCountPerColumn
= LISTVIEW_GetCountPerColumn(hwnd
);
6270 while (nItem
+ nCountPerColumn
< GETITEMCOUNT(infoPtr
))
6272 nItem
+= nCountPerColumn
;
6273 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
6277 else if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
6279 lvFindInfo
.flags
= LVFI_NEARESTXY
;
6280 lvFindInfo
.vkDirection
= VK_RIGHT
;
6281 ListView_GetItemPosition(hwnd
, nItem
, &lvFindInfo
.pt
);
6282 while ((nItem
= ListView_FindItemW(hwnd
, nItem
, &lvFindInfo
)) != -1)
6284 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
6293 /* search by index */
6294 for (i
= nItem
; i
< GETITEMCOUNT(infoPtr
); i
++)
6296 if ((ListView_GetItemState(hwnd
, i
, uMask
) & uMask
) == uMask
)
6305 /* LISTVIEW_GetNumberOfWorkAreas */
6309 * Retrieves the origin coordinates when in icon or small icon display mode.
6312 * [I] HWND : window handle
6313 * [O] LPPOINT : coordinate information
6319 static LRESULT
LISTVIEW_GetOrigin(HWND hwnd
, LPPOINT lpptOrigin
)
6321 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
6322 UINT uView
= lStyle
& LVS_TYPEMASK
;
6323 BOOL bResult
= FALSE
;
6325 TRACE("(hwnd=%x, lpptOrigin=%p)\n", hwnd
, lpptOrigin
);
6327 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
6329 SCROLLINFO scrollInfo
;
6330 ZeroMemory(lpptOrigin
, sizeof(POINT
));
6331 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
6332 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
6334 if (lStyle
& WS_HSCROLL
)
6336 scrollInfo
.fMask
= SIF_POS
;
6337 if (GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
) != FALSE
)
6338 lpptOrigin
->x
= -scrollInfo
.nPos
* LISTVIEW_SCROLL_DIV_SIZE
;
6341 if (lStyle
& WS_VSCROLL
)
6343 scrollInfo
.fMask
= SIF_POS
;
6344 if (GetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
) != FALSE
)
6345 lpptOrigin
->y
= -scrollInfo
.nPos
* LISTVIEW_SCROLL_DIV_SIZE
;
6356 * Retrieves the number of items that are marked as selected.
6359 * [I] HWND : window handle
6362 * Number of items selected.
6364 static LRESULT
LISTVIEW_GetSelectedCount(HWND hwnd
)
6367 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
6368 INT nSelectedCount
= 0;
6371 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
6373 if (ListView_GetItemState(hwnd
, i
, LVIS_SELECTED
) & LVIS_SELECTED
)
6377 return nSelectedCount
;
6382 * Retrieves item index that marks the start of a multiple selection.
6385 * [I] HWND : window handle
6388 * Index number or -1 if there is no selection mark.
6390 static LRESULT
LISTVIEW_GetSelectionMark(HWND hwnd
)
6392 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
6394 return infoPtr
->nSelectionMark
;
6400 * Retrieves the width of a string.
6403 * [I] hwnd : window handle
6404 * [I] lpszText : text string to process
6405 * [I] isW : TRUE if lpszText is Unicode, FALSE otherwise
6408 * SUCCESS : string width (in pixels)
6411 static LRESULT
LISTVIEW_GetStringWidthT(HWND hwnd
, LPCWSTR lpszText
, BOOL isW
)
6413 if (is_textT(lpszText
, isW
))
6415 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
6416 HFONT hFont
= infoPtr
->hFont
? infoPtr
->hFont
: infoPtr
->hDefaultFont
;
6417 HDC hdc
= GetDC(hwnd
);
6418 HFONT hOldFont
= SelectObject(hdc
, hFont
);
6420 ZeroMemory(&stringSize
, sizeof(SIZE
));
6422 GetTextExtentPointW(hdc
, lpszText
, lstrlenW(lpszText
), &stringSize
);
6424 GetTextExtentPointA(hdc
, (LPCSTR
)lpszText
, lstrlenA((LPCSTR
)lpszText
), &stringSize
);
6425 SelectObject(hdc
, hOldFont
);
6426 ReleaseDC(hwnd
, hdc
);
6427 return stringSize
.cx
;
6434 * Retrieves the text backgound color.
6437 * [I] HWND : window handle
6440 * COLORREF associated with the the background.
6442 static LRESULT
LISTVIEW_GetTextBkColor(HWND hwnd
)
6444 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
6446 return infoPtr
->clrTextBk
;
6451 * Retrieves the text color.
6454 * [I] HWND : window handle
6457 * COLORREF associated with the text.
6459 static LRESULT
LISTVIEW_GetTextColor(HWND hwnd
)
6461 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
6463 return infoPtr
->clrText
;
6468 * Determines item if a hit or closest if not
6471 * [I] HWND : window handle
6472 * [IO] LPLV_INTHIT : hit test information
6473 * [I] subitem : fill out iSubItem.
6476 * SUCCESS : item index of hit
6479 static INT
LISTVIEW_SuperHitTestItem(HWND hwnd
, LPLV_INTHIT lpInt
, BOOL subitem
)
6481 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
6482 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
6483 UINT uView
= lStyle
& LVS_TYPEMASK
;
6484 INT i
,topindex
,bottomindex
;
6486 DWORD xterm
, yterm
, dist
;
6488 TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd
, lpInt
->ht
.pt
.x
, lpInt
->ht
.pt
.y
);
6490 topindex
= ListView_GetTopIndex(hwnd
);
6491 if (uView
== LVS_REPORT
)
6493 bottomindex
= topindex
+ LISTVIEW_GetCountPerColumn(hwnd
) + 1;
6494 bottomindex
= min(bottomindex
,GETITEMCOUNT(infoPtr
));
6498 bottomindex
= GETITEMCOUNT(infoPtr
);
6501 lpInt
->distance
= 0x7fffffff;
6502 lpInt
->iDistItem
= -1;
6504 for (i
= topindex
; i
< bottomindex
; i
++)
6506 rcItem
.left
= LVIR_BOUNDS
;
6507 if (LISTVIEW_GetItemRect(hwnd
, i
, &rcItem
))
6509 if (PtInRect(&rcItem
, lpInt
->ht
.pt
))
6511 rcItem
.left
= LVIR_ICON
;
6512 if (LISTVIEW_GetItemRect(hwnd
, i
, &rcItem
))
6514 if (PtInRect(&rcItem
, lpInt
->ht
.pt
))
6516 lpInt
->ht
.flags
= LVHT_ONITEMICON
;
6517 lpInt
->ht
.iItem
= i
;
6518 if (subitem
) lpInt
->ht
.iSubItem
= 0;
6523 rcItem
.left
= LVIR_LABEL
;
6524 if (LISTVIEW_GetItemRect(hwnd
, i
, &rcItem
))
6526 if (PtInRect(&rcItem
, lpInt
->ht
.pt
))
6528 lpInt
->ht
.flags
= LVHT_ONITEMLABEL
;
6529 lpInt
->ht
.iItem
= i
;
6530 if (subitem
) lpInt
->ht
.iSubItem
= 0;
6535 lpInt
->ht
.flags
= LVHT_ONITEMSTATEICON
;
6536 lpInt
->ht
.iItem
= i
;
6537 if (subitem
) lpInt
->ht
.iSubItem
= 0;
6543 * Now compute distance from point to center of boundary
6544 * box. Since we are only interested in the relative
6545 * distance, we can skip the nasty square root operation
6547 xterm
= rcItem
.left
+ (rcItem
.right
- rcItem
.left
)/2 - lpInt
->ht
.pt
.x
;
6548 yterm
= rcItem
.top
+ (rcItem
.bottom
- rcItem
.top
)/2 - lpInt
->ht
.pt
.y
;
6549 dist
= xterm
* xterm
+ yterm
* yterm
;
6550 if (dist
< lpInt
->distance
)
6552 lpInt
->distance
= dist
;
6553 lpInt
->iDistItem
= i
;
6559 lpInt
->ht
.flags
= LVHT_NOWHERE
;
6560 TRACE("no hit, closest item %d, distance %ld\n", lpInt
->iDistItem
, lpInt
->distance
);
6567 * Determines which section of the item was selected (if any).
6570 * [I] HWND : window handle
6571 * [IO] LPLVHITTESTINFO : hit test information
6572 * [I] subitem : fill out iSubItem.
6575 * SUCCESS : item index
6578 static INT
LISTVIEW_HitTestItem(HWND hwnd
, LPLVHITTESTINFO lpHitTestInfo
, BOOL subitem
)
6581 LV_INTHIT lv_inthit
;
6583 TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd
, lpHitTestInfo
->pt
.x
,
6584 lpHitTestInfo
->pt
.y
);
6586 memcpy(&lv_inthit
, lpHitTestInfo
, sizeof(LVHITTESTINFO
));
6587 ret
= LISTVIEW_SuperHitTestItem(hwnd
, &lv_inthit
, subitem
);
6588 memcpy(lpHitTestInfo
, &lv_inthit
, sizeof(LVHITTESTINFO
));
6594 * Determines which listview item is located at the specified position.
6597 * [I] HWND : window handle
6598 * [IO} LPLVHITTESTINFO : hit test information
6601 * SUCCESS : item index
6604 static LRESULT
LISTVIEW_HitTest(HWND hwnd
, LPLVHITTESTINFO lpHitTestInfo
)
6606 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
6609 lpHitTestInfo
->flags
= 0;
6611 if (infoPtr
->rcList
.left
> lpHitTestInfo
->pt
.x
)
6612 lpHitTestInfo
->flags
= LVHT_TOLEFT
;
6613 else if (infoPtr
->rcList
.right
< lpHitTestInfo
->pt
.x
)
6614 lpHitTestInfo
->flags
= LVHT_TORIGHT
;
6615 if (infoPtr
->rcList
.top
> lpHitTestInfo
->pt
.y
)
6616 lpHitTestInfo
->flags
|= LVHT_ABOVE
;
6617 else if (infoPtr
->rcList
.bottom
< lpHitTestInfo
->pt
.y
)
6618 lpHitTestInfo
->flags
|= LVHT_BELOW
;
6620 if (lpHitTestInfo
->flags
== 0)
6622 /* NOTE (mm 20001022): We must not allow iSubItem to be touched, for
6623 * an app might pass only a structure with space up to iItem!
6624 * (MS Office 97 does that for instance in the file open dialog)
6626 nItem
= LISTVIEW_HitTestItem(hwnd
, lpHitTestInfo
, FALSE
);
6634 * Inserts a new column.
6637 * [I] HWND : window handle
6638 * [I] INT : column index
6639 * [I] LPLVCOLUMNW : column information
6642 * SUCCESS : new column index
6645 static LRESULT
LISTVIEW_InsertColumnT(HWND hwnd
, INT nColumn
,
6646 LPLVCOLUMNW lpColumn
, BOOL isW
)
6648 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
6649 INT nNewColumn
= -1;
6652 TRACE("(hwnd=%x, nColumn=%d, lpColumn=%p)\n",hwnd
, nColumn
, lpColumn
);
6654 if (lpColumn
!= NULL
)
6656 /* initialize memory */
6657 ZeroMemory(&hdi
, sizeof(hdi
));
6659 if (lpColumn
->mask
& LVCF_FMT
)
6661 /* format member is valid */
6662 hdi
.mask
|= HDI_FORMAT
;
6664 /* set text alignment (leftmost column must be left-aligned) */
6667 hdi
.fmt
|= HDF_LEFT
;
6671 if (lpColumn
->fmt
& LVCFMT_LEFT
)
6673 hdi
.fmt
|= HDF_LEFT
;
6675 else if (lpColumn
->fmt
& LVCFMT_RIGHT
)
6677 hdi
.fmt
|= HDF_RIGHT
;
6679 else if (lpColumn
->fmt
& LVCFMT_CENTER
)
6681 hdi
.fmt
|= HDF_CENTER
;
6685 if (lpColumn
->fmt
& LVCFMT_BITMAP_ON_RIGHT
)
6687 hdi
.fmt
|= HDF_BITMAP_ON_RIGHT
;
6691 if (lpColumn
->fmt
& LVCFMT_COL_HAS_IMAGES
)
6696 if (lpColumn
->fmt
& LVCFMT_IMAGE
)
6698 hdi
.fmt
|= HDF_IMAGE
;
6699 hdi
.iImage
= I_IMAGECALLBACK
;
6703 if (lpColumn
->mask
& LVCF_WIDTH
)
6705 hdi
.mask
|= HDI_WIDTH
;
6706 if(lpColumn
->cx
== LVSCW_AUTOSIZE_USEHEADER
)
6708 /* make it fill the remainder of the controls width */
6713 ZeroMemory(&hdit
, sizeof(hdit
));
6715 /* get the width of every item except the current one */
6716 hdit
.mask
= HDI_WIDTH
;
6719 for(item_index
= 0; item_index
< (nColumn
- 1); item_index
++) {
6720 Header_GetItemW(infoPtr
->hwndHeader
, item_index
, (LPARAM
)(&hdit
));
6724 /* retrieve the layout of the header */
6725 GetClientRect(hwnd
, &rcHeader
);
6726 /* GetWindowRect(infoPtr->hwndHeader, &rcHeader);*/
6727 TRACE("start cxy=%d left=%d right=%d\n", hdi
.cxy
, rcHeader
.left
, rcHeader
.right
);
6729 hdi
.cxy
= (rcHeader
.right
- rcHeader
.left
) - hdi
.cxy
;
6732 hdi
.cxy
= lpColumn
->cx
;
6735 if (lpColumn
->mask
& LVCF_TEXT
)
6737 hdi
.mask
|= HDI_TEXT
| HDI_FORMAT
;
6738 hdi
.pszText
= lpColumn
->pszText
;
6739 hdi
.cchTextMax
= textlenT(lpColumn
->pszText
, isW
);
6740 hdi
.fmt
|= HDF_STRING
;
6743 if (lpColumn
->mask
& LVCF_IMAGE
)
6745 hdi
.mask
|= HDI_IMAGE
;
6746 hdi
.iImage
= lpColumn
->iImage
;
6749 if (lpColumn
->mask
& LVCF_ORDER
)
6751 hdi
.mask
|= HDI_ORDER
;
6752 hdi
.iOrder
= lpColumn
->iOrder
;
6755 /* insert item in header control */
6756 nNewColumn
= SendMessageW(infoPtr
->hwndHeader
, HDM_INSERTITEMT(isW
),
6757 (WPARAM
)nColumn
, (LPARAM
)&hdi
);
6759 /* Need to reset the item width when inserting a new column */
6760 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
6762 LISTVIEW_UpdateScroll(hwnd
);
6763 InvalidateRect(hwnd
, NULL
, FALSE
);
6769 /* LISTVIEW_InsertCompare: callback routine for comparing pszText members of the LV_ITEMS
6770 in a LISTVIEW on insert. Passed to DPA_Sort in LISTVIEW_InsertItem.
6771 This function should only be used for inserting items into a sorted list (LVM_INSERTITEM)
6772 and not during the processing of a LVM_SORTITEMS message. Applications should provide
6773 their own sort proc. when sending LVM_SORTITEMS.
6776 (remarks on LVITEM: LVM_INSERTITEM will insert the new item in the proper sort postion...
6778 LVS_SORTXXX must be specified,
6779 LVS_OWNERDRAW is not set,
6780 <item>.pszText is not LPSTR_TEXTCALLBACK.
6782 (LVS_SORT* flags): "For the LVS_SORTASCENDING... styles, item indices
6783 are sorted based on item text..."
6785 static INT WINAPI
LISTVIEW_InsertCompare( LPVOID first
, LPVOID second
, LPARAM lParam
)
6787 LONG lStyle
= GetWindowLongW((HWND
) lParam
, GWL_STYLE
);
6788 LISTVIEW_ITEM
* lv_first
= (LISTVIEW_ITEM
*) DPA_GetPtr( (HDPA
)first
, 0 );
6789 LISTVIEW_ITEM
* lv_second
= (LISTVIEW_ITEM
*) DPA_GetPtr( (HDPA
)second
, 0 );
6790 INT cmpv
= lstrcmpW( lv_first
->pszText
, lv_second
->pszText
);
6791 /* if we're sorting descending, negate the return value */
6792 return (lStyle
& LVS_SORTDESCENDING
) ? -cmpv
: cmpv
;
6797 * Inserts a new item in the listview control.
6800 * [I] HWND : window handle
6801 * [I] LPLVITEMW : item information
6802 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
6805 * SUCCESS : new item index
6808 static LRESULT
LISTVIEW_InsertItemT(HWND hwnd
, LPLVITEMW lpLVItem
, BOOL isW
)
6810 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
6811 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
6812 UINT uView
= lStyle
& LVS_TYPEMASK
;
6816 LISTVIEW_ITEM
*lpItem
= NULL
;
6818 TRACE("(hwnd=%x, lpLVItem=%s, isW=%d)\n",
6819 hwnd
, debuglvitem_t(lpLVItem
, isW
), isW
);
6821 if (lStyle
& LVS_OWNERDATA
)
6823 nItem
= infoPtr
->hdpaItems
->nItemCount
;
6824 infoPtr
->hdpaItems
->nItemCount
++;
6828 if (lpLVItem
!= NULL
)
6830 /* make sure it's not a subitem; cannot insert a subitem */
6831 if (lpLVItem
->iSubItem
== 0)
6833 if ( (lpItem
= (LISTVIEW_ITEM
*)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM
))) )
6835 ZeroMemory(lpItem
, sizeof(LISTVIEW_ITEM
));
6836 if (LISTVIEW_InitItemT(hwnd
, lpItem
, lpLVItem
, isW
))
6838 /* insert item in listview control data structure */
6839 if ( (hdpaSubItems
= DPA_Create(8)) )
6841 if ( (nItem
= DPA_InsertPtr(hdpaSubItems
, 0, lpItem
)) != -1)
6843 if ( ((lStyle
& LVS_SORTASCENDING
) || (lStyle
& LVS_SORTDESCENDING
))
6844 && !(lStyle
& LVS_OWNERDRAWFIXED
)
6845 && (LPSTR_TEXTCALLBACKW
!= lpLVItem
->pszText
) )
6847 /* Insert the item in the proper sort order based on the pszText
6848 member. See comments for LISTVIEW_InsertCompare() for greater detail */
6849 nItem
= DPA_InsertPtr( infoPtr
->hdpaItems
,
6850 GETITEMCOUNT( infoPtr
) + 1, hdpaSubItems
);
6851 DPA_Sort( infoPtr
->hdpaItems
, LISTVIEW_InsertCompare
, hwnd
);
6852 nItem
= DPA_GetPtrIndex( infoPtr
->hdpaItems
, hdpaSubItems
);
6856 nItem
= DPA_InsertPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
,
6863 LISTVIEW_ShiftIndices(hwnd
,nItem
,1);
6865 /* manage item focus */
6866 if (lpLVItem
->mask
& LVIF_STATE
)
6868 lpItem
->state
&= ~(LVIS_FOCUSED
|LVIS_SELECTED
);
6869 if (lpLVItem
->stateMask
& LVIS_SELECTED
)
6870 LISTVIEW_SetSelection(hwnd
, nItem
);
6871 else if (lpLVItem
->stateMask
& LVIS_FOCUSED
)
6872 LISTVIEW_SetItemFocus(hwnd
, nItem
);
6875 /* send LVN_INSERTITEM notification */
6876 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
6878 nmlv
.lParam
= lpItem
->lParam
;
6879 listview_notify(hwnd
, LVN_INSERTITEM
, &nmlv
);
6881 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_LIST
))
6883 nItemWidth
= LISTVIEW_CalculateWidth(hwnd
, lpLVItem
->iItem
);
6884 if (nItemWidth
> infoPtr
->nItemWidth
)
6885 infoPtr
->nItemWidth
= nItemWidth
;
6888 /* align items (set position of each item) */
6889 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
6891 if (lStyle
& LVS_ALIGNLEFT
)
6892 LISTVIEW_AlignLeft(hwnd
);
6894 LISTVIEW_AlignTop(hwnd
);
6897 LISTVIEW_UpdateScroll(hwnd
);
6898 /* refresh client area */
6899 InvalidateRect(hwnd
, NULL
, FALSE
);
6908 /* free memory if unsuccessful */
6909 if ((nItem
== -1) && (lpItem
!= NULL
))
6910 COMCTL32_Free(lpItem
);
6917 * Redraws a range of items.
6920 * [I] HWND : window handle
6921 * [I] INT : first item
6922 * [I] INT : last item
6928 static LRESULT
LISTVIEW_RedrawItems(HWND hwnd
, INT nFirst
, INT nLast
)
6930 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
6931 BOOL bResult
= FALSE
;
6935 if (nFirst
<= nLast
)
6937 if ((nFirst
>= 0) && (nFirst
< GETITEMCOUNT(infoPtr
)))
6939 if ((nLast
>= 0) && (nLast
< GETITEMCOUNT(infoPtr
)))
6941 for (i
= nFirst
; i
<= nLast
; i
++)
6943 rcItem
.left
= LVIR_BOUNDS
;
6944 LISTVIEW_GetItemRect(hwnd
, i
, &rcItem
);
6945 InvalidateRect(hwnd
, &rcItem
, TRUE
);
6954 /* LISTVIEW_Scroll */
6958 * Sets the background color.
6961 * [I] HWND : window handle
6962 * [I] COLORREF : background color
6968 static LRESULT
LISTVIEW_SetBkColor(HWND hwnd
, COLORREF clrBk
)
6970 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
6972 if(infoPtr
->clrBk
!=clrBk
){
6973 infoPtr
->clrBk
= clrBk
;
6974 InvalidateRect(hwnd
, NULL
, TRUE
);
6980 /* LISTVIEW_SetBkImage */
6984 * Sets the callback mask. This mask will be used when the parent
6985 * window stores state information (some or all).
6988 * [I] HWND : window handle
6989 * [I] UINT : state mask
6995 static BOOL
LISTVIEW_SetCallbackMask(HWND hwnd
, UINT uMask
)
6997 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
6999 infoPtr
->uCallbackMask
= uMask
;
7006 * Sets the attributes of a header item.
7009 * [I] HWND : window handle
7010 * [I] INT : column index
7011 * [I] LPLVCOLUMNW : column attributes
7012 * [I] isW: if TRUE, the lpColumn is a LPLVCOLUMNW,
7013 * otherwise it is in fact a LPLVCOLUMNA
7019 static LRESULT
LISTVIEW_SetColumnT(HWND hwnd
, INT nColumn
,
7020 LPLVCOLUMNW lpColumn
, BOOL isW
)
7022 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
7023 BOOL bResult
= FALSE
;
7024 HDITEMW hdi
, hdiget
;
7026 if ((lpColumn
!= NULL
) && (nColumn
>= 0) &&
7027 (nColumn
< Header_GetItemCount(infoPtr
->hwndHeader
)))
7029 /* initialize memory */
7030 ZeroMemory(&hdi
, sizeof(hdi
));
7032 if (lpColumn
->mask
& LVCF_FMT
)
7034 /* format member is valid */
7035 hdi
.mask
|= HDI_FORMAT
;
7037 /* get current format first */
7038 hdiget
.mask
= HDI_FORMAT
;
7039 if (Header_GetItemW(infoPtr
->hwndHeader
, nColumn
, &hdiget
))
7040 /* preserve HDF_STRING if present */
7041 hdi
.fmt
= hdiget
.fmt
& HDF_STRING
;
7043 /* set text alignment (leftmost column must be left-aligned) */
7046 hdi
.fmt
|= HDF_LEFT
;
7050 if (lpColumn
->fmt
& LVCFMT_LEFT
)
7051 hdi
.fmt
|= HDF_LEFT
;
7052 else if (lpColumn
->fmt
& LVCFMT_RIGHT
)
7053 hdi
.fmt
|= HDF_RIGHT
;
7054 else if (lpColumn
->fmt
& LVCFMT_CENTER
)
7055 hdi
.fmt
|= HDF_CENTER
;
7058 if (lpColumn
->fmt
& LVCFMT_BITMAP_ON_RIGHT
)
7059 hdi
.fmt
|= HDF_BITMAP_ON_RIGHT
;
7061 if (lpColumn
->fmt
& LVCFMT_COL_HAS_IMAGES
)
7062 hdi
.fmt
|= HDF_IMAGE
;
7064 if (lpColumn
->fmt
& LVCFMT_IMAGE
)
7066 hdi
.fmt
|= HDF_IMAGE
;
7067 hdi
.iImage
= I_IMAGECALLBACK
;
7071 if (lpColumn
->mask
& LVCF_WIDTH
)
7073 hdi
.mask
|= HDI_WIDTH
;
7074 hdi
.cxy
= lpColumn
->cx
;
7077 if (lpColumn
->mask
& LVCF_TEXT
)
7079 hdi
.mask
|= HDI_TEXT
| HDI_FORMAT
;
7080 hdi
.pszText
= lpColumn
->pszText
;
7081 hdi
.cchTextMax
= textlenT(lpColumn
->pszText
, isW
);
7082 hdi
.fmt
|= HDF_STRING
;
7085 if (lpColumn
->mask
& LVCF_IMAGE
)
7087 hdi
.mask
|= HDI_IMAGE
;
7088 hdi
.iImage
= lpColumn
->iImage
;
7091 if (lpColumn
->mask
& LVCF_ORDER
)
7093 hdi
.mask
|= HDI_ORDER
;
7094 hdi
.iOrder
= lpColumn
->iOrder
;
7097 /* set header item attributes */
7098 bResult
= Header_SetItemW(infoPtr
->hwndHeader
, nColumn
, &hdi
);
7106 * Sets the column order array
7109 * [I] HWND : window handle
7110 * [I] INT : number of elements in column order array
7111 * [I] INT : pointer to column order array
7117 static LRESULT
LISTVIEW_SetColumnOrderArray(HWND hwnd
, INT iCount
, LPINT lpiArray
)
7119 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0); */
7121 FIXME("iCount %d lpiArray %p\n", iCount
, lpiArray
);
7132 * Sets the width of a column
7135 * [I] HWND : window handle
7136 * [I] INT : column index
7137 * [I] INT : column width
7143 static LRESULT
LISTVIEW_SetColumnWidth(HWND hwnd
, INT iCol
, INT cx
)
7145 LISTVIEW_INFO
*infoPtr
;
7148 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
7149 UINT uView
= lStyle
& LVS_TYPEMASK
;
7154 WCHAR text_buffer
[DISP_TEXT_SIZE
];
7155 INT header_item_count
;
7160 WCHAR szDispText
[DISP_TEXT_SIZE
];
7162 /* make sure we can get the listview info */
7163 if (!(infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0)))
7166 if (!infoPtr
->hwndHeader
) /* make sure we have a header */
7169 /* set column width only if in report or list mode */
7170 if ((uView
!= LVS_REPORT
) && (uView
!= LVS_LIST
))
7173 TRACE("(hwnd=%x, iCol=%d, cx=%d\n", hwnd
, iCol
, cx
);
7175 /* take care of invalid cx values */
7176 if((uView
== LVS_REPORT
) && (cx
< -2))
7177 cx
= LVSCW_AUTOSIZE
;
7178 else if (uView
== LVS_LIST
&& (cx
< 1))
7181 /* resize all columns if in LVS_LIST mode */
7182 if(uView
== LVS_LIST
) {
7183 infoPtr
->nItemWidth
= cx
;
7184 InvalidateRect(hwnd
, NULL
, TRUE
); /* force redraw of the listview */
7188 /* autosize based on listview items width */
7189 if(cx
== LVSCW_AUTOSIZE
)
7191 /* set the width of the column to the width of the widest item */
7192 if (iCol
== 0 || uView
== LVS_LIST
)
7195 for(item_index
= 0; item_index
< GETITEMCOUNT(infoPtr
); item_index
++)
7197 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, item_index
);
7198 cx
= (nLabelWidth
>cx
)?nLabelWidth
:cx
;
7200 /* I had to add the '3' to prevent clipping of the end of the
7201 line. Probably one of these padding numbers is incorrect. */
7202 if (infoPtr
->himlSmall
)
7203 cx
+= WIDTH_PADDING
+ IMAGE_PADDING
+ 3;
7207 ZeroMemory(&lvItem
, sizeof(lvItem
));
7208 lvItem
.iSubItem
= iCol
;
7209 lvItem
.mask
= LVIF_TEXT
;
7210 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
7211 lvItem
.pszText
= szDispText
;
7212 *lvItem
.pszText
= '\0';
7214 for(item_index
= 0; item_index
< GETITEMCOUNT(infoPtr
); item_index
++)
7216 lvItem
.iItem
= item_index
;
7217 LISTVIEW_GetItemT(hwnd
, &lvItem
, FALSE
, TRUE
);
7218 nLabelWidth
= LISTVIEW_GetStringWidthT(hwnd
, lvItem
.pszText
, TRUE
);
7219 cx
= (nLabelWidth
>cx
)?nLabelWidth
:cx
;
7222 cx
+= TRAILING_PADDING
;
7223 } /* autosize based on listview header width */
7224 else if(cx
== LVSCW_AUTOSIZE_USEHEADER
)
7226 header_item_count
= Header_GetItemCount(infoPtr
->hwndHeader
);
7228 /* if iCol is the last column make it fill the remainder of the controls width */
7229 if(iCol
== (header_item_count
- 1)) {
7230 /* get the width of every item except the current one */
7231 hdi
.mask
= HDI_WIDTH
;
7234 for(item_index
= 0; item_index
< (header_item_count
- 1); item_index
++) {
7235 Header_GetItemW(infoPtr
->hwndHeader
, item_index
, (LPARAM
)(&hdi
));
7239 /* retrieve the layout of the header */
7240 GetWindowRect(infoPtr
->hwndHeader
, &rcHeader
);
7242 cx
= (rcHeader
.right
- rcHeader
.left
) - cx
;
7246 /* Despite what the MS docs say, if this is not the last
7247 column, then MS resizes the column to the width of the
7248 largest text string in the column, including headers
7249 and items. This is different from LVSCW_AUTOSIZE in that
7250 LVSCW_AUTOSIZE ignores the header string length.
7253 /* retrieve header font */
7254 header_font
= SendMessageW(infoPtr
->hwndHeader
, WM_GETFONT
, 0L, 0L);
7256 /* retrieve header text */
7257 hdi
.mask
= HDI_TEXT
;
7258 hdi
.cchTextMax
= sizeof(text_buffer
)/sizeof(text_buffer
[0]);
7259 hdi
.pszText
= text_buffer
;
7261 Header_GetItemW(infoPtr
->hwndHeader
, iCol
, (LPARAM
)(&hdi
));
7263 /* determine the width of the text in the header */
7265 old_font
= SelectObject(hdc
, header_font
); /* select the font into hdc */
7267 GetTextExtentPoint32W(hdc
, text_buffer
, lstrlenW(text_buffer
), &size
);
7269 SelectObject(hdc
, old_font
); /* restore the old font */
7270 ReleaseDC(hwnd
, hdc
);
7272 ZeroMemory(&lvItem
, sizeof(lvItem
));
7273 lvItem
.iSubItem
= iCol
;
7274 lvItem
.mask
= LVIF_TEXT
;
7275 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
7276 lvItem
.pszText
= szDispText
;
7277 *lvItem
.pszText
= '\0';
7279 for(item_index
= 0; item_index
< GETITEMCOUNT(infoPtr
); item_index
++)
7281 lvItem
.iItem
= item_index
;
7282 LISTVIEW_GetItemT(hwnd
, &lvItem
, FALSE
, TRUE
);
7283 nLabelWidth
= LISTVIEW_GetStringWidthT(hwnd
, lvItem
.pszText
, TRUE
);
7284 nLabelWidth
+= TRAILING_PADDING
;
7285 /* While it is possible for subitems to have icons, even MS messes
7286 up the positioning, so I suspect no applications actually use
7288 if (item_index
== 0 && infoPtr
->himlSmall
)
7289 /* I had to add the '3' to prevent clipping of the end of the
7290 line. Probably one of these padding numbers is incorrect. */
7291 nLabelWidth
+= WIDTH_PADDING
+ IMAGE_PADDING
+ 3;
7292 cx
= (nLabelWidth
>cx
)?nLabelWidth
:cx
;
7297 /* call header to update the column change */
7298 hdi
.mask
= HDI_WIDTH
;
7301 lret
= Header_SetItemW(infoPtr
->hwndHeader
, (WPARAM
)iCol
, (LPARAM
)&hdi
);
7303 InvalidateRect(hwnd
, NULL
, TRUE
); /* force redraw of the listview */
7310 * Sets the extended listview style.
7313 * [I] HWND : window handle
7318 * SUCCESS : previous style
7321 static LRESULT
LISTVIEW_SetExtendedListViewStyle(HWND hwnd
, DWORD dwMask
, DWORD dwStyle
)
7323 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
7324 DWORD dwOldStyle
= infoPtr
->dwExStyle
;
7328 infoPtr
->dwExStyle
= (dwOldStyle
& ~dwMask
) | (dwStyle
& dwMask
);
7330 infoPtr
->dwExStyle
= dwStyle
;
7335 /* LISTVIEW_SetHotCursor */
7339 * Sets the hot item index.
7342 * [I] HWND : window handle
7346 * SUCCESS : previous hot item index
7347 * FAILURE : -1 (no hot item)
7349 static LRESULT
LISTVIEW_SetHotItem(HWND hwnd
, INT iIndex
)
7351 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
7352 INT iOldIndex
= infoPtr
->nHotItem
;
7355 infoPtr
->nHotItem
= iIndex
;
7362 * Sets the amount of time the cursor must hover over an item before it is selected.
7365 * [I] HWND : window handle
7366 * [I] DWORD : dwHoverTime, if -1 the hover time is set to the default
7369 * Returns the previous hover time
7371 static LRESULT
LISTVIEW_SetHoverTime(HWND hwnd
, DWORD dwHoverTime
)
7373 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
7374 DWORD oldHoverTime
= infoPtr
->dwHoverTime
;
7376 infoPtr
->dwHoverTime
= dwHoverTime
;
7378 return oldHoverTime
;
7383 * Sets spacing for icons of LVS_ICON style.
7386 * [I] HWND : window handle
7387 * [I] DWORD : MAKELONG(cx, cy)
7390 * MAKELONG(oldcx, oldcy)
7392 static LRESULT
LISTVIEW_SetIconSpacing(HWND hwnd
, DWORD spacing
)
7394 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
7395 INT cy
= HIWORD(spacing
);
7396 INT cx
= LOWORD(spacing
);
7398 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
7399 UINT uView
= lStyle
& LVS_TYPEMASK
;
7401 oldspacing
= MAKELONG(infoPtr
->iconSpacing
.cx
, infoPtr
->iconSpacing
.cy
);
7402 if (cx
== -1) /* set to default */
7403 cx
= GetSystemMetrics(SM_CXICONSPACING
);
7404 if (cy
== -1) /* set to default */
7405 cy
= GetSystemMetrics(SM_CYICONSPACING
);
7408 infoPtr
->iconSpacing
.cx
= cx
;
7410 { /* if 0 then compute width */
7411 if (uView
== LVS_ICON
)
7412 FIXME("width computation not yet done\n");
7414 * Should scan each item and determine max width of
7415 * icon or label, then make that the width
7417 else /* FIXME: unknown computation for non LVS_ICON - this is a guess */
7418 infoPtr
->iconSpacing
.cx
= LISTVIEW_GetItemWidth(hwnd
);
7421 infoPtr
->iconSpacing
.cy
= cy
;
7423 { /* if 0 then compute height */
7424 if (uView
== LVS_ICON
)
7425 infoPtr
->iconSpacing
.cy
= infoPtr
->iconSize
.cy
+ infoPtr
->ntmHeight
7426 + ICON_BOTTOM_PADDING
+ ICON_TOP_PADDING
+ LABEL_VERT_OFFSET
;
7427 /* FIXME. I don't think so; I think it is based on twice the ntmHeight */
7428 else /* FIXME: unknown computation for non LVS_ICON - this is a guess */
7429 infoPtr
->iconSpacing
.cy
= LISTVIEW_GetItemHeight(hwnd
);
7432 TRACE("old=(%d,%d), new=(%ld,%ld)\n", LOWORD(oldspacing
), HIWORD(oldspacing
),
7433 infoPtr
->iconSpacing
.cx
, infoPtr
->iconSpacing
.cy
);
7435 /* these depend on the iconSpacing */
7436 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
7437 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(hwnd
);
7447 * [I] HWND : window handle
7448 * [I] INT : image list type
7449 * [I] HIMAGELIST : image list handle
7452 * SUCCESS : old image list
7455 static HIMAGELIST
LISTVIEW_SetImageList(HWND hwnd
, INT nType
, HIMAGELIST himl
)
7457 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
7458 HIMAGELIST himlOld
= 0;
7464 himlOld
= infoPtr
->himlNormal
;
7465 infoPtr
->himlNormal
= himl
;
7469 himlOld
= infoPtr
->himlSmall
;
7470 infoPtr
->himlSmall
= himl
;
7474 himlOld
= infoPtr
->himlState
;
7475 infoPtr
->himlState
= himl
;
7476 ImageList_SetBkColor(infoPtr
->himlState
, CLR_NONE
);
7480 oldHeight
= infoPtr
->nItemHeight
;
7481 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(hwnd
);
7482 if (infoPtr
->nItemHeight
!= oldHeight
)
7483 LISTVIEW_UpdateScroll(hwnd
);
7490 * Preallocates memory (does *not* set the actual count of items !)
7493 * [I] HWND : window handle
7494 * [I] INT : item count (projected number of items to allocate)
7495 * [I] DWORD : update flags
7501 static BOOL
LISTVIEW_SetItemCount(HWND hwnd
, INT nItems
, DWORD dwFlags
)
7503 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
7505 TRACE("(hwnd=%x, nItems=%d, dwFlags=%lx)\n", hwnd
, nItems
, dwFlags
);
7507 if (GetWindowLongW(hwnd
, GWL_STYLE
) & LVS_OWNERDATA
)
7509 int precount
,topvisible
;
7511 TRACE("LVS_OWNERDATA is set!\n");
7512 if (dwFlags
& (LVSICF_NOINVALIDATEALL
| LVSICF_NOSCROLL
))
7513 FIXME("flags %s %s not implemented\n",
7514 (dwFlags
& LVSICF_NOINVALIDATEALL
) ? "LVSICF_NOINVALIDATEALL"
7516 (dwFlags
& LVSICF_NOSCROLL
) ? "LVSICF_NOSCROLL" : "");
7519 * Internally remove all the selections.
7523 LISTVIEW_SELECTION
*selection
;
7524 selection
= DPA_GetPtr(infoPtr
->hdpaSelectionRanges
,0);
7526 LISTVIEW_RemoveSelectionRange(hwnd
,selection
->lower
,
7529 while (infoPtr
->hdpaSelectionRanges
->nItemCount
>0);
7531 precount
= infoPtr
->hdpaItems
->nItemCount
;
7532 topvisible
= ListView_GetTopIndex(hwnd
) +
7533 LISTVIEW_GetCountPerColumn(hwnd
) + 1;
7535 infoPtr
->hdpaItems
->nItemCount
= nItems
;
7537 LISTVIEW_UpdateSize(hwnd
);
7538 LISTVIEW_UpdateScroll(hwnd
);
7539 if (min(precount
,infoPtr
->hdpaItems
->nItemCount
)<topvisible
)
7540 InvalidateRect(hwnd
, NULL
, TRUE
);
7544 /* According to MSDN for non-LVS_OWNERDATA this is just
7545 * a performance issue. The control allocates its internal
7546 * data structures for the number of items specified. It
7547 * cuts down on the number of memory allocations. Therefore
7548 * we will just issue a WARN here
7550 WARN("for non-ownerdata performance option not implemented.\n");
7558 * Sets the position of an item.
7561 * [I] HWND : window handle
7562 * [I] INT : item index
7563 * [I] LONG : x coordinate
7564 * [I] LONG : y coordinate
7570 static BOOL
LISTVIEW_SetItemPosition(HWND hwnd
, INT nItem
,
7571 LONG nPosX
, LONG nPosY
)
7573 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
7574 UINT lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
7575 UINT uView
= lStyle
& LVS_TYPEMASK
;
7576 LISTVIEW_ITEM
*lpItem
;
7578 BOOL bResult
= FALSE
;
7580 TRACE("(hwnd=%x, nItem=%d, X=%ld, Y=%ld)\n", hwnd
, nItem
, nPosX
, nPosY
);
7582 if (lStyle
& LVS_OWNERDATA
)
7585 if ((nItem
>= 0) || (nItem
< GETITEMCOUNT(infoPtr
)))
7587 if ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
))
7589 if ( (hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
)) )
7591 if ( (lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0)) )
7595 orig
= lpItem
->ptPosition
;
7596 if ((nPosX
== -1) && (nPosY
== -1))
7598 /* This point value seems to be an undocumented feature. The
7599 * best guess is that it means either at the origin, or at
7600 * the true beginning of the list. I will assume the origin.
7603 if (!LISTVIEW_GetOrigin(hwnd
, &pt1
))
7610 if (uView
== LVS_ICON
)
7612 nPosX
+= (infoPtr
->iconSpacing
.cx
- infoPtr
->iconSize
.cx
) / 2;
7613 nPosY
+= ICON_TOP_PADDING
;
7615 TRACE("requested special (-1,-1), set to origin (%ld,%ld)\n",
7619 lpItem
->ptPosition
.x
= nPosX
;
7620 lpItem
->ptPosition
.y
= nPosY
;
7621 if (uView
== LVS_ICON
)
7623 lpItem
->ptPosition
.y
-= ICON_TOP_PADDING
;
7624 lpItem
->ptPosition
.x
-= (infoPtr
->iconSpacing
.cx
- infoPtr
->iconSize
.cx
) / 2;
7625 if ((lpItem
->ptPosition
.y
< 0) || (lpItem
->ptPosition
.x
< 0))
7627 FIXME("failed orig (%ld,%ld), intent (%ld,%ld), is (%ld, %ld), setting neg to 0\n",
7628 orig
.x
, orig
.y
, nPosX
, nPosY
, lpItem
->ptPosition
.x
, lpItem
->ptPosition
.y
);
7631 if (lpItem->ptPosition.x < 0) lpItem->ptPosition.x = 0;
7632 if (lpItem->ptPosition.y < 0) lpItem->ptPosition.y = 0;
7637 TRACE("orig (%ld,%ld), intent (%ld,%ld), is (%ld,%ld)\n",
7638 orig
.x
, orig
.y
, nPosX
, nPosY
, lpItem
->ptPosition
.x
, lpItem
->ptPosition
.y
);
7651 * Sets the state of one or many items.
7654 * [I] HWND : window handle
7655 * [I]INT : item index
7656 * [I] LPLVITEM : item or subitem info
7662 static LRESULT
LISTVIEW_SetItemState(HWND hwnd
, INT nItem
, LPLVITEMW lpLVItem
)
7664 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
7665 BOOL bResult
= TRUE
;
7668 TRACE("(hwnd=%x, nItem=%d, lpLVItem=%s)\n",
7669 hwnd
, nItem
, debuglvitem_t(lpLVItem
, TRUE
));
7671 ZeroMemory(&lvItem
, sizeof(lvItem
));
7672 lvItem
.mask
= LVIF_STATE
;
7673 lvItem
.state
= lpLVItem
->state
;
7674 lvItem
.stateMask
= lpLVItem
->stateMask
;
7675 lvItem
.iItem
= nItem
;
7679 /* apply to all items */
7680 for (lvItem
.iItem
= 0; lvItem
.iItem
< GETITEMCOUNT(infoPtr
); lvItem
.iItem
++)
7681 if (!ListView_SetItemW(hwnd
, &lvItem
)) bResult
= FALSE
;
7684 bResult
= ListView_SetItemW(hwnd
, &lvItem
);
7691 * Sets the text of an item or subitem.
7694 * [I] hwnd : window handle
7695 * [I] nItem : item index
7696 * [I] lpLVItem : item or subitem info
7697 * [I] isW : TRUE if input is Unicode
7703 static BOOL
LISTVIEW_SetItemTextT(HWND hwnd
, INT nItem
, LPLVITEMW lpLVItem
, BOOL isW
)
7705 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
7706 BOOL bResult
= FALSE
;
7709 TRACE("(hwnd=%x, nItem=%d, lpLVItem=%s, isW=%d)\n",
7710 hwnd
, nItem
, debuglvitem_t(lpLVItem
, isW
), isW
);
7712 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
7714 ZeroMemory(&lvItem
, sizeof(LVITEMW
));
7715 lvItem
.mask
= LVIF_TEXT
;
7716 lvItem
.pszText
= lpLVItem
->pszText
;
7717 lvItem
.iItem
= nItem
;
7718 lvItem
.iSubItem
= lpLVItem
->iSubItem
;
7719 if(isW
) bResult
= ListView_SetItemW(hwnd
, &lvItem
);
7720 else bResult
= ListView_SetItemA(hwnd
, &lvItem
);
7728 * Set item index that marks the start of a multiple selection.
7731 * [I] HWND : window handle
7735 * Index number or -1 if there is no selection mark.
7737 static LRESULT
LISTVIEW_SetSelectionMark(HWND hwnd
, INT nIndex
)
7739 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
7740 INT nOldIndex
= infoPtr
->nSelectionMark
;
7742 TRACE("(hwnd=%x, nIndex=%d)\n", hwnd
, nIndex
);
7744 infoPtr
->nSelectionMark
= nIndex
;
7751 * Sets the text background color.
7754 * [I] HWND : window handle
7755 * [I] COLORREF : text background color
7761 static LRESULT
LISTVIEW_SetTextBkColor(HWND hwnd
, COLORREF clrTextBk
)
7763 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
7765 TRACE("(hwnd=%x, clrTextBk=%lx)\n", hwnd
, clrTextBk
);
7767 infoPtr
->clrTextBk
= clrTextBk
;
7768 InvalidateRect(hwnd
, NULL
, TRUE
);
7775 * Sets the text foreground color.
7778 * [I] HWND : window handle
7779 * [I] COLORREF : text color
7785 static LRESULT
LISTVIEW_SetTextColor (HWND hwnd
, COLORREF clrText
)
7787 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
7789 TRACE("(hwnd=%x, clrText=%lx)\n", hwnd
, clrText
);
7791 infoPtr
->clrText
= clrText
;
7792 InvalidateRect(hwnd
, NULL
, TRUE
);
7797 /* LISTVIEW_SetToolTips */
7798 /* LISTVIEW_SetUnicodeFormat */
7799 /* LISTVIEW_SetWorkAreas */
7803 * Callback internally used by LISTVIEW_SortItems()
7806 * [I] LPVOID : first LISTVIEW_ITEM to compare
7807 * [I] LPVOID : second LISTVIEW_ITEM to compare
7808 * [I] LPARAM : HWND of control
7811 * if first comes before second : negative
7812 * if first comes after second : positive
7813 * if first and second are equivalent : zero
7815 static INT WINAPI
LISTVIEW_CallBackCompare(LPVOID first
, LPVOID second
, LPARAM lParam
)
7817 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW((HWND
)lParam
, 0);
7818 LISTVIEW_ITEM
* lv_first
= (LISTVIEW_ITEM
*) DPA_GetPtr( (HDPA
)first
, 0 );
7819 LISTVIEW_ITEM
* lv_second
= (LISTVIEW_ITEM
*) DPA_GetPtr( (HDPA
)second
, 0 );
7821 /* Forward the call to the client defined callback */
7822 return (infoPtr
->pfnCompare
)( lv_first
->lParam
, lv_second
->lParam
, infoPtr
->lParamSort
);
7827 * Sorts the listview items.
7830 * [I] HWND : window handle
7831 * [I] WPARAM : application-defined value
7832 * [I] LPARAM : pointer to comparision callback
7838 static LRESULT
LISTVIEW_SortItems(HWND hwnd
, PFNLVCOMPARE pfnCompare
, LPARAM lParamSort
)
7840 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
7841 UINT lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
7842 HDPA hdpaSubItems
=NULL
;
7843 LISTVIEW_ITEM
*pLVItem
=NULL
;
7844 LPVOID selectionMarkItem
;
7847 TRACE("(hwnd=%x, pfnCompare=%p, lParamSort=%lx)\n", hwnd
, pfnCompare
, lParamSort
);
7849 if (lStyle
& LVS_OWNERDATA
) return FALSE
;
7851 if (!infoPtr
|| !infoPtr
->hdpaItems
) return FALSE
;
7853 nCount
= GETITEMCOUNT(infoPtr
);
7854 /* if there are 0 or 1 items, there is no need to sort */
7858 infoPtr
->pfnCompare
= pfnCompare
;
7859 infoPtr
->lParamSort
= lParamSort
;
7860 DPA_Sort(infoPtr
->hdpaItems
, LISTVIEW_CallBackCompare
, hwnd
);
7862 /* Adjust selections and indices so that they are the way they should
7863 * be after the sort (otherwise, the list items move around, but
7864 * whatever is at the item's previous original position will be
7867 selectionMarkItem
=(infoPtr
->nSelectionMark
>=0)?DPA_GetPtr(infoPtr
->hdpaItems
, infoPtr
->nSelectionMark
):NULL
;
7868 for (i
=0; i
< nCount
; i
++)
7870 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, i
);
7871 pLVItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
7873 if (pLVItem
->state
& LVIS_SELECTED
)
7874 LISTVIEW_AddSelectionRange(hwnd
, i
, i
);
7876 LISTVIEW_RemoveSelectionRange(hwnd
, i
, i
);
7877 if (pLVItem
->state
& LVIS_FOCUSED
)
7878 infoPtr
->nFocusedItem
=i
;
7880 if (selectionMarkItem
!= NULL
)
7881 infoPtr
->nSelectionMark
= DPA_GetPtrIndex(infoPtr
->hdpaItems
, selectionMarkItem
);
7882 /* I believe nHotItem should be left alone, see LISTVIEW_ShiftIndices */
7884 /* align the items */
7885 LISTVIEW_AlignTop(hwnd
);
7887 /* refresh the display */
7888 InvalidateRect(hwnd
, NULL
, TRUE
);
7893 /* LISTVIEW_SubItemHitTest */
7897 * Updates an items or rearranges the listview control.
7900 * [I] HWND : window handle
7901 * [I] INT : item index
7907 static LRESULT
LISTVIEW_Update(HWND hwnd
, INT nItem
)
7909 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
7910 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
7911 BOOL bResult
= FALSE
;
7914 TRACE("(hwnd=%x, nItem=%d)\n", hwnd
, nItem
);
7916 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
7920 /* rearrange with default alignment style */
7921 if ((lStyle
& LVS_AUTOARRANGE
) && (((lStyle
& LVS_TYPEMASK
) == LVS_ICON
) ||
7922 ((lStyle
& LVS_TYPEMASK
) == LVS_SMALLICON
)))
7924 ListView_Arrange(hwnd
, 0);
7928 /* get item bounding rectangle */
7929 ListView_GetItemRect(hwnd
, nItem
, &rc
, LVIR_BOUNDS
);
7930 InvalidateRect(hwnd
, &rc
, TRUE
);
7939 * Creates the listview control.
7942 * [I] HWND : window handle
7947 static LRESULT
LISTVIEW_Create(HWND hwnd
, LPCREATESTRUCTW lpcs
)
7949 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
7950 UINT uView
= lpcs
->style
& LVS_TYPEMASK
;
7953 TRACE("(hwnd=%x, lpcs=%p)\n", hwnd
, lpcs
);
7955 /* initialize info pointer */
7956 ZeroMemory(infoPtr
, sizeof(LISTVIEW_INFO
));
7958 /* determine the type of structures to use */
7959 infoPtr
->notifyFormat
= SendMessageW(GetParent(hwnd
), WM_NOTIFYFORMAT
,
7960 (WPARAM
)hwnd
, (LPARAM
)NF_QUERY
);
7962 /* initialize color information */
7963 infoPtr
->clrBk
= GetSysColor(COLOR_WINDOW
);
7964 infoPtr
->clrText
= GetSysColor(COLOR_WINDOWTEXT
);
7965 infoPtr
->clrTextBk
= CLR_DEFAULT
;
7967 /* set default values */
7968 infoPtr
->hwndSelf
= hwnd
;
7969 infoPtr
->uCallbackMask
= 0;
7970 infoPtr
->nFocusedItem
= -1;
7971 infoPtr
->nSelectionMark
= -1;
7972 infoPtr
->nHotItem
= -1;
7973 infoPtr
->iconSpacing
.cx
= GetSystemMetrics(SM_CXICONSPACING
);
7974 infoPtr
->iconSpacing
.cy
= GetSystemMetrics(SM_CYICONSPACING
);
7975 ZeroMemory(&infoPtr
->rcList
, sizeof(RECT
));
7976 infoPtr
->hwndEdit
= 0;
7977 infoPtr
->pedititem
= NULL
;
7978 infoPtr
->nEditLabelItem
= -1;
7980 /* get default font (icon title) */
7981 SystemParametersInfoW(SPI_GETICONTITLELOGFONT
, 0, &logFont
, 0);
7982 infoPtr
->hDefaultFont
= CreateFontIndirectW(&logFont
);
7983 infoPtr
->hFont
= infoPtr
->hDefaultFont
;
7984 LISTVIEW_SaveTextMetrics(hwnd
);
7987 infoPtr
->hwndHeader
= CreateWindowW(WC_HEADERW
, (LPCWSTR
)NULL
,
7988 WS_CHILD
| HDS_HORZ
| HDS_BUTTONS
,
7989 0, 0, 0, 0, hwnd
, (HMENU
)0,
7990 lpcs
->hInstance
, NULL
);
7992 /* set header font */
7993 SendMessageW(infoPtr
->hwndHeader
, WM_SETFONT
, (WPARAM
)infoPtr
->hFont
,
7996 if (uView
== LVS_ICON
)
7998 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXICON
);
7999 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYICON
);
8001 else if (uView
== LVS_REPORT
)
8003 if (!(LVS_NOCOLUMNHEADER
& lpcs
->style
))
8005 ShowWindow(infoPtr
->hwndHeader
, SW_SHOWNORMAL
);
8009 /* set HDS_HIDDEN flag to hide the header bar */
8010 SetWindowLongW(infoPtr
->hwndHeader
, GWL_STYLE
,
8011 GetWindowLongW(infoPtr
->hwndHeader
, GWL_STYLE
) | HDS_HIDDEN
);
8015 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
8016 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
8020 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
8021 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
8024 /* display unsupported listview window styles */
8025 LISTVIEW_UnsupportedStyles(lpcs
->style
);
8027 /* allocate memory for the data structure */
8028 infoPtr
->hdpaItems
= DPA_Create(10);
8030 /* allocate memory for the selection ranges */
8031 infoPtr
->hdpaSelectionRanges
= DPA_Create(10);
8033 /* initialize size of items */
8034 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
8035 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(hwnd
);
8037 /* initialize the hover time to -1(indicating the default system hover time) */
8038 infoPtr
->dwHoverTime
= -1;
8045 * Erases the background of the listview control.
8048 * [I] HWND : window handle
8049 * [I] WPARAM : device context handle
8050 * [I] LPARAM : not used
8056 static LRESULT
LISTVIEW_EraseBackground(HWND hwnd
, WPARAM wParam
,
8059 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
8062 TRACE("(hwnd=%x, wParam=%x, lParam=%lx)\n", hwnd
, wParam
, lParam
);
8064 if (infoPtr
->clrBk
== CLR_NONE
)
8066 bResult
= SendMessageW(GetParent(hwnd
), WM_ERASEBKGND
, wParam
, lParam
);
8071 HBRUSH hBrush
= CreateSolidBrush(infoPtr
->clrBk
);
8072 GetClientRect(hwnd
, &rc
);
8073 FillRect((HDC
)wParam
, &rc
, hBrush
);
8074 DeleteObject(hBrush
);
8082 static void LISTVIEW_FillBackground(HWND hwnd
, HDC hdc
, LPRECT rc
)
8084 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
8086 TRACE("(hwnd=%x, hdc=%x, rc=%p)\n", hwnd
, hdc
, rc
);
8088 if (infoPtr
->clrBk
!= CLR_NONE
)
8090 HBRUSH hBrush
= CreateSolidBrush(infoPtr
->clrBk
);
8091 FillRect(hdc
, rc
, hBrush
);
8092 DeleteObject(hBrush
);
8098 * Retrieves the listview control font.
8101 * [I] HWND : window handle
8106 static LRESULT
LISTVIEW_GetFont(HWND hwnd
)
8108 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
8110 TRACE("(hwnd=%x)\n", hwnd
);
8112 return infoPtr
->hFont
;
8117 * Performs vertical scrolling.
8120 * [I] HWND : window handle
8121 * [I] INT : scroll code
8122 * [I] SHORT : current scroll position if scroll code is SB_THUMBPOSITION
8124 * [I] HWND : scrollbar control window handle
8129 static LRESULT
LISTVIEW_VScroll(HWND hwnd
, INT nScrollCode
, SHORT nCurrentPos
,
8132 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
8133 SCROLLINFO scrollInfo
;
8135 TRACE("(hwnd=%x, nScrollCode=%d, nCurrentPos=%d, hScrollWnd=%x)\n",
8136 hwnd
, nScrollCode
, nCurrentPos
, hScrollWnd
);
8138 SendMessageW(infoPtr
->hwndEdit
, WM_KILLFOCUS
, 0, 0);
8140 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
8141 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
8142 scrollInfo
.fMask
= SIF_PAGE
| SIF_POS
| SIF_RANGE
;
8144 if (GetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
) != FALSE
)
8146 INT nOldScrollPos
= scrollInfo
.nPos
;
8147 switch (nScrollCode
)
8150 if (scrollInfo
.nPos
> scrollInfo
.nMin
)
8155 if (scrollInfo
.nPos
< scrollInfo
.nMax
)
8160 if (scrollInfo
.nPos
> scrollInfo
.nMin
)
8162 if (scrollInfo
.nPos
>= scrollInfo
.nPage
)
8163 scrollInfo
.nPos
-= scrollInfo
.nPage
;
8165 scrollInfo
.nPos
= scrollInfo
.nMin
;
8170 if (scrollInfo
.nPos
< scrollInfo
.nMax
)
8172 if (scrollInfo
.nPos
<= scrollInfo
.nMax
- scrollInfo
.nPage
)
8173 scrollInfo
.nPos
+= scrollInfo
.nPage
;
8175 scrollInfo
.nPos
= scrollInfo
.nMax
;
8179 case SB_THUMBPOSITION
:
8181 scrollInfo
.nPos
= nCurrentPos
;
8182 if (scrollInfo
.nPos
> scrollInfo
.nMax
)
8183 scrollInfo
.nPos
=scrollInfo
.nMax
;
8185 if (scrollInfo
.nPos
< scrollInfo
.nMin
)
8186 scrollInfo
.nPos
=scrollInfo
.nMin
;
8191 if (nOldScrollPos
!= scrollInfo
.nPos
)
8193 scrollInfo
.fMask
= SIF_POS
;
8194 SetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
, TRUE
);
8195 if (IsWindowVisible(infoPtr
->hwndHeader
))
8197 RECT rListview
, rcHeader
, rDest
;
8198 GetClientRect(hwnd
, &rListview
);
8199 GetWindowRect(infoPtr
->hwndHeader
, &rcHeader
);
8200 MapWindowPoints((HWND
) NULL
, hwnd
, (LPPOINT
) &rcHeader
, 2);
8201 SubtractRect(&rDest
, &rListview
, &rcHeader
);
8202 InvalidateRect(hwnd
, &rDest
, TRUE
);
8205 InvalidateRect(hwnd
, NULL
, TRUE
);
8214 * Performs horizontal scrolling.
8217 * [I] HWND : window handle
8218 * [I] INT : scroll code
8219 * [I] SHORT : current scroll position if scroll code is SB_THUMBPOSITION
8221 * [I] HWND : scrollbar control window handle
8226 static LRESULT
LISTVIEW_HScroll(HWND hwnd
, INT nScrollCode
, SHORT nCurrentPos
,
8229 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
8230 SCROLLINFO scrollInfo
;
8232 TRACE("(hwnd=%x, nScrollCode=%d, nCurrentPos=%d, hScrollWnd=%x)\n",
8233 hwnd
, nScrollCode
, nCurrentPos
, hScrollWnd
);
8235 SendMessageW(infoPtr
->hwndEdit
, WM_KILLFOCUS
, 0, 0);
8237 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
8238 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
8239 scrollInfo
.fMask
= SIF_PAGE
| SIF_POS
| SIF_RANGE
;
8241 if (GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
) != FALSE
)
8243 INT nOldScrollPos
= scrollInfo
.nPos
;
8245 switch (nScrollCode
)
8248 if (scrollInfo
.nPos
> scrollInfo
.nMin
)
8253 if (scrollInfo
.nPos
< scrollInfo
.nMax
)
8258 if (scrollInfo
.nPos
> scrollInfo
.nMin
)
8260 if (scrollInfo
.nPos
>= scrollInfo
.nPage
)
8261 scrollInfo
.nPos
-= scrollInfo
.nPage
;
8263 scrollInfo
.nPos
= scrollInfo
.nMin
;
8268 if (scrollInfo
.nPos
< scrollInfo
.nMax
)
8270 if (scrollInfo
.nPos
<= scrollInfo
.nMax
- scrollInfo
.nPage
)
8271 scrollInfo
.nPos
+= scrollInfo
.nPage
;
8273 scrollInfo
.nPos
= scrollInfo
.nMax
;
8277 case SB_THUMBPOSITION
:
8279 scrollInfo
.nPos
= nCurrentPos
;
8281 if (scrollInfo
.nPos
> scrollInfo
.nMax
)
8282 scrollInfo
.nPos
=scrollInfo
.nMax
;
8284 if (scrollInfo
.nPos
< scrollInfo
.nMin
)
8285 scrollInfo
.nPos
=scrollInfo
.nMin
;
8289 if (nOldScrollPos
!= scrollInfo
.nPos
)
8291 UINT uView
= GetWindowLongW(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
8292 scrollInfo
.fMask
= SIF_POS
;
8293 SetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
, TRUE
);
8294 if(uView
== LVS_REPORT
)
8296 scrollInfo
.fMask
= SIF_POS
;
8297 GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
);
8298 LISTVIEW_UpdateHeaderSize(hwnd
, scrollInfo
.nPos
);
8300 InvalidateRect(hwnd
, NULL
, TRUE
);
8307 static LRESULT
LISTVIEW_MouseWheel(HWND hwnd
, INT wheelDelta
)
8309 UINT uView
= GetWindowLongW(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
8310 INT gcWheelDelta
= 0;
8311 UINT pulScrollLines
= 3;
8312 SCROLLINFO scrollInfo
;
8314 TRACE("(hwnd=%x, wheelDelta=%d)\n", hwnd
, wheelDelta
);
8316 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES
,0, &pulScrollLines
, 0);
8317 gcWheelDelta
-= wheelDelta
;
8319 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
8320 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
8321 scrollInfo
.fMask
= SIF_POS
| SIF_RANGE
;
8328 * listview should be scrolled by a multiple of 37 dependently on its dimension or its visible item number
8329 * should be fixed in the future.
8331 if (GetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
) != FALSE
)
8332 LISTVIEW_VScroll(hwnd
, SB_THUMBPOSITION
, scrollInfo
.nPos
+ (gcWheelDelta
< 0) ? 37 : -37, 0);
8336 if (abs(gcWheelDelta
) >= WHEEL_DELTA
&& pulScrollLines
)
8338 if (GetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
) != FALSE
)
8340 int cLineScroll
= min(LISTVIEW_GetCountPerColumn(hwnd
), pulScrollLines
);
8341 cLineScroll
*= (gcWheelDelta
/ WHEEL_DELTA
);
8342 LISTVIEW_VScroll(hwnd
, SB_THUMBPOSITION
, scrollInfo
.nPos
+ cLineScroll
, 0);
8348 LISTVIEW_HScroll(hwnd
, (gcWheelDelta
< 0) ? SB_LINELEFT
: SB_LINERIGHT
, 0, 0);
8359 * [I] HWND : window handle
8360 * [I] INT : virtual key
8361 * [I] LONG : key data
8366 static LRESULT
LISTVIEW_KeyDown(HWND hwnd
, INT nVirtualKey
, LONG lKeyData
)
8368 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
8369 UINT uView
= GetWindowLongW(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
8371 NMLVKEYDOWN nmKeyDown
;
8373 TRACE("(hwnd=%x, nVirtualKey=%d, lKeyData=%ld)\n", hwnd
, nVirtualKey
, lKeyData
);
8375 /* send LVN_KEYDOWN notification */
8376 nmKeyDown
.wVKey
= nVirtualKey
;
8377 nmKeyDown
.flags
= 0;
8378 notify(hwnd
, LVN_KEYDOWN
, &nmKeyDown
.hdr
);
8380 switch (nVirtualKey
)
8383 if ((GETITEMCOUNT(infoPtr
) > 0) && (infoPtr
->nFocusedItem
!= -1))
8385 hdr_notify(hwnd
, NM_RETURN
); /* NM_RETURN notification */
8386 hdr_notify(hwnd
, LVN_ITEMACTIVATE
); /* LVN_ITEMACTIVATE notification */
8391 if (GETITEMCOUNT(infoPtr
) > 0)
8396 if (GETITEMCOUNT(infoPtr
) > 0)
8397 nItem
= GETITEMCOUNT(infoPtr
) - 1;
8401 nItem
= ListView_GetNextItem(hwnd
, infoPtr
->nFocusedItem
, LVNI_TOLEFT
);
8405 nItem
= ListView_GetNextItem(hwnd
, infoPtr
->nFocusedItem
, LVNI_ABOVE
);
8409 nItem
= ListView_GetNextItem(hwnd
, infoPtr
->nFocusedItem
, LVNI_TORIGHT
);
8413 nItem
= ListView_GetNextItem(hwnd
, infoPtr
->nFocusedItem
, LVNI_BELOW
);
8417 if (uView
== LVS_REPORT
)
8418 nItem
= infoPtr
->nFocusedItem
- LISTVIEW_GetCountPerColumn(hwnd
);
8420 nItem
= infoPtr
->nFocusedItem
- LISTVIEW_GetCountPerColumn(hwnd
)
8421 * LISTVIEW_GetCountPerRow(hwnd
);
8422 if(nItem
< 0) nItem
= 0;
8426 if (uView
== LVS_REPORT
)
8427 nItem
= infoPtr
->nFocusedItem
+ LISTVIEW_GetCountPerColumn(hwnd
);
8429 nItem
= infoPtr
->nFocusedItem
+ LISTVIEW_GetCountPerColumn(hwnd
)
8430 * LISTVIEW_GetCountPerRow(hwnd
);
8431 if(nItem
>= GETITEMCOUNT(infoPtr
)) nItem
= GETITEMCOUNT(infoPtr
) - 1;
8435 if ((nItem
!= -1) && (nItem
!= infoPtr
->nFocusedItem
))
8437 if (LISTVIEW_KeySelection(hwnd
, nItem
))
8438 UpdateWindow(hwnd
); /* update client area */
8449 * [I] HWND : window handle
8454 static LRESULT
LISTVIEW_KillFocus(HWND hwnd
)
8456 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
8457 UINT uView
= GetWindowLongW(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
8460 TRACE("(hwnd=%x)\n", hwnd
);
8462 /* send NM_KILLFOCUS notification */
8463 hdr_notify(hwnd
, NM_KILLFOCUS
);
8465 /* set window focus flag */
8466 infoPtr
->bFocus
= FALSE
;
8468 /* NEED drawing optimization ; redraw the selected items */
8469 if (uView
& LVS_REPORT
)
8471 nTop
= LISTVIEW_GetTopIndex(hwnd
);
8473 LISTVIEW_GetCountPerColumn(hwnd
) + 1;
8478 nBottom
= GETITEMCOUNT(infoPtr
);
8480 for (i
= nTop
; i
<nBottom
; i
++)
8482 if (LISTVIEW_IsSelected(hwnd
,i
))
8485 rcItem
.left
= LVIR_BOUNDS
;
8486 LISTVIEW_GetItemRect(hwnd
, i
, &rcItem
);
8487 InvalidateRect(hwnd
, &rcItem
, FALSE
);
8496 * Processes double click messages (left mouse button).
8499 * [I] HWND : window handle
8500 * [I] WORD : key flag
8501 * [I] WORD : x coordinate
8502 * [I] WORD : y coordinate
8507 static LRESULT
LISTVIEW_LButtonDblClk(HWND hwnd
, WORD wKey
, WORD wPosX
,
8510 LVHITTESTINFO htInfo
;
8513 TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd
, wKey
, wPosX
, wPosY
);
8515 htInfo
.pt
.x
= wPosX
;
8516 htInfo
.pt
.y
= wPosY
;
8518 /* send NM_DBLCLK notification */
8519 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
8520 if (LISTVIEW_HitTestItem(hwnd
, &htInfo
, TRUE
) != -1)
8522 nmlv
.iItem
= htInfo
.iItem
;
8523 nmlv
.iSubItem
= htInfo
.iSubItem
;
8530 nmlv
.ptAction
.x
= wPosX
;
8531 nmlv
.ptAction
.y
= wPosY
;
8532 listview_notify(hwnd
, NM_DBLCLK
, &nmlv
);
8535 /* To send the LVN_ITEMACTIVATE, it must be on an Item */
8536 if(nmlv
.iItem
!= -1)
8537 hdr_notify(hwnd
, LVN_ITEMACTIVATE
);
8544 * Processes mouse down messages (left mouse button).
8547 * [I] HWND : window handle
8548 * [I] WORD : key flag
8549 * [I] WORD : x coordinate
8550 * [I] WORD : y coordinate
8555 static LRESULT
LISTVIEW_LButtonDown(HWND hwnd
, WORD wKey
, WORD wPosX
,
8558 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
8559 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
8560 static BOOL bGroupSelect
= TRUE
;
8564 TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd
, wKey
, wPosX
, wPosY
);
8566 /* send NM_RELEASEDCAPTURE notification */
8567 hdr_notify(hwnd
, NM_RELEASEDCAPTURE
);
8569 if (infoPtr
->bFocus
== FALSE
)
8572 /* set left button down flag */
8573 infoPtr
->bLButtonDown
= TRUE
;
8575 ptPosition
.x
= wPosX
;
8576 ptPosition
.y
= wPosY
;
8577 nItem
= LISTVIEW_MouseSelection(hwnd
, ptPosition
);
8578 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
8580 if (lStyle
& LVS_SINGLESEL
)
8582 if ((ListView_GetItemState(hwnd
, nItem
, LVIS_SELECTED
) & LVIS_SELECTED
)
8583 && infoPtr
->nEditLabelItem
== -1)
8584 infoPtr
->nEditLabelItem
= nItem
;
8586 LISTVIEW_SetSelection(hwnd
, nItem
);
8590 if ((wKey
& MK_CONTROL
) && (wKey
& MK_SHIFT
))
8593 LISTVIEW_AddGroupSelection(hwnd
, nItem
);
8595 LISTVIEW_AddSelection(hwnd
, nItem
);
8597 else if (wKey
& MK_CONTROL
)
8599 bGroupSelect
= LISTVIEW_ToggleSelection(hwnd
, nItem
);
8601 else if (wKey
& MK_SHIFT
)
8603 LISTVIEW_SetGroupSelection(hwnd
, nItem
);
8608 (ListView_GetItemState(hwnd
, nItem
, LVIS_SELECTED
) & LVIS_SELECTED
);
8610 /* set selection (clears other pre-existing selections) */
8611 LISTVIEW_SetSelection(hwnd
, nItem
);
8613 if (was_selected
&& infoPtr
->nEditLabelItem
== -1)
8614 infoPtr
->nEditLabelItem
= nItem
;
8620 /* remove all selections */
8621 LISTVIEW_RemoveAllSelections(hwnd
);
8624 /* redraw if we could have possibly selected something */
8625 if(!GETITEMCOUNT(infoPtr
)) InvalidateRect(hwnd
, NULL
, TRUE
);
8632 * Processes mouse up messages (left mouse button).
8635 * [I] HWND : window handle
8636 * [I] WORD : key flag
8637 * [I] WORD : x coordinate
8638 * [I] WORD : y coordinate
8643 static LRESULT
LISTVIEW_LButtonUp(HWND hwnd
, WORD wKey
, WORD wPosX
,
8646 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
8648 TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd
, wKey
, wPosX
, wPosY
);
8650 if (infoPtr
->bLButtonDown
!= FALSE
)
8652 LVHITTESTINFO lvHitTestInfo
;
8655 lvHitTestInfo
.pt
.x
= wPosX
;
8656 lvHitTestInfo
.pt
.y
= wPosY
;
8658 /* send NM_CLICK notification */
8659 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
8660 if (LISTVIEW_HitTestItem(hwnd
, &lvHitTestInfo
, TRUE
) != -1)
8662 nmlv
.iItem
= lvHitTestInfo
.iItem
;
8663 nmlv
.iSubItem
= lvHitTestInfo
.iSubItem
;
8670 nmlv
.ptAction
.x
= wPosX
;
8671 nmlv
.ptAction
.y
= wPosY
;
8672 listview_notify(hwnd
, NM_CLICK
, &nmlv
);
8674 /* set left button flag */
8675 infoPtr
->bLButtonDown
= FALSE
;
8677 if(infoPtr
->nEditLabelItem
!= -1)
8679 if(lvHitTestInfo
.iItem
== infoPtr
->nEditLabelItem
)
8680 LISTVIEW_EditLabelT(hwnd
, lvHitTestInfo
.iItem
, TRUE
);
8681 infoPtr
->nEditLabelItem
= -1;
8690 * Creates the listview control (called before WM_CREATE).
8693 * [I] HWND : window handle
8694 * [I] WPARAM : unhandled
8695 * [I] LPARAM : widow creation info
8700 static LRESULT
LISTVIEW_NCCreate(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
8702 LISTVIEW_INFO
*infoPtr
;
8704 TRACE("(hwnd=%x, wParam=%x, lParam=%lx)\n", hwnd
, wParam
, lParam
);
8706 /* allocate memory for info structure */
8707 infoPtr
= (LISTVIEW_INFO
*)COMCTL32_Alloc(sizeof(LISTVIEW_INFO
));
8708 if (infoPtr
== NULL
)
8710 ERR("could not allocate info memory!\n");
8714 SetWindowLongW(hwnd
, 0, (LONG
)infoPtr
);
8715 if ((LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0) != infoPtr
)
8717 ERR("pointer assignment error!\n");
8721 return DefWindowProcW(hwnd
, WM_NCCREATE
, wParam
, lParam
);
8726 * Destroys the listview control (called after WM_DESTROY).
8729 * [I] HWND : window handle
8734 static LRESULT
LISTVIEW_NCDestroy(HWND hwnd
)
8736 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
8738 TRACE("(hwnd=%x)\n", hwnd
);
8740 /* delete all items */
8741 LISTVIEW_DeleteAllItems(hwnd
);
8743 /* destroy data structure */
8744 DPA_Destroy(infoPtr
->hdpaItems
);
8745 DPA_Destroy(infoPtr
->hdpaSelectionRanges
);
8748 infoPtr
->hFont
= (HFONT
)0;
8749 if (infoPtr
->hDefaultFont
)
8751 DeleteObject(infoPtr
->hDefaultFont
);
8754 /* free listview info pointer*/
8755 COMCTL32_Free(infoPtr
);
8757 SetWindowLongW(hwnd
, 0, 0);
8763 * Handles notifications from children.
8766 * [I] HWND : window handle
8767 * [I] INT : control identifier
8768 * [I] LPNMHDR : notification information
8773 static LRESULT
LISTVIEW_Notify(HWND hwnd
, INT nCtrlId
, LPNMHDR lpnmh
)
8775 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
8777 TRACE("(hwnd=%x, nCtrlId=%d, lpnmh=%p)\n", hwnd
, nCtrlId
, lpnmh
);
8779 if (lpnmh
->hwndFrom
== infoPtr
->hwndHeader
)
8781 /* handle notification from header control */
8782 if (lpnmh
->code
== HDN_ENDTRACKW
)
8784 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
8785 InvalidateRect(hwnd
, NULL
, TRUE
);
8787 else if(lpnmh
->code
== HDN_ITEMCLICKW
)
8789 /* Handle sorting by Header Column */
8792 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
8794 nmlv
.iSubItem
= ((LPNMHEADERW
)lpnmh
)->iItem
;
8795 listview_notify(hwnd
, LVN_COLUMNCLICK
, &nmlv
);
8797 else if(lpnmh
->code
== NM_RELEASEDCAPTURE
)
8799 /* Idealy this should be done in HDN_ENDTRACKA
8800 * but since SetItemBounds in Header.c is called after
8801 * the notification is sent, it is neccessary to handle the
8802 * update of the scroll bar here (Header.c works fine as it is,
8803 * no need to disturb it)
8805 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
8806 LISTVIEW_UpdateScroll(hwnd
);
8807 InvalidateRect(hwnd
, NULL
, TRUE
);
8817 * Determines the type of structure to use.
8820 * [I] HWND : window handle of the sender
8821 * [I] HWND : listview window handle
8822 * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
8827 static LRESULT
LISTVIEW_NotifyFormat(HWND hwndFrom
, HWND hwnd
, INT nCommand
)
8829 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
8831 TRACE("(hwndFrom=%x, hwnd=%x, nCommand=%d)\n", hwndFrom
, hwnd
, nCommand
);
8833 if (nCommand
== NF_REQUERY
)
8834 infoPtr
->notifyFormat
= SendMessageW(hwndFrom
, WM_NOTIFYFORMAT
,
8835 (WPARAM
)hwnd
, (LPARAM
)NF_QUERY
);
8841 * Paints/Repaints the listview control.
8844 * [I] HWND : window handle
8845 * [I] HDC : device context handle
8850 static LRESULT
LISTVIEW_Paint(HWND hwnd
, HDC hdc
)
8854 TRACE("(hwnd=%x, hdc=%x)\n", hwnd
, hdc
);
8858 hdc
= BeginPaint(hwnd
, &ps
);
8859 LISTVIEW_Refresh(hwnd
, hdc
);
8860 EndPaint(hwnd
, &ps
);
8864 LISTVIEW_Refresh(hwnd
, hdc
);
8872 * Processes double click messages (right mouse button).
8875 * [I] HWND : window handle
8876 * [I] WORD : key flag
8877 * [I] WORD : x coordinate
8878 * [I] WORD : y coordinate
8883 static LRESULT
LISTVIEW_RButtonDblClk(HWND hwnd
, WORD wKey
, WORD wPosX
,
8886 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd
, wKey
, wPosX
, wPosY
);
8888 /* send NM_RELEASEDCAPTURE notification */
8889 hdr_notify(hwnd
, NM_RELEASEDCAPTURE
);
8891 /* send NM_RDBLCLK notification */
8892 hdr_notify(hwnd
, NM_RDBLCLK
);
8899 * Processes mouse down messages (right mouse button).
8902 * [I] HWND : window handle
8903 * [I] WORD : key flag
8904 * [I] WORD : x coordinate
8905 * [I] WORD : y coordinate
8910 static LRESULT
LISTVIEW_RButtonDown(HWND hwnd
, WORD wKey
, WORD wPosX
,
8913 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
8917 LVHITTESTINFO lvHitTestInfo
;
8919 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd
, wKey
, wPosX
, wPosY
);
8921 /* send NM_RELEASEDCAPTURE notification */
8922 hdr_notify(hwnd
, NM_RELEASEDCAPTURE
);
8924 /* make sure the listview control window has the focus */
8925 if (infoPtr
->bFocus
== FALSE
)
8928 /* set right button down flag */
8929 infoPtr
->bRButtonDown
= TRUE
;
8931 /* determine the index of the selected item */
8932 ptPosition
.x
= wPosX
;
8933 ptPosition
.y
= wPosY
;
8934 nItem
= LISTVIEW_MouseSelection(hwnd
, ptPosition
);
8935 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
8937 LISTVIEW_SetItemFocus(hwnd
,nItem
);
8938 if (!((wKey
& MK_SHIFT
) || (wKey
& MK_CONTROL
)) &&
8939 !LISTVIEW_IsSelected(hwnd
,nItem
))
8940 LISTVIEW_SetSelection(hwnd
, nItem
);
8944 LISTVIEW_RemoveAllSelections(hwnd
);
8947 lvHitTestInfo
.pt
.x
= wPosX
;
8948 lvHitTestInfo
.pt
.y
= wPosY
;
8950 /* Send NM_RClICK notification */
8951 ZeroMemory(&nmlv
, sizeof(nmlv
));
8952 if (LISTVIEW_HitTestItem(hwnd
, &lvHitTestInfo
, TRUE
) != -1)
8954 nmlv
.iItem
= lvHitTestInfo
.iItem
;
8955 nmlv
.iSubItem
= lvHitTestInfo
.iSubItem
;
8962 nmlv
.ptAction
.x
= wPosX
;
8963 nmlv
.ptAction
.y
= wPosY
;
8964 listview_notify(hwnd
, NM_RCLICK
, &nmlv
);
8971 * Processes mouse up messages (right mouse button).
8974 * [I] HWND : window handle
8975 * [I] WORD : key flag
8976 * [I] WORD : x coordinate
8977 * [I] WORD : y coordinate
8982 static LRESULT
LISTVIEW_RButtonUp(HWND hwnd
, WORD wKey
, WORD wPosX
,
8985 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
8987 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd
, wKey
, wPosX
, wPosY
);
8989 if (infoPtr
->bRButtonDown
)
8996 /* set button flag */
8997 infoPtr
->bRButtonDown
= FALSE
;
8999 /* Change to screen coordinate for WM_CONTEXTMENU */
9000 ClientToScreen(hwnd
, &pt
);
9002 /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
9003 SendMessageW( hwnd
, WM_CONTEXTMENU
, (WPARAM
) hwnd
, MAKELPARAM(pt
.x
, pt
.y
));
9014 * [I] HWND : window handle
9015 * [I] HWND : window handle of previously focused window
9020 static LRESULT
LISTVIEW_SetFocus(HWND hwnd
, HWND hwndLoseFocus
)
9022 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
9024 TRACE("(hwnd=%x, hwndLoseFocus=%x)\n", hwnd
, hwndLoseFocus
);
9026 /* send NM_SETFOCUS notification */
9027 hdr_notify(hwnd
, NM_SETFOCUS
);
9029 /* set window focus flag */
9030 infoPtr
->bFocus
= TRUE
;
9042 * [I] HWND : window handle
9043 * [I] HFONT : font handle
9044 * [I] WORD : redraw flag
9049 static LRESULT
LISTVIEW_SetFont(HWND hwnd
, HFONT hFont
, WORD fRedraw
)
9051 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
9052 UINT uView
= GetWindowLongW(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
9054 TRACE("(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd
, hFont
, fRedraw
);
9056 infoPtr
->hFont
= hFont
? hFont
: infoPtr
->hDefaultFont
;
9057 LISTVIEW_SaveTextMetrics(hwnd
);
9059 if (uView
== LVS_REPORT
)
9061 /* set header font */
9062 SendMessageW(infoPtr
->hwndHeader
, WM_SETFONT
, (WPARAM
)hFont
,
9063 MAKELPARAM(fRedraw
, 0));
9066 /* invalidate listview control client area */
9067 InvalidateRect(hwnd
, NULL
, TRUE
);
9069 if (fRedraw
!= FALSE
)
9077 * Message handling for WM_SETREDRAW.
9078 * For the Listview, it invalidates the entire window (the doc specifies otherwise)
9081 * [I] HWND : window handle
9082 * [I] bRedraw: state of redraw flag
9085 * DefWinProc return value
9087 static LRESULT
LISTVIEW_SetRedraw(HWND hwnd
, BOOL bRedraw
)
9089 LRESULT lResult
= DefWindowProcW(hwnd
, WM_SETREDRAW
, bRedraw
, 0);
9091 RedrawWindow(hwnd
, NULL
, 0,
9092 RDW_INVALIDATE
| RDW_FRAME
| RDW_ERASE
| RDW_ALLCHILDREN
| RDW_ERASENOW
);
9098 * Resizes the listview control. This function processes WM_SIZE
9099 * messages. At this time, the width and height are not used.
9102 * [I] HWND : window handle
9103 * [I] WORD : new width
9104 * [I] WORD : new height
9109 static LRESULT
LISTVIEW_Size(HWND hwnd
, int Width
, int Height
)
9111 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
9112 UINT uView
= lStyle
& LVS_TYPEMASK
;
9114 TRACE("(hwnd=%x, width=%d, height=%d)\n", hwnd
, Width
, Height
);
9116 LISTVIEW_UpdateSize(hwnd
);
9118 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
9120 if (lStyle
& LVS_ALIGNLEFT
)
9121 LISTVIEW_AlignLeft(hwnd
);
9123 LISTVIEW_AlignTop(hwnd
);
9126 LISTVIEW_UpdateScroll(hwnd
);
9128 /* invalidate client area + erase background */
9129 InvalidateRect(hwnd
, NULL
, TRUE
);
9136 * Sets the size information.
9139 * [I] HWND : window handle
9144 static VOID
LISTVIEW_UpdateSize(HWND hwnd
)
9146 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
9147 LONG lStyle
= GetWindowLongW(hwnd
, GWL_STYLE
);
9148 UINT uView
= lStyle
& LVS_TYPEMASK
;
9151 TRACE("(hwnd=%x)\n", hwnd
);
9153 GetClientRect(hwnd
, &rcList
);
9154 infoPtr
->rcList
.left
= 0;
9155 infoPtr
->rcList
.right
= max(rcList
.right
- rcList
.left
, 1);
9156 infoPtr
->rcList
.top
= 0;
9157 infoPtr
->rcList
.bottom
= max(rcList
.bottom
- rcList
.top
, 1);
9159 if (uView
== LVS_LIST
)
9161 if (lStyle
& WS_HSCROLL
)
9163 INT nHScrollHeight
= GetSystemMetrics(SM_CYHSCROLL
);
9164 if (infoPtr
->rcList
.bottom
> nHScrollHeight
)
9165 infoPtr
->rcList
.bottom
-= nHScrollHeight
;
9168 else if (uView
== LVS_REPORT
)
9175 Header_Layout(infoPtr
->hwndHeader
, &hl
);
9177 SetWindowPos(wp
.hwnd
, wp
.hwndInsertAfter
, wp
.x
, wp
.y
, wp
.cx
, wp
.cy
, wp
.flags
);
9179 if (!(LVS_NOCOLUMNHEADER
& lStyle
))
9180 infoPtr
->rcList
.top
= max(wp
.cy
, 0);
9186 * Processes WM_STYLECHANGED messages.
9189 * [I] HWND : window handle
9190 * [I] WPARAM : window style type (normal or extended)
9191 * [I] LPSTYLESTRUCT : window style information
9196 static INT
LISTVIEW_StyleChanged(HWND hwnd
, WPARAM wStyleType
,
9199 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
9200 UINT uNewView
= lpss
->styleNew
& LVS_TYPEMASK
;
9201 UINT uOldView
= lpss
->styleOld
& LVS_TYPEMASK
;
9202 RECT rcList
= infoPtr
->rcList
;
9204 TRACE("(hwnd=%x, styletype=%x, stylestruct=%p)\n",
9205 hwnd
, wStyleType
, lpss
);
9207 if (wStyleType
== GWL_STYLE
)
9209 if (uOldView
== LVS_REPORT
)
9210 ShowWindow(infoPtr
->hwndHeader
, SW_HIDE
);
9212 if ((lpss
->styleOld
& WS_HSCROLL
) != 0)
9213 ShowScrollBar(hwnd
, SB_HORZ
, FALSE
);
9215 if ((lpss
->styleOld
& WS_VSCROLL
) != 0)
9216 ShowScrollBar(hwnd
, SB_VERT
, FALSE
);
9218 if (uNewView
== LVS_ICON
)
9220 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXICON
);
9221 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYICON
);
9222 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
9223 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(hwnd
);
9224 if (lpss
->styleNew
& LVS_ALIGNLEFT
)
9225 LISTVIEW_AlignLeft(hwnd
);
9227 LISTVIEW_AlignTop(hwnd
);
9229 else if (uNewView
== LVS_REPORT
)
9236 Header_Layout(infoPtr
->hwndHeader
, &hl
);
9237 SetWindowPos(infoPtr
->hwndHeader
, hwnd
, wp
.x
, wp
.y
, wp
.cx
, wp
.cy
,
9239 if (!(LVS_NOCOLUMNHEADER
& lpss
->styleNew
))
9240 ShowWindow(infoPtr
->hwndHeader
, SW_SHOWNORMAL
);
9242 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
9243 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
9244 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
9245 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(hwnd
);
9247 else if (uNewView
== LVS_LIST
)
9249 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
9250 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
9251 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
9252 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(hwnd
);
9256 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
9257 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
9258 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
9259 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(hwnd
);
9260 if (lpss
->styleNew
& LVS_ALIGNLEFT
)
9261 LISTVIEW_AlignLeft(hwnd
);
9263 LISTVIEW_AlignTop(hwnd
);
9266 /* update the size of the client area */
9267 LISTVIEW_UpdateSize(hwnd
);
9269 /* add scrollbars if needed */
9270 LISTVIEW_UpdateScroll(hwnd
);
9272 /* invalidate client area + erase background */
9273 InvalidateRect(hwnd
, NULL
, TRUE
);
9275 /* print the list of unsupported window styles */
9276 LISTVIEW_UnsupportedStyles(lpss
->styleNew
);
9279 /* If they change the view and we have an active edit control
9280 we will need to kill the control since the redraw will
9281 misplace the edit control.
9283 if (infoPtr
->hwndEdit
&&
9284 ((uNewView
& (LVS_ICON
|LVS_LIST
|LVS_SMALLICON
)) !=
9285 ((LVS_ICON
|LVS_LIST
|LVS_SMALLICON
) & uOldView
)))
9287 SendMessageW(infoPtr
->hwndEdit
, WM_KILLFOCUS
, 0, 0);
9295 * Window procedure of the listview control.
9298 static LRESULT WINAPI
LISTVIEW_WindowProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
,
9301 TRACE("(hwnd=%x uMsg=%x wParam=%x lParam=%lx)\n", hwnd
, uMsg
, wParam
, lParam
);
9302 if (!GetWindowLongW(hwnd
, 0) && (uMsg
!= WM_NCCREATE
))
9303 return DefWindowProcW( hwnd
, uMsg
, wParam
, lParam
);
9306 case LVM_APPROXIMATEVIEWRECT
:
9307 return LISTVIEW_ApproximateViewRect(hwnd
, (INT
)wParam
,
9308 LOWORD(lParam
), HIWORD(lParam
));
9310 return LISTVIEW_Arrange(hwnd
, (INT
)wParam
);
9312 /* case LVM_CREATEDRAGIMAGE: */
9314 case LVM_DELETEALLITEMS
:
9315 return LISTVIEW_DeleteAllItems(hwnd
);
9317 case LVM_DELETECOLUMN
:
9318 return LISTVIEW_DeleteColumn(hwnd
, (INT
)wParam
);
9320 case LVM_DELETEITEM
:
9321 return LISTVIEW_DeleteItem(hwnd
, (INT
)wParam
);
9323 case LVM_EDITLABELW
:
9324 return LISTVIEW_EditLabelT(hwnd
, (INT
)wParam
, TRUE
);
9326 case LVM_EDITLABELA
:
9327 return LISTVIEW_EditLabelT(hwnd
, (INT
)wParam
, FALSE
);
9329 case LVM_ENSUREVISIBLE
:
9330 return LISTVIEW_EnsureVisible(hwnd
, (INT
)wParam
, (BOOL
)lParam
);
9333 return LISTVIEW_FindItemW(hwnd
, (INT
)wParam
, (LPLVFINDINFOW
)lParam
);
9336 return LISTVIEW_FindItemA(hwnd
, (INT
)wParam
, (LPLVFINDINFOA
)lParam
);
9338 case LVM_GETBKCOLOR
:
9339 return LISTVIEW_GetBkColor(hwnd
);
9341 /* case LVM_GETBKIMAGE: */
9343 case LVM_GETCALLBACKMASK
:
9344 return LISTVIEW_GetCallbackMask(hwnd
);
9346 case LVM_GETCOLUMNA
:
9347 return LISTVIEW_GetColumnT(hwnd
, (INT
)wParam
, (LPLVCOLUMNW
)lParam
, FALSE
);
9349 case LVM_GETCOLUMNW
:
9350 return LISTVIEW_GetColumnT(hwnd
, (INT
)wParam
, (LPLVCOLUMNW
)lParam
, TRUE
);
9352 case LVM_GETCOLUMNORDERARRAY
:
9353 return LISTVIEW_GetColumnOrderArray(hwnd
, (INT
)wParam
, (LPINT
)lParam
);
9355 case LVM_GETCOLUMNWIDTH
:
9356 return LISTVIEW_GetColumnWidth(hwnd
, (INT
)wParam
);
9358 case LVM_GETCOUNTPERPAGE
:
9359 return LISTVIEW_GetCountPerPage(hwnd
);
9361 case LVM_GETEDITCONTROL
:
9362 return LISTVIEW_GetEditControl(hwnd
);
9364 case LVM_GETEXTENDEDLISTVIEWSTYLE
:
9365 return LISTVIEW_GetExtendedListViewStyle(hwnd
);
9368 return LISTVIEW_GetHeader(hwnd
);
9370 case LVM_GETHOTCURSOR
:
9371 FIXME("LVM_GETHOTCURSOR: unimplemented\n");
9374 case LVM_GETHOTITEM
:
9375 return LISTVIEW_GetHotItem(hwnd
);
9377 case LVM_GETHOVERTIME
:
9378 return LISTVIEW_GetHoverTime(hwnd
);
9380 case LVM_GETIMAGELIST
:
9381 return LISTVIEW_GetImageList(hwnd
, (INT
)wParam
);
9383 case LVM_GETISEARCHSTRINGA
:
9384 case LVM_GETISEARCHSTRINGW
:
9385 FIXME("LVM_GETISEARCHSTRING: unimplemented\n");
9389 return LISTVIEW_GetItemT(hwnd
, (LPLVITEMW
)lParam
, FALSE
, FALSE
);
9392 return LISTVIEW_GetItemT(hwnd
, (LPLVITEMW
)lParam
, FALSE
, TRUE
);
9394 case LVM_GETITEMCOUNT
:
9395 return LISTVIEW_GetItemCount(hwnd
);
9397 case LVM_GETITEMPOSITION
:
9398 return LISTVIEW_GetItemPosition(hwnd
, (INT
)wParam
, (LPPOINT
)lParam
);
9400 case LVM_GETITEMRECT
:
9401 return LISTVIEW_GetItemRect(hwnd
, (INT
)wParam
, (LPRECT
)lParam
);
9403 case LVM_GETITEMSPACING
:
9404 return LISTVIEW_GetItemSpacing(hwnd
, (BOOL
)wParam
);
9406 case LVM_GETITEMSTATE
:
9407 return LISTVIEW_GetItemState(hwnd
, (INT
)wParam
, (UINT
)lParam
);
9409 case LVM_GETITEMTEXTA
:
9410 return LISTVIEW_GetItemTextT(hwnd
, (INT
)wParam
, (LPLVITEMW
)lParam
, FALSE
);
9412 case LVM_GETITEMTEXTW
:
9413 return LISTVIEW_GetItemTextT(hwnd
, (INT
)wParam
, (LPLVITEMW
)lParam
, TRUE
);
9415 case LVM_GETNEXTITEM
:
9416 return LISTVIEW_GetNextItem(hwnd
, (INT
)wParam
, LOWORD(lParam
));
9418 case LVM_GETNUMBEROFWORKAREAS
:
9419 FIXME("LVM_GETNUMBEROFWORKAREAS: unimplemented\n");
9423 return LISTVIEW_GetOrigin(hwnd
, (LPPOINT
)lParam
);
9425 case LVM_GETSELECTEDCOUNT
:
9426 return LISTVIEW_GetSelectedCount(hwnd
);
9428 case LVM_GETSELECTIONMARK
:
9429 return LISTVIEW_GetSelectionMark(hwnd
);
9431 case LVM_GETSTRINGWIDTHA
:
9432 return LISTVIEW_GetStringWidthT(hwnd
, (LPCWSTR
)lParam
, FALSE
);
9434 case LVM_GETSTRINGWIDTHW
:
9435 return LISTVIEW_GetStringWidthT(hwnd
, (LPCWSTR
)lParam
, TRUE
);
9437 case LVM_GETSUBITEMRECT
:
9438 FIXME("LVM_GETSUBITEMRECT: unimplemented\n");
9441 case LVM_GETTEXTBKCOLOR
:
9442 return LISTVIEW_GetTextBkColor(hwnd
);
9444 case LVM_GETTEXTCOLOR
:
9445 return LISTVIEW_GetTextColor(hwnd
);
9447 case LVM_GETTOOLTIPS
:
9448 FIXME("LVM_GETTOOLTIPS: unimplemented\n");
9451 case LVM_GETTOPINDEX
:
9452 return LISTVIEW_GetTopIndex(hwnd
);
9454 /*case LVM_GETUNICODEFORMAT:
9455 FIXME("LVM_GETUNICODEFORMAT: unimplemented\n");
9458 case LVM_GETVIEWRECT
:
9459 return LISTVIEW_GetViewRect(hwnd
, (LPRECT
)lParam
);
9461 case LVM_GETWORKAREAS
:
9462 FIXME("LVM_GETWORKAREAS: unimplemented\n");
9466 return LISTVIEW_HitTest(hwnd
, (LPLVHITTESTINFO
)lParam
);
9468 case LVM_INSERTCOLUMNA
:
9469 return LISTVIEW_InsertColumnT(hwnd
, (INT
)wParam
, (LPLVCOLUMNW
)lParam
, FALSE
);
9471 case LVM_INSERTCOLUMNW
:
9472 return LISTVIEW_InsertColumnT(hwnd
, (INT
)wParam
, (LPLVCOLUMNW
)lParam
, TRUE
);
9474 case LVM_INSERTITEMA
:
9475 return LISTVIEW_InsertItemT(hwnd
, (LPLVITEMW
)lParam
, FALSE
);
9477 case LVM_INSERTITEMW
:
9478 return LISTVIEW_InsertItemT(hwnd
, (LPLVITEMW
)lParam
, TRUE
);
9480 case LVM_REDRAWITEMS
:
9481 return LISTVIEW_RedrawItems(hwnd
, (INT
)wParam
, (INT
)lParam
);
9483 /* case LVM_SCROLL: */
9484 /* return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); */
9486 case LVM_SETBKCOLOR
:
9487 return LISTVIEW_SetBkColor(hwnd
, (COLORREF
)lParam
);
9489 /* case LVM_SETBKIMAGE: */
9491 case LVM_SETCALLBACKMASK
:
9492 return LISTVIEW_SetCallbackMask(hwnd
, (UINT
)wParam
);
9494 case LVM_SETCOLUMNA
:
9495 return LISTVIEW_SetColumnT(hwnd
, (INT
)wParam
, (LPLVCOLUMNW
)lParam
, FALSE
);
9497 case LVM_SETCOLUMNW
:
9498 return LISTVIEW_SetColumnT(hwnd
, (INT
)wParam
, (LPLVCOLUMNW
)lParam
, TRUE
);
9500 case LVM_SETCOLUMNORDERARRAY
:
9501 return LISTVIEW_SetColumnOrderArray(hwnd
, (INT
)wParam
, (LPINT
)lParam
);
9503 case LVM_SETCOLUMNWIDTH
:
9504 return LISTVIEW_SetColumnWidth(hwnd
, (INT
)wParam
, SLOWORD(lParam
));
9506 case LVM_SETEXTENDEDLISTVIEWSTYLE
:
9507 return LISTVIEW_SetExtendedListViewStyle(hwnd
, (DWORD
)wParam
, (DWORD
)lParam
);
9509 /* case LVM_SETHOTCURSOR: */
9511 case LVM_SETHOTITEM
:
9512 return LISTVIEW_SetHotItem(hwnd
, (INT
)wParam
);
9514 case LVM_SETHOVERTIME
:
9515 return LISTVIEW_SetHoverTime(hwnd
, (DWORD
)wParam
);
9517 case LVM_SETICONSPACING
:
9518 return LISTVIEW_SetIconSpacing(hwnd
, (DWORD
)lParam
);
9520 case LVM_SETIMAGELIST
:
9521 return (LRESULT
)LISTVIEW_SetImageList(hwnd
, (INT
)wParam
, (HIMAGELIST
)lParam
);
9524 return LISTVIEW_SetItemT(hwnd
, (LPLVITEMW
)lParam
, FALSE
);
9527 return LISTVIEW_SetItemT(hwnd
, (LPLVITEMW
)lParam
, TRUE
);
9529 case LVM_SETITEMCOUNT
:
9530 return LISTVIEW_SetItemCount(hwnd
, (INT
)wParam
, (DWORD
)lParam
);
9532 case LVM_SETITEMPOSITION
:
9533 return LISTVIEW_SetItemPosition(hwnd
, (INT
)wParam
, (INT
)LOWORD(lParam
),
9534 (INT
)HIWORD(lParam
));
9536 case LVM_SETITEMPOSITION32
:
9537 return LISTVIEW_SetItemPosition(hwnd
, (INT
)wParam
, ((POINT
*)lParam
)->x
,
9538 ((POINT
*)lParam
)->y
);
9540 case LVM_SETITEMSTATE
:
9541 return LISTVIEW_SetItemState(hwnd
, (INT
)wParam
, (LPLVITEMW
)lParam
);
9543 case LVM_SETITEMTEXTA
:
9544 return LISTVIEW_SetItemTextT(hwnd
, (INT
)wParam
, (LPLVITEMW
)lParam
, FALSE
);
9546 case LVM_SETITEMTEXTW
:
9547 return LISTVIEW_SetItemTextT(hwnd
, (INT
)wParam
, (LPLVITEMW
)lParam
, TRUE
);
9549 case LVM_SETSELECTIONMARK
:
9550 return LISTVIEW_SetSelectionMark(hwnd
, (INT
)lParam
);
9552 case LVM_SETTEXTBKCOLOR
:
9553 return LISTVIEW_SetTextBkColor(hwnd
, (COLORREF
)lParam
);
9555 case LVM_SETTEXTCOLOR
:
9556 return LISTVIEW_SetTextColor(hwnd
, (COLORREF
)lParam
);
9558 /* case LVM_SETTOOLTIPS: */
9559 /* case LVM_SETUNICODEFORMAT: */
9560 /* case LVM_SETWORKAREAS: */
9563 return LISTVIEW_SortItems(hwnd
, (PFNLVCOMPARE
)lParam
, (LPARAM
)wParam
);
9565 /* case LVM_SUBITEMHITTEST: */
9568 return LISTVIEW_Update(hwnd
, (INT
)wParam
);
9571 return LISTVIEW_ProcessLetterKeys( hwnd
, wParam
, lParam
);
9574 return LISTVIEW_Command(hwnd
, wParam
, lParam
);
9577 return LISTVIEW_Create(hwnd
, (LPCREATESTRUCTW
)lParam
);
9580 return LISTVIEW_EraseBackground(hwnd
, wParam
, lParam
);
9583 return DLGC_WANTCHARS
| DLGC_WANTARROWS
;
9586 return LISTVIEW_GetFont(hwnd
);
9589 return LISTVIEW_HScroll(hwnd
, (INT
)LOWORD(wParam
),
9590 (INT
)HIWORD(wParam
), (HWND
)lParam
);
9593 return LISTVIEW_KeyDown(hwnd
, (INT
)wParam
, (LONG
)lParam
);
9596 return LISTVIEW_KillFocus(hwnd
);
9598 case WM_LBUTTONDBLCLK
:
9599 return LISTVIEW_LButtonDblClk(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
9602 case WM_LBUTTONDOWN
:
9603 return LISTVIEW_LButtonDown(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
9606 return LISTVIEW_LButtonUp(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
9609 return LISTVIEW_MouseMove (hwnd
, wParam
, lParam
);
9612 return LISTVIEW_MouseHover(hwnd
, wParam
, lParam
);
9615 return LISTVIEW_NCCreate(hwnd
, wParam
, lParam
);
9618 return LISTVIEW_NCDestroy(hwnd
);
9621 return LISTVIEW_Notify(hwnd
, (INT
)wParam
, (LPNMHDR
)lParam
);
9623 case WM_NOTIFYFORMAT
:
9624 return LISTVIEW_NotifyFormat(hwnd
, (HWND
)wParam
, (INT
)lParam
);
9627 return LISTVIEW_Paint(hwnd
, (HDC
)wParam
);
9629 case WM_RBUTTONDBLCLK
:
9630 return LISTVIEW_RButtonDblClk(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
9633 case WM_RBUTTONDOWN
:
9634 return LISTVIEW_RButtonDown(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
9638 return LISTVIEW_RButtonUp(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
9642 return LISTVIEW_SetFocus(hwnd
, (HWND
)wParam
);
9645 return LISTVIEW_SetFont(hwnd
, (HFONT
)wParam
, (WORD
)lParam
);
9648 return LISTVIEW_SetRedraw(hwnd
, (BOOL
)wParam
);
9651 return LISTVIEW_Size(hwnd
, (int)SLOWORD(lParam
), (int)SHIWORD(lParam
));
9653 case WM_STYLECHANGED
:
9654 return LISTVIEW_StyleChanged(hwnd
, wParam
, (LPSTYLESTRUCT
)lParam
);
9656 /* case WM_TIMER: */
9659 return LISTVIEW_VScroll(hwnd
, (INT
)LOWORD(wParam
),
9660 (INT
)HIWORD(wParam
), (HWND
)lParam
);
9663 if (wParam
& (MK_SHIFT
| MK_CONTROL
))
9664 return DefWindowProcW( hwnd
, uMsg
, wParam
, lParam
);
9665 return LISTVIEW_MouseWheel(hwnd
, (short int)HIWORD(wParam
));/* case WM_WINDOWPOSCHANGED: */
9667 /* case WM_WININICHANGE: */
9670 if (uMsg
>= WM_USER
)
9672 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg
, wParam
,
9676 /* call default window procedure */
9677 return DefWindowProcW(hwnd
, uMsg
, wParam
, lParam
);
9685 * Registers the window class.
9693 VOID
LISTVIEW_Register(void)
9697 ZeroMemory(&wndClass
, sizeof(WNDCLASSW
));
9698 wndClass
.style
= CS_GLOBALCLASS
| CS_DBLCLKS
;
9699 wndClass
.lpfnWndProc
= (WNDPROC
)LISTVIEW_WindowProc
;
9700 wndClass
.cbClsExtra
= 0;
9701 wndClass
.cbWndExtra
= sizeof(LISTVIEW_INFO
*);
9702 wndClass
.hCursor
= LoadCursorW(0, IDC_ARROWW
);
9703 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
9704 wndClass
.lpszClassName
= WC_LISTVIEWW
;
9705 RegisterClassW(&wndClass
);
9710 * Unregisters the window class.
9718 VOID
LISTVIEW_Unregister(void)
9720 UnregisterClassW(WC_LISTVIEWW
, (HINSTANCE
)NULL
);
9725 * Handle any WM_COMMAND messages
9731 static LRESULT
LISTVIEW_Command(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
9733 switch (HIWORD(wParam
))
9738 * Adjust the edit window size
9741 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(hwnd
, 0);
9742 HDC hdc
= GetDC(infoPtr
->hwndEdit
);
9743 HFONT hFont
, hOldFont
= 0;
9748 len
= GetWindowTextW(infoPtr
->hwndEdit
, buffer
, sizeof(buffer
)/sizeof(buffer
[0]));
9749 GetWindowRect(infoPtr
->hwndEdit
, &rect
);
9751 /* Select font to get the right dimension of the string */
9752 hFont
= SendMessageW(infoPtr
->hwndEdit
, WM_GETFONT
, 0, 0);
9755 hOldFont
= SelectObject(hdc
, hFont
);
9758 if (GetTextExtentPoint32W(hdc
, buffer
, lstrlenW(buffer
), &sz
))
9760 TEXTMETRICW textMetric
;
9762 /* Add Extra spacing for the next character */
9763 GetTextMetricsW(hdc
, &textMetric
);
9764 sz
.cx
+= (textMetric
.tmMaxCharWidth
* 2);
9772 rect
.bottom
- rect
.top
,
9773 SWP_DRAWFRAME
|SWP_NOMOVE
);
9776 SelectObject(hdc
, hOldFont
);
9778 ReleaseDC(hwnd
, hdc
);
9784 return SendMessageW (GetParent (hwnd
), WM_COMMAND
, wParam
, lParam
);
9793 * Subclassed edit control windproc function
9799 static LRESULT
EditLblWndProcT(HWND hwnd
, UINT uMsg
,
9800 WPARAM wParam
, LPARAM lParam
, BOOL isW
)
9802 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(GetParent(hwnd
), 0);
9803 EDITLABEL_ITEM
*einfo
= infoPtr
->pedititem
;
9804 static BOOL bIgnoreKillFocus
= FALSE
;
9805 BOOL cancel
= FALSE
;
9807 TRACE("(hwnd=%x, uMsg=%x, wParam=%x, lParam=%lx, isW=%d)\n",
9808 hwnd
, uMsg
, wParam
, lParam
, isW
);
9813 return DLGC_WANTARROWS
| DLGC_WANTALLKEYS
;
9816 if(bIgnoreKillFocus
) return TRUE
;
9821 WNDPROC editProc
= einfo
->EditWndProc
;
9822 SetWindowLongW(hwnd
, GWL_WNDPROC
, (LONG
)editProc
);
9823 COMCTL32_Free(einfo
);
9824 infoPtr
->pedititem
= NULL
;
9825 return CallWindowProcT(editProc
, hwnd
, uMsg
, wParam
, lParam
, isW
);
9829 if (VK_ESCAPE
== (INT
)wParam
)
9834 else if (VK_RETURN
== (INT
)wParam
)
9838 return CallWindowProcT(einfo
->EditWndProc
, hwnd
, uMsg
, wParam
, lParam
, isW
);
9841 if (einfo
->EditLblCb
)
9843 LPWSTR buffer
= NULL
;
9847 DWORD len
= isW
? GetWindowTextLengthW(hwnd
) : GetWindowTextLengthA(hwnd
);
9851 if ( (buffer
= COMCTL32_Alloc((len
+1) * (isW
? sizeof(WCHAR
) : sizeof(CHAR
)))) )
9853 if (isW
) GetWindowTextW(hwnd
, buffer
, len
+1);
9854 else GetWindowTextA(hwnd
, (CHAR
*)buffer
, len
+1);
9858 /* Processing LVN_ENDLABELEDIT message could kill the focus */
9859 /* eg. Using a messagebox */
9860 bIgnoreKillFocus
= TRUE
;
9861 einfo
->EditLblCb(GetParent(hwnd
), buffer
, einfo
->param
);
9863 if (buffer
) COMCTL32_Free(buffer
);
9865 einfo
->EditLblCb
= NULL
;
9866 bIgnoreKillFocus
= FALSE
;
9869 SendMessageW(hwnd
, WM_CLOSE
, 0, 0);
9875 * Subclassed edit control windproc function
9881 LRESULT CALLBACK
EditLblWndProcW(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
9883 return EditLblWndProcT(hwnd
, uMsg
, wParam
, lParam
, TRUE
);
9888 * Subclassed edit control windproc function
9894 LRESULT CALLBACK
EditLblWndProcA(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
9896 return EditLblWndProcT(hwnd
, uMsg
, wParam
, lParam
, FALSE
);
9901 * Creates a subclassed edit cotrol
9907 HWND
CreateEditLabelT(LPCWSTR text
, DWORD style
, INT x
, INT y
,
9908 INT width
, INT height
, HWND parent
, HINSTANCE hinst
,
9909 EditlblCallbackW EditLblCb
, DWORD param
, BOOL isW
)
9911 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongW(parent
, 0);
9912 WCHAR editName
[5] = { 'E', 'd', 'i', 't', '\0' };
9917 TEXTMETRICW textMetric
;
9919 TRACE("(text=%s, ..., isW=%d)\n", debugstr_t(text
, isW
), isW
);
9921 if (NULL
== (infoPtr
->pedititem
= COMCTL32_Alloc(sizeof(EDITLABEL_ITEM
))))
9924 style
|= WS_CHILDWINDOW
|WS_CLIPSIBLINGS
|ES_LEFT
|WS_BORDER
;
9925 hdc
= GetDC(parent
);
9927 /* Select the font to get appropriate metric dimensions */
9928 if(infoPtr
->hFont
!= 0)
9929 hOldFont
= SelectObject(hdc
, infoPtr
->hFont
);
9931 /*Get String Lenght in pixels */
9932 GetTextExtentPoint32W(hdc
, text
, lstrlenW(text
), &sz
);
9934 /*Add Extra spacing for the next character */
9935 GetTextMetricsW(hdc
, &textMetric
);
9936 sz
.cx
+= (textMetric
.tmMaxCharWidth
* 2);
9938 if(infoPtr
->hFont
!= 0)
9939 SelectObject(hdc
, hOldFont
);
9941 ReleaseDC(parent
, hdc
);
9943 hedit
= CreateWindowW(editName
, text
, style
, x
, y
, sz
.cx
, height
, parent
, 0, hinst
, 0);
9945 hedit
= CreateWindowA("Edit", (LPCSTR
)text
, style
, x
, y
, sz
.cx
, height
, parent
, 0, hinst
, 0);
9949 COMCTL32_Free(infoPtr
->pedititem
);
9953 infoPtr
->pedititem
->param
= param
;
9954 infoPtr
->pedititem
->EditLblCb
= EditLblCb
;
9955 infoPtr
->pedititem
->EditWndProc
= (WNDPROC
)
9956 (isW
? SetWindowLongW(hedit
, GWL_WNDPROC
, (LONG
)EditLblWndProcW
) :
9957 SetWindowLongA(hedit
, GWL_WNDPROC
, (LONG
)EditLblWndProcA
) );
9959 SendMessageW(hedit
, WM_SETFONT
, infoPtr
->hFont
, FALSE
);