ReactOS 0.4.15-dev-8434-g155a7c7
listview.c
Go to the documentation of this file.
1/*
2 * Listview control
3 *
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
9 * Copyright 2009-2015 Nikolay Sivov
10 * Copyright 2009 Owen Rudge for CodeWeavers
11 * Copyright 2012-2013 Daniel Jelinski
12 *
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 *
27 * TODO:
28 *
29 * Default Message Processing
30 * -- WM_CREATE: create the icon and small icon image lists at this point only if
31 * the LVS_SHAREIMAGELISTS style is not specified.
32 * -- WM_WINDOWPOSCHANGED: arrange the list items if the current view is icon
33 * or small icon and the LVS_AUTOARRANGE style is specified.
34 * -- WM_TIMER
35 * -- WM_WININICHANGE
36 *
37 * Features
38 * -- Hot item handling, mouse hovering
39 * -- Workareas support
40 * -- Tilemode support
41 * -- Groups support
42 *
43 * Bugs
44 * -- Expand large item in ICON mode when the cursor is flying over the icon or text.
45 * -- Support CustomDraw options for _WIN32_IE >= 0x560 (see NMLVCUSTOMDRAW docs).
46 * -- LVA_SNAPTOGRID not implemented
47 * -- LISTVIEW_ApproximateViewRect partially implemented
48 * -- LISTVIEW_StyleChanged doesn't handle some changes too well
49 *
50 * Speedups
51 * -- LISTVIEW_GetNextItem needs to be rewritten. It is currently
52 * linear in the number of items in the list, and this is
53 * unacceptable for large lists.
54 * -- if list is sorted by item text LISTVIEW_InsertItemT could use
55 * binary search to calculate item index (e.g. DPA_Search()).
56 * This requires sorted state to be reliably tracked in item modifiers.
57 * -- we should keep an ordered array of coordinates in iconic mode.
58 * This would allow framing items (iterator_frameditems),
59 * and finding the nearest item (LVFI_NEARESTXY) a lot more efficiently.
60 *
61 * Flags
62 * -- LVIF_COLUMNS
63 * -- LVIF_GROUPID
64 *
65 * States
66 * -- LVIS_ACTIVATING (not currently supported by comctl32.dll version 6.0)
67 * -- LVIS_DROPHILITED
68 *
69 * Styles
70 * -- LVS_NOLABELWRAP
71 * -- LVS_NOSCROLL (see Q137520)
72 * -- LVS_ALIGNTOP
73 *
74 * Extended Styles
75 * -- LVS_EX_BORDERSELECT
76 * -- LVS_EX_FLATSB
77 * -- LVS_EX_INFOTIP
78 * -- LVS_EX_LABELTIP
79 * -- LVS_EX_MULTIWORKAREAS
80 * -- LVS_EX_REGIONAL
81 * -- LVS_EX_SIMPLESELECT
82 * -- LVS_EX_TWOCLICKACTIVATE
83 * -- LVS_EX_UNDERLINECOLD
84 * -- LVS_EX_UNDERLINEHOT
85 *
86 * Notifications:
87 * -- LVN_BEGINSCROLL, LVN_ENDSCROLL
88 * -- LVN_GETINFOTIP
89 * -- LVN_HOTTRACK
90 * -- LVN_SETDISPINFO
91 *
92 * Messages:
93 * -- LVM_ENABLEGROUPVIEW
94 * -- LVM_GETBKIMAGE, LVM_SETBKIMAGE
95 * -- LVM_GETGROUPINFO, LVM_SETGROUPINFO
96 * -- LVM_GETGROUPMETRICS, LVM_SETGROUPMETRICS
97 * -- LVM_GETINSERTMARK, LVM_SETINSERTMARK
98 * -- LVM_GETINSERTMARKCOLOR, LVM_SETINSERTMARKCOLOR
99 * -- LVM_GETINSERTMARKRECT
100 * -- LVM_GETNUMBEROFWORKAREAS
101 * -- LVM_GETOUTLINECOLOR, LVM_SETOUTLINECOLOR
102 * -- LVM_GETSELECTEDCOLUMN, LVM_SETSELECTEDCOLUMN
103 * -- LVM_GETISEARCHSTRINGW, LVM_GETISEARCHSTRINGA
104 * -- LVM_GETTILEINFO, LVM_SETTILEINFO
105 * -- LVM_GETTILEVIEWINFO, LVM_SETTILEVIEWINFO
106 * -- LVM_GETWORKAREAS, LVM_SETWORKAREAS
107 * -- LVM_HASGROUP, LVM_INSERTGROUP, LVM_REMOVEGROUP, LVM_REMOVEALLGROUPS
108 * -- LVM_INSERTGROUPSORTED
109 * -- LVM_INSERTMARKHITTEST
110 * -- LVM_ISGROUPVIEWENABLED
111 * -- LVM_MOVEGROUP
112 * -- LVM_MOVEITEMTOGROUP
113 * -- LVM_SETINFOTIP
114 * -- LVM_SETTILEWIDTH
115 * -- LVM_SORTGROUPS
116 *
117 * Macros:
118 * -- ListView_GetHoverTime, ListView_SetHoverTime
119 * -- ListView_GetISearchString
120 * -- ListView_GetNumberOfWorkAreas
121 * -- ListView_GetWorkAreas, ListView_SetWorkAreas
122 *
123 * Functions:
124 * -- LVGroupComparE
125 */
126
127#include <assert.h>
128#include <ctype.h>
129#include <string.h>
130#include <stdlib.h>
131#include <stdarg.h>
132#include <stdio.h>
133
134#include "windef.h"
135#include "winbase.h"
136#include "winnt.h"
137#include "wingdi.h"
138#include "winuser.h"
139#include "winnls.h"
140#include "commctrl.h"
141#include "comctl32.h"
142#include "uxtheme.h"
143
144#include "wine/debug.h"
145
147
148typedef struct tagCOLUMN_INFO
149{
150 RECT rcHeader; /* tracks the header's rectangle */
151 INT fmt; /* same as LVCOLUMN.fmt */
154
155typedef struct tagITEMHDR
156{
160
161typedef struct tagSUBITEM_INFO
162{
166
167typedef struct tagITEM_ID ITEM_ID;
168
169typedef struct tagITEM_INFO
170{
177
179{
180 UINT id; /* item id */
181 HDPA item; /* link to item data */
182};
183
184typedef struct tagRANGE
185{
189
190typedef struct tagRANGES
191{
194
195typedef struct tagITERATOR
196{
203
205{
209
211{
214 NOTIFY_MASK_UNMASK_ALL = 0xffffffff
216
217typedef struct tagLISTVIEW_INFO
218{
219 /* control window */
221 RECT rcList; /* This rectangle is really the window
222 * client rectangle possibly reduced by the
223 * horizontal scroll bar and/or header - see
224 * LISTVIEW_UpdateSize. This rectangle offset
225 * by the LISTVIEW_GetOrigin value is in
226 * client coordinates */
227
228 /* notification window */
233
234 /* tooltips */
236
237 /* items */
238 INT nItemCount; /* the number of items in the list */
239 HDPA hdpaItems; /* array ITEM_INFO pointers */
240 HDPA hdpaItemIds; /* array of ITEM_ID pointers */
241 HDPA hdpaPosX; /* maintains the (X, Y) coordinates of the */
242 HDPA hdpaPosY; /* items in LVS_ICON, and LVS_SMALLICON modes */
244 INT nSelectionMark; /* item to start next multiselection from */
246
247 /* columns */
248 HDPA hdpaColumns; /* array of COLUMN_INFO pointers */
249 BOOL colRectsDirty; /* trigger column rectangles requery from header */
250
251 /* item metrics */
252 BOOL bNoItemMetrics; /* flags if item metrics are not yet computed */
255
256 /* sorting */
257 PFNLVCOMPARE pfnCompare; /* sorting callback pointer */
259
260 /* style */
261 DWORD dwStyle; /* the cached window GWL_STYLE */
262 DWORD dwLvExStyle; /* extended listview style */
263 DWORD uView; /* current view available through LVM_[G,S]ETVIEW */
264
265 /* edit item */
269 DELAYED_ITEM_EDIT itemEdit; /* Pointer to this structure will be the timer ID */
270
271 /* icons */
279 POINT currIconPos; /* this is the position next icon will be placed */
280
281 /* header */
283 INT xTrackLine; /* The x coefficient of the track line or -1 if none */
284
285 /* marquee selection */
286 BOOL bMarqueeSelect; /* marquee selection/highlight underway */
288 RECT marqueeRect; /* absolute coordinates of marquee selection */
289 RECT marqueeDrawRect; /* relative coordinates for drawing marquee */
290 POINT marqueeOrigin; /* absolute coordinates of marquee click origin */
291
292 /* focus drawing */
293 BOOL bFocus; /* control has focus */
295 RECT rcFocus; /* focus bounds */
296
297 /* colors */
298 HBRUSH hBkBrush;
302#ifdef __REACTOS__
303 BOOL bDefaultBkColor;
304#endif
305
306 /* font */
309 INT ntmHeight; /* Some cached metrics of the font used */
310 INT ntmMaxCharWidth; /* by the listview to draw items */
312
313 /* mouse operation */
316 POINT ptClickPos; /* point where the user clicked */
317 INT nLButtonDownItem; /* tracks item to reset multiselection on WM_LBUTTONUP */
321
322 /* keyboard operation */
327
328 /* painting */
329 BOOL bIsDrawing; /* Drawing in progress */
330 INT nMeasureItemHeight; /* WM_MEASUREITEM result */
331 BOOL redraw; /* WM_SETREDRAW switch */
332
333 /* misc */
334 DWORD iVersion; /* CCM_[G,S]ETVERSION */
336
337/*
338 * constants
339 */
340/* How many we debug buffer to allocate */
341#define DEBUG_BUFFERS 20
342/* The size of a single debug buffer */
343#define DEBUG_BUFFER_SIZE 256
344
345/* Internal interface to LISTVIEW_HScroll and LISTVIEW_VScroll */
346#define SB_INTERNAL -1
347
348/* maximum size of a label */
349#define DISP_TEXT_SIZE 260
350
351/* padding for items in list and small icon display modes */
352#define WIDTH_PADDING 12
353
354/* padding for items in list, report and small icon display modes */
355#define HEIGHT_PADDING 1
356
357/* offset of items in report display mode */
358#define REPORT_MARGINX 2
359
360/* padding for icon in large icon display mode
361 * ICON_TOP_PADDING_NOTHITABLE - space between top of box and area
362 * that HITTEST will see.
363 * ICON_TOP_PADDING_HITABLE - spacing between above and icon.
364 * ICON_TOP_PADDING - sum of the two above.
365 * ICON_BOTTOM_PADDING - between bottom of icon and top of text
366 * LABEL_HOR_PADDING - between text and sides of box
367 * LABEL_VERT_PADDING - between bottom of text and end of box
368 *
369 * ICON_LR_PADDING - additional width above icon size.
370 * ICON_LR_HALF - half of the above value
371 */
372#define ICON_TOP_PADDING_NOTHITABLE 2
373#define ICON_TOP_PADDING_HITABLE 2
374#define ICON_TOP_PADDING (ICON_TOP_PADDING_NOTHITABLE + ICON_TOP_PADDING_HITABLE)
375#define ICON_BOTTOM_PADDING 4
376#define LABEL_HOR_PADDING 5
377#define LABEL_VERT_PADDING 7
378#define ICON_LR_PADDING 16
379#define ICON_LR_HALF (ICON_LR_PADDING/2)
380
381/* default label width for items in list and small icon display modes */
382#define DEFAULT_LABEL_WIDTH 40
383/* maximum select rectangle width for empty text item in LV_VIEW_DETAILS */
384#define MAX_EMPTYTEXT_SELECT_WIDTH 80
385
386/* default column width for items in list display mode */
387#define DEFAULT_COLUMN_WIDTH 128
388
389/* Size of "line" scroll for V & H scrolls */
390#define LISTVIEW_SCROLL_ICON_LINE_SIZE 37
391
392/* Padding between image and label */
393#define IMAGE_PADDING 2
394
395/* Padding behind the label */
396#define TRAILING_LABEL_PADDING 12
397#define TRAILING_HEADER_PADDING 11
398
399/* Border for the icon caption */
400#define CAPTION_BORDER 2
401
402/* Standard DrawText flags */
403#define LV_ML_DT_FLAGS (DT_TOP | DT_NOPREFIX | DT_EDITCONTROL | DT_CENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS | DT_END_ELLIPSIS)
404#define LV_FL_DT_FLAGS (DT_TOP | DT_NOPREFIX | DT_EDITCONTROL | DT_CENTER | DT_WORDBREAK | DT_NOCLIP)
405#define LV_SL_DT_FLAGS (DT_VCENTER | DT_NOPREFIX | DT_EDITCONTROL | DT_SINGLELINE | DT_WORD_ELLIPSIS | DT_END_ELLIPSIS)
406
407/* Image index from state */
408#define STATEIMAGEINDEX(x) (((x) & LVIS_STATEIMAGEMASK) >> 12)
409
410/* The time in milliseconds to reset the search in the list */
411#define KEY_DELAY 450
412
413/* Dump the LISTVIEW_INFO structure to the debug channel */
414#define LISTVIEW_DUMP(iP) do { \
415 TRACE("hwndSelf=%p, clrBk=0x%06x, clrText=0x%06x, clrTextBk=0x%06x, ItemHeight=%d, ItemWidth=%d, Style=0x%08x\n", \
416 iP->hwndSelf, iP->clrBk, iP->clrText, iP->clrTextBk, \
417 iP->nItemHeight, iP->nItemWidth, iP->dwStyle); \
418 TRACE("hwndSelf=%p, himlNor=%p, himlSml=%p, himlState=%p, Focused=%d, Hot=%d, exStyle=0x%08x, Focus=%d\n", \
419 iP->hwndSelf, iP->himlNormal, iP->himlSmall, iP->himlState, \
420 iP->nFocusedItem, iP->nHotItem, iP->dwLvExStyle, iP->bFocus ); \
421 TRACE("hwndSelf=%p, ntmH=%d, icSz.cx=%d, icSz.cy=%d, icSp.cx=%d, icSp.cy=%d, notifyFmt=%d\n", \
422 iP->hwndSelf, iP->ntmHeight, iP->iconSize.cx, iP->iconSize.cy, \
423 iP->iconSpacing.cx, iP->iconSpacing.cy, iP->notifyFormat); \
424 TRACE("hwndSelf=%p, rcList=%s\n", iP->hwndSelf, wine_dbgstr_rect(&iP->rcList)); \
425} while(0)
426
427static const WCHAR themeClass[] = {'L','i','s','t','V','i','e','w',0};
428
429/*
430 * forward declarations
431 */
433static void LISTVIEW_GetItemBox(const LISTVIEW_INFO *, INT, LPRECT);
434static void LISTVIEW_GetItemOrigin(const LISTVIEW_INFO *, INT, LPPOINT);
437static void LISTVIEW_GetOrigin(const LISTVIEW_INFO *, LPPOINT);
452
453/******** Text handling functions *************************************/
454
455/* A text pointer is either NULL, LPSTR_TEXTCALLBACK, or points to a
456 * text string. The string may be ANSI or Unicode, in which case
457 * the boolean isW tells us the type of the string.
458 *
459 * The name of the function tell what type of strings it expects:
460 * W: Unicode, T: ANSI/Unicode - function of isW
461 */
462
463static inline BOOL is_text(LPCWSTR text)
464{
465 return text != NULL && text != LPSTR_TEXTCALLBACKW;
466}
467
468static inline int textlenT(LPCWSTR text, BOOL isW)
469{
470 return !is_text(text) ? 0 :
472}
473
474static inline void textcpynT(LPWSTR dest, BOOL isDestW, LPCWSTR src, BOOL isSrcW, INT max)
475{
476 if (isDestW)
477 if (isSrcW) lstrcpynW(dest, src, max);
478 else MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1, dest, max);
479 else
480 if (isSrcW) WideCharToMultiByte(CP_ACP, 0, src, -1, (LPSTR)dest, max, NULL, NULL);
481 else lstrcpynA((LPSTR)dest, (LPCSTR)src, max);
482}
483
485{
486 LPWSTR wstr = (LPWSTR)text;
487
488 if (!isW && is_text(text))
489 {
491 wstr = Alloc(len * sizeof(WCHAR));
492 if (wstr) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)text, -1, wstr, len);
493 }
494 TRACE(" wstr=%s\n", text == LPSTR_TEXTCALLBACKW ? "(callback)" : debugstr_w(wstr));
495 return wstr;
496}
497
498static inline void textfreeT(LPWSTR wstr, BOOL isW)
499{
500 if (!isW && is_text(wstr)) Free (wstr);
501}
502
503/*
504 * dest is a pointer to a Unicode string
505 * src is a pointer to a string (Unicode if isW, ANSI if !isW)
506 */
508{
509 BOOL bResult = TRUE;
510
512 {
513 if (is_text(*dest)) Free(*dest);
515 }
516 else
517 {
518 LPWSTR pszText = textdupTtoW(src, isW);
519 if (*dest == LPSTR_TEXTCALLBACKW) *dest = NULL;
520 bResult = Str_SetPtrW(dest, pszText);
521 textfreeT(pszText, isW);
522 }
523 return bResult;
524}
525
526/*
527 * compares a Unicode to a Unicode/ANSI text string
528 */
529static inline int textcmpWT(LPCWSTR aw, LPCWSTR bt, BOOL isW)
530{
531 if (!aw) return bt ? -1 : 0;
532 if (!bt) return 1;
533 if (aw == LPSTR_TEXTCALLBACKW)
534 return bt == LPSTR_TEXTCALLBACKW ? 1 : -1;
535 if (bt != LPSTR_TEXTCALLBACKW)
536 {
537 LPWSTR bw = textdupTtoW(bt, isW);
538 int r = bw ? lstrcmpW(aw, bw) : 1;
539 textfreeT(bw, isW);
540 return r;
541 }
542
543 return 1;
544}
545
546static inline int lstrncmpiW(LPCWSTR s1, LPCWSTR s2, int n)
547{
548 n = min(min(n, lstrlenW(s1)), lstrlenW(s2));
550}
551
552/******** Debugging functions *****************************************/
553
555{
556 if (text == LPSTR_TEXTCALLBACKW) return "(callback)";
557 return isW ? debugstr_w(text) : debugstr_a((LPCSTR)text);
558}
559
561{
562 if (text == LPSTR_TEXTCALLBACKW) return "(callback)";
563 n = min(textlenT(text, isW), n);
564 return isW ? debugstr_wn(text, n) : debugstr_an((LPCSTR)text, n);
565}
566
567static char* debug_getbuf(void)
568{
569 static int index = 0;
571 return buffers[index++ % DEBUG_BUFFERS];
572}
573
574static inline const char* debugrange(const RANGE *lprng)
575{
576 if (!lprng) return "(null)";
577 return wine_dbg_sprintf("[%d, %d]", lprng->lower, lprng->upper);
578}
579
580static const char* debugscrollinfo(const SCROLLINFO *pScrollInfo)
581{
582 char* buf = debug_getbuf(), *text = buf;
584
585 if (pScrollInfo == NULL) return "(null)";
586 len = snprintf(buf, size, "{cbSize=%u, ", pScrollInfo->cbSize);
587 if (len == -1) goto end;
588 buf += len; size -= len;
589 if (pScrollInfo->fMask & SIF_RANGE)
590 len = snprintf(buf, size, "nMin=%d, nMax=%d, ", pScrollInfo->nMin, pScrollInfo->nMax);
591 else len = 0;
592 if (len == -1) goto end;
593 buf += len; size -= len;
594 if (pScrollInfo->fMask & SIF_PAGE)
595 len = snprintf(buf, size, "nPage=%u, ", pScrollInfo->nPage);
596 else len = 0;
597 if (len == -1) goto end;
598 buf += len; size -= len;
599 if (pScrollInfo->fMask & SIF_POS)
600 len = snprintf(buf, size, "nPos=%d, ", pScrollInfo->nPos);
601 else len = 0;
602 if (len == -1) goto end;
603 buf += len; size -= len;
604 if (pScrollInfo->fMask & SIF_TRACKPOS)
605 len = snprintf(buf, size, "nTrackPos=%d, ", pScrollInfo->nTrackPos);
606 else len = 0;
607 if (len == -1) goto end;
608 buf += len;
609 goto undo;
610end:
611 buf = text + strlen(text);
612undo:
613 if (buf - text > 2) { buf[-2] = '}'; buf[-1] = 0; }
614 return text;
615}
616
617static const char* debugnmlistview(const NMLISTVIEW *plvnm)
618{
619 if (!plvnm) return "(null)";
620 return wine_dbg_sprintf("iItem=%d, iSubItem=%d, uNewState=0x%x,"
621 " uOldState=0x%x, uChanged=0x%x, ptAction=%s, lParam=%ld",
622 plvnm->iItem, plvnm->iSubItem, plvnm->uNewState, plvnm->uOldState,
623 plvnm->uChanged, wine_dbgstr_point(&plvnm->ptAction), plvnm->lParam);
624}
625
626static const char* debuglvitem_t(const LVITEMW *lpLVItem, BOOL isW)
627{
628 char* buf = debug_getbuf(), *text = buf;
630
631 if (lpLVItem == NULL) return "(null)";
632 len = snprintf(buf, size, "{iItem=%d, iSubItem=%d, ", lpLVItem->iItem, lpLVItem->iSubItem);
633 if (len == -1) goto end;
634 buf += len; size -= len;
635 if (lpLVItem->mask & LVIF_STATE)
636 len = snprintf(buf, size, "state=%x, stateMask=%x, ", lpLVItem->state, lpLVItem->stateMask);
637 else len = 0;
638 if (len == -1) goto end;
639 buf += len; size -= len;
640 if (lpLVItem->mask & LVIF_TEXT)
641 len = snprintf(buf, size, "pszText=%s, cchTextMax=%d, ", debugtext_tn(lpLVItem->pszText, isW, 80), lpLVItem->cchTextMax);
642 else len = 0;
643 if (len == -1) goto end;
644 buf += len; size -= len;
645 if (lpLVItem->mask & LVIF_IMAGE)
646 len = snprintf(buf, size, "iImage=%d, ", lpLVItem->iImage);
647 else len = 0;
648 if (len == -1) goto end;
649 buf += len; size -= len;
650 if (lpLVItem->mask & LVIF_PARAM)
651 len = snprintf(buf, size, "lParam=%lx, ", lpLVItem->lParam);
652 else len = 0;
653 if (len == -1) goto end;
654 buf += len; size -= len;
655 if (lpLVItem->mask & LVIF_INDENT)
656 len = snprintf(buf, size, "iIndent=%d, ", lpLVItem->iIndent);
657 else len = 0;
658 if (len == -1) goto end;
659 buf += len;
660 goto undo;
661end:
662 buf = text + strlen(text);
663undo:
664 if (buf - text > 2) { buf[-2] = '}'; buf[-1] = 0; }
665 return text;
666}
667
668static const char* debuglvcolumn_t(const LVCOLUMNW *lpColumn, BOOL isW)
669{
670 char* buf = debug_getbuf(), *text = buf;
672
673 if (lpColumn == NULL) return "(null)";
674 len = snprintf(buf, size, "{");
675 if (len == -1) goto end;
676 buf += len; size -= len;
677 if (lpColumn->mask & LVCF_SUBITEM)
678 len = snprintf(buf, size, "iSubItem=%d, ", lpColumn->iSubItem);
679 else len = 0;
680 if (len == -1) goto end;
681 buf += len; size -= len;
682 if (lpColumn->mask & LVCF_FMT)
683 len = snprintf(buf, size, "fmt=%x, ", lpColumn->fmt);
684 else len = 0;
685 if (len == -1) goto end;
686 buf += len; size -= len;
687 if (lpColumn->mask & LVCF_WIDTH)
688 len = snprintf(buf, size, "cx=%d, ", lpColumn->cx);
689 else len = 0;
690 if (len == -1) goto end;
691 buf += len; size -= len;
692 if (lpColumn->mask & LVCF_TEXT)
693 len = snprintf(buf, size, "pszText=%s, cchTextMax=%d, ", debugtext_tn(lpColumn->pszText, isW, 80), lpColumn->cchTextMax);
694 else len = 0;
695 if (len == -1) goto end;
696 buf += len; size -= len;
697 if (lpColumn->mask & LVCF_IMAGE)
698 len = snprintf(buf, size, "iImage=%d, ", lpColumn->iImage);
699 else len = 0;
700 if (len == -1) goto end;
701 buf += len; size -= len;
702 if (lpColumn->mask & LVCF_ORDER)
703 len = snprintf(buf, size, "iOrder=%d, ", lpColumn->iOrder);
704 else len = 0;
705 if (len == -1) goto end;
706 buf += len;
707 goto undo;
708end:
709 buf = text + strlen(text);
710undo:
711 if (buf - text > 2) { buf[-2] = '}'; buf[-1] = 0; }
712 return text;
713}
714
715static const char* debuglvhittestinfo(const LVHITTESTINFO *lpht)
716{
717 if (!lpht) return "(null)";
718
719 return wine_dbg_sprintf("{pt=%s, flags=0x%x, iItem=%d, iSubItem=%d}",
720 wine_dbgstr_point(&lpht->pt), lpht->flags, lpht->iItem, lpht->iSubItem);
721}
722
723/* Return the corresponding text for a given scroll value */
724static inline LPCSTR debugscrollcode(int nScrollCode)
725{
726 switch(nScrollCode)
727 {
728 case SB_LINELEFT: return "SB_LINELEFT";
729 case SB_LINERIGHT: return "SB_LINERIGHT";
730 case SB_PAGELEFT: return "SB_PAGELEFT";
731 case SB_PAGERIGHT: return "SB_PAGERIGHT";
732 case SB_THUMBPOSITION: return "SB_THUMBPOSITION";
733 case SB_THUMBTRACK: return "SB_THUMBTRACK";
734 case SB_ENDSCROLL: return "SB_ENDSCROLL";
735 case SB_INTERNAL: return "SB_INTERNAL";
736 default: return "unknown";
737 }
738}
739
740
741/******** Notification functions ************************************/
742
743static int get_ansi_notification(UINT unicodeNotificationCode)
744{
745 switch (unicodeNotificationCode)
746 {
751 case LVN_GETDISPINFOA:
753 case LVN_SETDISPINFOA:
755 case LVN_ODFINDITEMA:
756 case LVN_ODFINDITEMW: return LVN_ODFINDITEMA;
757 case LVN_GETINFOTIPA:
758 case LVN_GETINFOTIPW: return LVN_GETINFOTIPA;
759 /* header forwards */
760 case HDN_TRACKA:
761 case HDN_TRACKW: return HDN_TRACKA;
762 case HDN_ENDTRACKA:
763 case HDN_ENDTRACKW: return HDN_ENDTRACKA;
764 case HDN_BEGINDRAG: return HDN_BEGINDRAG;
765 case HDN_ENDDRAG: return HDN_ENDDRAG;
768 case HDN_ITEMCHANGEDA:
770 case HDN_ITEMCLICKA:
771 case HDN_ITEMCLICKW: return HDN_ITEMCLICKA;
774 default: break;
775 }
776 FIXME("unknown notification %x\n", unicodeNotificationCode);
777 return unicodeNotificationCode;
778}
779
780/* forwards header notifications to listview parent */
782{
784 LRESULT ret;
785 NMHEADERA *lpnmh = (NMHEADERA*) lpnmhW;
786
787 /* on unicode format exit earlier */
788 if (infoPtr->notifyFormat == NFR_UNICODE)
789 return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, lpnmh->hdr.idFrom,
790 (LPARAM)lpnmh);
791
792 /* header always supplies unicode notifications,
793 all we have to do is to convert strings to ANSI */
794 if (lpnmh->pitem)
795 {
796 /* convert item text */
797 if (lpnmh->pitem->mask & HDI_TEXT)
798 {
799 text = (LPCWSTR)lpnmh->pitem->pszText;
800 lpnmh->pitem->pszText = NULL;
801 Str_SetPtrWtoA(&lpnmh->pitem->pszText, text);
802 }
803 /* convert filter text */
804 if ((lpnmh->pitem->mask & HDI_FILTER) && (lpnmh->pitem->type == HDFT_ISSTRING) &&
805 lpnmh->pitem->pvFilter)
806 {
807 filter = (LPCWSTR)((HD_TEXTFILTERA*)lpnmh->pitem->pvFilter)->pszText;
808 ((HD_TEXTFILTERA*)lpnmh->pitem->pvFilter)->pszText = NULL;
809 Str_SetPtrWtoA(&((HD_TEXTFILTERA*)lpnmh->pitem->pvFilter)->pszText, filter);
810 }
811 }
812 lpnmh->hdr.code = get_ansi_notification(lpnmh->hdr.code);
813
814 ret = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, lpnmh->hdr.idFrom,
815 (LPARAM)lpnmh);
816
817 /* cleanup */
818 if(text)
819 {
820 Free(lpnmh->pitem->pszText);
821 lpnmh->pitem->pszText = (LPSTR)text;
822 }
823 if(filter)
824 {
825 Free(((HD_TEXTFILTERA*)lpnmh->pitem->pvFilter)->pszText);
826 ((HD_TEXTFILTERA*)lpnmh->pitem->pvFilter)->pszText = (LPSTR)filter;
827 }
828
829 return ret;
830}
831
832static LRESULT notify_hdr(const LISTVIEW_INFO *infoPtr, INT code, LPNMHDR pnmh)
833{
835
836 TRACE("(code=%d)\n", code);
837
838 pnmh->hwndFrom = infoPtr->hwndSelf;
839 pnmh->idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
840 pnmh->code = code;
841 result = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, pnmh->idFrom, (LPARAM)pnmh);
842
843 TRACE(" <= %ld\n", result);
844
845 return result;
846}
847
848static inline BOOL notify(const LISTVIEW_INFO *infoPtr, INT code)
849{
850 NMHDR nmh;
851 HWND hwnd = infoPtr->hwndSelf;
852 notify_hdr(infoPtr, code, &nmh);
853 return IsWindow(hwnd);
854}
855
856static inline void notify_itemactivate(const LISTVIEW_INFO *infoPtr, const LVHITTESTINFO *htInfo)
857{
858 NMITEMACTIVATE nmia;
860
861 nmia.uNewState = 0;
862 nmia.uOldState = 0;
863 nmia.uChanged = 0;
864 nmia.uKeyFlags = 0;
865
867 item.iItem = htInfo->iItem;
868 item.iSubItem = 0;
869 item.stateMask = (UINT)-1;
870 if (LISTVIEW_GetItemT(infoPtr, &item, TRUE)) {
871 nmia.lParam = item.lParam;
872 nmia.uOldState = item.state;
873 nmia.uNewState = item.state | LVIS_ACTIVATING;
874 nmia.uChanged = LVIF_STATE;
875 }
876
877 nmia.iItem = htInfo->iItem;
878 nmia.iSubItem = htInfo->iSubItem;
879 nmia.ptAction = htInfo->pt;
880
881 if (GetKeyState(VK_SHIFT) & 0x8000) nmia.uKeyFlags |= LVKF_SHIFT;
882 if (GetKeyState(VK_CONTROL) & 0x8000) nmia.uKeyFlags |= LVKF_CONTROL;
883 if (GetKeyState(VK_MENU) & 0x8000) nmia.uKeyFlags |= LVKF_ALT;
884
885 notify_hdr(infoPtr, LVN_ITEMACTIVATE, (LPNMHDR)&nmia);
886}
887
888static inline LRESULT notify_listview(const LISTVIEW_INFO *infoPtr, INT code, LPNMLISTVIEW plvnm)
889{
890 TRACE("(code=%d, plvnm=%s)\n", code, debugnmlistview(plvnm));
891 return notify_hdr(infoPtr, code, (LPNMHDR)plvnm);
892}
893
894/* Handles NM_DBLCLK, NM_CLICK, NM_RDBLCLK, NM_RCLICK. Only NM_RCLICK return value is used. */
895static BOOL notify_click(const LISTVIEW_INFO *infoPtr, INT code, const LVHITTESTINFO *lvht)
896{
897 NMITEMACTIVATE nmia;
899 HWND hwnd = infoPtr->hwndSelf;
900 LRESULT ret;
901
902 TRACE("code=%d, lvht=%s\n", code, debuglvhittestinfo(lvht));
903 ZeroMemory(&nmia, sizeof(nmia));
904 nmia.iItem = lvht->iItem;
905 nmia.iSubItem = lvht->iSubItem;
906 nmia.ptAction = lvht->pt;
907 item.mask = LVIF_PARAM;
908 item.iItem = lvht->iItem;
909 item.iSubItem = 0;
910 if (LISTVIEW_GetItemT(infoPtr, &item, TRUE)) nmia.lParam = item.lParam;
911 ret = notify_hdr(infoPtr, code, (NMHDR*)&nmia);
912 return IsWindow(hwnd) && (code == NM_RCLICK ? !ret : TRUE);
913}
914
915static BOOL notify_deleteitem(const LISTVIEW_INFO *infoPtr, INT nItem)
916{
917 NMLISTVIEW nmlv;
919 HWND hwnd = infoPtr->hwndSelf;
920
921 ZeroMemory(&nmlv, sizeof (NMLISTVIEW));
922 nmlv.iItem = nItem;
923 item.mask = LVIF_PARAM;
924 item.iItem = nItem;
925 item.iSubItem = 0;
926 if (LISTVIEW_GetItemT(infoPtr, &item, TRUE)) nmlv.lParam = item.lParam;
927 notify_listview(infoPtr, LVN_DELETEITEM, &nmlv);
928 return IsWindow(hwnd);
929}
930
931/*
932 Send notification. depends on dispinfoW having same
933 structure as dispinfoA.
934 infoPtr : listview struct
935 code : *Unicode* notification code
936 pdi : dispinfo structure (can be unicode or ansi)
937 isW : TRUE if dispinfo is Unicode
938*/
940{
941 INT length = 0, ret_length;
942 LPWSTR buffer = NULL, ret_text;
943 BOOL return_ansi = FALSE;
944 BOOL return_unicode = FALSE;
945 BOOL ret;
946
947 if ((pdi->item.mask & LVIF_TEXT) && is_text(pdi->item.pszText))
948 {
949 return_unicode = ( isW && infoPtr->notifyFormat == NFR_ANSI);
950 return_ansi = (!isW && infoPtr->notifyFormat == NFR_UNICODE);
951 }
952
953 ret_length = pdi->item.cchTextMax;
954 ret_text = pdi->item.pszText;
955
956 if (return_unicode || return_ansi)
957 {
958 if (code != LVN_GETDISPINFOW)
959 {
960 length = return_ansi ?
961 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pdi->item.pszText, -1, NULL, 0):
962 WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, NULL, 0, NULL, NULL);
963 }
964 else
965 {
966 length = pdi->item.cchTextMax;
967 *pdi->item.pszText = 0; /* make sure we don't process garbage */
968 }
969
970 buffer = Alloc( (return_ansi ? sizeof(WCHAR) : sizeof(CHAR)) * length);
971 if (!buffer) return FALSE;
972
973 if (return_ansi)
974 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pdi->item.pszText, -1,
975 buffer, length);
976 else
977 WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, (LPSTR) buffer,
978 length, NULL, NULL);
979
980 pdi->item.pszText = buffer;
981 pdi->item.cchTextMax = length;
982 }
983
984 if (infoPtr->notifyFormat == NFR_ANSI)
986
987 TRACE(" pdi->item=%s\n", debuglvitem_t(&pdi->item, infoPtr->notifyFormat != NFR_ANSI));
988 ret = notify_hdr(infoPtr, code, &pdi->hdr);
989 TRACE(" resulting code=%d\n", pdi->hdr.code);
990
991 if (return_ansi || return_unicode)
992 {
993 if (return_ansi && (pdi->hdr.code == LVN_GETDISPINFOA))
994 {
995 strcpy((char*)ret_text, (char*)pdi->item.pszText);
996 }
997 else if (return_unicode && (pdi->hdr.code == LVN_GETDISPINFOW))
998 {
999 lstrcpyW(ret_text, pdi->item.pszText);
1000 }
1001 else if (return_ansi) /* note : pointer can be changed by app ! */
1002 {
1003 WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, (LPSTR) ret_text,
1004 ret_length, NULL, NULL);
1005 }
1006 else
1007 MultiByteToWideChar(CP_ACP, 0, (LPSTR) pdi->item.pszText, -1,
1008 ret_text, ret_length);
1009
1010 pdi->item.pszText = ret_text; /* restores our buffer */
1011 pdi->item.cchTextMax = ret_length;
1012
1013 Free(buffer);
1014 return ret;
1015 }
1016
1017 /* if dispinfo holder changed notification code then convert */
1018 if (!isW && (pdi->hdr.code == LVN_GETDISPINFOW) && (pdi->item.mask & LVIF_TEXT))
1019 {
1020 length = WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, NULL, 0, NULL, NULL);
1021
1022 buffer = Alloc(length * sizeof(CHAR));
1023 if (!buffer) return FALSE;
1024
1025 WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, (LPSTR) buffer,
1026 ret_length, NULL, NULL);
1027
1028 strcpy((LPSTR)pdi->item.pszText, (LPSTR)buffer);
1029 Free(buffer);
1030 }
1031
1032 return ret;
1033}
1034
1035static void customdraw_fill(NMLVCUSTOMDRAW *lpnmlvcd, const LISTVIEW_INFO *infoPtr, HDC hdc,
1036 const RECT *rcBounds, const LVITEMW *lplvItem)
1037{
1038 ZeroMemory(lpnmlvcd, sizeof(NMLVCUSTOMDRAW));
1039 lpnmlvcd->nmcd.hdc = hdc;
1040 lpnmlvcd->nmcd.rc = *rcBounds;
1041 lpnmlvcd->clrTextBk = infoPtr->clrTextBk;
1042 lpnmlvcd->clrText = infoPtr->clrText;
1043 if (!lplvItem) return;
1044 lpnmlvcd->nmcd.dwItemSpec = lplvItem->iItem + 1;
1045 lpnmlvcd->iSubItem = lplvItem->iSubItem;
1046 if (lplvItem->state & LVIS_SELECTED) lpnmlvcd->nmcd.uItemState |= CDIS_SELECTED;
1047 if (lplvItem->state & LVIS_FOCUSED) lpnmlvcd->nmcd.uItemState |= CDIS_FOCUS;
1048 if (lplvItem->iItem == infoPtr->nHotItem) lpnmlvcd->nmcd.uItemState |= CDIS_HOT;
1049 lpnmlvcd->nmcd.lItemlParam = lplvItem->lParam;
1050}
1051
1052static inline DWORD notify_customdraw (const LISTVIEW_INFO *infoPtr, DWORD dwDrawStage, NMLVCUSTOMDRAW *lpnmlvcd)
1053{
1054 BOOL isForItem = (lpnmlvcd->nmcd.dwItemSpec != 0);
1055 DWORD result;
1056
1057 lpnmlvcd->nmcd.dwDrawStage = dwDrawStage;
1058 if (isForItem) lpnmlvcd->nmcd.dwDrawStage |= CDDS_ITEM;
1059 if (lpnmlvcd->iSubItem) lpnmlvcd->nmcd.dwDrawStage |= CDDS_SUBITEM;
1060 if (isForItem) lpnmlvcd->nmcd.dwItemSpec--;
1061 result = notify_hdr(infoPtr, NM_CUSTOMDRAW, &lpnmlvcd->nmcd.hdr);
1062 if (isForItem) lpnmlvcd->nmcd.dwItemSpec++;
1063 return result;
1064}
1065
1066static void prepaint_setup (const LISTVIEW_INFO *infoPtr, HDC hdc, NMLVCUSTOMDRAW *lpnmlvcd, BOOL SubItem)
1067{
1068 COLORREF backcolor, textcolor;
1069
1070 /* apparently, for selected items, we have to override the returned values */
1071 if (!SubItem || (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT))
1072 {
1073 if (lpnmlvcd->nmcd.uItemState & CDIS_SELECTED)
1074 {
1075 if (infoPtr->bFocus)
1076 {
1079 }
1080 else if (infoPtr->dwStyle & LVS_SHOWSELALWAYS)
1081 {
1083 lpnmlvcd->clrText = comctl32_color.clrBtnText;
1084 }
1085 }
1086 }
1087
1088 backcolor = lpnmlvcd->clrTextBk;
1089 textcolor = lpnmlvcd->clrText;
1090
1091 if (backcolor == CLR_DEFAULT)
1092 backcolor = comctl32_color.clrWindow;
1093 if (textcolor == CLR_DEFAULT)
1094 textcolor = comctl32_color.clrWindowText;
1095
1096 /* Set the text attributes */
1097 if (backcolor != CLR_NONE)
1098 {
1100 SetBkColor(hdc, backcolor);
1101 }
1102 else
1104 SetTextColor(hdc, textcolor);
1105}
1106
1107static inline DWORD notify_postpaint (const LISTVIEW_INFO *infoPtr, NMLVCUSTOMDRAW *lpnmlvcd)
1108{
1109 return notify_customdraw(infoPtr, CDDS_POSTPAINT, lpnmlvcd);
1110}
1111
1112/* returns TRUE when repaint needed, FALSE otherwise */
1114{
1116 mis.CtlType = ODT_LISTVIEW;
1117 mis.CtlID = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
1118 mis.itemID = -1;
1119 mis.itemWidth = 0;
1120 mis.itemData = 0;
1121 mis.itemHeight= infoPtr->nItemHeight;
1122 SendMessageW(infoPtr->hwndNotify, WM_MEASUREITEM, mis.CtlID, (LPARAM)&mis);
1123 if (infoPtr->nItemHeight != max(mis.itemHeight, 1))
1124 {
1125 infoPtr->nMeasureItemHeight = infoPtr->nItemHeight = max(mis.itemHeight, 1);
1126 return TRUE;
1127 }
1128 return FALSE;
1129}
1130
1131/******** Item iterator functions **********************************/
1132
1133static RANGES ranges_create(int count);
1134static void ranges_destroy(RANGES ranges);
1135static BOOL ranges_add(RANGES ranges, RANGE range);
1136static BOOL ranges_del(RANGES ranges, RANGE range);
1137static void ranges_dump(RANGES ranges);
1138
1139static inline BOOL ranges_additem(RANGES ranges, INT nItem)
1140{
1141 RANGE range = { nItem, nItem + 1 };
1142
1143 return ranges_add(ranges, range);
1144}
1145
1146static inline BOOL ranges_delitem(RANGES ranges, INT nItem)
1147{
1148 RANGE range = { nItem, nItem + 1 };
1149
1150 return ranges_del(ranges, range);
1151}
1152
1153/***
1154 * ITERATOR DOCUMENTATION
1155 *
1156 * The iterator functions allow for easy, and convenient iteration
1157 * over items of interest in the list. Typically, you create an
1158 * iterator, use it, and destroy it, as such:
1159 * ITERATOR i;
1160 *
1161 * iterator_xxxitems(&i, ...);
1162 * while (iterator_{prev,next}(&i)
1163 * {
1164 * //code which uses i.nItem
1165 * }
1166 * iterator_destroy(&i);
1167 *
1168 * where xxx is either: framed, or visible.
1169 * Note that it is important that the code destroys the iterator
1170 * after it's done with it, as the creation of the iterator may
1171 * allocate memory, which thus needs to be freed.
1172 *
1173 * You can iterate both forwards, and backwards through the list,
1174 * by using iterator_next or iterator_prev respectively.
1175 *
1176 * Lower numbered items are draw on top of higher number items in
1177 * LVS_ICON, and LVS_SMALLICON (which are the only modes where
1178 * items may overlap). So, to test items, you should use
1179 * iterator_next
1180 * which lists the items top to bottom (in Z-order).
1181 * For drawing items, you should use
1182 * iterator_prev
1183 * which lists the items bottom to top (in Z-order).
1184 * If you keep iterating over the items after the end-of-items
1185 * marker (-1) is returned, the iterator will start from the
1186 * beginning. Typically, you don't need to test for -1,
1187 * because iterator_{next,prev} will return TRUE if more items
1188 * are to be iterated over, or FALSE otherwise.
1189 *
1190 * Note: the iterator is defined to be bidirectional. That is,
1191 * any number of prev followed by any number of next, or
1192 * five versa, should leave the iterator at the same item:
1193 * prev * n, next * n = next * n, prev * n
1194 *
1195 * The iterator has a notion of an out-of-order, special item,
1196 * which sits at the start of the list. This is used in
1197 * LVS_ICON, and LVS_SMALLICON mode to handle the focused item,
1198 * which needs to be first, as it may overlap other items.
1199 *
1200 * The code is a bit messy because we have:
1201 * - a special item to deal with
1202 * - simple range, or composite range
1203 * - empty range.
1204 * If you find bugs, or want to add features, please make sure you
1205 * always check/modify *both* iterator_prev, and iterator_next.
1206 */
1207
1208/****
1209 * This function iterates through the items in increasing order,
1210 * but prefixed by the special item, then -1. That is:
1211 * special, 1, 2, 3, ..., n, -1.
1212 * Each item is listed only once.
1213 */
1215{
1216 if (i->nItem == -1)
1217 {
1218 i->nItem = i->nSpecial;
1219 if (i->nItem != -1) return TRUE;
1220 }
1221 if (i->nItem == i->nSpecial)
1222 {
1223 if (i->ranges) i->index = 0;
1224 goto pickarange;
1225 }
1226
1227 i->nItem++;
1228testitem:
1229 if (i->nItem == i->nSpecial) i->nItem++;
1230 if (i->nItem < i->range.upper) return TRUE;
1231
1232pickarange:
1233 if (i->ranges)
1234 {
1235 if (i->index < DPA_GetPtrCount(i->ranges->hdpa))
1236 i->range = *(RANGE*)DPA_GetPtr(i->ranges->hdpa, i->index++);
1237 else goto end;
1238 }
1239 else if (i->nItem >= i->range.upper) goto end;
1240
1241 i->nItem = i->range.lower;
1242 if (i->nItem >= 0) goto testitem;
1243end:
1244 i->nItem = -1;
1245 return FALSE;
1246}
1247
1248/****
1249 * This function iterates through the items in decreasing order,
1250 * followed by the special item, then -1. That is:
1251 * n, n-1, ..., 3, 2, 1, special, -1.
1252 * Each item is listed only once.
1253 */
1255{
1256 BOOL start = FALSE;
1257
1258 if (i->nItem == -1)
1259 {
1260 start = TRUE;
1261 if (i->ranges) i->index = DPA_GetPtrCount(i->ranges->hdpa);
1262 goto pickarange;
1263 }
1264 if (i->nItem == i->nSpecial)
1265 {
1266 i->nItem = -1;
1267 return FALSE;
1268 }
1269
1270testitem:
1271 i->nItem--;
1272 if (i->nItem == i->nSpecial) i->nItem--;
1273 if (i->nItem >= i->range.lower) return TRUE;
1274
1275pickarange:
1276 if (i->ranges)
1277 {
1278 if (i->index > 0)
1279 i->range = *(RANGE*)DPA_GetPtr(i->ranges->hdpa, --i->index);
1280 else goto end;
1281 }
1282 else if (!start && i->nItem < i->range.lower) goto end;
1283
1284 i->nItem = i->range.upper;
1285 if (i->nItem > 0) goto testitem;
1286end:
1287 return (i->nItem = i->nSpecial) != -1;
1288}
1289
1291{
1292 RANGE range;
1293
1294 if (!i->ranges) return i->range;
1295
1296 if (DPA_GetPtrCount(i->ranges->hdpa) > 0)
1297 {
1298 range.lower = (*(RANGE*)DPA_GetPtr(i->ranges->hdpa, 0)).lower;
1299 range.upper = (*(RANGE*)DPA_GetPtr(i->ranges->hdpa, DPA_GetPtrCount(i->ranges->hdpa) - 1)).upper;
1300 }
1301 else range.lower = range.upper = 0;
1302
1303 return range;
1304}
1305
1306/***
1307 * Releases resources associated with this iterator.
1308 */
1309static inline void iterator_destroy(const ITERATOR *i)
1310{
1311 ranges_destroy(i->ranges);
1312}
1313
1314/***
1315 * Create an empty iterator.
1316 */
1317static inline void iterator_empty(ITERATOR* i)
1318{
1319 ZeroMemory(i, sizeof(*i));
1320 i->nItem = i->nSpecial = i->range.lower = i->range.upper = -1;
1321}
1322
1323/***
1324 * Create an iterator over a range.
1325 */
1327{
1329 i->range = range;
1330}
1331
1332/***
1333 * Create an iterator over a bunch of ranges.
1334 * Please note that the iterator will take ownership of the ranges,
1335 * and will free them upon destruction.
1336 */
1337static inline void iterator_rangesitems(ITERATOR* i, RANGES ranges)
1338{
1340 i->ranges = ranges;
1341}
1342
1343/***
1344 * Creates an iterator over the items which intersect frame.
1345 * Uses absolute coordinates rather than compensating for the current offset.
1346 */
1347static BOOL iterator_frameditems_absolute(ITERATOR* i, const LISTVIEW_INFO* infoPtr, const RECT *frame)
1348{
1349 RECT rcItem, rcTemp;
1350 RANGES ranges;
1351
1352 TRACE("(frame=%s)\n", wine_dbgstr_rect(frame));
1353
1354 /* in case we fail, we want to return an empty iterator */
1356
1357 if (infoPtr->nItemCount == 0)
1358 return TRUE;
1359
1360 if (infoPtr->uView == LV_VIEW_ICON || infoPtr->uView == LV_VIEW_SMALLICON)
1361 {
1362 INT nItem;
1363
1364 if (infoPtr->uView == LV_VIEW_ICON && infoPtr->nFocusedItem != -1)
1365 {
1366 LISTVIEW_GetItemBox(infoPtr, infoPtr->nFocusedItem, &rcItem);
1367 if (IntersectRect(&rcTemp, &rcItem, frame))
1368 i->nSpecial = infoPtr->nFocusedItem;
1369 }
1370 if (!(ranges = ranges_create(50))) return FALSE;
1371 iterator_rangesitems(i, ranges);
1372 /* to do better here, we need to have PosX, and PosY sorted */
1373 TRACE("building icon ranges:\n");
1374 for (nItem = 0; nItem < infoPtr->nItemCount; nItem++)
1375 {
1376 rcItem.left = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosX, nItem);
1377 rcItem.top = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosY, nItem);
1378 rcItem.right = rcItem.left + infoPtr->nItemWidth;
1379 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
1380 if (IntersectRect(&rcTemp, &rcItem, frame))
1381 ranges_additem(i->ranges, nItem);
1382 }
1383 return TRUE;
1384 }
1385 else if (infoPtr->uView == LV_VIEW_DETAILS)
1386 {
1387 RANGE range;
1388
1389 if (frame->left >= infoPtr->nItemWidth) return TRUE;
1390 if (frame->top >= infoPtr->nItemHeight * infoPtr->nItemCount) return TRUE;
1391
1392 range.lower = max(frame->top / infoPtr->nItemHeight, 0);
1393 range.upper = min((frame->bottom - 1) / infoPtr->nItemHeight, infoPtr->nItemCount - 1) + 1;
1394 if (range.upper <= range.lower) return TRUE;
1396 TRACE(" report=%s\n", debugrange(&i->range));
1397 }
1398 else
1399 {
1400 INT nPerCol = max((infoPtr->rcList.bottom - infoPtr->rcList.top) / infoPtr->nItemHeight, 1);
1401 INT nFirstRow = max(frame->top / infoPtr->nItemHeight, 0);
1402 INT nLastRow = min((frame->bottom - 1) / infoPtr->nItemHeight, nPerCol - 1);
1403 INT nFirstCol;
1404 INT nLastCol;
1405 INT lower;
1406 RANGE item_range;
1407 INT nCol;
1408
1409 if (infoPtr->nItemWidth)
1410 {
1411 nFirstCol = max(frame->left / infoPtr->nItemWidth, 0);
1412 nLastCol = min((frame->right - 1) / infoPtr->nItemWidth, (infoPtr->nItemCount + nPerCol - 1) / nPerCol);
1413 }
1414 else
1415 {
1416 nFirstCol = max(frame->left, 0);
1417 nLastCol = min(frame->right - 1, (infoPtr->nItemCount + nPerCol - 1) / nPerCol);
1418 }
1419
1420 lower = nFirstCol * nPerCol + nFirstRow;
1421
1422 TRACE("nPerCol=%d, nFirstRow=%d, nLastRow=%d, nFirstCol=%d, nLastCol=%d, lower=%d\n",
1423 nPerCol, nFirstRow, nLastRow, nFirstCol, nLastCol, lower);
1424
1425 if (nLastCol < nFirstCol || nLastRow < nFirstRow) return TRUE;
1426
1427 if (!(ranges = ranges_create(nLastCol - nFirstCol + 1))) return FALSE;
1428 iterator_rangesitems(i, ranges);
1429 TRACE("building list ranges:\n");
1430 for (nCol = nFirstCol; nCol <= nLastCol; nCol++)
1431 {
1432 item_range.lower = nCol * nPerCol + nFirstRow;
1433 if(item_range.lower >= infoPtr->nItemCount) break;
1434 item_range.upper = min(nCol * nPerCol + nLastRow + 1, infoPtr->nItemCount);
1435 TRACE(" list=%s\n", debugrange(&item_range));
1436 ranges_add(i->ranges, item_range);
1437 }
1438 }
1439
1440 return TRUE;
1441}
1442
1443/***
1444 * Creates an iterator over the items which intersect lprc.
1445 */
1447{
1448 RECT frame = *lprc;
1449 POINT Origin;
1450
1451 TRACE("(lprc=%s)\n", wine_dbgstr_rect(lprc));
1452
1453 LISTVIEW_GetOrigin(infoPtr, &Origin);
1454 OffsetRect(&frame, -Origin.x, -Origin.y);
1455
1456 return iterator_frameditems_absolute(i, infoPtr, &frame);
1457}
1458
1459/***
1460 * Creates an iterator over the items which intersect the visible region of hdc.
1461 */
1463{
1464 POINT Origin, Position;
1465 RECT rcItem, rcClip;
1466 INT rgntype;
1467
1468 rgntype = GetClipBox(hdc, &rcClip);
1469 if (rgntype == NULLREGION)
1470 {
1472 return TRUE;
1473 }
1474 if (!iterator_frameditems(i, infoPtr, &rcClip)) return FALSE;
1475 if (rgntype == SIMPLEREGION) return TRUE;
1476
1477 /* first deal with the special item */
1478 if (i->nSpecial != -1)
1479 {
1480 LISTVIEW_GetItemBox(infoPtr, i->nSpecial, &rcItem);
1481 if (!RectVisible(hdc, &rcItem)) i->nSpecial = -1;
1482 }
1483
1484 /* if we can't deal with the region, we'll just go with the simple range */
1485 LISTVIEW_GetOrigin(infoPtr, &Origin);
1486 TRACE("building visible range:\n");
1487 if (!i->ranges && i->range.lower < i->range.upper)
1488 {
1489 if (!(i->ranges = ranges_create(50))) return TRUE;
1490 if (!ranges_add(i->ranges, i->range))
1491 {
1492 ranges_destroy(i->ranges);
1493 i->ranges = 0;
1494 return TRUE;
1495 }
1496 }
1497
1498 /* now delete the invisible items from the list */
1499 while(iterator_next(i))
1500 {
1501 LISTVIEW_GetItemOrigin(infoPtr, i->nItem, &Position);
1502 rcItem.left = (infoPtr->uView == LV_VIEW_DETAILS) ? Origin.x : Position.x + Origin.x;
1503 rcItem.top = Position.y + Origin.y;
1504 rcItem.right = rcItem.left + infoPtr->nItemWidth;
1505 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
1506 if (!RectVisible(hdc, &rcItem))
1507 ranges_delitem(i->ranges, i->nItem);
1508 }
1509 /* the iterator should restart on the next iterator_next */
1510 TRACE("done\n");
1511
1512 return TRUE;
1513}
1514
1515/* Remove common elements from two iterators */
1516/* Passed iterators have to point on the first elements */
1518{
1519 if(!iter1->ranges || !iter2->ranges) {
1520 int lower, upper;
1521
1522 if(iter1->ranges || iter2->ranges ||
1523 (iter1->range.lower<iter2->range.lower && iter1->range.upper>iter2->range.upper) ||
1524 (iter1->range.lower>iter2->range.lower && iter1->range.upper<iter2->range.upper)) {
1525 ERR("result is not a one range iterator\n");
1526 return FALSE;
1527 }
1528
1529 if(iter1->range.lower==-1 || iter2->range.lower==-1)
1530 return TRUE;
1531
1532 lower = iter1->range.lower;
1533 upper = iter1->range.upper;
1534
1535 if(lower < iter2->range.lower)
1536 iter1->range.upper = iter2->range.lower;
1537 else if(upper > iter2->range.upper)
1538 iter1->range.lower = iter2->range.upper;
1539 else
1540 iter1->range.lower = iter1->range.upper = -1;
1541
1542 if(iter2->range.lower < lower)
1543 iter2->range.upper = lower;
1544 else if(iter2->range.upper > upper)
1545 iter2->range.lower = upper;
1546 else
1547 iter2->range.lower = iter2->range.upper = -1;
1548
1549 return TRUE;
1550 }
1551
1552 iterator_next(iter1);
1553 iterator_next(iter2);
1554
1555 while(1) {
1556 if(iter1->nItem==-1 || iter2->nItem==-1)
1557 break;
1558
1559 if(iter1->nItem == iter2->nItem) {
1560 int delete = iter1->nItem;
1561
1562 iterator_prev(iter1);
1563 iterator_prev(iter2);
1564 ranges_delitem(iter1->ranges, delete);
1565 ranges_delitem(iter2->ranges, delete);
1566 iterator_next(iter1);
1567 iterator_next(iter2);
1568 } else if(iter1->nItem > iter2->nItem)
1569 iterator_next(iter2);
1570 else
1571 iterator_next(iter1);
1572 }
1573
1574 iter1->nItem = iter1->range.lower = iter1->range.upper = -1;
1575 iter2->nItem = iter2->range.lower = iter2->range.upper = -1;
1576 return TRUE;
1577}
1578
1579/******** Misc helper functions ************************************/
1580
1583{
1584 if (isW) return CallWindowProcW(proc, hwnd, uMsg, wParam, lParam);
1585 else return CallWindowProcA(proc, hwnd, uMsg, wParam, lParam);
1586}
1587
1588static inline BOOL is_autoarrange(const LISTVIEW_INFO *infoPtr)
1589{
1590 return (infoPtr->dwStyle & LVS_AUTOARRANGE) &&
1591 (infoPtr->uView == LV_VIEW_ICON || infoPtr->uView == LV_VIEW_SMALLICON);
1592}
1593
1594static void toggle_checkbox_state(LISTVIEW_INFO *infoPtr, INT nItem)
1595{
1597 if(state == 1 || state == 2)
1598 {
1599 LVITEMW lvitem;
1600 state ^= 3;
1603 LISTVIEW_SetItemState(infoPtr, nItem, &lvitem);
1604 }
1605}
1606
1607/* this should be called after window style got updated,
1608 it used to reset view state to match current window style */
1609static inline void map_style_view(LISTVIEW_INFO *infoPtr)
1610{
1611 switch (infoPtr->dwStyle & LVS_TYPEMASK)
1612 {
1613 case LVS_ICON:
1614 infoPtr->uView = LV_VIEW_ICON;
1615 break;
1616 case LVS_REPORT:
1617 infoPtr->uView = LV_VIEW_DETAILS;
1618 break;
1619 case LVS_SMALLICON:
1620 infoPtr->uView = LV_VIEW_SMALLICON;
1621 break;
1622 case LVS_LIST:
1623 infoPtr->uView = LV_VIEW_LIST;
1624 }
1625}
1626
1627/* computes next item id value */
1629{
1631
1632 if (count > 0)
1633 {
1634 ITEM_ID *lpID = DPA_GetPtr(infoPtr->hdpaItemIds, count - 1);
1635 return lpID->id + 1;
1636 }
1637 return 0;
1638}
1639
1640/******** Internal API functions ************************************/
1641
1642static inline COLUMN_INFO * LISTVIEW_GetColumnInfo(const LISTVIEW_INFO *infoPtr, INT nSubItem)
1643{
1644 static COLUMN_INFO mainItem;
1645
1646 if (nSubItem == 0 && DPA_GetPtrCount(infoPtr->hdpaColumns) == 0) return &mainItem;
1647 assert (nSubItem >= 0 && nSubItem < DPA_GetPtrCount(infoPtr->hdpaColumns));
1648
1649 /* update cached column rectangles */
1650 if (infoPtr->colRectsDirty)
1651 {
1653 LISTVIEW_INFO *Ptr = (LISTVIEW_INFO*)infoPtr;
1654 INT i;
1655
1656 for (i = 0; i < DPA_GetPtrCount(infoPtr->hdpaColumns); i++) {
1657 info = DPA_GetPtr(infoPtr->hdpaColumns, i);
1658 SendMessageW(infoPtr->hwndHeader, HDM_GETITEMRECT, i, (LPARAM)&info->rcHeader);
1659 }
1660 Ptr->colRectsDirty = FALSE;
1661 }
1662
1663 return DPA_GetPtr(infoPtr->hdpaColumns, nSubItem);
1664}
1665
1667{
1670
1671 if (infoPtr->hwndHeader) return 0;
1672
1673 TRACE("Creating header for list %p\n", infoPtr->hwndSelf);
1674
1675 /* setup creation flags */
1676 dFlags |= (LVS_NOSORTHEADER & infoPtr->dwStyle) ? 0 : HDS_BUTTONS;
1677 dFlags |= (LVS_NOCOLUMNHEADER & infoPtr->dwStyle) ? HDS_HIDDEN : 0;
1678
1680
1681 /* create header */
1682 infoPtr->hwndHeader = CreateWindowW(WC_HEADERW, NULL, dFlags,
1683 0, 0, 0, 0, infoPtr->hwndSelf, NULL, hInst, NULL);
1684 if (!infoPtr->hwndHeader) return -1;
1685
1686 /* set header unicode format */
1688
1689 /* set header font */
1690 SendMessageW(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont, TRUE);
1691
1692 /* set header image list */
1693 if (infoPtr->himlSmall)
1694 SendMessageW(infoPtr->hwndHeader, HDM_SETIMAGELIST, 0, (LPARAM)infoPtr->himlSmall);
1695
1696 LISTVIEW_UpdateSize(infoPtr);
1697
1698 return 0;
1699}
1700
1701static inline void LISTVIEW_GetHeaderRect(const LISTVIEW_INFO *infoPtr, INT nSubItem, LPRECT lprc)
1702{
1703 *lprc = LISTVIEW_GetColumnInfo(infoPtr, nSubItem)->rcHeader;
1704}
1705
1706static inline BOOL LISTVIEW_IsHeaderEnabled(const LISTVIEW_INFO *infoPtr)
1707{
1708 return (infoPtr->uView == LV_VIEW_DETAILS ||
1709 infoPtr->dwLvExStyle & LVS_EX_HEADERINALLVIEWS) &&
1710 !(infoPtr->dwStyle & LVS_NOCOLUMNHEADER);
1711}
1712
1713static inline BOOL LISTVIEW_GetItemW(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem)
1714{
1715 return LISTVIEW_GetItemT(infoPtr, lpLVItem, TRUE);
1716}
1717
1718/* used to handle collapse main item column case */
1719static inline BOOL LISTVIEW_DrawFocusRect(const LISTVIEW_INFO *infoPtr, HDC hdc)
1720{
1721#ifdef __REACTOS__
1722 BOOL Ret = FALSE;
1723
1724 if (infoPtr->rcFocus.left < infoPtr->rcFocus.right)
1725 {
1726 DWORD dwOldBkColor, dwOldTextColor;
1727
1728 dwOldBkColor = SetBkColor(hdc, RGB(255, 255, 255));
1729 dwOldTextColor = SetBkColor(hdc, RGB(0, 0, 0));
1730 Ret = DrawFocusRect(hdc, &infoPtr->rcFocus);
1731 SetBkColor(hdc, dwOldBkColor);
1732 SetBkColor(hdc, dwOldTextColor);
1733 }
1734 return Ret;
1735#else
1736 return (infoPtr->rcFocus.left < infoPtr->rcFocus.right) ?
1737 DrawFocusRect(hdc, &infoPtr->rcFocus) : FALSE;
1738#endif
1739}
1740
1741/* Listview invalidation functions: use _only_ these functions to invalidate */
1742
1743static inline BOOL is_redrawing(const LISTVIEW_INFO *infoPtr)
1744{
1745 return infoPtr->redraw;
1746}
1747
1748static inline void LISTVIEW_InvalidateRect(const LISTVIEW_INFO *infoPtr, const RECT* rect)
1749{
1750 if(!is_redrawing(infoPtr)) return;
1751 TRACE(" invalidating rect=%s\n", wine_dbgstr_rect(rect));
1752 InvalidateRect(infoPtr->hwndSelf, rect, TRUE);
1753}
1754
1755static inline void LISTVIEW_InvalidateItem(const LISTVIEW_INFO *infoPtr, INT nItem)
1756{
1757 RECT rcBox;
1758
1759 if (!is_redrawing(infoPtr) || nItem < 0 || nItem >= infoPtr->nItemCount)
1760 return;
1761
1762 LISTVIEW_GetItemBox(infoPtr, nItem, &rcBox);
1763 LISTVIEW_InvalidateRect(infoPtr, &rcBox);
1764}
1765
1766static inline void LISTVIEW_InvalidateSubItem(const LISTVIEW_INFO *infoPtr, INT nItem, INT nSubItem)
1767{
1768 POINT Origin, Position;
1769 RECT rcBox;
1770
1771 if(!is_redrawing(infoPtr)) return;
1772 assert (infoPtr->uView == LV_VIEW_DETAILS);
1773 LISTVIEW_GetOrigin(infoPtr, &Origin);
1774 LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position);
1775 LISTVIEW_GetHeaderRect(infoPtr, nSubItem, &rcBox);
1776 rcBox.top = 0;
1777 rcBox.bottom = infoPtr->nItemHeight;
1778 OffsetRect(&rcBox, Origin.x, Origin.y + Position.y);
1779 LISTVIEW_InvalidateRect(infoPtr, &rcBox);
1780}
1781
1782static inline void LISTVIEW_InvalidateList(const LISTVIEW_INFO *infoPtr)
1783{
1784 LISTVIEW_InvalidateRect(infoPtr, NULL);
1785}
1786
1787static inline void LISTVIEW_InvalidateColumn(const LISTVIEW_INFO *infoPtr, INT nColumn)
1788{
1789 RECT rcCol;
1790
1791 if(!is_redrawing(infoPtr)) return;
1792 LISTVIEW_GetHeaderRect(infoPtr, nColumn, &rcCol);
1793 rcCol.top = infoPtr->rcList.top;
1794 rcCol.bottom = infoPtr->rcList.bottom;
1795 LISTVIEW_InvalidateRect(infoPtr, &rcCol);
1796}
1797
1798/***
1799 * DESCRIPTION:
1800 * Retrieves the number of items that can fit vertically in the client area.
1801 *
1802 * PARAMETER(S):
1803 * [I] infoPtr : valid pointer to the listview structure
1804 *
1805 * RETURN:
1806 * Number of items per row.
1807 */
1808static inline INT LISTVIEW_GetCountPerRow(const LISTVIEW_INFO *infoPtr)
1809{
1810 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
1811
1812 return max(nListWidth/(infoPtr->nItemWidth ? infoPtr->nItemWidth : 1), 1);
1813}
1814
1815/***
1816 * DESCRIPTION:
1817 * Retrieves the number of items that can fit horizontally in the client
1818 * area.
1819 *
1820 * PARAMETER(S):
1821 * [I] infoPtr : valid pointer to the listview structure
1822 *
1823 * RETURN:
1824 * Number of items per column.
1825 */
1826static inline INT LISTVIEW_GetCountPerColumn(const LISTVIEW_INFO *infoPtr)
1827{
1828 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
1829
1830 return infoPtr->nItemHeight ? max(nListHeight / infoPtr->nItemHeight, 1) : 0;
1831}
1832
1833
1834/*************************************************************************
1835 * LISTVIEW_ProcessLetterKeys
1836 *
1837 * Processes keyboard messages generated by pressing the letter keys
1838 * on the keyboard.
1839 * What this does is perform a case insensitive search from the
1840 * current position with the following quirks:
1841 * - If two chars or more are pressed in quick succession we search
1842 * for the corresponding string (e.g. 'abc').
1843 * - If there is a delay we wipe away the current search string and
1844 * restart with just that char.
1845 * - If the user keeps pressing the same character, whether slowly or
1846 * fast, so that the search string is entirely composed of this
1847 * character ('aaaaa' for instance), then we search for first item
1848 * that starting with that character.
1849 * - If the user types the above character in quick succession, then
1850 * we must also search for the corresponding string ('aaaaa'), and
1851 * go to that string if there is a match.
1852 *
1853 * PARAMETERS
1854 * [I] hwnd : handle to the window
1855 * [I] charCode : the character code, the actual character
1856 * [I] keyData : key data
1857 *
1858 * RETURNS
1859 *
1860 * Zero.
1861 *
1862 * BUGS
1863 *
1864 * - The current implementation has a list of characters it will
1865 * accept and it ignores everything else. In particular it will
1866 * ignore accentuated characters which seems to match what
1867 * Windows does. But I'm not sure it makes sense to follow
1868 * Windows there.
1869 * - We don't sound a beep when the search fails.
1870 *
1871 * SEE ALSO
1872 *
1873 * TREEVIEW_ProcessLetterKeys
1874 */
1875static INT LISTVIEW_ProcessLetterKeys(LISTVIEW_INFO *infoPtr, WPARAM charCode, LPARAM keyData)
1876{
1878 DWORD prevTime;
1879 LVITEMW item;
1880 int startidx;
1881 INT nItem;
1882 INT diff;
1883
1884 /* simple parameter checking */
1885 if (!charCode || !keyData || infoPtr->nItemCount == 0) return 0;
1886
1887 /* only allow the valid WM_CHARs through */
1888 if (!iswalnum(charCode) &&
1889 charCode != '.' && charCode != '`' && charCode != '!' &&
1890 charCode != '@' && charCode != '#' && charCode != '$' &&
1891 charCode != '%' && charCode != '^' && charCode != '&' &&
1892 charCode != '*' && charCode != '(' && charCode != ')' &&
1893 charCode != '-' && charCode != '_' && charCode != '+' &&
1894 charCode != '=' && charCode != '\\'&& charCode != ']' &&
1895 charCode != '}' && charCode != '[' && charCode != '{' &&
1896 charCode != '/' && charCode != '?' && charCode != '>' &&
1897 charCode != '<' && charCode != ',' && charCode != '~')
1898 return 0;
1899
1900 /* update the search parameters */
1901 prevTime = infoPtr->lastKeyPressTimestamp;
1903 diff = infoPtr->lastKeyPressTimestamp - prevTime;
1904
1905 if (diff >= 0 && diff < KEY_DELAY)
1906 {
1907 if (infoPtr->nSearchParamLength < MAX_PATH - 1)
1908 infoPtr->szSearchParam[infoPtr->nSearchParamLength++] = charCode;
1909
1910 if (infoPtr->charCode != charCode)
1911 infoPtr->charCode = charCode = 0;
1912 }
1913 else
1914 {
1915 infoPtr->charCode = charCode;
1916 infoPtr->szSearchParam[0] = charCode;
1917 infoPtr->nSearchParamLength = 1;
1918 }
1919
1920 /* should start from next after focused item, so next item that matches
1921 will be selected, if there isn't any and focused matches it will be selected
1922 on second search stage from beginning of the list */
1923 if (infoPtr->nFocusedItem >= 0 && infoPtr->nItemCount > 1)
1924 {
1925 /* with some accumulated search data available start with current focus, otherwise
1926 it's excluded from search */
1927 startidx = infoPtr->nSearchParamLength > 1 ? infoPtr->nFocusedItem : infoPtr->nFocusedItem + 1;
1928 if (startidx == infoPtr->nItemCount) startidx = 0;
1929 }
1930 else
1931 startidx = 0;
1932
1933 /* let application handle this for virtual listview */
1934 if (infoPtr->dwStyle & LVS_OWNERDATA)
1935 {
1936 NMLVFINDITEMW nmlv;
1937
1938 memset(&nmlv.lvfi, 0, sizeof(nmlv.lvfi));
1939 nmlv.lvfi.flags = (LVFI_WRAP | LVFI_PARTIAL);
1940 nmlv.lvfi.psz = infoPtr->szSearchParam;
1941 nmlv.iStart = startidx;
1942
1943 infoPtr->szSearchParam[infoPtr->nSearchParamLength] = 0;
1944
1945 nItem = notify_hdr(infoPtr, LVN_ODFINDITEMW, (LPNMHDR)&nmlv.hdr);
1946 }
1947 else
1948 {
1949 int i = startidx, endidx;
1950
1951 /* and search from the current position */
1952 nItem = -1;
1953 endidx = infoPtr->nItemCount;
1954
1955 /* first search in [startidx, endidx), on failure continue in [0, startidx) */
1956 while (1)
1957 {
1958 /* start from first item if not found with >= startidx */
1959 if (i == infoPtr->nItemCount && startidx > 0)
1960 {
1961 endidx = startidx;
1962 startidx = 0;
1963 }
1964
1965 for (i = startidx; i < endidx; i++)
1966 {
1967 /* retrieve text */
1968 item.mask = LVIF_TEXT;
1969 item.iItem = i;
1970 item.iSubItem = 0;
1971 item.pszText = buffer;
1972 item.cchTextMax = MAX_PATH;
1973 if (!LISTVIEW_GetItemW(infoPtr, &item)) return 0;
1974
1975 if (!lstrncmpiW(item.pszText, infoPtr->szSearchParam, infoPtr->nSearchParamLength))
1976 {
1977 nItem = i;
1978 break;
1979 }
1980 /* this is used to find first char match when search string is not available yet,
1981 otherwise every WM_CHAR will search to next item by first char, ignoring that we're
1982 already waiting for user to complete a string */
1983 else if (nItem == -1 && infoPtr->nSearchParamLength == 1 && !lstrncmpiW(item.pszText, infoPtr->szSearchParam, 1))
1984 {
1985 /* this would work but we must keep looking for a longer match */
1986 nItem = i;
1987 }
1988 }
1989
1990 if ( nItem != -1 || /* found something */
1991 endidx != infoPtr->nItemCount || /* second search done */
1992 (startidx == 0 && endidx == infoPtr->nItemCount) /* full range for first search */ )
1993 break;
1994 };
1995 }
1996
1997 if (nItem != -1)
1998 LISTVIEW_KeySelection(infoPtr, nItem, FALSE);
1999
2000 return 0;
2001}
2002
2003/*************************************************************************
2004 * LISTVIEW_UpdateHeaderSize [Internal]
2005 *
2006 * Function to resize the header control
2007 *
2008 * PARAMS
2009 * [I] hwnd : handle to a window
2010 * [I] nNewScrollPos : scroll pos to set
2011 *
2012 * RETURNS
2013 * None.
2014 */
2015static void LISTVIEW_UpdateHeaderSize(const LISTVIEW_INFO *infoPtr, INT nNewScrollPos)
2016{
2017 RECT winRect;
2018 POINT point[2];
2019
2020 TRACE("nNewScrollPos=%d\n", nNewScrollPos);
2021
2022 if (!infoPtr->hwndHeader) return;
2023
2024 GetWindowRect(infoPtr->hwndHeader, &winRect);
2025 point[0].x = winRect.left;
2026 point[0].y = winRect.top;
2027 point[1].x = winRect.right;
2028 point[1].y = winRect.bottom;
2029
2031 point[0].x = -nNewScrollPos;
2032 point[1].x += nNewScrollPos;
2033
2034 SetWindowPos(infoPtr->hwndHeader,0,
2035 point[0].x,point[0].y,point[1].x,point[1].y,
2038}
2039
2041{
2042 SCROLLINFO horzInfo;
2043 INT dx;
2044
2045 ZeroMemory(&horzInfo, sizeof(SCROLLINFO));
2046 horzInfo.cbSize = sizeof(SCROLLINFO);
2047 horzInfo.nPage = infoPtr->rcList.right - infoPtr->rcList.left;
2048
2049 /* for now, we'll set info.nMax to the _count_, and adjust it later */
2050 if (infoPtr->uView == LV_VIEW_LIST)
2051 {
2052 INT nPerCol = LISTVIEW_GetCountPerColumn(infoPtr);
2053 horzInfo.nMax = (infoPtr->nItemCount + nPerCol - 1) / nPerCol;
2054
2055 /* scroll by at least one column per page */
2056 if(horzInfo.nPage < infoPtr->nItemWidth)
2057 horzInfo.nPage = infoPtr->nItemWidth;
2058
2059 if (infoPtr->nItemWidth)
2060 horzInfo.nPage /= infoPtr->nItemWidth;
2061 }
2062 else if (infoPtr->uView == LV_VIEW_DETAILS)
2063 {
2064 horzInfo.nMax = infoPtr->nItemWidth;
2065 }
2066 else /* LV_VIEW_ICON, or LV_VIEW_SMALLICON */
2067 {
2068 RECT rcView;
2069
2070 if (LISTVIEW_GetViewRect(infoPtr, &rcView)) horzInfo.nMax = rcView.right - rcView.left;
2071 }
2072
2073 if (LISTVIEW_IsHeaderEnabled(infoPtr))
2074 {
2075 if (DPA_GetPtrCount(infoPtr->hdpaColumns))
2076 {
2077 RECT rcHeader;
2078 INT index;
2079
2081 DPA_GetPtrCount(infoPtr->hdpaColumns) - 1, 0);
2082
2083 LISTVIEW_GetHeaderRect(infoPtr, index, &rcHeader);
2084 horzInfo.nMax = rcHeader.right;
2085 TRACE("horzInfo.nMax=%d\n", horzInfo.nMax);
2086 }
2087 }
2088
2089 horzInfo.fMask = SIF_RANGE | SIF_PAGE;
2090 horzInfo.nMax = max(horzInfo.nMax - 1, 0);
2091#ifdef __REACTOS__ /* CORE-16466 part 1 of 4 */
2092 horzInfo.nMax = (horzInfo.nPage == 0 ? 0 : horzInfo.nMax);
2093#endif
2094 dx = GetScrollPos(infoPtr->hwndSelf, SB_HORZ);
2095 dx -= SetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &horzInfo, TRUE);
2096 TRACE("horzInfo=%s\n", debugscrollinfo(&horzInfo));
2097
2098 /* Update the Header Control */
2099 if (infoPtr->hwndHeader)
2100 {
2101 horzInfo.fMask = SIF_POS;
2102 GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &horzInfo);
2103 LISTVIEW_UpdateHeaderSize(infoPtr, horzInfo.nPos);
2104 }
2105
2106 LISTVIEW_UpdateSize(infoPtr);
2107 return dx;
2108}
2109
2111{
2112 SCROLLINFO vertInfo;
2113 INT dy;
2114
2115 ZeroMemory(&vertInfo, sizeof(SCROLLINFO));
2116 vertInfo.cbSize = sizeof(SCROLLINFO);
2117#ifdef __REACTOS__ /* CORE-16466 part 2 of 4 */
2118 vertInfo.nPage = max(0, infoPtr->rcList.bottom - infoPtr->rcList.top);
2119#else
2120 vertInfo.nPage = infoPtr->rcList.bottom - infoPtr->rcList.top;
2121#endif
2122
2123 if (infoPtr->uView == LV_VIEW_DETAILS)
2124 {
2125#ifdef __REACTOS__ /* CORE-16466 part 3a of 4 */
2126 if (vertInfo.nPage != 0)
2127 {
2128#endif
2129 vertInfo.nMax = infoPtr->nItemCount;
2130
2131 /* scroll by at least one page */
2132 if(vertInfo.nPage < infoPtr->nItemHeight)
2133 vertInfo.nPage = infoPtr->nItemHeight;
2134
2135 if (infoPtr->nItemHeight > 0)
2136 vertInfo.nPage /= infoPtr->nItemHeight;
2137#ifdef __REACTOS__ /* CORE-16466 part 3b of 4 */
2138 }
2139#endif
2140 }
2141 else if (infoPtr->uView != LV_VIEW_LIST) /* LV_VIEW_ICON, or LV_VIEW_SMALLICON */
2142 {
2143 RECT rcView;
2144
2145 if (LISTVIEW_GetViewRect(infoPtr, &rcView)) vertInfo.nMax = rcView.bottom - rcView.top;
2146 }
2147
2148 vertInfo.fMask = SIF_RANGE | SIF_PAGE;
2149 vertInfo.nMax = max(vertInfo.nMax - 1, 0);
2150#ifdef __REACTOS__ /* CORE-16466 part 4 of 4 */
2151 vertInfo.nMax = (vertInfo.nPage == 0 ? 0 : vertInfo.nMax);
2152#endif
2153 dy = GetScrollPos(infoPtr->hwndSelf, SB_VERT);
2154 dy -= SetScrollInfo(infoPtr->hwndSelf, SB_VERT, &vertInfo, TRUE);
2155 TRACE("vertInfo=%s\n", debugscrollinfo(&vertInfo));
2156
2157 LISTVIEW_UpdateSize(infoPtr);
2158 return dy;
2159}
2160
2161/***
2162 * DESCRIPTION:
2163 * Update the scrollbars. This function should be called whenever
2164 * the content, size or view changes.
2165 *
2166 * PARAMETER(S):
2167 * [I] infoPtr : valid pointer to the listview structure
2168 *
2169 * RETURN:
2170 * None
2171 */
2173{
2174 INT dx, dy, pass;
2175
2176 if ((infoPtr->dwStyle & LVS_NOSCROLL) || !is_redrawing(infoPtr)) return;
2177
2178 /* Setting the horizontal scroll can change the listview size
2179 * (and potentially everything else) so we need to recompute
2180 * everything again for the vertical scroll and vice-versa
2181 */
2182 for (dx = 0, dy = 0, pass = 0; pass <= 1; pass++)
2183 {
2184 dx += LISTVIEW_UpdateHScroll(infoPtr);
2185 dy += LISTVIEW_UpdateVScroll(infoPtr);
2186 }
2187
2188 /* Change of the range may have changed the scroll pos. If so move the content */
2189 if (dx != 0 || dy != 0)
2190 {
2191 RECT listRect;
2192 listRect = infoPtr->rcList;
2193 ScrollWindowEx(infoPtr->hwndSelf, dx, dy, &listRect, &listRect, 0, 0,
2195 }
2196}
2197
2198
2199/***
2200 * DESCRIPTION:
2201 * Shows/hides the focus rectangle.
2202 *
2203 * PARAMETER(S):
2204 * [I] infoPtr : valid pointer to the listview structure
2205 * [I] fShow : TRUE to show the focus, FALSE to hide it.
2206 *
2207 * RETURN:
2208 * None
2209 */
2210static void LISTVIEW_ShowFocusRect(const LISTVIEW_INFO *infoPtr, BOOL fShow)
2211{
2212 HDC hdc;
2213
2214 TRACE("fShow=%d, nItem=%d\n", fShow, infoPtr->nFocusedItem);
2215
2216 if (infoPtr->nFocusedItem < 0) return;
2217
2218 /* we need some gymnastics in ICON mode to handle large items */
2219 if (infoPtr->uView == LV_VIEW_ICON)
2220 {
2221 RECT rcBox;
2222
2223 LISTVIEW_GetItemBox(infoPtr, infoPtr->nFocusedItem, &rcBox);
2224 if ((rcBox.bottom - rcBox.top) > infoPtr->nItemHeight)
2225 {
2226 LISTVIEW_InvalidateRect(infoPtr, &rcBox);
2227 return;
2228 }
2229 }
2230
2231 if (!(hdc = GetDC(infoPtr->hwndSelf))) return;
2232
2233 /* for some reason, owner draw should work only in report mode */
2234 if ((infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && (infoPtr->uView == LV_VIEW_DETAILS))
2235 {
2236 DRAWITEMSTRUCT dis;
2237 LVITEMW item;
2238
2239 HFONT hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
2240 HFONT hOldFont = SelectObject(hdc, hFont);
2241
2242 item.iItem = infoPtr->nFocusedItem;
2243 item.iSubItem = 0;
2244 item.mask = LVIF_PARAM;
2245 if (!LISTVIEW_GetItemW(infoPtr, &item)) goto done;
2246
2247 ZeroMemory(&dis, sizeof(dis));
2248 dis.CtlType = ODT_LISTVIEW;
2249 dis.CtlID = (UINT)GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
2250 dis.itemID = item.iItem;
2251 dis.itemAction = ODA_FOCUS;
2252 if (fShow) dis.itemState |= ODS_FOCUS;
2253 dis.hwndItem = infoPtr->hwndSelf;
2254 dis.hDC = hdc;
2255 LISTVIEW_GetItemBox(infoPtr, dis.itemID, &dis.rcItem);
2256 dis.itemData = item.lParam;
2257
2258 SendMessageW(infoPtr->hwndNotify, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis);
2259
2260 SelectObject(hdc, hOldFont);
2261 }
2262 else
2263 LISTVIEW_InvalidateItem(infoPtr, infoPtr->nFocusedItem);
2264
2265done:
2266 ReleaseDC(infoPtr->hwndSelf, hdc);
2267}
2268
2269/***
2270 * Invalidates all visible selected items.
2271 */
2273{
2274 ITERATOR i;
2275
2276 iterator_frameditems(&i, infoPtr, &infoPtr->rcList);
2277 while(iterator_next(&i))
2278 {
2279#ifdef __REACTOS__
2280 if (LISTVIEW_GetItemState(infoPtr, i.nItem, LVIS_SELECTED | LVIS_CUT))
2281#else
2282 if (LISTVIEW_GetItemState(infoPtr, i.nItem, LVIS_SELECTED))
2283#endif
2284 LISTVIEW_InvalidateItem(infoPtr, i.nItem);
2285 }
2287}
2288
2289
2290/***
2291 * DESCRIPTION: [INTERNAL]
2292 * Computes an item's (left,top) corner, relative to rcView.
2293 * That is, the position has NOT been made relative to the Origin.
2294 * This is deliberate, to avoid computing the Origin over, and
2295 * over again, when this function is called in a loop. Instead,
2296 * one can factor the computation of the Origin before the loop,
2297 * and offset the value returned by this function, on every iteration.
2298 *
2299 * PARAMETER(S):
2300 * [I] infoPtr : valid pointer to the listview structure
2301 * [I] nItem : item number
2302 * [O] lpptOrig : item top, left corner
2303 *
2304 * RETURN:
2305 * None.
2306 */
2307static void LISTVIEW_GetItemOrigin(const LISTVIEW_INFO *infoPtr, INT nItem, LPPOINT lpptPosition)
2308{
2309 assert(nItem >= 0 && nItem < infoPtr->nItemCount);
2310
2311 if ((infoPtr->uView == LV_VIEW_SMALLICON) || (infoPtr->uView == LV_VIEW_ICON))
2312 {
2313 lpptPosition->x = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosX, nItem);
2314 lpptPosition->y = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosY, nItem);
2315 }
2316 else if (infoPtr->uView == LV_VIEW_LIST)
2317 {
2318 INT nCountPerColumn = LISTVIEW_GetCountPerColumn(infoPtr);
2319 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
2320 lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight;
2321 }
2322 else /* LV_VIEW_DETAILS */
2323 {
2324 lpptPosition->x = REPORT_MARGINX;
2325 /* item is always at zero indexed column */
2326 if (DPA_GetPtrCount(infoPtr->hdpaColumns) > 0)
2327 lpptPosition->x += LISTVIEW_GetColumnInfo(infoPtr, 0)->rcHeader.left;
2328 lpptPosition->y = nItem * infoPtr->nItemHeight;
2329 }
2330}
2331
2332/***
2333 * DESCRIPTION: [INTERNAL]
2334 * Compute the rectangles of an item. This is to localize all
2335 * the computations in one place. If you are not interested in some
2336 * of these values, simply pass in a NULL -- the function is smart
2337 * enough to compute only what's necessary. The function computes
2338 * the standard rectangles (BOUNDS, ICON, LABEL) plus a non-standard
2339 * one, the BOX rectangle. This rectangle is very cheap to compute,
2340 * and is guaranteed to contain all the other rectangles. Computing
2341 * the ICON rect is also cheap, but all the others are potentially
2342 * expensive. This gives an easy and effective optimization when
2343 * searching (like point inclusion, or rectangle intersection):
2344 * first test against the BOX, and if TRUE, test against the desired
2345 * rectangle.
2346 * If the function does not have all the necessary information
2347 * to computed the requested rectangles, will crash with a
2348 * failed assertion. This is done so we catch all programming
2349 * errors, given that the function is called only from our code.
2350 *
2351 * We have the following 'special' meanings for a few fields:
2352 * * If LVIS_FOCUSED is set, we assume the item has the focus
2353 * This is important in ICON mode, where it might get a larger
2354 * then usual rectangle
2355 *
2356 * Please note that subitem support works only in REPORT mode.
2357 *
2358 * PARAMETER(S):
2359 * [I] infoPtr : valid pointer to the listview structure
2360 * [I] lpLVItem : item to compute the measures for
2361 * [O] lprcBox : ptr to Box rectangle
2362 * Same as LVM_GETITEMRECT with LVIR_BOUNDS
2363 * [0] lprcSelectBox : ptr to select box rectangle
2364 * Same as LVM_GETITEMRECT with LVIR_SELECTEDBOUNDS
2365 * [O] lprcIcon : ptr to Icon rectangle
2366 * Same as LVM_GETITEMRECT with LVIR_ICON
2367 * [O] lprcStateIcon: ptr to State Icon rectangle
2368 * [O] lprcLabel : ptr to Label rectangle
2369 * Same as LVM_GETITEMRECT with LVIR_LABEL
2370 *
2371 * RETURN:
2372 * None.
2373 */
2374static void LISTVIEW_GetItemMetrics(const LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem,
2375 LPRECT lprcBox, LPRECT lprcSelectBox,
2376 LPRECT lprcIcon, LPRECT lprcStateIcon, LPRECT lprcLabel)
2377{
2378 BOOL doSelectBox = FALSE, doIcon = FALSE, doLabel = FALSE, oversizedBox = FALSE;
2379 RECT Box, SelectBox, Icon, Label;
2380 COLUMN_INFO *lpColumnInfo = NULL;
2381 SIZE labelSize = { 0, 0 };
2382
2383 TRACE("(lpLVItem=%s)\n", debuglvitem_t(lpLVItem, TRUE));
2384
2385 /* Be smart and try to figure out the minimum we have to do */
2386 if (lpLVItem->iSubItem) assert(infoPtr->uView == LV_VIEW_DETAILS);
2387 if (infoPtr->uView == LV_VIEW_ICON && (lprcBox || lprcLabel))
2388 {
2389 assert((lpLVItem->mask & LVIF_STATE) && (lpLVItem->stateMask & LVIS_FOCUSED));
2390 if (lpLVItem->state & LVIS_FOCUSED) oversizedBox = doLabel = TRUE;
2391 }
2392 if (lprcSelectBox) doSelectBox = TRUE;
2393 if (lprcLabel) doLabel = TRUE;
2394 if (doLabel || lprcIcon || lprcStateIcon) doIcon = TRUE;
2395 if (doSelectBox)
2396 {
2397 doIcon = TRUE;
2398 doLabel = TRUE;
2399 }
2400
2401 /************************************************************/
2402 /* compute the box rectangle (it should be cheap to do) */
2403 /************************************************************/
2404 if (lpLVItem->iSubItem || infoPtr->uView == LV_VIEW_DETAILS)
2405 lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, lpLVItem->iSubItem);
2406
2407 if (lpLVItem->iSubItem)
2408 {
2409 Box = lpColumnInfo->rcHeader;
2410 }
2411 else
2412 {
2413 Box.left = 0;
2414 Box.right = infoPtr->nItemWidth;
2415 }
2416 Box.top = 0;
2417 Box.bottom = infoPtr->nItemHeight;
2418
2419 /******************************************************************/
2420 /* compute ICON bounding box (ala LVM_GETITEMRECT) and STATEICON */
2421 /******************************************************************/
2422 if (doIcon)
2423 {
2424 LONG state_width = 0;
2425
2426 if (infoPtr->himlState && lpLVItem->iSubItem == 0)
2427 state_width = infoPtr->iconStateSize.cx;
2428
2429 if (infoPtr->uView == LV_VIEW_ICON)
2430 {
2431 Icon.left = Box.left + state_width;
2432 if (infoPtr->himlNormal)
2433 Icon.left += (infoPtr->nItemWidth - infoPtr->iconSize.cx - state_width) / 2;
2434 Icon.top = Box.top + ICON_TOP_PADDING;
2435 Icon.right = Icon.left;
2436 Icon.bottom = Icon.top;
2437 if (infoPtr->himlNormal)
2438 {
2439 Icon.right += infoPtr->iconSize.cx;
2440 Icon.bottom += infoPtr->iconSize.cy;
2441 }
2442 }
2443 else /* LV_VIEW_SMALLICON, LV_VIEW_LIST or LV_VIEW_DETAILS */
2444 {
2445 Icon.left = Box.left + state_width;
2446
2447 if (infoPtr->uView == LV_VIEW_DETAILS && lpLVItem->iSubItem == 0)
2448 {
2449 /* we need the indent in report mode */
2450 assert(lpLVItem->mask & LVIF_INDENT);
2451 Icon.left += infoPtr->iconSize.cx * lpLVItem->iIndent + REPORT_MARGINX;
2452 }
2453
2454 Icon.top = Box.top;
2455 Icon.right = Icon.left;
2456 if (infoPtr->himlSmall &&
2457 (!lpColumnInfo || lpLVItem->iSubItem == 0 ||
2458 ((infoPtr->dwLvExStyle & LVS_EX_SUBITEMIMAGES) && lpLVItem->iImage != I_IMAGECALLBACK)))
2459 Icon.right += infoPtr->iconSize.cx;
2460 Icon.bottom = Icon.top + infoPtr->iconSize.cy;
2461 }
2462 if(lprcIcon) *lprcIcon = Icon;
2463 TRACE(" - icon=%s\n", wine_dbgstr_rect(&Icon));
2464
2465 /* TODO: is this correct? */
2466 if (lprcStateIcon)
2467 {
2468 lprcStateIcon->left = Icon.left - state_width;
2469 lprcStateIcon->right = Icon.left;
2470 lprcStateIcon->top = Icon.top;
2471 lprcStateIcon->bottom = lprcStateIcon->top + infoPtr->iconSize.cy;
2472 TRACE(" - state icon=%s\n", wine_dbgstr_rect(lprcStateIcon));
2473 }
2474 }
2475 else Icon.right = 0;
2476
2477 /************************************************************/
2478 /* compute LABEL bounding box (ala LVM_GETITEMRECT) */
2479 /************************************************************/
2480 if (doLabel)
2481 {
2482 /* calculate how far to the right can the label stretch */
2483 Label.right = Box.right;
2484 if (infoPtr->uView == LV_VIEW_DETAILS)
2485 {
2486 if (lpLVItem->iSubItem == 0)
2487 {
2488 /* we need a zero based rect here */
2489 Label = lpColumnInfo->rcHeader;
2490 OffsetRect(&Label, -Label.left, 0);
2491 }
2492 }
2493
2494 if (lpLVItem->iSubItem || ((infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && infoPtr->uView == LV_VIEW_DETAILS))
2495 {
2496 labelSize.cx = infoPtr->nItemWidth;
2497 labelSize.cy = infoPtr->nItemHeight;
2498 goto calc_label;
2499 }
2500
2501 /* we need the text in non owner draw mode */
2502 assert(lpLVItem->mask & LVIF_TEXT);
2503 if (is_text(lpLVItem->pszText))
2504 {
2505 HFONT hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
2506 HDC hdc = GetDC(infoPtr->hwndSelf);
2507 HFONT hOldFont = SelectObject(hdc, hFont);
2508 UINT uFormat;
2509 RECT rcText;
2510
2511 /* compute rough rectangle where the label will go */
2512 SetRectEmpty(&rcText);
2513 rcText.right = infoPtr->nItemWidth - TRAILING_LABEL_PADDING;
2514 rcText.bottom = infoPtr->nItemHeight;
2515 if (infoPtr->uView == LV_VIEW_ICON)
2516 rcText.bottom -= ICON_TOP_PADDING + infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
2517
2518 /* now figure out the flags */
2519 if (infoPtr->uView == LV_VIEW_ICON)
2520 uFormat = oversizedBox ? LV_FL_DT_FLAGS : LV_ML_DT_FLAGS;
2521 else
2522 uFormat = LV_SL_DT_FLAGS;
2523
2524 DrawTextW (hdc, lpLVItem->pszText, -1, &rcText, uFormat | DT_CALCRECT);
2525
2526 if (rcText.right != rcText.left)
2527 labelSize.cx = min(rcText.right - rcText.left + TRAILING_LABEL_PADDING, infoPtr->nItemWidth);
2528
2529 labelSize.cy = rcText.bottom - rcText.top;
2530
2531 SelectObject(hdc, hOldFont);
2532 ReleaseDC(infoPtr->hwndSelf, hdc);
2533 }
2534
2535calc_label:
2536 if (infoPtr->uView == LV_VIEW_ICON)
2537 {
2538 Label.left = Box.left + (infoPtr->nItemWidth - labelSize.cx) / 2;
2539 Label.top = Box.top + ICON_TOP_PADDING_HITABLE +
2540 infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
2541 Label.right = Label.left + labelSize.cx;
2542 Label.bottom = Label.top + infoPtr->nItemHeight;
2543 if (!oversizedBox && labelSize.cy > infoPtr->ntmHeight)
2544 {
2545 labelSize.cy = min(Box.bottom - Label.top, labelSize.cy);
2546 labelSize.cy /= infoPtr->ntmHeight;
2547 labelSize.cy = max(labelSize.cy, 1);
2548 labelSize.cy *= infoPtr->ntmHeight;
2549 }
2550 Label.bottom = Label.top + labelSize.cy + HEIGHT_PADDING;
2551 }
2552 else if (infoPtr->uView == LV_VIEW_DETAILS)
2553 {
2554 Label.left = Icon.right;
2555 Label.top = Box.top;
2556 Label.right = lpLVItem->iSubItem ? lpColumnInfo->rcHeader.right :
2557 lpColumnInfo->rcHeader.right - lpColumnInfo->rcHeader.left;
2558 Label.bottom = Label.top + infoPtr->nItemHeight;
2559 }
2560 else /* LV_VIEW_SMALLICON or LV_VIEW_LIST */
2561 {
2562 Label.left = Icon.right;
2563 Label.top = Box.top;
2564 Label.right = min(Label.left + labelSize.cx, Label.right);
2565 Label.bottom = Label.top + infoPtr->nItemHeight;
2566 }
2567
2568 if (lprcLabel) *lprcLabel = Label;
2569 TRACE(" - label=%s\n", wine_dbgstr_rect(&Label));
2570 }
2571
2572 /************************************************************/
2573 /* compute SELECT bounding box */
2574 /************************************************************/
2575 if (doSelectBox)
2576 {
2577 if (infoPtr->uView == LV_VIEW_DETAILS)
2578 {
2579 SelectBox.left = Icon.left;
2580 SelectBox.top = Box.top;
2581 SelectBox.bottom = Box.bottom;
2582
2583 if (labelSize.cx)
2584 SelectBox.right = min(Label.left + labelSize.cx, Label.right);
2585 else
2586 SelectBox.right = min(Label.left + MAX_EMPTYTEXT_SELECT_WIDTH, Label.right);
2587 }
2588 else
2589 {
2590 UnionRect(&SelectBox, &Icon, &Label);
2591 }
2592 if (lprcSelectBox) *lprcSelectBox = SelectBox;
2593 TRACE(" - select box=%s\n", wine_dbgstr_rect(&SelectBox));
2594 }
2595
2596 /* Fix the Box if necessary */
2597 if (lprcBox)
2598 {
2599 if (oversizedBox) UnionRect(lprcBox, &Box, &Label);
2600 else *lprcBox = Box;
2601 }
2602 TRACE(" - box=%s\n", wine_dbgstr_rect(&Box));
2603}
2604
2605/***
2606 * DESCRIPTION: [INTERNAL]
2607 *
2608 * PARAMETER(S):
2609 * [I] infoPtr : valid pointer to the listview structure
2610 * [I] nItem : item number
2611 * [O] lprcBox : ptr to Box rectangle
2612 *
2613 * RETURN:
2614 * None.
2615 */
2616static void LISTVIEW_GetItemBox(const LISTVIEW_INFO *infoPtr, INT nItem, LPRECT lprcBox)
2617{
2618 WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
2619 POINT Position, Origin;
2620 LVITEMW lvItem;
2621
2622 LISTVIEW_GetOrigin(infoPtr, &Origin);
2623 LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position);
2624
2625 /* Be smart and try to figure out the minimum we have to do */
2626 lvItem.mask = 0;
2627 if (infoPtr->uView == LV_VIEW_ICON && infoPtr->bFocus && LISTVIEW_GetItemState(infoPtr, nItem, LVIS_FOCUSED))
2628 lvItem.mask |= LVIF_TEXT;
2629 lvItem.iItem = nItem;
2630 lvItem.iSubItem = 0;
2631 lvItem.pszText = szDispText;
2632 lvItem.cchTextMax = DISP_TEXT_SIZE;
2633 if (lvItem.mask) LISTVIEW_GetItemW(infoPtr, &lvItem);
2634 if (infoPtr->uView == LV_VIEW_ICON)
2635 {
2636 lvItem.mask |= LVIF_STATE;
2637 lvItem.stateMask = LVIS_FOCUSED;
2638 lvItem.state = (lvItem.mask & LVIF_TEXT ? LVIS_FOCUSED : 0);
2639 }
2640 LISTVIEW_GetItemMetrics(infoPtr, &lvItem, lprcBox, 0, 0, 0, 0);
2641
2642 if (infoPtr->uView == LV_VIEW_DETAILS && infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT &&
2643 SendMessageW(infoPtr->hwndHeader, HDM_ORDERTOINDEX, 0, 0))
2644 {
2645 OffsetRect(lprcBox, Origin.x, Position.y + Origin.y);
2646 }
2647 else
2648 OffsetRect(lprcBox, Position.x + Origin.x, Position.y + Origin.y);
2649}
2650
2651/* LISTVIEW_MapIdToIndex helper */
2653{
2654 ITEM_ID *id1 = (ITEM_ID*)p1;
2655 ITEM_ID *id2 = (ITEM_ID*)p2;
2656
2657 if (id1->id == id2->id) return 0;
2658
2659 return (id1->id < id2->id) ? -1 : 1;
2660}
2661
2662/***
2663 * DESCRIPTION:
2664 * Returns the item index for id specified.
2665 *
2666 * PARAMETER(S):
2667 * [I] infoPtr : valid pointer to the listview structure
2668 * [I] iID : item id to get index for
2669 *
2670 * RETURN:
2671 * Item index, or -1 on failure.
2672 */
2673static INT LISTVIEW_MapIdToIndex(const LISTVIEW_INFO *infoPtr, UINT iID)
2674{
2675 ITEM_ID ID;
2676 INT index;
2677
2678 TRACE("iID=%d\n", iID);
2679
2680 if (infoPtr->dwStyle & LVS_OWNERDATA) return -1;
2681 if (infoPtr->nItemCount == 0) return -1;
2682
2683 ID.id = iID;
2685
2686 if (index != -1)
2687 {
2688 ITEM_ID *lpID = DPA_GetPtr(infoPtr->hdpaItemIds, index);
2689 return DPA_GetPtrIndex(infoPtr->hdpaItems, lpID->item);
2690 }
2691
2692 return -1;
2693}
2694
2695/***
2696 * DESCRIPTION:
2697 * Returns the item id for index given.
2698 *
2699 * PARAMETER(S):
2700 * [I] infoPtr : valid pointer to the listview structure
2701 * [I] iItem : item index to get id for
2702 *
2703 * RETURN:
2704 * Item id.
2705 */
2706static DWORD LISTVIEW_MapIndexToId(const LISTVIEW_INFO *infoPtr, INT iItem)
2707{
2708 ITEM_INFO *lpItem;
2709 HDPA hdpaSubItems;
2710
2711 TRACE("iItem=%d\n", iItem);
2712
2713 if (infoPtr->dwStyle & LVS_OWNERDATA) return -1;
2714 if (iItem < 0 || iItem >= infoPtr->nItemCount) return -1;
2715
2716 hdpaSubItems = DPA_GetPtr(infoPtr->hdpaItems, iItem);
2717 lpItem = DPA_GetPtr(hdpaSubItems, 0);
2718
2719 return lpItem->id->id;
2720}
2721
2722/***
2723 * DESCRIPTION:
2724 * Returns the current icon position, and advances it along the top.
2725 * The returned position is not offset by Origin.
2726 *
2727 * PARAMETER(S):
2728 * [I] infoPtr : valid pointer to the listview structure
2729 * [O] lpPos : will get the current icon position
2730 * [I] nItem : item id to get position for
2731 *
2732 * RETURN:
2733 * None
2734 */
2735#ifdef __REACTOS__
2736static void LISTVIEW_NextIconPosTop(LISTVIEW_INFO *infoPtr, LPPOINT lpPos, INT nItem)
2737#else
2739#endif
2740{
2741 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
2742
2743 *lpPos = infoPtr->currIconPos;
2744
2745 infoPtr->currIconPos.x += infoPtr->nItemWidth;
2746 if (infoPtr->currIconPos.x + infoPtr->nItemWidth <= nListWidth) return;
2747
2748 infoPtr->currIconPos.x = 0;
2749 infoPtr->currIconPos.y += infoPtr->nItemHeight;
2750}
2751
2752
2753/***
2754 * DESCRIPTION:
2755 * Returns the current icon position, and advances it down the left edge.
2756 * The returned position is not offset by Origin.
2757 *
2758 * PARAMETER(S):
2759 * [I] infoPtr : valid pointer to the listview structure
2760 * [O] lpPos : will get the current icon position
2761 * [I] nItem : item id to get position for
2762 *
2763 * RETURN:
2764 * None
2765 */
2766#ifdef __REACTOS__
2767static void LISTVIEW_NextIconPosLeft(LISTVIEW_INFO *infoPtr, LPPOINT lpPos, INT nItem)
2768#else
2770#endif
2771{
2772 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2773
2774 *lpPos = infoPtr->currIconPos;
2775
2776 infoPtr->currIconPos.y += infoPtr->nItemHeight;
2777 if (infoPtr->currIconPos.y + infoPtr->nItemHeight <= nListHeight) return;
2778
2779 infoPtr->currIconPos.x += infoPtr->nItemWidth;
2780 infoPtr->currIconPos.y = 0;
2781}
2782
2783
2784#ifdef __REACTOS__
2785/***
2786 * DESCRIPTION:
2787 * Returns the grid position closest to the already placed icon.
2788 * The returned position is not offset by Origin.
2789 *
2790 * PARAMETER(S):
2791 * [I] infoPtr : valid pointer to the listview structure
2792 * [O] lpPos : will get the current icon position
2793 * [I] nItem : item id to get position for
2794 *
2795 * RETURN:
2796 * None
2797 */
2798static void LISTVIEW_NextIconPosSnap(LISTVIEW_INFO *infoPtr, LPPOINT lpPos, INT nItem)
2799{
2800 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2801 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
2802 INT nMaxColumns = nListWidth / infoPtr->nItemWidth;
2803 INT nMaxRows = nListHeight / infoPtr->nItemHeight;
2804 POINT oldPosition;
2805
2806 // get the existing x and y position and then snap to the closest grid square
2807 oldPosition.x = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosX, nItem);
2808 oldPosition.y = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosY, nItem);
2809
2810 // FIXME: This could should deal with multiple icons in the same grid square
2811 // equivalent of max(0, round(oldPosition / itemSize) * itemSize), but without need for 'round' function
2812 (*lpPos).x = max(0, oldPosition.x + (infoPtr->nItemWidth >> 1) - (oldPosition.x + (infoPtr->nItemWidth >> 1)) % infoPtr->nItemWidth);
2813 (*lpPos).y = max(0, oldPosition.y + (infoPtr->nItemHeight >> 1) - (oldPosition.y + (infoPtr->nItemHeight >> 1)) % infoPtr->nItemHeight);
2814
2815 // deal with any icons that have gone out of range
2816 if ((*lpPos).x > nListWidth) (*lpPos).x = nMaxColumns * infoPtr->nItemWidth;
2817 if ((*lpPos).y > nListHeight) (*lpPos).y = nMaxRows * infoPtr->nItemHeight;
2818}
2819#endif
2820
2821
2822/***
2823 * DESCRIPTION:
2824 * Moves an icon to the specified position.
2825 * It takes care of invalidating the item, etc.
2826 *
2827 * PARAMETER(S):
2828 * [I] infoPtr : valid pointer to the listview structure
2829 * [I] nItem : the item to move
2830 * [I] lpPos : the new icon position
2831 * [I] isNew : flags the item as being new
2832 *
2833 * RETURN:
2834 * Success: TRUE
2835 * Failure: FALSE
2836 */
2837static BOOL LISTVIEW_MoveIconTo(const LISTVIEW_INFO *infoPtr, INT nItem, const POINT *lppt, BOOL isNew)
2838{
2839 POINT old;
2840
2841 if (!isNew)
2842 {
2843 old.x = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosX, nItem);
2844 old.y = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosY, nItem);
2845
2846 if (lppt->x == old.x && lppt->y == old.y) return TRUE;
2847 LISTVIEW_InvalidateItem(infoPtr, nItem);
2848 }
2849
2850 /* Allocating a POINTER for every item is too resource intensive,
2851 * so we'll keep the (x,y) in different arrays */
2852 if (!DPA_SetPtr(infoPtr->hdpaPosX, nItem, (void *)(LONG_PTR)lppt->x)) return FALSE;
2853 if (!DPA_SetPtr(infoPtr->hdpaPosY, nItem, (void *)(LONG_PTR)lppt->y)) return FALSE;
2854
2855 LISTVIEW_InvalidateItem(infoPtr, nItem);
2856
2857 return TRUE;
2858}
2859
2860/***
2861 * DESCRIPTION:
2862 * Arranges listview items in icon display mode.
2863 *
2864 * PARAMETER(S):
2865 * [I] infoPtr : valid pointer to the listview structure
2866 * [I] nAlignCode : alignment code
2867 *
2868 * RETURN:
2869 * SUCCESS : TRUE
2870 * FAILURE : FALSE
2871 */
2872static BOOL LISTVIEW_Arrange(LISTVIEW_INFO *infoPtr, INT nAlignCode)
2873{
2874#ifdef __REACTOS__
2875 void (*next_pos)(LISTVIEW_INFO *, LPPOINT, INT);
2876#else
2877 void (*next_pos)(LISTVIEW_INFO *, LPPOINT);
2878#endif
2879 POINT pos;
2880 INT i;
2881
2882 if (infoPtr->uView != LV_VIEW_ICON && infoPtr->uView != LV_VIEW_SMALLICON) return FALSE;
2883
2884 TRACE("nAlignCode=%d\n", nAlignCode);
2885
2886 if (nAlignCode == LVA_DEFAULT)
2887 {
2888 if (infoPtr->dwStyle & LVS_ALIGNLEFT) nAlignCode = LVA_ALIGNLEFT;
2889 else nAlignCode = LVA_ALIGNTOP;
2890 }
2891
2892 switch (nAlignCode)
2893 {
2894 case LVA_ALIGNLEFT: next_pos = LISTVIEW_NextIconPosLeft; break;
2895 case LVA_ALIGNTOP: next_pos = LISTVIEW_NextIconPosTop; break;
2896#ifdef __REACTOS__
2897 case LVA_SNAPTOGRID: next_pos = LISTVIEW_NextIconPosSnap; break;
2898#else
2899 case LVA_SNAPTOGRID: next_pos = LISTVIEW_NextIconPosTop; break; /* FIXME */
2900#endif
2901 default: return FALSE;
2902 }
2903
2904 infoPtr->currIconPos.x = infoPtr->currIconPos.y = 0;
2905 for (i = 0; i < infoPtr->nItemCount; i++)
2906 {
2907#ifdef __REACTOS__
2908 next_pos(infoPtr, &pos, i);
2909#else
2910 next_pos(infoPtr, &pos);
2911#endif
2912 LISTVIEW_MoveIconTo(infoPtr, i, &pos, FALSE);
2913 }
2914
2915 return TRUE;
2916}
2917
2918/***
2919 * DESCRIPTION:
2920 * Retrieves the bounding rectangle of all the items, not offset by Origin.
2921 * For LVS_REPORT always returns empty rectangle.
2922 *
2923 * PARAMETER(S):
2924 * [I] infoPtr : valid pointer to the listview structure
2925 * [O] lprcView : bounding rectangle
2926 *
2927 * RETURN:
2928 * SUCCESS : TRUE
2929 * FAILURE : FALSE
2930 */
2931static void LISTVIEW_GetAreaRect(const LISTVIEW_INFO *infoPtr, LPRECT lprcView)
2932{
2933 INT i, x, y;
2934
2935 SetRectEmpty(lprcView);
2936
2937 switch (infoPtr->uView)
2938 {
2939 case LV_VIEW_ICON:
2940 case LV_VIEW_SMALLICON:
2941 for (i = 0; i < infoPtr->nItemCount; i++)
2942 {
2943 x = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosX, i);
2944 y = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosY, i);
2945 lprcView->right = max(lprcView->right, x);
2946 lprcView->bottom = max(lprcView->bottom, y);
2947 }
2948 if (infoPtr->nItemCount > 0)
2949 {
2950 lprcView->right += infoPtr->nItemWidth;
2951 lprcView->bottom += infoPtr->nItemHeight;
2952 }
2953 break;
2954
2955 case LV_VIEW_LIST:
2956 y = LISTVIEW_GetCountPerColumn(infoPtr);
2957 x = infoPtr->nItemCount / y;
2958 if (infoPtr->nItemCount % y) x++;
2959 lprcView->right = x * infoPtr->nItemWidth;
2960 lprcView->bottom = y * infoPtr->nItemHeight;
2961 break;
2962 }
2963}
2964
2965/***
2966 * DESCRIPTION:
2967 * Retrieves the bounding rectangle of all the items.
2968 *
2969 * PARAMETER(S):
2970 * [I] infoPtr : valid pointer to the listview structure
2971 * [O] lprcView : bounding rectangle
2972 *
2973 * RETURN:
2974 * SUCCESS : TRUE
2975 * FAILURE : FALSE
2976 */
2977static BOOL LISTVIEW_GetViewRect(const LISTVIEW_INFO *infoPtr, LPRECT lprcView)
2978{
2979 POINT ptOrigin;
2980
2981 TRACE("(lprcView=%p)\n", lprcView);
2982
2983 if (!lprcView) return FALSE;
2984
2985 LISTVIEW_GetAreaRect(infoPtr, lprcView);
2986
2987 if (infoPtr->uView != LV_VIEW_DETAILS)
2988 {
2989 LISTVIEW_GetOrigin(infoPtr, &ptOrigin);
2990 OffsetRect(lprcView, ptOrigin.x, ptOrigin.y);
2991 }
2992
2993 TRACE("lprcView=%s\n", wine_dbgstr_rect(lprcView));
2994
2995 return TRUE;
2996}
2997
2998/***
2999 * DESCRIPTION:
3000 * Retrieves the subitem pointer associated with the subitem index.
3001 *
3002 * PARAMETER(S):
3003 * [I] hdpaSubItems : DPA handle for a specific item
3004 * [I] nSubItem : index of subitem
3005 *
3006 * RETURN:
3007 * SUCCESS : subitem pointer
3008 * FAILURE : NULL
3009 */
3010static SUBITEM_INFO* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems, INT nSubItem)
3011{
3012 SUBITEM_INFO *lpSubItem;
3013 INT i;
3014
3015 /* we should binary search here if need be */
3016 for (i = 1; i < DPA_GetPtrCount(hdpaSubItems); i++)
3017 {
3018 lpSubItem = DPA_GetPtr(hdpaSubItems, i);
3019 if (lpSubItem->iSubItem == nSubItem)
3020 return lpSubItem;
3021 }
3022
3023 return NULL;
3024}
3025
3026
3027/***
3028 * DESCRIPTION:
3029 * Calculates the desired item width.
3030 *
3031 * PARAMETER(S):
3032 * [I] infoPtr : valid pointer to the listview structure
3033 *
3034 * RETURN:
3035 * The desired item width.
3036 */
3038{
3039 INT nItemWidth = 0;
3040
3041 TRACE("uView=%d\n", infoPtr->uView);
3042
3043 if (infoPtr->uView == LV_VIEW_ICON)
3044 nItemWidth = infoPtr->iconSpacing.cx;
3045 else if (infoPtr->uView == LV_VIEW_DETAILS)
3046 {
3047 if (DPA_GetPtrCount(infoPtr->hdpaColumns) > 0)
3048 {
3049 RECT rcHeader;
3050 INT index;
3051
3053 DPA_GetPtrCount(infoPtr->hdpaColumns) - 1, 0);
3054
3055 LISTVIEW_GetHeaderRect(infoPtr, index, &rcHeader);
3056 nItemWidth = rcHeader.right;
3057 }
3058 }
3059 else /* LV_VIEW_SMALLICON, or LV_VIEW_LIST */
3060 {
3061 WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
3062 LVITEMW lvItem;
3063 INT i;
3064
3065 lvItem.mask = LVIF_TEXT;
3066 lvItem.iSubItem = 0;
3067
3068 for (i = 0; i < infoPtr->nItemCount; i++)
3069 {
3070 lvItem.iItem = i;
3071 lvItem.pszText = szDispText;
3072 lvItem.cchTextMax = DISP_TEXT_SIZE;
3073 if (LISTVIEW_GetItemW(infoPtr, &lvItem))
3074 nItemWidth = max(LISTVIEW_GetStringWidthT(infoPtr, lvItem.pszText, TRUE),
3075 nItemWidth);
3076 }
3077
3078 if (infoPtr->himlSmall) nItemWidth += infoPtr->iconSize.cx;
3079 if (infoPtr->himlState) nItemWidth += infoPtr->iconStateSize.cx;
3080
3081 nItemWidth = max(DEFAULT_COLUMN_WIDTH, nItemWidth + WIDTH_PADDING);
3082 }
3083
3084 return nItemWidth;
3085}
3086
3087/***
3088 * DESCRIPTION:
3089 * Calculates the desired item height.
3090 *
3091 * PARAMETER(S):
3092 * [I] infoPtr : valid pointer to the listview structure
3093 *
3094 * RETURN:
3095 * The desired item height.
3096 */
3098{
3099 INT nItemHeight;
3100
3101 TRACE("uView=%d\n", infoPtr->uView);
3102
3103 if (infoPtr->uView == LV_VIEW_ICON)
3104 nItemHeight = infoPtr->iconSpacing.cy;
3105 else
3106 {
3107 nItemHeight = infoPtr->ntmHeight;
3108 if (infoPtr->himlState)
3109 nItemHeight = max(nItemHeight, infoPtr->iconStateSize.cy);
3110 if (infoPtr->himlSmall)
3111 nItemHeight = max(nItemHeight, infoPtr->iconSize.cy);
3112 nItemHeight += HEIGHT_PADDING;
3113 if (infoPtr->nMeasureItemHeight > 0)
3114 nItemHeight = infoPtr->nMeasureItemHeight;
3115 }
3116
3117 return max(nItemHeight, 1);
3118}
3119
3120/***
3121 * DESCRIPTION:
3122 * Updates the width, and height of an item.
3123 *
3124 * PARAMETER(S):
3125 * [I] infoPtr : valid pointer to the listview structure
3126 *
3127 * RETURN:
3128 * None.
3129 */
3130static inline void LISTVIEW_UpdateItemSize(LISTVIEW_INFO *infoPtr)
3131{
3132 infoPtr->nItemWidth = LISTVIEW_CalculateItemWidth(infoPtr);
3133 infoPtr->nItemHeight = LISTVIEW_CalculateItemHeight(infoPtr);
3134}
3135
3136
3137/***
3138 * DESCRIPTION:
3139 * Retrieves and saves important text metrics info for the current
3140 * Listview font.
3141 *
3142 * PARAMETER(S):
3143 * [I] infoPtr : valid pointer to the listview structure
3144 *
3145 */
3147{
3148 HDC hdc = GetDC(infoPtr->hwndSelf);
3149 HFONT hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
3150 HFONT hOldFont = SelectObject(hdc, hFont);
3152 SIZE sz;
3153
3154 if (GetTextMetricsW(hdc, &tm))
3155 {
3156 infoPtr->ntmHeight = tm.tmHeight;
3157 infoPtr->ntmMaxCharWidth = tm.tmMaxCharWidth;
3158 }
3159
3160 if (GetTextExtentPoint32A(hdc, "...", 3, &sz))
3161 infoPtr->nEllipsisWidth = sz.cx;
3162
3163 SelectObject(hdc, hOldFont);
3164 ReleaseDC(infoPtr->hwndSelf, hdc);
3165
3166 TRACE("tmHeight=%d\n", infoPtr->ntmHeight);
3167}
3168
3169/***
3170 * DESCRIPTION:
3171 * A compare function for ranges
3172 *
3173 * PARAMETER(S)
3174 * [I] range1 : pointer to range 1;
3175 * [I] range2 : pointer to range 2;
3176 * [I] flags : flags
3177 *
3178 * RETURNS:
3179 * > 0 : if range 1 > range 2
3180 * < 0 : if range 2 > range 1
3181 * = 0 : if range intersects range 2
3182 */
3184{
3185 INT cmp;
3186
3187 if (((RANGE*)range1)->upper <= ((RANGE*)range2)->lower)
3188 cmp = -1;
3189 else if (((RANGE*)range2)->upper <= ((RANGE*)range1)->lower)
3190 cmp = 1;
3191 else
3192 cmp = 0;
3193
3194 TRACE("range1=%s, range2=%s, cmp=%d\n", debugrange(range1), debugrange(range2), cmp);
3195
3196 return cmp;
3197}
3198
3199#define ranges_check(ranges, desc) if (TRACE_ON(listview)) ranges_assert(ranges, desc, __FILE__, __LINE__)
3200
3201static void ranges_assert(RANGES ranges, LPCSTR desc, const char *file, int line)
3202{
3203 INT i;
3204 RANGE *prev, *curr;
3205
3206 TRACE("*** Checking %s:%d:%s ***\n", file, line, desc);
3207 assert (ranges);
3208 assert (DPA_GetPtrCount(ranges->hdpa) >= 0);
3209 ranges_dump(ranges);
3210 if (DPA_GetPtrCount(ranges->hdpa) > 0)
3211 {
3212 prev = DPA_GetPtr(ranges->hdpa, 0);
3213 assert (prev->lower >= 0 && prev->lower < prev->upper);
3214 for (i = 1; i < DPA_GetPtrCount(ranges->hdpa); i++)
3215 {
3216 curr = DPA_GetPtr(ranges->hdpa, i);
3217 assert (prev->upper <= curr->lower);
3218 assert (curr->lower < curr->upper);
3219 prev = curr;
3220 }
3221 }
3222 TRACE("--- Done checking---\n");
3223}
3224
3226{
3227 RANGES ranges = Alloc(sizeof(struct tagRANGES));
3228 if (!ranges) return NULL;
3229 ranges->hdpa = DPA_Create(count);
3230 if (ranges->hdpa) return ranges;
3231 Free(ranges);
3232 return NULL;
3233}
3234
3235static void ranges_clear(RANGES ranges)
3236{
3237 INT i;
3238
3239 for(i = 0; i < DPA_GetPtrCount(ranges->hdpa); i++)
3240 Free(DPA_GetPtr(ranges->hdpa, i));
3241 DPA_DeleteAllPtrs(ranges->hdpa);
3242}
3243
3244
3245static void ranges_destroy(RANGES ranges)
3246{
3247 if (!ranges) return;
3248 ranges_clear(ranges);
3249 DPA_Destroy(ranges->hdpa);
3250 Free(ranges);
3251}
3252
3254{
3255 RANGES clone;
3256 INT i;
3257
3258#ifdef __REACTOS__
3259 if (!ranges || !ranges->hdpa)
3260 {
3261 /*
3262 * If a ExplorerBand tree rename operation is completed by left-clicking in
3263 * DefView, the navigation to the newly named item causes the ListView in DefView
3264 * to call LISTVIEW_DeselectAllSkipItems during ListView destruction.
3265 */
3266 return NULL;
3267 }
3268#endif
3269 if (!(clone = ranges_create(DPA_GetPtrCount(ranges->hdpa)))) goto fail;
3270
3271 for (i = 0; i < DPA_GetPtrCount(ranges->hdpa); i++)
3272 {
3273 RANGE *newrng = Alloc(sizeof(RANGE));
3274 if (!newrng) goto fail;
3275 *newrng = *((RANGE*)DPA_GetPtr(ranges->hdpa, i));
3276 if (!DPA_SetPtr(clone->hdpa, i, newrng))
3277 {
3278 Free(newrng);
3279 goto fail;
3280 }
3281 }
3282 return clone;
3283
3284fail:
3285 TRACE ("clone failed\n");
3286 ranges_destroy(clone);
3287 return NULL;
3288}
3289
3290static RANGES ranges_diff(RANGES ranges, RANGES sub)
3291{
3292 INT i;
3293
3294 for (i = 0; i < DPA_GetPtrCount(sub->hdpa); i++)
3295 ranges_del(ranges, *((RANGE *)DPA_GetPtr(sub->hdpa, i)));
3296
3297 return ranges;
3298}
3299
3300static void ranges_dump(RANGES ranges)
3301{
3302 INT i;
3303
3304 for (i = 0; i < DPA_GetPtrCount(ranges->hdpa); i++)
3305 TRACE(" %s\n", debugrange(DPA_GetPtr(ranges->hdpa, i)));
3306}
3307
3308static inline BOOL ranges_contain(RANGES ranges, INT nItem)
3309{
3310 RANGE srchrng = { nItem, nItem + 1 };
3311
3312 TRACE("(nItem=%d)\n", nItem);
3313 ranges_check(ranges, "before contain");
3314 return DPA_Search(ranges->hdpa, &srchrng, 0, ranges_cmp, 0, DPAS_SORTED) != -1;
3315}
3316
3318{
3319 INT i, count = 0;
3320
3321 for (i = 0; i < DPA_GetPtrCount(ranges->hdpa); i++)
3322 {
3323 RANGE *sel = DPA_GetPtr(ranges->hdpa, i);
3324 count += sel->upper - sel->lower;
3325 }
3326
3327 return count;
3328}
3329
3330static BOOL ranges_shift(RANGES ranges, INT nItem, INT delta, INT nUpper)
3331{
3332 RANGE srchrng = { nItem, nItem + 1 }, *chkrng;
3333 INT index;
3334
3335 index = DPA_Search(ranges->hdpa, &srchrng, 0, ranges_cmp, 0, DPAS_SORTED | DPAS_INSERTAFTER);
3336 if (index == -1) return TRUE;
3337
3338 for (; index < DPA_GetPtrCount(ranges->hdpa); index++)
3339 {
3340 chkrng = DPA_GetPtr(ranges->hdpa, index);
3341 if (chkrng->lower >= nItem)
3342 chkrng->lower = max(min(chkrng->lower + delta, nUpper - 1), 0);
3343 if (chkrng->upper > nItem)
3344 chkrng->upper = max(min(chkrng->upper + delta, nUpper), 0);
3345 }
3346 return TRUE;
3347}
3348
3350{
3351 RANGE srchrgn;
3352 INT index;
3353
3354 TRACE("(%s)\n", debugrange(&range));
3355 ranges_check(ranges, "before add");
3356
3357 /* try find overlapping regions first */
3358 srchrgn.lower = range.lower - 1;
3359 srchrgn.upper = range.upper + 1;
3360 index = DPA_Search(ranges->hdpa, &srchrgn, 0, ranges_cmp, 0, DPAS_SORTED);
3361
3362 if (index == -1)
3363 {
3364 RANGE *newrgn;
3365
3366 TRACE("Adding new range\n");
3367
3368 /* create the brand new range to insert */
3369 newrgn = Alloc(sizeof(RANGE));
3370 if(!newrgn) goto fail;
3371 *newrgn = range;
3372
3373 /* figure out where to insert it */
3374 index = DPA_Search(ranges->hdpa, newrgn, 0, ranges_cmp, 0, DPAS_SORTED | DPAS_INSERTAFTER);
3375 TRACE("index=%d\n", index);
3376 if (index == -1) index = 0;
3377
3378 /* and get it over with */
3379 if (DPA_InsertPtr(ranges->hdpa, index, newrgn) == -1)
3380 {
3381 Free(newrgn);
3382 goto fail;
3383 }
3384 }
3385 else
3386 {
3387 RANGE *chkrgn, *mrgrgn;
3388 INT fromindex, mergeindex;
3389
3390 chkrgn = DPA_GetPtr(ranges->hdpa, index);
3391 TRACE("Merge with %s @%d\n", debugrange(chkrgn), index);
3392
3393 chkrgn->lower = min(range.lower, chkrgn->lower);
3394 chkrgn->upper = max(range.upper, chkrgn->upper);
3395
3396 TRACE("New range %s @%d\n", debugrange(chkrgn), index);
3397
3398 /* merge now common ranges */
3399 fromindex = 0;
3400 srchrgn.lower = chkrgn->lower - 1;
3401 srchrgn.upper = chkrgn->upper + 1;
3402
3403 do
3404 {
3405 mergeindex = DPA_Search(ranges->hdpa, &srchrgn, fromindex, ranges_cmp, 0, 0);
3406 if (mergeindex == -1) break;
3407 if (mergeindex == index)
3408 {
3409 fromindex = index + 1;
3410 continue;
3411 }
3412
3413 TRACE("Merge with index %i\n", mergeindex);
3414
3415 mrgrgn = DPA_GetPtr(ranges->hdpa, mergeindex);
3416 chkrgn->lower = min(chkrgn->lower, mrgrgn->lower);
3417 chkrgn->upper = max(chkrgn->upper, mrgrgn->upper);
3418 Free(mrgrgn);
3419 DPA_DeletePtr(ranges->hdpa, mergeindex);
3420 if (mergeindex < index) index --;
3421 } while(1);
3422 }
3423
3424 ranges_check(ranges, "after add");
3425 return TRUE;
3426
3427fail:
3428 ranges_check(ranges, "failed add");
3429 return FALSE;
3430}
3431
3433{
3434 RANGE *chkrgn;
3435 INT index;
3436
3437 TRACE("(%s)\n", debugrange(&range));
3438 ranges_check(ranges, "before del");
3439
3440 /* we don't use DPAS_SORTED here, since we need *
3441 * to find the first overlapping range */
3442 index = DPA_Search(ranges->hdpa, &range, 0, ranges_cmp, 0, 0);
3443 while(index != -1)
3444 {
3445 chkrgn = DPA_GetPtr(ranges->hdpa, index);
3446
3447 TRACE("Matches range %s @%d\n", debugrange(chkrgn), index);
3448
3449 /* case 1: Same range */
3450 if ( (chkrgn->upper == range.upper) &&
3451 (chkrgn->lower == range.lower) )
3452 {
3453 DPA_DeletePtr(ranges->hdpa, index);
3454 Free(chkrgn);
3455 break;
3456 }
3457 /* case 2: engulf */
3458 else if ( (chkrgn->upper <= range.upper) &&
3459 (chkrgn->lower >= range.lower) )
3460 {
3461 DPA_DeletePtr(ranges->hdpa, index);
3462 Free(chkrgn);
3463 }
3464 /* case 3: overlap upper */
3465 else if ( (chkrgn->upper <= range.upper) &&
3466 (chkrgn->lower < range.lower) )
3467 {
3468 chkrgn->upper = range.lower;
3469 }
3470 /* case 4: overlap lower */
3471 else if ( (chkrgn->upper > range.upper) &&
3472 (chkrgn->lower >= range.lower) )
3473 {
3474 chkrgn->lower = range.upper;
3475 break;
3476 }
3477 /* case 5: fully internal */
3478 else
3479 {
3480 RANGE *newrgn;
3481
3482 if (!(newrgn = Alloc(sizeof(RANGE)))) goto fail;
3483 newrgn->lower = chkrgn->lower;
3484 newrgn->upper = range.lower;
3485 chkrgn->lower = range.upper;
3486 if (DPA_InsertPtr(ranges->hdpa, index, newrgn) == -1)
3487 {
3488 Free(newrgn);
3489 goto fail;
3490 }
3491 break;
3492 }
3493
3494 index = DPA_Search(ranges->hdpa, &range, index, ranges_cmp, 0, 0);
3495 }
3496
3497 ranges_check(ranges, "after del");
3498 return TRUE;
3499
3500fail:
3501 ranges_check(ranges, "failed del");
3502 return FALSE;
3503}
3504
3505/***
3506* DESCRIPTION:
3507* Removes all selection ranges
3508*
3509* Parameters(s):
3510* [I] infoPtr : valid pointer to the listview structure
3511* [I] toSkip : item range to skip removing the selection
3512*
3513* RETURNS:
3514* SUCCESS : TRUE
3515* FAILURE : FALSE
3516*/
3518{
3519 LVITEMW lvItem;
3520 ITERATOR i;
3521 RANGES clone;
3522
3523 TRACE("()\n");
3524
3525 lvItem.state = 0;
3526 lvItem.stateMask = LVIS_SELECTED;
3527
3528 /* need to clone the DPA because callbacks can change it */
3529 if (!(clone = ranges_clone(infoPtr->selectionRanges))) return FALSE;
3530 iterator_rangesitems(&i, ranges_diff(clone, toSkip));
3531 while(iterator_next(&i))
3532 LISTVIEW_SetItemState(infoPtr, i.nItem, &lvItem);
3533 /* note that the iterator destructor will free the cloned range */
3535
3536 return TRUE;
3537}
3538
3540{
3541 RANGES toSkip;
3542
3543 if (!(toSkip = ranges_create(1))) return FALSE;
3544 if (nItem != -1) ranges_additem(toSkip, nItem);
3545 LISTVIEW_DeselectAllSkipItems(infoPtr, toSkip);
3546 ranges_destroy(toSkip);
3547 return TRUE;
3548}
3549
3551{
3552 return LISTVIEW_DeselectAllSkipItem(infoPtr, -1);
3553}
3554
3555/***
3556 * DESCRIPTION:
3557 * Retrieves the number of items that are marked as selected.
3558 *
3559 * PARAMETER(S):
3560 * [I] infoPtr : valid pointer to the listview structure
3561 *
3562 * RETURN:
3563 * Number of items selected.
3564 */
3566{
3567 INT nSelectedCount = 0;
3568
3569 if (infoPtr->uCallbackMask & LVIS_SELECTED)
3570 {
3571 INT i;
3572 for (i = 0; i < infoPtr->nItemCount; i++)
3573 {
3574 if (LISTVIEW_GetItemState(infoPtr, i, LVIS_SELECTED))
3575 nSelectedCount++;
3576 }
3577 }
3578 else
3579 nSelectedCount = ranges_itemcount(infoPtr->selectionRanges);
3580
3581 TRACE("nSelectedCount=%d\n", nSelectedCount);
3582 return nSelectedCount;
3583}
3584
3585/***
3586 * DESCRIPTION:
3587 * Manages the item focus.
3588 *
3589 * PARAMETER(S):
3590 * [I] infoPtr : valid pointer to the listview structure
3591 * [I] nItem : item index
3592 *
3593 * RETURN:
3594 * TRUE : focused item changed
3595 * FALSE : focused item has NOT changed
3596 */
3597static inline BOOL LISTVIEW_SetItemFocus(LISTVIEW_INFO *infoPtr, INT nItem)
3598{
3599 INT oldFocus = infoPtr->nFocusedItem;
3600 LVITEMW lvItem;
3601
3602 if (nItem == infoPtr->nFocusedItem) return FALSE;
3603
3604 lvItem.state = nItem == -1 ? 0 : LVIS_FOCUSED;
3605 lvItem.stateMask = LVIS_FOCUSED;
3606 LISTVIEW_SetItemState(infoPtr, nItem == -1 ? infoPtr->nFocusedItem : nItem, &lvItem);
3607
3608 return oldFocus != infoPtr->nFocusedItem;
3609}
3610
3611static INT shift_item(const LISTVIEW_INFO *infoPtr, INT nShiftItem, INT nItem, INT direction)
3612{
3613 if (nShiftItem < nItem) return nShiftItem;
3614
3615 if (nShiftItem > nItem) return nShiftItem + direction;
3616
3617 if (direction > 0) return nShiftItem + direction;
3618
3619 return min(nShiftItem, infoPtr->nItemCount - 1);
3620}
3621
3622/* This function updates focus index.
3623
3624Parameters:
3625 focus : current focus index
3626 item : index of item to be added/removed
3627 direction : add/remove flag
3628*/
3629static void LISTVIEW_ShiftFocus(LISTVIEW_INFO *infoPtr, INT focus, INT item, INT direction)
3630{
3631 DWORD old_mask = infoPtr->notify_mask & NOTIFY_MASK_ITEM_CHANGE;
3632
3633 infoPtr->notify_mask &= ~NOTIFY_MASK_ITEM_CHANGE;
3634 focus = shift_item(infoPtr, focus, item, direction);
3635 if (focus != infoPtr->nFocusedItem)
3636 LISTVIEW_SetItemFocus(infoPtr, focus);
3637 infoPtr->notify_mask |= old_mask;
3638}
3639
3652static void LISTVIEW_ShiftIndices(LISTVIEW_INFO *infoPtr, INT nItem, INT direction)
3653{
3654 TRACE("Shifting %i, %i steps\n", nItem, direction);
3655
3656 ranges_shift(infoPtr->selectionRanges, nItem, direction, infoPtr->nItemCount);
3657 assert(abs(direction) == 1);
3658 infoPtr->nSelectionMark = shift_item(infoPtr, infoPtr->nSelectionMark, nItem, direction);
3659
3660 /* But we are not supposed to modify nHotItem! */
3661}
3662
3675{
3676 INT nFirst = min(infoPtr->nSelectionMark, nItem);
3677 INT nLast = max(infoPtr->nSelectionMark, nItem);
3678 HWND hwndSelf = infoPtr->hwndSelf;
3679 NMLVODSTATECHANGE nmlv;
3680 DWORD old_mask;
3681 LVITEMW item;
3682 INT i;
3683
3684 /* Temporarily disable change notification
3685 * If the control is LVS_OWNERDATA, we need to send
3686 * only one LVN_ODSTATECHANGED notification.
3687 * See MSDN documentation for LVN_ITEMCHANGED.
3688 */
3689 old_mask = infoPtr->notify_mask & NOTIFY_MASK_ITEM_CHANGE;
3690 if (infoPtr->dwStyle & LVS_OWNERDATA)
3691 infoPtr->notify_mask &= ~NOTIFY_MASK_ITEM_CHANGE;
3692
3693 if (nFirst == -1) nFirst = nItem;
3694
3695 item.state = LVIS_SELECTED;
3696 item.stateMask = LVIS_SELECTED;
3697
3698 for (i = nFirst; i <= nLast; i++)
3699 LISTVIEW_SetItemState(infoPtr,i,&item);
3700
3701 ZeroMemory(&nmlv, sizeof(nmlv));
3702 nmlv.iFrom = nFirst;
3703 nmlv.iTo = nLast;
3704 nmlv.uOldState = 0;
3705 nmlv.uNewState = item.state;
3706
3707 notify_hdr(infoPtr, LVN_ODSTATECHANGED, (LPNMHDR)&nmlv);
3708 if (!IsWindow(hwndSelf))
3709 return FALSE;
3710 infoPtr->notify_mask |= old_mask;
3711 return TRUE;
3712}
3713
3714
3715/***
3716 * DESCRIPTION:
3717 * Sets a single group selection.
3718 *
3719 * PARAMETER(S):
3720 * [I] infoPtr : valid pointer to the listview structure
3721 * [I] nItem : item index
3722 *
3723 * RETURN:
3724 * None
3725 */
3727{
3729 DWORD old_mask;
3730 LVITEMW item;
3731 ITERATOR i;
3732
3733 if (!(selection = ranges_create(100))) return;
3734
3735 item.state = LVIS_SELECTED;
3736 item.stateMask = LVIS_SELECTED;
3737
3738 if ((infoPtr->uView == LV_VIEW_LIST) || (infoPtr->uView == LV_VIEW_DETAILS))
3739 {
3740 if (infoPtr->nSelectionMark == -1)
3741 {
3742 infoPtr->nSelectionMark = nItem;
3743 ranges_additem(selection, nItem);
3744 }
3745 else
3746 {
3747 RANGE sel;
3748
3749 sel.lower = min(infoPtr->nSelectionMark, nItem);
3750 sel.upper = max(infoPtr->nSelectionMark, nItem) + 1;
3751 ranges_add(selection, sel);
3752 }
3753 }
3754 else
3755 {
3756 RECT rcItem, rcSel, rcSelMark;
3757 POINT ptItem;
3758
3759 rcItem.left = LVIR_BOUNDS;
3760 if (!LISTVIEW_GetItemRect(infoPtr, nItem, &rcItem)) {
3762 return;
3763 }
3764 rcSelMark.left = LVIR_BOUNDS;
3765 if (!LISTVIEW_GetItemRect(infoPtr, infoPtr->nSelectionMark, &rcSelMark)) {
3767 return;
3768 }
3769 UnionRect(&rcSel, &rcItem, &rcSelMark);
3770 iterator_frameditems(&i, infoPtr, &rcSel);
3771 while(iterator_next(&i))
3772 {
3773 LISTVIEW_GetItemPosition(infoPtr, i.nItem, &ptItem);
3774 if (PtInRect(&rcSel, ptItem)) ranges_additem(selection, i.nItem);
3775 }
3777 }
3778
3779 /* disable per item notifications on LVS_OWNERDATA style
3780 FIXME: single LVN_ODSTATECHANGED should be used */
3781 old_mask = infoPtr->notify_mask & NOTIFY_MASK_ITEM_CHANGE;
3782 if (infoPtr->dwStyle & LVS_OWNERDATA)
3783 infoPtr->notify_mask &= ~NOTIFY_MASK_ITEM_CHANGE;
3784
3786
3787
3789 while(iterator_next(&i))
3790 LISTVIEW_SetItemState(infoPtr, i.nItem, &item);
3791 /* this will also destroy the selection */
3793
3794 infoPtr->notify_mask |= old_mask;
3795 LISTVIEW_SetItemFocus(infoPtr, nItem);
3796}
3797
3798/***
3799 * DESCRIPTION:
3800 * Sets a single selection.
3801 *
3802 * PARAMETER(S):
3803 * [I] infoPtr : valid pointer to the listview structure
3804 * [I] nItem : item index
3805 *
3806 * RETURN:
3807 * None
3808 */
3809static void LISTVIEW_SetSelection(LISTVIEW_INFO *infoPtr, INT nItem)
3810{
3811 LVITEMW lvItem;
3812
3813 TRACE("nItem=%d\n", nItem);
3814
3815 LISTVIEW_DeselectAllSkipItem(infoPtr, nItem);
3816
3817 lvItem.state = LVIS_FOCUSED | LVIS_SELECTED;
3819 LISTVIEW_SetItemState(infoPtr, nItem, &lvItem);
3820
3821 infoPtr->nSelectionMark = nItem;
3822}
3823
3824/***
3825 * DESCRIPTION:
3826 * Set selection(s) with keyboard.
3827 *
3828 * PARAMETER(S):
3829 * [I] infoPtr : valid pointer to the listview structure
3830 * [I] nItem : item index
3831 * [I] space : VK_SPACE code sent
3832 *
3833 * RETURN:
3834 * SUCCESS : TRUE (needs to be repainted)
3835 * FAILURE : FALSE (nothing has changed)
3836 */
3838{
3839 /* FIXME: pass in the state */
3840 WORD wShift = GetKeyState(VK_SHIFT) & 0x8000;
3841 WORD wCtrl = GetKeyState(VK_CONTROL) & 0x8000;
3842 BOOL bResult = FALSE;
3843
3844 TRACE("nItem=%d, wShift=%d, wCtrl=%d\n", nItem, wShift, wCtrl);
3845 if ((nItem >= 0) && (nItem < infoPtr->nItemCount))
3846 {
3847 bResult = TRUE;
3848
3849 if (infoPtr->dwStyle & LVS_SINGLESEL || (wShift == 0 && wCtrl == 0))
3850 LISTVIEW_SetSelection(infoPtr, nItem);
3851 else
3852 {
3853 if (wShift)
3854 LISTVIEW_SetGroupSelection(infoPtr, nItem);
3855 else if (wCtrl)
3856 {
3857 LVITEMW lvItem;
3858 lvItem.state = ~LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED);
3859 lvItem.stateMask = LVIS_SELECTED;
3860 if (space)
3861 {
3862 LISTVIEW_SetItemState(infoPtr, nItem, &lvItem);
3863 if (lvItem.state & LVIS_SELECTED)
3864 infoPtr->nSelectionMark = nItem;
3865 }
3866 bResult = LISTVIEW_SetItemFocus(infoPtr, nItem);
3867 }
3868 }
3869 LISTVIEW_EnsureVisible(infoPtr, nItem, FALSE);
3870 }
3871
3872 UpdateWindow(infoPtr->hwndSelf); /* update client area */
3873 return bResult;
3874}
3875
3876static BOOL LISTVIEW_GetItemAtPt(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, POINT pt)
3877{
3878 LVHITTESTINFO lvHitTestInfo;
3879
3880 ZeroMemory(&lvHitTestInfo, sizeof(lvHitTestInfo));
3881 lvHitTestInfo.pt.x = pt.x;
3882 lvHitTestInfo.pt.y = pt.y;
3883
3884 LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, FALSE);
3885
3886 lpLVItem->mask = LVIF_PARAM;
3887 lpLVItem->iItem = lvHitTestInfo.iItem;
3888 lpLVItem->iSubItem = 0;
3889
3890 return LISTVIEW_GetItemT(infoPtr, lpLVItem, TRUE);
3891}
3892
3893static inline BOOL LISTVIEW_IsHotTracking(const LISTVIEW_INFO *infoPtr)
3894{
3895 return ((infoPtr->dwLvExStyle & LVS_EX_TRACKSELECT) ||
3896 (infoPtr->dwLvExStyle & LVS_EX_ONECLICKACTIVATE) ||
3898}
3899
3900/***
3901 * DESCRIPTION:
3902 * Called when the mouse is being actively tracked and has hovered for a specified
3903 * amount of time
3904 *
3905 * PARAMETER(S):
3906 * [I] infoPtr : valid pointer to the listview structure
3907 * [I] fwKeys : key indicator
3908 * [I] x,y : mouse position
3909 *
3910 * RETURN:
3911 * 0 if the message was processed, non-zero if there was an error
3912 *
3913 * INFO:
3914 * LVS_EX_TRACKSELECT: An item is automatically selected when the cursor remains
3915 * over the item for a certain period of time.
3916 *
3917 */
3919{
3920 NMHDR hdr;
3921
3922 if (notify_hdr(infoPtr, NM_HOVER, &hdr)) return 0;
3923
3924 if (LISTVIEW_IsHotTracking(infoPtr))
3925 {
3926 LVITEMW item;
3927 POINT pt;
3928
3929 pt.x = x;
3930 pt.y = y;
3931
3932 if (LISTVIEW_GetItemAtPt(infoPtr, &item, pt))
3933 LISTVIEW_SetSelection(infoPtr, item.iItem);
3934
3935 SetFocus(infoPtr->hwndSelf);
3936 }
3937
3938 return 0;
3939}
3940
3941#define SCROLL_LEFT 0x1
3942#define SCROLL_RIGHT 0x2
3943#define SCROLL_UP 0x4
3944#define SCROLL_DOWN 0x8
3945
3946/***
3947 * DESCRIPTION:
3948 * Utility routine to draw and highlight items within a marquee selection rectangle.
3949 *
3950 * PARAMETER(S):
3951 * [I] infoPtr : valid pointer to the listview structure
3952 * [I] coords_orig : original co-ordinates of the cursor
3953 * [I] coords_offs : offsetted coordinates of the cursor
3954 * [I] offset : offset amount
3955 * [I] scroll : Bitmask of which directions we should scroll, if at all
3956 *
3957 * RETURN:
3958 * None.
3959 */
3960static void LISTVIEW_MarqueeHighlight(LISTVIEW_INFO *infoPtr, const POINT *coords_orig,
3961 INT scroll)
3962{
3963 BOOL controlDown = FALSE;
3964 LVITEMW item;
3965 ITERATOR old_elems, new_elems;
3966 RECT rect;
3967 POINT coords_offs, offset;
3968
3969 /* Ensure coordinates are within client bounds */
3970 coords_offs.x = max(min(coords_orig->x, infoPtr->rcList.right), 0);
3971 coords_offs.y = max(min(coords_orig->y, infoPtr->rcList.bottom), 0);
3972
3973 /* Get offset */
3974 LISTVIEW_GetOrigin(infoPtr, &offset);
3975
3976 /* Offset coordinates by the appropriate amount */
3977 coords_offs.x -= offset.x;
3978 coords_offs.y -= offset.y;
3979
3980 if (coords_offs.x > infoPtr->marqueeOrigin.x)
3981 {
3982 rect.left = infoPtr->marqueeOrigin.x;
3983 rect.right = coords_offs.x;
3984 }
3985 else
3986 {
3987 rect.left = coords_offs.x;
3988 rect.right = infoPtr->marqueeOrigin.x;
3989 }
3990
3991 if (coords_offs.y > infoPtr->marqueeOrigin.y)
3992 {
3993 rect.top = infoPtr->marqueeOrigin.y;
3994 rect.bottom = coords_offs.y;
3995 }
3996 else
3997 {
3998 rect.top = coords_offs.y;
3999 rect.bottom = infoPtr->marqueeOrigin.y;
4000 }
4001
4002 /* Cancel out the old marquee rectangle and draw the new one */
4003 LISTVIEW_InvalidateRect(infoPtr, &infoPtr->marqueeDrawRect);
4004
4005 /* Scroll by the appropriate distance if applicable - speed up scrolling as
4006 the cursor is further away */
4007
4008 if ((scroll & SCROLL_LEFT) && (coords_orig->x <= 0))
4009 LISTVIEW_Scroll(infoPtr, coords_orig->x, 0);
4010
4011 if ((scroll & SCROLL_RIGHT) && (coords_orig->x >= infoPtr->rcList.right))
4012 LISTVIEW_Scroll(infoPtr, (coords_orig->x - infoPtr->rcList.right), 0);
4013
4014 if ((scroll & SCROLL_UP) && (coords_orig->y <= 0))
4015 LISTVIEW_Scroll(infoPtr, 0, coords_orig->y);
4016
4017 if ((scroll & SCROLL_DOWN) && (coords_orig->y >= infoPtr->rcList.bottom))
4018 LISTVIEW_Scroll(infoPtr, 0, (coords_orig->y - infoPtr->rcList.bottom));
4019
4020 iterator_frameditems_absolute(&old_elems, infoPtr, &infoPtr->marqueeRect);
4021
4022 infoPtr->marqueeRect = rect;
4023 infoPtr->marqueeDrawRect = rect;
4024 OffsetRect(&infoPtr->marqueeDrawRect, offset.x, offset.y);
4025
4026 iterator_frameditems_absolute(&new_elems, infoPtr, &infoPtr->marqueeRect);
4027 iterator_remove_common_items(&old_elems, &new_elems);
4028
4029 /* Iterate over no longer selected items */
4030 while (iterator_next(&old_elems))
4031 {
4032 if (old_elems.nItem > -1)
4033 {
4034 if (LISTVIEW_GetItemState(infoPtr, old_elems.nItem, LVIS_SELECTED) == LVIS_SELECTED)
4035 item.state = 0;
4036 else
4037 item.state = LVIS_SELECTED;
4038
4039 item.stateMask = LVIS_SELECTED;
4040
4041 LISTVIEW_SetItemState(infoPtr, old_elems.nItem, &item);
4042 }
4043 }
4044 iterator_destroy(&old_elems);
4045
4046
4047 /* Iterate over newly selected items */
4048 if (GetKeyState(VK_CONTROL) & 0x8000)
4049 controlDown = TRUE;
4050
4051 while (iterator_next(&new_elems))
4052 {
4053 if (new_elems.nItem > -1)
4054 {
4055 /* If CTRL is pressed, invert. If not, always select the item. */
4056 if ((controlDown) && (LISTVIEW_GetItemState(infoPtr, new_elems.nItem, LVIS_SELECTED)))
4057 item.state = 0;
4058 else
4059 item.state = LVIS_SELECTED;
4060
4061 item.stateMask = LVIS_SELECTED;
4062
4063 LISTVIEW_SetItemState(infoPtr, new_elems.nItem, &item);
4064 }
4065 }
4066 iterator_destroy(&new_elems);
4067
4068 LISTVIEW_InvalidateRect(infoPtr, &infoPtr->marqueeDrawRect);
4069}
4070
4071/***
4072 * DESCRIPTION:
4073 * Called when we are in a marquee selection that involves scrolling the listview (ie,
4074 * the cursor is outside the bounds of the client area). This is a TIMERPROC.
4075 *
4076 * PARAMETER(S):
4077 * [I] hwnd : Handle to the listview
4078 * [I] uMsg : WM_TIMER (ignored)
4079 * [I] idEvent : The timer ID interpreted as a pointer to a LISTVIEW_INFO struct
4080 * [I] dwTimer : The elapsed time (ignored)
4081 *
4082 * RETURN:
4083 * None.
4084 */
4086{
4087 LISTVIEW_INFO *infoPtr;
4088 SCROLLINFO scrollInfo;
4089 POINT coords;
4090 INT scroll = 0;
4091
4092 infoPtr = (LISTVIEW_INFO *) idEvent;
4093
4094 if (!infoPtr)
4095 return;
4096
4097 /* Get the current cursor position and convert to client coordinates */
4100
4101 scrollInfo.cbSize = sizeof(SCROLLINFO);
4102 scrollInfo.fMask = SIF_ALL;
4103
4104 /* Work out in which directions we can scroll */
4105 if (GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo))
4106 {
4107 if (scrollInfo.nPos != scrollInfo.nMin)
4108 scroll |= SCROLL_UP;
4109
4110 if (((scrollInfo.nPage + scrollInfo.nPos) - 1) != scrollInfo.nMax)
4111 scroll |= SCROLL_DOWN;
4112 }
4113
4114 if (GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo))
4115 {
4116 if (scrollInfo.nPos != scrollInfo.nMin)
4117 scroll |= SCROLL_LEFT;
4118
4119 if (((scrollInfo.nPage + scrollInfo.nPos) - 1) != scrollInfo.nMax)
4120 scroll |= SCROLL_RIGHT;
4121 }
4122
4123 if (((coords.x <= 0) && (scroll & SCROLL_LEFT)) ||
4124 ((coords.y <= 0) && (scroll & SCROLL_UP)) ||
4125 ((coords.x >= infoPtr->rcList.right) && (scroll & SCROLL_RIGHT)) ||
4126 ((coords.y >= infoPtr->rcList.bottom) && (scroll & SCROLL_DOWN)))
4127 {
4128 LISTVIEW_MarqueeHighlight(infoPtr, &coords, scroll);
4129 }
4130}
4131
4132/***
4133 * DESCRIPTION:
4134 * Called whenever WM_MOUSEMOVE is received.
4135 *
4136 * PARAMETER(S):
4137 * [I] infoPtr : valid pointer to the listview structure
4138 * [I] fwKeys : key indicator
4139 * [I] x,y : mouse position
4140 *
4141 * RETURN:
4142 * 0 if the message is processed, non-zero if there was an error
4143 */
4145{
4147 RECT rect;
4148 POINT pt;
4149
4150 pt.x = x;
4151 pt.y = y;
4152
4153 if (!(fwKeys & MK_LBUTTON))
4154 infoPtr->bLButtonDown = FALSE;
4155
4156 if (infoPtr->bLButtonDown)
4157 {
4158 rect.left = rect.right = infoPtr->ptClickPos.x;
4159 rect.top = rect.bottom = infoPtr->ptClickPos.y;
4160
4162
4163 if (infoPtr->bMarqueeSelect)
4164 {
4165 /* Enable the timer if we're going outside our bounds, in case the user doesn't
4166 move the mouse again */
4167
4168 if ((x <= 0) || (y <= 0) || (x >= infoPtr->rcList.right) ||
4169 (y >= infoPtr->rcList.bottom))
4170 {
4171 if (!infoPtr->bScrolling)
4172 {
4173 infoPtr->bScrolling = TRUE;
4174 SetTimer(infoPtr->hwndSelf, (UINT_PTR) infoPtr, 1, LISTVIEW_ScrollTimer);
4175 }
4176 }
4177 else
4178 {
4179 infoPtr->bScrolling = FALSE;
4180 KillTimer(infoPtr->hwndSelf, (UINT_PTR) infoPtr);
4181 }
4182
4183 LISTVIEW_MarqueeHighlight(infoPtr, &pt, 0);
4184 return 0;
4185 }
4186
4187 ht.pt = pt;
4188 LISTVIEW_HitTest(infoPtr, &ht, TRUE, TRUE);
4189
4190 /* reset item marker */
4191 if (infoPtr->nLButtonDownItem != ht.iItem)
4192 infoPtr->nLButtonDownItem = -1;
4193
4194 if (!PtInRect(&rect, pt))
4195 {
4196 /* this path covers the following:
4197 1. WM_LBUTTONDOWN over selected item (sets focus on it)
4198 2. change focus with keys
4199 3. move mouse over item from step 1 selects it and moves focus on it */
4200 if (infoPtr->nLButtonDownItem != -1 &&
4202 {
4203 LVITEMW lvItem;
4204
4205 lvItem.state = LVIS_FOCUSED | LVIS_SELECTED;
4207
4208 LISTVIEW_SetItemState(infoPtr, infoPtr->nLButtonDownItem, &lvItem);
4209 infoPtr->nLButtonDownItem = -1;
4210 }
4211
4212 if (!infoPtr->bDragging)
4213 {
4214 ht.pt = infoPtr->ptClickPos;
4215 LISTVIEW_HitTest(infoPtr, &ht, TRUE, TRUE);
4216
4217 /* If the click is outside the range of an item, begin a
4218 highlight. If not, begin an item drag. */
4219 if (ht.iItem == -1)
4220 {
4221 NMHDR hdr;
4222
4223 /* If we're allowing multiple selections, send notification.
4224 If return value is non-zero, cancel. */
4225 if (!(infoPtr->dwStyle & LVS_SINGLESEL) && (notify_hdr(infoPtr, LVN_MARQUEEBEGIN, &hdr) == 0))
4226 {
4227 /* Store the absolute coordinates of the click */
4228 POINT offset;
4229 LISTVIEW_GetOrigin(infoPtr, &offset);
4230
4231 infoPtr->marqueeOrigin.x = infoPtr->ptClickPos.x - offset.x;
4232 infoPtr->marqueeOrigin.y = infoPtr->ptClickPos.y - offset.y;
4233
4234 /* Begin selection and capture mouse */
4235 infoPtr->bMarqueeSelect = TRUE;
4236 infoPtr->marqueeRect = rect;
4237 SetCapture(infoPtr->hwndSelf);
4238 }
4239 }
4240 else
4241 {
4242 NMLISTVIEW nmlv;
4243
4244 ZeroMemory(&nmlv, sizeof(nmlv));
4245 nmlv.iItem = ht.iItem;
4246 nmlv.ptAction = infoPtr->ptClickPos;
4247
4248 notify_listview(infoPtr, LVN_BEGINDRAG, &nmlv);
4249 infoPtr->bDragging = TRUE;
4250 }
4251 }
4252
4253 return 0;
4254 }
4255 }
4256
4257 /* see if we are supposed to be tracking mouse hovering */
4258 if (LISTVIEW_IsHotTracking(infoPtr)) {
4259 TRACKMOUSEEVENT trackinfo;
4260 DWORD flags;
4261
4262 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
4263 trackinfo.dwFlags = TME_QUERY;
4264
4265 /* see if we are already tracking this hwnd */
4266 _TrackMouseEvent(&trackinfo);
4267
4268 flags = TME_LEAVE;
4269 if(infoPtr->dwLvExStyle & LVS_EX_TRACKSELECT)
4270 flags |= TME_HOVER;
4271
4272 if((trackinfo.dwFlags & flags) != flags || trackinfo.hwndTrack != infoPtr->hwndSelf) {
4273 trackinfo.dwFlags = flags;
4274 trackinfo.dwHoverTime = infoPtr->dwHoverTime;
4275 trackinfo.hwndTrack = infoPtr->hwndSelf;
4276
4277 /* call TRACKMOUSEEVENT so we receive WM_MOUSEHOVER messages */
4278 _TrackMouseEvent(&trackinfo);
4279 }
4280 }
4281
4282 return 0;
4283}
4284
4285
4286/***
4287 * Tests whether the item is assignable to a list with style lStyle
4288 */
4289static inline BOOL is_assignable_item(const LVITEMW *lpLVItem, LONG lStyle)
4290{
4291 if ( (lpLVItem->mask & LVIF_TEXT) &&
4292 (lpLVItem->pszText == LPSTR_TEXTCALLBACKW) &&
4293 (lStyle & (LVS_SORTASCENDING | LVS_SORTDESCENDING)) ) return FALSE;
4294
4295 return TRUE;
4296}
4297
4298
4299/***
4300 * DESCRIPTION:
4301 * Helper for LISTVIEW_SetItemT and LISTVIEW_InsertItemT: sets item attributes.
4302 *
4303 * PARAMETER(S):
4304 * [I] infoPtr : valid pointer to the listview structure
4305 * [I] lpLVItem : valid pointer to new item attributes
4306 * [I] isNew : the item being set is being inserted
4307 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
4308 * [O] bChanged : will be set to TRUE if the item really changed
4309 *
4310 * RETURN:
4311 * SUCCESS : TRUE
4312 * FAILURE : FALSE
4313 */
4314static BOOL set_main_item(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL isNew, BOOL isW, BOOL *bChanged)
4315{
4316 ITEM_INFO *lpItem;
4317 NMLISTVIEW nmlv;
4318 UINT uChanged = 0;
4319 LVITEMW item;
4320 /* stateMask is ignored for LVM_INSERTITEM */
4321 UINT stateMask = isNew ? ~0 : lpLVItem->stateMask;
4322
4323 TRACE("()\n");
4324
4325 assert(lpLVItem->iItem >= 0 && lpLVItem->iItem < infoPtr->nItemCount);
4326
4327 if (lpLVItem->mask == 0) return TRUE;
4328
4329 if (infoPtr->dwStyle & LVS_OWNERDATA)
4330 {
4331 /* a virtual listview only stores selection and focus */
4332 if (lpLVItem->mask & ~LVIF_STATE)
4333 return FALSE;
4334 lpItem = NULL;
4335 }
4336 else
4337 {
4338 HDPA hdpaSubItems = DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
4339 lpItem = DPA_GetPtr(hdpaSubItems, 0);
4340 assert (lpItem);
4341 }
4342
4343 /* we need to get the lParam and state of the item */
4344 item.iItem = lpLVItem->iItem;
4345 item.iSubItem = lpLVItem->iSubItem;
4346 item.mask = LVIF_STATE | LVIF_PARAM;
4347 item.stateMask = (infoPtr->dwStyle & LVS_OWNERDATA) ? LVIS_FOCUSED | LVIS_SELECTED : ~0;
4348
4349 item.state = 0;
4350 item.lParam = 0;
4351 if (!isNew && !LISTVIEW_GetItemW(infoPtr, &item)) return FALSE;
4352
4353 TRACE("oldState=%x, newState=%x\n", item.state, lpLVItem->state);
4354 /* determine what fields will change */
4355 if ((lpLVItem->mask & LVIF_STATE) && ((item.state ^ lpLVItem->state) & stateMask & ~infoPtr->uCallbackMask))
4356 uChanged |= LVIF_STATE;
4357
4358 if ((lpLVItem->mask & LVIF_IMAGE) && (lpItem->hdr.iImage != lpLVItem->iImage))
4359 uChanged |= LVIF_IMAGE;
4360
4361 if ((lpLVItem->mask & LVIF_PARAM) && (lpItem->lParam != lpLVItem->lParam))
4362 uChanged |= LVIF_PARAM;
4363
4364 if ((lpLVItem->mask & LVIF_INDENT) && (lpItem->iIndent != lpLVItem->iIndent))
4365 uChanged |= LVIF_INDENT;
4366
4367 if ((lpLVItem->mask & LVIF_TEXT) && textcmpWT(lpItem->hdr.pszText, lpLVItem->pszText, isW))
4368 uChanged |= LVIF_TEXT;
4369
4370 TRACE("change mask=0x%x\n", uChanged);
4371
4372 memset(&nmlv, 0, sizeof(NMLISTVIEW));
4373 nmlv.iItem = lpLVItem->iItem;
4374 if (lpLVItem->mask & LVIF_STATE)
4375 {
4376 nmlv.uNewState = (item.state & ~stateMask) | (lpLVItem->state & stateMask);
4377 nmlv.uOldState = item.state;
4378 }
4379 nmlv.uChanged = uChanged ? uChanged : lpLVItem->mask;
4380 nmlv.lParam = item.lParam;
4381
4382 /* Send LVN_ITEMCHANGING notification, if the item is not being inserted
4383 and we are _NOT_ virtual (LVS_OWNERDATA), and change notifications
4384 are enabled. Even nothing really changed we still need to send this,
4385 in this case uChanged mask is just set to passed item mask. */
4386 if (lpItem && !isNew && (infoPtr->notify_mask & NOTIFY_MASK_ITEM_CHANGE))
4387 {
4388 HWND hwndSelf = infoPtr->hwndSelf;
4389
4390 if (notify_listview(infoPtr, LVN_ITEMCHANGING, &nmlv))
4391 return FALSE;
4392 if (!IsWindow(hwndSelf))
4393 return FALSE;
4394 }
4395
4396 /* When item is inserted we need to shift existing focus index if new item has lower index. */
4397 if (isNew && (stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED) &&
4398 /* this means we won't hit a focus change path later */
4399 ((uChanged & LVIF_STATE) == 0 || (!(lpLVItem->state & LVIS_FOCUSED) && (infoPtr->nFocusedItem != lpLVItem->iItem))))
4400 {
4401 if (infoPtr->nFocusedItem != -1 && (lpLVItem->iItem <= infoPtr->nFocusedItem))
4402 infoPtr->nFocusedItem++;
4403 }
4404
4405 if (!uChanged) return TRUE;
4406 *bChanged = TRUE;
4407
4408 /* copy information */
4409 if (lpLVItem->mask & LVIF_TEXT)
4410 textsetptrT(&lpItem->hdr.pszText, lpLVItem->pszText, isW);
4411
4412 if (lpLVItem->mask & LVIF_IMAGE)
4413 lpItem->hdr.iImage = lpLVItem->iImage;
4414
4415 if (lpLVItem->mask & LVIF_PARAM)
4416 lpItem->lParam = lpLVItem->lParam;
4417
4418 if (lpLVItem->mask & LVIF_INDENT)
4419 lpItem->iIndent = lpLVItem->iIndent;
4420
4421 if (uChanged & LVIF_STATE)
4422 {
4423 if (lpItem && (stateMask & ~infoPtr->uCallbackMask))
4424 {
4425 lpItem->state &= ~stateMask;
4426 lpItem->state |= (lpLVItem->state & stateMask);
4427 }
4428 if (lpLVItem->state & stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED)
4429 {
4430 if (infoPtr->dwStyle & LVS_SINGLESEL) LISTVIEW_DeselectAllSkipItem(infoPtr, lpLVItem->iItem);
4431 ranges_additem(infoPtr->selectionRanges, lpLVItem->iItem);
4432 }
4433 else if (stateMask & LVIS_SELECTED)
4434 {
4435 ranges_delitem(infoPtr->selectionRanges, lpLVItem->iItem);
4436 }
4437 /* If we are asked to change focus, and we manage it, do it.
4438 It's important to have all new item data stored at this point,
4439 because changing existing focus could result in a redrawing operation,
4440 which in turn could ask for disp data, application should see all data
4441 for inserted item when processing LVN_GETDISPINFO.
4442
4443 The way this works application will see nested item change notifications -
4444 changed item notifications interrupted by ones from item losing focus. */
4445 if (stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED)
4446 {
4447 if (lpLVItem->state & LVIS_FOCUSED)
4448 {
4449 /* update selection mark */
4450 if (infoPtr->nFocusedItem == -1 && infoPtr->nSelectionMark == -1)
4451 infoPtr->nSelectionMark = lpLVItem->iItem;
4452
4453 if (infoPtr->nFocusedItem != -1)
4454 {
4455 /* remove current focus */
4456 item.mask = LVIF_STATE;
4457 item.state = 0;
4458 item.stateMask = LVIS_FOCUSED;
4459
4460 /* recurse with redrawing an item */
4461 LISTVIEW_SetItemState(infoPtr, infoPtr->nFocusedItem, &item);
4462 }
4463
4464 infoPtr->nFocusedItem = lpLVItem->iItem;
4465 LISTVIEW_EnsureVisible(infoPtr, lpLVItem->iItem, infoPtr->uView == LV_VIEW_LIST);
4466 }
4467 else if (infoPtr->nFocusedItem == lpLVItem->iItem)
4468 {
4469 infoPtr->nFocusedItem = -1;
4470 }
4471 }
4472 }
4473
4474 /* if we're inserting the item, we're done */
4475 if (isNew) return TRUE;
4476
4477 /* send LVN_ITEMCHANGED notification */
4478 if (lpLVItem->mask & LVIF_PARAM) nmlv.lParam = lpLVItem->lParam;
4479 if (infoPtr->notify_mask & NOTIFY_MASK_ITEM_CHANGE)
4480 notify_listview(infoPtr, LVN_ITEMCHANGED, &nmlv);
4481
4482 return TRUE;
4483}
4484
4485/***
4486 * DESCRIPTION:
4487 * Helper for LISTVIEW_{Set,Insert}ItemT *only*: sets subitem attributes.
4488 *
4489 * PARAMETER(S):
4490 * [I] infoPtr : valid pointer to the listview structure
4491 * [I] lpLVItem : valid pointer to new subitem attributes
4492 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
4493 * [O] bChanged : will be set to TRUE if the item really changed
4494 *
4495 * RETURN:
4496 * SUCCESS : TRUE
4497 * FAILURE : FALSE
4498 */
4499static BOOL set_sub_item(const LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL isW, BOOL *bChanged)
4500{
4501 HDPA hdpaSubItems;
4502 SUBITEM_INFO *lpSubItem;
4503
4504 /* we do not support subitems for virtual listviews */
4505 if (infoPtr->dwStyle & LVS_OWNERDATA) return FALSE;
4506
4507 /* set subitem only if column is present */
4508 if (lpLVItem->iSubItem >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return FALSE;
4509
4510 /* First do some sanity checks */
4511 /* The LVIF_STATE flag is valid for subitems, but does not appear to be
4512 particularly useful. We currently do not actually do anything with
4513 the flag on subitems.
4514 */
4515 if (lpLVItem->mask & ~(LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_DI_SETITEM)) return FALSE;
4516 if (!(lpLVItem->mask & (LVIF_TEXT | LVIF_IMAGE | LVIF_STATE))) return TRUE;
4517
4518 /* get the subitem structure, and create it if not there */
4519 hdpaSubItems = DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
4520 assert (hdpaSubItems);
4521
4522 lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem);
4523 if (!lpSubItem)
4524 {
4525 SUBITEM_INFO *tmpSubItem;
4526 INT i;
4527
4528 lpSubItem = Alloc(sizeof(SUBITEM_INFO));
4529 if (!lpSubItem) return FALSE;
4530 /* we could binary search here, if need be...*/
4531 for (i = 1; i < DPA_GetPtrCount(hdpaSubItems); i++)
4532 {
4533 tmpSubItem = DPA_GetPtr(hdpaSubItems, i);
4534 if (tmpSubItem->iSubItem > lpLVItem->iSubItem) break;
4535 }
4536 if (DPA_InsertPtr(hdpaSubItems, i, lpSubItem) == -1)
4537 {
4538 Free(lpSubItem);
4539 return FALSE;
4540 }
4541 lpSubItem->iSubItem = lpLVItem->iSubItem;
4542 lpSubItem->hdr.iImage = I_IMAGECALLBACK;
4543 *bChanged = TRUE;
4544 }
4545
4546 if ((lpLVItem->mask & LVIF_IMAGE) && (lpSubItem->hdr.iImage != lpLVItem->iImage))
4547 {
4548 lpSubItem->hdr.iImage = lpLVItem->iImage;
4549 *bChanged = TRUE;
4550 }
4551
4552 if ((lpLVItem->mask & LVIF_TEXT) && textcmpWT(lpSubItem->hdr.pszText, lpLVItem->pszText, isW))
4553 {
4554 textsetptrT(&lpSubItem->hdr.pszText, lpLVItem->pszText, isW);
4555 *bChanged = TRUE;
4556 }
4557
4558 return TRUE;
4559}
4560
4561/***
4562 * DESCRIPTION:
4563 * Sets item attributes.
4564 *
4565 * PARAMETER(S):
4566 * [I] infoPtr : valid pointer to the listview structure
4567 * [I] lpLVItem : new item attributes
4568 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
4569 *
4570 * RETURN:
4571 * SUCCESS : TRUE
4572 * FAILURE : FALSE
4573 */
4575{
4576 HWND hwndSelf = infoPtr->hwndSelf;
4577 LPWSTR pszText = NULL;
4578 BOOL bResult, bChanged = FALSE;
4579 RECT oldItemArea;
4580
4581 TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW);
4582
4583 if (!lpLVItem || lpLVItem->iItem < 0 || lpLVItem->iItem >= infoPtr->nItemCount)
4584 return FALSE;
4585
4586 /* Store old item area */
4587 LISTVIEW_GetItemBox(infoPtr, lpLVItem->iItem, &oldItemArea);
4588
4589 /* For efficiency, we transform the lpLVItem->pszText to Unicode here */
4590 if ((lpLVItem->mask & LVIF_TEXT) && is_text(lpLVItem->pszText))
4591 {
4592 pszText = lpLVItem->pszText;
4593 lpLVItem->pszText = textdupTtoW(lpLVItem->pszText, isW);
4594 }
4595
4596 /* actually set the fields */
4597 if (!is_assignable_item(lpLVItem, infoPtr->dwStyle)) return FALSE;
4598
4599 if (lpLVItem->iSubItem)
4600 bResult = set_sub_item(infoPtr, lpLVItem, TRUE, &bChanged);
4601 else
4602 bResult = set_main_item(infoPtr, lpLVItem, FALSE, TRUE, &bChanged);
4603 if (!IsWindow(hwndSelf))
4604 return FALSE;
4605
4606 /* redraw item, if necessary */
4607 if (bChanged && !infoPtr->bIsDrawing)
4608 {
4609 /* this little optimization eliminates some nasty flicker */
4610 if ( infoPtr->uView == LV_VIEW_DETAILS && !(infoPtr->dwStyle & LVS_OWNERDRAWFIXED) &&
4611 !(infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) &&
4612 lpLVItem->iSubItem > 0 && lpLVItem->iSubItem <= DPA_GetPtrCount(infoPtr->hdpaColumns) )
4613 LISTVIEW_InvalidateSubItem(infoPtr, lpLVItem->iItem, lpLVItem->iSubItem);
4614 else
4615 {
4616 LISTVIEW_InvalidateRect(infoPtr, &oldItemArea);
4617 LISTVIEW_InvalidateItem(infoPtr, lpLVItem->iItem);
4618 }
4619 }
4620 /* restore text */
4621 if (pszText)
4622 {
4623 textfreeT(lpLVItem->pszText, isW);
4624 lpLVItem->pszText = pszText;
4625 }
4626
4627 return bResult;
4628}
4629
4630/***
4631 * DESCRIPTION:
4632 * Retrieves the index of the item at coordinate (0, 0) of the client area.
4633 *
4634 * PARAMETER(S):
4635 * [I] infoPtr : valid pointer to the listview structure
4636 *
4637 * RETURN:
4638 * item index
4639 */
4641{
4642 INT nItem = 0;
4643 SCROLLINFO scrollInfo;
4644
4645 scrollInfo.cbSize = sizeof(SCROLLINFO);
4646 scrollInfo.fMask = SIF_POS;
4647
4648 if (infoPtr->uView == LV_VIEW_LIST)
4649 {
4650 if (GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo))
4651 nItem = scrollInfo.nPos * LISTVIEW_GetCountPerColumn(infoPtr);
4652 }
4653 else if (infoPtr->uView == LV_VIEW_DETAILS)
4654 {
4655 if (GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo))
4656 nItem = scrollInfo.nPos;
4657 }
4658 else
4659 {
4660 if (GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo))
4661 nItem = LISTVIEW_GetCountPerRow(infoPtr) * (scrollInfo.nPos / infoPtr->nItemHeight);
4662 }
4663
4664 TRACE("nItem=%d\n", nItem);
4665
4666 return nItem;
4667}
4668
4669
4670/***
4671 * DESCRIPTION:
4672 * Erases the background of the given rectangle
4673 *
4674 * PARAMETER(S):
4675 * [I] infoPtr : valid pointer to the listview structure
4676 * [I] hdc : device context handle
4677 * [I] lprcBox : clipping rectangle
4678 *
4679 * RETURN:
4680 * Success: TRUE
4681 * Failure: FALSE
4682 */
4683static inline BOOL LISTVIEW_FillBkgnd(const LISTVIEW_INFO *infoPtr, HDC hdc, const RECT *lprcBox)
4684{
4685 if (!infoPtr->hBkBrush) return FALSE;
4686
4687 TRACE("(hdc=%p, lprcBox=%s, hBkBrush=%p)\n", hdc, wine_dbgstr_rect(lprcBox), infoPtr->hBkBrush);
4688
4689 return FillRect(hdc, lprcBox, infoPtr->hBkBrush);
4690}
4691
4692/* Draw main item or subitem */
4693static void LISTVIEW_DrawItemPart(LISTVIEW_INFO *infoPtr, LVITEMW *item, const NMLVCUSTOMDRAW *nmlvcd, const POINT *pos)
4694{
4695 RECT rcSelect, rcLabel, rcBox, rcStateIcon, rcIcon;
4696 const RECT *background;
4698 UINT format;
4699 RECT *focus;
4700
4701 /* now check if we need to update the focus rectangle */
4702 focus = infoPtr->bFocus && (item->state & LVIS_FOCUSED) ? &infoPtr->rcFocus : 0;
4703 if (!focus) item->state &= ~LVIS_FOCUSED;
4704
4705 LISTVIEW_GetItemMetrics(infoPtr, item, &rcBox, &rcSelect, &rcIcon, &rcStateIcon, &rcLabel);
4706 OffsetRect(&rcBox, pos->x, pos->y);
4707 OffsetRect(&rcSelect, pos->x, pos->y);
4708 OffsetRect(&rcIcon, pos->x, pos->y);
4709 OffsetRect(&rcStateIcon, pos->x, pos->y);
4710 OffsetRect(&rcLabel, pos->x, pos->y);
4711 TRACE("%d: box=%s, select=%s, icon=%s. label=%s\n", item->iSubItem,
4712 wine_dbgstr_rect(&rcBox), wine_dbgstr_rect(&rcSelect),
4713 wine_dbgstr_rect(&rcIcon), wine_dbgstr_rect(&rcLabel));
4714
4715 /* FIXME: temporary hack */
4716 rcSelect.left = rcLabel.left;
4717
4718 if (infoPtr->uView == LV_VIEW_DETAILS && item->iSubItem == 0)
4719 {
4720 if (!(infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT))
4721 OffsetRect(&rcSelect, LISTVIEW_GetColumnInfo(infoPtr, 0)->rcHeader.left, 0);
4722 OffsetRect(&rcIcon, LISTVIEW_GetColumnInfo(infoPtr, 0)->rcHeader.left, 0);
4723 OffsetRect(&rcStateIcon, LISTVIEW_GetColumnInfo(infoPtr, 0)->rcHeader.left, 0);
4724 OffsetRect(&rcLabel, LISTVIEW_GetColumnInfo(infoPtr, 0)->rcHeader.left, 0);
4725 }
4726
4727 /* in icon mode, the label rect is really what we want to draw the
4728 * background for */
4729 /* in detail mode, we want to paint background for label rect when
4730 * item is not selected or listview has full row select; otherwise paint
4731 * background for text only */
4732 if ( infoPtr->uView == LV_VIEW_ICON ||
4733 (infoPtr->uView == LV_VIEW_DETAILS && (!(item->state & LVIS_SELECTED) ||
4734 (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT))))
4735 background = &rcLabel;
4736 else
4737 background = &rcSelect;
4738
4739 if (nmlvcd->clrTextBk != CLR_NONE)
4740 ExtTextOutW(nmlvcd->nmcd.hdc, background->left, background->top, ETO_OPAQUE, background, NULL, 0, NULL);
4741
4742 if (item->state & LVIS_FOCUSED)
4743 {
4744 if (infoPtr->uView == LV_VIEW_DETAILS)
4745 {
4746 if (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT)
4747 {
4748 /* we have to update left focus bound too if item isn't in leftmost column
4749 and reduce right box bound */
4750 if (DPA_GetPtrCount(infoPtr->hdpaColumns) > 0)
4751 {
4752 INT leftmost;
4753
4754 if ((leftmost = SendMessageW(infoPtr->hwndHeader, HDM_ORDERTOINDEX, 0, 0)))
4755 {
4756 INT Originx = pos->x - LISTVIEW_GetColumnInfo(infoPtr, leftmost)->rcHeader.left;
4757 INT rightmost = SendMessageW(infoPtr->hwndHeader, HDM_ORDERTOINDEX,
4758 DPA_GetPtrCount(infoPtr->hdpaColumns) - 1, 0);
4759
4760 rcBox.right = LISTVIEW_GetColumnInfo(infoPtr, rightmost)->rcHeader.right + Originx;
4761 rcSelect.left = LISTVIEW_GetColumnInfo(infoPtr, leftmost)->rcHeader.left + Originx;
4762 }
4763 }
4764 rcSelect.right = rcBox.right;
4765 }
4766 infoPtr->rcFocus = rcSelect;
4767 }
4768 else
4769 infoPtr->rcFocus = rcLabel;
4770 }
4771
4772 /* state icons */
4773 if (infoPtr->himlState && STATEIMAGEINDEX(item->state) && (item->iSubItem == 0))
4774 {
4775 UINT stateimage = STATEIMAGEINDEX(item->state);
4776 if (stateimage)
4777 {
4778 TRACE("stateimage=%d\n", stateimage);
4779 ImageList_Draw(infoPtr->himlState, stateimage-1, nmlvcd->nmcd.hdc, rcStateIcon.left, rcStateIcon.top, ILD_NORMAL);
4780 }
4781 }
4782
4783 /* item icons */
4784 himl = (infoPtr->uView == LV_VIEW_ICON ? infoPtr->himlNormal : infoPtr->himlSmall);
4785 if (himl && item->iImage >= 0 && !IsRectEmpty(&rcIcon))
4786 {
4787 UINT style;
4788
4789 TRACE("iImage=%d\n", item->iImage);
4790
4791 if (item->state & (LVIS_SELECTED | LVIS_CUT) && infoPtr->bFocus)
4793 else
4794 style = ILD_NORMAL;
4795
4796 ImageList_DrawEx(himl, item->iImage, nmlvcd->nmcd.hdc, rcIcon.left, rcIcon.top,
4797 rcIcon.right - rcIcon.left, rcIcon.bottom - rcIcon.top, infoPtr->clrBk,
4798 item->state & LVIS_CUT ? RGB(255, 255, 255) : CLR_DEFAULT,
4799 style | (item->state & LVIS_OVERLAYMASK));
4800 }
4801
4802 /* Don't bother painting item being edited */
4803 if (infoPtr->hwndEdit && item->iItem == infoPtr->nEditLabelItem && item->iSubItem == 0) return;
4804
4805 /* figure out the text drawing flags */
4806 format = (infoPtr->uView == LV_VIEW_ICON ? (focus ? LV_FL_DT_FLAGS : LV_ML_DT_FLAGS) : LV_SL_DT_FLAGS);
4807 if (infoPtr->uView == LV_VIEW_ICON)
4808 format = (focus ? LV_FL_DT_FLAGS : LV_ML_DT_FLAGS);
4809 else if (item->iSubItem)
4810 {
4811 switch (LISTVIEW_GetColumnInfo(infoPtr, item->iSubItem)->fmt & LVCFMT_JUSTIFYMASK)
4812 {
4813 case LVCFMT_RIGHT: format |= DT_RIGHT; break;
4814 case LVCFMT_CENTER: format |= DT_CENTER; break;
4815 default: format |= DT_LEFT;
4816 }
4817 }
4818 if (!(format & (DT_RIGHT | DT_CENTER)))
4819 {
4820 if (himl && item->iImage >= 0 && !IsRectEmpty(&rcIcon)) rcLabel.left += IMAGE_PADDING;
4821 else rcLabel.left += LABEL_HOR_PADDING;
4822 }
4823 else if (format & DT_RIGHT) rcLabel.right -= LABEL_HOR_PADDING;
4824
4825 /* for GRIDLINES reduce the bottom so the text formats correctly */
4826 if (infoPtr->uView == LV_VIEW_DETAILS && infoPtr->dwLvExStyle & LVS_EX_GRIDLINES)
4827 rcLabel.bottom--;
4828
4829#ifdef __REACTOS__
4830 if ((!(item->state & LVIS_SELECTED) || !infoPtr->bFocus) && (infoPtr->dwLvExStyle & LVS_EX_TRANSPARENTSHADOWTEXT))
4831 DrawShadowText(nmlvcd->nmcd.hdc, item->pszText, -1, &rcLabel, format, RGB(255, 255, 255), RGB(0, 0, 0), 2, 2);
4832 else
4833#endif
4834 DrawTextW(nmlvcd->nmcd.hdc, item->pszText, -1, &rcLabel, format);
4835}
4836
4837/***
4838 * DESCRIPTION:
4839 * Draws an item.
4840 *
4841 * PARAMETER(S):
4842 * [I] infoPtr : valid pointer to the listview structure
4843 * [I] hdc : device context handle
4844 * [I] nItem : item index
4845 * [I] nSubItem : subitem index
4846 * [I] pos : item position in client coordinates
4847 * [I] cdmode : custom draw mode
4848 *
4849 * RETURN:
4850 * Success: TRUE
4851 * Failure: FALSE
4852 */
4853static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, ITERATOR *subitems, POINT pos, DWORD cdmode)
4854{
4855 WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
4856 static WCHAR callbackW[] = { '(', 'c', 'a', 'l', 'l', 'b', 'a', 'c', 'k', ')', 0 };
4857 DWORD cdsubitemmode = CDRF_DODEFAULT;
4858 RECT *focus, rcBox;
4859 NMLVCUSTOMDRAW nmlvcd;
4860 LVITEMW lvItem;
4861
4862 TRACE("(hdc=%p, nItem=%d, subitems=%p, pos=%s)\n", hdc, nItem, subitems, wine_dbgstr_point(&pos));
4863
4864 /* get information needed for drawing the item */
4866 if (infoPtr->uView == LV_VIEW_DETAILS) lvItem.mask |= LVIF_INDENT;
4868 lvItem.iItem = nItem;
4869 lvItem.iSubItem = 0;
4870 lvItem.state = 0;
4871 lvItem.lParam = 0;
4872 lvItem.cchTextMax = DISP_TEXT_SIZE;
4873 lvItem.pszText = szDispText;
4874 if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE;
4875 if (lvItem.pszText == LPSTR_TEXTCALLBACKW) lvItem.pszText = callbackW;
4876 TRACE(" lvItem=%s\n", debuglvitem_t(&lvItem, TRUE));
4877
4878 /* now check if we need to update the focus rectangle */
4879 focus = infoPtr->bFocus && (lvItem.state & LVIS_FOCUSED) ? &infoPtr->rcFocus : 0;
4880 if (!focus) lvItem.state &= ~LVIS_FOCUSED;
4881
4882 LISTVIEW_GetItemMetrics(infoPtr, &lvItem, &rcBox, NULL, NULL, NULL, NULL);
4883 OffsetRect(&rcBox, pos.x, pos.y);
4884
4885 /* Full custom draw stage sequence looks like this:
4886
4887 LV_VIEW_DETAILS:
4888
4889 - CDDS_ITEMPREPAINT
4890 - CDDS_ITEMPREPAINT|CDDS_SUBITEM | => sent n times, where n is number of subitems,
4891 CDDS_ITEMPOSTPAINT|CDDS_SUBITEM | including item itself
4892 - CDDS_ITEMPOSTPAINT
4893
4894 other styles:
4895
4896 - CDDS_ITEMPREPAINT
4897 - CDDS_ITEMPOSTPAINT
4898 */
4899
4900 /* fill in the custom draw structure */
4901 customdraw_fill(&nmlvcd, infoPtr, hdc, &rcBox, &lvItem);
4902 if (cdmode & CDRF_NOTIFYITEMDRAW)
4903 cdsubitemmode = notify_customdraw(infoPtr, CDDS_ITEMPREPAINT, &nmlvcd);
4904 if (cdsubitemmode & CDRF_SKIPDEFAULT) goto postpaint;
4905
4906 if (subitems)
4907 {
4908 while (iterator_next(subitems))
4909 {
4910 DWORD subitemstage = CDRF_DODEFAULT;
4911 NMLVCUSTOMDRAW temp_nmlvcd;
4912
4913 /* We need to query for each subitem, item's data (subitem == 0) is already here at this point */
4914 if (subitems->nItem)
4915 {
4918 lvItem.iItem = nItem;
4919 lvItem.iSubItem = subitems->nItem;
4920 lvItem.state = 0;
4921 lvItem.lParam = 0;
4922 lvItem.cchTextMax = DISP_TEXT_SIZE;
4923 lvItem.pszText = szDispText;
4924 if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE;
4925 if (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT)
4926 lvItem.state = LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED);
4927 if (lvItem.pszText == LPSTR_TEXTCALLBACKW) lvItem.pszText = callbackW;
4928 TRACE(" lvItem=%s\n", debuglvitem_t(&lvItem, TRUE));
4929
4930 /* update custom draw data */
4931 LISTVIEW_GetItemMetrics(infoPtr, &lvItem, &nmlvcd.nmcd.rc, NULL, NULL, NULL, NULL);
4932 OffsetRect(&nmlvcd.nmcd.rc, pos.x, pos.y);
4933 nmlvcd.iSubItem = subitems->nItem;
4934 }
4935
4936 if (cdsubitemmode & CDRF_NOTIFYSUBITEMDRAW)
4937 subitemstage = notify_customdraw(infoPtr, CDDS_SUBITEM | CDDS_ITEMPREPAINT, &nmlvcd);
4938
4939 /*
4940 * A selection should neither affect the colors in the post paint notification nor
4941 * affect the colors of the next drawn subitem. Copy the structure to prevent this.
4942 */
4943 temp_nmlvcd = nmlvcd;
4944 prepaint_setup(infoPtr, hdc, &temp_nmlvcd, subitems->nItem);
4945
4946 if (!(subitemstage & CDRF_SKIPDEFAULT))
4947 LISTVIEW_DrawItemPart(infoPtr, &lvItem, &temp_nmlvcd, &pos);
4948
4949 if (subitemstage & CDRF_NOTIFYPOSTPAINT)
4950 subitemstage = notify_customdraw(infoPtr, CDDS_SUBITEM | CDDS_ITEMPOSTPAINT, &nmlvcd);
4951 }
4952 }
4953 else
4954 {
4955 prepaint_setup(infoPtr, hdc, &nmlvcd, FALSE);
4956 LISTVIEW_DrawItemPart(infoPtr, &lvItem, &nmlvcd, &pos);
4957 }
4958
4959postpaint:
4960 if (cdsubitemmode & CDRF_NOTIFYPOSTPAINT)
4961 {
4962 nmlvcd.iSubItem = 0;
4963 notify_customdraw(infoPtr, CDDS_ITEMPOSTPAINT, &nmlvcd);
4964 }
4965
4966 return TRUE;
4967}
4968
4969/***
4970 * DESCRIPTION:
4971 * Draws listview items when in owner draw mode.
4972 *
4973 * PARAMETER(S):
4974 * [I] infoPtr : valid pointer to the listview structure
4975 * [I] hdc : device context handle
4976 *
4977 * RETURN:
4978 * None
4979 */
4980static void LISTVIEW_RefreshOwnerDraw(const LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, DWORD cdmode)
4981{
4982 UINT uID = (UINT)GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
4983 DWORD cditemmode = CDRF_DODEFAULT;
4984 NMLVCUSTOMDRAW nmlvcd;
4985 POINT Origin, Position;
4986 DRAWITEMSTRUCT dis;
4987 LVITEMW item;
4988
4989 TRACE("()\n");
4990
4991 ZeroMemory(&dis, sizeof(dis));
4992
4993 /* Get scroll info once before loop */
4994 LISTVIEW_GetOrigin(infoPtr, &Origin);
4995
4996 /* iterate through the invalidated rows */
4997 while(iterator_next(i))
4998 {
4999 item.iItem = i->nItem;
5000 item.iSubItem = 0;
5001 item.mask = LVIF_PARAM | LVIF_STATE;
5002 item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
5003 if (!LISTVIEW_GetItemW(infoPtr, &item)) continue;
5004
5005 dis.CtlType = ODT_LISTVIEW;
5006 dis.CtlID = uID;
5007 dis.itemID = item.iItem;
5009 dis.itemState = 0;
5010 if (item.state & LVIS_SELECTED) dis.itemState |= ODS_SELECTED;
5011 if (infoPtr->bFocus && (item.state & LVIS_FOCUSED)) dis.itemState |= ODS_FOCUS;
5012 dis.hwndItem = infoPtr->hwndSelf;
5013 dis.hDC = hdc;
5014 LISTVIEW_GetItemOrigin(infoPtr, dis.itemID, &Position);
5015 dis.rcItem.left = Position.x + Origin.x;
5016 dis.rcItem.right = dis.rcItem.left + infoPtr->nItemWidth;
5017 dis.rcItem.top = Position.y + Origin.y;
5018 dis.rcItem.bottom = dis.rcItem.top + infoPtr->nItemHeight;
5019 dis.itemData = item.lParam;
5020
5021 TRACE("item=%s, rcItem=%s\n", debuglvitem_t(&item, TRUE), wine_dbgstr_rect(&dis.rcItem));
5022
5023 /*
5024 * Even if we do not send the CDRF_NOTIFYITEMDRAW we need to fill the nmlvcd
5025 * structure for the rest. of the paint cycle
5026 */
5027 customdraw_fill(&nmlvcd, infoPtr, hdc, &dis.rcItem, &item);
5028 if (cdmode & CDRF_NOTIFYITEMDRAW)
5029 cditemmode = notify_customdraw(infoPtr, CDDS_PREPAINT, &nmlvcd);
5030
5031 if (!(cditemmode & CDRF_SKIPDEFAULT))
5032 {
5033 prepaint_setup (infoPtr, hdc, &nmlvcd, FALSE);
5034 SendMessageW(infoPtr->hwndNotify, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis);
5035 }
5036
5037 if (cditemmode & CDRF_NOTIFYPOSTPAINT)
5038 notify_postpaint(infoPtr, &nmlvcd);
5039 }
5040}
5041
5042/***
5043 * DESCRIPTION:
5044 * Draws listview items when in report display mode.
5045 *
5046 * PARAMETER(S):
5047 * [I] infoPtr : valid pointer to the listview structure
5048 * [I] hdc : device context handle
5049 * [I] cdmode : custom draw mode
5050 *
5051 * RETURN:
5052 * None
5053 */
5055{
5056 INT rgntype;
5057 RECT rcClip, rcItem;
5058 POINT Origin;
5059 RANGES colRanges;
5060 INT col;
5061 ITERATOR j;
5062
5063 TRACE("()\n");
5064
5065 /* figure out what to draw */
5066 rgntype = GetClipBox(hdc, &rcClip);
5067 if (rgntype == NULLREGION) return;
5068
5069 /* Get scroll info once before loop */
5070 LISTVIEW_GetOrigin(infoPtr, &Origin);
5071
5072 colRanges = ranges_create(DPA_GetPtrCount(infoPtr->hdpaColumns));
5073
5074 /* narrow down the columns we need to paint */
5075 for(col = 0; col < DPA_GetPtrCount(infoPtr->hdpaColumns); col++)
5076 {
5077 INT index = SendMessageW(infoPtr->hwndHeader, HDM_ORDERTOINDEX, col, 0);
5078
5079 LISTVIEW_GetHeaderRect(infoPtr, index, &rcItem);
5080 if ((rcItem.right + Origin.x >= rcClip.left) && (rcItem.left + Origin.x < rcClip.right))
5081 ranges_additem(colRanges, index);
5082 }
5083 iterator_rangesitems(&j, colRanges);
5084
5085 /* in full row select, we _have_ to draw the main item */
5086 if (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT)
5087 j.nSpecial = 0;
5088
5089 /* iterate through the invalidated rows */
5090 while(iterator_next(i))
5091 {
5092 RANGES subitems;
5094 ITERATOR k;
5095
5096 SelectObject(hdc, infoPtr->hFont);
5097 LISTVIEW_GetItemOrigin(infoPtr, i->nItem, &Position);
5098 Position.x = Origin.x;
5099 Position.y += Origin.y;
5100
5101 subitems = ranges_create(DPA_GetPtrCount(infoPtr->hdpaColumns));
5102
5103 /* iterate through the invalidated columns */
5104 while(iterator_next(&j))
5105 {
5106 LISTVIEW_GetHeaderRect(infoPtr, j.nItem, &rcItem);
5107
5108 if (rgntype == COMPLEXREGION && !((infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) && j.nItem == 0))
5109 {
5110 rcItem.top = 0;
5111 rcItem.bottom = infoPtr->nItemHeight;
5112 OffsetRect(&rcItem, Origin.x, Position.y);
5113 if (!RectVisible(hdc, &rcItem)) continue;
5114 }
5115
5116 ranges_additem(subitems, j.nItem);
5117 }
5118
5119 iterator_rangesitems(&k, subitems);
5120 LISTVIEW_DrawItem(infoPtr, hdc, i->nItem, &k, Position, cdmode);
5122 }
5124}
5125
5126/***
5127 * DESCRIPTION:
5128 * Draws the gridlines if necessary when in report display mode.
5129 *
5130 * PARAMETER(S):
5131 * [I] infoPtr : valid pointer to the listview structure
5132 * [I] hdc : device context handle
5133 *
5134 * RETURN:
5135 * None
5136 */
5138{
5139 INT rgntype;
5140 INT y, itemheight;
5141 INT col, index;
5142 HPEN hPen, hOldPen;
5143 RECT rcClip, rcItem = {0};
5144 POINT Origin;
5145 RANGES colRanges;
5146 ITERATOR j;
5147 BOOL rmost = FALSE;
5148
5149 TRACE("()\n");
5150
5151 /* figure out what to draw */
5152 rgntype = GetClipBox(hdc, &rcClip);
5153 if (rgntype == NULLREGION) return;
5154
5155 /* Get scroll info once before loop */
5156 LISTVIEW_GetOrigin(infoPtr, &Origin);
5157
5158 colRanges = ranges_create(DPA_GetPtrCount(infoPtr->hdpaColumns));
5159
5160 /* narrow down the columns we need to paint */
5161 for(col = 0; col < DPA_GetPtrCount(infoPtr->hdpaColumns); col++)
5162 {
5163 index = SendMessageW(infoPtr->hwndHeader, HDM_ORDERTOINDEX, col, 0);
5164
5165 LISTVIEW_GetHeaderRect(infoPtr, index, &rcItem);
5166 if ((rcItem.right + Origin.x >= rcClip.left) && (rcItem.left + Origin.x < rcClip.right))
5167 ranges_additem(colRanges, index);
5168 }
5169
5170 /* is right most vertical line visible? */
5171 if (DPA_GetPtrCount(infoPtr->hdpaColumns) > 0)
5172 {
5174 LISTVIEW_GetHeaderRect(infoPtr, index, &rcItem);
5175 rmost = (rcItem.right + Origin.x < rcClip.right);
5176 }
5177
5178 if ((hPen = CreatePen( PS_SOLID, 1, comctl32_color.clr3dFace )))
5179 {
5180 hOldPen = SelectObject ( hdc, hPen );
5181
5182 /* draw the vertical lines for the columns */
5183 iterator_rangesitems(&j, colRanges);
5184 while(iterator_next(&j))
5185 {
5186 LISTVIEW_GetHeaderRect(infoPtr, j.nItem, &rcItem);
5187 if (rcItem.left == 0) continue; /* skip leftmost column */
5188 rcItem.left += Origin.x;
5189 rcItem.right += Origin.x;
5190 rcItem.top = infoPtr->rcList.top;
5191 rcItem.bottom = infoPtr->rcList.bottom;
5192 TRACE("vert col=%d, rcItem=%s\n", j.nItem, wine_dbgstr_rect(&rcItem));
5193 MoveToEx (hdc, rcItem.left, rcItem.top, NULL);
5194 LineTo (hdc, rcItem.left, rcItem.bottom);
5195 }
5197 /* draw rightmost grid line if visible */
5198 if (rmost)
5199 {
5201 DPA_GetPtrCount(infoPtr->hdpaColumns) - 1, 0);
5202 LISTVIEW_GetHeaderRect(infoPtr, index, &rcItem);
5203
5204 rcItem.right += Origin.x;
5205
5206 MoveToEx (hdc, rcItem.right, infoPtr->rcList.top, NULL);
5207 LineTo (hdc, rcItem.right, infoPtr->rcList.bottom);
5208 }
5209
5210 /* draw the horizontal lines for the rows */
5211 itemheight = LISTVIEW_CalculateItemHeight(infoPtr);
5212 rcItem.left = infoPtr->rcList.left;
5213 rcItem.right = infoPtr->rcList.right;
5214 for(y = Origin.y > 1 ? Origin.y - 1 : itemheight - 1 + Origin.y % itemheight; y<=infoPtr->rcList.bottom; y+=itemheight)
5215 {
5216 rcItem.bottom = rcItem.top = y;
5217 TRACE("horz rcItem=%s\n", wine_dbgstr_rect(&rcItem));
5218 MoveToEx (hdc, rcItem.left, rcItem.top, NULL);
5219 LineTo (hdc, rcItem.right, rcItem.top);
5220 }
5221
5222 SelectObject( hdc, hOldPen );
5223 DeleteObject( hPen );
5224 }
5225 else
5226 ranges_destroy(colRanges);
5227}
5228
5229/***
5230 * DESCRIPTION:
5231 * Draws listview items when in list display mode.
5232 *
5233 * PARAMETER(S):
5234 * [I] infoPtr : valid pointer to the listview structure
5235 * [I] hdc : device context handle
5236 * [I] cdmode : custom draw mode
5237 *
5238 * RETURN:
5239 * None
5240 */
5241static void LISTVIEW_RefreshList(LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, DWORD cdmode)
5242{
5243 POINT Origin, Position;
5244
5245 /* Get scroll info once before loop */
5246 LISTVIEW_GetOrigin(infoPtr, &Origin);
5247
5248 while(iterator_prev(i))
5249 {
5250 SelectObject(hdc, infoPtr->hFont);
5251 LISTVIEW_GetItemOrigin(infoPtr, i->nItem, &Position);
5252 Position.x += Origin.x;
5253 Position.y += Origin.y;
5254
5255 LISTVIEW_DrawItem(infoPtr, hdc, i->nItem, NULL, Position, cdmode);
5256 }
5257}
5258
5259
5260/***
5261 * DESCRIPTION:
5262 * Draws listview items.
5263 *
5264 * PARAMETER(S):
5265 * [I] infoPtr : valid pointer to the listview structure
5266 * [I] hdc : device context handle
5267 * [I] prcErase : rect to be erased before refresh (may be NULL)
5268 *
5269 * RETURN:
5270 * NoneX
5271 */
5272static void LISTVIEW_Refresh(LISTVIEW_INFO *infoPtr, HDC hdc, const RECT *prcErase)
5273{
5274 COLORREF oldTextColor = 0, oldBkColor = 0;
5275 NMLVCUSTOMDRAW nmlvcd;
5276 HFONT hOldFont = 0;
5277 DWORD cdmode;
5278 INT oldBkMode = 0;
5279 RECT rcClient;
5280 ITERATOR i;
5281 HDC hdcOrig = hdc;
5282 HBITMAP hbmp = NULL;
5283 RANGE range;
5284
5285 LISTVIEW_DUMP(infoPtr);
5286
5287 if (infoPtr->dwLvExStyle & LVS_EX_DOUBLEBUFFER) {
5288 TRACE("double buffering\n");
5289
5290 hdc = CreateCompatibleDC(hdcOrig);
5291 if (!hdc) {
5292 ERR("Failed to create DC for backbuffer\n");
5293 return;
5294 }
5295 hbmp = CreateCompatibleBitmap(hdcOrig, infoPtr->rcList.right,
5296 infoPtr->rcList.bottom);
5297 if (!hbmp) {
5298 ERR("Failed to create bitmap for backbuffer\n");
5299 DeleteDC(hdc);
5300 return;
5301 }
5302
5304 SelectObject(hdc, infoPtr->hFont);
5305
5306 if(GetClipBox(hdcOrig, &rcClient))
5307 IntersectClipRect(hdc, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
5308 } else {
5309 /* Save dc values we're gonna trash while drawing
5310 * FIXME: Should be done in LISTVIEW_DrawItem() */
5311 hOldFont = SelectObject(hdc, infoPtr->hFont);
5312 oldBkMode = GetBkMode(hdc);
5313 oldBkColor = GetBkColor(hdc);
5314 oldTextColor = GetTextColor(hdc);
5315 }
5316
5317 infoPtr->bIsDrawing = TRUE;
5318
5319 if (prcErase) {
5320 LISTVIEW_FillBkgnd(infoPtr, hdc, prcErase);
5321 } else if (infoPtr->dwLvExStyle & LVS_EX_DOUBLEBUFFER) {
5322 /* If no erasing was done (usually because RedrawWindow was called
5323 * with RDW_INVALIDATE only) we need to copy the old contents into
5324 * the backbuffer before continuing. */
5325 BitBlt(hdc, infoPtr->rcList.left, infoPtr->rcList.top,
5326 infoPtr->rcList.right - infoPtr->rcList.left,
5327 infoPtr->rcList.bottom - infoPtr->rcList.top,
5328 hdcOrig, infoPtr->rcList.left, infoPtr->rcList.top, SRCCOPY);
5329 }
5330
5331 GetClientRect(infoPtr->hwndSelf, &rcClient);
5332 customdraw_fill(&nmlvcd, infoPtr, hdc, &rcClient, 0);
5333 cdmode = notify_customdraw(infoPtr, CDDS_PREPAINT, &nmlvcd);
5334 if (cdmode & CDRF_SKIPDEFAULT) goto enddraw;
5335
5336 /* nothing to draw */
5337 if(infoPtr->nItemCount == 0) goto enddraw;
5338
5339 /* figure out what we need to draw */
5340 iterator_visibleitems(&i, infoPtr, hdc);
5342
5343 /* send cache hint notification */
5344 if (infoPtr->dwStyle & LVS_OWNERDATA)
5345 {
5346 NMLVCACHEHINT nmlv;
5347
5348 ZeroMemory(&nmlv, sizeof(NMLVCACHEHINT));
5349 nmlv.iFrom = range.lower;
5350 nmlv.iTo = range.upper - 1;
5351 notify_hdr(infoPtr, LVN_ODCACHEHINT, &nmlv.hdr);
5352 }
5353
5354 if ((infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && (infoPtr->uView == LV_VIEW_DETAILS))
5355 LISTVIEW_RefreshOwnerDraw(infoPtr, &i, hdc, cdmode);
5356 else
5357 {
5358 if (infoPtr->uView == LV_VIEW_DETAILS)
5359 LISTVIEW_RefreshReport(infoPtr, &i, hdc, cdmode);
5360 else /* LV_VIEW_LIST, LV_VIEW_ICON or LV_VIEW_SMALLICON */
5361 LISTVIEW_RefreshList(infoPtr, &i, hdc, cdmode);
5362
5363 /* if we have a focus rect and it's visible, draw it */
5364 if (infoPtr->bFocus && range.lower <= infoPtr->nFocusedItem &&
5365 (range.upper - 1) >= infoPtr->nFocusedItem)
5366 LISTVIEW_DrawFocusRect(infoPtr, hdc);
5367 }
5369
5370enddraw:
5371 /* For LVS_EX_GRIDLINES go and draw lines */
5372 /* This includes the case where there were *no* items */
5373 if ((infoPtr->uView == LV_VIEW_DETAILS) && infoPtr->dwLvExStyle & LVS_EX_GRIDLINES)
5375
5376 /* Draw marquee rectangle if appropriate */
5377 if (infoPtr->bMarqueeSelect)
5378#ifdef __REACTOS__
5379 {
5380 SetBkColor(hdc, RGB(255, 255, 255));
5381 SetTextColor(hdc, RGB(0, 0, 0));
5382 DrawFocusRect(hdc, &infoPtr->marqueeDrawRect);
5383 }
5384#else
5385 DrawFocusRect(hdc, &infoPtr->marqueeDrawRect);
5386#endif
5387
5388 if (cdmode & CDRF_NOTIFYPOSTPAINT)
5389 notify_postpaint(infoPtr, &nmlvcd);
5390
5391 if(hbmp) {
5392 BitBlt(hdcOrig, infoPtr->rcList.left, infoPtr->rcList.top,
5393 infoPtr->rcList.right - infoPtr->rcList.left,
5394 infoPtr->rcList.bottom - infoPtr->rcList.top,
5395 hdc, infoPtr->rcList.left, infoPtr->rcList.top, SRCCOPY);
5396
5398 DeleteDC(hdc);
5399 } else {
5400 SelectObject(hdc, hOldFont);
5401 SetBkMode(hdc, oldBkMode);
5402 SetBkColor(hdc, oldBkColor);
5403 SetTextColor(hdc, oldTextColor);
5404 }
5405
5406 infoPtr->bIsDrawing = FALSE;
5407}
5408
5409
5410/***
5411 * DESCRIPTION:
5412 * Calculates the approximate width and height of a given number of items.
5413 *
5414 * PARAMETER(S):
5415 * [I] infoPtr : valid pointer to the listview structure
5416 * [I] nItemCount : number of items
5417 * [I] wWidth : width
5418 * [I] wHeight : height
5419 *
5420 * RETURN:
5421 * Returns a DWORD. The width in the low word and the height in high word.
5422 */
5423static DWORD LISTVIEW_ApproximateViewRect(const LISTVIEW_INFO *infoPtr, INT nItemCount,
5424 WORD wWidth, WORD wHeight)
5425{
5426 DWORD dwViewRect = 0;
5427
5428 if (nItemCount == -1)
5429 nItemCount = infoPtr->nItemCount;
5430
5431 if (infoPtr->uView == LV_VIEW_LIST)
5432 {
5433 INT nItemCountPerColumn = 1;
5434 INT nColumnCount = 0;
5435
5436 if (wHeight == 0xFFFF)
5437 {
5438 /* use current height */
5439 wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
5440 }
5441
5442 if (wHeight < infoPtr->nItemHeight)
5443 wHeight = infoPtr->nItemHeight;
5444
5445 if (nItemCount > 0)
5446 {
5447 if (infoPtr->nItemHeight > 0)
5448 {
5449 nItemCountPerColumn = wHeight / infoPtr->nItemHeight;
5450 if (nItemCountPerColumn == 0)
5451 nItemCountPerColumn = 1;
5452
5453 if (nItemCount % nItemCountPerColumn != 0)
5454 nColumnCount = nItemCount / nItemCountPerColumn;
5455 else
5456 nColumnCount = nItemCount / nItemCountPerColumn + 1;
5457 }
5458 }
5459
5460 /* Microsoft padding magic */
5461 wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2;
5462 wWidth = nColumnCount * infoPtr->nItemWidth + 2;
5463
5464 dwViewRect = MAKELONG(wWidth, wHeight);
5465 }
5466 else if (infoPtr->uView == LV_VIEW_DETAILS)
5467 {
5468 RECT rcBox;
5469
5470 if (infoPtr->nItemCount > 0)
5471 {
5472 LISTVIEW_GetItemBox(infoPtr, 0, &rcBox);
5473 wWidth = rcBox.right - rcBox.left;
5474 wHeight = (rcBox.bottom - rcBox.top) * nItemCount;
5475 }
5476 else
5477 {
5478 /* use current height and width */
5479 if (wHeight == 0xffff)
5480 wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
5481 if (wWidth == 0xffff)
5482 wWidth = infoPtr->rcList.right - infoPtr->rcList.left;
5483 }
5484
5485 dwViewRect = MAKELONG(wWidth, wHeight);
5486 }
5487 else if (infoPtr->uView == LV_VIEW_ICON)
5488 {
5489 UINT rows,cols;
5490 UINT nItemWidth;
5491 UINT nItemHeight;
5492
5493 nItemWidth = infoPtr->iconSpacing.cx;
5494 nItemHeight = infoPtr->iconSpacing.cy;
5495
5496 if (wWidth == 0xffff)
5497 wWidth = infoPtr->rcList.right - infoPtr->rcList.left;
5498
5499 if (wWidth < nItemWidth)
5500 wWidth = nItemWidth;
5501
5502 cols = wWidth / nItemWidth;
5503 if (cols > nItemCount)
5504 cols = nItemCount;
5505 if (cols < 1)
5506 cols = 1;
5507
5508 if (nItemCount)
5509 {
5510 rows = nItemCount / cols;
5511 if (nItemCount % cols)
5512 rows++;
5513 }
5514 else
5515 rows = 0;
5516
5517 wHeight = (nItemHeight * rows)+2;
5518 wWidth = (nItemWidth * cols)+2;
5519
5520 dwViewRect = MAKELONG(wWidth, wHeight);
5521 }
5522 else if (infoPtr->uView == LV_VIEW_SMALLICON)
5523 FIXME("uView == LV_VIEW_SMALLICON: not implemented\n");
5524
5525 return dwViewRect;
5526}
5527
5528/***
5529 * DESCRIPTION:
5530 * Cancel edit label with saving item text.
5531 *
5532 * PARAMETER(S):
5533 * [I] infoPtr : valid pointer to the listview structure
5534 *
5535 * RETURN:
5536 * Always returns TRUE.
5537 */
5539{
5540 if (infoPtr->hwndEdit)
5541 {
5542 /* handle value will be lost after LISTVIEW_EndEditLabelT */
5543 HWND edit = infoPtr->hwndEdit;
5544
5546 SendMessageW(edit, WM_CLOSE, 0, 0);
5547 }
5548
5549 return TRUE;
5550}
5551
5552/***
5553 * DESCRIPTION:
5554 * Create a drag image list for the specified item.
5555 *
5556 * PARAMETER(S):
5557 * [I] infoPtr : valid pointer to the listview structure
5558 * [I] iItem : index of item
5559 * [O] lppt : Upper-left corner of the image
5560 *
5561 * RETURN:
5562 * Returns a handle to the image list if successful, NULL otherwise.
5563 */
5565{
5566 RECT rcItem;
5567 SIZE size;
5568 POINT pos;
5569 HDC hdc, hdcOrig;
5570 HBITMAP hbmp, hOldbmp;
5571 HFONT hOldFont;
5572 HIMAGELIST dragList = 0;
5573 TRACE("iItem=%d Count=%d\n", iItem, infoPtr->nItemCount);
5574
5575 if (iItem < 0 || iItem >= infoPtr->nItemCount || !lppt)
5576 return 0;
5577
5578 rcItem.left = LVIR_BOUNDS;
5579 if (!LISTVIEW_GetItemRect(infoPtr, iItem, &rcItem))
5580 return 0;
5581
5582 lppt->x = rcItem.left;
5583 lppt->y = rcItem.top;
5584
5585 size.cx = rcItem.right - rcItem.left;
5586 size.cy = rcItem.bottom - rcItem.top;
5587
5588 hdcOrig = GetDC(infoPtr->hwndSelf);
5589 hdc = CreateCompatibleDC(hdcOrig);
5590 hbmp = CreateCompatibleBitmap(hdcOrig, size.cx, size.cy);
5591 hOldbmp = SelectObject(hdc, hbmp);
5592 hOldFont = SelectObject(hdc, infoPtr->hFont);
5593
5594 SetRect(&rcItem, 0, 0, size.cx, size.cy);
5595 FillRect(hdc, &rcItem, infoPtr->hBkBrush);
5596
5597 pos.x = pos.y = 0;
5598 if (LISTVIEW_DrawItem(infoPtr, hdc, iItem, NULL, pos, CDRF_DODEFAULT))
5599 {
5600 dragList = ImageList_Create(size.cx, size.cy, ILC_COLOR, 10, 10);
5601 SelectObject(hdc, hOldbmp);
5602 ImageList_Add(dragList, hbmp, 0);
5603 }
5604 else
5605 SelectObject(hdc, hOldbmp);
5606
5607 SelectObject(hdc, hOldFont);
5609 DeleteDC(hdc);
5610 ReleaseDC(infoPtr->hwndSelf, hdcOrig);
5611
5612 TRACE("ret=%p\n", dragList);
5613
5614 return dragList;
5615}
5616
5617
5618/***
5619 * DESCRIPTION:
5620 * Removes all listview items and subitems.
5621 *
5622 * PARAMETER(S):
5623 * [I] infoPtr : valid pointer to the listview structure
5624 *
5625 * RETURN:
5626 * SUCCESS : TRUE
5627 * FAILURE : FALSE
5628 */
5630{
5631 HDPA hdpaSubItems = NULL;
5633 ITEMHDR *hdrItem;
5634 ITEM_INFO *lpItem;
5635 ITEM_ID *lpID;
5636 INT i, j;
5637
5638 TRACE("()\n");
5639
5640 /* we do it directly, to avoid notifications */
5641 ranges_clear(infoPtr->selectionRanges);
5642 infoPtr->nSelectionMark = -1;
5643 infoPtr->nFocusedItem = -1;
5644 SetRectEmpty(&infoPtr->rcFocus);
5645 /* But we are supposed to leave nHotItem as is! */
5646
5647 /* send LVN_DELETEALLITEMS notification */
5648 if (!(infoPtr->dwStyle & LVS_OWNERDATA) || !destroy)
5649 {
5650 NMLISTVIEW nmlv;
5651
5652 memset(&nmlv, 0, sizeof(NMLISTVIEW));
5653 nmlv.iItem = -1;
5654 suppress = notify_listview(infoPtr, LVN_DELETEALLITEMS, &nmlv);
5655 }
5656
5657 for (i = infoPtr->nItemCount - 1; i >= 0; i--)
5658 {
5659 if (!(infoPtr->dwStyle & LVS_OWNERDATA))
5660 {
5661 /* send LVN_DELETEITEM notification, if not suppressed
5662 and if it is not a virtual listview */
5663 if (!suppress) notify_deleteitem(infoPtr, i);
5664 hdpaSubItems = DPA_GetPtr(infoPtr->hdpaItems, i);
5665 lpItem = DPA_GetPtr(hdpaSubItems, 0);
5666 /* free id struct */
5667 j = DPA_GetPtrIndex(infoPtr->hdpaItemIds, lpItem->id);
5668 lpID = DPA_GetPtr(infoPtr->hdpaItemIds, j);
5669 DPA_DeletePtr(infoPtr->hdpaItemIds, j);
5670 Free(lpID);
5671 /* both item and subitem start with ITEMHDR header */
5672 for (j = 0; j < DPA_GetPtrCount(hdpaSubItems); j++)
5673 {
5674 hdrItem = DPA_GetPtr(hdpaSubItems, j);
5675 if (is_text(hdrItem->pszText)) Free(hdrItem->pszText);
5676 Free(hdrItem);
5677 }
5678 DPA_Destroy(hdpaSubItems);
5679 DPA_DeletePtr(infoPtr->hdpaItems, i);
5680 }
5681 DPA_DeletePtr(infoPtr->hdpaPosX, i);
5682 DPA_DeletePtr(infoPtr->hdpaPosY, i);
5683 infoPtr->nItemCount --;
5684 }
5685
5686 if (!destroy)
5687 {
5688 LISTVIEW_Arrange(infoPtr, LVA_DEFAULT);
5689 LISTVIEW_UpdateScroll(infoPtr);
5690 }
5691 LISTVIEW_InvalidateList(infoPtr);
5692
5693 return TRUE;
5694}
5695
5696/***
5697 * DESCRIPTION:
5698 * Scrolls, and updates the columns, when a column is changing width.
5699 *
5700 * PARAMETER(S):
5701 * [I] infoPtr : valid pointer to the listview structure
5702 * [I] nColumn : column to scroll
5703 * [I] dx : amount of scroll, in pixels
5704 *
5705 * RETURN:
5706 * None.
5707 */
5708static void LISTVIEW_ScrollColumns(LISTVIEW_INFO *infoPtr, INT nColumn, INT dx)
5709{
5710 COLUMN_INFO *lpColumnInfo;
5711 RECT rcOld, rcCol;
5712 POINT ptOrigin;
5713 INT nCol;
5714 HDITEMW hdi;
5715
5716 if (nColumn < 0 || DPA_GetPtrCount(infoPtr->hdpaColumns) < 1) return;
5717 lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, min(nColumn, DPA_GetPtrCount(infoPtr->hdpaColumns) - 1));
5718 rcCol = lpColumnInfo->rcHeader;
5719 if (nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns))
5720 rcCol.left = rcCol.right;
5721
5722 /* adjust the other columns */
5723 hdi.mask = HDI_ORDER;
5724 if (SendMessageW(infoPtr->hwndHeader, HDM_GETITEMW, nColumn, (LPARAM)&hdi))
5725 {
5726 INT nOrder = hdi.iOrder;
5727 for (nCol = 0; nCol < DPA_GetPtrCount(infoPtr->hdpaColumns); nCol++)
5728 {
5729 hdi.mask = HDI_ORDER;
5730 SendMessageW(infoPtr->hwndHeader, HDM_GETITEMW, nCol, (LPARAM)&hdi);
5731 if (hdi.iOrder >= nOrder) {
5732 lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, nCol);
5733 lpColumnInfo->rcHeader.left += dx;
5734 lpColumnInfo->rcHeader.right += dx;
5735 }
5736 }
5737 }
5738
5739 /* do not update screen if not in report mode */
5740 if (!is_redrawing(infoPtr) || infoPtr->uView != LV_VIEW_DETAILS) return;
5741
5742 /* Need to reset the item width when inserting a new column */
5743 infoPtr->nItemWidth += dx;
5744
5745 LISTVIEW_UpdateScroll(infoPtr);
5746 LISTVIEW_GetOrigin(infoPtr, &ptOrigin);
5747
5748 /* scroll to cover the deleted column, and invalidate for redraw */
5749 rcOld = infoPtr->rcList;
5750 rcOld.left = ptOrigin.x + rcCol.left + dx;
5751 ScrollWindowEx(infoPtr->hwndSelf, dx, 0, &rcOld, &rcOld, 0, 0, SW_ERASE | SW_INVALIDATE);
5752}
5753
5754/***
5755 * DESCRIPTION:
5756 * Removes a column from the listview control.
5757 *
5758 * PARAMETER(S):
5759 * [I] infoPtr : valid pointer to the listview structure
5760 * [I] nColumn : column index
5761 *
5762 * RETURN:
5763 * SUCCESS : TRUE
5764 * FAILURE : FALSE
5765 */
5767{
5768 RECT rcCol;
5769
5770 TRACE("nColumn=%d\n", nColumn);
5771
5772 if (nColumn < 0 || nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns))
5773 return FALSE;
5774
5775 /* While the MSDN specifically says that column zero should not be deleted,
5776 what actually happens is that the column itself is deleted but no items or subitems
5777 are removed.
5778 */
5779
5780 LISTVIEW_GetHeaderRect(infoPtr, nColumn, &rcCol);
5781
5782 if (!SendMessageW(infoPtr->hwndHeader, HDM_DELETEITEM, nColumn, 0))
5783 return FALSE;
5784
5785 Free(DPA_GetPtr(infoPtr->hdpaColumns, nColumn));
5786 DPA_DeletePtr(infoPtr->hdpaColumns, nColumn);
5787
5788 if (!(infoPtr->dwStyle & LVS_OWNERDATA) && nColumn)
5789 {
5790 SUBITEM_INFO *lpSubItem, *lpDelItem;
5791 HDPA hdpaSubItems;
5792 INT nItem, nSubItem, i;
5793
5794 for (nItem = 0; nItem < infoPtr->nItemCount; nItem++)
5795 {
5796 hdpaSubItems = DPA_GetPtr(infoPtr->hdpaItems, nItem);
5797 nSubItem = 0;
5798 lpDelItem = 0;
5799 for (i = 1; i < DPA_GetPtrCount(hdpaSubItems); i++)
5800 {
5801 lpSubItem = DPA_GetPtr(hdpaSubItems, i);
5802 if (lpSubItem->iSubItem == nColumn)
5803 {
5804 nSubItem = i;
5805 lpDelItem = lpSubItem;
5806 }
5807 else if (lpSubItem->iSubItem > nColumn)
5808 {
5809 lpSubItem->iSubItem--;
5810 }
5811 }
5812
5813 /* if we found our subitem, zap it */
5814 if (nSubItem > 0)
5815 {
5816 /* free string */
5817 if (is_text(lpDelItem->hdr.pszText))
5818 Free(lpDelItem->hdr.pszText);
5819
5820 /* free item */
5821 Free(lpDelItem);
5822
5823 /* free dpa memory */
5824 DPA_DeletePtr(hdpaSubItems, nSubItem);
5825 }
5826 }
5827 }
5828
5829 /* update the other column info */
5830 if(DPA_GetPtrCount(infoPtr->hdpaColumns) == 0)
5831 LISTVIEW_InvalidateList(infoPtr);
5832 else
5833 LISTVIEW_ScrollColumns(infoPtr, nColumn, -(rcCol.right - rcCol.left));
5834 LISTVIEW_UpdateItemSize(infoPtr);
5835
5836 return TRUE;
5837}
5838
5839/***
5840 * DESCRIPTION:
5841 * Invalidates the listview after an item's insertion or deletion.
5842 *
5843 * PARAMETER(S):
5844 * [I] infoPtr : valid pointer to the listview structure
5845 * [I] nItem : item index
5846 * [I] dir : -1 if deleting, 1 if inserting
5847 *
5848 * RETURN:
5849 * None
5850 */
5851static void LISTVIEW_ScrollOnInsert(LISTVIEW_INFO *infoPtr, INT nItem, INT dir)
5852{
5853 INT nPerCol, nItemCol, nItemRow;
5854 RECT rcScroll;
5855 POINT Origin;
5856
5857 /* if we don't refresh, what's the point of scrolling? */
5858 if (!is_redrawing(infoPtr)) return;
5859
5860 assert (abs(dir) == 1);
5861
5862 /* arrange icons if autoarrange is on */
5863 if (is_autoarrange(infoPtr))
5864 {
5865 BOOL arrange = TRUE;
5866 if (dir < 0 && nItem >= infoPtr->nItemCount) arrange = FALSE;
5867 if (dir > 0 && nItem == infoPtr->nItemCount - 1) arrange = FALSE;
5868 if (arrange) LISTVIEW_Arrange(infoPtr, LVA_DEFAULT);
5869 }
5870
5871 /* scrollbars need updating */
5872 LISTVIEW_UpdateScroll(infoPtr);
5873
5874 /* figure out the item's position */
5875 if (infoPtr->uView == LV_VIEW_DETAILS)
5876 nPerCol = infoPtr->nItemCount + 1;
5877 else if (infoPtr->uView == LV_VIEW_LIST)
5878 nPerCol = LISTVIEW_GetCountPerColumn(infoPtr);
5879 else /* LV_VIEW_ICON, or LV_VIEW_SMALLICON */
5880 return;
5881
5882 nItemCol = nItem / nPerCol;
5883 nItemRow = nItem % nPerCol;
5884 LISTVIEW_GetOrigin(infoPtr, &Origin);
5885
5886 /* move the items below up a slot */
5887 rcScroll.left = nItemCol * infoPtr->nItemWidth;
5888 rcScroll.top = nItemRow * infoPtr->nItemHeight;
5889 rcScroll.right = rcScroll.left + infoPtr->nItemWidth;
5890 rcScroll.bottom = nPerCol * infoPtr->nItemHeight;
5891 OffsetRect(&rcScroll, Origin.x, Origin.y);
5892 TRACE("rcScroll=%s, dx=%d\n", wine_dbgstr_rect(&rcScroll), dir * infoPtr->nItemHeight);
5893 if (IntersectRect(&rcScroll, &rcScroll, &infoPtr->rcList))
5894 {
5895 TRACE("Invalidating rcScroll=%s, rcList=%s\n", wine_dbgstr_rect(&rcScroll), wine_dbgstr_rect(&infoPtr->rcList));
5896 InvalidateRect(infoPtr->hwndSelf, &rcScroll, TRUE);
5897 }
5898
5899 /* report has only that column, so we're done */
5900 if (infoPtr->uView == LV_VIEW_DETAILS) return;
5901
5902 /* now for LISTs, we have to deal with the columns to the right */
5903 SetRect(&rcScroll, (nItemCol + 1) * infoPtr->nItemWidth, 0,
5904 (infoPtr->nItemCount / nPerCol + 1) * infoPtr->nItemWidth,
5905 nPerCol * infoPtr->nItemHeight);
5906 OffsetRect(&rcScroll, Origin.x, Origin.y);
5907 if (IntersectRect(&rcScroll, &rcScroll, &infoPtr->rcList))
5908 InvalidateRect(infoPtr->hwndSelf, &rcScroll, TRUE);
5909}
5910
5911/***
5912 * DESCRIPTION:
5913 * Removes an item from the listview control.
5914 *
5915 * PARAMETER(S):
5916 * [I] infoPtr : valid pointer to the listview structure
5917 * [I] nItem : item index
5918 *
5919 * RETURN:
5920 * SUCCESS : TRUE
5921 * FAILURE : FALSE
5922 */
5924{
5925 LVITEMW item;
5926 const BOOL is_icon = (infoPtr->uView == LV_VIEW_SMALLICON || infoPtr->uView == LV_VIEW_ICON);
5927 INT focus = infoPtr->nFocusedItem;
5928
5929 TRACE("(nItem=%d)\n", nItem);
5930
5931 if (nItem < 0 || nItem >= infoPtr->nItemCount) return FALSE;
5932
5933 /* remove selection, and focus */
5934 item.state = 0;
5935 item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
5936 LISTVIEW_SetItemState(infoPtr, nItem, &item);
5937
5938 /* send LVN_DELETEITEM notification. */
5939 if (!notify_deleteitem(infoPtr, nItem)) return FALSE;
5940
5941 /* we need to do this here, because we'll be deleting stuff */
5942 if (is_icon)
5943 LISTVIEW_InvalidateItem(infoPtr, nItem);
5944
5945 if (!(infoPtr->dwStyle & LVS_OWNERDATA))
5946 {
5947 HDPA hdpaSubItems;
5948 ITEMHDR *hdrItem;
5949 ITEM_INFO *lpItem;
5950 ITEM_ID *lpID;
5951 INT i;
5952
5953 hdpaSubItems = DPA_DeletePtr(infoPtr->hdpaItems, nItem);
5954 lpItem = DPA_GetPtr(hdpaSubItems, 0);
5955
5956 /* free id struct */
5957 i = DPA_GetPtrIndex(infoPtr->hdpaItemIds, lpItem->id);
5958 lpID = DPA_GetPtr(infoPtr->hdpaItemIds, i);
5959 DPA_DeletePtr(infoPtr->hdpaItemIds, i);
5960 Free(lpID);
5961 for (i = 0; i < DPA_GetPtrCount(hdpaSubItems); i++)
5962 {
5963 hdrItem = DPA_GetPtr(hdpaSubItems, i);
5964 if (is_text(hdrItem->pszText)) Free(hdrItem->pszText);
5965 Free(hdrItem);
5966 }
5967 DPA_Destroy(hdpaSubItems);
5968 }
5969
5970 if (is_icon)
5971 {
5972 DPA_DeletePtr(infoPtr->hdpaPosX, nItem);
5973 DPA_DeletePtr(infoPtr->hdpaPosY, nItem);
5974 }
5975
5976 infoPtr->nItemCount--;
5977 LISTVIEW_ShiftIndices(infoPtr, nItem, -1);
5978 LISTVIEW_ShiftFocus(infoPtr, focus, nItem, -1);
5979
5980 /* now is the invalidation fun */
5981 if (!is_icon)
5982 LISTVIEW_ScrollOnInsert(infoPtr, nItem, -1);
5983 return TRUE;
5984}
5985
5986
5987/***
5988 * DESCRIPTION:
5989 * Callback implementation for editlabel control
5990 *
5991 * PARAMETER(S):
5992 * [I] infoPtr : valid pointer to the listview structure
5993 * [I] storeText : store edit box text as item text
5994 * [I] isW : TRUE if psxText is Unicode, FALSE if it's ANSI
5995 *
5996 * RETURN:
5997 * SUCCESS : TRUE
5998 * FAILURE : FALSE
5999 */
6001{
6002 HWND hwndSelf = infoPtr->hwndSelf;
6003 WCHAR szDispText[DISP_TEXT_SIZE] = { 0 };
6004 NMLVDISPINFOW dispInfo;
6005 INT editedItem = infoPtr->nEditLabelItem;
6006 BOOL same;
6007 WCHAR *pszText = NULL;
6008 BOOL res;
6009
6010 if (storeText)
6011 {
6013
6014 if (len++)
6015 {
6016 if (!(pszText = Alloc(len * (isW ? sizeof(WCHAR) : sizeof(CHAR)))))
6017 return FALSE;
6018
6019 if (isW)
6020 GetWindowTextW(infoPtr->hwndEdit, pszText, len);
6021 else
6022 GetWindowTextA(infoPtr->hwndEdit, (CHAR*)pszText, len);
6023 }
6024 }
6025
6026 TRACE("(pszText=%s, isW=%d)\n", debugtext_t(pszText, isW), isW);
6027
6028 ZeroMemory(&dispInfo, sizeof(dispInfo));
6029 dispInfo.item.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT;
6030 dispInfo.item.iItem = editedItem;
6031 dispInfo.item.iSubItem = 0;
6032 dispInfo.item.stateMask = ~0;
6033 dispInfo.item.pszText = szDispText;
6034 dispInfo.item.cchTextMax = DISP_TEXT_SIZE;
6035 if (!LISTVIEW_GetItemT(infoPtr, &dispInfo.item, isW))
6036 {
6037 res = FALSE;
6038 goto cleanup;
6039 }
6040
6041 if (isW)
6042 same = (lstrcmpW(dispInfo.item.pszText, pszText) == 0);
6043 else
6044 {
6045 LPWSTR tmp = textdupTtoW(pszText, FALSE);
6046 same = (lstrcmpW(dispInfo.item.pszText, tmp) == 0);
6047 textfreeT(tmp, FALSE);
6048 }
6049
6050 /* add the text from the edit in */
6051 dispInfo.item.mask |= LVIF_TEXT;
6052 dispInfo.item.pszText = same ? NULL : pszText;
6053 dispInfo.item.cchTextMax = textlenT(dispInfo.item.pszText, isW);
6054
6055 infoPtr->notify_mask &= ~NOTIFY_MASK_END_LABEL_EDIT;
6056
6057 /* Do we need to update the Item Text */
6058 res = notify_dispinfoT(infoPtr, LVN_ENDLABELEDITW, &dispInfo, isW);
6059
6061
6062 infoPtr->nEditLabelItem = -1;
6063 infoPtr->hwndEdit = 0;
6064
6065 if (!res) goto cleanup;
6066
6067 if (!IsWindow(hwndSelf))
6068 {
6069 res = FALSE;
6070 goto cleanup;
6071 }
6072 if (!pszText) return TRUE;
6073 if (same)
6074 {
6075 res = TRUE;
6076 goto cleanup;
6077 }
6078
6079 if (!(infoPtr->dwStyle & LVS_OWNERDATA))
6080 {
6081 HDPA hdpaSubItems = DPA_GetPtr(infoPtr->hdpaItems, editedItem);
6082 ITEM_INFO* lpItem = DPA_GetPtr(hdpaSubItems, 0);
6083 if (lpItem && lpItem->hdr.pszText == LPSTR_TEXTCALLBACKW)
6084 {
6085 LISTVIEW_InvalidateItem(infoPtr, editedItem);
6086 res = TRUE;
6087 goto cleanup;
6088 }
6089 }
6090
6091 ZeroMemory(&dispInfo, sizeof(dispInfo));
6092 dispInfo.item.mask = LVIF_TEXT;
6093 dispInfo.item.iItem = editedItem;
6094 dispInfo.item.iSubItem = 0;
6095 dispInfo.item.pszText = pszText;
6096 dispInfo.item.cchTextMax = textlenT(pszText, isW);
6097 res = LISTVIEW_SetItemT(infoPtr, &dispInfo.item, isW);
6098
6099cleanup:
6100 Free(pszText);
6101
6102 return res;
6103}
6104
6105/***
6106 * DESCRIPTION:
6107 * Subclassed edit control windproc function
6108 *
6109 * PARAMETER(S):
6110 * [I] hwnd : the edit window handle
6111 * [I] uMsg : the message that is to be processed
6112 * [I] wParam : first message parameter
6113 * [I] lParam : second message parameter
6114 * [I] isW : TRUE if input is Unicode
6115 *
6116 * RETURN:
6117 * Zero.
6118 */
6120{
6122 BOOL save = TRUE;
6123
6124 TRACE("(hwnd=%p, uMsg=%x, wParam=%lx, lParam=%lx, isW=%d)\n",
6125 hwnd, uMsg, wParam, lParam, isW);
6126
6127 switch (uMsg)
6128 {
6129 case WM_GETDLGCODE:
6131
6132 case WM_DESTROY:
6133 {
6134 WNDPROC editProc = infoPtr->EditWndProc;
6135 infoPtr->EditWndProc = 0;
6137 return CallWindowProcT(editProc, hwnd, uMsg, wParam, lParam, isW);
6138 }
6139
6140 case WM_KEYDOWN:
6141 if (VK_ESCAPE == (INT)wParam)
6142 {
6143 save = FALSE;
6144 break;
6145 }
6146 else if (VK_RETURN == (INT)wParam)
6147 break;
6148
6149 default:
6150 return CallWindowProcT(infoPtr->EditWndProc, hwnd, uMsg, wParam, lParam, isW);
6151 }
6152
6153 /* kill the edit */
6154 if (infoPtr->hwndEdit)
6155 LISTVIEW_EndEditLabelT(infoPtr, save, isW);
6156
6157 SendMessageW(hwnd, WM_CLOSE, 0, 0);
6158 return 0;
6159}
6160
6161/***
6162 * DESCRIPTION:
6163 * Subclassed edit control Unicode windproc function
6164 *
6165 * PARAMETER(S):
6166 * [I] hwnd : the edit window handle
6167 * [I] uMsg : the message that is to be processed
6168 * [I] wParam : first message parameter
6169 * [I] lParam : second message parameter
6170 *
6171 * RETURN:
6172 */
6174{
6175 return EditLblWndProcT(hwnd, uMsg, wParam, lParam, TRUE);
6176}
6177
6178/***
6179 * DESCRIPTION:
6180 * Subclassed edit control ANSI windproc function
6181 *
6182 * PARAMETER(S):
6183 * [I] hwnd : the edit window handle
6184 * [I] uMsg : the message that is to be processed
6185 * [I] wParam : first message parameter
6186 * [I] lParam : second message parameter
6187 *
6188 * RETURN:
6189 */
6191{
6192 return EditLblWndProcT(hwnd, uMsg, wParam, lParam, FALSE);
6193}
6194
6195/***
6196 * DESCRIPTION:
6197 * Creates a subclassed edit control
6198 *
6199 * PARAMETER(S):
6200 * [I] infoPtr : valid pointer to the listview structure
6201 * [I] text : initial text for the edit
6202 * [I] style : the window style
6203 * [I] isW : TRUE if input is Unicode
6204 *
6205 * RETURN:
6206 */
6208{
6211 HWND hedit;
6212
6213 TRACE("(%p, text=%s, isW=%d)\n", infoPtr, debugtext_t(text, isW), isW);
6214
6215 /* window will be resized and positioned after LVN_BEGINLABELEDIT */
6216 if (isW)
6217 hedit = CreateWindowW(WC_EDITW, text, style, 0, 0, 0, 0, infoPtr->hwndSelf, 0, hinst, 0);
6218 else
6219 hedit = CreateWindowA(WC_EDITA, (LPCSTR)text, style, 0, 0, 0, 0, infoPtr->hwndSelf, 0, hinst, 0);
6220
6221 if (!hedit) return 0;
6222
6223 infoPtr->EditWndProc = (WNDPROC)
6226
6227 SendMessageW(hedit, WM_SETFONT, (WPARAM)infoPtr->hFont, FALSE);
6229
6230 return hedit;
6231}
6232
6233/***
6234 * DESCRIPTION:
6235 * Begin in place editing of specified list view item
6236 *
6237 * PARAMETER(S):
6238 * [I] infoPtr : valid pointer to the listview structure
6239 * [I] nItem : item index
6240 * [I] isW : TRUE if it's a Unicode req, FALSE if ASCII
6241 *
6242 * RETURN:
6243 * SUCCESS : TRUE
6244 * FAILURE : FALSE
6245 */
6247{
6248 WCHAR disptextW[DISP_TEXT_SIZE] = { 0 };
6249 HWND hwndSelf = infoPtr->hwndSelf;
6250 NMLVDISPINFOW dispInfo;
6251 HFONT hOldFont = NULL;
6253 RECT rect;
6254 SIZE sz;
6255 HDC hdc;
6256
6257 TRACE("(nItem=%d, isW=%d)\n", nItem, isW);
6258
6259 if (~infoPtr->dwStyle & LVS_EDITLABELS) return 0;
6260
6261 /* remove existing edit box */
6262 if (infoPtr->hwndEdit)
6263 {
6264 SetFocus(infoPtr->hwndSelf);
6265 infoPtr->hwndEdit = 0;
6266 }
6267
6268 if (nItem < 0 || nItem >= infoPtr->nItemCount) return 0;
6269
6270 infoPtr->nEditLabelItem = nItem;
6271
6272 LISTVIEW_SetSelection(infoPtr, nItem);
6273 LISTVIEW_SetItemFocus(infoPtr, nItem);
6274 LISTVIEW_InvalidateItem(infoPtr, nItem);
6275
6276 rect.left = LVIR_LABEL;
6277 if (!LISTVIEW_GetItemRect(infoPtr, nItem, &rect)) return 0;
6278
6279 ZeroMemory(&dispInfo, sizeof(dispInfo));
6280 dispInfo.item.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT;
6281 dispInfo.item.iItem = nItem;
6282 dispInfo.item.iSubItem = 0;
6283 dispInfo.item.stateMask = ~0;
6284 dispInfo.item.pszText = disptextW;
6285 dispInfo.item.cchTextMax = DISP_TEXT_SIZE;
6286 if (!LISTVIEW_GetItemT(infoPtr, &dispInfo.item, isW)) return 0;
6287
6288 infoPtr->hwndEdit = CreateEditLabelT(infoPtr, dispInfo.item.pszText, isW);
6289 if (!infoPtr->hwndEdit) return 0;
6290
6291 if (notify_dispinfoT(infoPtr, LVN_BEGINLABELEDITW, &dispInfo, isW))
6292 {
6293 if (!IsWindow(hwndSelf))
6294 return 0;
6295 SendMessageW(infoPtr->hwndEdit, WM_CLOSE, 0, 0);
6296 infoPtr->hwndEdit = 0;
6297 return 0;
6298 }
6299
6300 TRACE("disp text=%s\n", debugtext_t(dispInfo.item.pszText, isW));
6301
6302 /* position and display edit box */
6303 hdc = GetDC(infoPtr->hwndSelf);
6304
6305 /* select the font to get appropriate metric dimensions */
6306 if (infoPtr->hFont)
6307 hOldFont = SelectObject(hdc, infoPtr->hFont);
6308
6309 /* use real edit box content, it could be altered during LVN_BEGINLABELEDIT notification */
6310 GetWindowTextW(infoPtr->hwndEdit, disptextW, DISP_TEXT_SIZE);
6311 TRACE("edit box text=%s\n", debugstr_w(disptextW));
6312
6313 /* get string length in pixels */
6314 GetTextExtentPoint32W(hdc, disptextW, lstrlenW(disptextW), &sz);
6315
6316 /* add extra spacing for the next character */
6318 sz.cx += tm.tmMaxCharWidth * 2;
6319
6320 if (infoPtr->hFont)
6321 SelectObject(hdc, hOldFont);
6322
6323 ReleaseDC(infoPtr->hwndSelf, hdc);
6324
6325 sz.cy = rect.bottom - rect.top + 2;
6326 rect.left -= 2;
6327 rect.top -= 1;
6328 TRACE("moving edit=(%d,%d)-(%d,%d)\n", rect.left, rect.top, sz.cx, sz.cy);
6329 MoveWindow(infoPtr->hwndEdit, rect.left, rect.top, sz.cx, sz.cy, FALSE);
6330 ShowWindow(infoPtr->hwndEdit, SW_NORMAL);
6331 SetFocus(infoPtr->hwndEdit);
6332 SendMessageW(infoPtr->hwndEdit, EM_SETSEL, 0, -1);
6333 return infoPtr->hwndEdit;
6334}
6335
6336
6337/***
6338 * DESCRIPTION:
6339 * Ensures the specified item is visible, scrolling into view if necessary.
6340 *
6341 * PARAMETER(S):
6342 * [I] infoPtr : valid pointer to the listview structure
6343 * [I] nItem : item index
6344 * [I] bPartial : partially or entirely visible
6345 *
6346 * RETURN:
6347 * SUCCESS : TRUE
6348 * FAILURE : FALSE
6349 */
6350static BOOL LISTVIEW_EnsureVisible(LISTVIEW_INFO *infoPtr, INT nItem, BOOL bPartial)
6351{
6352 INT nScrollPosHeight = 0;
6353 INT nScrollPosWidth = 0;
6354 INT nHorzAdjust = 0;
6355 INT nVertAdjust = 0;
6356 INT nHorzDiff = 0;
6357 INT nVertDiff = 0;
6358 RECT rcItem, rcTemp;
6359
6360 rcItem.left = LVIR_BOUNDS;
6361 if (!LISTVIEW_GetItemRect(infoPtr, nItem, &rcItem)) return FALSE;
6362
6363 if (bPartial && IntersectRect(&rcTemp, &infoPtr->rcList, &rcItem)) return TRUE;
6364
6365 if (rcItem.left < infoPtr->rcList.left || rcItem.right > infoPtr->rcList.right)
6366 {
6367 /* scroll left/right, but in LV_VIEW_DETAILS mode */
6368 if (infoPtr->uView == LV_VIEW_LIST)
6369 nScrollPosWidth = infoPtr->nItemWidth;
6370 else if ((infoPtr->uView == LV_VIEW_SMALLICON) || (infoPtr->uView == LV_VIEW_ICON))
6371 nScrollPosWidth = 1;
6372
6373 if (rcItem.left < infoPtr->rcList.left)
6374 {
6375 nHorzAdjust = -1;
6376 if (infoPtr->uView != LV_VIEW_DETAILS) nHorzDiff = rcItem.left - infoPtr->rcList.left;
6377 }
6378 else
6379 {
6380 nHorzAdjust = 1;
6381 if (infoPtr->uView != LV_VIEW_DETAILS) nHorzDiff = rcItem.right - infoPtr->rcList.right;
6382 }
6383 }
6384
6385 if (rcItem.top < infoPtr->rcList.top || rcItem.bottom > infoPtr->rcList.bottom)
6386 {
6387 /* scroll up/down, but not in LVS_LIST mode */
6388 if (infoPtr->uView == LV_VIEW_DETAILS)
6389 nScrollPosHeight = infoPtr->nItemHeight;
6390 else if ((infoPtr->uView == LV_VIEW_ICON) || (infoPtr->uView == LV_VIEW_SMALLICON))
6391 nScrollPosHeight = 1;
6392
6393 if (rcItem.top < infoPtr->rcList.top)
6394 {
6395 nVertAdjust = -1;
6396 if (infoPtr->uView != LV_VIEW_LIST) nVertDiff = rcItem.top - infoPtr->rcList.top;
6397 }
6398 else
6399 {
6400 nVertAdjust = 1;
6401 if (infoPtr->uView != LV_VIEW_LIST) nVertDiff = rcItem.bottom - infoPtr->rcList.bottom;
6402 }
6403 }
6404
6405 if (!nScrollPosWidth && !nScrollPosHeight) return TRUE;
6406
6407 if (nScrollPosWidth)
6408 {
6409 INT diff = nHorzDiff / nScrollPosWidth;
6410 if (nHorzDiff % nScrollPosWidth) diff += nHorzAdjust;
6411 LISTVIEW_HScroll(infoPtr, SB_INTERNAL, diff);
6412 }
6413
6414 if (nScrollPosHeight)
6415 {
6416 INT diff = nVertDiff / nScrollPosHeight;
6417 if (nVertDiff % nScrollPosHeight) diff += nVertAdjust;
6418 LISTVIEW_VScroll(infoPtr, SB_INTERNAL, diff);
6419 }
6420
6421 return TRUE;
6422}
6423
6424/***
6425 * DESCRIPTION:
6426 * Searches for an item with specific characteristics.
6427 *
6428 * PARAMETER(S):
6429 * [I] hwnd : window handle
6430 * [I] nStart : base item index
6431 * [I] lpFindInfo : item information to look for
6432 *
6433 * RETURN:
6434 * SUCCESS : index of item
6435 * FAILURE : -1
6436 */
6437static INT LISTVIEW_FindItemW(const LISTVIEW_INFO *infoPtr, INT nStart,
6438 const LVFINDINFOW *lpFindInfo)
6439{
6440 WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
6441 BOOL bWrap = FALSE, bNearest = FALSE;
6442 INT nItem = nStart + 1, nLast = infoPtr->nItemCount, nNearestItem = -1;
6443 ULONG xdist, ydist, dist, mindist = 0x7fffffff;
6445 LVITEMW lvItem;
6446
6447 /* Search in virtual listviews should be done by application, not by
6448 listview control, so we just send LVN_ODFINDITEMW and return the result */
6449 if (infoPtr->dwStyle & LVS_OWNERDATA)
6450 {
6451 NMLVFINDITEMW nmlv;
6452
6453 nmlv.iStart = nStart;
6454 nmlv.lvfi = *lpFindInfo;
6455 return notify_hdr(infoPtr, LVN_ODFINDITEMW, (LPNMHDR)&nmlv.hdr);
6456 }
6457
6458 if (!lpFindInfo || nItem < 0) return -1;
6459
6460 lvItem.mask = 0;
6461 if (lpFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL | LVFI_SUBSTRING))
6462 {
6463 lvItem.mask |= LVIF_TEXT;
6464 lvItem.pszText = szDispText;
6465 lvItem.cchTextMax = DISP_TEXT_SIZE;
6466 }
6467
6468 if (lpFindInfo->flags & LVFI_WRAP)
6469 bWrap = TRUE;
6470
6471 if ((lpFindInfo->flags & LVFI_NEARESTXY) &&
6472 (infoPtr->uView == LV_VIEW_ICON || infoPtr->uView == LV_VIEW_SMALLICON))
6473 {
6474 POINT Origin;
6475 RECT rcArea;
6476
6477 LISTVIEW_GetOrigin(infoPtr, &Origin);
6478 Destination.x = lpFindInfo->pt.x - Origin.x;
6479 Destination.y = lpFindInfo->pt.y - Origin.y;
6480 switch(lpFindInfo->vkDirection)
6481 {
6482 case VK_DOWN: Destination.y += infoPtr->nItemHeight; break;
6483 case VK_UP: Destination.y -= infoPtr->nItemHeight; break;
6484 case VK_RIGHT: Destination.x += infoPtr->nItemWidth; break;
6485 case VK_LEFT: Destination.x -= infoPtr->nItemWidth; break;
6486 case VK_HOME: Destination.x = Destination.y = 0; break;
6487 case VK_NEXT: Destination.y += infoPtr->rcList.bottom - infoPtr->rcList.top; break;
6488 case VK_PRIOR: Destination.y -= infoPtr->rcList.bottom - infoPtr->rcList.top; break;
6489 case VK_END:
6490 LISTVIEW_GetAreaRect(infoPtr, &rcArea);
6491 Destination.x = rcArea.right;
6492 Destination.y = rcArea.bottom;
6493 break;
6494 default: ERR("Unknown vkDirection=%d\n", lpFindInfo->vkDirection);
6495 }
6496 bNearest = TRUE;
6497 }
6498 else Destination.x = Destination.y = 0;
6499
6500 /* if LVFI_PARAM is specified, all other flags are ignored */
6501 if (lpFindInfo->flags & LVFI_PARAM)
6502 {
6503 lvItem.mask |= LVIF_PARAM;
6504 bNearest = FALSE;
6505 lvItem.mask &= ~LVIF_TEXT;
6506 }
6507
6508 nItem = bNearest ? -1 : nStart + 1;
6509
6510again:
6511 for (; nItem < nLast; nItem++)
6512 {
6513 lvItem.iItem = nItem;
6514 lvItem.iSubItem = 0;
6515 lvItem.pszText = szDispText;
6516 if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) continue;
6517
6518 if (lvItem.mask & LVIF_PARAM)
6519 {
6520 if (lpFindInfo->lParam == lvItem.lParam)
6521 return nItem;
6522 else
6523 continue;
6524 }
6525
6526 if (lvItem.mask & LVIF_TEXT)
6527 {
6528 if (lpFindInfo->flags & (LVFI_PARTIAL | LVFI_SUBSTRING))
6529 {
6530 WCHAR *p = wcsstr(lvItem.pszText, lpFindInfo->psz);
6531 if (!p || p != lvItem.pszText) continue;
6532 }
6533 else
6534 {
6535 if (lstrcmpW(lvItem.pszText, lpFindInfo->psz) != 0) continue;
6536 }
6537 }
6538
6539 if (!bNearest) return nItem;
6540
6541 /* This is very inefficient. To do a good job here,
6542 * we need a sorted array of (x,y) item positions */
6543 LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position);
6544
6545 /* compute the distance^2 to the destination */
6546 xdist = Destination.x - Position.x;
6547 ydist = Destination.y - Position.y;
6548 dist = xdist * xdist + ydist * ydist;
6549
6550 /* remember the distance, and item if it's closer */
6551 if (dist < mindist)
6552 {
6553 mindist = dist;
6554 nNearestItem = nItem;
6555 }
6556 }
6557
6558 if (bWrap)
6559 {
6560 nItem = 0;
6561 nLast = min(nStart + 1, infoPtr->nItemCount);
6562 bWrap = FALSE;
6563 goto again;
6564 }
6565
6566 return nNearestItem;
6567}
6568
6569/***
6570 * DESCRIPTION:
6571 * Searches for an item with specific characteristics.
6572 *
6573 * PARAMETER(S):
6574 * [I] hwnd : window handle
6575 * [I] nStart : base item index
6576 * [I] lpFindInfo : item information to look for
6577 *
6578 * RETURN:
6579 * SUCCESS : index of item
6580 * FAILURE : -1
6581 */
6582static INT LISTVIEW_FindItemA(const LISTVIEW_INFO *infoPtr, INT nStart,
6583 const LVFINDINFOA *lpFindInfo)
6584{
6585 LVFINDINFOW fiw;
6586 INT res;
6587 LPWSTR strW = NULL;
6588
6589 memcpy(&fiw, lpFindInfo, sizeof(fiw));
6590 if (lpFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL | LVFI_SUBSTRING))
6591 fiw.psz = strW = textdupTtoW((LPCWSTR)lpFindInfo->psz, FALSE);
6592 res = LISTVIEW_FindItemW(infoPtr, nStart, &fiw);
6594 return res;
6595}
6596
6597/***
6598 * DESCRIPTION:
6599 * Retrieves column attributes.
6600 *
6601 * PARAMETER(S):
6602 * [I] infoPtr : valid pointer to the listview structure
6603 * [I] nColumn : column index
6604 * [IO] lpColumn : column information
6605 * [I] isW : if TRUE, then lpColumn is a LPLVCOLUMNW
6606 * otherwise it is in fact a LPLVCOLUMNA
6607 *
6608 * RETURN:
6609 * SUCCESS : TRUE
6610 * FAILURE : FALSE
6611 */
6612static BOOL LISTVIEW_GetColumnT(const LISTVIEW_INFO *infoPtr, INT nColumn, LPLVCOLUMNW lpColumn, BOOL isW)
6613{
6614 COLUMN_INFO *lpColumnInfo;
6615 HDITEMW hdi;
6616
6617 if (!lpColumn || nColumn < 0 || nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return FALSE;
6618 lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, nColumn);
6619
6620 /* initialize memory */
6621 ZeroMemory(&hdi, sizeof(hdi));
6622
6623 if (lpColumn->mask & LVCF_TEXT)
6624 {
6625 hdi.mask |= HDI_TEXT;
6626 hdi.pszText = lpColumn->pszText;
6627 hdi.cchTextMax = lpColumn->cchTextMax;
6628 }
6629
6630 if (lpColumn->mask & LVCF_IMAGE)
6631 hdi.mask |= HDI_IMAGE;
6632
6633 if (lpColumn->mask & LVCF_ORDER)
6634 hdi.mask |= HDI_ORDER;
6635
6636 if (lpColumn->mask & LVCF_SUBITEM)
6637 hdi.mask |= HDI_LPARAM;
6638
6639 if (!SendMessageW(infoPtr->hwndHeader, isW ? HDM_GETITEMW : HDM_GETITEMA, nColumn, (LPARAM)&hdi)) return FALSE;
6640
6641 if (lpColumn->mask & LVCF_FMT)
6642 lpColumn->fmt = lpColumnInfo->fmt;
6643
6644 if (lpColumn->mask & LVCF_WIDTH)
6645 lpColumn->cx = lpColumnInfo->rcHeader.right - lpColumnInfo->rcHeader.left;
6646
6647 if (lpColumn->mask & LVCF_IMAGE)
6648 lpColumn->iImage = hdi.iImage;
6649
6650 if (lpColumn->mask & LVCF_ORDER)
6651 lpColumn->iOrder = hdi.iOrder;
6652
6653 if (lpColumn->mask & LVCF_SUBITEM)
6654 lpColumn->iSubItem = hdi.lParam;
6655
6656 if (lpColumn->mask & LVCF_MINWIDTH)
6657 lpColumn->cxMin = lpColumnInfo->cxMin;
6658
6659 return TRUE;
6660}
6661
6662static inline BOOL LISTVIEW_GetColumnOrderArray(const LISTVIEW_INFO *infoPtr, INT iCount, LPINT lpiArray)
6663{
6664 if (!infoPtr->hwndHeader) return FALSE;
6665 return SendMessageW(infoPtr->hwndHeader, HDM_GETORDERARRAY, iCount, (LPARAM)lpiArray);
6666}
6667
6668/***
6669 * DESCRIPTION:
6670 * Retrieves the column width.
6671 *
6672 * PARAMETER(S):
6673 * [I] infoPtr : valid pointer to the listview structure
6674 * [I] int : column index
6675 *
6676 * RETURN:
6677 * SUCCESS : column width
6678 * FAILURE : zero
6679 */
6680static INT LISTVIEW_GetColumnWidth(const LISTVIEW_INFO *infoPtr, INT nColumn)
6681{
6682 INT nColumnWidth = 0;
6683 HDITEMW hdItem;
6684
6685 TRACE("nColumn=%d\n", nColumn);
6686
6687 /* we have a 'column' in LIST and REPORT mode only */
6688 switch(infoPtr->uView)
6689 {
6690 case LV_VIEW_LIST:
6691 nColumnWidth = infoPtr->nItemWidth;
6692 break;
6693 case LV_VIEW_DETAILS:
6694 /* We are not using LISTVIEW_GetHeaderRect as this data is updated only after a HDN_ITEMCHANGED.
6695 * There is an application that subclasses the listview, calls LVM_GETCOLUMNWIDTH in the
6696 * HDN_ITEMCHANGED handler and goes into infinite recursion if it receives old data.
6697 */
6698 hdItem.mask = HDI_WIDTH;
6699 if (!SendMessageW(infoPtr->hwndHeader, HDM_GETITEMW, nColumn, (LPARAM)&hdItem))
6700 {
6701 WARN("(%p): HDM_GETITEMW failed for item %d\n", infoPtr->hwndSelf, nColumn);
6702 return 0;
6703 }
6704 nColumnWidth = hdItem.cxy;
6705 break;
6706 }
6707
6708 TRACE("nColumnWidth=%d\n", nColumnWidth);
6709 return nColumnWidth;
6710}
6711
6712/***
6713 * DESCRIPTION:
6714 * In list or report display mode, retrieves the number of items that can fit
6715 * vertically in the visible area. In icon or small icon display mode,
6716 * retrieves the total number of visible items.
6717 *
6718 * PARAMETER(S):
6719 * [I] infoPtr : valid pointer to the listview structure
6720 *
6721 * RETURN:
6722 * Number of fully visible items.
6723 */
6725{
6726 switch (infoPtr->uView)
6727 {
6728 case LV_VIEW_ICON:
6729 case LV_VIEW_SMALLICON:
6730 return infoPtr->nItemCount;
6731 case LV_VIEW_DETAILS:
6732 return LISTVIEW_GetCountPerColumn(infoPtr);
6733 case LV_VIEW_LIST:
6734 return LISTVIEW_GetCountPerRow(infoPtr) * LISTVIEW_GetCountPerColumn(infoPtr);
6735 }
6736 assert(FALSE);
6737 return 0;
6738}
6739
6740/***
6741 * DESCRIPTION:
6742 * Retrieves an image list handle.
6743 *
6744 * PARAMETER(S):
6745 * [I] infoPtr : valid pointer to the listview structure
6746 * [I] nImageList : image list identifier
6747 *
6748 * RETURN:
6749 * SUCCESS : image list handle
6750 * FAILURE : NULL
6751 */
6752static HIMAGELIST LISTVIEW_GetImageList(const LISTVIEW_INFO *infoPtr, INT nImageList)
6753{
6754 switch (nImageList)
6755 {
6756 case LVSIL_NORMAL: return infoPtr->himlNormal;
6757 case LVSIL_SMALL: return infoPtr->himlSmall;
6758 case LVSIL_STATE: return infoPtr->himlState;
6759 case LVSIL_GROUPHEADER:
6760 FIXME("LVSIL_GROUPHEADER not supported\n");
6761 break;
6762 default:
6763 WARN("got unknown imagelist index - %d\n", nImageList);
6764 }
6765 return NULL;
6766}
6767
6768/* LISTVIEW_GetISearchString */
6769
6770/***
6771 * DESCRIPTION:
6772 * Retrieves item attributes.
6773 *
6774 * PARAMETER(S):
6775 * [I] hwnd : window handle
6776 * [IO] lpLVItem : item info
6777 * [I] isW : if TRUE, then lpLVItem is a LPLVITEMW,
6778 * if FALSE, then lpLVItem is a LPLVITEMA.
6779 *
6780 * NOTE:
6781 * This is the internal 'GetItem' interface -- it tries to
6782 * be smart and avoid text copies, if possible, by modifying
6783 * lpLVItem->pszText to point to the text string. Please note
6784 * that this is not always possible (e.g. OWNERDATA), so on
6785 * entry you *must* supply valid values for pszText, and cchTextMax.
6786 * The only difference to the documented interface is that upon
6787 * return, you should use *only* the lpLVItem->pszText, rather than
6788 * the buffer pointer you provided on input. Most code already does
6789 * that, so it's not a problem.
6790 * For the two cases when the text must be copied (that is,
6791 * for LVM_GETITEM, and LVM_GETITEMTEXT), use LISTVIEW_GetItemExtT.
6792 *
6793 * RETURN:
6794 * SUCCESS : TRUE
6795 * FAILURE : FALSE
6796 */
6797static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
6798{
6799 ITEMHDR callbackHdr = { LPSTR_TEXTCALLBACKW, I_IMAGECALLBACK };
6800 NMLVDISPINFOW dispInfo;
6801 ITEM_INFO *lpItem;
6802 ITEMHDR* pItemHdr;
6803 HDPA hdpaSubItems;
6804 INT isubitem;
6805
6806 TRACE("(item=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW);
6807
6808 if (!lpLVItem || lpLVItem->iItem < 0 || lpLVItem->iItem >= infoPtr->nItemCount)
6809 return FALSE;
6810
6811 if (lpLVItem->mask == 0) return TRUE;
6812 TRACE("mask=%x\n", lpLVItem->mask);
6813
6814 /* make a local copy */
6815 isubitem = lpLVItem->iSubItem;
6816
6817 if (isubitem && (lpLVItem->mask & LVIF_STATE))
6818 lpLVItem->state = 0;
6819
6820 /* a quick optimization if all we're asked is the focus state
6821 * these queries are worth optimising since they are common,
6822 * and can be answered in constant time, without the heavy accesses */
6823 if ( (lpLVItem->mask == LVIF_STATE) && (lpLVItem->stateMask == LVIS_FOCUSED) &&
6824 !(infoPtr->uCallbackMask & LVIS_FOCUSED) )
6825 {
6826 lpLVItem->state = 0;
6827 if (infoPtr->nFocusedItem == lpLVItem->iItem && isubitem == 0)
6828 lpLVItem->state |= LVIS_FOCUSED;
6829 return TRUE;
6830 }
6831
6832 ZeroMemory(&dispInfo, sizeof(dispInfo));
6833
6834 /* if the app stores all the data, handle it separately */
6835 if (infoPtr->dwStyle & LVS_OWNERDATA)
6836 {
6837 dispInfo.item.state = 0;
6838
6839 /* apparently, we should not callback for lParam in LVS_OWNERDATA */
6840 if ((lpLVItem->mask & ~(LVIF_STATE | LVIF_PARAM)) ||
6841 ((lpLVItem->mask & LVIF_STATE) && (infoPtr->uCallbackMask & lpLVItem->stateMask)))
6842 {
6843 UINT mask = lpLVItem->mask;
6844
6845 /* NOTE: copy only fields which we _know_ are initialized, some apps
6846 * depend on the uninitialized fields being 0 */
6847 dispInfo.item.mask = lpLVItem->mask & ~LVIF_PARAM;
6848 dispInfo.item.iItem = lpLVItem->iItem;
6849 dispInfo.item.iSubItem = isubitem;
6850 if (lpLVItem->mask & LVIF_TEXT)
6851 {
6852 if (lpLVItem->mask & LVIF_NORECOMPUTE)
6853 /* reset mask */
6854 dispInfo.item.mask &= ~(LVIF_TEXT | LVIF_NORECOMPUTE);
6855 else
6856 {
6857 dispInfo.item.pszText = lpLVItem->pszText;
6858 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
6859 }
6860 }
6861 if (lpLVItem->mask & LVIF_STATE)
6862 dispInfo.item.stateMask = lpLVItem->stateMask & infoPtr->uCallbackMask;
6863 /* could be zeroed on LVIF_NORECOMPUTE case */
6864 if (dispInfo.item.mask)
6865 {
6866 notify_dispinfoT(infoPtr, LVN_GETDISPINFOW, &dispInfo, isW);
6867 dispInfo.item.stateMask = lpLVItem->stateMask;
6868 if (lpLVItem->mask & (LVIF_GROUPID|LVIF_COLUMNS))
6869 {
6870 /* full size structure expected - _WIN32IE >= 0x560 */
6871 *lpLVItem = dispInfo.item;
6872 }
6873 else if (lpLVItem->mask & LVIF_INDENT)
6874 {
6875 /* indent member expected - _WIN32IE >= 0x300 */
6876 memcpy(lpLVItem, &dispInfo.item, offsetof( LVITEMW, iGroupId ));
6877 }
6878 else
6879 {
6880 /* minimal structure expected */
6881 memcpy(lpLVItem, &dispInfo.item, offsetof( LVITEMW, iIndent ));
6882 }
6883 lpLVItem->mask = mask;
6884 TRACE(" getdispinfo(1):lpLVItem=%s\n", debuglvitem_t(lpLVItem, isW));
6885 }
6886 }
6887
6888 /* make sure lParam is zeroed out */
6889 if (lpLVItem->mask & LVIF_PARAM) lpLVItem->lParam = 0;
6890
6891 /* callback marked pointer required here */
6892 if ((lpLVItem->mask & LVIF_TEXT) && (lpLVItem->mask & LVIF_NORECOMPUTE))
6893 lpLVItem->pszText = LPSTR_TEXTCALLBACKW;
6894
6895 /* we store only a little state, so if we're not asked, we're done */
6896 if (!(lpLVItem->mask & LVIF_STATE) || isubitem) return TRUE;
6897
6898 /* if focus is handled by us, report it */
6899 if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED )
6900 {
6901 lpLVItem->state &= ~LVIS_FOCUSED;
6902 if (infoPtr->nFocusedItem == lpLVItem->iItem)
6903 lpLVItem->state |= LVIS_FOCUSED;
6904 }
6905
6906 /* and do the same for selection, if we handle it */
6907 if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED )
6908 {
6909 lpLVItem->state &= ~LVIS_SELECTED;
6910 if (ranges_contain(infoPtr->selectionRanges, lpLVItem->iItem))
6911 lpLVItem->state |= LVIS_SELECTED;
6912 }
6913
6914 return TRUE;
6915 }
6916
6917 /* find the item and subitem structures before we proceed */
6918 hdpaSubItems = DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
6919 lpItem = DPA_GetPtr(hdpaSubItems, 0);
6920 assert (lpItem);
6921
6922 if (isubitem)
6923 {
6924 SUBITEM_INFO *lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, isubitem);
6925 pItemHdr = lpSubItem ? &lpSubItem->hdr : &callbackHdr;
6926 if (!lpSubItem)
6927 {
6928 WARN(" iSubItem invalid (%08x), ignored.\n", isubitem);
6929 isubitem = 0;
6930 }
6931 }
6932 else
6933 pItemHdr = &lpItem->hdr;
6934
6935 /* Do we need to query the state from the app? */
6936 if ((lpLVItem->mask & LVIF_STATE) && infoPtr->uCallbackMask && isubitem == 0)
6937 {
6938 dispInfo.item.mask |= LVIF_STATE;
6939 dispInfo.item.stateMask = infoPtr->uCallbackMask;
6940 }
6941
6942 /* Do we need to enquire about the image? */
6943 if ((lpLVItem->mask & LVIF_IMAGE) && pItemHdr->iImage == I_IMAGECALLBACK &&
6944 (isubitem == 0 || (infoPtr->dwLvExStyle & LVS_EX_SUBITEMIMAGES)))
6945 {
6946 dispInfo.item.mask |= LVIF_IMAGE;
6947 dispInfo.item.iImage = I_IMAGECALLBACK;
6948 }
6949
6950 /* Only items support indentation */
6951 if ((lpLVItem->mask & LVIF_INDENT) && lpItem->iIndent == I_INDENTCALLBACK &&
6952 (isubitem == 0))
6953 {
6954 dispInfo.item.mask |= LVIF_INDENT;
6955 dispInfo.item.iIndent = I_INDENTCALLBACK;
6956 }
6957
6958 /* Apps depend on calling back for text if it is NULL or LPSTR_TEXTCALLBACKW */
6959 if ((lpLVItem->mask & LVIF_TEXT) && !(lpLVItem->mask & LVIF_NORECOMPUTE) &&
6960 !is_text(pItemHdr->pszText))
6961 {
6962 dispInfo.item.mask |= LVIF_TEXT;
6963 dispInfo.item.pszText = lpLVItem->pszText;
6964 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
6965 if (dispInfo.item.pszText && dispInfo.item.cchTextMax > 0)
6966 *dispInfo.item.pszText = '\0';
6967 }
6968
6969 /* If we don't have all the requested info, query the application */
6970 if (dispInfo.item.mask)
6971 {
6972 dispInfo.item.iItem = lpLVItem->iItem;
6973 dispInfo.item.iSubItem = lpLVItem->iSubItem; /* yes: the original subitem */
6974 dispInfo.item.lParam = lpItem->lParam;
6975 notify_dispinfoT(infoPtr, LVN_GETDISPINFOW, &dispInfo, isW);
6976 TRACE(" getdispinfo(2):item=%s\n", debuglvitem_t(&dispInfo.item, isW));
6977 }
6978
6979 /* we should not store values for subitems */
6980 if (isubitem) dispInfo.item.mask &= ~LVIF_DI_SETITEM;
6981
6982 /* Now, handle the iImage field */
6983 if (dispInfo.item.mask & LVIF_IMAGE)
6984 {
6985 lpLVItem->iImage = dispInfo.item.iImage;
6986 if ((dispInfo.item.mask & LVIF_DI_SETITEM) && pItemHdr->iImage == I_IMAGECALLBACK)
6987 pItemHdr->iImage = dispInfo.item.iImage;
6988 }
6989 else if (lpLVItem->mask & LVIF_IMAGE)
6990 {
6991 if(isubitem == 0 || (infoPtr->dwLvExStyle & LVS_EX_SUBITEMIMAGES))
6992 lpLVItem->iImage = pItemHdr->iImage;
6993 else
6994 lpLVItem->iImage = 0;
6995 }
6996
6997 /* The pszText field */
6998 if (dispInfo.item.mask & LVIF_TEXT)
6999 {
7000 if ((dispInfo.item.mask & LVIF_DI_SETITEM) && pItemHdr->pszText)
7001 textsetptrT(&pItemHdr->pszText, dispInfo.item.pszText, isW);
7002
7003 lpLVItem->pszText = dispInfo.item.pszText;
7004 }
7005 else if (lpLVItem->mask & LVIF_TEXT)
7006 {
7007 /* if LVN_GETDISPINFO's disabled with LVIF_NORECOMPUTE return callback placeholder */
7008 if (isW || !is_text(pItemHdr->pszText)) lpLVItem->pszText = pItemHdr->pszText;
7009 else textcpynT(lpLVItem->pszText, isW, pItemHdr->pszText, TRUE, lpLVItem->cchTextMax);
7010 }
7011
7012 /* Next is the lParam field */
7013 if (dispInfo.item.mask & LVIF_PARAM)
7014 {
7015 lpLVItem->lParam = dispInfo.item.lParam;
7016 if ((dispInfo.item.mask & LVIF_DI_SETITEM))
7017 lpItem->lParam = dispInfo.item.lParam;
7018 }
7019 else if (lpLVItem->mask & LVIF_PARAM)
7020 lpLVItem->lParam = lpItem->lParam;
7021
7022 /* if this is a subitem, we're done */
7023 if (isubitem) return TRUE;
7024
7025 /* ... the state field (this one is different due to uCallbackmask) */
7026 if (lpLVItem->mask & LVIF_STATE)
7027 {
7028 lpLVItem->state = lpItem->state & lpLVItem->stateMask;
7029 if (dispInfo.item.mask & LVIF_STATE)
7030 {
7031 lpLVItem->state &= ~dispInfo.item.stateMask;
7032 lpLVItem->state |= (dispInfo.item.state & dispInfo.item.stateMask);
7033 }
7034 if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED )
7035 {
7036 lpLVItem->state &= ~LVIS_FOCUSED;
7037 if (infoPtr->nFocusedItem == lpLVItem->iItem)
7038 lpLVItem->state |= LVIS_FOCUSED;
7039 }
7040 if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED )
7041 {
7042 lpLVItem->state &= ~LVIS_SELECTED;
7043 if (ranges_contain(infoPtr->selectionRanges, lpLVItem->iItem))
7044 lpLVItem->state |= LVIS_SELECTED;
7045 }
7046 }
7047
7048 /* and last, but not least, the indent field */
7049 if (dispInfo.item.mask & LVIF_INDENT)
7050 {
7051 lpLVItem->iIndent = dispInfo.item.iIndent;
7052 if ((dispInfo.item.mask & LVIF_DI_SETITEM) && lpItem->iIndent == I_INDENTCALLBACK)
7053 lpItem->iIndent = dispInfo.item.iIndent;
7054 }
7055 else if (lpLVItem->mask & LVIF_INDENT)
7056 {
7057 lpLVItem->iIndent = lpItem->iIndent;
7058 }
7059
7060 return TRUE;
7061}
7062
7063/***
7064 * DESCRIPTION:
7065 * Retrieves item attributes.
7066 *
7067 * PARAMETER(S):
7068 * [I] hwnd : window handle
7069 * [IO] lpLVItem : item info
7070 * [I] isW : if TRUE, then lpLVItem is a LPLVITEMW,
7071 * if FALSE, then lpLVItem is a LPLVITEMA.
7072 *
7073 * NOTE:
7074 * This is the external 'GetItem' interface -- it properly copies
7075 * the text in the provided buffer.
7076 *
7077 * RETURN:
7078 * SUCCESS : TRUE
7079 * FAILURE : FALSE
7080 */
7081static BOOL LISTVIEW_GetItemExtT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
7082{
7083 LPWSTR pszText;
7084 BOOL bResult;
7085
7086 if (!lpLVItem || lpLVItem->iItem < 0 || lpLVItem->iItem >= infoPtr->nItemCount)
7087 return FALSE;
7088
7089 pszText = lpLVItem->pszText;
7090 bResult = LISTVIEW_GetItemT(infoPtr, lpLVItem, isW);
7091 if (bResult && (lpLVItem->mask & LVIF_TEXT) && lpLVItem->pszText != pszText)
7092 {
7093 if (lpLVItem->pszText != LPSTR_TEXTCALLBACKW)
7094 textcpynT(pszText, isW, lpLVItem->pszText, isW, lpLVItem->cchTextMax);
7095 else
7096 pszText = LPSTR_TEXTCALLBACKW;
7097 }
7098 lpLVItem->pszText = pszText;
7099
7100 return bResult;
7101}
7102
7103
7104/***
7105 * DESCRIPTION:
7106 * Retrieves the position (upper-left) of the listview control item.
7107 * Note that for LVS_ICON style, the upper-left is that of the icon
7108 * and not the bounding box.
7109 *
7110 * PARAMETER(S):
7111 * [I] infoPtr : valid pointer to the listview structure
7112 * [I] nItem : item index
7113 * [O] lpptPosition : coordinate information
7114 *
7115 * RETURN:
7116 * SUCCESS : TRUE
7117 * FAILURE : FALSE
7118 */
7119static BOOL LISTVIEW_GetItemPosition(const LISTVIEW_INFO *infoPtr, INT nItem, LPPOINT lpptPosition)
7120{
7121 POINT Origin;
7122
7123 TRACE("(nItem=%d, lpptPosition=%p)\n", nItem, lpptPosition);
7124
7125 if (!lpptPosition || nItem < 0 || nItem >= infoPtr->nItemCount) return FALSE;
7126
7127 LISTVIEW_GetOrigin(infoPtr, &Origin);
7128 LISTVIEW_GetItemOrigin(infoPtr, nItem, lpptPosition);
7129
7130 if (infoPtr->uView == LV_VIEW_ICON)
7131 {
7132 lpptPosition->x += (infoPtr->nItemWidth - infoPtr->iconSize.cx) / 2;
7133 lpptPosition->y += ICON_TOP_PADDING;
7134 }
7135 lpptPosition->x += Origin.x;
7136 lpptPosition->y += Origin.y;
7137
7138 TRACE (" lpptPosition=%s\n", wine_dbgstr_point(lpptPosition));
7139 return TRUE;
7140}
7141
7142
7143/***
7144 * DESCRIPTION:
7145 * Retrieves the bounding rectangle for a listview control item.
7146 *
7147 * PARAMETER(S):
7148 * [I] infoPtr : valid pointer to the listview structure
7149 * [I] nItem : item index
7150 * [IO] lprc : bounding rectangle coordinates
7151 * lprc->left specifies the portion of the item for which the bounding
7152 * rectangle will be retrieved.
7153 *
7154 * LVIR_BOUNDS Returns the bounding rectangle of the entire item,
7155 * including the icon and label.
7156 * *
7157 * * For LVS_ICON
7158 * * Experiment shows that native control returns:
7159 * * width = min (48, length of text line)
7160 * * .left = position.x - (width - iconsize.cx)/2
7161 * * .right = .left + width
7162 * * height = #lines of text * ntmHeight + icon height + 8
7163 * * .top = position.y - 2
7164 * * .bottom = .top + height
7165 * * separation between items .y = itemSpacing.cy - height
7166 * * .x = itemSpacing.cx - width
7167 * LVIR_ICON Returns the bounding rectangle of the icon or small icon.
7168 * *
7169 * * For LVS_ICON
7170 * * Experiment shows that native control returns:
7171 * * width = iconSize.cx + 16
7172 * * .left = position.x - (width - iconsize.cx)/2
7173 * * .right = .left + width
7174 * * height = iconSize.cy + 4
7175 * * .top = position.y - 2
7176 * * .bottom = .top + height
7177 * * separation between items .y = itemSpacing.cy - height
7178 * * .x = itemSpacing.cx - width
7179 * LVIR_LABEL Returns the bounding rectangle of the item text.
7180 * *
7181 * * For LVS_ICON
7182 * * Experiment shows that native control returns:
7183 * * width = text length
7184 * * .left = position.x - width/2
7185 * * .right = .left + width
7186 * * height = ntmH * linecount + 2
7187 * * .top = position.y + iconSize.cy + 6
7188 * * .bottom = .top + height
7189 * * separation between items .y = itemSpacing.cy - height
7190 * * .x = itemSpacing.cx - width
7191 * LVIR_SELECTBOUNDS Returns the union of the LVIR_ICON and LVIR_LABEL
7192 * rectangles, but excludes columns in report view.
7193 *
7194 * RETURN:
7195 * SUCCESS : TRUE
7196 * FAILURE : FALSE
7197 *
7198 * NOTES
7199 * Note that the bounding rectangle of the label in the LVS_ICON view depends
7200 * upon whether the window has the focus currently and on whether the item
7201 * is the one with the focus. Ensure that the control's record of which
7202 * item has the focus agrees with the items' records.
7203 */
7205{
7206 WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
7207 BOOL doLabel = TRUE, oversizedBox = FALSE;
7208 POINT Position, Origin;
7209 LVITEMW lvItem;
7210 LONG mode;
7211
7212 TRACE("(hwnd=%p, nItem=%d, lprc=%p)\n", infoPtr->hwndSelf, nItem, lprc);
7213
7214 if (!lprc || nItem < 0 || nItem >= infoPtr->nItemCount) return FALSE;
7215
7216 LISTVIEW_GetOrigin(infoPtr, &Origin);
7217 LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position);
7218
7219 /* Be smart and try to figure out the minimum we have to do */
7220 if (lprc->left == LVIR_ICON) doLabel = FALSE;
7221 if (infoPtr->uView == LV_VIEW_DETAILS && lprc->left == LVIR_BOUNDS) doLabel = FALSE;
7222 if (infoPtr->uView == LV_VIEW_ICON && lprc->left != LVIR_ICON &&
7223 infoPtr->bFocus && LISTVIEW_GetItemState(infoPtr, nItem, LVIS_FOCUSED))
7224 oversizedBox = TRUE;
7225
7226 /* get what we need from the item before hand, so we make
7227 * only one request. This can speed up things, if data
7228 * is stored on the app side */
7229 lvItem.mask = 0;
7230 if (infoPtr->uView == LV_VIEW_DETAILS) lvItem.mask |= LVIF_INDENT;
7231 if (doLabel) lvItem.mask |= LVIF_TEXT;
7232 lvItem.iItem = nItem;
7233 lvItem.iSubItem = 0;
7234 lvItem.pszText = szDispText;
7235 lvItem.cchTextMax = DISP_TEXT_SIZE;
7236 if (lvItem.mask && !LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE;
7237 /* we got the state already up, simulate it here, to avoid a reget */
7238 if (infoPtr->uView == LV_VIEW_ICON && (lprc->left != LVIR_ICON))
7239 {
7240 lvItem.mask |= LVIF_STATE;
7241 lvItem.stateMask = LVIS_FOCUSED;
7242 lvItem.state = (oversizedBox ? LVIS_FOCUSED : 0);
7243 }
7244
7245 if (infoPtr->uView == LV_VIEW_DETAILS && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) && lprc->left == LVIR_SELECTBOUNDS)
7247
7248 mode = lprc->left;
7249 switch(lprc->left)
7250 {
7251 case LVIR_ICON:
7252 LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, NULL, lprc, NULL, NULL);
7253 break;
7254
7255 case LVIR_LABEL:
7256 LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, NULL, NULL, NULL, lprc);
7257 break;
7258
7259 case LVIR_BOUNDS:
7260 LISTVIEW_GetItemMetrics(infoPtr, &lvItem, lprc, NULL, NULL, NULL, NULL);
7261 break;
7262
7263 case LVIR_SELECTBOUNDS:
7264 LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, lprc, NULL, NULL, NULL);
7265 break;
7266
7267 default:
7268 WARN("Unknown value: %d\n", lprc->left);
7269 return FALSE;
7270 }
7271
7272 if (infoPtr->uView == LV_VIEW_DETAILS)
7273 {
7274 if (mode != LVIR_BOUNDS)
7275 OffsetRect(lprc, Origin.x + LISTVIEW_GetColumnInfo(infoPtr, 0)->rcHeader.left,
7276 Position.y + Origin.y);
7277 else
7278 OffsetRect(lprc, Origin.x, Position.y + Origin.y);
7279 }
7280 else
7281 OffsetRect(lprc, Position.x + Origin.x, Position.y + Origin.y);
7282
7283 TRACE(" rect=%s\n", wine_dbgstr_rect(lprc));
7284
7285 return TRUE;
7286}
7287
7288/***
7289 * DESCRIPTION:
7290 * Retrieves the spacing between listview control items.
7291 *
7292 * PARAMETER(S):
7293 * [I] infoPtr : valid pointer to the listview structure
7294 * [IO] lprc : rectangle to receive the output
7295 * on input, lprc->top = nSubItem
7296 * lprc->left = LVIR_ICON | LVIR_BOUNDS | LVIR_LABEL
7297 *
7298 * NOTE: for subItem = 0, we should return the bounds of the _entire_ item,
7299 * not only those of the first column.
7300 *
7301 * RETURN:
7302 * TRUE: success
7303 * FALSE: failure
7304 */
7306{
7307 RECT rect = { 0, 0, 0, 0 };
7308 POINT origin;
7309 INT y;
7310
7311 if (!lprc) return FALSE;
7312
7313 TRACE("(item=%d, subitem=%d, type=%d)\n", item, lprc->top, lprc->left);
7314 /* Subitem of '0' means item itself, and this works for all control view modes */
7315 if (lprc->top == 0)
7316 return LISTVIEW_GetItemRect(infoPtr, item, lprc);
7317
7318 if (infoPtr->uView != LV_VIEW_DETAILS) return FALSE;
7319
7320 LISTVIEW_GetOrigin(infoPtr, &origin);
7321 /* this works for any item index, no matter if it exists or not */
7322 y = item * infoPtr->nItemHeight + origin.y;
7323
7324 if (infoPtr->hwndHeader && SendMessageW(infoPtr->hwndHeader, HDM_GETITEMRECT, lprc->top, (LPARAM)&rect))
7325 {
7326 rect.top = 0;
7327 rect.bottom = infoPtr->nItemHeight;
7328 }
7329 else
7330 {
7331 /* Native implementation is broken for this case and garbage is left for left and right fields,
7332 we zero them to get predictable output */
7333 lprc->left = lprc->right = lprc->top = 0;
7334 lprc->bottom = infoPtr->nItemHeight;
7335 OffsetRect(lprc, origin.x, y);
7336 TRACE("return rect %s\n", wine_dbgstr_rect(lprc));
7337 return TRUE;
7338 }
7339
7340 switch (lprc->left)
7341 {
7342 case LVIR_ICON:
7343 {
7344 /* it doesn't matter if main item actually has an icon, if imagelist is set icon width is returned */
7345 if (infoPtr->himlSmall)
7346 rect.right = rect.left + infoPtr->iconSize.cx;
7347 else
7348 rect.right = rect.left;
7349
7350 rect.bottom = rect.top + infoPtr->iconSize.cy;
7351 break;
7352 }
7353 case LVIR_LABEL:
7354 case LVIR_BOUNDS:
7355 break;
7356
7357 default:
7358 ERR("Unknown bounds=%d\n", lprc->left);
7359 return FALSE;
7360 }
7361
7362 OffsetRect(&rect, origin.x, y);
7363 *lprc = rect;
7364 TRACE("return rect %s\n", wine_dbgstr_rect(lprc));
7365
7366 return TRUE;
7367}
7368
7369/***
7370 * DESCRIPTION:
7371 * Retrieves the spacing between listview control items.
7372 *
7373 * PARAMETER(S):
7374 * [I] infoPtr : valid pointer to the listview structure
7375 * [I] bSmall : flag for small or large icon
7376 *
7377 * RETURN:
7378 * Horizontal + vertical spacing
7379 */
7380static LONG LISTVIEW_GetItemSpacing(const LISTVIEW_INFO *infoPtr, BOOL bSmall)
7381{
7382 LONG lResult;
7383
7384 if (!bSmall)
7385 {
7386 lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
7387 }
7388 else
7389 {
7390 if (infoPtr->uView == LV_VIEW_ICON)
7392 else
7393 lResult = MAKELONG(infoPtr->nItemWidth, infoPtr->nItemHeight);
7394 }
7395 return lResult;
7396}
7397
7398/***
7399 * DESCRIPTION:
7400 * Retrieves the state of a listview control item.
7401 *
7402 * PARAMETER(S):
7403 * [I] infoPtr : valid pointer to the listview structure
7404 * [I] nItem : item index
7405 * [I] uMask : state mask
7406 *
7407 * RETURN:
7408 * State specified by the mask.
7409 */
7410static UINT LISTVIEW_GetItemState(const LISTVIEW_INFO *infoPtr, INT nItem, UINT uMask)
7411{
7412 LVITEMW lvItem;
7413
7414 if (nItem < 0 || nItem >= infoPtr->nItemCount) return 0;
7415
7416 lvItem.iItem = nItem;
7417 lvItem.iSubItem = 0;
7418 lvItem.mask = LVIF_STATE;
7419 lvItem.stateMask = uMask;
7420 if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return 0;
7421
7422 return lvItem.state & uMask;
7423}
7424
7425/***
7426 * DESCRIPTION:
7427 * Retrieves the text of a listview control item or subitem.
7428 *
7429 * PARAMETER(S):
7430 * [I] hwnd : window handle
7431 * [I] nItem : item index
7432 * [IO] lpLVItem : item information
7433 * [I] isW : TRUE if lpLVItem is Unicode
7434 *
7435 * RETURN:
7436 * SUCCESS : string length
7437 * FAILURE : 0
7438 */
7439static INT LISTVIEW_GetItemTextT(const LISTVIEW_INFO *infoPtr, INT nItem, LPLVITEMW lpLVItem, BOOL isW)
7440{
7441 if (!lpLVItem || nItem < 0 || nItem >= infoPtr->nItemCount) return 0;
7442
7443 lpLVItem->mask = LVIF_TEXT;
7444 lpLVItem->iItem = nItem;
7445 if (!LISTVIEW_GetItemExtT(infoPtr, lpLVItem, isW)) return 0;
7446
7447 return textlenT(lpLVItem->pszText, isW);
7448}
7449
7450/***
7451 * DESCRIPTION:
7452 * Searches for an item based on properties + relationships.
7453 *
7454 * PARAMETER(S):
7455 * [I] infoPtr : valid pointer to the listview structure
7456 * [I] nItem : item index
7457 * [I] uFlags : relationship flag
7458 *
7459 * RETURN:
7460 * SUCCESS : item index
7461 * FAILURE : -1
7462 */
7463static INT LISTVIEW_GetNextItem(const LISTVIEW_INFO *infoPtr, INT nItem, UINT uFlags)
7464{
7465 UINT uMask = 0;
7466 LVFINDINFOW lvFindInfo;
7467 INT nCountPerColumn;
7468#ifndef __REACTOS__
7469 INT nCountPerRow;
7470#endif
7471 INT i;
7472
7473 TRACE("nItem=%d, uFlags=%x, nItemCount=%d\n", nItem, uFlags, infoPtr->nItemCount);
7474 if (nItem < -1 || nItem >= infoPtr->nItemCount) return -1;
7475
7476 ZeroMemory(&lvFindInfo, sizeof(lvFindInfo));
7477
7478 if (uFlags & LVNI_CUT)
7479 uMask |= LVIS_CUT;
7480
7482 uMask |= LVIS_DROPHILITED;
7483
7484 if (uFlags & LVNI_FOCUSED)
7485 uMask |= LVIS_FOCUSED;
7486
7487 if (uFlags & LVNI_SELECTED)
7488 uMask |= LVIS_SELECTED;
7489
7490 /* if we're asked for the focused item, that's only one,
7491 * so it's worth optimizing */
7492 if (uFlags & LVNI_FOCUSED)
7493 {
7494 if ((LISTVIEW_GetItemState(infoPtr, infoPtr->nFocusedItem, uMask) & uMask) != uMask) return -1;
7495 return (infoPtr->nFocusedItem == nItem) ? -1 : infoPtr->nFocusedItem;
7496 }
7497
7498 if (uFlags & LVNI_ABOVE)
7499 {
7500 if ((infoPtr->uView == LV_VIEW_LIST) || (infoPtr->uView == LV_VIEW_DETAILS))
7501 {
7502 while (nItem >= 0)
7503 {
7504 nItem--;
7505 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
7506 return nItem;
7507 }
7508 }
7509 else
7510 {
7511#ifndef __REACTOS__
7512 /* Special case for autoarrange - move 'til the top of a list */
7513 if (is_autoarrange(infoPtr))
7514 {
7515 nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr);
7516 while (nItem - nCountPerRow >= 0)
7517 {
7518 nItem -= nCountPerRow;
7519 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
7520 return nItem;
7521 }
7522 return -1;
7523 }
7524#endif
7525 lvFindInfo.flags = LVFI_NEARESTXY;
7526 lvFindInfo.vkDirection = VK_UP;
7527 LISTVIEW_GetItemPosition(infoPtr, nItem, &lvFindInfo.pt);
7528 while ((nItem = LISTVIEW_FindItemW(infoPtr, nItem, &lvFindInfo)) != -1)
7529 {
7530 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
7531 return nItem;
7532 }
7533 }
7534 }
7535 else if (uFlags & LVNI_BELOW)
7536 {
7537 if ((infoPtr->uView == LV_VIEW_LIST) || (infoPtr->uView == LV_VIEW_DETAILS))
7538 {
7539 while (nItem < infoPtr->nItemCount)
7540 {
7541 nItem++;
7542 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
7543 return nItem;
7544 }
7545 }
7546 else
7547 {
7548#ifndef __REACTOS__
7549 /* Special case for autoarrange - move 'til the bottom of a list */
7550 if (is_autoarrange(infoPtr))
7551 {
7552 nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr);
7553 while (nItem + nCountPerRow < infoPtr->nItemCount )
7554 {
7555 nItem += nCountPerRow;
7556 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
7557 return nItem;
7558 }
7559 return -1;
7560 }
7561#endif
7562 lvFindInfo.flags = LVFI_NEARESTXY;
7563 lvFindInfo.vkDirection = VK_DOWN;
7564 LISTVIEW_GetItemPosition(infoPtr, nItem, &lvFindInfo.pt);
7565 while ((nItem = LISTVIEW_FindItemW(infoPtr, nItem, &lvFindInfo)) != -1)
7566 {
7567 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
7568 return nItem;
7569 }
7570 }
7571 }
7572 else if (uFlags & LVNI_TOLEFT)
7573 {
7574 if (infoPtr->uView == LV_VIEW_LIST)
7575 {
7576 nCountPerColumn = LISTVIEW_GetCountPerColumn(infoPtr);
7577 while (nItem - nCountPerColumn >= 0)
7578 {
7579 nItem -= nCountPerColumn;
7580 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
7581 return nItem;
7582 }
7583 }
7584 else if ((infoPtr->uView == LV_VIEW_SMALLICON) || (infoPtr->uView == LV_VIEW_ICON))
7585 {
7586#ifndef __REACTOS__
7587 /* Special case for autoarrange - move 'til the beginning of a row */
7588 if (is_autoarrange(infoPtr))
7589 {
7590 nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr);
7591 while (nItem % nCountPerRow > 0)
7592 {
7593 nItem --;
7594 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
7595 return nItem;
7596 }
7597 return -1;
7598 }
7599#endif
7600 lvFindInfo.flags = LVFI_NEARESTXY;
7601 lvFindInfo.vkDirection = VK_LEFT;
7602 LISTVIEW_GetItemPosition(infoPtr, nItem, &lvFindInfo.pt);
7603 while ((nItem = LISTVIEW_FindItemW(infoPtr, nItem, &lvFindInfo)) != -1)
7604 {
7605 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
7606 return nItem;
7607 }
7608 }
7609 }
7610 else if (uFlags & LVNI_TORIGHT)
7611 {
7612 if (infoPtr->uView == LV_VIEW_LIST)
7613 {
7614 nCountPerColumn = LISTVIEW_GetCountPerColumn(infoPtr);
7615 while (nItem + nCountPerColumn < infoPtr->nItemCount)
7616 {
7617 nItem += nCountPerColumn;
7618 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
7619 return nItem;
7620 }
7621 }
7622 else if ((infoPtr->uView == LV_VIEW_SMALLICON) || (infoPtr->uView == LV_VIEW_ICON))
7623 {
7624#ifndef __REACTOS__
7625 /* Special case for autoarrange - move 'til the end of a row */
7626 if (is_autoarrange(infoPtr))
7627 {
7628 nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr);
7629 while (nItem % nCountPerRow < nCountPerRow - 1 )
7630 {
7631 nItem ++;
7632 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
7633 return nItem;
7634 }
7635 return -1;
7636 }
7637#endif
7638 lvFindInfo.flags = LVFI_NEARESTXY;
7639 lvFindInfo.vkDirection = VK_RIGHT;
7640 LISTVIEW_GetItemPosition(infoPtr, nItem, &lvFindInfo.pt);
7641 while ((nItem = LISTVIEW_FindItemW(infoPtr, nItem, &lvFindInfo)) != -1)
7642 {
7643 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
7644 return nItem;
7645 }
7646 }
7647 }
7648 else
7649 {
7650 nItem++;
7651
7652 /* search by index */
7653 for (i = nItem; i < infoPtr->nItemCount; i++)
7654 {
7655 if ((LISTVIEW_GetItemState(infoPtr, i, uMask) & uMask) == uMask)
7656 return i;
7657 }
7658 }
7659
7660 return -1;
7661}
7662
7663/* LISTVIEW_GetNumberOfWorkAreas */
7664
7665/***
7666 * DESCRIPTION:
7667 * Retrieves the origin coordinates when in icon or small icon display mode.
7668 *
7669 * PARAMETER(S):
7670 * [I] infoPtr : valid pointer to the listview structure
7671 * [O] lpptOrigin : coordinate information
7672 *
7673 * RETURN:
7674 * None.
7675 */
7676static void LISTVIEW_GetOrigin(const LISTVIEW_INFO *infoPtr, LPPOINT lpptOrigin)
7677{
7678 INT nHorzPos = 0, nVertPos = 0;
7679 SCROLLINFO scrollInfo;
7680
7681 scrollInfo.cbSize = sizeof(SCROLLINFO);
7682 scrollInfo.fMask = SIF_POS;
7683
7684 if (GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo))
7685 nHorzPos = scrollInfo.nPos;
7686 if (GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo))
7687 nVertPos = scrollInfo.nPos;
7688
7689 TRACE("nHorzPos=%d, nVertPos=%d\n", nHorzPos, nVertPos);
7690
7691 lpptOrigin->x = infoPtr->rcList.left;
7692 lpptOrigin->y = infoPtr->rcList.top;
7693 if (infoPtr->uView == LV_VIEW_LIST)
7694 nHorzPos *= infoPtr->nItemWidth;
7695 else if (infoPtr->uView == LV_VIEW_DETAILS)
7696 nVertPos *= infoPtr->nItemHeight;
7697
7698 lpptOrigin->x -= nHorzPos;
7699 lpptOrigin->y -= nVertPos;
7700
7701 TRACE(" origin=%s\n", wine_dbgstr_point(lpptOrigin));
7702}
7703
7704/***
7705 * DESCRIPTION:
7706 * Retrieves the width of a string.
7707 *
7708 * PARAMETER(S):
7709 * [I] hwnd : window handle
7710 * [I] lpszText : text string to process
7711 * [I] isW : TRUE if lpszText is Unicode, FALSE otherwise
7712 *
7713 * RETURN:
7714 * SUCCESS : string width (in pixels)
7715 * FAILURE : zero
7716 */
7718{
7719 SIZE stringSize;
7720
7721 stringSize.cx = 0;
7722 if (is_text(lpszText))
7723 {
7724 HFONT hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
7725 HDC hdc = GetDC(infoPtr->hwndSelf);
7726 HFONT hOldFont = SelectObject(hdc, hFont);
7727
7728 if (isW)
7729 GetTextExtentPointW(hdc, lpszText, lstrlenW(lpszText), &stringSize);
7730 else
7731 GetTextExtentPointA(hdc, (LPCSTR)lpszText, lstrlenA((LPCSTR)lpszText), &stringSize);
7732 SelectObject(hdc, hOldFont);
7733 ReleaseDC(infoPtr->hwndSelf, hdc);
7734 }
7735 return stringSize.cx;
7736}
7737
7738/***
7739 * DESCRIPTION:
7740 * Determines which listview item is located at the specified position.
7741 *
7742 * PARAMETER(S):
7743 * [I] infoPtr : valid pointer to the listview structure
7744 * [IO] lpht : hit test information
7745 * [I] subitem : fill out iSubItem.
7746 * [I] select : return the index only if the hit selects the item
7747 *
7748 * NOTE:
7749 * (mm 20001022): We must not allow iSubItem to be touched, for
7750 * an app might pass only a structure with space up to iItem!
7751 * (MS Office 97 does that for instance in the file open dialog)
7752 *
7753 * RETURN:
7754 * SUCCESS : item index
7755 * FAILURE : -1
7756 */
7757static INT LISTVIEW_HitTest(const LISTVIEW_INFO *infoPtr, LPLVHITTESTINFO lpht, BOOL subitem, BOOL select)
7758{
7759 WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
7760 RECT rcBox, rcBounds, rcState, rcIcon, rcLabel, rcSearch;
7761 POINT Origin, Position, opt;
7762 BOOL is_fullrow;
7763 LVITEMW lvItem;
7764 ITERATOR i;
7765 INT iItem;
7766
7767 TRACE("(pt=%s, subitem=%d, select=%d)\n", wine_dbgstr_point(&lpht->pt), subitem, select);
7768
7769 lpht->flags = 0;
7770 lpht->iItem = -1;
7771 if (subitem) lpht->iSubItem = 0;
7772
7773 LISTVIEW_GetOrigin(infoPtr, &Origin);
7774
7775 /* set whole list relation flags */
7776 if (subitem && infoPtr->uView == LV_VIEW_DETAILS)
7777 {
7778 /* LVM_SUBITEMHITTEST checks left bound of possible client area */
7779 if (infoPtr->rcList.left > lpht->pt.x && Origin.x < lpht->pt.x)
7780 lpht->flags |= LVHT_TOLEFT;
7781
7782 if (lpht->pt.y < infoPtr->rcList.top && lpht->pt.y >= 0)
7783 opt.y = lpht->pt.y + infoPtr->rcList.top;
7784 else
7785 opt.y = lpht->pt.y;
7786
7787 if (infoPtr->rcList.bottom < opt.y)
7788 lpht->flags |= LVHT_BELOW;
7789 }
7790 else
7791 {
7792 if (infoPtr->rcList.left > lpht->pt.x)
7793 lpht->flags |= LVHT_TOLEFT;
7794 else if (infoPtr->rcList.right < lpht->pt.x)
7795 lpht->flags |= LVHT_TORIGHT;
7796
7797 if (infoPtr->rcList.top > lpht->pt.y)
7798 lpht->flags |= LVHT_ABOVE;
7799 else if (infoPtr->rcList.bottom < lpht->pt.y)
7800 lpht->flags |= LVHT_BELOW;
7801 }
7802
7803 /* even if item is invalid try to find subitem */
7804 if (infoPtr->uView == LV_VIEW_DETAILS && subitem)
7805 {
7806 RECT *pRect;
7807 INT j;
7808
7809 opt.x = lpht->pt.x - Origin.x;
7810
7811 lpht->iSubItem = -1;
7812 for (j = 0; j < DPA_GetPtrCount(infoPtr->hdpaColumns); j++)
7813 {
7814 pRect = &LISTVIEW_GetColumnInfo(infoPtr, j)->rcHeader;
7815
7816 if ((opt.x >= pRect->left) && (opt.x < pRect->right))
7817 {
7818 lpht->iSubItem = j;
7819 break;
7820 }
7821 }
7822 TRACE("lpht->iSubItem=%d\n", lpht->iSubItem);
7823
7824 /* if we're outside horizontal columns bounds there's nothing to test further */
7825 if (lpht->iSubItem == -1)
7826 {
7827 lpht->iItem = -1;
7828 lpht->flags = LVHT_NOWHERE;
7829 return -1;
7830 }
7831 }
7832
7833 TRACE("lpht->flags=0x%x\n", lpht->flags);
7834 if (lpht->flags) return -1;
7835
7836 lpht->flags |= LVHT_NOWHERE;
7837
7838 /* first deal with the large items */
7839 rcSearch.left = lpht->pt.x;
7840 rcSearch.top = lpht->pt.y;
7841 rcSearch.right = rcSearch.left + 1;
7842 rcSearch.bottom = rcSearch.top + 1;
7843
7844 iterator_frameditems(&i, infoPtr, &rcSearch);
7845 iterator_next(&i); /* go to first item in the sequence */
7846 iItem = i.nItem;
7848
7849 TRACE("lpht->iItem=%d\n", iItem);
7850 if (iItem == -1) return -1;
7851
7852 lvItem.mask = LVIF_STATE | LVIF_TEXT;
7853 if (infoPtr->uView == LV_VIEW_DETAILS) lvItem.mask |= LVIF_INDENT;
7855 if (infoPtr->uView == LV_VIEW_ICON) lvItem.stateMask |= LVIS_FOCUSED;
7856 lvItem.iItem = iItem;
7857 lvItem.iSubItem = subitem ? lpht->iSubItem : 0;
7858 lvItem.pszText = szDispText;
7859 lvItem.cchTextMax = DISP_TEXT_SIZE;
7860 if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return -1;
7861 if (!infoPtr->bFocus) lvItem.state &= ~LVIS_FOCUSED;
7862
7863 LISTVIEW_GetItemMetrics(infoPtr, &lvItem, &rcBox, NULL, &rcIcon, &rcState, &rcLabel);
7864 LISTVIEW_GetItemOrigin(infoPtr, iItem, &Position);
7865 opt.x = lpht->pt.x - Position.x - Origin.x;
7866
7867 if (lpht->pt.y < infoPtr->rcList.top && lpht->pt.y >= 0)
7868 opt.y = lpht->pt.y - Position.y - Origin.y + infoPtr->rcList.top;
7869 else
7870 opt.y = lpht->pt.y - Position.y - Origin.y;
7871
7872 if (infoPtr->uView == LV_VIEW_DETAILS)
7873 {
7874 rcBounds = rcBox;
7875 if (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT)
7876 opt.x = lpht->pt.x - Origin.x;
7877 }
7878 else
7879 {
7880 UnionRect(&rcBounds, &rcIcon, &rcLabel);
7881 UnionRect(&rcBounds, &rcBounds, &rcState);
7882 }
7883 TRACE("rcBounds=%s\n", wine_dbgstr_rect(&rcBounds));
7884 if (!PtInRect(&rcBounds, opt)) return -1;
7885
7886 /* That's a special case - row rectangle is used as item rectangle and
7887 returned flags contain all item parts. */
7888 is_fullrow = (infoPtr->uView == LV_VIEW_DETAILS) && ((infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) || (infoPtr->dwStyle & LVS_OWNERDRAWFIXED));
7889
7890 if (PtInRect(&rcIcon, opt))
7891 lpht->flags |= LVHT_ONITEMICON;
7892 else if (PtInRect(&rcLabel, opt))
7893 lpht->flags |= LVHT_ONITEMLABEL;
7894 else if (infoPtr->himlState && PtInRect(&rcState, opt))
7895 lpht->flags |= LVHT_ONITEMSTATEICON;
7896 if (is_fullrow && !(lpht->flags & LVHT_ONITEM))
7897 {
7898 lpht->flags = LVHT_ONITEM | LVHT_ABOVE;
7899 }
7900 if (lpht->flags & LVHT_ONITEM)
7901 lpht->flags &= ~LVHT_NOWHERE;
7902 TRACE("lpht->flags=0x%x\n", lpht->flags);
7903
7904 if (select && !is_fullrow)
7905 {
7906 if (infoPtr->uView == LV_VIEW_DETAILS)
7907 {
7908 /* get main item bounds */
7909 lvItem.iSubItem = 0;
7910 LISTVIEW_GetItemMetrics(infoPtr, &lvItem, &rcBox, NULL, &rcIcon, &rcState, &rcLabel);
7911 UnionRect(&rcBounds, &rcIcon, &rcLabel);
7912 UnionRect(&rcBounds, &rcBounds, &rcState);
7913 }
7914 if (!PtInRect(&rcBounds, opt)) iItem = -1;
7915 }
7916 return lpht->iItem = iItem;
7917}
7918
7919/***
7920 * DESCRIPTION:
7921 * Inserts a new item in the listview control.
7922 *
7923 * PARAMETER(S):
7924 * [I] infoPtr : valid pointer to the listview structure
7925 * [I] lpLVItem : item information
7926 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
7927 *
7928 * RETURN:
7929 * SUCCESS : new item index
7930 * FAILURE : -1
7931 */
7932static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL isW)
7933{
7934 INT nItem;
7935 HDPA hdpaSubItems;
7936 NMLISTVIEW nmlv;
7937 ITEM_INFO *lpItem;
7938 ITEM_ID *lpID;
7939 BOOL is_sorted, has_changed;
7940 LVITEMW item;
7941 HWND hwndSelf = infoPtr->hwndSelf;
7942
7943 TRACE("(item=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW);
7944
7945 if (infoPtr->dwStyle & LVS_OWNERDATA) return infoPtr->nItemCount++;
7946
7947 /* make sure it's an item, and not a subitem; cannot insert a subitem */
7948 if (!lpLVItem || lpLVItem->iSubItem) return -1;
7949
7950 if (!is_assignable_item(lpLVItem, infoPtr->dwStyle)) return -1;
7951
7952 if (!(lpItem = Alloc(sizeof(ITEM_INFO)))) return -1;
7953
7954 /* insert item in listview control data structure */
7955 if ( !(hdpaSubItems = DPA_Create(8)) ) goto fail;
7956 if ( !DPA_SetPtr(hdpaSubItems, 0, lpItem) ) assert (FALSE);
7957
7958 /* link with id struct */
7959 if (!(lpID = Alloc(sizeof(ITEM_ID)))) goto fail;
7960 lpItem->id = lpID;
7961 lpID->item = hdpaSubItems;
7962 lpID->id = get_next_itemid(infoPtr);
7963 if ( DPA_InsertPtr(infoPtr->hdpaItemIds, infoPtr->nItemCount, lpID) == -1) goto fail;
7964
7966 !(infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && (LPSTR_TEXTCALLBACKW != lpLVItem->pszText);
7967
7968 if (lpLVItem->iItem < 0 && !is_sorted) return -1;
7969
7970 /* calculate new item index */
7971 if (is_sorted)
7972 {
7973 HDPA hItem;
7974 ITEM_INFO *item_s;
7975 INT i = 0, cmpv;
7976 WCHAR *textW;
7977
7978 textW = textdupTtoW(lpLVItem->pszText, isW);
7979
7980 while (i < infoPtr->nItemCount)
7981 {
7982 hItem = DPA_GetPtr( infoPtr->hdpaItems, i);
7983 item_s = DPA_GetPtr(hItem, 0);
7984
7985 cmpv = textcmpWT(item_s->hdr.pszText, textW, TRUE);
7986 if (infoPtr->dwStyle & LVS_SORTDESCENDING) cmpv *= -1;
7987
7988 if (cmpv >= 0) break;
7989 i++;
7990 }
7991
7993
7994 nItem = i;
7995 }
7996 else
7997 nItem = min(lpLVItem->iItem, infoPtr->nItemCount);
7998
7999 TRACE("inserting at %d, sorted=%d, count=%d, iItem=%d\n", nItem, is_sorted, infoPtr->nItemCount, lpLVItem->iItem);
8000 nItem = DPA_InsertPtr( infoPtr->hdpaItems, nItem, hdpaSubItems );
8001 if (nItem == -1) goto fail;
8002 infoPtr->nItemCount++;
8003
8004 /* shift indices first so they don't get tangled */
8005 LISTVIEW_ShiftIndices(infoPtr, nItem, 1);
8006
8007 /* set the item attributes */
8008 if (lpLVItem->mask & (LVIF_GROUPID|LVIF_COLUMNS))
8009 {
8010 /* full size structure expected - _WIN32IE >= 0x560 */
8011 item = *lpLVItem;
8012 }
8013 else if (lpLVItem->mask & LVIF_INDENT)
8014 {
8015 /* indent member expected - _WIN32IE >= 0x300 */
8016 memcpy(&item, lpLVItem, offsetof( LVITEMW, iGroupId ));
8017 }
8018 else
8019 {
8020 /* minimal structure expected */
8021 memcpy(&item, lpLVItem, offsetof( LVITEMW, iIndent ));
8022 }
8023 item.iItem = nItem;
8024 if (infoPtr->dwLvExStyle & LVS_EX_CHECKBOXES)
8025 {
8026 if (item.mask & LVIF_STATE)
8027 {
8028 item.stateMask |= LVIS_STATEIMAGEMASK;
8029 item.state &= ~LVIS_STATEIMAGEMASK;
8030 item.state |= INDEXTOSTATEIMAGEMASK(1);
8031 }
8032 else
8033 {
8034 item.mask |= LVIF_STATE;
8035 item.stateMask = LVIS_STATEIMAGEMASK;
8036 item.state = INDEXTOSTATEIMAGEMASK(1);
8037 }
8038 }
8039
8040 if (!set_main_item(infoPtr, &item, TRUE, isW, &has_changed)) goto undo;
8041
8042 /* make room for the position, if we are in the right mode */
8043 if ((infoPtr->uView == LV_VIEW_SMALLICON) || (infoPtr->uView == LV_VIEW_ICON))
8044 {
8045 if (DPA_InsertPtr(infoPtr->hdpaPosX, nItem, 0) == -1)
8046 goto undo;
8047 if (DPA_InsertPtr(infoPtr->hdpaPosY, nItem, 0) == -1)
8048 {
8049 DPA_DeletePtr(infoPtr->hdpaPosX, nItem);
8050 goto undo;
8051 }
8052 }
8053
8054 /* send LVN_INSERTITEM notification */
8055 memset(&nmlv, 0, sizeof(NMLISTVIEW));
8056 nmlv.iItem = nItem;
8057 nmlv.lParam = lpItem->lParam;
8058 notify_listview(infoPtr, LVN_INSERTITEM, &nmlv);
8059 if (!IsWindow(hwndSelf))
8060 return -1;
8061
8062 /* align items (set position of each item) */
8063 if (infoPtr->uView == LV_VIEW_SMALLICON || infoPtr->uView == LV_VIEW_ICON)
8064 {
8065 POINT pt;
8066
8067#ifdef __REACTOS__
8068 if (infoPtr->dwStyle & LVS_ALIGNLEFT)
8069 LISTVIEW_NextIconPosLeft(infoPtr, &pt, nItem);
8070 else
8071 LISTVIEW_NextIconPosTop(infoPtr, &pt, nItem);
8072#else
8073 if (infoPtr->dwStyle & LVS_ALIGNLEFT)
8074 LISTVIEW_NextIconPosLeft(infoPtr, &pt);
8075 else
8076 LISTVIEW_NextIconPosTop(infoPtr, &pt);
8077#endif
8078
8079 LISTVIEW_MoveIconTo(infoPtr, nItem, &pt, TRUE);
8080 }
8081
8082 /* now is the invalidation fun */
8083 LISTVIEW_ScrollOnInsert(infoPtr, nItem, 1);
8084 return nItem;
8085
8086undo:
8087 LISTVIEW_ShiftIndices(infoPtr, nItem, -1);
8088 LISTVIEW_ShiftFocus(infoPtr, infoPtr->nFocusedItem, nItem, -1);
8089 DPA_DeletePtr(infoPtr->hdpaItems, nItem);
8090 infoPtr->nItemCount--;
8091fail:
8092 DPA_DeletePtr(hdpaSubItems, 0);
8093 DPA_Destroy (hdpaSubItems);
8094 Free (lpItem);
8095 return -1;
8096}
8097
8098/***
8099 * DESCRIPTION:
8100 * Checks item visibility.
8101 *
8102 * PARAMETER(S):
8103 * [I] infoPtr : valid pointer to the listview structure
8104 * [I] nFirst : item index to check for
8105 *
8106 * RETURN:
8107 * Item visible : TRUE
8108 * Item invisible or failure : FALSE
8109 */
8110static BOOL LISTVIEW_IsItemVisible(const LISTVIEW_INFO *infoPtr, INT nItem)
8111{
8112 POINT Origin, Position;
8113 RECT rcItem;
8114 HDC hdc;
8115 BOOL ret;
8116
8117 TRACE("nItem=%d\n", nItem);
8118
8119 if (nItem < 0 || nItem >= DPA_GetPtrCount(infoPtr->hdpaItems)) return FALSE;
8120
8121 LISTVIEW_GetOrigin(infoPtr, &Origin);
8122 LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position);
8123 rcItem.left = Position.x + Origin.x;
8124 rcItem.top = Position.y + Origin.y;
8125 rcItem.right = rcItem.left + infoPtr->nItemWidth;
8126 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
8127
8128 hdc = GetDC(infoPtr->hwndSelf);
8129 if (!hdc) return FALSE;
8130 ret = RectVisible(hdc, &rcItem);
8131 ReleaseDC(infoPtr->hwndSelf, hdc);
8132
8133 return ret;
8134}
8135
8136/***
8137 * DESCRIPTION:
8138 * Redraws a range of items.
8139 *
8140 * PARAMETER(S):
8141 * [I] infoPtr : valid pointer to the listview structure
8142 * [I] nFirst : first item
8143 * [I] nLast : last item
8144 *
8145 * RETURN:
8146 * SUCCESS : TRUE
8147 * FAILURE : FALSE
8148 */
8149static BOOL LISTVIEW_RedrawItems(const LISTVIEW_INFO *infoPtr, INT nFirst, INT nLast)
8150{
8151 INT i;
8152
8153 for (i = max(nFirst, 0); i <= min(nLast, infoPtr->nItemCount - 1); i++)
8154 LISTVIEW_InvalidateItem(infoPtr, i);
8155
8156 return TRUE;
8157}
8158
8159/***
8160 * DESCRIPTION:
8161 * Scroll the content of a listview.
8162 *
8163 * PARAMETER(S):
8164 * [I] infoPtr : valid pointer to the listview structure
8165 * [I] dx : horizontal scroll amount in pixels
8166 * [I] dy : vertical scroll amount in pixels
8167 *
8168 * RETURN:
8169 * SUCCESS : TRUE
8170 * FAILURE : FALSE
8171 *
8172 * COMMENTS:
8173 * If the control is in report view (LV_VIEW_DETAILS) the control can
8174 * be scrolled only in line increments. "dy" will be rounded to the
8175 * nearest number of pixels that are a whole line. Ex: if line height
8176 * is 16 and an 8 is passed, the list will be scrolled by 16. If a 7
8177 * is passed, then the scroll will be 0. (per MSDN 7/2002)
8178 */
8180{
8181 switch(infoPtr->uView) {
8182 case LV_VIEW_DETAILS:
8183 dy += (dy < 0 ? -1 : 1) * infoPtr->nItemHeight/2;
8184 dy /= infoPtr->nItemHeight;
8185 break;
8186 case LV_VIEW_LIST:
8187 if (dy != 0) return FALSE;
8188 break;
8189 default: /* icon */
8190 break;
8191 }
8192
8193 if (dx != 0) LISTVIEW_HScroll(infoPtr, SB_INTERNAL, dx);
8194 if (dy != 0) LISTVIEW_VScroll(infoPtr, SB_INTERNAL, dy);
8195
8196 return TRUE;
8197}
8198
8199/***
8200 * DESCRIPTION:
8201 * Sets the background color.
8202 *
8203 * PARAMETER(S):
8204 * [I] infoPtr : valid pointer to the listview structure
8205 * [I] color : background color
8206 *
8207 * RETURN:
8208 * SUCCESS : TRUE
8209 * FAILURE : FALSE
8210 */
8212{
8213 TRACE("(color=%x)\n", color);
8214
8215#ifdef __REACTOS__
8216 infoPtr->bDefaultBkColor = FALSE;
8217#endif
8218 if(infoPtr->clrBk != color) {
8219 if (infoPtr->clrBk != CLR_NONE) DeleteObject(infoPtr->hBkBrush);
8220 infoPtr->clrBk = color;
8221 if (color == CLR_NONE)
8222 infoPtr->hBkBrush = (HBRUSH)GetClassLongPtrW(infoPtr->hwndSelf, GCLP_HBRBACKGROUND);
8223 else
8224 {
8225 infoPtr->hBkBrush = CreateSolidBrush(color);
8226 infoPtr->dwLvExStyle &= ~LVS_EX_TRANSPARENTBKGND;
8227 }
8228 }
8229
8230 return TRUE;
8231}
8232
8233/* LISTVIEW_SetBkImage */
8234
8235/*** Helper for {Insert,Set}ColumnT *only* */
8236static void column_fill_hditem(const LISTVIEW_INFO *infoPtr, HDITEMW *lphdi, INT nColumn,
8237 const LVCOLUMNW *lpColumn, BOOL isW)
8238{
8239 if (lpColumn->mask & LVCF_FMT)
8240 {
8241 /* format member is valid */
8242 lphdi->mask |= HDI_FORMAT;
8243
8244 /* set text alignment (leftmost column must be left-aligned) */
8245 if (nColumn == 0 || (lpColumn->fmt & LVCFMT_JUSTIFYMASK) == LVCFMT_LEFT)
8246 lphdi->fmt |= HDF_LEFT;
8247 else if ((lpColumn->fmt & LVCFMT_JUSTIFYMASK) == LVCFMT_RIGHT)
8248 lphdi->fmt |= HDF_RIGHT;
8249 else if ((lpColumn->fmt & LVCFMT_JUSTIFYMASK) == LVCFMT_CENTER)
8250 lphdi->fmt |= HDF_CENTER;
8251
8252 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
8253 lphdi->fmt |= HDF_BITMAP_ON_RIGHT;
8254
8255 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
8256 {
8257 lphdi->fmt |= HDF_IMAGE;
8258 lphdi->iImage = I_IMAGECALLBACK;
8259 }
8260
8261 if (lpColumn->fmt & LVCFMT_FIXED_WIDTH)
8262 lphdi->fmt |= HDF_FIXEDWIDTH;
8263 }
8264
8265 if (lpColumn->mask & LVCF_WIDTH)
8266 {
8267 lphdi->mask |= HDI_WIDTH;
8268 if(lpColumn->cx == LVSCW_AUTOSIZE_USEHEADER)
8269 {
8270 /* make it fill the remainder of the controls width */
8271 RECT rcHeader;
8272 INT item_index;
8273
8274 for(item_index = 0; item_index < (nColumn - 1); item_index++)
8275 {
8276 LISTVIEW_GetHeaderRect(infoPtr, item_index, &rcHeader);
8277 lphdi->cxy += rcHeader.right - rcHeader.left;
8278 }
8279
8280 /* retrieve the layout of the header */
8281 GetClientRect(infoPtr->hwndSelf, &rcHeader);
8282 TRACE("start cxy=%d rcHeader=%s\n", lphdi->cxy, wine_dbgstr_rect(&rcHeader));
8283
8284 lphdi->cxy = (rcHeader.right - rcHeader.left) - lphdi->cxy;
8285 }
8286 else
8287 lphdi->cxy = lpColumn->cx;
8288 }
8289
8290 if (lpColumn->mask & LVCF_TEXT)
8291 {
8292 lphdi->mask |= HDI_TEXT | HDI_FORMAT;
8293 lphdi->fmt |= HDF_STRING;
8294 lphdi->pszText = lpColumn->pszText;
8295 lphdi->cchTextMax = textlenT(lpColumn->pszText, isW);
8296 }
8297
8298 if (lpColumn->mask & LVCF_IMAGE)
8299 {
8300 lphdi->mask |= HDI_IMAGE;
8301 lphdi->iImage = lpColumn->iImage;
8302 }
8303
8304 if (lpColumn->mask & LVCF_ORDER)
8305 {
8306 lphdi->mask |= HDI_ORDER;
8307 lphdi->iOrder = lpColumn->iOrder;
8308 }
8309}
8310
8311
8312/***
8313 * DESCRIPTION:
8314 * Inserts a new column.
8315 *
8316 * PARAMETER(S):
8317 * [I] infoPtr : valid pointer to the listview structure
8318 * [I] nColumn : column index
8319 * [I] lpColumn : column information
8320 * [I] isW : TRUE if lpColumn is Unicode, FALSE otherwise
8321 *
8322 * RETURN:
8323 * SUCCESS : new column index
8324 * FAILURE : -1
8325 */
8327 const LVCOLUMNW *lpColumn, BOOL isW)
8328{
8329 COLUMN_INFO *lpColumnInfo;
8330 INT nNewColumn;
8331 HDITEMW hdi;
8332
8333 TRACE("(nColumn=%d, lpColumn=%s, isW=%d)\n", nColumn, debuglvcolumn_t(lpColumn, isW), isW);
8334
8335 if (!lpColumn || nColumn < 0) return -1;
8336 nColumn = min(nColumn, DPA_GetPtrCount(infoPtr->hdpaColumns));
8337
8338 ZeroMemory(&hdi, sizeof(HDITEMW));
8339 column_fill_hditem(infoPtr, &hdi, nColumn, lpColumn, isW);
8340
8341 /*
8342 * A mask not including LVCF_WIDTH turns into a mask of width, width 10
8343 * (can be seen in SPY) otherwise column never gets added.
8344 */
8345 if (!(lpColumn->mask & LVCF_WIDTH)) {
8346 hdi.mask |= HDI_WIDTH;
8347 hdi.cxy = 10;
8348 }
8349
8350 /*
8351 * when the iSubItem is available Windows copies it to the header lParam. It seems
8352 * to happen only in LVM_INSERTCOLUMN - not in LVM_SETCOLUMN
8353 */
8354 if (lpColumn->mask & LVCF_SUBITEM)
8355 {
8356 hdi.mask |= HDI_LPARAM;
8357 hdi.lParam = lpColumn->iSubItem;
8358 }
8359
8360 /* create header if not present */
8361 LISTVIEW_CreateHeader(infoPtr);
8362 if (!(LVS_NOCOLUMNHEADER & infoPtr->dwStyle) &&
8363 (infoPtr->uView == LV_VIEW_DETAILS) && (WS_VISIBLE & infoPtr->dwStyle))
8364 {
8366 }
8367
8368 /* insert item in header control */
8369 nNewColumn = SendMessageW(infoPtr->hwndHeader,
8371 nColumn, (LPARAM)&hdi);
8372 if (nNewColumn == -1) return -1;
8373 if (nNewColumn != nColumn) ERR("nColumn=%d, nNewColumn=%d\n", nColumn, nNewColumn);
8374
8375 /* create our own column info */
8376 if (!(lpColumnInfo = Alloc(sizeof(COLUMN_INFO)))) goto fail;
8377 if (DPA_InsertPtr(infoPtr->hdpaColumns, nNewColumn, lpColumnInfo) == -1) goto fail;
8378
8379 if (lpColumn->mask & LVCF_FMT) lpColumnInfo->fmt = lpColumn->fmt;
8380 if (lpColumn->mask & LVCF_MINWIDTH) lpColumnInfo->cxMin = lpColumn->cxMin;
8381 if (!SendMessageW(infoPtr->hwndHeader, HDM_GETITEMRECT, nNewColumn, (LPARAM)&lpColumnInfo->rcHeader))
8382 goto fail;
8383
8384 /* now we have to actually adjust the data */
8385 if (!(infoPtr->dwStyle & LVS_OWNERDATA) && infoPtr->nItemCount > 0)
8386 {
8387 SUBITEM_INFO *lpSubItem;
8388 HDPA hdpaSubItems;
8389 INT nItem, i;
8390 LVITEMW item;
8391 BOOL changed;
8392
8393 item.iSubItem = nNewColumn;
8394 item.mask = LVIF_TEXT | LVIF_IMAGE;
8395 item.iImage = I_IMAGECALLBACK;
8396 item.pszText = LPSTR_TEXTCALLBACKW;
8397
8398 for (nItem = 0; nItem < infoPtr->nItemCount; nItem++)
8399 {
8400 hdpaSubItems = DPA_GetPtr(infoPtr->hdpaItems, nItem);
8401 for (i = 1; i < DPA_GetPtrCount(hdpaSubItems); i++)
8402 {
8403 lpSubItem = DPA_GetPtr(hdpaSubItems, i);
8404 if (lpSubItem->iSubItem >= nNewColumn)
8405 lpSubItem->iSubItem++;
8406 }
8407
8408 /* add new subitem for each item */
8409 item.iItem = nItem;
8410 set_sub_item(infoPtr, &item, isW, &changed);
8411 }
8412 }
8413
8414 /* make space for the new column */
8415 LISTVIEW_ScrollColumns(infoPtr, nNewColumn + 1, lpColumnInfo->rcHeader.right - lpColumnInfo->rcHeader.left);
8416 LISTVIEW_UpdateItemSize(infoPtr);
8417
8418 return nNewColumn;
8419
8420fail:
8421 if (nNewColumn != -1) SendMessageW(infoPtr->hwndHeader, HDM_DELETEITEM, nNewColumn, 0);
8422 if (lpColumnInfo)
8423 {
8424 DPA_DeletePtr(infoPtr->hdpaColumns, nNewColumn);
8425 Free(lpColumnInfo);
8426 }
8427 return -1;
8428}
8429
8430/***
8431 * DESCRIPTION:
8432 * Sets the attributes of a header item.
8433 *
8434 * PARAMETER(S):
8435 * [I] infoPtr : valid pointer to the listview structure
8436 * [I] nColumn : column index
8437 * [I] lpColumn : column attributes
8438 * [I] isW: if TRUE, then lpColumn is a LPLVCOLUMNW, else it is a LPLVCOLUMNA
8439 *
8440 * RETURN:
8441 * SUCCESS : TRUE
8442 * FAILURE : FALSE
8443 */
8444static BOOL LISTVIEW_SetColumnT(const LISTVIEW_INFO *infoPtr, INT nColumn,
8445 const LVCOLUMNW *lpColumn, BOOL isW)
8446{
8447 HDITEMW hdi, hdiget;
8448 BOOL bResult;
8449
8450 TRACE("(nColumn=%d, lpColumn=%s, isW=%d)\n", nColumn, debuglvcolumn_t(lpColumn, isW), isW);
8451
8452 if (!lpColumn || nColumn < 0 || nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return FALSE;
8453
8454 ZeroMemory(&hdi, sizeof(HDITEMW));
8455 if (lpColumn->mask & LVCF_FMT)
8456 {
8457 hdi.mask |= HDI_FORMAT;
8458 hdiget.mask = HDI_FORMAT;
8459 if (SendMessageW(infoPtr->hwndHeader, HDM_GETITEMW, nColumn, (LPARAM)&hdiget))
8460 hdi.fmt = hdiget.fmt & HDF_STRING;
8461 }
8462 column_fill_hditem(infoPtr, &hdi, nColumn, lpColumn, isW);
8463
8464 /* set header item attributes */
8465 bResult = SendMessageW(infoPtr->hwndHeader, isW ? HDM_SETITEMW : HDM_SETITEMA, nColumn, (LPARAM)&hdi);
8466 if (!bResult) return FALSE;
8467
8468 if (lpColumn->mask & LVCF_FMT)
8469 {
8470 COLUMN_INFO *lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, nColumn);
8471 INT oldFmt = lpColumnInfo->fmt;
8472
8473 lpColumnInfo->fmt = lpColumn->fmt;
8474 if ((oldFmt ^ lpColumn->fmt) & (LVCFMT_JUSTIFYMASK | LVCFMT_IMAGE))
8475 {
8476 if (infoPtr->uView == LV_VIEW_DETAILS) LISTVIEW_InvalidateColumn(infoPtr, nColumn);
8477 }
8478 }
8479
8480 if (lpColumn->mask & LVCF_MINWIDTH)
8481 LISTVIEW_GetColumnInfo(infoPtr, nColumn)->cxMin = lpColumn->cxMin;
8482
8483 return TRUE;
8484}
8485
8486/***
8487 * DESCRIPTION:
8488 * Sets the column order array
8489 *
8490 * PARAMETERS:
8491 * [I] infoPtr : valid pointer to the listview structure
8492 * [I] iCount : number of elements in column order array
8493 * [I] lpiArray : pointer to column order array
8494 *
8495 * RETURN:
8496 * SUCCESS : TRUE
8497 * FAILURE : FALSE
8498 */
8499static BOOL LISTVIEW_SetColumnOrderArray(LISTVIEW_INFO *infoPtr, INT iCount, const INT *lpiArray)
8500{
8501 if (!infoPtr->hwndHeader) return FALSE;
8502 infoPtr->colRectsDirty = TRUE;
8503 return SendMessageW(infoPtr->hwndHeader, HDM_SETORDERARRAY, iCount, (LPARAM)lpiArray);
8504}
8505
8506/***
8507 * DESCRIPTION:
8508 * Sets the width of a column
8509 *
8510 * PARAMETERS:
8511 * [I] infoPtr : valid pointer to the listview structure
8512 * [I] nColumn : column index
8513 * [I] cx : column width
8514 *
8515 * RETURN:
8516 * SUCCESS : TRUE
8517 * FAILURE : FALSE
8518 */
8520{
8521 WCHAR szDispText[DISP_TEXT_SIZE] = { 0 };
8522 INT max_cx = 0;
8523 HDITEMW hdi;
8524
8525 TRACE("(nColumn=%d, cx=%d)\n", nColumn, cx);
8526
8527 /* set column width only if in report or list mode */
8528 if (infoPtr->uView != LV_VIEW_DETAILS && infoPtr->uView != LV_VIEW_LIST) return FALSE;
8529
8530 /* take care of invalid cx values - LVSCW_AUTOSIZE_* values are negative,
8531 with _USEHEADER being the lowest */
8533 else if (infoPtr->uView == LV_VIEW_LIST && cx <= 0) return FALSE;
8534
8535 /* resize all columns if in LV_VIEW_LIST mode */
8536 if(infoPtr->uView == LV_VIEW_LIST)
8537 {
8538 infoPtr->nItemWidth = cx;
8539 LISTVIEW_InvalidateList(infoPtr);
8540 return TRUE;
8541 }
8542
8543 if (nColumn < 0 || nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return FALSE;
8544
8545 if (cx == LVSCW_AUTOSIZE || (cx == LVSCW_AUTOSIZE_USEHEADER && nColumn < DPA_GetPtrCount(infoPtr->hdpaColumns) -1))
8546 {
8547 INT nLabelWidth;
8548 LVITEMW lvItem;
8549
8550 lvItem.mask = LVIF_TEXT;
8551 lvItem.iItem = 0;
8552 lvItem.iSubItem = nColumn;
8553 lvItem.cchTextMax = DISP_TEXT_SIZE;
8554 for (; lvItem.iItem < infoPtr->nItemCount; lvItem.iItem++)
8555 {
8556 lvItem.pszText = szDispText;
8557 if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) continue;
8558 nLabelWidth = LISTVIEW_GetStringWidthT(infoPtr, lvItem.pszText, TRUE);
8559 if (max_cx < nLabelWidth) max_cx = nLabelWidth;
8560 }
8561 if (infoPtr->himlSmall && (nColumn == 0 || (LISTVIEW_GetColumnInfo(infoPtr, nColumn)->fmt & LVCFMT_IMAGE)))
8562 max_cx += infoPtr->iconSize.cx;
8563 max_cx += TRAILING_LABEL_PADDING;
8564 if (nColumn == 0 && (infoPtr->dwLvExStyle & LVS_EX_CHECKBOXES))
8565 max_cx += GetSystemMetrics(SM_CXSMICON);
8566 }
8567
8568 /* autosize based on listview items width */
8569 if(cx == LVSCW_AUTOSIZE)
8570 cx = max_cx;
8571 else if(cx == LVSCW_AUTOSIZE_USEHEADER)
8572 {
8573 /* if iCol is the last column make it fill the remainder of the controls width */
8574 if(nColumn == DPA_GetPtrCount(infoPtr->hdpaColumns) - 1)
8575 {
8576 RECT rcHeader;
8577 POINT Origin;
8578
8579 LISTVIEW_GetOrigin(infoPtr, &Origin);
8580 LISTVIEW_GetHeaderRect(infoPtr, nColumn, &rcHeader);
8581
8582 cx = infoPtr->rcList.right - Origin.x - rcHeader.left;
8583 }
8584 else
8585 {
8586 /* Despite what the MS docs say, if this is not the last
8587 column, then MS resizes the column to the width of the
8588 largest text string in the column, including headers
8589 and items. This is different from LVSCW_AUTOSIZE in that
8590 LVSCW_AUTOSIZE ignores the header string length. */
8591 cx = 0;
8592
8593 /* retrieve header text */
8596 hdi.pszText = szDispText;
8597 if (SendMessageW(infoPtr->hwndHeader, HDM_GETITEMW, nColumn, (LPARAM)&hdi))
8598 {
8599 HDC hdc = GetDC(infoPtr->hwndSelf);
8600 HFONT old_font = SelectObject(hdc, (HFONT)SendMessageW(infoPtr->hwndHeader, WM_GETFONT, 0, 0));
8602 INT bitmap_margin = 0;
8603 SIZE size;
8604
8605 if (GetTextExtentPoint32W(hdc, hdi.pszText, lstrlenW(hdi.pszText), &size))
8607
8608 if (hdi.fmt & (HDF_IMAGE|HDF_BITMAP))
8609 bitmap_margin = SendMessageW(infoPtr->hwndHeader, HDM_GETBITMAPMARGIN, 0, 0);
8610
8611 if ((hdi.fmt & HDF_IMAGE) && himl)
8612 {
8613 INT icon_cx, icon_cy;
8614
8615 if (!ImageList_GetIconSize(himl, &icon_cx, &icon_cy))
8616 cx += icon_cx + 2*bitmap_margin;
8617 }
8618 else if (hdi.fmt & HDF_BITMAP)
8619 {
8620 BITMAP bmp;
8621
8622 GetObjectW(hdi.hbm, sizeof(BITMAP), &bmp);
8623 cx += bmp.bmWidth + 2*bitmap_margin;
8624 }
8625
8626 SelectObject(hdc, old_font);
8627 ReleaseDC(infoPtr->hwndSelf, hdc);
8628 }
8629 cx = max (cx, max_cx);
8630 }
8631 }
8632
8633 if (cx < 0) return FALSE;
8634
8635 /* call header to update the column change */
8636 hdi.mask = HDI_WIDTH;
8637 hdi.cxy = max(cx, LISTVIEW_GetColumnInfo(infoPtr, nColumn)->cxMin);
8638 TRACE("hdi.cxy=%d\n", hdi.cxy);
8639 return SendMessageW(infoPtr->hwndHeader, HDM_SETITEMW, nColumn, (LPARAM)&hdi);
8640}
8641
8642/***
8643 * Creates the checkbox imagelist. Helper for LISTVIEW_SetExtendedListViewStyle
8644 *
8645 */
8647{
8648 HDC hdc_wnd, hdc;
8649 HBITMAP hbm_im, hbm_mask, hbm_orig;
8650 RECT rc;
8651 HBRUSH hbr_white = GetStockObject(WHITE_BRUSH);
8652 HBRUSH hbr_black = GetStockObject(BLACK_BRUSH);
8654
8656 ILC_COLOR | ILC_MASK, 2, 2);
8657 hdc_wnd = GetDC(infoPtr->hwndSelf);
8658 hdc = CreateCompatibleDC(hdc_wnd);
8661 ReleaseDC(infoPtr->hwndSelf, hdc_wnd);
8662
8664 hbm_orig = SelectObject(hdc, hbm_mask);
8665 FillRect(hdc, &rc, hbr_white);
8666 InflateRect(&rc, -2, -2);
8667 FillRect(hdc, &rc, hbr_black);
8668
8669 SelectObject(hdc, hbm_im);
8671 SelectObject(hdc, hbm_orig);
8672 ImageList_Add(himl, hbm_im, hbm_mask);
8673
8674 SelectObject(hdc, hbm_im);
8676 SelectObject(hdc, hbm_orig);
8677 ImageList_Add(himl, hbm_im, hbm_mask);
8678
8679 DeleteObject(hbm_mask);
8680 DeleteObject(hbm_im);
8681 DeleteDC(hdc);
8682
8683 return himl;
8684}
8685
8686/***
8687 * DESCRIPTION:
8688 * Sets the extended listview style.
8689 *
8690 * PARAMETERS:
8691 * [I] infoPtr : valid pointer to the listview structure
8692 * [I] dwMask : mask
8693 * [I] dwStyle : style
8694 *
8695 * RETURN:
8696 * SUCCESS : previous style
8697 * FAILURE : 0
8698 */
8700{
8701 DWORD old_ex_style = infoPtr->dwLvExStyle;
8702
8703 TRACE("mask=0x%08x, ex_style=0x%08x\n", mask, ex_style);
8704
8705 /* set new style */
8706 if (mask)
8707 infoPtr->dwLvExStyle = (old_ex_style & ~mask) | (ex_style & mask);
8708 else
8709 infoPtr->dwLvExStyle = ex_style;
8710
8711 if((infoPtr->dwLvExStyle ^ old_ex_style) & LVS_EX_CHECKBOXES)
8712 {
8713 HIMAGELIST himl = 0;
8714 if(infoPtr->dwLvExStyle & LVS_EX_CHECKBOXES)
8715 {
8716 LVITEMW item;
8717 item.mask = LVIF_STATE;
8718 item.stateMask = LVIS_STATEIMAGEMASK;
8719 item.state = INDEXTOSTATEIMAGEMASK(1);
8720 LISTVIEW_SetItemState(infoPtr, -1, &item);
8721
8723 if(!(infoPtr->dwStyle & LVS_SHAREIMAGELISTS))
8724 ImageList_Destroy(infoPtr->himlState);
8725 }
8727 /* checkbox list replaces previous custom list or... */
8728 if(((infoPtr->dwLvExStyle & LVS_EX_CHECKBOXES) &&
8729 !(infoPtr->dwStyle & LVS_SHAREIMAGELISTS)) ||
8730 /* ...previous was checkbox list */
8731 (old_ex_style & LVS_EX_CHECKBOXES))
8733 }
8734
8735 if((infoPtr->dwLvExStyle ^ old_ex_style) & LVS_EX_HEADERDRAGDROP)
8736 {
8737 DWORD style;
8738
8739 /* if not already created */
8740 LISTVIEW_CreateHeader(infoPtr);
8741
8743 if (infoPtr->dwLvExStyle & LVS_EX_HEADERDRAGDROP)
8745 else
8746 style &= ~HDS_DRAGDROP;
8748 }
8749
8750 /* GRIDLINES adds decoration at top so changes sizes */
8751 if((infoPtr->dwLvExStyle ^ old_ex_style) & LVS_EX_GRIDLINES)
8752 {
8753 LISTVIEW_CreateHeader(infoPtr);
8754 LISTVIEW_UpdateSize(infoPtr);
8755 }
8756
8757 if((infoPtr->dwLvExStyle ^ old_ex_style) & LVS_EX_FULLROWSELECT)
8758 {
8759 LISTVIEW_CreateHeader(infoPtr);
8760 }
8761
8762 if((infoPtr->dwLvExStyle ^ old_ex_style) & LVS_EX_TRANSPARENTBKGND)
8763 {
8764 if (infoPtr->dwLvExStyle & LVS_EX_TRANSPARENTBKGND)
8765 LISTVIEW_SetBkColor(infoPtr, CLR_NONE);
8766 }
8767
8768 if((infoPtr->dwLvExStyle ^ old_ex_style) & LVS_EX_HEADERINALLVIEWS)
8769 {
8770 if (infoPtr->dwLvExStyle & LVS_EX_HEADERINALLVIEWS)
8771 LISTVIEW_CreateHeader(infoPtr);
8772 else
8773 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
8774 LISTVIEW_UpdateSize(infoPtr);
8775 LISTVIEW_UpdateScroll(infoPtr);
8776 }
8777
8778#ifdef __REACTOS__
8779 if ((infoPtr->dwLvExStyle & LVS_EX_SNAPTOGRID) > (old_ex_style & LVS_EX_SNAPTOGRID))
8780 {
8782 }
8783#endif
8784
8785 LISTVIEW_InvalidateList(infoPtr);
8786 return old_ex_style;
8787}
8788
8789/***
8790 * DESCRIPTION:
8791 * Sets the new hot cursor used during hot tracking and hover selection.
8792 *
8793 * PARAMETER(S):
8794 * [I] infoPtr : valid pointer to the listview structure
8795 * [I] hCursor : the new hot cursor handle
8796 *
8797 * RETURN:
8798 * Returns the previous hot cursor
8799 */
8801{
8802 HCURSOR oldCursor = infoPtr->hHotCursor;
8803
8804 infoPtr->hHotCursor = hCursor;
8805
8806 return oldCursor;
8807}
8808
8809
8810/***
8811 * DESCRIPTION:
8812 * Sets the hot item index.
8813 *
8814 * PARAMETERS:
8815 * [I] infoPtr : valid pointer to the listview structure
8816 * [I] iIndex : index
8817 *
8818 * RETURN:
8819 * SUCCESS : previous hot item index
8820 * FAILURE : -1 (no hot item)
8821 */
8823{
8824 INT iOldIndex = infoPtr->nHotItem;
8825
8826 infoPtr->nHotItem = iIndex;
8827
8828 return iOldIndex;
8829}
8830
8831
8832/***
8833 * DESCRIPTION:
8834 * Sets the amount of time the cursor must hover over an item before it is selected.
8835 *
8836 * PARAMETER(S):
8837 * [I] infoPtr : valid pointer to the listview structure
8838 * [I] dwHoverTime : hover time, if -1 the hover time is set to the default
8839 *
8840 * RETURN:
8841 * Returns the previous hover time
8842 */
8843static DWORD LISTVIEW_SetHoverTime(LISTVIEW_INFO *infoPtr, DWORD dwHoverTime)
8844{
8845 DWORD oldHoverTime = infoPtr->dwHoverTime;
8846
8847 infoPtr->dwHoverTime = dwHoverTime;
8848
8849 return oldHoverTime;
8850}
8851
8852/***
8853 * DESCRIPTION:
8854 * Sets spacing for icons of LVS_ICON style.
8855 *
8856 * PARAMETER(S):
8857 * [I] infoPtr : valid pointer to the listview structure
8858 * [I] cx : horizontal spacing (-1 = system spacing, 0 = autosize)
8859 * [I] cy : vertical spacing (-1 = system spacing, 0 = autosize)
8860 *
8861 * RETURN:
8862 * MAKELONG(oldcx, oldcy)
8863 */
8865{
8866 INT iconWidth = 0, iconHeight = 0;
8867 DWORD oldspacing = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
8868
8869 TRACE("requested=(%d,%d)\n", cx, cy);
8870
8871 /* set to defaults, if instructed to */
8872 if (cx == -1 && cy == -1)
8873 {
8874 infoPtr->autoSpacing = TRUE;
8875 if (infoPtr->himlNormal)
8876 ImageList_GetIconSize(infoPtr->himlNormal, &iconWidth, &iconHeight);
8879 }
8880 else
8881 infoPtr->autoSpacing = FALSE;
8882
8883 /* if 0 then keep width */
8884 if (cx != 0)
8885 infoPtr->iconSpacing.cx = cx;
8886
8887 /* if 0 then keep height */
8888 if (cy != 0)
8889 infoPtr->iconSpacing.cy = cy;
8890
8891 TRACE("old=(%d,%d), new=(%d,%d), iconSize=(%d,%d), ntmH=%d\n",
8892 LOWORD(oldspacing), HIWORD(oldspacing), infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy,
8893 infoPtr->iconSize.cx, infoPtr->iconSize.cy,
8894 infoPtr->ntmHeight);
8895
8896 /* these depend on the iconSpacing */
8897 LISTVIEW_UpdateItemSize(infoPtr);
8898
8899 return oldspacing;
8900}
8901
8902static inline void set_icon_size(SIZE *size, HIMAGELIST himl, BOOL is_small)
8903{
8904 INT cx, cy;
8905
8906 if (himl && ImageList_GetIconSize(himl, &cx, &cy))
8907 {
8908 size->cx = cx;
8909 size->cy = cy;
8910 }
8911 else
8912 {
8913 size->cx = GetSystemMetrics(is_small ? SM_CXSMICON : SM_CXICON);
8914 size->cy = GetSystemMetrics(is_small ? SM_CYSMICON : SM_CYICON);
8915 }
8916}
8917
8918/***
8919 * DESCRIPTION:
8920 * Sets image lists.
8921 *
8922 * PARAMETER(S):
8923 * [I] infoPtr : valid pointer to the listview structure
8924 * [I] nType : image list type
8925 * [I] himl : image list handle
8926 *
8927 * RETURN:
8928 * SUCCESS : old image list
8929 * FAILURE : NULL
8930 */
8932{
8933 INT oldHeight = infoPtr->nItemHeight;
8934 HIMAGELIST himlOld = 0;
8935
8936 TRACE("(nType=%d, himl=%p)\n", nType, himl);
8937
8938 switch (nType)
8939 {
8940 case LVSIL_NORMAL:
8941 himlOld = infoPtr->himlNormal;
8942 infoPtr->himlNormal = himl;
8943 if (infoPtr->uView == LV_VIEW_ICON) set_icon_size(&infoPtr->iconSize, himl, FALSE);
8944 if (infoPtr->autoSpacing)
8945 LISTVIEW_SetIconSpacing(infoPtr, -1, -1);
8946 break;
8947
8948 case LVSIL_SMALL:
8949 himlOld = infoPtr->himlSmall;
8950 infoPtr->himlSmall = himl;
8951 if (infoPtr->uView != LV_VIEW_ICON) set_icon_size(&infoPtr->iconSize, himl, TRUE);
8952 if (infoPtr->hwndHeader)
8954 break;
8955
8956 case LVSIL_STATE:
8957 himlOld = infoPtr->himlState;
8958 infoPtr->himlState = himl;
8959 set_icon_size(&infoPtr->iconStateSize, himl, TRUE);
8961 break;
8962
8963 default:
8964 ERR("Unknown icon type=%d\n", nType);
8965 return NULL;
8966 }
8967
8968 infoPtr->nItemHeight = LISTVIEW_CalculateItemHeight(infoPtr);
8969 if (infoPtr->nItemHeight != oldHeight)
8970 LISTVIEW_UpdateScroll(infoPtr);
8971
8972 return himlOld;
8973}
8974
8975/***
8976 * DESCRIPTION:
8977 * Preallocates memory (does *not* set the actual count of items !)
8978 *
8979 * PARAMETER(S):
8980 * [I] infoPtr : valid pointer to the listview structure
8981 * [I] nItems : item count (projected number of items to allocate)
8982 * [I] dwFlags : update flags
8983 *
8984 * RETURN:
8985 * SUCCESS : TRUE
8986 * FAILURE : FALSE
8987 */
8989{
8990 TRACE("(nItems=%d, dwFlags=%x)\n", nItems, dwFlags);
8991
8992 if (infoPtr->dwStyle & LVS_OWNERDATA)
8993 {
8994 INT nOldCount = infoPtr->nItemCount;
8995 infoPtr->nItemCount = nItems;
8996
8997 if (nItems < nOldCount)
8998 {
8999 RANGE range = { nItems, nOldCount };
9000 ranges_del(infoPtr->selectionRanges, range);
9001 if (infoPtr->nFocusedItem >= nItems)
9002 {
9003 LISTVIEW_SetItemFocus(infoPtr, -1);
9004 infoPtr->nFocusedItem = -1;
9005 SetRectEmpty(&infoPtr->rcFocus);
9006 }
9007 }
9008
9009 LISTVIEW_UpdateScroll(infoPtr);
9010
9011 /* the flags are valid only in ownerdata report and list modes */
9012 if (infoPtr->uView == LV_VIEW_ICON || infoPtr->uView == LV_VIEW_SMALLICON) dwFlags = 0;
9013
9014 if (!(dwFlags & LVSICF_NOSCROLL) && infoPtr->nFocusedItem != -1)
9015 LISTVIEW_EnsureVisible(infoPtr, infoPtr->nFocusedItem, FALSE);
9016
9018 LISTVIEW_InvalidateList(infoPtr);
9019 else
9020 {
9021 INT nFrom, nTo;
9022 POINT Origin;
9023 RECT rcErase;
9024
9025 LISTVIEW_GetOrigin(infoPtr, &Origin);
9026 nFrom = min(nOldCount, nItems);
9027 nTo = max(nOldCount, nItems);
9028
9029 if (infoPtr->uView == LV_VIEW_DETAILS)
9030 {
9031 SetRect(&rcErase, 0, nFrom * infoPtr->nItemHeight, infoPtr->nItemWidth,
9032 nTo * infoPtr->nItemHeight);
9033 OffsetRect(&rcErase, Origin.x, Origin.y);
9034 if (IntersectRect(&rcErase, &rcErase, &infoPtr->rcList))
9035 LISTVIEW_InvalidateRect(infoPtr, &rcErase);
9036 }
9037 else /* LV_VIEW_LIST */
9038 {
9039 INT nPerCol = LISTVIEW_GetCountPerColumn(infoPtr);
9040
9041 rcErase.left = (nFrom / nPerCol) * infoPtr->nItemWidth;
9042 rcErase.top = (nFrom % nPerCol) * infoPtr->nItemHeight;
9043 rcErase.right = rcErase.left + infoPtr->nItemWidth;
9044 rcErase.bottom = nPerCol * infoPtr->nItemHeight;
9045 OffsetRect(&rcErase, Origin.x, Origin.y);
9046 if (IntersectRect(&rcErase, &rcErase, &infoPtr->rcList))
9047 LISTVIEW_InvalidateRect(infoPtr, &rcErase);
9048
9049 rcErase.left = (nFrom / nPerCol + 1) * infoPtr->nItemWidth;
9050 rcErase.top = 0;
9051 rcErase.right = (nTo / nPerCol + 1) * infoPtr->nItemWidth;
9052 rcErase.bottom = nPerCol * infoPtr->nItemHeight;
9053 OffsetRect(&rcErase, Origin.x, Origin.y);
9054 if (IntersectRect(&rcErase, &rcErase, &infoPtr->rcList))
9055 LISTVIEW_InvalidateRect(infoPtr, &rcErase);
9056 }
9057 }
9058 }
9059 else
9060 {
9061 /* According to MSDN for non-LVS_OWNERDATA this is just
9062 * a performance issue. The control allocates its internal
9063 * data structures for the number of items specified. It
9064 * cuts down on the number of memory allocations. Therefore
9065 * we will just issue a WARN here
9066 */
9067 WARN("for non-ownerdata performance option not implemented.\n");
9068 }
9069
9070 return TRUE;
9071}
9072
9073/***
9074 * DESCRIPTION:
9075 * Sets the position of an item.
9076 *
9077 * PARAMETER(S):
9078 * [I] infoPtr : valid pointer to the listview structure
9079 * [I] nItem : item index
9080 * [I] pt : coordinate
9081 *
9082 * RETURN:
9083 * SUCCESS : TRUE
9084 * FAILURE : FALSE
9085 */
9087{
9088 POINT Origin, Pt;
9089
9090 TRACE("(nItem=%d, pt=%s)\n", nItem, wine_dbgstr_point(pt));
9091
9092 if (!pt || nItem < 0 || nItem >= infoPtr->nItemCount ||
9093 !(infoPtr->uView == LV_VIEW_ICON || infoPtr->uView == LV_VIEW_SMALLICON)) return FALSE;
9094
9095#ifdef __REACTOS__
9096 /* FIXME: This should really call snap to grid if auto-arrange is enabled
9097 and limit the size of the grid to nItemCount elements */
9098 if (is_autoarrange(infoPtr)) return FALSE;
9099#endif
9100
9101 Pt = *pt;
9102 LISTVIEW_GetOrigin(infoPtr, &Origin);
9103
9104 /* This point value seems to be an undocumented feature.
9105 * The best guess is that it means either at the origin,
9106 * or at true beginning of the list. I will assume the origin. */
9107 if ((Pt.x == -1) && (Pt.y == -1))
9108 Pt = Origin;
9109
9110 if (infoPtr->uView == LV_VIEW_ICON)
9111 {
9112 Pt.x -= (infoPtr->nItemWidth - infoPtr->iconSize.cx) / 2;
9113 Pt.y -= ICON_TOP_PADDING;
9114 }
9115 Pt.x -= Origin.x;
9116 Pt.y -= Origin.y;
9117
9118#ifdef __REACTOS__
9119 if (infoPtr->dwLvExStyle & LVS_EX_SNAPTOGRID)
9120 {
9121 Pt.x = max(0, Pt.x + (infoPtr->nItemWidth >> 1) - (Pt.x + (infoPtr->nItemWidth >> 1)) % infoPtr->nItemWidth);
9122 Pt.y = max(0, Pt.y + (infoPtr->nItemHeight >> 1) - (Pt.y + (infoPtr->nItemHeight >> 1)) % infoPtr->nItemHeight);
9123 }
9124#endif
9125
9126 return LISTVIEW_MoveIconTo(infoPtr, nItem, &Pt, FALSE);
9127}
9128
9129/***
9130 * DESCRIPTION:
9131 * Sets the state of one or many items.
9132 *
9133 * PARAMETER(S):
9134 * [I] infoPtr : valid pointer to the listview structure
9135 * [I] nItem : item index
9136 * [I] item : item or subitem info
9137 *
9138 * RETURN:
9139 * SUCCESS : TRUE
9140 * FAILURE : FALSE
9141 */
9143{
9144 BOOL ret = TRUE;
9145 LVITEMW lvItem;
9146
9147 if (!item) return FALSE;
9148
9149 lvItem.iItem = nItem;
9150 lvItem.iSubItem = 0;
9151 lvItem.mask = LVIF_STATE;
9152 lvItem.state = item->state;
9153 lvItem.stateMask = item->stateMask;
9154 TRACE("item=%s\n", debuglvitem_t(&lvItem, TRUE));
9155
9156 if (nItem == -1)
9157 {
9158 UINT oldstate = 0;
9159 DWORD old_mask;
9160
9161 /* special case optimization for recurring attempt to deselect all */
9162 if (lvItem.state == 0 && lvItem.stateMask == LVIS_SELECTED && !LISTVIEW_GetSelectedCount(infoPtr))
9163 return TRUE;
9164
9165 /* select all isn't allowed in LVS_SINGLESEL */
9166 if ((lvItem.state & lvItem.stateMask & LVIS_SELECTED) && (infoPtr->dwStyle & LVS_SINGLESEL))
9167 return FALSE;
9168
9169 /* focus all isn't allowed */
9170 if (lvItem.state & lvItem.stateMask & LVIS_FOCUSED) return FALSE;
9171
9172 old_mask = infoPtr->notify_mask & NOTIFY_MASK_ITEM_CHANGE;
9173 if (infoPtr->dwStyle & LVS_OWNERDATA)
9174 {
9175 infoPtr->notify_mask &= ~NOTIFY_MASK_ITEM_CHANGE;
9176 if (!(lvItem.state & LVIS_SELECTED) && LISTVIEW_GetSelectedCount(infoPtr))
9177 oldstate |= LVIS_SELECTED;
9178 if (infoPtr->nFocusedItem != -1) oldstate |= LVIS_FOCUSED;
9179 }
9180
9181 /* apply to all items */
9182 for (lvItem.iItem = 0; lvItem.iItem < infoPtr->nItemCount; lvItem.iItem++)
9183 if (!LISTVIEW_SetItemT(infoPtr, &lvItem, TRUE)) ret = FALSE;
9184
9185 if (infoPtr->dwStyle & LVS_OWNERDATA)
9186 {
9187 NMLISTVIEW nmlv;
9188
9189 infoPtr->notify_mask |= old_mask;
9190
9191 nmlv.iItem = -1;
9192 nmlv.iSubItem = 0;
9193 nmlv.uNewState = lvItem.state & lvItem.stateMask;
9194 nmlv.uOldState = oldstate & lvItem.stateMask;
9195 nmlv.uChanged = LVIF_STATE;
9196 nmlv.ptAction.x = nmlv.ptAction.y = 0;
9197 nmlv.lParam = 0;
9198
9199 notify_listview(infoPtr, LVN_ITEMCHANGED, &nmlv);
9200 }
9201 }
9202 else
9203 ret = LISTVIEW_SetItemT(infoPtr, &lvItem, TRUE);
9204
9205 return ret;
9206}
9207
9208/***
9209 * DESCRIPTION:
9210 * Sets the text of an item or subitem.
9211 *
9212 * PARAMETER(S):
9213 * [I] hwnd : window handle
9214 * [I] nItem : item index
9215 * [I] lpLVItem : item or subitem info
9216 * [I] isW : TRUE if input is Unicode
9217 *
9218 * RETURN:
9219 * SUCCESS : TRUE
9220 * FAILURE : FALSE
9221 */
9222static BOOL LISTVIEW_SetItemTextT(LISTVIEW_INFO *infoPtr, INT nItem, const LVITEMW *lpLVItem, BOOL isW)
9223{
9224 LVITEMW lvItem;
9225
9226 if (!lpLVItem || nItem < 0 || nItem >= infoPtr->nItemCount) return FALSE;
9227 if (infoPtr->dwStyle & LVS_OWNERDATA) return FALSE;
9228
9229 lvItem.iItem = nItem;
9230 lvItem.iSubItem = lpLVItem->iSubItem;
9231 lvItem.mask = LVIF_TEXT;
9232 lvItem.pszText = lpLVItem->pszText;
9233 lvItem.cchTextMax = lpLVItem->cchTextMax;
9234
9235 TRACE("(nItem=%d, lpLVItem=%s, isW=%d)\n", nItem, debuglvitem_t(&lvItem, isW), isW);
9236
9237 return LISTVIEW_SetItemT(infoPtr, &lvItem, isW);
9238}
9239
9240/***
9241 * DESCRIPTION:
9242 * Set item index that marks the start of a multiple selection.
9243 *
9244 * PARAMETER(S):
9245 * [I] infoPtr : valid pointer to the listview structure
9246 * [I] nIndex : index
9247 *
9248 * RETURN:
9249 * Index number or -1 if there is no selection mark.
9250 */
9252{
9253 INT nOldIndex = infoPtr->nSelectionMark;
9254
9255 TRACE("(nIndex=%d)\n", nIndex);
9256
9257 if (nIndex >= -1 && nIndex < infoPtr->nItemCount)
9258 infoPtr->nSelectionMark = nIndex;
9259
9260 return nOldIndex;
9261}
9262
9263/***
9264 * DESCRIPTION:
9265 * Sets the text background color.
9266 *
9267 * PARAMETER(S):
9268 * [I] infoPtr : valid pointer to the listview structure
9269 * [I] color : text background color
9270 *
9271 * RETURN:
9272 * SUCCESS : TRUE
9273 * FAILURE : FALSE
9274 */
9276{
9277 TRACE("(color=%x)\n", color);
9278
9279 infoPtr->clrTextBk = color;
9280 return TRUE;
9281}
9282
9283/***
9284 * DESCRIPTION:
9285 * Sets the text foreground color.
9286 *
9287 * PARAMETER(S):
9288 * [I] infoPtr : valid pointer to the listview structure
9289 * [I] color : text color
9290 *
9291 * RETURN:
9292 * SUCCESS : TRUE
9293 * FAILURE : FALSE
9294 */
9296{
9297 TRACE("(color=%x)\n", color);
9298
9299 infoPtr->clrText = color;
9300 return TRUE;
9301}
9302
9303/***
9304 * DESCRIPTION:
9305 * Sets new ToolTip window to ListView control.
9306 *
9307 * PARAMETER(S):
9308 * [I] infoPtr : valid pointer to the listview structure
9309 * [I] hwndNewToolTip : handle to new ToolTip
9310 *
9311 * RETURN:
9312 * old tool tip
9313 */
9314static HWND LISTVIEW_SetToolTips( LISTVIEW_INFO *infoPtr, HWND hwndNewToolTip)
9315{
9316 HWND hwndOldToolTip = infoPtr->hwndToolTip;
9317 infoPtr->hwndToolTip = hwndNewToolTip;
9318 return hwndOldToolTip;
9319}
9320
9321/*
9322 * DESCRIPTION:
9323 * sets the Unicode character format flag for the control
9324 * PARAMETER(S):
9325 * [I] infoPtr :valid pointer to the listview structure
9326 * [I] fUnicode :true to switch to UNICODE false to switch to ANSI
9327 *
9328 * RETURN:
9329 * Old Unicode Format
9330 */
9332{
9333 SHORT rc = infoPtr->notifyFormat;
9334 infoPtr->notifyFormat = (unicode) ? NFR_UNICODE : NFR_ANSI;
9335 return rc == NFR_UNICODE;
9336}
9337
9338/*
9339 * DESCRIPTION:
9340 * sets the control view mode
9341 * PARAMETER(S):
9342 * [I] infoPtr :valid pointer to the listview structure
9343 * [I] nView :new view mode value
9344 *
9345 * RETURN:
9346 * SUCCESS: 1
9347 * FAILURE: -1
9348 */
9350{
9352
9353 if (infoPtr->uView == nView) return 1;
9354
9355 if ((INT)nView < 0 || nView > LV_VIEW_MAX) return -1;
9356 if (nView == LV_VIEW_TILE)
9357 {
9358 FIXME("View LV_VIEW_TILE unimplemented\n");
9359 return -1;
9360 }
9361
9362 infoPtr->uView = nView;
9363
9364 SendMessageW(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
9365 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
9366
9367 ShowScrollBar(infoPtr->hwndSelf, SB_BOTH, FALSE);
9368 SetRectEmpty(&infoPtr->rcFocus);
9369
9370 himl = (nView == LV_VIEW_ICON ? infoPtr->himlNormal : infoPtr->himlSmall);
9371 set_icon_size(&infoPtr->iconSize, himl, nView != LV_VIEW_ICON);
9372
9373 switch (nView)
9374 {
9375 case LV_VIEW_ICON:
9376 case LV_VIEW_SMALLICON:
9377 LISTVIEW_Arrange(infoPtr, LVA_DEFAULT);
9378 break;
9379 case LV_VIEW_DETAILS:
9380 {
9381 HDLAYOUT hl;
9382 WINDOWPOS wp;
9383
9384 LISTVIEW_CreateHeader( infoPtr );
9385
9386 hl.prc = &infoPtr->rcList;
9387 hl.pwpos = &wp;
9388 SendMessageW(infoPtr->hwndHeader, HDM_LAYOUT, 0, (LPARAM)&hl);
9389 SetWindowPos(infoPtr->hwndHeader, infoPtr->hwndSelf, wp.x, wp.y, wp.cx, wp.cy,
9391 break;
9392 }
9393 case LV_VIEW_LIST:
9394 break;
9395 }
9396
9397 LISTVIEW_UpdateItemSize(infoPtr);
9398 LISTVIEW_UpdateSize(infoPtr);
9399 LISTVIEW_UpdateScroll(infoPtr);
9400 LISTVIEW_InvalidateList(infoPtr);
9401
9402 TRACE("nView=%d\n", nView);
9403
9404 return 1;
9405}
9406
9407/* LISTVIEW_SetWorkAreas */
9408
9409/***
9410 * DESCRIPTION:
9411 * Callback internally used by LISTVIEW_SortItems() in response of LVM_SORTITEMS
9412 *
9413 * PARAMETER(S):
9414 * [I] first : pointer to first ITEM_INFO to compare
9415 * [I] second : pointer to second ITEM_INFO to compare
9416 * [I] lParam : HWND of control
9417 *
9418 * RETURN:
9419 * if first comes before second : negative
9420 * if first comes after second : positive
9421 * if first and second are equivalent : zero
9422 */
9424{
9425 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)lParam;
9426 ITEM_INFO* lv_first = DPA_GetPtr( first, 0 );
9427 ITEM_INFO* lv_second = DPA_GetPtr( second, 0 );
9428
9429 /* Forward the call to the client defined callback */
9430 return (infoPtr->pfnCompare)( lv_first->lParam , lv_second->lParam, infoPtr->lParamSort );
9431}
9432
9433/***
9434 * DESCRIPTION:
9435 * Callback internally used by LISTVIEW_SortItems() in response of LVM_SORTITEMSEX
9436 *
9437 * PARAMETER(S):
9438 * [I] first : pointer to first ITEM_INFO to compare
9439 * [I] second : pointer to second ITEM_INFO to compare
9440 * [I] lParam : HWND of control
9441 *
9442 * RETURN:
9443 * if first comes before second : negative
9444 * if first comes after second : positive
9445 * if first and second are equivalent : zero
9446 */
9448{
9449 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)lParam;
9450 INT first_idx = DPA_GetPtrIndex( infoPtr->hdpaItems, first );
9451 INT second_idx = DPA_GetPtrIndex( infoPtr->hdpaItems, second );
9452
9453 /* Forward the call to the client defined callback */
9454 return (infoPtr->pfnCompare)( first_idx, second_idx, infoPtr->lParamSort );
9455}
9456
9457/***
9458 * DESCRIPTION:
9459 * Sorts the listview items.
9460 *
9461 * PARAMETER(S):
9462 * [I] infoPtr : valid pointer to the listview structure
9463 * [I] pfnCompare : application-defined value
9464 * [I] lParamSort : pointer to comparison callback
9465 * [I] IsEx : TRUE when LVM_SORTITEMSEX used
9466 *
9467 * RETURN:
9468 * SUCCESS : TRUE
9469 * FAILURE : FALSE
9470 */
9472 LPARAM lParamSort, BOOL IsEx)
9473{
9474 HDPA hdpaSubItems;
9475 ITEM_INFO *lpItem;
9476 LPVOID selectionMarkItem = NULL;
9477 LPVOID focusedItem = NULL;
9478 int i;
9479
9480 TRACE("(pfnCompare=%p, lParamSort=%lx)\n", pfnCompare, lParamSort);
9481
9482 if (infoPtr->dwStyle & LVS_OWNERDATA) return FALSE;
9483
9484 if (!pfnCompare) return FALSE;
9485 if (!infoPtr->hdpaItems) return FALSE;
9486
9487 /* if there are 0 or 1 items, there is no need to sort */
9488 if (infoPtr->nItemCount < 2) return TRUE;
9489
9490 /* clear selection */
9491 ranges_clear(infoPtr->selectionRanges);
9492
9493 /* save selection mark and focused item */
9494 if (infoPtr->nSelectionMark >= 0)
9495 selectionMarkItem = DPA_GetPtr(infoPtr->hdpaItems, infoPtr->nSelectionMark);
9496 if (infoPtr->nFocusedItem >= 0)
9497 focusedItem = DPA_GetPtr(infoPtr->hdpaItems, infoPtr->nFocusedItem);
9498
9499 infoPtr->pfnCompare = pfnCompare;
9500 infoPtr->lParamSort = lParamSort;
9501 if (IsEx)
9503 else
9505
9506 /* restore selection ranges */
9507 for (i=0; i < infoPtr->nItemCount; i++)
9508 {
9509 hdpaSubItems = DPA_GetPtr(infoPtr->hdpaItems, i);
9510 lpItem = DPA_GetPtr(hdpaSubItems, 0);
9511
9512 if (lpItem->state & LVIS_SELECTED)
9513 ranges_additem(infoPtr->selectionRanges, i);
9514 }
9515 /* restore selection mark and focused item */
9516 infoPtr->nSelectionMark = DPA_GetPtrIndex(infoPtr->hdpaItems, selectionMarkItem);
9517 infoPtr->nFocusedItem = DPA_GetPtrIndex(infoPtr->hdpaItems, focusedItem);
9518
9519 /* I believe nHotItem should be left alone, see LISTVIEW_ShiftIndices */
9520
9521 /* refresh the display */
9522 LISTVIEW_InvalidateList(infoPtr);
9523 return TRUE;
9524}
9525
9526/***
9527 * DESCRIPTION:
9528 * Update theme handle after a theme change.
9529 *
9530 * PARAMETER(S):
9531 * [I] infoPtr : valid pointer to the listview structure
9532 *
9533 * RETURN:
9534 * SUCCESS : 0
9535 * FAILURE : something else
9536 */
9538{
9539 HTHEME theme = GetWindowTheme(infoPtr->hwndSelf);
9540 CloseThemeData(theme);
9542 return 0;
9543}
9544
9545/***
9546 * DESCRIPTION:
9547 * Updates an items or rearranges the listview control.
9548 *
9549 * PARAMETER(S):
9550 * [I] infoPtr : valid pointer to the listview structure
9551 * [I] nItem : item index
9552 *
9553 * RETURN:
9554 * SUCCESS : TRUE
9555 * FAILURE : FALSE
9556 */
9557static BOOL LISTVIEW_Update(LISTVIEW_INFO *infoPtr, INT nItem)
9558{
9559 TRACE("(nItem=%d)\n", nItem);
9560
9561 if (nItem < 0 || nItem >= infoPtr->nItemCount) return FALSE;
9562
9563 /* rearrange with default alignment style */
9564 if (is_autoarrange(infoPtr))
9565 LISTVIEW_Arrange(infoPtr, LVA_DEFAULT);
9566 else
9567 LISTVIEW_InvalidateItem(infoPtr, nItem);
9568
9569 return TRUE;
9570}
9571
9572/***
9573 * DESCRIPTION:
9574 * Draw the track line at the place defined in the infoPtr structure.
9575 * The line is drawn with a XOR pen so drawing the line for the second time
9576 * in the same place erases the line.
9577 *
9578 * PARAMETER(S):
9579 * [I] infoPtr : valid pointer to the listview structure
9580 *
9581 * RETURN:
9582 * SUCCESS : TRUE
9583 * FAILURE : FALSE
9584 */
9586{
9587 HDC hdc;
9588
9589 if (infoPtr->xTrackLine == -1)
9590 return FALSE;
9591
9592 if (!(hdc = GetDC(infoPtr->hwndSelf)))
9593 return FALSE;
9594 PatBlt( hdc, infoPtr->xTrackLine, infoPtr->rcList.top,
9595 1, infoPtr->rcList.bottom - infoPtr->rcList.top, DSTINVERT );
9596 ReleaseDC(infoPtr->hwndSelf, hdc);
9597 return TRUE;
9598}
9599
9600/***
9601 * DESCRIPTION:
9602 * Called when an edit control should be displayed. This function is called after
9603 * we are sure that there was a single click - not a double click (this is a TIMERPROC).
9604 *
9605 * PARAMETER(S):
9606 * [I] hwnd : Handle to the listview
9607 * [I] uMsg : WM_TIMER (ignored)
9608 * [I] idEvent : The timer ID interpreted as a pointer to a DELAYED_EDIT_ITEM struct
9609 * [I] dwTimer : The elapsed time (ignored)
9610 *
9611 * RETURN:
9612 * None.
9613 */
9615{
9616 DELAYED_ITEM_EDIT *editItem = (DELAYED_ITEM_EDIT *)idEvent;
9618
9619 KillTimer(hwnd, idEvent);
9620 editItem->fEnabled = FALSE;
9621 /* check if the item is still selected */
9622 if (infoPtr->bFocus && LISTVIEW_GetItemState(infoPtr, editItem->iItem, LVIS_SELECTED))
9623 LISTVIEW_EditLabelT(infoPtr, editItem->iItem, TRUE);
9624}
9625
9626/***
9627 * DESCRIPTION:
9628 * Creates the listview control - the WM_NCCREATE phase.
9629 *
9630 * PARAMETER(S):
9631 * [I] hwnd : window handle
9632 * [I] lpcs : the create parameters
9633 *
9634 * RETURN:
9635 * Success: TRUE
9636 * Failure: FALSE
9637 */
9639{
9640 LISTVIEW_INFO *infoPtr;
9641 LOGFONTW logFont;
9642
9643 TRACE("(lpcs=%p)\n", lpcs);
9644
9645 /* initialize info pointer */
9646 infoPtr = Alloc(sizeof(LISTVIEW_INFO));
9647 if (!infoPtr) return FALSE;
9648
9649 SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)infoPtr);
9650
9651 infoPtr->hwndSelf = hwnd;
9652 infoPtr->dwStyle = lpcs->style; /* Note: may be changed in WM_CREATE */
9653 map_style_view(infoPtr);
9654 /* determine the type of structures to use */
9655 infoPtr->hwndNotify = lpcs->hwndParent;
9656 /* infoPtr->notifyFormat will be filled in WM_CREATE */
9657
9658 /* initialize color information */
9659 infoPtr->clrBk = CLR_NONE;
9660 infoPtr->clrText = CLR_DEFAULT;
9661 infoPtr->clrTextBk = CLR_DEFAULT;
9663#ifdef __REACTOS__
9664 infoPtr->bDefaultBkColor = TRUE;
9665#endif
9666
9667 /* set default values */
9668 infoPtr->nFocusedItem = -1;
9669 infoPtr->nSelectionMark = -1;
9670 infoPtr->nHotItem = -1;
9671 infoPtr->redraw = TRUE;
9672 infoPtr->bNoItemMetrics = TRUE;
9674 infoPtr->autoSpacing = TRUE;
9677 infoPtr->nEditLabelItem = -1;
9678 infoPtr->nLButtonDownItem = -1;
9679 infoPtr->dwHoverTime = HOVER_DEFAULT; /* default system hover time */
9680 infoPtr->cWheelRemainder = 0;
9681 infoPtr->nMeasureItemHeight = 0;
9682 infoPtr->xTrackLine = -1; /* no track line */
9683 infoPtr->itemEdit.fEnabled = FALSE;
9684 infoPtr->iVersion = COMCTL32_VERSION;
9685 infoPtr->colRectsDirty = FALSE;
9686
9687 /* get default font (icon title) */
9689 infoPtr->hDefaultFont = CreateFontIndirectW(&logFont);
9690 infoPtr->hFont = infoPtr->hDefaultFont;
9691 LISTVIEW_SaveTextMetrics(infoPtr);
9692
9693 /* allocate memory for the data structure */
9694 if (!(infoPtr->selectionRanges = ranges_create(10))) goto fail;
9695 if (!(infoPtr->hdpaItems = DPA_Create(10))) goto fail;
9696 if (!(infoPtr->hdpaItemIds = DPA_Create(10))) goto fail;
9697 if (!(infoPtr->hdpaPosX = DPA_Create(10))) goto fail;
9698 if (!(infoPtr->hdpaPosY = DPA_Create(10))) goto fail;
9699 if (!(infoPtr->hdpaColumns = DPA_Create(10))) goto fail;
9700
9701 return DefWindowProcW(hwnd, WM_NCCREATE, wParam, (LPARAM)lpcs);
9702
9703fail:
9704 DestroyWindow(infoPtr->hwndHeader);
9706 DPA_Destroy(infoPtr->hdpaItems);
9707 DPA_Destroy(infoPtr->hdpaItemIds);
9708 DPA_Destroy(infoPtr->hdpaPosX);
9709 DPA_Destroy(infoPtr->hdpaPosY);
9710 DPA_Destroy(infoPtr->hdpaColumns);
9711 Free(infoPtr);
9712 return FALSE;
9713}
9714
9715/***
9716 * DESCRIPTION:
9717 * Creates the listview control - the WM_CREATE phase. Most of the data is
9718 * already set up in LISTVIEW_NCCreate
9719 *
9720 * PARAMETER(S):
9721 * [I] hwnd : window handle
9722 * [I] lpcs : the create parameters
9723 *
9724 * RETURN:
9725 * Success: 0
9726 * Failure: -1
9727 */
9729{
9731
9732 TRACE("(lpcs=%p, style=0x%08x)\n", lpcs, lpcs->style);
9733
9734 infoPtr->dwStyle = lpcs->style;
9735 map_style_view(infoPtr);
9736
9737 infoPtr->notifyFormat = SendMessageW(infoPtr->hwndNotify, WM_NOTIFYFORMAT,
9738 (WPARAM)infoPtr->hwndSelf, NF_QUERY);
9739 /* on error defaulting to ANSI notifications */
9740 if (infoPtr->notifyFormat == 0) infoPtr->notifyFormat = NFR_ANSI;
9741 TRACE("notify format=%d\n", infoPtr->notifyFormat);
9742
9743 if ((infoPtr->uView == LV_VIEW_DETAILS) && (lpcs->style & WS_VISIBLE))
9744 {
9745 if (LISTVIEW_CreateHeader(infoPtr) < 0) return -1;
9746 }
9747 else
9748 infoPtr->hwndHeader = 0;
9749
9750 /* init item size to avoid division by 0 */
9751 LISTVIEW_UpdateItemSize (infoPtr);
9752 LISTVIEW_UpdateSize (infoPtr);
9753
9754 if (infoPtr->uView == LV_VIEW_DETAILS)
9755 {
9756 if (!(LVS_NOCOLUMNHEADER & lpcs->style) && (WS_VISIBLE & lpcs->style))
9757 {
9759 }
9760 LISTVIEW_UpdateScroll(infoPtr);
9761 /* send WM_MEASUREITEM notification */
9762 if (infoPtr->dwStyle & LVS_OWNERDRAWFIXED) notify_measureitem(infoPtr);
9763 }
9764
9766
9767 /* initialize the icon sizes */
9768 set_icon_size(&infoPtr->iconSize, infoPtr->himlNormal, infoPtr->uView != LV_VIEW_ICON);
9769 set_icon_size(&infoPtr->iconStateSize, infoPtr->himlState, TRUE);
9770 return 0;
9771}
9772
9773/***
9774 * DESCRIPTION:
9775 * Destroys the listview control.
9776 *
9777 * PARAMETER(S):
9778 * [I] infoPtr : valid pointer to the listview structure
9779 *
9780 * RETURN:
9781 * Success: 0
9782 * Failure: -1
9783 */
9785{
9786 HTHEME theme = GetWindowTheme(infoPtr->hwndSelf);
9787 CloseThemeData(theme);
9788
9789 /* delete all items */
9790 LISTVIEW_DeleteAllItems(infoPtr, TRUE);
9791
9792 return 0;
9793}
9794
9795/***
9796 * DESCRIPTION:
9797 * Enables the listview control.
9798 *
9799 * PARAMETER(S):
9800 * [I] infoPtr : valid pointer to the listview structure
9801 * [I] bEnable : specifies whether to enable or disable the window
9802 *
9803 * RETURN:
9804 * SUCCESS : TRUE
9805 * FAILURE : FALSE
9806 */
9807static BOOL LISTVIEW_Enable(const LISTVIEW_INFO *infoPtr)
9808{
9809 if (infoPtr->dwStyle & LVS_OWNERDRAWFIXED)
9810 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
9811 return TRUE;
9812}
9813
9814/***
9815 * DESCRIPTION:
9816 * Erases the background of the listview control.
9817 *
9818 * PARAMETER(S):
9819 * [I] infoPtr : valid pointer to the listview structure
9820 * [I] hdc : device context handle
9821 *
9822 * RETURN:
9823 * SUCCESS : TRUE
9824 * FAILURE : FALSE
9825 */
9826static inline BOOL LISTVIEW_EraseBkgnd(const LISTVIEW_INFO *infoPtr, HDC hdc)
9827{
9828 RECT rc;
9829
9830 TRACE("(hdc=%p)\n", hdc);
9831
9832 if (!GetClipBox(hdc, &rc)) return FALSE;
9833
9834 if (infoPtr->clrBk == CLR_NONE)
9835 {
9836 if (infoPtr->dwLvExStyle & LVS_EX_TRANSPARENTBKGND)
9837 return SendMessageW(infoPtr->hwndNotify, WM_PRINTCLIENT,
9839 else
9840 return SendMessageW(infoPtr->hwndNotify, WM_ERASEBKGND, (WPARAM)hdc, 0);
9841 }
9842
9843 /* for double buffered controls we need to do this during refresh */
9844 if (infoPtr->dwLvExStyle & LVS_EX_DOUBLEBUFFER) return FALSE;
9845
9846 return LISTVIEW_FillBkgnd(infoPtr, hdc, &rc);
9847}
9848
9849
9850/***
9851 * DESCRIPTION:
9852 * Helper function for LISTVIEW_[HV]Scroll *only*.
9853 * Performs vertical/horizontal scrolling by a give amount.
9854 *
9855 * PARAMETER(S):
9856 * [I] infoPtr : valid pointer to the listview structure
9857 * [I] dx : amount of horizontal scroll
9858 * [I] dy : amount of vertical scroll
9859 */
9860static void scroll_list(LISTVIEW_INFO *infoPtr, INT dx, INT dy)
9861{
9862 /* now we can scroll the list */
9863 ScrollWindowEx(infoPtr->hwndSelf, dx, dy, &infoPtr->rcList,
9864 &infoPtr->rcList, 0, 0, SW_ERASE | SW_INVALIDATE);
9865 /* if we have focus, adjust rect */
9866 OffsetRect(&infoPtr->rcFocus, dx, dy);
9867 UpdateWindow(infoPtr->hwndSelf);
9868}
9869
9870/***
9871 * DESCRIPTION:
9872 * Performs vertical scrolling.
9873 *
9874 * PARAMETER(S):
9875 * [I] infoPtr : valid pointer to the listview structure
9876 * [I] nScrollCode : scroll code
9877 * [I] nScrollDiff : units to scroll in SB_INTERNAL mode, 0 otherwise
9878 * [I] hScrollWnd : scrollbar control window handle
9879 *
9880 * RETURN:
9881 * Zero
9882 *
9883 * NOTES:
9884 * SB_LINEUP/SB_LINEDOWN:
9885 * for LVS_ICON, LVS_SMALLICON is 37 by experiment
9886 * for LVS_REPORT is 1 line
9887 * for LVS_LIST cannot occur
9888 *
9889 */
9890static LRESULT LISTVIEW_VScroll(LISTVIEW_INFO *infoPtr, INT nScrollCode,
9891 INT nScrollDiff)
9892{
9893 INT nOldScrollPos, nNewScrollPos;
9894 SCROLLINFO scrollInfo;
9895 BOOL is_an_icon;
9896
9897 TRACE("(nScrollCode=%d(%s), nScrollDiff=%d)\n", nScrollCode,
9898 debugscrollcode(nScrollCode), nScrollDiff);
9899
9900 if (infoPtr->hwndEdit) SendMessageW(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
9901
9902 scrollInfo.cbSize = sizeof(SCROLLINFO);
9903 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS;
9904
9905 is_an_icon = ((infoPtr->uView == LV_VIEW_ICON) || (infoPtr->uView == LV_VIEW_SMALLICON));
9906
9907 if (!GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo)) return 1;
9908
9909 nOldScrollPos = scrollInfo.nPos;
9910 switch (nScrollCode)
9911 {
9912 case SB_INTERNAL:
9913 break;
9914
9915 case SB_LINEUP:
9916 nScrollDiff = (is_an_icon) ? -LISTVIEW_SCROLL_ICON_LINE_SIZE : -1;
9917 break;
9918
9919 case SB_LINEDOWN:
9920 nScrollDiff = (is_an_icon) ? LISTVIEW_SCROLL_ICON_LINE_SIZE : 1;
9921 break;
9922
9923 case SB_PAGEUP:
9924 nScrollDiff = -scrollInfo.nPage;
9925 break;
9926
9927 case SB_PAGEDOWN:
9928 nScrollDiff = scrollInfo.nPage;
9929 break;
9930
9931 case SB_THUMBPOSITION:
9932 case SB_THUMBTRACK:
9933 nScrollDiff = scrollInfo.nTrackPos - scrollInfo.nPos;
9934 break;
9935
9936 default:
9937 nScrollDiff = 0;
9938 }
9939
9940 /* quit right away if pos isn't changing */
9941 if (nScrollDiff == 0) return 0;
9942
9943 /* calculate new position, and handle overflows */
9944 nNewScrollPos = scrollInfo.nPos + nScrollDiff;
9945 if (nScrollDiff > 0) {
9946 if (nNewScrollPos < nOldScrollPos ||
9947 nNewScrollPos > scrollInfo.nMax)
9948 nNewScrollPos = scrollInfo.nMax;
9949 } else {
9950 if (nNewScrollPos > nOldScrollPos ||
9951 nNewScrollPos < scrollInfo.nMin)
9952 nNewScrollPos = scrollInfo.nMin;
9953 }
9954
9955 /* set the new position, and reread in case it changed */
9956 scrollInfo.fMask = SIF_POS;
9957 scrollInfo.nPos = nNewScrollPos;
9958 nNewScrollPos = SetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo, TRUE);
9959
9960 /* carry on only if it really changed */
9961 if (nNewScrollPos == nOldScrollPos) return 0;
9962
9963 /* now adjust to client coordinates */
9964 nScrollDiff = nOldScrollPos - nNewScrollPos;
9965 if (infoPtr->uView == LV_VIEW_DETAILS) nScrollDiff *= infoPtr->nItemHeight;
9966
9967 /* and scroll the window */
9968 scroll_list(infoPtr, 0, nScrollDiff);
9969
9970 return 0;
9971}
9972
9973/***
9974 * DESCRIPTION:
9975 * Performs horizontal scrolling.
9976 *
9977 * PARAMETER(S):
9978 * [I] infoPtr : valid pointer to the listview structure
9979 * [I] nScrollCode : scroll code
9980 * [I] nScrollDiff : units to scroll in SB_INTERNAL mode, 0 otherwise
9981 * [I] hScrollWnd : scrollbar control window handle
9982 *
9983 * RETURN:
9984 * Zero
9985 *
9986 * NOTES:
9987 * SB_LINELEFT/SB_LINERIGHT:
9988 * for LVS_ICON, LVS_SMALLICON 1 pixel
9989 * for LVS_REPORT is 1 pixel
9990 * for LVS_LIST is 1 column --> which is a 1 because the
9991 * scroll is based on columns not pixels
9992 *
9993 */
9994static LRESULT LISTVIEW_HScroll(LISTVIEW_INFO *infoPtr, INT nScrollCode,
9995 INT nScrollDiff)
9996{
9997 INT nOldScrollPos, nNewScrollPos;
9998 SCROLLINFO scrollInfo;
9999 BOOL is_an_icon;
10000
10001 TRACE("(nScrollCode=%d(%s), nScrollDiff=%d)\n", nScrollCode,
10002 debugscrollcode(nScrollCode), nScrollDiff);
10003
10004 if (infoPtr->hwndEdit) SendMessageW(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
10005
10006 scrollInfo.cbSize = sizeof(SCROLLINFO);
10007 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS;
10008
10009 is_an_icon = ((infoPtr->uView == LV_VIEW_ICON) || (infoPtr->uView == LV_VIEW_SMALLICON));
10010
10011 if (!GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo)) return 1;
10012
10013 nOldScrollPos = scrollInfo.nPos;
10014
10015 switch (nScrollCode)
10016 {
10017 case SB_INTERNAL:
10018 break;
10019
10020 case SB_LINELEFT:
10021 nScrollDiff = (is_an_icon) ? -LISTVIEW_SCROLL_ICON_LINE_SIZE : -1;
10022 break;
10023
10024 case SB_LINERIGHT:
10025 nScrollDiff = (is_an_icon) ? LISTVIEW_SCROLL_ICON_LINE_SIZE : 1;
10026 break;
10027
10028 case SB_PAGELEFT:
10029 nScrollDiff = -scrollInfo.nPage;
10030 break;
10031
10032 case SB_PAGERIGHT:
10033 nScrollDiff = scrollInfo.nPage;
10034 break;
10035
10036 case SB_THUMBPOSITION:
10037 case SB_THUMBTRACK:
10038 nScrollDiff = scrollInfo.nTrackPos - scrollInfo.nPos;
10039 break;
10040
10041 default:
10042 nScrollDiff = 0;
10043 }
10044
10045 /* quit right away if pos isn't changing */
10046 if (nScrollDiff == 0) return 0;
10047
10048 /* calculate new position, and handle overflows */
10049 nNewScrollPos = scrollInfo.nPos + nScrollDiff;
10050 if (nScrollDiff > 0) {
10051 if (nNewScrollPos < nOldScrollPos ||
10052 nNewScrollPos > scrollInfo.nMax)
10053 nNewScrollPos = scrollInfo.nMax;
10054 } else {
10055 if (nNewScrollPos > nOldScrollPos ||
10056 nNewScrollPos < scrollInfo.nMin)
10057 nNewScrollPos = scrollInfo.nMin;
10058 }
10059
10060 /* set the new position, and reread in case it changed */
10061 scrollInfo.fMask = SIF_POS;
10062 scrollInfo.nPos = nNewScrollPos;
10063 nNewScrollPos = SetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo, TRUE);
10064
10065 /* carry on only if it really changed */
10066 if (nNewScrollPos == nOldScrollPos) return 0;
10067
10068 LISTVIEW_UpdateHeaderSize(infoPtr, nNewScrollPos);
10069
10070 /* now adjust to client coordinates */
10071 nScrollDiff = nOldScrollPos - nNewScrollPos;
10072 if (infoPtr->uView == LV_VIEW_LIST) nScrollDiff *= infoPtr->nItemWidth;
10073
10074 /* and scroll the window */
10075 scroll_list(infoPtr, nScrollDiff, 0);
10076
10077 return 0;
10078}
10079
10080static LRESULT LISTVIEW_MouseWheel(LISTVIEW_INFO *infoPtr, INT wheelDelta)
10081{
10082 INT pulScrollLines = 3;
10083
10084 TRACE("(wheelDelta=%d)\n", wheelDelta);
10085
10086 switch(infoPtr->uView)
10087 {
10088 case LV_VIEW_ICON:
10089 case LV_VIEW_SMALLICON:
10090 /*
10091 * listview should be scrolled by a multiple of 37 dependently on its dimension or its visible item number
10092 * should be fixed in the future.
10093 */
10094 LISTVIEW_VScroll(infoPtr, SB_INTERNAL, (wheelDelta > 0) ?
10096 break;
10097
10098 case LV_VIEW_DETAILS:
10099 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
10100
10101 /* if scrolling changes direction, ignore left overs */
10102 if ((wheelDelta < 0 && infoPtr->cWheelRemainder < 0) ||
10103 (wheelDelta > 0 && infoPtr->cWheelRemainder > 0))
10104 infoPtr->cWheelRemainder += wheelDelta;
10105 else
10106 infoPtr->cWheelRemainder = wheelDelta;
10107 if (infoPtr->cWheelRemainder && pulScrollLines)
10108 {
10109 int cLineScroll;
10110 pulScrollLines = min((UINT)LISTVIEW_GetCountPerColumn(infoPtr), pulScrollLines);
10111 cLineScroll = pulScrollLines * infoPtr->cWheelRemainder / WHEEL_DELTA;
10112 infoPtr->cWheelRemainder -= WHEEL_DELTA * cLineScroll / pulScrollLines;
10113 LISTVIEW_VScroll(infoPtr, SB_INTERNAL, -cLineScroll);
10114 }
10115 break;
10116
10117 case LV_VIEW_LIST:
10118 LISTVIEW_HScroll(infoPtr, (wheelDelta > 0) ? SB_LINELEFT : SB_LINERIGHT, 0);
10119 break;
10120 }
10121 return 0;
10122}
10123
10124/***
10125 * DESCRIPTION:
10126 * ???
10127 *
10128 * PARAMETER(S):
10129 * [I] infoPtr : valid pointer to the listview structure
10130 * [I] nVirtualKey : virtual key
10131 * [I] lKeyData : key data
10132 *
10133 * RETURN:
10134 * Zero
10135 */
10136static LRESULT LISTVIEW_KeyDown(LISTVIEW_INFO *infoPtr, INT nVirtualKey, LONG lKeyData)
10137{
10138 HWND hwndSelf = infoPtr->hwndSelf;
10139 INT nItem = -1;
10140 NMLVKEYDOWN nmKeyDown;
10141
10142 TRACE("(nVirtualKey=%d, lKeyData=%d)\n", nVirtualKey, lKeyData);
10143
10144 /* send LVN_KEYDOWN notification */
10145 nmKeyDown.wVKey = nVirtualKey;
10146 nmKeyDown.flags = 0;
10147 notify_hdr(infoPtr, LVN_KEYDOWN, &nmKeyDown.hdr);
10148 if (!IsWindow(hwndSelf))
10149 return 0;
10150
10151 switch (nVirtualKey)
10152 {
10153 case VK_SPACE:
10154 nItem = infoPtr->nFocusedItem;
10155 if (infoPtr->dwLvExStyle & LVS_EX_CHECKBOXES)
10156 toggle_checkbox_state(infoPtr, infoPtr->nFocusedItem);
10157 break;
10158
10159 case VK_RETURN:
10160 if ((infoPtr->nItemCount > 0) && (infoPtr->nFocusedItem != -1))
10161 {
10162 if (!notify(infoPtr, NM_RETURN)) return 0;
10163 if (!notify(infoPtr, LVN_ITEMACTIVATE)) return 0;
10164 }
10165 break;
10166
10167 case VK_HOME:
10168 if (infoPtr->nItemCount > 0)
10169 nItem = 0;
10170 break;
10171
10172 case VK_END:
10173 if (infoPtr->nItemCount > 0)
10174 nItem = infoPtr->nItemCount - 1;
10175 break;
10176
10177 case VK_LEFT:
10178 nItem = LISTVIEW_GetNextItem(infoPtr, infoPtr->nFocusedItem, LVNI_TOLEFT);
10179 break;
10180
10181 case VK_UP:
10182 nItem = LISTVIEW_GetNextItem(infoPtr, infoPtr->nFocusedItem, LVNI_ABOVE);
10183 break;
10184
10185 case VK_RIGHT:
10186 nItem = LISTVIEW_GetNextItem(infoPtr, infoPtr->nFocusedItem, LVNI_TORIGHT);
10187 break;
10188
10189 case VK_DOWN:
10190 nItem = LISTVIEW_GetNextItem(infoPtr, infoPtr->nFocusedItem, LVNI_BELOW);
10191 break;
10192
10193 case VK_PRIOR:
10194 if (infoPtr->uView == LV_VIEW_DETAILS)
10195 {
10196 INT topidx = LISTVIEW_GetTopIndex(infoPtr);
10197 if (infoPtr->nFocusedItem == topidx)
10198 nItem = topidx - LISTVIEW_GetCountPerColumn(infoPtr) + 1;
10199 else
10200 nItem = topidx;
10201 }
10202 else
10203 nItem = infoPtr->nFocusedItem - LISTVIEW_GetCountPerColumn(infoPtr)
10204 * LISTVIEW_GetCountPerRow(infoPtr);
10205 if(nItem < 0) nItem = 0;
10206 break;
10207
10208 case VK_NEXT:
10209 if (infoPtr->uView == LV_VIEW_DETAILS)
10210 {
10211 INT topidx = LISTVIEW_GetTopIndex(infoPtr);
10212 INT cnt = LISTVIEW_GetCountPerColumn(infoPtr);
10213 if (infoPtr->nFocusedItem == topidx + cnt - 1)
10214 nItem = infoPtr->nFocusedItem + cnt - 1;
10215 else
10216 nItem = topidx + cnt - 1;
10217 }
10218 else
10219 nItem = infoPtr->nFocusedItem + LISTVIEW_GetCountPerColumn(infoPtr)
10220 * LISTVIEW_GetCountPerRow(infoPtr);
10221 if(nItem >= infoPtr->nItemCount) nItem = infoPtr->nItemCount - 1;
10222 break;
10223 }
10224
10225 if ((nItem != -1) && (nItem != infoPtr->nFocusedItem || nVirtualKey == VK_SPACE))
10226 LISTVIEW_KeySelection(infoPtr, nItem, nVirtualKey == VK_SPACE);
10227
10228 return 0;
10229}
10230
10231/***
10232 * DESCRIPTION:
10233 * Kills the focus.
10234 *
10235 * PARAMETER(S):
10236 * [I] infoPtr : valid pointer to the listview structure
10237 *
10238 * RETURN:
10239 * Zero
10240 */
10242{
10243 TRACE("()\n");
10244
10245 /* drop any left over scroll amount */
10246 infoPtr->cWheelRemainder = 0;
10247
10248 /* if we did not have the focus, there's nothing more to do */
10249 if (!infoPtr->bFocus) return 0;
10250
10251 /* send NM_KILLFOCUS notification */
10252 if (!notify(infoPtr, NM_KILLFOCUS)) return 0;
10253
10254 /* if we have a focus rectangle, get rid of it */
10255 LISTVIEW_ShowFocusRect(infoPtr, FALSE);
10256
10257 /* if have a marquee selection, stop it */
10258 if (infoPtr->bMarqueeSelect)
10259 {
10260 /* Remove the marquee rectangle and release our mouse capture */
10261 LISTVIEW_InvalidateRect(infoPtr, &infoPtr->marqueeRect);
10263
10264 SetRectEmpty(&infoPtr->marqueeRect);
10265
10266 infoPtr->bMarqueeSelect = FALSE;
10267 infoPtr->bScrolling = FALSE;
10268 KillTimer(infoPtr->hwndSelf, (UINT_PTR) infoPtr);
10269 }
10270
10271 /* set window focus flag */
10272 infoPtr->bFocus = FALSE;
10273
10274 /* invalidate the selected items before resetting focus flag */
10276
10277 return 0;
10278}
10279
10280/***
10281 * DESCRIPTION:
10282 * Processes double click messages (left mouse button).
10283 *
10284 * PARAMETER(S):
10285 * [I] infoPtr : valid pointer to the listview structure
10286 * [I] wKey : key flag
10287 * [I] x,y : mouse coordinate
10288 *
10289 * RETURN:
10290 * Zero
10291 */
10293{
10294 LVHITTESTINFO htInfo;
10295
10296 TRACE("(key=%hu, X=%u, Y=%u)\n", wKey, x, y);
10297
10298 /* Cancel the item edition if any */
10299 if (infoPtr->itemEdit.fEnabled)
10300 {
10301 KillTimer(infoPtr->hwndSelf, (UINT_PTR)&infoPtr->itemEdit);
10302 infoPtr->itemEdit.fEnabled = FALSE;
10303 }
10304
10305 /* send NM_RELEASEDCAPTURE notification */
10306 if (!notify(infoPtr, NM_RELEASEDCAPTURE)) return 0;
10307
10308 htInfo.pt.x = x;
10309 htInfo.pt.y = y;
10310
10311 /* send NM_DBLCLK notification */
10312 LISTVIEW_HitTest(infoPtr, &htInfo, TRUE, FALSE);
10313 if (!notify_click(infoPtr, NM_DBLCLK, &htInfo)) return 0;
10314
10315 /* To send the LVN_ITEMACTIVATE, it must be on an Item */
10316 if(htInfo.iItem != -1) notify_itemactivate(infoPtr,&htInfo);
10317
10318 return 0;
10319}
10320
10322{
10323 MSG msg;
10324 RECT r;
10325
10326 r.top = r.bottom = pt.y;
10327 r.left = r.right = pt.x;
10328
10330
10331 SetCapture(infoPtr->hwndSelf);
10332
10333 while (1)
10334 {
10335 if (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD))
10336 {
10337 if (msg.message == WM_MOUSEMOVE)
10338 {
10339 pt.x = (short)LOWORD(msg.lParam);
10340 pt.y = (short)HIWORD(msg.lParam);
10341 if (PtInRect(&r, pt))
10342 continue;
10343 else
10344 {
10346 return 1;
10347 }
10348 }
10349 else if (msg.message >= WM_LBUTTONDOWN &&
10350 msg.message <= WM_RBUTTONDBLCLK)
10351 {
10352 break;
10353 }
10354
10356 }
10357
10358 if (GetCapture() != infoPtr->hwndSelf)
10359 return 0;
10360 }
10361
10363 return 0;
10364}
10365
10366
10367/***
10368 * DESCRIPTION:
10369 * Processes mouse down messages (left mouse button).
10370 *
10371 * PARAMETERS:
10372 * infoPtr [I ] valid pointer to the listview structure
10373 * wKey [I ] key flag
10374 * x,y [I ] mouse coordinate
10375 *
10376 * RETURN:
10377 * Zero
10378 */
10380{
10381 LVHITTESTINFO lvHitTestInfo;
10382 static BOOL bGroupSelect = TRUE;
10383 POINT pt = { x, y };
10384 INT nItem;
10385
10386 TRACE("(key=%hu, X=%u, Y=%u)\n", wKey, x, y);
10387
10388 /* send NM_RELEASEDCAPTURE notification */
10389 if (!notify(infoPtr, NM_RELEASEDCAPTURE)) return 0;
10390
10391 /* set left button down flag and record the click position */
10392 infoPtr->bLButtonDown = TRUE;
10393 infoPtr->ptClickPos = pt;
10394 infoPtr->bDragging = FALSE;
10395 infoPtr->bMarqueeSelect = FALSE;
10396 infoPtr->bScrolling = FALSE;
10397
10398 lvHitTestInfo.pt.x = x;
10399 lvHitTestInfo.pt.y = y;
10400
10401 nItem = LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE);
10402 TRACE("at %s, nItem=%d\n", wine_dbgstr_point(&pt), nItem);
10403 if ((nItem >= 0) && (nItem < infoPtr->nItemCount))
10404 {
10405 if ((infoPtr->dwLvExStyle & LVS_EX_CHECKBOXES) && (lvHitTestInfo.flags & LVHT_ONITEMSTATEICON))
10406 {
10407 notify_click(infoPtr, NM_CLICK, &lvHitTestInfo);
10408 toggle_checkbox_state(infoPtr, nItem);
10409 infoPtr->bLButtonDown = FALSE;
10410 return 0;
10411 }
10412
10413 if (infoPtr->dwStyle & LVS_SINGLESEL)
10414 {
10415 if (LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED))
10416 infoPtr->nEditLabelItem = nItem;
10417 else
10418 LISTVIEW_SetSelection(infoPtr, nItem);
10419 }
10420 else
10421 {
10422 if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
10423 {
10424 if (bGroupSelect)
10425 {
10426 if (!LISTVIEW_AddGroupSelection(infoPtr, nItem)) return 0;
10427 LISTVIEW_SetItemFocus(infoPtr, nItem);
10428 infoPtr->nSelectionMark = nItem;
10429 }
10430 else
10431 {
10432 LVITEMW item;
10433
10435 item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
10436
10437 LISTVIEW_SetItemState(infoPtr,nItem,&item);
10438 infoPtr->nSelectionMark = nItem;
10439 }
10440 }
10441 else if (wKey & MK_CONTROL)
10442 {
10443 LVITEMW item;
10444
10445 bGroupSelect = (LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED) == 0);
10446
10447 item.state = (bGroupSelect ? LVIS_SELECTED : 0) | LVIS_FOCUSED;
10448 item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
10449 LISTVIEW_SetItemState(infoPtr, nItem, &item);
10450 infoPtr->nSelectionMark = nItem;
10451 }
10452 else if (wKey & MK_SHIFT)
10453 {
10454 LISTVIEW_SetGroupSelection(infoPtr, nItem);
10455 }
10456 else
10457 {
10458 if (LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED))
10459 {
10460 infoPtr->nEditLabelItem = nItem;
10461 infoPtr->nLButtonDownItem = nItem;
10462
10463 LISTVIEW_SetItemFocus(infoPtr, nItem);
10464 }
10465 else
10466 /* set selection (clears other pre-existing selections) */
10467 LISTVIEW_SetSelection(infoPtr, nItem);
10468 }
10469 }
10470
10471 if (!infoPtr->bFocus)
10472 SetFocus(infoPtr->hwndSelf);
10473
10474 if (infoPtr->dwLvExStyle & LVS_EX_ONECLICKACTIVATE)
10475 if(lvHitTestInfo.iItem != -1) notify_itemactivate(infoPtr,&lvHitTestInfo);
10476 }
10477 else
10478 {
10479 if (!infoPtr->bFocus)
10480 SetFocus(infoPtr->hwndSelf);
10481
10482 /* remove all selections */
10483 if (!(wKey & MK_CONTROL) && !(wKey & MK_SHIFT))
10484 LISTVIEW_DeselectAll(infoPtr);
10486 }
10487
10488 return 0;
10489}
10490
10491/***
10492 * DESCRIPTION:
10493 * Processes mouse up messages (left mouse button).
10494 *
10495 * PARAMETERS:
10496 * infoPtr [I ] valid pointer to the listview structure
10497 * wKey [I ] key flag
10498 * x,y [I ] mouse coordinate
10499 *
10500 * RETURN:
10501 * Zero
10502 */
10504{
10505 LVHITTESTINFO lvHitTestInfo;
10506
10507 TRACE("(key=%hu, X=%u, Y=%u)\n", wKey, x, y);
10508
10509 if (!infoPtr->bLButtonDown) return 0;
10510
10511 lvHitTestInfo.pt.x = x;
10512 lvHitTestInfo.pt.y = y;
10513
10514 /* send NM_CLICK notification */
10515 LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, FALSE);
10516 if (!notify_click(infoPtr, NM_CLICK, &lvHitTestInfo)) return 0;
10517
10518 /* set left button flag */
10519 infoPtr->bLButtonDown = FALSE;
10520
10521 /* set a single selection, reset others */
10522 if(lvHitTestInfo.iItem == infoPtr->nLButtonDownItem && lvHitTestInfo.iItem != -1)
10523 LISTVIEW_SetSelection(infoPtr, infoPtr->nLButtonDownItem);
10524 infoPtr->nLButtonDownItem = -1;
10525
10526 if (infoPtr->bDragging || infoPtr->bMarqueeSelect)
10527 {
10528 /* Remove the marquee rectangle and release our mouse capture */
10529 if (infoPtr->bMarqueeSelect)
10530 {
10531 LISTVIEW_InvalidateRect(infoPtr, &infoPtr->marqueeDrawRect);
10533 }
10534
10535 SetRectEmpty(&infoPtr->marqueeRect);
10536 SetRectEmpty(&infoPtr->marqueeDrawRect);
10537
10538 infoPtr->bDragging = FALSE;
10539 infoPtr->bMarqueeSelect = FALSE;
10540 infoPtr->bScrolling = FALSE;
10541
10542 KillTimer(infoPtr->hwndSelf, (UINT_PTR) infoPtr);
10543 return 0;
10544 }
10545
10546 /* if we clicked on a selected item, edit the label */
10547 if(lvHitTestInfo.iItem == infoPtr->nEditLabelItem && (lvHitTestInfo.flags & LVHT_ONITEMLABEL))
10548 {
10549 /* we want to make sure the user doesn't want to do a double click. So we will
10550 * delay the edit. WM_LBUTTONDBLCLICK will cancel the timer
10551 */
10552 infoPtr->itemEdit.fEnabled = TRUE;
10553 infoPtr->itemEdit.iItem = lvHitTestInfo.iItem;
10554 SetTimer(infoPtr->hwndSelf,
10555 (UINT_PTR)&infoPtr->itemEdit,
10558 }
10559
10560 return 0;
10561}
10562
10563/***
10564 * DESCRIPTION:
10565 * Destroys the listview control (called after WM_DESTROY).
10566 *
10567 * PARAMETER(S):
10568 * [I] infoPtr : valid pointer to the listview structure
10569 *
10570 * RETURN:
10571 * Zero
10572 */
10574{
10575 INT i;
10576
10577 TRACE("()\n");
10578
10579 /* destroy data structure */
10580 DPA_Destroy(infoPtr->hdpaItems);
10581 DPA_Destroy(infoPtr->hdpaItemIds);
10582 DPA_Destroy(infoPtr->hdpaPosX);
10583 DPA_Destroy(infoPtr->hdpaPosY);
10584 /* columns */
10585 for (i = 0; i < DPA_GetPtrCount(infoPtr->hdpaColumns); i++)
10586 Free(DPA_GetPtr(infoPtr->hdpaColumns, i));
10587 DPA_Destroy(infoPtr->hdpaColumns);
10589#ifdef __REACTOS__
10590 infoPtr->selectionRanges = NULL; /* See note in ranges_clone */
10591#endif
10592
10593 /* destroy image lists */
10594 if (!(infoPtr->dwStyle & LVS_SHAREIMAGELISTS))
10595 {
10596 ImageList_Destroy(infoPtr->himlNormal);
10597 ImageList_Destroy(infoPtr->himlSmall);
10598 ImageList_Destroy(infoPtr->himlState);
10599 }
10600
10601 /* destroy font, bkgnd brush */
10602 infoPtr->hFont = 0;
10603 if (infoPtr->hDefaultFont) DeleteObject(infoPtr->hDefaultFont);
10604 if (infoPtr->clrBk != CLR_NONE) DeleteObject(infoPtr->hBkBrush);
10605
10606 SetWindowLongPtrW(infoPtr->hwndSelf, 0, 0);
10607
10608 /* free listview info pointer*/
10609 Free(infoPtr);
10610
10611 return 0;
10612}
10613
10614/***
10615 * DESCRIPTION:
10616 * Handles notifications.
10617 *
10618 * PARAMETER(S):
10619 * [I] infoPtr : valid pointer to the listview structure
10620 * [I] lpnmhdr : notification information
10621 *
10622 * RETURN:
10623 * Zero
10624 */
10625static LRESULT LISTVIEW_Notify(LISTVIEW_INFO *infoPtr, NMHDR *lpnmhdr)
10626{
10627 NMHEADERW *lpnmh;
10628
10629 TRACE("(lpnmhdr=%p)\n", lpnmhdr);
10630
10631 if (!lpnmhdr || lpnmhdr->hwndFrom != infoPtr->hwndHeader) return 0;
10632
10633 /* remember: HDN_LAST < HDN_FIRST */
10634 if (lpnmhdr->code > HDN_FIRST || lpnmhdr->code < HDN_LAST) return 0;
10635 lpnmh = (NMHEADERW *)lpnmhdr;
10636
10637 if (lpnmh->iItem < 0 || lpnmh->iItem >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return 0;
10638
10639 switch (lpnmhdr->code)
10640 {
10641 case HDN_TRACKW:
10642 case HDN_TRACKA:
10643 {
10644 COLUMN_INFO *lpColumnInfo;
10645 POINT ptOrigin;
10646 INT x;
10647
10648 if (!lpnmh->pitem || !(lpnmh->pitem->mask & HDI_WIDTH))
10649 break;
10650
10651 /* remove the old line (if any) */
10652 LISTVIEW_DrawTrackLine(infoPtr);
10653
10654 /* compute & draw the new line */
10655 lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, lpnmh->iItem);
10656 x = lpColumnInfo->rcHeader.left + lpnmh->pitem->cxy;
10657 LISTVIEW_GetOrigin(infoPtr, &ptOrigin);
10658 infoPtr->xTrackLine = x + ptOrigin.x;
10659 LISTVIEW_DrawTrackLine(infoPtr);
10660 return notify_forward_header(infoPtr, lpnmh);
10661 }
10662
10663 case HDN_ENDTRACKA:
10664 case HDN_ENDTRACKW:
10665 /* remove the track line (if any) */
10666 LISTVIEW_DrawTrackLine(infoPtr);
10667 infoPtr->xTrackLine = -1;
10668 return notify_forward_header(infoPtr, lpnmh);
10669
10670 case HDN_BEGINDRAG:
10671 if ((infoPtr->dwLvExStyle & LVS_EX_HEADERDRAGDROP) == 0) return 1;
10672 return notify_forward_header(infoPtr, lpnmh);
10673
10674 case HDN_ENDDRAG:
10675 infoPtr->colRectsDirty = TRUE;
10676 LISTVIEW_InvalidateList(infoPtr);
10677 return notify_forward_header(infoPtr, lpnmh);
10678
10679 case HDN_ITEMCHANGEDW:
10680 case HDN_ITEMCHANGEDA:
10681 {
10682 COLUMN_INFO *lpColumnInfo;
10683 HDITEMW hdi;
10684 INT dx, cxy;
10685
10686 if (!lpnmh->pitem || !(lpnmh->pitem->mask & HDI_WIDTH))
10687 {
10688 hdi.mask = HDI_WIDTH;
10689 if (!SendMessageW(infoPtr->hwndHeader, HDM_GETITEMW, lpnmh->iItem, (LPARAM)&hdi)) return 0;
10690 cxy = hdi.cxy;
10691 }
10692 else
10693 cxy = lpnmh->pitem->cxy;
10694
10695 /* determine how much we change since the last know position */
10696 lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, lpnmh->iItem);
10697 dx = cxy - (lpColumnInfo->rcHeader.right - lpColumnInfo->rcHeader.left);
10698 if (dx != 0)
10699 {
10700 lpColumnInfo->rcHeader.right += dx;
10701
10702 hdi.mask = HDI_ORDER;
10703 SendMessageW(infoPtr->hwndHeader, HDM_GETITEMW, lpnmh->iItem, (LPARAM)&hdi);
10704
10705 /* not the rightmost one */
10706 if (hdi.iOrder + 1 < DPA_GetPtrCount(infoPtr->hdpaColumns))
10707 {
10708 INT nIndex = SendMessageW(infoPtr->hwndHeader, HDM_ORDERTOINDEX,
10709 hdi.iOrder + 1, 0);
10710 LISTVIEW_ScrollColumns(infoPtr, nIndex, dx);
10711 }
10712 else
10713 {
10714 /* only needs to update the scrolls */
10715 infoPtr->nItemWidth += dx;
10716 LISTVIEW_UpdateScroll(infoPtr);
10717 }
10718 LISTVIEW_UpdateItemSize(infoPtr);
10719 if (infoPtr->uView == LV_VIEW_DETAILS && is_redrawing(infoPtr))
10720 {
10721 POINT ptOrigin;
10722 RECT rcCol = lpColumnInfo->rcHeader;
10723
10724 LISTVIEW_GetOrigin(infoPtr, &ptOrigin);
10725 OffsetRect(&rcCol, ptOrigin.x, 0);
10726
10727 rcCol.top = infoPtr->rcList.top;
10728 rcCol.bottom = infoPtr->rcList.bottom;
10729
10730 /* resizing left-aligned columns leaves most of the left side untouched */
10731 if ((lpColumnInfo->fmt & LVCFMT_JUSTIFYMASK) == LVCFMT_LEFT)
10732 {
10733 INT nMaxDirty = infoPtr->nEllipsisWidth + infoPtr->ntmMaxCharWidth;
10734 if (dx > 0)
10735 nMaxDirty += dx;
10736 rcCol.left = max (rcCol.left, rcCol.right - nMaxDirty);
10737 }
10738
10739 /* when shrinking the last column clear the now unused field */
10740 if (hdi.iOrder == DPA_GetPtrCount(infoPtr->hdpaColumns) - 1)
10741 {
10742 RECT right;
10743
10744 rcCol.right -= dx;
10745
10746 /* deal with right from rightmost column area */
10747 right.left = rcCol.right;
10748 right.top = rcCol.top;
10749 right.bottom = rcCol.bottom;
10750 right.right = infoPtr->rcList.right;
10751
10752 LISTVIEW_InvalidateRect(infoPtr, &right);
10753 }
10754
10755 LISTVIEW_InvalidateRect(infoPtr, &rcCol);
10756 }
10757 }
10758 break;
10759 }
10760
10761 case HDN_ITEMCLICKW:
10762 case HDN_ITEMCLICKA:
10763 {
10764 /* Handle sorting by Header Column */
10765 NMLISTVIEW nmlv;
10766
10767 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
10768 nmlv.iItem = -1;
10769 nmlv.iSubItem = lpnmh->iItem;
10770 notify_listview(infoPtr, LVN_COLUMNCLICK, &nmlv);
10771 return notify_forward_header(infoPtr, lpnmh);
10772 }
10773
10776 /* FIXME: for LVS_EX_HEADERINALLVIEWS and not LV_VIEW_DETAILS
10777 we should use LVSCW_AUTOSIZE_USEHEADER, helper rework or
10778 split needed for that */
10780 return notify_forward_header(infoPtr, lpnmh);
10781 }
10782 return 0;
10783}
10784
10785/***
10786 * DESCRIPTION:
10787 * Paint non-client area of control.
10788 *
10789 * PARAMETER(S):
10790 * [I] infoPtr : valid pointer to the listview structureof the sender
10791 * [I] region : update region
10792 *
10793 * RETURN:
10794 * TRUE - frame was painted
10795 * FALSE - call default window proc
10796 */
10797static BOOL LISTVIEW_NCPaint(const LISTVIEW_INFO *infoPtr, HRGN region)
10798{
10799 HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
10800 HDC dc;
10801 RECT r;
10802 HRGN cliprgn;
10803 int cxEdge = GetSystemMetrics (SM_CXEDGE),
10804 cyEdge = GetSystemMetrics (SM_CYEDGE);
10805
10806 if (!theme)
10807 return DefWindowProcW (infoPtr->hwndSelf, WM_NCPAINT, (WPARAM)region, 0);
10808
10809 GetWindowRect(infoPtr->hwndSelf, &r);
10810
10811 cliprgn = CreateRectRgn (r.left + cxEdge, r.top + cyEdge,
10812 r.right - cxEdge, r.bottom - cyEdge);
10813 if (region != (HRGN)1)
10814 CombineRgn (cliprgn, cliprgn, region, RGN_AND);
10815 OffsetRect(&r, -r.left, -r.top);
10816
10817#ifdef __REACTOS__ /* r73789 */
10818 dc = GetWindowDC(infoPtr->hwndSelf);
10819 /* Exclude client part */
10820 ExcludeClipRect(dc, r.left + cxEdge, r.top + cyEdge,
10821 r.right - cxEdge, r.bottom -cyEdge);
10822#else
10823 dc = GetDCEx(infoPtr->hwndSelf, region, DCX_WINDOW|DCX_INTERSECTRGN);
10824 OffsetRect(&r, -r.left, -r.top);
10825#endif
10826
10827 if (IsThemeBackgroundPartiallyTransparent (theme, 0, 0))
10829 DrawThemeBackground (theme, dc, 0, 0, &r, 0);
10830 ReleaseDC(infoPtr->hwndSelf, dc);
10831
10832 /* Call default proc to get the scrollbars etc. painted */
10833 DefWindowProcW (infoPtr->hwndSelf, WM_NCPAINT, (WPARAM)cliprgn, 0);
10834 DeleteObject(cliprgn);
10835
10836 return FALSE;
10837}
10838
10839/***
10840 * DESCRIPTION:
10841 * Determines the type of structure to use.
10842 *
10843 * PARAMETER(S):
10844 * [I] infoPtr : valid pointer to the listview structureof the sender
10845 * [I] hwndFrom : listview window handle
10846 * [I] nCommand : command specifying the nature of the WM_NOTIFYFORMAT
10847 *
10848 * RETURN:
10849 * Zero
10850 */
10851static LRESULT LISTVIEW_NotifyFormat(LISTVIEW_INFO *infoPtr, HWND hwndFrom, INT nCommand)
10852{
10853 TRACE("(hwndFrom=%p, nCommand=%d)\n", hwndFrom, nCommand);
10854
10855 if (nCommand == NF_REQUERY)
10856 infoPtr->notifyFormat = SendMessageW(infoPtr->hwndNotify, WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY);
10857
10858 return infoPtr->notifyFormat;
10859}
10860
10861/***
10862 * DESCRIPTION:
10863 * Paints/Repaints the listview control. Internal use.
10864 *
10865 * PARAMETER(S):
10866 * [I] infoPtr : valid pointer to the listview structure
10867 * [I] hdc : device context handle
10868 *
10869 * RETURN:
10870 * Zero
10871 */
10873{
10874 TRACE("(hdc=%p)\n", hdc);
10875
10876 if (infoPtr->bNoItemMetrics && infoPtr->nItemCount)
10877 {
10878 infoPtr->bNoItemMetrics = FALSE;
10879 LISTVIEW_UpdateItemSize(infoPtr);
10880 if (infoPtr->uView == LV_VIEW_ICON || infoPtr->uView == LV_VIEW_SMALLICON)
10881 LISTVIEW_Arrange(infoPtr, LVA_DEFAULT);
10882 LISTVIEW_UpdateScroll(infoPtr);
10883 }
10884
10885 if (infoPtr->hwndHeader) UpdateWindow(infoPtr->hwndHeader);
10886
10887 if (hdc)
10888 LISTVIEW_Refresh(infoPtr, hdc, NULL);
10889 else
10890 {
10891 PAINTSTRUCT ps;
10892
10893 hdc = BeginPaint(infoPtr->hwndSelf, &ps);
10894 if (!hdc) return 1;
10895 LISTVIEW_Refresh(infoPtr, hdc, ps.fErase ? &ps.rcPaint : NULL);
10896 EndPaint(infoPtr->hwndSelf, &ps);
10897 }
10898
10899 return 0;
10900}
10901
10902/***
10903 * DESCRIPTION:
10904 * Paints/Repaints the listview control, WM_PAINT handler.
10905 *
10906 * PARAMETER(S):
10907 * [I] infoPtr : valid pointer to the listview structure
10908 * [I] hdc : device context handle
10909 *
10910 * RETURN:
10911 * Zero
10912 */
10914{
10915 TRACE("(hdc=%p)\n", hdc);
10916
10917 if (!is_redrawing(infoPtr))
10918 return DefWindowProcW (infoPtr->hwndSelf, WM_PAINT, (WPARAM)hdc, 0);
10919
10920 return LISTVIEW_Paint(infoPtr, hdc);
10921}
10922
10923/***
10924 * DESCRIPTION:
10925 * Paints/Repaints the listview control.
10926 *
10927 * PARAMETER(S):
10928 * [I] infoPtr : valid pointer to the listview structure
10929 * [I] hdc : device context handle
10930 * [I] options : drawing options
10931 *
10932 * RETURN:
10933 * Zero
10934 */
10936{
10937 if ((options & PRF_CHECKVISIBLE) && !IsWindowVisible(infoPtr->hwndSelf))
10938 return 0;
10939
10941 FIXME("(hdc=%p options=0x%08x) partial stub\n", hdc, options);
10942
10943 if (options & PRF_ERASEBKGND)
10944 LISTVIEW_EraseBkgnd(infoPtr, hdc);
10945
10946 if (options & PRF_CLIENT)
10947 LISTVIEW_Paint(infoPtr, hdc);
10948
10949 return 0;
10950}
10951
10952
10953/***
10954 * DESCRIPTION:
10955 * Processes double click messages (right mouse button).
10956 *
10957 * PARAMETER(S):
10958 * [I] infoPtr : valid pointer to the listview structure
10959 * [I] wKey : key flag
10960 * [I] x,y : mouse coordinate
10961 *
10962 * RETURN:
10963 * Zero
10964 */
10966{
10967 LVHITTESTINFO lvHitTestInfo;
10968
10969 TRACE("(key=%hu,X=%u,Y=%u)\n", wKey, x, y);
10970
10971 /* send NM_RELEASEDCAPTURE notification */
10972 if (!notify(infoPtr, NM_RELEASEDCAPTURE)) return 0;
10973
10974 /* send NM_RDBLCLK notification */
10975 lvHitTestInfo.pt.x = x;
10976 lvHitTestInfo.pt.y = y;
10977 LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, FALSE);
10978 notify_click(infoPtr, NM_RDBLCLK, &lvHitTestInfo);
10979
10980 return 0;
10981}
10982
10983/***
10984 * DESCRIPTION:
10985 * Processes WM_RBUTTONDOWN message and corresponding drag operation.
10986 *
10987 * PARAMETER(S):
10988 * [I] infoPtr : valid pointer to the listview structure
10989 * [I] wKey : key flag
10990 * [I] x, y : mouse coordinate
10991 *
10992 * RETURN:
10993 * Zero
10994 */
10996{
10998 INT item;
10999
11000 TRACE("(key=%hu, x=%d, y=%d)\n", wKey, x, y);
11001
11002 /* send NM_RELEASEDCAPTURE notification */
11003 if (!notify(infoPtr, NM_RELEASEDCAPTURE)) return 0;
11004
11005 /* determine the index of the selected item */
11006 ht.pt.x = x;
11007 ht.pt.y = y;
11008 item = LISTVIEW_HitTest(infoPtr, &ht, TRUE, TRUE);
11009
11010 /* make sure the listview control window has the focus */
11011 if (!infoPtr->bFocus) SetFocus(infoPtr->hwndSelf);
11012
11013 if ((item >= 0) && (item < infoPtr->nItemCount))
11014 {
11015 LISTVIEW_SetItemFocus(infoPtr, item);
11016 if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)) &&
11018 LISTVIEW_SetSelection(infoPtr, item);
11019 }
11020 else
11021 LISTVIEW_DeselectAll(infoPtr);
11022
11023 if (LISTVIEW_TrackMouse(infoPtr, ht.pt))
11024 {
11025 if (ht.iItem != -1)
11026 {
11027 NMLISTVIEW nmlv;
11028
11029 memset(&nmlv, 0, sizeof(nmlv));
11030 nmlv.iItem = ht.iItem;
11031 nmlv.ptAction = ht.pt;
11032
11033 notify_listview(infoPtr, LVN_BEGINRDRAG, &nmlv);
11034 }
11035 }
11036 else
11037 {
11038 SetFocus(infoPtr->hwndSelf);
11039
11040 ht.pt.x = x;
11041 ht.pt.y = y;
11042 LISTVIEW_HitTest(infoPtr, &ht, TRUE, FALSE);
11043
11044 if (notify_click(infoPtr, NM_RCLICK, &ht))
11045 {
11046 /* Send a WM_CONTEXTMENU message in response to the WM_RBUTTONUP */
11048 (WPARAM)infoPtr->hwndSelf, (LPARAM)GetMessagePos());
11049 }
11050 }
11051
11052 return 0;
11053}
11054
11055/***
11056 * DESCRIPTION:
11057 * Sets the cursor.
11058 *
11059 * PARAMETER(S):
11060 * [I] infoPtr : valid pointer to the listview structure
11061 * [I] hwnd : window handle of window containing the cursor
11062 * [I] nHittest : hit-test code
11063 * [I] wMouseMsg : ideintifier of the mouse message
11064 *
11065 * RETURN:
11066 * TRUE if cursor is set
11067 * FALSE otherwise
11068 */
11070{
11071 LVHITTESTINFO lvHitTestInfo;
11072
11073 if (!LISTVIEW_IsHotTracking(infoPtr)) goto forward;
11074
11075 if (!infoPtr->hHotCursor) goto forward;
11076
11077 GetCursorPos(&lvHitTestInfo.pt);
11078 if (LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, FALSE, FALSE) < 0) goto forward;
11079
11080 SetCursor(infoPtr->hHotCursor);
11081
11082 return TRUE;
11083
11084forward:
11085
11086 return DefWindowProcW(infoPtr->hwndSelf, WM_SETCURSOR, wParam, lParam);
11087}
11088
11089/***
11090 * DESCRIPTION:
11091 * Sets the focus.
11092 *
11093 * PARAMETER(S):
11094 * [I] infoPtr : valid pointer to the listview structure
11095 * [I] hwndLoseFocus : handle of previously focused window
11096 *
11097 * RETURN:
11098 * Zero
11099 */
11100static LRESULT LISTVIEW_SetFocus(LISTVIEW_INFO *infoPtr, HWND hwndLoseFocus)
11101{
11102 TRACE("(hwndLoseFocus=%p)\n", hwndLoseFocus);
11103
11104 /* if we have the focus already, there's nothing to do */
11105 if (infoPtr->bFocus) return 0;
11106
11107 /* send NM_SETFOCUS notification */
11108 if (!notify(infoPtr, NM_SETFOCUS)) return 0;
11109
11110 /* set window focus flag */
11111 infoPtr->bFocus = TRUE;
11112
11113 /* put the focus rect back on */
11114 LISTVIEW_ShowFocusRect(infoPtr, TRUE);
11115
11116 /* redraw all visible selected items */
11118
11119 return 0;
11120}
11121
11122/***
11123 * DESCRIPTION:
11124 * Sets the font.
11125 *
11126 * PARAMETER(S):
11127 * [I] infoPtr : valid pointer to the listview structure
11128 * [I] fRedraw : font handle
11129 * [I] fRedraw : redraw flag
11130 *
11131 * RETURN:
11132 * Zero
11133 */
11135{
11136 HFONT oldFont = infoPtr->hFont;
11137 INT oldHeight = infoPtr->nItemHeight;
11138
11139 TRACE("(hfont=%p,redraw=%hu)\n", hFont, fRedraw);
11140
11141 infoPtr->hFont = hFont ? hFont : infoPtr->hDefaultFont;
11142 if (infoPtr->hFont == oldFont) return 0;
11143
11144 LISTVIEW_SaveTextMetrics(infoPtr);
11145
11146 infoPtr->nItemHeight = LISTVIEW_CalculateItemHeight(infoPtr);
11147
11148 if (infoPtr->uView == LV_VIEW_DETAILS)
11149 {
11150 SendMessageW(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(fRedraw, 0));
11151 LISTVIEW_UpdateSize(infoPtr);
11152 LISTVIEW_UpdateScroll(infoPtr);
11153 }
11154 else if (infoPtr->nItemHeight != oldHeight)
11155 LISTVIEW_UpdateScroll(infoPtr);
11156
11157 if (fRedraw) LISTVIEW_InvalidateList(infoPtr);
11158
11159 return 0;
11160}
11161
11162/***
11163 * DESCRIPTION:
11164 * Message handling for WM_SETREDRAW.
11165 * For the Listview, it invalidates the entire window (the doc specifies otherwise)
11166 *
11167 * PARAMETER(S):
11168 * [I] infoPtr : valid pointer to the listview structure
11169 * [I] redraw: state of redraw flag
11170 *
11171 * RETURN:
11172 * Zero.
11173 */
11175{
11176 TRACE("old=%d, new=%d\n", infoPtr->redraw, redraw);
11177
11178 if (infoPtr->redraw == !!redraw)
11179 return 0;
11180
11181 if (!(infoPtr->redraw = !!redraw))
11182 return 0;
11183
11184 if (is_autoarrange(infoPtr))
11185 LISTVIEW_Arrange(infoPtr, LVA_DEFAULT);
11186 LISTVIEW_UpdateScroll(infoPtr);
11187
11188 /* despite what the WM_SETREDRAW docs says, apps expect us
11189 * to invalidate the listview here... stupid! */
11190 LISTVIEW_InvalidateList(infoPtr);
11191
11192 return 0;
11193}
11194
11195/***
11196 * DESCRIPTION:
11197 * Resizes the listview control. This function processes WM_SIZE
11198 * messages. At this time, the width and height are not used.
11199 *
11200 * PARAMETER(S):
11201 * [I] infoPtr : valid pointer to the listview structure
11202 * [I] Width : new width
11203 * [I] Height : new height
11204 *
11205 * RETURN:
11206 * Zero
11207 */
11209{
11210 RECT rcOld = infoPtr->rcList;
11211
11212 TRACE("(width=%d, height=%d)\n", Width, Height);
11213
11214 LISTVIEW_UpdateSize(infoPtr);
11215 if (EqualRect(&rcOld, &infoPtr->rcList)) return 0;
11216
11217 /* do not bother with display related stuff if we're not redrawing */
11218 if (!is_redrawing(infoPtr)) return 0;
11219
11220 if (is_autoarrange(infoPtr))
11221 LISTVIEW_Arrange(infoPtr, LVA_DEFAULT);
11222
11223 LISTVIEW_UpdateScroll(infoPtr);
11224
11225 /* refresh all only for lists whose height changed significantly */
11226 if ((infoPtr->uView == LV_VIEW_LIST) &&
11227 (rcOld.bottom - rcOld.top) / infoPtr->nItemHeight !=
11228 (infoPtr->rcList.bottom - infoPtr->rcList.top) / infoPtr->nItemHeight)
11229 LISTVIEW_InvalidateList(infoPtr);
11230
11231 return 0;
11232}
11233
11234/***
11235 * DESCRIPTION:
11236 * Sets the size information.
11237 *
11238 * PARAMETER(S):
11239 * [I] infoPtr : valid pointer to the listview structure
11240 *
11241 * RETURN:
11242 * None
11243 */
11245{
11246 TRACE("uView=%d, rcList(old)=%s\n", infoPtr->uView, wine_dbgstr_rect(&infoPtr->rcList));
11247
11248 GetClientRect(infoPtr->hwndSelf, &infoPtr->rcList);
11249
11250 if (infoPtr->uView == LV_VIEW_LIST)
11251 {
11252 /* Apparently the "LIST" style is supposed to have the same
11253 * number of items in a column even if there is no scroll bar.
11254 * Since if a scroll bar already exists then the bottom is already
11255 * reduced, only reduce if the scroll bar does not currently exist.
11256 * The "2" is there to mimic the native control. I think it may be
11257 * related to either padding or edges. (GLA 7/2002)
11258 */
11259 if (!(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & WS_HSCROLL))
11261 infoPtr->rcList.bottom = max (infoPtr->rcList.bottom - 2, 0);
11262 }
11263
11264 /* When ListView control is created invisible, header isn't created right away. */
11265 if (infoPtr->hwndHeader)
11266 {
11267 POINT origin;
11268 WINDOWPOS wp;
11269 HDLAYOUT hl;
11270 RECT rect;
11271
11272 LISTVIEW_GetOrigin(infoPtr, &origin);
11273
11274 rect = infoPtr->rcList;
11275 rect.left += origin.x;
11276
11277 hl.prc = &rect;
11278 hl.pwpos = &wp;
11279 SendMessageW( infoPtr->hwndHeader, HDM_LAYOUT, 0, (LPARAM)&hl );
11280 TRACE(" wp.flags=0x%08x, wp=%d,%d (%dx%d)\n", wp.flags, wp.x, wp.y, wp.cx, wp.cy);
11281
11282 if (LISTVIEW_IsHeaderEnabled(infoPtr))
11283 wp.flags |= SWP_SHOWWINDOW;
11284 else
11285 {
11286 wp.flags |= SWP_HIDEWINDOW;
11287 wp.cy = 0;
11288 }
11289
11290 SetWindowPos(wp.hwnd, wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
11291 TRACE(" after SWP wp=%d,%d (%dx%d)\n", wp.x, wp.y, wp.cx, wp.cy);
11292
11293 infoPtr->rcList.top = max(wp.cy, 0);
11294 }
11295 /* extra padding for grid */
11296 if (infoPtr->uView == LV_VIEW_DETAILS && infoPtr->dwLvExStyle & LVS_EX_GRIDLINES)
11297 infoPtr->rcList.top += 2;
11298
11299 TRACE(" rcList=%s\n", wine_dbgstr_rect(&infoPtr->rcList));
11300}
11301
11302/***
11303 * DESCRIPTION:
11304 * Processes WM_STYLECHANGED messages.
11305 *
11306 * PARAMETER(S):
11307 * [I] infoPtr : valid pointer to the listview structure
11308 * [I] wStyleType : window style type (normal or extended)
11309 * [I] lpss : window style information
11310 *
11311 * RETURN:
11312 * Zero
11313 */
11314static INT LISTVIEW_StyleChanged(LISTVIEW_INFO *infoPtr, WPARAM wStyleType,
11315 const STYLESTRUCT *lpss)
11316{
11317 UINT uNewView, uOldView;
11318 UINT style;
11319
11320 TRACE("(styletype=%lx, styleOld=0x%08x, styleNew=0x%08x)\n",
11321 wStyleType, lpss->styleOld, lpss->styleNew);
11322
11323 if (wStyleType != GWL_STYLE || lpss->styleNew == infoPtr->dwStyle) return 0;
11324
11325 infoPtr->dwStyle = lpss->styleNew;
11326
11327 if (((lpss->styleOld & WS_HSCROLL) != 0)&&
11328 ((lpss->styleNew & WS_HSCROLL) == 0))
11329 ShowScrollBar(infoPtr->hwndSelf, SB_HORZ, FALSE);
11330
11331 if (((lpss->styleOld & WS_VSCROLL) != 0)&&
11332 ((lpss->styleNew & WS_VSCROLL) == 0))
11333 ShowScrollBar(infoPtr->hwndSelf, SB_VERT, FALSE);
11334
11335 uNewView = lpss->styleNew & LVS_TYPEMASK;
11336 uOldView = lpss->styleOld & LVS_TYPEMASK;
11337
11338 if (uNewView != uOldView)
11339 {
11341
11342 /* LVM_SETVIEW doesn't change window style bits within LVS_TYPEMASK,
11343 changing style updates current view only when view bits change. */
11344 map_style_view(infoPtr);
11345 SendMessageW(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
11346 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
11347
11348 ShowScrollBar(infoPtr->hwndSelf, SB_BOTH, FALSE);
11349 SetRectEmpty(&infoPtr->rcFocus);
11350
11351 himl = (uNewView == LVS_ICON ? infoPtr->himlNormal : infoPtr->himlSmall);
11352 set_icon_size(&infoPtr->iconSize, himl, uNewView != LVS_ICON);
11353
11354 if (uNewView == LVS_REPORT)
11355 {
11356 HDLAYOUT hl;
11357 WINDOWPOS wp;
11358
11359 LISTVIEW_CreateHeader( infoPtr );
11360
11361 hl.prc = &infoPtr->rcList;
11362 hl.pwpos = &wp;
11363 SendMessageW( infoPtr->hwndHeader, HDM_LAYOUT, 0, (LPARAM)&hl );
11364 SetWindowPos(infoPtr->hwndHeader, infoPtr->hwndSelf, wp.x, wp.y, wp.cx, wp.cy,
11365 wp.flags | ((infoPtr->dwStyle & LVS_NOCOLUMNHEADER)
11367 }
11368
11369 LISTVIEW_UpdateItemSize(infoPtr);
11370 }
11371
11372 if (uNewView == LVS_REPORT || infoPtr->dwLvExStyle & LVS_EX_HEADERINALLVIEWS)
11373 {
11374 if ((lpss->styleOld ^ lpss->styleNew) & LVS_NOCOLUMNHEADER)
11375 {
11376 if (lpss->styleNew & LVS_NOCOLUMNHEADER)
11377 {
11378 /* Turn off the header control */
11380 TRACE("Hide header control, was 0x%08x\n", style);
11382 } else {
11383 /* Turn on the header control */
11384 if ((style = GetWindowLongW(infoPtr->hwndHeader, GWL_STYLE)) & HDS_HIDDEN)
11385 {
11386 TRACE("Show header control, was 0x%08x\n", style);
11388 }
11389 }
11390 }
11391 }
11392
11393 if ( (uNewView == LVS_ICON || uNewView == LVS_SMALLICON) &&
11394 (uNewView != uOldView || ((lpss->styleNew ^ lpss->styleOld) & LVS_ALIGNMASK)) )
11395 LISTVIEW_Arrange(infoPtr, LVA_DEFAULT);
11396
11397 /* update the size of the client area */
11398 LISTVIEW_UpdateSize(infoPtr);
11399
11400 /* add scrollbars if needed */
11401 LISTVIEW_UpdateScroll(infoPtr);
11402
11403 /* invalidate client area + erase background */
11404 LISTVIEW_InvalidateList(infoPtr);
11405
11406 return 0;
11407}
11408
11409/***
11410 * DESCRIPTION:
11411 * Processes WM_STYLECHANGING messages.
11412 *
11413 * PARAMETER(S):
11414 * [I] wStyleType : window style type (normal or extended)
11415 * [I0] lpss : window style information
11416 *
11417 * RETURN:
11418 * Zero
11419 */
11421 STYLESTRUCT *lpss)
11422{
11423 TRACE("(styletype=%lx, styleOld=0x%08x, styleNew=0x%08x)\n",
11424 wStyleType, lpss->styleOld, lpss->styleNew);
11425
11426 /* don't forward LVS_OWNERDATA only if not already set to */
11427 if ((lpss->styleNew ^ lpss->styleOld) & LVS_OWNERDATA)
11428 {
11429 if (lpss->styleOld & LVS_OWNERDATA)
11430 lpss->styleNew |= LVS_OWNERDATA;
11431 else
11432 lpss->styleNew &= ~LVS_OWNERDATA;
11433 }
11434
11435 return 0;
11436}
11437
11438/***
11439 * DESCRIPTION:
11440 * Processes WM_SHOWWINDOW messages.
11441 *
11442 * PARAMETER(S):
11443 * [I] infoPtr : valid pointer to the listview structure
11444 * [I] bShown : window is being shown (FALSE when hidden)
11445 * [I] iStatus : window show status
11446 *
11447 * RETURN:
11448 * Zero
11449 */
11450static LRESULT LISTVIEW_ShowWindow(LISTVIEW_INFO *infoPtr, WPARAM bShown, LPARAM iStatus)
11451{
11452 /* header delayed creation */
11453 if ((infoPtr->uView == LV_VIEW_DETAILS) && bShown)
11454 {
11455 LISTVIEW_CreateHeader(infoPtr);
11456
11457 if (!(LVS_NOCOLUMNHEADER & infoPtr->dwStyle))
11459 }
11460
11461 return DefWindowProcW(infoPtr->hwndSelf, WM_SHOWWINDOW, bShown, iStatus);
11462}
11463
11464/***
11465 * DESCRIPTION:
11466 * Processes CCM_GETVERSION messages.
11467 *
11468 * PARAMETER(S):
11469 * [I] infoPtr : valid pointer to the listview structure
11470 *
11471 * RETURN:
11472 * Current version
11473 */
11474static inline LRESULT LISTVIEW_GetVersion(const LISTVIEW_INFO *infoPtr)
11475{
11476 return infoPtr->iVersion;
11477}
11478
11479/***
11480 * DESCRIPTION:
11481 * Processes CCM_SETVERSION messages.
11482 *
11483 * PARAMETER(S):
11484 * [I] infoPtr : valid pointer to the listview structure
11485 * [I] iVersion : version to be set
11486 *
11487 * RETURN:
11488 * -1 when requested version is greater than DLL version;
11489 * previous version otherwise
11490 */
11492{
11493 INT iOldVersion = infoPtr->iVersion;
11494
11495 if (iVersion > COMCTL32_VERSION)
11496 return -1;
11497
11498 infoPtr->iVersion = iVersion;
11499
11500 TRACE("new version %d\n", iVersion);
11501
11502 return iOldVersion;
11503}
11504
11505/***
11506 * DESCRIPTION:
11507 * Window procedure of the listview control.
11508 *
11509 */
11510static LRESULT WINAPI
11512{
11514
11515 TRACE("(hwnd=%p uMsg=%x wParam=%lx lParam=%lx)\n", hwnd, uMsg, wParam, lParam);
11516
11517 if (!infoPtr && (uMsg != WM_NCCREATE))
11518 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
11519
11520 switch (uMsg)
11521 {
11523 return LISTVIEW_ApproximateViewRect(infoPtr, (INT)wParam,
11525 case LVM_ARRANGE:
11526 return LISTVIEW_Arrange(infoPtr, (INT)wParam);
11527
11529 return LISTVIEW_CancelEditLabel(infoPtr);
11530
11533
11534 case LVM_DELETEALLITEMS:
11535 return LISTVIEW_DeleteAllItems(infoPtr, FALSE);
11536
11537 case LVM_DELETECOLUMN:
11538 return LISTVIEW_DeleteColumn(infoPtr, (INT)wParam);
11539
11540 case LVM_DELETEITEM:
11541 return LISTVIEW_DeleteItem(infoPtr, (INT)wParam);
11542
11543 case LVM_EDITLABELA:
11544 case LVM_EDITLABELW:
11545 return (LRESULT)LISTVIEW_EditLabelT(infoPtr, (INT)wParam,
11546 uMsg == LVM_EDITLABELW);
11547 /* case LVM_ENABLEGROUPVIEW: */
11548
11549 case LVM_ENSUREVISIBLE:
11550 return LISTVIEW_EnsureVisible(infoPtr, (INT)wParam, (BOOL)lParam);
11551
11552 case LVM_FINDITEMW:
11553 return LISTVIEW_FindItemW(infoPtr, (INT)wParam, (LPLVFINDINFOW)lParam);
11554
11555 case LVM_FINDITEMA:
11556 return LISTVIEW_FindItemA(infoPtr, (INT)wParam, (LPLVFINDINFOA)lParam);
11557
11558 case LVM_GETBKCOLOR:
11559 return infoPtr->clrBk;
11560
11561 /* case LVM_GETBKIMAGE: */
11562
11564 return infoPtr->uCallbackMask;
11565
11566 case LVM_GETCOLUMNA:
11567 case LVM_GETCOLUMNW:
11568 return LISTVIEW_GetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam,
11569 uMsg == LVM_GETCOLUMNW);
11570
11573
11574 case LVM_GETCOLUMNWIDTH:
11575 return LISTVIEW_GetColumnWidth(infoPtr, (INT)wParam);
11576
11578 return LISTVIEW_GetCountPerPage(infoPtr);
11579
11580 case LVM_GETEDITCONTROL:
11581 return (LRESULT)infoPtr->hwndEdit;
11582
11584 return infoPtr->dwLvExStyle;
11585
11586 /* case LVM_GETGROUPINFO: */
11587
11588 /* case LVM_GETGROUPMETRICS: */
11589
11590 case LVM_GETHEADER:
11591 return (LRESULT)infoPtr->hwndHeader;
11592
11593 case LVM_GETHOTCURSOR:
11594 return (LRESULT)infoPtr->hHotCursor;
11595
11596 case LVM_GETHOTITEM:
11597 return infoPtr->nHotItem;
11598
11599 case LVM_GETHOVERTIME:
11600 return infoPtr->dwHoverTime;
11601
11602 case LVM_GETIMAGELIST:
11603 return (LRESULT)LISTVIEW_GetImageList(infoPtr, (INT)wParam);
11604
11605 /* case LVM_GETINSERTMARK: */
11606
11607 /* case LVM_GETINSERTMARKCOLOR: */
11608
11609 /* case LVM_GETINSERTMARKRECT: */
11610
11613 FIXME("LVM_GETISEARCHSTRING: unimplemented\n");
11614 return FALSE;
11615
11616 case LVM_GETITEMA:
11617 case LVM_GETITEMW:
11618 return LISTVIEW_GetItemExtT(infoPtr, (LPLVITEMW)lParam, uMsg == LVM_GETITEMW);
11619
11620 case LVM_GETITEMCOUNT:
11621 return infoPtr->nItemCount;
11622
11624 return LISTVIEW_GetItemPosition(infoPtr, (INT)wParam, (LPPOINT)lParam);
11625
11626 case LVM_GETITEMRECT:
11627 return LISTVIEW_GetItemRect(infoPtr, (INT)wParam, (LPRECT)lParam);
11628
11629 case LVM_GETITEMSPACING:
11630 return LISTVIEW_GetItemSpacing(infoPtr, (BOOL)wParam);
11631
11632 case LVM_GETITEMSTATE:
11633 return LISTVIEW_GetItemState(infoPtr, (INT)wParam, (UINT)lParam);
11634
11635 case LVM_GETITEMTEXTA:
11636 case LVM_GETITEMTEXTW:
11637 return LISTVIEW_GetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam,
11638 uMsg == LVM_GETITEMTEXTW);
11639
11640 case LVM_GETNEXTITEM:
11641 return LISTVIEW_GetNextItem(infoPtr, (INT)wParam, LOWORD(lParam));
11642
11644 FIXME("LVM_GETNUMBEROFWORKAREAS: unimplemented\n");
11645 return 1;
11646
11647 case LVM_GETORIGIN:
11648 if (!lParam) return FALSE;
11649 if (infoPtr->uView == LV_VIEW_DETAILS ||
11650 infoPtr->uView == LV_VIEW_LIST) return FALSE;
11652 return TRUE;
11653
11654 /* case LVM_GETOUTLINECOLOR: */
11655
11656 /* case LVM_GETSELECTEDCOLUMN: */
11657
11659 return LISTVIEW_GetSelectedCount(infoPtr);
11660
11662 return infoPtr->nSelectionMark;
11663
11666 return LISTVIEW_GetStringWidthT(infoPtr, (LPCWSTR)lParam,
11667 uMsg == LVM_GETSTRINGWIDTHW);
11668
11669 case LVM_GETSUBITEMRECT:
11670 return LISTVIEW_GetSubItemRect(infoPtr, (UINT)wParam, (LPRECT)lParam);
11671
11672 case LVM_GETTEXTBKCOLOR:
11673 return infoPtr->clrTextBk;
11674
11675 case LVM_GETTEXTCOLOR:
11676 return infoPtr->clrText;
11677
11678 /* case LVM_GETTILEINFO: */
11679
11680 /* case LVM_GETTILEVIEWINFO: */
11681
11682 case LVM_GETTOOLTIPS:
11683 if( !infoPtr->hwndToolTip )
11685 return (LRESULT)infoPtr->hwndToolTip;
11686
11687 case LVM_GETTOPINDEX:
11688 return LISTVIEW_GetTopIndex(infoPtr);
11689
11691 return (infoPtr->notifyFormat == NFR_UNICODE);
11692
11693 case LVM_GETVIEW:
11694 return infoPtr->uView;
11695
11696 case LVM_GETVIEWRECT:
11697 return LISTVIEW_GetViewRect(infoPtr, (LPRECT)lParam);
11698
11699 case LVM_GETWORKAREAS:
11700 FIXME("LVM_GETWORKAREAS: unimplemented\n");
11701 return FALSE;
11702
11703 /* case LVM_HASGROUP: */
11704
11705 case LVM_HITTEST:
11706 return LISTVIEW_HitTest(infoPtr, (LPLVHITTESTINFO)lParam, FALSE, TRUE);
11707
11708 case LVM_INSERTCOLUMNA:
11709 case LVM_INSERTCOLUMNW:
11711 uMsg == LVM_INSERTCOLUMNW);
11712
11713 /* case LVM_INSERTGROUP: */
11714
11715 /* case LVM_INSERTGROUPSORTED: */
11716
11717 case LVM_INSERTITEMA:
11718 case LVM_INSERTITEMW:
11719 return LISTVIEW_InsertItemT(infoPtr, (LPLVITEMW)lParam, uMsg == LVM_INSERTITEMW);
11720
11721 /* case LVM_INSERTMARKHITTEST: */
11722
11723 /* case LVM_ISGROUPVIEWENABLED: */
11724
11725 case LVM_ISITEMVISIBLE:
11726 return LISTVIEW_IsItemVisible(infoPtr, (INT)wParam);
11727
11728 case LVM_MAPIDTOINDEX:
11729 return LISTVIEW_MapIdToIndex(infoPtr, (UINT)wParam);
11730
11731 case LVM_MAPINDEXTOID:
11732 return LISTVIEW_MapIndexToId(infoPtr, (INT)wParam);
11733
11734 /* case LVM_MOVEGROUP: */
11735
11736 /* case LVM_MOVEITEMTOGROUP: */
11737
11738 case LVM_REDRAWITEMS:
11739 return LISTVIEW_RedrawItems(infoPtr, (INT)wParam, (INT)lParam);
11740
11741 /* case LVM_REMOVEALLGROUPS: */
11742
11743 /* case LVM_REMOVEGROUP: */
11744
11745 case LVM_SCROLL:
11746 return LISTVIEW_Scroll(infoPtr, (INT)wParam, (INT)lParam);
11747
11748 case LVM_SETBKCOLOR:
11749 return LISTVIEW_SetBkColor(infoPtr, (COLORREF)lParam);
11750
11751 /* case LVM_SETBKIMAGE: */
11752
11754 infoPtr->uCallbackMask = (UINT)wParam;
11755 return TRUE;
11756
11757 case LVM_SETCOLUMNA:
11758 case LVM_SETCOLUMNW:
11759 return LISTVIEW_SetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam,
11760 uMsg == LVM_SETCOLUMNW);
11761
11764
11765 case LVM_SETCOLUMNWIDTH:
11766 return LISTVIEW_SetColumnWidth(infoPtr, (INT)wParam, (short)LOWORD(lParam));
11767
11770
11771 /* case LVM_SETGROUPINFO: */
11772
11773 /* case LVM_SETGROUPMETRICS: */
11774
11775 case LVM_SETHOTCURSOR:
11776 return (LRESULT)LISTVIEW_SetHotCursor(infoPtr, (HCURSOR)lParam);
11777
11778 case LVM_SETHOTITEM:
11779 return LISTVIEW_SetHotItem(infoPtr, (INT)wParam);
11780
11781 case LVM_SETHOVERTIME:
11782 return LISTVIEW_SetHoverTime(infoPtr, (DWORD)lParam);
11783
11784 case LVM_SETICONSPACING:
11785 if(lParam == -1)
11786 return LISTVIEW_SetIconSpacing(infoPtr, -1, -1);
11788
11789 case LVM_SETIMAGELIST:
11791
11792 /* case LVM_SETINFOTIP: */
11793
11794 /* case LVM_SETINSERTMARK: */
11795
11796 /* case LVM_SETINSERTMARKCOLOR: */
11797
11798 case LVM_SETITEMA:
11799 case LVM_SETITEMW:
11800 {
11801 if (infoPtr->dwStyle & LVS_OWNERDATA) return FALSE;
11802 return LISTVIEW_SetItemT(infoPtr, (LPLVITEMW)lParam, (uMsg == LVM_SETITEMW));
11803 }
11804
11805 case LVM_SETITEMCOUNT:
11806 return LISTVIEW_SetItemCount(infoPtr, (INT)wParam, (DWORD)lParam);
11807
11809 {
11810 POINT pt;
11811 pt.x = (short)LOWORD(lParam);
11812 pt.y = (short)HIWORD(lParam);
11813 return LISTVIEW_SetItemPosition(infoPtr, (INT)wParam, &pt);
11814 }
11815
11817 return LISTVIEW_SetItemPosition(infoPtr, (INT)wParam, (POINT*)lParam);
11818
11819 case LVM_SETITEMSTATE:
11820 return LISTVIEW_SetItemState(infoPtr, (INT)wParam, (LPLVITEMW)lParam);
11821
11822 case LVM_SETITEMTEXTA:
11823 case LVM_SETITEMTEXTW:
11824 return LISTVIEW_SetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam,
11825 uMsg == LVM_SETITEMTEXTW);
11826
11827 /* case LVM_SETOUTLINECOLOR: */
11828
11829 /* case LVM_SETSELECTEDCOLUMN: */
11830
11832 return LISTVIEW_SetSelectionMark(infoPtr, (INT)lParam);
11833
11834 case LVM_SETTEXTBKCOLOR:
11835 return LISTVIEW_SetTextBkColor(infoPtr, (COLORREF)lParam);
11836
11837 case LVM_SETTEXTCOLOR:
11838 return LISTVIEW_SetTextColor(infoPtr, (COLORREF)lParam);
11839
11840 /* case LVM_SETTILEINFO: */
11841
11842 /* case LVM_SETTILEVIEWINFO: */
11843
11844 /* case LVM_SETTILEWIDTH: */
11845
11846 case LVM_SETTOOLTIPS:
11847 return (LRESULT)LISTVIEW_SetToolTips(infoPtr, (HWND)lParam);
11848
11850 return LISTVIEW_SetUnicodeFormat(infoPtr, wParam);
11851
11852 case LVM_SETVIEW:
11853 return LISTVIEW_SetView(infoPtr, wParam);
11854
11855 /* case LVM_SETWORKAREAS: */
11856
11857 /* case LVM_SORTGROUPS: */
11858
11859 case LVM_SORTITEMS:
11860 case LVM_SORTITEMSEX:
11861 return LISTVIEW_SortItems(infoPtr, (PFNLVCOMPARE)lParam, wParam,
11862 uMsg == LVM_SORTITEMSEX);
11863 case LVM_SUBITEMHITTEST:
11864 return LISTVIEW_HitTest(infoPtr, (LPLVHITTESTINFO)lParam, TRUE, FALSE);
11865
11866 case LVM_UPDATE:
11867 return LISTVIEW_Update(infoPtr, (INT)wParam);
11868
11869 case CCM_GETVERSION:
11870 return LISTVIEW_GetVersion(infoPtr);
11871
11872 case CCM_SETVERSION:
11873 return LISTVIEW_SetVersion(infoPtr, wParam);
11874
11875 case WM_CHAR:
11876 return LISTVIEW_ProcessLetterKeys( infoPtr, wParam, lParam );
11877
11878 case WM_COMMAND:
11879 return LISTVIEW_Command(infoPtr, wParam, lParam);
11880
11881 case WM_NCCREATE:
11883
11884 case WM_CREATE:
11886
11887 case WM_DESTROY:
11888 return LISTVIEW_Destroy(infoPtr);
11889
11890 case WM_ENABLE:
11891 return LISTVIEW_Enable(infoPtr);
11892
11893 case WM_ERASEBKGND:
11894 return LISTVIEW_EraseBkgnd(infoPtr, (HDC)wParam);
11895
11896 case WM_GETDLGCODE:
11898
11899 case WM_GETFONT:
11900 return (LRESULT)infoPtr->hFont;
11901
11902 case WM_HSCROLL:
11903 return LISTVIEW_HScroll(infoPtr, (INT)LOWORD(wParam), 0);
11904
11905 case WM_KEYDOWN:
11906 return LISTVIEW_KeyDown(infoPtr, (INT)wParam, (LONG)lParam);
11907
11908 case WM_KILLFOCUS:
11909 return LISTVIEW_KillFocus(infoPtr);
11910
11911 case WM_LBUTTONDBLCLK:
11913
11914 case WM_LBUTTONDOWN:
11916
11917 case WM_LBUTTONUP:
11919
11920 case WM_MOUSEMOVE:
11922
11923 case WM_MOUSEHOVER:
11925
11926 case WM_NCDESTROY:
11927 return LISTVIEW_NCDestroy(infoPtr);
11928
11929 case WM_NCPAINT:
11930 return LISTVIEW_NCPaint(infoPtr, (HRGN)wParam);
11931
11932 case WM_NOTIFY:
11933 return LISTVIEW_Notify(infoPtr, (LPNMHDR)lParam);
11934
11935 case WM_NOTIFYFORMAT:
11936 return LISTVIEW_NotifyFormat(infoPtr, (HWND)wParam, (INT)lParam);
11937
11938 case WM_PRINTCLIENT:
11939 return LISTVIEW_PrintClient(infoPtr, (HDC)wParam, (DWORD)lParam);
11940
11941 case WM_PAINT:
11942 return LISTVIEW_WMPaint(infoPtr, (HDC)wParam);
11943
11944 case WM_RBUTTONDBLCLK:
11946
11947 case WM_RBUTTONDOWN:
11949
11950 case WM_SETCURSOR:
11951 return LISTVIEW_SetCursor(infoPtr, wParam, lParam);
11952
11953 case WM_SETFOCUS:
11954 return LISTVIEW_SetFocus(infoPtr, (HWND)wParam);
11955
11956 case WM_SETFONT:
11957 return LISTVIEW_SetFont(infoPtr, (HFONT)wParam, (WORD)lParam);
11958
11959 case WM_SETREDRAW:
11960 return LISTVIEW_SetRedraw(infoPtr, (BOOL)wParam);
11961
11962 case WM_SHOWWINDOW:
11963 return LISTVIEW_ShowWindow(infoPtr, wParam, lParam);
11964
11965 case WM_STYLECHANGED:
11967
11968 case WM_STYLECHANGING:
11970
11971 case WM_SYSCOLORCHANGE:
11973#ifdef __REACTOS__
11974 if (infoPtr->bDefaultBkColor)
11975 {
11977 infoPtr->bDefaultBkColor = TRUE;
11978 LISTVIEW_InvalidateList(infoPtr);
11979 }
11980#endif
11981 return 0;
11982
11983/* case WM_TIMER: */
11984 case WM_THEMECHANGED:
11985 return LISTVIEW_ThemeChanged(infoPtr);
11986
11987 case WM_VSCROLL:
11988 return LISTVIEW_VScroll(infoPtr, (INT)LOWORD(wParam), 0);
11989
11990 case WM_MOUSEWHEEL:
11991 if (wParam & (MK_SHIFT | MK_CONTROL))
11992 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
11993 return LISTVIEW_MouseWheel(infoPtr, (short int)HIWORD(wParam));
11994
11996 if (!(((WINDOWPOS *)lParam)->flags & SWP_NOSIZE))
11997 {
11998 SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE |
12000
12001 if ((infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && (infoPtr->uView == LV_VIEW_DETAILS))
12002 {
12003 if (notify_measureitem(infoPtr)) LISTVIEW_InvalidateList(infoPtr);
12004 }
12005 LISTVIEW_Size(infoPtr, ((WINDOWPOS *)lParam)->cx, ((WINDOWPOS *)lParam)->cy);
12006 }
12007 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
12008
12009/* case WM_WININICHANGE: */
12010
12011 default:
12012 if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
12013 ERR("unknown msg %04x wp=%08lx lp=%08lx\n", uMsg, wParam, lParam);
12014
12015 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
12016 }
12017
12018}
12019
12020/***
12021 * DESCRIPTION:
12022 * Registers the window class.
12023 *
12024 * PARAMETER(S):
12025 * None
12026 *
12027 * RETURN:
12028 * None
12029 */
12031{
12032 WNDCLASSW wndClass;
12033
12034 ZeroMemory(&wndClass, sizeof(WNDCLASSW));
12035 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
12037 wndClass.cbClsExtra = 0;
12038 wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *);
12039 wndClass.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
12040 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
12041 wndClass.lpszClassName = WC_LISTVIEWW;
12042 RegisterClassW(&wndClass);
12043}
12044
12045/***
12046 * DESCRIPTION:
12047 * Unregisters the window class.
12048 *
12049 * PARAMETER(S):
12050 * None
12051 *
12052 * RETURN:
12053 * None
12054 */
12056{
12058}
12059
12060/***
12061 * DESCRIPTION:
12062 * Handle any WM_COMMAND messages
12063 *
12064 * PARAMETER(S):
12065 * [I] infoPtr : valid pointer to the listview structure
12066 * [I] wParam : the first message parameter
12067 * [I] lParam : the second message parameter
12068 *
12069 * RETURN:
12070 * Zero.
12071 */
12073{
12074
12075 TRACE("(%p %x %x %lx)\n", infoPtr, HIWORD(wParam), LOWORD(wParam), lParam);
12076
12077 if (!infoPtr->hwndEdit) return 0;
12078
12079 switch (HIWORD(wParam))
12080 {
12081 case EN_UPDATE:
12082 {
12083 /*
12084 * Adjust the edit window size
12085 */
12086 WCHAR buffer[1024];
12087 HDC hdc = GetDC(infoPtr->hwndEdit);
12088 HFONT hFont, hOldFont = 0;
12089 RECT rect;
12090 SIZE sz;
12091
12092 if (!infoPtr->hwndEdit || !hdc) return 0;
12094 GetWindowRect(infoPtr->hwndEdit, &rect);
12095
12096 /* Select font to get the right dimension of the string */
12097 hFont = (HFONT)SendMessageW(infoPtr->hwndEdit, WM_GETFONT, 0, 0);
12098 if (hFont)
12099 {
12100 hOldFont = SelectObject(hdc, hFont);
12101 }
12102
12104 {
12105 TEXTMETRICW textMetric;
12106
12107 /* Add Extra spacing for the next character */
12108 GetTextMetricsW(hdc, &textMetric);
12109 sz.cx += (textMetric.tmMaxCharWidth * 2);
12110
12111 SetWindowPos(infoPtr->hwndEdit, NULL, 0, 0, sz.cx,
12112 rect.bottom - rect.top, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOZORDER);
12113 }
12114 if (hFont)
12115 SelectObject(hdc, hOldFont);
12116
12117 ReleaseDC(infoPtr->hwndEdit, hdc);
12118
12119 break;
12120 }
12121 case EN_KILLFOCUS:
12122 {
12124 LISTVIEW_CancelEditLabel(infoPtr);
12125 break;
12126 }
12127
12128 default:
12129 return SendMessageW (infoPtr->hwndNotify, WM_COMMAND, wParam, lParam);
12130 }
12131
12132 return 0;
12133}
_STLP_MOVE_TO_STD_NAMESPACE bool is_sorted(_ForwardIter __first, _ForwardIter __last)
Definition: _algo.h:722
void destroy(_Tp *__pointer)
Definition: _construct.h:278
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
Arabic default style
Definition: afstyles.h:94
static int bw
Definition: maze.c:120
static int state
Definition: maze.c:121
unsigned int dir
Definition: maze.c:112
int nItems
Definition: appswitch.c:56
static const char * wine_dbgstr_point(const POINT *ppt)
Definition: atltest.h:138
static const char * wine_dbgstr_rect(const RECT *prc)
Definition: atltest.h:160
#define msg(x)
Definition: auth_time.c:54
HWND hWnd
Definition: settings.c:17
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
#define index(s, c)
Definition: various.h:29
HFONT hFont
Definition: main.c:53
#define ARRAY_SIZE(A)
Definition: main.h:33
#define FIXME(fmt,...)
Definition: precomp.h:53
#define WARN(fmt,...)
Definition: precomp.h:61
#define ERR(fmt,...)
Definition: precomp.h:57
PVOID Alloc(IN DWORD dwFlags, IN SIZE_T dwBytes)
Definition: main.c:63
PWCHAR Label
Definition: format.c:70
HBITMAP hbmp
HIMAGELIST himl
WPARAM wParam
Definition: combotst.c:138
LPARAM lParam
Definition: combotst.c:139
BOOL COMCTL32_IsReflectedMessage(UINT uMsg) DECLSPEC_HIDDEN
Definition: commctrl.c:1748
BOOL Str_SetPtrWtoA(LPSTR *lppDest, LPCWSTR lpSrc) DECLSPEC_HIDDEN
HWND COMCTL32_CreateToolTip(HWND) DECLSPEC_HIDDEN
Definition: commctrl.c:1544
VOID COMCTL32_RefreshSysColors(void) DECLSPEC_HIDDEN
Definition: commctrl.c:1586
COMCTL32_SysColor comctl32_color
Definition: commctrl.c:82
BOOL WINAPI _TrackMouseEvent(TRACKMOUSEEVENT *ptme)
Definition: commctrl.c:1207
int WINAPI DrawShadowText(HDC hdc, LPCWSTR pszText, UINT cch, RECT *prc, DWORD dwFlags, COLORREF crText, COLORREF crShadow, int ixOffset, int iyOffset)
Definition: commctrl.c:1845
int selection
Definition: ctm.c:92
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
UINT uFlags
Definition: api.c:59
BOOL WINAPI DPA_Sort(HDPA hdpa, PFNDPACOMPARE pfnCompare, LPARAM lParam)
Definition: dpa.c:813
INT WINAPI DPA_Search(HDPA hdpa, LPVOID pFind, INT nStart, PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT uOptions)
Definition: dpa.c:845
BOOL WINAPI DPA_SetPtr(HDPA hdpa, INT i, LPVOID p)
Definition: dpa.c:626
BOOL WINAPI DPA_DeleteAllPtrs(HDPA hdpa)
Definition: dpa.c:730
INT WINAPI DPA_GetPtrIndex(HDPA hdpa, LPCVOID p)
Definition: dpa.c:561
LPVOID WINAPI DPA_DeletePtr(HDPA hdpa, INT i)
Definition: dpa.c:677
BOOL WINAPI DPA_Destroy(HDPA hdpa)
Definition: dpa.c:396
HDPA WINAPI DPA_Create(INT nGrow)
Definition: dpa.c:950
INT WINAPI DPA_InsertPtr(HDPA hdpa, INT i, LPVOID p)
Definition: dpa.c:591
BOOL WINAPI ImageList_Draw(HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
Definition: imagelist.c:1228
COLORREF WINAPI ImageList_SetBkColor(HIMAGELIST himl, COLORREF clrBk)
Definition: imagelist.c:2889
INT WINAPI ImageList_Add(HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
Definition: imagelist.c:448
BOOL WINAPI ImageList_Destroy(HIMAGELIST himl)
Definition: imagelist.c:928
BOOL WINAPI ImageList_DrawEx(HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg, UINT fStyle)
Definition: imagelist.c:1264
HIMAGELIST WINAPI ImageList_Create(INT cx, INT cy, UINT flags, INT cInitial, INT cGrow)
Definition: imagelist.c:804
BOOL WINAPI ImageList_GetIconSize(HIMAGELIST himl, INT *cx, INT *cy)
Definition: imagelist.c:2037
static LRESULT LISTVIEW_Notify(LISTVIEW_INFO *infoPtr, NMHDR *lpnmhdr)
Definition: listview.c:10625
static void LISTVIEW_UpdateScroll(LISTVIEW_INFO *infoPtr)
Definition: listview.c:2172
static void LISTVIEW_SetSelection(LISTVIEW_INFO *infoPtr, INT nItem)
Definition: listview.c:3809
static void LISTVIEW_SaveTextMetrics(LISTVIEW_INFO *infoPtr)
Definition: listview.c:3146
struct tagRANGE RANGE
#define MAX_EMPTYTEXT_SELECT_WIDTH
Definition: listview.c:384
static void LISTVIEW_InvalidateSelectedItems(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:2272
notification_mask
Definition: listview.c:211
@ NOTIFY_MASK_UNMASK_ALL
Definition: listview.c:214
@ NOTIFY_MASK_ITEM_CHANGE
Definition: listview.c:212
@ NOTIFY_MASK_END_LABEL_EDIT
Definition: listview.c:213
static LRESULT LISTVIEW_LButtonUp(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y)
Definition: listview.c:10503
#define LV_FL_DT_FLAGS
Definition: listview.c:404
static BOOL is_text(LPCWSTR text)
Definition: listview.c:463
static INT LISTVIEW_FindItemW(const LISTVIEW_INFO *infoPtr, INT nStart, const LVFINDINFOW *lpFindInfo)
Definition: listview.c:6437
static int textcmpWT(LPCWSTR aw, LPCWSTR bt, BOOL isW)
Definition: listview.c:529
static LRESULT LISTVIEW_PrintClient(LISTVIEW_INFO *infoPtr, HDC hdc, DWORD options)
Definition: listview.c:10935
static DWORD LISTVIEW_MapIndexToId(const LISTVIEW_INFO *infoPtr, INT iItem)
Definition: listview.c:2706
static void map_style_view(LISTVIEW_INFO *infoPtr)
Definition: listview.c:1609
static INT LISTVIEW_GetSelectedCount(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:3565
static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, ITERATOR *subitems, POINT pos, DWORD cdmode)
Definition: listview.c:4853
static BOOL LISTVIEW_KeySelection(LISTVIEW_INFO *, INT, BOOL)
Definition: listview.c:3837
static BOOL LISTVIEW_Enable(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:9807
#define LISTVIEW_SCROLL_ICON_LINE_SIZE
Definition: listview.c:390
#define IMAGE_PADDING
Definition: listview.c:393
static void LISTVIEW_GetHeaderRect(const LISTVIEW_INFO *infoPtr, INT nSubItem, LPRECT lprc)
Definition: listview.c:1701
static BOOL LISTVIEW_DeleteItem(LISTVIEW_INFO *infoPtr, INT nItem)
Definition: listview.c:5923
struct tagRANGES * RANGES
static DWORD LISTVIEW_SetExtendedListViewStyle(LISTVIEW_INFO *infoPtr, DWORD mask, DWORD ex_style)
Definition: listview.c:8699
#define ICON_BOTTOM_PADDING
Definition: listview.c:375
#define REPORT_MARGINX
Definition: listview.c:358
static void iterator_rangeitems(ITERATOR *i, RANGE range)
Definition: listview.c:1326
static LRESULT LISTVIEW_SetFocus(LISTVIEW_INFO *infoPtr, HWND hwndLoseFocus)
Definition: listview.c:11100
static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT item, LPRECT lprc)
Definition: listview.c:7305
static VOID CALLBACK LISTVIEW_ScrollTimer(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
Definition: listview.c:4085
static BOOL LISTVIEW_SetCursor(const LISTVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
Definition: listview.c:11069
static VOID CALLBACK LISTVIEW_DelayedEditItem(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
Definition: listview.c:9614
static void textcpynT(LPWSTR dest, BOOL isDestW, LPCWSTR src, BOOL isSrcW, INT max)
Definition: listview.c:474
struct tagITEM_INFO ITEM_INFO
static INT LISTVIEW_MapIdToIndex(const LISTVIEW_INFO *infoPtr, UINT iID)
Definition: listview.c:2673
static DWORD notify_customdraw(const LISTVIEW_INFO *infoPtr, DWORD dwDrawStage, NMLVCUSTOMDRAW *lpnmlvcd)
Definition: listview.c:1052
void LISTVIEW_Unregister(void)
Definition: listview.c:12055
static RANGES ranges_diff(RANGES ranges, RANGES sub)
Definition: listview.c:3290
static LRESULT CallWindowProcT(WNDPROC proc, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL isW)
Definition: listview.c:1581
static LRESULT LISTVIEW_Create(HWND hwnd, const CREATESTRUCTW *lpcs)
Definition: listview.c:9728
static HWND CreateEditLabelT(LISTVIEW_INFO *infoPtr, LPCWSTR text, BOOL isW)
Definition: listview.c:6207
static BOOL LISTVIEW_NCPaint(const LISTVIEW_INFO *infoPtr, HRGN region)
Definition: listview.c:10797
static BOOL LISTVIEW_GetColumnOrderArray(const LISTVIEW_INFO *infoPtr, INT iCount, LPINT lpiArray)
Definition: listview.c:6662
void LISTVIEW_Register(void)
Definition: listview.c:12030
static INT LISTVIEW_ProcessLetterKeys(LISTVIEW_INFO *infoPtr, WPARAM charCode, LPARAM keyData)
Definition: listview.c:1875
static INT LISTVIEW_HitTest(const LISTVIEW_INFO *, LPLVHITTESTINFO, BOOL, BOOL)
Definition: listview.c:7757
#define ICON_TOP_PADDING_HITABLE
Definition: listview.c:373
static LPWSTR textdupTtoW(LPCWSTR text, BOOL isW)
Definition: listview.c:484
static LPCSTR debugtext_tn(LPCWSTR text, BOOL isW, INT n)
Definition: listview.c:560
static BOOL LISTVIEW_SortItems(LISTVIEW_INFO *infoPtr, PFNLVCOMPARE pfnCompare, LPARAM lParamSort, BOOL IsEx)
Definition: listview.c:9471
static void iterator_destroy(const ITERATOR *i)
Definition: listview.c:1309
static void LISTVIEW_NextIconPosLeft(LISTVIEW_INFO *infoPtr, LPPOINT lpPos)
Definition: listview.c:2769
static INT LISTVIEW_GetItemTextT(const LISTVIEW_INFO *infoPtr, INT nItem, LPLVITEMW lpLVItem, BOOL isW)
Definition: listview.c:7439
static void prepaint_setup(const LISTVIEW_INFO *infoPtr, HDC hdc, NMLVCUSTOMDRAW *lpnmlvcd, BOOL SubItem)
Definition: listview.c:1066
static INT LISTVIEW_GetColumnWidth(const LISTVIEW_INFO *infoPtr, INT nColumn)
Definition: listview.c:6680
static LRESULT notify_hdr(const LISTVIEW_INFO *infoPtr, INT code, LPNMHDR pnmh)
Definition: listview.c:832
static void LISTVIEW_InvalidateColumn(const LISTVIEW_INFO *infoPtr, INT nColumn)
Definition: listview.c:1787
static LRESULT LISTVIEW_VScroll(LISTVIEW_INFO *, INT, INT)
Definition: listview.c:9890
static LRESULT LISTVIEW_SetRedraw(LISTVIEW_INFO *infoPtr, BOOL redraw)
Definition: listview.c:11174
static BOOL LISTVIEW_SetItemCount(LISTVIEW_INFO *infoPtr, INT nItems, DWORD dwFlags)
Definition: listview.c:8988
static char * debug_getbuf(void)
Definition: listview.c:567
static BOOL LISTVIEW_SetBkColor(LISTVIEW_INFO *infoPtr, COLORREF color)
Definition: listview.c:8211
static LPCSTR debugtext_t(LPCWSTR text, BOOL isW)
Definition: listview.c:554
static BOOL is_autoarrange(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:1588
static HIMAGELIST LISTVIEW_CreateDragImage(LISTVIEW_INFO *infoPtr, INT iItem, LPPOINT lppt)
Definition: listview.c:5564
#define ranges_check(ranges, desc)
Definition: listview.c:3199
static LRESULT CALLBACK EditLblWndProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: listview.c:6173
static int textlenT(LPCWSTR text, BOOL isW)
Definition: listview.c:468
static LRESULT LISTVIEW_ThemeChanged(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:9537
static BOOL set_sub_item(const LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL isW, BOOL *bChanged)
Definition: listview.c:4499
static BOOL LISTVIEW_SetItemFocus(LISTVIEW_INFO *infoPtr, INT nItem)
Definition: listview.c:3597
#define DEBUG_BUFFERS
Definition: listview.c:341
static void LISTVIEW_UpdateHeaderSize(const LISTVIEW_INFO *infoPtr, INT nNewScrollPos)
Definition: listview.c:2015
static BOOL LISTVIEW_MoveIconTo(const LISTVIEW_INFO *infoPtr, INT nItem, const POINT *lppt, BOOL isNew)
Definition: listview.c:2837
static INT LISTVIEW_GetNextItem(const LISTVIEW_INFO *infoPtr, INT nItem, UINT uFlags)
Definition: listview.c:7463
static BOOL ranges_contain(RANGES ranges, INT nItem)
Definition: listview.c:3308
static void LISTVIEW_Refresh(LISTVIEW_INFO *infoPtr, HDC hdc, const RECT *prcErase)
Definition: listview.c:5272
#define LV_SL_DT_FLAGS
Definition: listview.c:405
static BOOL LISTVIEW_IsHeaderEnabled(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:1706
#define KEY_DELAY
Definition: listview.c:411
static LRESULT LISTVIEW_Size(LISTVIEW_INFO *infoPtr, int Width, int Height)
Definition: listview.c:11208
static DWORD LISTVIEW_SetHoverTime(LISTVIEW_INFO *infoPtr, DWORD dwHoverTime)
Definition: listview.c:8843
static BOOL LISTVIEW_SetTextBkColor(LISTVIEW_INFO *infoPtr, COLORREF color)
Definition: listview.c:9275
static LRESULT LISTVIEW_MouseWheel(LISTVIEW_INFO *infoPtr, INT wheelDelta)
Definition: listview.c:10080
static HIMAGELIST LISTVIEW_GetImageList(const LISTVIEW_INFO *infoPtr, INT nImageList)
Definition: listview.c:6752
#define LABEL_HOR_PADDING
Definition: listview.c:376
static BOOL ranges_del(RANGES ranges, RANGE range)
Definition: listview.c:3432
static INT LISTVIEW_UpdateVScroll(LISTVIEW_INFO *infoPtr)
Definition: listview.c:2110
static LRESULT LISTVIEW_ShowWindow(LISTVIEW_INFO *infoPtr, WPARAM bShown, LPARAM iStatus)
Definition: listview.c:11450
static INT LISTVIEW_StyleChanged(LISTVIEW_INFO *infoPtr, WPARAM wStyleType, const STYLESTRUCT *lpss)
Definition: listview.c:11314
static BOOL LISTVIEW_DrawTrackLine(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:9585
static void LISTVIEW_DrawItemPart(LISTVIEW_INFO *infoPtr, LVITEMW *item, const NMLVCUSTOMDRAW *nmlvcd, const POINT *pos)
Definition: listview.c:4693
static DWORD LISTVIEW_ApproximateViewRect(const LISTVIEW_INFO *infoPtr, INT nItemCount, WORD wWidth, WORD wHeight)
Definition: listview.c:5423
static BOOL LISTVIEW_FillBkgnd(const LISTVIEW_INFO *infoPtr, HDC hdc, const RECT *lprcBox)
Definition: listview.c:4683
static RANGES ranges_create(int count)
Definition: listview.c:3225
#define LISTVIEW_DUMP(iP)
Definition: listview.c:414
#define DISP_TEXT_SIZE
Definition: listview.c:349
static BOOL ranges_add(RANGES ranges, RANGE range)
Definition: listview.c:3349
static void ranges_dump(RANGES ranges)
Definition: listview.c:3300
static BOOL LISTVIEW_GetItemW(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem)
Definition: listview.c:1713
static BOOL LISTVIEW_EraseBkgnd(const LISTVIEW_INFO *infoPtr, HDC hdc)
Definition: listview.c:9826
static BOOL LISTVIEW_IsItemVisible(const LISTVIEW_INFO *infoPtr, INT nItem)
Definition: listview.c:8110
static BOOL LISTVIEW_Update(LISTVIEW_INFO *infoPtr, INT nItem)
Definition: listview.c:9557
static BOOL ranges_additem(RANGES ranges, INT nItem)
Definition: listview.c:1139
static BOOL LISTVIEW_GetItemExtT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
Definition: listview.c:7081
static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL isW)
Definition: listview.c:7932
static RANGE iterator_range(const ITERATOR *i)
Definition: listview.c:1290
static LRESULT LISTVIEW_NotifyFormat(LISTVIEW_INFO *infoPtr, HWND hwndFrom, INT nCommand)
Definition: listview.c:10851
static LRESULT LISTVIEW_NCDestroy(LISTVIEW_INFO *infoPtr)
Definition: listview.c:10573
static BOOL LISTVIEW_GetItemAtPt(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, POINT pt)
Definition: listview.c:3876
static void ranges_clear(RANGES ranges)
Definition: listview.c:3235
static BOOL LISTVIEW_GetColumnT(const LISTVIEW_INFO *infoPtr, INT nColumn, LPLVCOLUMNW lpColumn, BOOL isW)
Definition: listview.c:6612
static BOOL LISTVIEW_DeleteColumn(LISTVIEW_INFO *infoPtr, INT nColumn)
Definition: listview.c:5766
static LRESULT LISTVIEW_CancelEditLabel(LISTVIEW_INFO *infoPtr)
Definition: listview.c:5538
static LRESULT notify_listview(const LISTVIEW_INFO *infoPtr, INT code, LPNMLISTVIEW plvnm)
Definition: listview.c:888
static LRESULT EditLblWndProcT(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL isW)
Definition: listview.c:6119
static int get_ansi_notification(UINT unicodeNotificationCode)
Definition: listview.c:743
static LRESULT notify_forward_header(const LISTVIEW_INFO *infoPtr, NMHEADERW *lpnmhW)
Definition: listview.c:781
static void scroll_list(LISTVIEW_INFO *infoPtr, INT dx, INT dy)
Definition: listview.c:9860
static void LISTVIEW_RefreshReport(LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, DWORD cdmode)
Definition: listview.c:5054
static HIMAGELIST LISTVIEW_CreateCheckBoxIL(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:8646
static const char * debugnmlistview(const NMLISTVIEW *plvnm)
Definition: listview.c:617
static void column_fill_hditem(const LISTVIEW_INFO *infoPtr, HDITEMW *lphdi, INT nColumn, const LVCOLUMNW *lpColumn, BOOL isW)
Definition: listview.c:8236
static HIMAGELIST LISTVIEW_SetImageList(LISTVIEW_INFO *, INT, HIMAGELIST)
Definition: listview.c:8931
static BOOL LISTVIEW_Arrange(LISTVIEW_INFO *infoPtr, INT nAlignCode)
Definition: listview.c:2872
static BOOL is_redrawing(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:1743
static void LISTVIEW_GetItemMetrics(const LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, LPRECT lprcBox, LPRECT lprcSelectBox, LPRECT lprcIcon, LPRECT lprcStateIcon, LPRECT lprcLabel)
Definition: listview.c:2374
static INT LISTVIEW_SetView(LISTVIEW_INFO *infoPtr, DWORD nView)
Definition: listview.c:9349
static HCURSOR LISTVIEW_SetHotCursor(LISTVIEW_INFO *infoPtr, HCURSOR hCursor)
Definition: listview.c:8800
static BOOL ranges_shift(RANGES ranges, INT nItem, INT delta, INT nUpper)
Definition: listview.c:3330
static void textfreeT(LPWSTR wstr, BOOL isW)
Definition: listview.c:498
static BOOL LISTVIEW_SetItemT(LISTVIEW_INFO *infoPtr, LVITEMW *lpLVItem, BOOL isW)
Definition: listview.c:4574
static void iterator_empty(ITERATOR *i)
Definition: listview.c:1317
static LRESULT LISTVIEW_GetVersion(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:11474
static BOOL LISTVIEW_DrawFocusRect(const LISTVIEW_INFO *infoPtr, HDC hdc)
Definition: listview.c:1719
static void iterator_rangesitems(ITERATOR *i, RANGES ranges)
Definition: listview.c:1337
static LPCSTR debugscrollcode(int nScrollCode)
Definition: listview.c:724
static void LISTVIEW_ShowFocusRect(const LISTVIEW_INFO *infoPtr, BOOL fShow)
Definition: listview.c:2210
static INT LISTVIEW_CalculateItemWidth(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:3037
static LRESULT LISTVIEW_WMPaint(LISTVIEW_INFO *infoPtr, HDC hdc)
Definition: listview.c:10913
static INT CALLBACK ranges_cmp(LPVOID range1, LPVOID range2, LPARAM flags)
Definition: listview.c:3183
static void ranges_destroy(RANGES ranges)
Definition: listview.c:3245
static BOOL notify_deleteitem(const LISTVIEW_INFO *infoPtr, INT nItem)
Definition: listview.c:915
static BOOL LISTVIEW_EndEditLabelT(LISTVIEW_INFO *, BOOL, BOOL)
Definition: listview.c:6000
static LRESULT LISTVIEW_RButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y)
Definition: listview.c:10995
static BOOL LISTVIEW_DeselectAllSkipItems(LISTVIEW_INFO *infoPtr, RANGES toSkip)
Definition: listview.c:3517
static BOOL LISTVIEW_DeselectAll(LISTVIEW_INFO *infoPtr)
Definition: listview.c:3550
#define LV_ML_DT_FLAGS
Definition: listview.c:403
static LRESULT LISTVIEW_Paint(LISTVIEW_INFO *infoPtr, HDC hdc)
Definition: listview.c:10872
static BOOL notify_measureitem(LISTVIEW_INFO *infoPtr)
Definition: listview.c:1113
static LRESULT LISTVIEW_Destroy(LISTVIEW_INFO *infoPtr)
Definition: listview.c:9784
static LRESULT LISTVIEW_LButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y)
Definition: listview.c:10379
static COLUMN_INFO * LISTVIEW_GetColumnInfo(const LISTVIEW_INFO *infoPtr, INT nSubItem)
Definition: listview.c:1642
static void LISTVIEW_InvalidateItem(const LISTVIEW_INFO *infoPtr, INT nItem)
Definition: listview.c:1755
static BOOL textsetptrT(LPWSTR *dest, LPCWSTR src, BOOL isW)
Definition: listview.c:507
static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, INT y)
Definition: listview.c:4144
static BOOL notify_click(const LISTVIEW_INFO *infoPtr, INT code, const LVHITTESTINFO *lvht)
Definition: listview.c:895
static LRESULT LISTVIEW_MouseHover(LISTVIEW_INFO *infoPtr, INT x, INT y)
Definition: listview.c:3918
static DWORD LISTVIEW_SetIconSpacing(LISTVIEW_INFO *infoPtr, INT cx, INT cy)
Definition: listview.c:8864
static void LISTVIEW_MarqueeHighlight(LISTVIEW_INFO *infoPtr, const POINT *coords_orig, INT scroll)
Definition: listview.c:3960
static void LISTVIEW_RefreshOwnerDraw(const LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, DWORD cdmode)
Definition: listview.c:4980
static const WCHAR themeClass[]
Definition: listview.c:427
static const char * debugrange(const RANGE *lprng)
Definition: listview.c:574
#define TRAILING_HEADER_PADDING
Definition: listview.c:397
static BOOL iterator_frameditems(ITERATOR *i, const LISTVIEW_INFO *infoPtr, const RECT *lprc)
Definition: listview.c:1446
static const char * debuglvitem_t(const LVITEMW *lpLVItem, BOOL isW)
Definition: listview.c:626
static BOOL LISTVIEW_SetColumnT(const LISTVIEW_INFO *infoPtr, INT nColumn, const LVCOLUMNW *lpColumn, BOOL isW)
Definition: listview.c:8444
static const char * debugscrollinfo(const SCROLLINFO *pScrollInfo)
Definition: listview.c:580
static BOOL iterator_next(ITERATOR *i)
Definition: listview.c:1214
static LRESULT LISTVIEW_KillFocus(LISTVIEW_INFO *infoPtr)
Definition: listview.c:10241
#define ICON_TOP_PADDING
Definition: listview.c:374
static BOOL set_main_item(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL isNew, BOOL isW, BOOL *bChanged)
Definition: listview.c:4314
static void LISTVIEW_NextIconPosTop(LISTVIEW_INFO *infoPtr, LPPOINT lpPos)
Definition: listview.c:2738
#define SB_INTERNAL
Definition: listview.c:346
static BOOL LISTVIEW_GetItemRect(const LISTVIEW_INFO *, INT, LPRECT)
Definition: listview.c:7204
static BOOL LISTVIEW_SetItemState(LISTVIEW_INFO *, INT, const LVITEMW *)
Definition: listview.c:9142
static INT WINAPI LISTVIEW_CallBackCompare(LPVOID first, LPVOID second, LPARAM lParam)
Definition: listview.c:9423
static BOOL LISTVIEW_RedrawItems(const LISTVIEW_INFO *infoPtr, INT nFirst, INT nLast)
Definition: listview.c:8149
static const char * debuglvcolumn_t(const LVCOLUMNW *lpColumn, BOOL isW)
Definition: listview.c:668
static RANGES ranges_clone(RANGES ranges)
Definition: listview.c:3253
static int lstrncmpiW(LPCWSTR s1, LPCWSTR s2, int n)
Definition: listview.c:546
static DWORD notify_postpaint(const LISTVIEW_INFO *infoPtr, NMLVCUSTOMDRAW *lpnmlvcd)
Definition: listview.c:1107
#define WIDTH_PADDING
Definition: listview.c:352
static BOOL LISTVIEW_SetColumnOrderArray(LISTVIEW_INFO *infoPtr, INT iCount, const INT *lpiArray)
Definition: listview.c:8499
static INT LISTVIEW_SetSelectionMark(LISTVIEW_INFO *infoPtr, INT nIndex)
Definition: listview.c:9251
static BOOL LISTVIEW_SetUnicodeFormat(LISTVIEW_INFO *infoPtr, BOOL unicode)
Definition: listview.c:9331
static INT LISTVIEW_SetHotItem(LISTVIEW_INFO *infoPtr, INT iIndex)
Definition: listview.c:8822
static BOOL LISTVIEW_GetViewRect(const LISTVIEW_INFO *, LPRECT)
Definition: listview.c:2977
static BOOL LISTVIEW_SetItemPosition(LISTVIEW_INFO *infoPtr, INT nItem, const POINT *pt)
Definition: listview.c:9086
static void LISTVIEW_ShiftFocus(LISTVIEW_INFO *infoPtr, INT focus, INT item, INT direction)
Definition: listview.c:3629
static LRESULT LISTVIEW_KeyDown(LISTVIEW_INFO *infoPtr, INT nVirtualKey, LONG lKeyData)
Definition: listview.c:10136
static BOOL iterator_remove_common_items(ITERATOR *iter1, ITERATOR *iter2)
Definition: listview.c:1517
static BOOL LISTVIEW_SetItemTextT(LISTVIEW_INFO *infoPtr, INT nItem, const LVITEMW *lpLVItem, BOOL isW)
Definition: listview.c:9222
#define DEFAULT_COLUMN_WIDTH
Definition: listview.c:387
static LRESULT LISTVIEW_TrackMouse(const LISTVIEW_INFO *infoPtr, POINT pt)
Definition: listview.c:10321
static BOOL LISTVIEW_DeselectAllSkipItem(LISTVIEW_INFO *infoPtr, INT nItem)
Definition: listview.c:3539
static void LISTVIEW_GetOrigin(const LISTVIEW_INFO *, LPPOINT)
Definition: listview.c:7676
static BOOL notify_dispinfoT(const LISTVIEW_INFO *infoPtr, UINT code, LPNMLVDISPINFOW pdi, BOOL isW)
Definition: listview.c:939
#define HEIGHT_PADDING
Definition: listview.c:355
struct tagITEMHDR ITEMHDR
static INT LISTVIEW_InsertColumnT(LISTVIEW_INFO *infoPtr, INT nColumn, const LVCOLUMNW *lpColumn, BOOL isW)
Definition: listview.c:8326
static UINT LISTVIEW_GetItemState(const LISTVIEW_INFO *, INT, UINT)
Definition: listview.c:7410
static INT LISTVIEW_GetStringWidthT(const LISTVIEW_INFO *, LPCWSTR, BOOL)
Definition: listview.c:7717
static LRESULT LISTVIEW_HScroll(LISTVIEW_INFO *, INT, INT)
Definition: listview.c:9994
static void LISTVIEW_InvalidateSubItem(const LISTVIEW_INFO *infoPtr, INT nItem, INT nSubItem)
Definition: listview.c:1766
#define SCROLL_DOWN
Definition: listview.c:3944
static INT WINAPI LISTVIEW_CallBackCompareEx(LPVOID first, LPVOID second, LPARAM lParam)
Definition: listview.c:9447
static INT LISTVIEW_GetCountPerColumn(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:1826
static void set_icon_size(SIZE *size, HIMAGELIST himl, BOOL is_small)
Definition: listview.c:8902
static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *, LPLVITEMW, BOOL)
Definition: listview.c:6797
static BOOL LISTVIEW_IsHotTracking(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:3893
static void LISTVIEW_GetAreaRect(const LISTVIEW_INFO *infoPtr, LPRECT lprcView)
Definition: listview.c:2931
static void LISTVIEW_RefreshReportGrid(LISTVIEW_INFO *infoPtr, HDC hdc)
Definition: listview.c:5137
struct tagDELAYED_ITEM_EDIT DELAYED_ITEM_EDIT
static void LISTVIEW_SetGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem)
Definition: listview.c:3726
static LONG LISTVIEW_GetItemSpacing(const LISTVIEW_INFO *infoPtr, BOOL bSmall)
Definition: listview.c:7380
#define SCROLL_LEFT
Definition: listview.c:3941
static BOOL LISTVIEW_GetItemPosition(const LISTVIEW_INFO *, INT, LPPOINT)
Definition: listview.c:7119
struct tagITERATOR ITERATOR
static INT CALLBACK MapIdSearchCompare(LPVOID p1, LPVOID p2, LPARAM lParam)
Definition: listview.c:2652
static void LISTVIEW_UpdateItemSize(LISTVIEW_INFO *infoPtr)
Definition: listview.c:3130
static INT LISTVIEW_GetTopIndex(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:4640
static LRESULT LISTVIEW_SetVersion(LISTVIEW_INFO *infoPtr, DWORD iVersion)
Definition: listview.c:11491
static BOOL iterator_frameditems_absolute(ITERATOR *i, const LISTVIEW_INFO *infoPtr, const RECT *frame)
Definition: listview.c:1347
static DWORD get_next_itemid(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:1628
static BOOL LISTVIEW_Scroll(LISTVIEW_INFO *, INT, INT)
Definition: listview.c:8179
static BOOL ranges_delitem(RANGES ranges, INT nItem)
Definition: listview.c:1146
#define TRAILING_LABEL_PADDING
Definition: listview.c:396
static void notify_itemactivate(const LISTVIEW_INFO *infoPtr, const LVHITTESTINFO *htInfo)
Definition: listview.c:856
static void LISTVIEW_ShiftIndices(LISTVIEW_INFO *infoPtr, INT nItem, INT direction)
Definition: listview.c:3652
static BOOL is_assignable_item(const LVITEMW *lpLVItem, LONG lStyle)
Definition: listview.c:4289
static void toggle_checkbox_state(LISTVIEW_INFO *infoPtr, INT nItem)
Definition: listview.c:1594
static INT LISTVIEW_GetCountPerRow(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:1808
static void LISTVIEW_GetItemOrigin(const LISTVIEW_INFO *, INT, LPPOINT)
Definition: listview.c:2307
static LRESULT LISTVIEW_SetFont(LISTVIEW_INFO *infoPtr, HFONT hFont, WORD fRedraw)
Definition: listview.c:11134
static INT LISTVIEW_CreateHeader(LISTVIEW_INFO *infoPtr)
Definition: listview.c:1666
static BOOL LISTVIEW_SetColumnWidth(LISTVIEW_INFO *infoPtr, INT nColumn, INT cx)
Definition: listview.c:8519
static INT LISTVIEW_StyleChanging(WPARAM wStyleType, STYLESTRUCT *lpss)
Definition: listview.c:11420
static HWND LISTVIEW_SetToolTips(LISTVIEW_INFO *infoPtr, HWND hwndNewToolTip)
Definition: listview.c:9314
static void LISTVIEW_RefreshList(LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, DWORD cdmode)
Definition: listview.c:5241
static void LISTVIEW_InvalidateList(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:1782
static LRESULT LISTVIEW_Command(LISTVIEW_INFO *, WPARAM, LPARAM)
Definition: listview.c:12072
static BOOL LISTVIEW_SetTextColor(LISTVIEW_INFO *infoPtr, COLORREF color)
Definition: listview.c:9295
#define DEBUG_BUFFER_SIZE
Definition: listview.c:343
static void LISTVIEW_ScrollColumns(LISTVIEW_INFO *infoPtr, INT nColumn, INT dx)
Definition: listview.c:5708
#define SCROLL_RIGHT
Definition: listview.c:3942
static void LISTVIEW_InvalidateRect(const LISTVIEW_INFO *infoPtr, const RECT *rect)
Definition: listview.c:1748
static LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: listview.c:11511
struct tagITEMHDR * LPITEMHDR
static HWND LISTVIEW_EditLabelT(LISTVIEW_INFO *infoPtr, INT nItem, BOOL isW)
Definition: listview.c:6246
static INT LISTVIEW_FindItemA(const LISTVIEW_INFO *infoPtr, INT nStart, const LVFINDINFOA *lpFindInfo)
Definition: listview.c:6582
struct tagLISTVIEW_INFO LISTVIEW_INFO
static INT LISTVIEW_GetCountPerPage(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:6724
static LRESULT LISTVIEW_RButtonDblClk(const LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y)
Definition: listview.c:10965
static void ranges_assert(RANGES ranges, LPCSTR desc, const char *file, int line)
Definition: listview.c:3201
static BOOL LISTVIEW_AddGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem)
Definition: listview.c:3674
static void LISTVIEW_GetItemBox(const LISTVIEW_INFO *, INT, LPRECT)
Definition: listview.c:2616
static BOOL iterator_visibleitems(ITERATOR *i, const LISTVIEW_INFO *infoPtr, HDC hdc)
Definition: listview.c:1462
static BOOL LISTVIEW_EnsureVisible(LISTVIEW_INFO *, INT, BOOL)
Definition: listview.c:6350
#define SCROLL_UP
Definition: listview.c:3943
static INT ranges_itemcount(RANGES ranges)
Definition: listview.c:3317
static void LISTVIEW_UpdateSize(LISTVIEW_INFO *)
Definition: listview.c:11244
static LRESULT LISTVIEW_LButtonDblClk(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y)
Definition: listview.c:10292
static BOOL iterator_prev(ITERATOR *i)
Definition: listview.c:1254
static void customdraw_fill(NMLVCUSTOMDRAW *lpnmlvcd, const LISTVIEW_INFO *infoPtr, HDC hdc, const RECT *rcBounds, const LVITEMW *lplvItem)
Definition: listview.c:1035
static void LISTVIEW_ScrollOnInsert(LISTVIEW_INFO *infoPtr, INT nItem, INT dir)
Definition: listview.c:5851
static INT shift_item(const LISTVIEW_INFO *infoPtr, INT nShiftItem, INT nItem, INT direction)
Definition: listview.c:3611
static const char * debuglvhittestinfo(const LVHITTESTINFO *lpht)
Definition: listview.c:715
static INT LISTVIEW_CalculateItemHeight(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:3097
static INT LISTVIEW_UpdateHScroll(LISTVIEW_INFO *infoPtr)
Definition: listview.c:2040
#define STATEIMAGEINDEX(x)
Definition: listview.c:408
struct tagCOLUMN_INFO COLUMN_INFO
static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, const CREATESTRUCTW *lpcs)
Definition: listview.c:9638
static BOOL LISTVIEW_DeleteAllItems(LISTVIEW_INFO *infoPtr, BOOL destroy)
Definition: listview.c:5629
static LRESULT CALLBACK EditLblWndProcA(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: listview.c:6190
struct tagSUBITEM_INFO SUBITEM_INFO
static SUBITEM_INFO * LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems, INT nSubItem)
Definition: listview.c:3010
#define COMCTL32_VERSION
Definition: resource.h:72
BOOL WINAPI Str_SetPtrW(LPWSTR *lppDest, LPCWSTR lpSrc)
Definition: string.c:236
const char * wine_dbg_sprintf(const char *format,...)
Definition: compat.c:296
#define CP_ACP
Definition: compat.h:109
#define lstrcpynA
Definition: compat.h:751
static __inline const char * debugstr_an(const char *s, int n)
Definition: compat.h:55
#define MAX_PATH
Definition: compat.h:34
#define CALLBACK
Definition: compat.h:35
#define lstrcpyW
Definition: compat.h:749
#define WideCharToMultiByte
Definition: compat.h:111
#define MultiByteToWideChar
Definition: compat.h:110
#define lstrcpynW
Definition: compat.h:738
#define lstrlenW
Definition: compat.h:750
static void cleanup(void)
Definition: main.c:1335
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:455
int WINAPI lstrcmpW(LPCWSTR str1, LPCWSTR str2)
Definition: locale.c:4242
INT WINAPI CompareStringW(LCID lcid, DWORD flags, LPCWSTR str1, INT len1, LPCWSTR str2, INT len2)
Definition: locale.c:4013
const WCHAR * text
Definition: package.c:1799
HRESULT WINAPI DrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect)
Definition: draw.c:128
BOOL WINAPI IsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId, int iStateId)
Definition: draw.c:1883
HRESULT WINAPI DrawThemeParentBackground(HWND hwnd, HDC hdc, RECT *prc)
Definition: draw.c:72
HTHEME WINAPI OpenThemeData(HWND hwnd, LPCWSTR classlist)
Definition: system.c:835
HTHEME WINAPI GetWindowTheme(HWND hwnd)
Definition: system.c:851
HRESULT WINAPI CloseThemeData(HTHEME hTheme)
Definition: system.c:950
unsigned short(__cdecl typeof(TIFFCurrentDirectory))(struct tiff *)
Definition: typeof.h:94
INT WSAAPI select(IN INT s, IN OUT LPFD_SET readfds, IN OUT LPFD_SET writefds, IN OUT LPFD_SET exceptfds, IN CONST struct timeval *timeout)
Definition: select.c:41
#define assert(x)
Definition: debug.h:53
#define pt(x, y)
Definition: drawing.c:79
static VOID BitBlt(_In_ ULONG Left, _In_ ULONG Top, _In_ ULONG Width, _In_ ULONG Height, _In_reads_bytes_(Delta *Height) PUCHAR Buffer, _In_ ULONG BitsPerPixel, _In_ ULONG Delta)
Definition: common.c:57
#define RGB(r, g, b)
Definition: precomp.h:71
HINSTANCE hInst
Definition: dxdiag.c:13
POINTL point
Definition: edittest.c:50
static INT cxMin
Definition: eventvwr.c:4312
#define WM_APP
Definition: eventvwr.h:73
#define abs(i)
Definition: fconv.c:206
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
unsigned short WORD
Definition: ntddk_ex.h:93
_Must_inspect_result_ _In_ PFSRTL_PER_STREAM_CONTEXT Ptr
Definition: fsrtlfuncs.h:898
pKey DeleteObject()
GLuint start
Definition: gl.h:1545
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
GLuint GLuint end
Definition: gl.h:1545
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLsizeiptr size
Definition: glext.h:5919
GLdouble n
Definition: glext.h:7729
GLuint res
Definition: glext.h:9613
GLenum src
Definition: glext.h:6340
GLuint buffer
Definition: glext.h:5915
GLuint color
Definition: glext.h:6243
GLuint coords
Definition: glext.h:7368
GLuint index
Definition: glext.h:6031
GLenum GLint GLuint mask
Definition: glext.h:6028
GLdouble GLdouble right
Definition: glext.h:10859
GLenum GLint * range
Definition: glext.h:7539
GLenum mode
Definition: glext.h:6217
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glext.h:7005
GLbitfield flags
Definition: glext.h:7161
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
const GLint * first
Definition: glext.h:5794
GLfloat GLfloat p
Definition: glext.h:8902
GLenum GLsizei len
Definition: glext.h:6722
const GLuint * buffers
Definition: glext.h:5916
GLuint64EXT * result
Definition: glext.h:11304
GLintptr offset
Definition: glext.h:5920
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
static const struct newhuff ht[]
Definition: huffman.h:296
#define iswalnum(_c)
Definition: ctype.h:671
_CONST_RETURN wchar_t *__cdecl wcsstr(_In_z_ const wchar_t *_Str, _In_z_ const wchar_t *_SubStr)
voidpf uLong int origin
Definition: ioapi.h:144
char hdr[14]
Definition: iptest.cpp:33
boolean suppress
Definition: jpeglib.h:1006
#define debugstr_a
Definition: kernel32.h:31
#define debugstr_wn
Definition: kernel32.h:33
#define debugstr_w
Definition: kernel32.h:32
GLint dy
Definition: linetemp.h:97
if(dx< 0)
Definition: linetemp.h:194
GLint dx
Definition: linetemp.h:97
int WINAPI lstrlenA(LPCSTR lpString)
Definition: lstring.c:145
static const WCHAR dc[]
struct S1 s1
struct S2 s2
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
BITMAP bmp
Definition: alphablend.c:62
HDC hdc
Definition: main.c:9
static HBITMAP
Definition: button.c:44
static HINSTANCE hinst
Definition: edit.c:551
static HDC
Definition: imagelist.c:92
static const WCHAR textW[]
Definition: itemdlg.c:1559
static const WCHAR desc[]
Definition: protectdata.c:36
static BOOL CALLBACK callbackW(PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W_DATA data, LPVOID context)
Definition: propset.c:144
static DWORD *static HFONT(WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDVA *)
#define cmp(status, error)
Definition: error.c:114
static char * dest
Definition: rtl.c:135
WCHAR strW[12]
Definition: clipboard.c:2029
static ATOM item
Definition: dde.c:856
static HTHEME(WINAPI *pOpenThemeDataEx)(HWND
#define min(a, b)
Definition: monoChain.cc:55
int k
Definition: mpi.c:3369
int notify
Definition: msacm.c:1366
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
unsigned int UINT
Definition: ndis.h:50
_In_ PUNICODE_STRING _Inout_ PUNICODE_STRING Destination
Definition: rtlfuncs.h:3016
#define LOCALE_USER_DEFAULT
INT WINAPI DrawTextW(HDC hdc, LPCWSTR str, INT count, LPRECT rect, UINT flags)
Definition: defwnd.c:16
static HANDLE proc()
Definition: pdb.c:34
#define LOWORD(l)
Definition: pedump.c:82
#define WS_CHILD
Definition: pedump.c:617
#define WS_BORDER
Definition: pedump.c:625
#define WS_VSCROLL
Definition: pedump.c:627
#define ES_AUTOHSCROLL
Definition: pedump.c:672
#define WS_VISIBLE
Definition: pedump.c:620
short SHORT
Definition: pedump.c:59
long LONG
Definition: pedump.c:60
#define WS_CHILDWINDOW
Definition: pedump.c:639
#define ES_LEFT
Definition: pedump.c:664
#define WS_CLIPSIBLINGS
Definition: pedump.c:618
#define WS_HSCROLL
Definition: pedump.c:628
#define INT
Definition: polytest.cpp:20
#define LVIR_ICON
Definition: commctrl.h:2473
#define NM_RELEASEDCAPTURE
Definition: commctrl.h:141
#define CDDS_ITEMPOSTPAINT
Definition: commctrl.h:286
#define LVM_GETCALLBACKMASK
Definition: commctrl.h:2416
#define LVM_DELETEALLITEMS
Definition: commctrl.h:2413
#define LVM_CREATEDRAGIMAGE
Definition: commctrl.h:2652
#define LVCF_ORDER
Definition: commctrl.h:2591
#define LV_VIEW_DETAILS
Definition: commctrl.h:2841
#define LVIS_OVERLAYMASK
Definition: commctrl.h:2325
#define LVSIL_SMALL
Definition: commctrl.h:2299
#define I_IMAGECALLBACK
Definition: commctrl.h:2385
#define LVM_GETITEMA
Definition: commctrl.h:2389
#define NM_RDBLCLK
Definition: commctrl.h:134
#define LVM_ARRANGE
Definition: commctrl.h:2532
#define LVN_GETDISPINFOA
Definition: commctrl.h:3153
_Out_opt_ int _Out_opt_ int * cy
Definition: commctrl.h:586
#define HDM_SETORDERARRAY
Definition: commctrl.h:809
#define HDS_BUTTONS
Definition: commctrl.h:629
#define LVS_EX_ONECLICKACTIVATE
Definition: commctrl.h:2735
#define HDS_HIDDEN
Definition: commctrl.h:631
#define LVCFMT_IMAGE
Definition: commctrl.h:2602
#define LVM_SETITEMTEXTW
Definition: commctrl.h:2687
#define CDDS_ITEM
Definition: commctrl.h:284
#define HDF_LEFT
Definition: commctrl.h:713
#define LVM_SETHOVERTIME
Definition: commctrl.h:2792
#define ILD_NORMAL
Definition: commctrl.h:417
#define LVN_ODFINDITEMW
Definition: commctrl.h:3145
#define LVS_SINGLESEL
Definition: commctrl.h:2266
#define LVM_SETCOLUMNW
Definition: commctrl.h:2625
#define TME_LEAVE
Definition: commctrl.h:4981
#define HDN_LAST
Definition: commctrl.h:206
#define LVM_SETTEXTCOLOR
Definition: commctrl.h:2658
#define LVCFMT_COL_HAS_IMAGES
Definition: commctrl.h:2604
#define LVS_ICON
Definition: commctrl.h:2261
#define HDI_TEXT
Definition: commctrl.h:704
#define LVFI_STRING
Definition: commctrl.h:2437
#define LVS_SHAREIMAGELISTS
Definition: commctrl.h:2270
#define LVM_INSERTCOLUMNA
Definition: commctrl.h:2631
#define LVM_GETITEMCOUNT
Definition: commctrl.h:2306
#define LVN_BEGINRDRAG
Definition: commctrl.h:3141
#define LVM_GETITEMSTATE
Definition: commctrl.h:2675
#define LVN_COLUMNCLICK
Definition: commctrl.h:3139
#define CDDS_ITEMPREPAINT
Definition: commctrl.h:285
#define LVIF_NORECOMPUTE
Definition: commctrl.h:2314
#define LVIS_ACTIVATING
Definition: commctrl.h:2323
#define LVS_NOCOLUMNHEADER
Definition: commctrl.h:2284
#define NM_DBLCLK
Definition: commctrl.h:131
#define LVFI_SUBSTRING
Definition: commctrl.h:2438
#define LVM_GETCOLUMNORDERARRAY
Definition: commctrl.h:2768
#define LVM_GETHEADER
Definition: commctrl.h:2650
#define LVCFMT_CENTER
Definition: commctrl.h:2600
#define HDF_CENTER
Definition: commctrl.h:715
#define LVM_GETTOPINDEX
Definition: commctrl.h:2664
#define LVM_GETITEMSPACING
Definition: commctrl.h:2711
#define HDN_ITEMCHANGEDW
Definition: commctrl.h:840
#define LPSTR_TEXTCALLBACKW
Definition: commctrl.h:2380
#define LVM_SETCOLUMNA
Definition: commctrl.h:2624
#define HDM_GETBITMAPMARGIN
Definition: commctrl.h:818
#define LVM_SETCOLUMNWIDTH
Definition: commctrl.h:2646
#define LVM_SETBKCOLOR
Definition: commctrl.h:2293
#define LVFI_WRAP
Definition: commctrl.h:2440
#define LVIF_STATE
Definition: commctrl.h:2312
#define LVS_EX_GRIDLINES
Definition: commctrl.h:2729
#define LVCF_IMAGE
Definition: commctrl.h:2590
#define LVS_EX_SNAPTOGRID
Definition: commctrl.h:2748
#define LVS_OWNERDATA
Definition: commctrl.h:2274
#define WC_LISTVIEWW
Definition: commctrl.h:2257
#define HOVER_DEFAULT
Definition: commctrl.h:4986
#define HDM_SETITEMA
Definition: commctrl.h:753
#define LVKF_CONTROL
Definition: commctrl.h:3056
#define CDDS_SUBITEM
Definition: commctrl.h:289
#define HDM_SETUNICODEFORMAT
Definition: commctrl.h:821
#define LVHT_BELOW
Definition: commctrl.h:2500
#define CDRF_NOTIFYSUBITEMDRAW
Definition: commctrl.h:276
#define LVS_EX_TWOCLICKACTIVATE
Definition: commctrl.h:2736
#define LVS_TYPEMASK
Definition: commctrl.h:2265
#define LVS_OWNERDRAWFIXED
Definition: commctrl.h:2283
#define LVNI_SELECTED
Definition: commctrl.h:2424
#define WC_EDITW
Definition: commctrl.h:4687
#define LVM_GETITEMPOSITION
Definition: commctrl.h:2483
#define HDF_RIGHT
Definition: commctrl.h:714
#define LVIF_COLUMNS
Definition: commctrl.h:2316
#define LVN_GETINFOTIPA
Definition: commctrl.h:3222
#define HDFT_ISSTRING
Definition: commctrl.h:642
#define LVM_SETITEMSTATE
Definition: commctrl.h:2672
#define LVHT_ONITEM
Definition: commctrl.h:2497
#define LVS_EX_HEADERDRAGDROP
Definition: commctrl.h:2733
#define LVKF_SHIFT
Definition: commctrl.h:3057
#define CLR_NONE
Definition: commctrl.h:319
#define LVHT_TOLEFT
Definition: commctrl.h:2502
#define CCM_GETVERSION
Definition: commctrl.h:115
#define LVFI_PARAM
Definition: commctrl.h:2436
#define LVNI_TOLEFT
Definition: commctrl.h:2430
#define LVM_EDITLABELW
Definition: commctrl.h:2536
#define LVN_SETDISPINFOW
Definition: commctrl.h:3156
#define HDM_INSERTITEMA
Definition: commctrl.h:736
#define HDS_FULLDRAG
Definition: commctrl.h:633
#define LVN_ODSTATECHANGED
Definition: commctrl.h:3148
#define CDRF_NOTIFYITEMDRAW
Definition: commctrl.h:275
#define LVM_GETHOTITEM
Definition: commctrl.h:2772
#define LVS_SHOWSELALWAYS
Definition: commctrl.h:2267
#define LVM_DELETECOLUMN
Definition: commctrl.h:2638
#define LVS_REPORT
Definition: commctrl.h:2262
#define LVM_SETITEMPOSITION
Definition: commctrl.h:2480
#define LVS_SMALLICON
Definition: commctrl.h:2263
#define HDM_LAYOUT
Definition: commctrl.h:767
#define LVM_FINDITEMW
Definition: commctrl.h:2466
#define LVN_GETINFOTIPW
Definition: commctrl.h:3223
#define LVN_DELETEALLITEMS
Definition: commctrl.h:3134
#define LVM_SETCALLBACKMASK
Definition: commctrl.h:2419
#define LVM_SETUNICODEFORMAT
Definition: commctrl.h:2287
#define LVA_DEFAULT
Definition: commctrl.h:2527
#define LVM_GETEDITCONTROL
Definition: commctrl.h:2542
#define LVM_EDITLABELA
Definition: commctrl.h:2535
#define LVM_GETNUMBEROFWORKAREAS
Definition: commctrl.h:2786
#define LVM_UPDATE
Definition: commctrl.h:2670
#define WC_EDITA
Definition: commctrl.h:4686
#define CDRF_DODEFAULT
Definition: commctrl.h:268
#define LVM_REDRAWITEMS
Definition: commctrl.h:2524
struct _IMAGELIST * HIMAGELIST
Definition: commctrl.h:324
#define LVCF_WIDTH
Definition: commctrl.h:2587
#define LVM_GETCOLUMNA
Definition: commctrl.h:2617
#define LVM_APPROXIMATEVIEWRECT
Definition: commctrl.h:2778
#define LVM_GETHOVERTIME
Definition: commctrl.h:2794
#define LVNI_TORIGHT
Definition: commctrl.h:2431
#define LVA_ALIGNLEFT
Definition: commctrl.h:2528
#define HDF_IMAGE
Definition: commctrl.h:723
#define LVNI_FOCUSED
Definition: commctrl.h:2423
#define LVM_GETSTRINGWIDTHA
Definition: commctrl.h:2486
#define LVNI_BELOW
Definition: commctrl.h:2429
#define LVM_SETIMAGELIST
Definition: commctrl.h:2303
_Out_opt_ int * cx
Definition: commctrl.h:585
#define LVA_ALIGNTOP
Definition: commctrl.h:2529
#define LVCFMT_BITMAP_ON_RIGHT
Definition: commctrl.h:2603
#define LVIF_INDENT
Definition: commctrl.h:2313
#define HDN_BEGINDRAG
Definition: commctrl.h:855
#define LVN_INSERTITEM
Definition: commctrl.h:3132
#define ODT_LISTVIEW
Definition: commctrl.h:80
#define HDM_GETITEMA
Definition: commctrl.h:746
#define LVM_SETITEMW
Definition: commctrl.h:2397
#define LVS_NOSCROLL
Definition: commctrl.h:2275
#define LVM_SETTOOLTIPS
Definition: commctrl.h:2796
#define CDIS_SELECTED
Definition: commctrl.h:291
#define HDI_WIDTH
Definition: commctrl.h:702
#define NM_HOVER
Definition: commctrl.h:138
#define LVN_ITEMCHANGING
Definition: commctrl.h:3130
#define CDRF_NOTIFYPOSTPAINT
Definition: commctrl.h:274
#define HDI_BITMAP
Definition: commctrl.h:707
#define HDN_ENDTRACKW
Definition: commctrl.h:850
#define LVM_GETVIEWRECT
Definition: commctrl.h:2654
#define LVM_GETNEXTITEM
Definition: commctrl.h:2433
#define LV_VIEW_LIST
Definition: commctrl.h:2843
#define LVS_EX_CHECKBOXES
Definition: commctrl.h:2731
#define LVHT_TORIGHT
Definition: commctrl.h:2501
#define LVN_ODCACHEHINT
Definition: commctrl.h:3143
#define LVFI_PARTIAL
Definition: commctrl.h:2439
#define NM_CLICK
Definition: commctrl.h:130
#define LVM_MAPIDTOINDEX
Definition: commctrl.h:3016
#define LVN_BEGINDRAG
Definition: commctrl.h:3140
#define LVM_MAPINDEXTOID
Definition: commctrl.h:3014
#define LVS_EX_FULLROWSELECT
Definition: commctrl.h:2734
#define NM_KILLFOCUS
Definition: commctrl.h:136
#define LVS_SORTASCENDING
Definition: commctrl.h:2268
#define LVM_GETSUBITEMRECT
Definition: commctrl.h:2762
#define LV_VIEW_TILE
Definition: commctrl.h:2844
#define LVM_ENSUREVISIBLE
Definition: commctrl.h:2518
#define LVS_EX_TRACKSELECT
Definition: commctrl.h:2732
#define LVM_GETTOOLTIPS
Definition: commctrl.h:2798
#define LVS_SORTDESCENDING
Definition: commctrl.h:2269
#define LVM_GETWORKAREAS
Definition: commctrl.h:2784
#define HDS_DRAGDROP
Definition: commctrl.h:632
#define HDN_ITEMCHANGINGA
Definition: commctrl.h:837
#define HDF_BITMAP_ON_RIGHT
Definition: commctrl.h:722
#define LVN_BEGINLABELEDITA
Definition: commctrl.h:3135
#define HDN_FIRST
Definition: commctrl.h:205
#define LVM_GETVIEW
Definition: commctrl.h:2848
#define LVM_SETSELECTIONMARK
Definition: commctrl.h:2790
#define LVM_SETITEMTEXTA
Definition: commctrl.h:2686
#define LVM_CANCELEDITLABEL
Definition: commctrl.h:3012
#define HDN_ITEMCLICKA
Definition: commctrl.h:841
#define NM_CUSTOMDRAW
Definition: commctrl.h:137
#define HDN_ENDTRACKA
Definition: commctrl.h:849
#define LVM_GETCOLUMNW
Definition: commctrl.h:2618
#define LVIS_DROPHILITED
Definition: commctrl.h:2321
#define DPAS_SORTED
Definition: commctrl.h:4862
#define HDN_TRACKW
Definition: commctrl.h:852
#define HDN_ENDDRAG
Definition: commctrl.h:856
#define LVSCW_AUTOSIZE
Definition: commctrl.h:2644
#define LVN_ENDLABELEDITW
Definition: commctrl.h:3138
#define LVM_SETITEMCOUNT
Definition: commctrl.h:2696
#define LVN_SETDISPINFOA
Definition: commctrl.h:3155
#define LVIR_LABEL
Definition: commctrl.h:2474
#define HDM_SETIMAGELIST
Definition: commctrl.h:794
#define LVM_SCROLL
Definition: commctrl.h:2521
#define LVM_GETIMAGELIST
Definition: commctrl.h:2295
#define WC_HEADERW
Definition: commctrl.h:624
#define LVNI_DROPHILITED
Definition: commctrl.h:2426
#define LVM_ISITEMVISIBLE
Definition: commctrl.h:3018
#define LVM_INSERTITEMA
Definition: commctrl.h:2403
#define LVM_GETCOUNTPERPAGE
Definition: commctrl.h:2666
#define LVIS_SELECTED
Definition: commctrl.h:2319
#define LVN_BEGINLABELEDITW
Definition: commctrl.h:3136
#define LVSIL_GROUPHEADER
Definition: commctrl.h:2301
#define CDIS_FOCUS
Definition: commctrl.h:295
#define HDN_ITEMCHANGINGW
Definition: commctrl.h:838
#define NM_RETURN
Definition: commctrl.h:132
#define HDF_STRING
Definition: commctrl.h:720
#define LVCFMT_JUSTIFYMASK
Definition: commctrl.h:2601
#define LVM_SETHOTCURSOR
Definition: commctrl.h:2774
#define HDM_GETORDERARRAY
Definition: commctrl.h:806
#define LVM_SUBITEMHITTEST
Definition: commctrl.h:2764
#define LVN_ENDLABELEDITA
Definition: commctrl.h:3137
#define LVIF_PARAM
Definition: commctrl.h:2311
#define LVM_GETITEMTEXTW
Definition: commctrl.h:2680
#define HDI_FORMAT
Definition: commctrl.h:705
#define LVM_GETITEMRECT
Definition: commctrl.h:2477
#define LVS_NOSORTHEADER
Definition: commctrl.h:2285
#define LVM_GETITEMTEXTA
Definition: commctrl.h:2679
#define LVS_EDITLABELS
Definition: commctrl.h:2273
#define LVM_GETBKCOLOR
Definition: commctrl.h:2291
#define CLR_DEFAULT
Definition: commctrl.h:320
#define HDS_HORZ
Definition: commctrl.h:628
#define LVM_INSERTCOLUMNW
Definition: commctrl.h:2632
#define LVM_GETISEARCHSTRINGA
Definition: commctrl.h:2714
#define LVHT_ONITEMICON
Definition: commctrl.h:2494
#define LVIF_TEXT
Definition: commctrl.h:2309
#define LVM_DELETEITEM
Definition: commctrl.h:2410
#define LVSICF_NOSCROLL
Definition: commctrl.h:2694
#define LVIR_SELECTBOUNDS
Definition: commctrl.h:2475
#define HDM_GETITEMW
Definition: commctrl.h:747
#define LVM_GETEXTENDEDLISTVIEWSTYLE
Definition: commctrl.h:2727
#define LVM_SETITEMA
Definition: commctrl.h:2396
#define HDN_DIVIDERDBLCLICKW
Definition: commctrl.h:846
#define CDDS_PREPAINT
Definition: commctrl.h:280
#define CCM_SETVERSION
Definition: commctrl.h:114
#define LVA_SNAPTOGRID
Definition: commctrl.h:2530
#define LVM_SETVIEW
Definition: commctrl.h:2846
#define LVNI_CUT
Definition: commctrl.h:2425
struct tagTRACKMOUSEEVENT TRACKMOUSEEVENT
#define LVCF_FMT
Definition: commctrl.h:2586
#define LVS_ALIGNMASK
Definition: commctrl.h:2281
#define LVM_GETSELECTIONMARK
Definition: commctrl.h:2788
#define LVM_GETORIGIN
Definition: commctrl.h:2668
#define HDM_GETITEMRECT
Definition: commctrl.h:791
#define NM_RCLICK
Definition: commctrl.h:133
#define NM_SETFOCUS
Definition: commctrl.h:135
#define LVS_EX_SUBITEMIMAGES
Definition: commctrl.h:2730
#define HDI_LPARAM
Definition: commctrl.h:706
#define LVM_SETICONSPACING
Definition: commctrl.h:2721
#define LVN_ODFINDITEMA
Definition: commctrl.h:3144
#define LVCF_SUBITEM
Definition: commctrl.h:2589
#define LVCFMT_LEFT
Definition: commctrl.h:2598
#define LVNI_ABOVE
Definition: commctrl.h:2428
#define ILC_MASK
Definition: commctrl.h:351
#define INDEXTOSTATEIMAGEMASK(i)
Definition: commctrl.h:2328
#define LV_VIEW_MAX
Definition: commctrl.h:2845
#define WM_MOUSEHOVER
Definition: commctrl.h:4974
#define CDDS_POSTPAINT
Definition: commctrl.h:281
#define HDF_BITMAP
Definition: commctrl.h:721
#define HDI_FILTER
Definition: commctrl.h:711
#define HDM_SETITEMW
Definition: commctrl.h:754
#define DPA_GetPtrCount(hdpa)
Definition: commctrl.h:4955
#define HDM_INSERTITEMW
Definition: commctrl.h:737
#define LVN_GETDISPINFOW
Definition: commctrl.h:3154
#define LVN_KEYDOWN
Definition: commctrl.h:3184
#define HDM_ORDERTOINDEX
Definition: commctrl.h:800
#define LVM_SETHOTITEM
Definition: commctrl.h:2770
#define LVM_GETSELECTEDCOUNT
Definition: commctrl.h:2708
#define LVS_EX_DOUBLEBUFFER
Definition: commctrl.h:2745
#define LVM_GETUNICODEFORMAT
Definition: commctrl.h:2289
#define LVM_GETTEXTCOLOR
Definition: commctrl.h:2656
#define LVSIL_STATE
Definition: commctrl.h:2300
#define LVCFMT_RIGHT
Definition: commctrl.h:2599
#define LVM_SETITEMPOSITION32
Definition: commctrl.h:2705
#define LVM_SETTEXTBKCOLOR
Definition: commctrl.h:2662
#define LVHT_ABOVE
Definition: commctrl.h:2499
#define TME_QUERY
Definition: commctrl.h:4983
#define LVIF_IMAGE
Definition: commctrl.h:2310
#define CDRF_SKIPDEFAULT
Definition: commctrl.h:270
#define LVM_SORTITEMSEX
Definition: commctrl.h:2800
#define LVN_MARQUEEBEGIN
Definition: commctrl.h:3198
#define DPAS_INSERTAFTER
Definition: commctrl.h:4864
#define HDN_TRACKA
Definition: commctrl.h:851
#define LVM_SETCOLUMNORDERARRAY
Definition: commctrl.h:2766
#define LV_VIEW_SMALLICON
Definition: commctrl.h:2842
#define LVS_ALIGNLEFT
Definition: commctrl.h:2280
#define LVKF_ALT
Definition: commctrl.h:3055
#define LVHT_ONITEMSTATEICON
Definition: commctrl.h:2496
#define LVHT_NOWHERE
Definition: commctrl.h:2493
#define LVN_ITEMCHANGED
Definition: commctrl.h:3131
#define HDI_IMAGE
Definition: commctrl.h:708
#define LVIF_DI_SETITEM
Definition: commctrl.h:3166
#define CDIS_HOT
Definition: commctrl.h:297
#define HDN_ITEMCHANGEDA
Definition: commctrl.h:839
#define LVM_INSERTITEMW
Definition: commctrl.h:2404
#define LVSCW_AUTOSIZE_USEHEADER
Definition: commctrl.h:2645
#define LVCF_TEXT
Definition: commctrl.h:2588
#define HDM_GETIMAGELIST
Definition: commctrl.h:797
#define LVIS_STATEIMAGEMASK
Definition: commctrl.h:2326
#define LVM_GETITEMW
Definition: commctrl.h:2390
#define HDN_ITEMCLICKW
Definition: commctrl.h:842
#define LVN_DELETEITEM
Definition: commctrl.h:3133
#define LVM_SORTITEMS
Definition: commctrl.h:2702
#define LVIS_FOCUSED
Definition: commctrl.h:2318
#define LV_VIEW_ICON
Definition: commctrl.h:2840
#define LVM_FINDITEMA
Definition: commctrl.h:2465
#define HDN_DIVIDERDBLCLICKA
Definition: commctrl.h:845
#define TME_HOVER
Definition: commctrl.h:4980
#define LVM_GETCOLUMNWIDTH
Definition: commctrl.h:2641
#define LVHT_ONITEMLABEL
Definition: commctrl.h:2495
int(CALLBACK * PFNLVCOMPARE)(LPARAM, LPARAM, LPARAM)
Definition: commctrl.h:2700
#define LVM_HITTEST
Definition: commctrl.h:2515
#define LVIF_GROUPID
Definition: commctrl.h:2315
#define LVM_GETTEXTBKCOLOR
Definition: commctrl.h:2660
#define LVS_AUTOARRANGE
Definition: commctrl.h:2272
#define LVS_LIST
Definition: commctrl.h:2264
#define LVM_GETISEARCHSTRINGW
Definition: commctrl.h:2715
#define ILC_COLOR
Definition: commctrl.h:352
#define LVN_ITEMACTIVATE
Definition: commctrl.h:3147
#define HDM_DELETEITEM
Definition: commctrl.h:743
#define LVSICF_NOINVALIDATEALL
Definition: commctrl.h:2693
#define HDI_ORDER
Definition: commctrl.h:710
#define LVM_GETSTRINGWIDTHW
Definition: commctrl.h:2487
#define LVM_GETHOTCURSOR
Definition: commctrl.h:2776
#define LVIR_BOUNDS
Definition: commctrl.h:2472
#define ILD_SELECTED
Definition: commctrl.h:430
#define I_INDENTCALLBACK
Definition: commctrl.h:2330
#define LVM_SETEXTENDEDLISTVIEWSTYLE
Definition: commctrl.h:2724
#define LVSIL_NORMAL
Definition: commctrl.h:2298
#define LVFI_NEARESTXY
Definition: commctrl.h:2441
#define LVIS_CUT
Definition: commctrl.h:2320
void redraw(int x, int y, int cx, int cy)
Definition: qtewin.cpp:1248
#define DPA_GetPtr
Definition: commctrl.h:5
#define WM_CONTEXTMENU
Definition: richedit.h:64
#define WM_PRINTCLIENT
Definition: richedit.h:70
#define WM_NOTIFY
Definition: richedit.h:61
#define ID
Definition: ruserpass.c:36
#define offsetof(TYPE, MEMBER)
#define memset(x, y, z)
Definition: compat.h:39
#define TRACE(s)
Definition: solgame.cpp:4
DWORD dwTime
Definition: solitaire.cpp:27
& rect
Definition: startmenu.cpp:1413
COLORREF clrHighlightText
Definition: comctl32.h:170
COLORREF clrBtnText
Definition: comctl32.h:167
COLORREF clrWindow
Definition: comctl32.h:176
COLORREF clr3dFace
Definition: comctl32.h:175
COLORREF clrWindowText
Definition: comctl32.h:177
COLORREF clrHighlight
Definition: comctl32.h:169
Definition: globals.h:96
Definition: bl.h:1331
Definition: dpa.c:49
UINT mask
Definition: commctrl.h:667
LPSTR pszText
Definition: commctrl.h:669
UINT type
Definition: commctrl.h:676
void * pvFilter
Definition: commctrl.h:677
UINT mask
Definition: commctrl.h:684
int iImage
Definition: commctrl.h:691
LPARAM lParam
Definition: commctrl.h:690
int iOrder
Definition: commctrl.h:692
int fmt
Definition: commctrl.h:689
int cxy
Definition: commctrl.h:685
LPWSTR pszText
Definition: commctrl.h:686
int cchTextMax
Definition: commctrl.h:688
WINDOWPOS * pwpos
Definition: commctrl.h:764
RECT * prc
Definition: commctrl.h:763
LONG y
Definition: windef.h:330
LONG x
Definition: windef.h:329
LONG cx
Definition: kdterminal.h:27
LONG cy
Definition: kdterminal.h:28
HWND hwnd
Definition: winuser.h:3588
UINT flags
Definition: winuser.h:3594
HWND hwndInsertAfter
Definition: winuser.h:3589
LPCWSTR lpszClassName
Definition: winuser.h:3185
HBRUSH hbrBackground
Definition: winuser.h:3183
int cbClsExtra
Definition: winuser.h:3178
UINT style
Definition: winuser.h:3176
WNDPROC lpfnWndProc
Definition: winuser.h:3177
int cbWndExtra
Definition: winuser.h:3179
HCURSOR hCursor
Definition: winuser.h:3182
Definition: inflate.c:139
Definition: fci.c:127
Definition: dsound.c:943
Definition: parser.c:49
ULONG_PTR itemData
Definition: winuser.h:3093
LPWSTR pszText
Definition: listview.c:157
INT iImage
Definition: listview.c:158
HDPA item
Definition: listview.c:181
UINT id
Definition: listview.c:180
LPARAM lParam
Definition: listview.c:173
ITEMHDR hdr
Definition: listview.c:171
UINT state
Definition: listview.c:172
ITEM_ID * id
Definition: listview.c:175
RANGES ranges
Definition: listview.c:200
RANGE range
Definition: listview.c:199
INT nSpecial
Definition: listview.c:198
HFONT hDefaultFont
Definition: listview.c:307
COLORREF clrTextBk
Definition: listview.c:301
BOOL bNoItemMetrics
Definition: listview.c:252
HIMAGELIST himlNormal
Definition: listview.c:272
BOOL colRectsDirty
Definition: listview.c:249
LPARAM lParamSort
Definition: listview.c:258
RECT marqueeDrawRect
Definition: listview.c:289
UINT uCallbackMask
Definition: listview.c:232
POINT currIconPos
Definition: listview.c:279
WNDPROC EditWndProc
Definition: listview.c:267
WCHAR szSearchParam[MAX_PATH]
Definition: listview.c:326
HIMAGELIST himlSmall
Definition: listview.c:273
DWORD dwHoverTime
Definition: listview.c:318
COLORREF clrBk
Definition: listview.c:299
HBRUSH hBkBrush
Definition: listview.c:298
COLORREF clrText
Definition: listview.c:300
POINT marqueeOrigin
Definition: listview.c:290
SIZE iconStateSize
Definition: listview.c:278
INT nMeasureItemHeight
Definition: listview.c:330
INT nSearchParamLength
Definition: listview.c:325
WPARAM charCode
Definition: listview.c:324
HIMAGELIST himlState
Definition: listview.c:274
INT nLButtonDownItem
Definition: listview.c:317
DWORD dwLvExStyle
Definition: listview.c:262
PFNLVCOMPARE pfnCompare
Definition: listview.c:257
DWORD lastKeyPressTimestamp
Definition: listview.c:323
RANGES selectionRanges
Definition: listview.c:243
HCURSOR hHotCursor
Definition: listview.c:319
SHORT notifyFormat
Definition: listview.c:229
DWORD notify_mask
Definition: listview.c:231
POINT ptClickPos
Definition: listview.c:316
BOOL bMarqueeSelect
Definition: listview.c:286
DELAYED_ITEM_EDIT itemEdit
Definition: listview.c:269
int cchTextMax
Definition: commctrl.h:2568
LPWSTR pszText
Definition: commctrl.h:2567
LVITEMW item
Definition: commctrl.h:3179
UINT vkDirection
Definition: commctrl.h:2460
LPCWSTR psz
Definition: commctrl.h:2457
LPARAM lParam
Definition: commctrl.h:2458
LPWSTR pszText
Definition: commctrl.h:2365
int iSubItem
Definition: commctrl.h:2362
int cchTextMax
Definition: commctrl.h:2366
UINT state
Definition: commctrl.h:2363
UINT mask
Definition: commctrl.h:2360
LPARAM lParam
Definition: commctrl.h:2368
UINT stateMask
Definition: commctrl.h:2364
int iImage
Definition: commctrl.h:2367
int iIndent
Definition: commctrl.h:2369
ULONG_PTR itemData
Definition: winuser.h:3646
DWORD_PTR dwItemSpec
Definition: commctrl.h:307
UINT_PTR idFrom
Definition: winuser.h:3158
UINT code
Definition: winuser.h:3159
HWND hwndFrom
Definition: winuser.h:3157
NMHDR hdr
Definition: commctrl.h:881
HDITEMA * pitem
Definition: commctrl.h:884
HDITEMW * pitem
Definition: commctrl.h:891
POINT ptAction
Definition: commctrl.h:3039
UINT uNewState
Definition: commctrl.h:3036
LPARAM lParam
Definition: commctrl.h:3040
UINT uOldState
Definition: commctrl.h:3037
COLORREF clrTextBk
Definition: commctrl.h:3064
NMCUSTOMDRAW nmcd
Definition: commctrl.h:3062
COLORREF clrText
Definition: commctrl.h:3063
LVFINDINFOW lvfi
Definition: commctrl.h:3101
long y
Definition: polytest.cpp:48
long x
Definition: polytest.cpp:48
HDPA hdpa
Definition: listview.c:192
INT upper
Definition: listview.c:187
INT lower
Definition: listview.c:186
LONG right
Definition: windef.h:308
LONG bottom
Definition: windef.h:309
LONG top
Definition: windef.h:307
LONG left
Definition: windef.h:306
DWORD styleNew
Definition: winuser.h:3693
DWORD styleOld
Definition: winuser.h:3692
ITEMHDR hdr
Definition: listview.c:163
LONG tmMaxCharWidth
Definition: wingdi.h:2389
Definition: time.h:68
static COORD Position
Definition: mouse.c:34
#define max(a, b)
Definition: svc.c:63
#define LONG_PTR
Definition: treelist.c:79
#define WHEEL_DELTA
Definition: treelist.c:99
#define GWLP_WNDPROC
Definition: treelist.c:66
#define WM_MOUSEWHEEL
Definition: treelist.c:96
HTREEITEM hItem
Definition: treelist.h:37
TW_UINT32 TW_UINT16 TW_UINT16 MSG
Definition: twain.h:1829
HANDLE HINSTANCE
Definition: typedefs.h:77
uint32_t DWORD_PTR
Definition: typedefs.h:65
int32_t INT
Definition: typedefs.h:58
#define MAKELONG(a, b)
Definition: typedefs.h:249
uint32_t ULONG
Definition: typedefs.h:59
#define HIWORD(l)
Definition: typedefs.h:247
pass
Definition: typegen.h:25
_In_ HFONT _Out_ PUINT _Out_ PUINT Width
Definition: font.h:89
_In_ HFONT _Out_ PUINT Height
Definition: font.h:88
static const WCHAR isW[]
Definition: lex.c:62
int ret
#define LPPOINT
Definition: precomp.h:31
FORCEINLINE BOOL is_icon(PCURICON_OBJECT object)
Definition: cursoricon.c:194
int WINAPI GetWindowTextA(HWND hWnd, LPSTR lpString, int nMaxCount)
Definition: window.c:1302
int WINAPI GetWindowTextW(HWND hWnd, LPWSTR lpString, int nMaxCount)
Definition: window.c:1384
#define ZeroMemory
Definition: winbase.h:1712
_In_ PCCERT_CONTEXT _In_ DWORD dwFlags
Definition: wincrypt.h:1176
_In_ LPWSTR _In_ ULONG _In_ ULONG _In_ ULONG _Out_ DEVINFO * pdi
Definition: winddi.h:3554
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4023
LONG_PTR LPARAM
Definition: windef.h:208
LONG_PTR LRESULT
Definition: windef.h:209
UINT_PTR WPARAM
Definition: windef.h:207
int * LPINT
Definition: windef.h:178
DWORD COLORREF
Definition: windef.h:300
HICON HCURSOR
Definition: windef.h:299
#define WINAPI
Definition: msvc.h:6
#define COMPLEXREGION
Definition: wingdi.h:363
int WINAPI GetBkMode(_In_ HDC)
BOOL WINAPI GetTextMetricsW(_In_ HDC, _Out_ LPTEXTMETRICW)
Definition: text.c:221
HGDIOBJ WINAPI GetStockObject(_In_ int)
int WINAPI GetObjectW(_In_ HANDLE h, _In_ int c, _Out_writes_bytes_opt_(c) LPVOID pv)
HBITMAP WINAPI CreateBitmap(_In_ INT cx, _In_ INT cy, _In_ UINT cPlanes, _In_ UINT cBitsPerPel, _In_opt_ const VOID *pvBits)
int WINAPI GetClipBox(_In_ HDC, _Out_ LPRECT)
COLORREF WINAPI SetBkColor(_In_ HDC, _In_ COLORREF)
Definition: dc.c:999
HRGN WINAPI CreateRectRgn(_In_ int, _In_ int, _In_ int, _In_ int)
COLORREF WINAPI GetTextColor(_In_ HDC)
Definition: text.c:861
#define NULLREGION
Definition: wingdi.h:361
BOOL WINAPI RectVisible(_In_ HDC, _In_ LPCRECT)
int WINAPI IntersectClipRect(_In_ HDC, _In_ int, _In_ int, _In_ int, _In_ int)
int WINAPI ExcludeClipRect(_In_ HDC, _In_ int, _In_ int, _In_ int, _In_ int)
BOOL WINAPI GetTextExtentPointW(_In_ HDC hdc, _In_reads_(c) LPCWSTR lpString, _In_ int c, _Out_ LPSIZE lpsz)
HGDIOBJ WINAPI SelectObject(_In_ HDC, _In_ HGDIOBJ)
Definition: dc.c:1546
BOOL WINAPI MoveToEx(_In_ HDC, _In_ int, _In_ int, _Out_opt_ LPPOINT)
HDC WINAPI CreateCompatibleDC(_In_opt_ HDC hdc)
int WINAPI CombineRgn(_In_opt_ HRGN hrgnDest, _In_opt_ HRGN hrgnSrc1, _In_opt_ HRGN hrgnSrc2, _In_ int fnCombineMode)
#define TRANSPARENT
Definition: wingdi.h:950
#define RGN_AND
Definition: wingdi.h:356
#define SRCCOPY
Definition: wingdi.h:333
#define WHITE_BRUSH
Definition: wingdi.h:902
COLORREF WINAPI GetBkColor(_In_ HDC)
Definition: dc.c:978
#define DSTINVERT
Definition: wingdi.h:327
#define SIMPLEREGION
Definition: wingdi.h:362
BOOL WINAPI ExtTextOutW(_In_ HDC hdc, _In_ int x, _In_ int y, _In_ UINT options, _In_opt_ const RECT *lprect, _In_reads_opt_(c) LPCWSTR lpString, _In_ UINT c, _In_reads_opt_(c) const INT *lpDx)
#define ETO_OPAQUE
Definition: wingdi.h:647
#define OPAQUE
Definition: wingdi.h:949
BOOL WINAPI PatBlt(_In_ HDC, _In_ int, _In_ int, _In_ int, _In_ int, _In_ DWORD)
#define BLACK_BRUSH
Definition: wingdi.h:896
HBITMAP WINAPI CreateCompatibleBitmap(_In_ HDC hdc, _In_ INT cx, _In_ INT cy)
int WINAPI FillRect(HDC, LPCRECT, HBRUSH)
HFONT WINAPI CreateFontIndirectW(_In_ const LOGFONTW *)
int WINAPI SetBkMode(_In_ HDC, _In_ int)
Definition: dc.c:1056
COLORREF WINAPI SetTextColor(_In_ HDC, _In_ COLORREF)
Definition: text.c:918
HBRUSH WINAPI CreateSolidBrush(_In_ COLORREF)
BOOL WINAPI DeleteDC(_In_ HDC)
HPEN WINAPI CreatePen(_In_ int, _In_ int, _In_ COLORREF)
BOOL WINAPI GetTextExtentPointA(_In_ HDC hdc, _In_reads_(c) LPCSTR lpString, _In_ int c, _Out_ LPSIZE lpsz)
BOOL WINAPI LineTo(_In_ HDC, _In_ int, _In_ int)
BOOL WINAPI GetTextExtentPoint32A(_In_ HDC hdc, _In_reads_(c) LPCSTR lpString, _In_ int c, _Out_ LPSIZE psizl)
#define PS_SOLID
Definition: wingdi.h:586
BOOL WINAPI GetTextExtentPoint32W(_In_ HDC hdc, _In_reads_(c) LPCWSTR lpString, _In_ int c, _Out_ LPSIZE psizl)
#define NORM_IGNORECASE
Definition: winnls.h:176
#define CSTR_EQUAL
Definition: winnls.h:456
#define snprintf
Definition: wintirpc.h:48
#define SW_SHOWNORMAL
Definition: winuser.h:770
#define WM_PAINT
Definition: winuser.h:1620
HWND WINAPI SetCapture(_In_ HWND hWnd)
int WINAPI ReleaseDC(_In_opt_ HWND, _In_ HDC)
#define WM_ERASEBKGND
Definition: winuser.h:1625
#define SetWindowLongPtrA
Definition: winuser.h:5354
BOOL WINAPI IsWindow(_In_opt_ HWND)
#define MK_SHIFT
Definition: winuser.h:2369
#define ODS_SELECTED
Definition: winuser.h:2545
#define SW_HIDE
Definition: winuser.h:768
#define WM_CLOSE
Definition: winuser.h:1621
#define SWP_NOACTIVATE
Definition: winuser.h:1242
#define SB_THUMBTRACK
Definition: winuser.h:573
#define GetWindowLongPtrW
Definition: winuser.h:4829
HDC WINAPI GetWindowDC(_In_opt_ HWND)
#define WM_ENABLE
Definition: winuser.h:1615
#define SM_CYEDGE
Definition: winuser.h:1009
#define SM_CXDRAG
Definition: winuser.h:1028
#define SB_LINEUP
Definition: winuser.h:564
#define WM_HSCROLL
Definition: winuser.h:1743
#define SWP_FRAMECHANGED
Definition: winuser.h:1240
#define MAKELPARAM(l, h)
Definition: winuser.h:4008
#define EN_KILLFOCUS
Definition: winuser.h:2025
#define COLOR_WINDOW
Definition: winuser.h:918
BOOL WINAPI ShowWindow(_In_ HWND, _In_ int)
BOOL WINAPI ReleaseCapture(void)
Definition: message.c:2890
DWORD WINAPI GetMessagePos(void)
Definition: message.c:1351
#define DT_CENTER
Definition: winuser.h:527
#define ODA_DRAWENTIRE
Definition: winuser.h:2542
#define DCX_WINDOW
Definition: winuser.h:2113
LRESULT WINAPI DefWindowProcW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define SM_CXEDGE
Definition: winuser.h:1008
struct tagSCROLLINFO SCROLLINFO
#define WM_VSCROLL
Definition: winuser.h:1744
#define CreateWindowA(a, b, c, d, e, f, g, h, i, j, k)
Definition: winuser.h:4315
BOOL WINAPI GetWindowRect(_In_ HWND, _Out_ LPRECT)
#define SIF_RANGE
Definition: winuser.h:1235
#define WM_CREATE
Definition: winuser.h:1608
#define DLGC_WANTCHARS
Definition: winuser.h:2618
BOOL WINAPI DrawFrameControl(_In_ HDC, _Inout_ LPRECT, _In_ UINT, _In_ UINT)
BOOL WINAPI SetWindowPos(_In_ HWND, _In_opt_ HWND, _In_ int, _In_ int, _In_ int, _In_ int, _In_ UINT)
#define EN_UPDATE
Definition: winuser.h:2028
#define SB_PAGERIGHT
Definition: winuser.h:571
#define SWP_DRAWFRAME
Definition: winuser.h:1239
#define VK_SPACE
Definition: winuser.h:2219
#define PRF_ERASEBKGND
Definition: winuser.h:2526
#define SB_VERT
Definition: winuser.h:553
LONG WINAPI SetWindowLongW(_In_ HWND, _In_ int, _In_ LONG)
LONG WINAPI GetWindowLongW(_In_ HWND, _In_ int)
#define DLGC_WANTALLKEYS
Definition: winuser.h:2612
#define WM_LBUTTONDBLCLK
Definition: winuser.h:1778
#define SWP_NOMOVE
Definition: winuser.h:1244
#define WM_COMMAND
Definition: winuser.h:1740
#define DFCS_BUTTONCHECK
Definition: winuser.h:496
#define SW_INVALIDATE
Definition: winuser.h:2579
#define SM_CYICONSPACING
Definition: winuser.h:1002
#define ODA_FOCUS
Definition: winuser.h:2544
ATOM WINAPI RegisterClassW(_In_ CONST WNDCLASSW *)
#define IDC_ARROW
Definition: winuser.h:687
#define VK_CONTROL
Definition: winuser.h:2203
BOOL WINAPI GetCursorPos(_Out_ LPPOINT)
Definition: cursoricon.c:2714
#define DFC_BUTTON
Definition: winuser.h:476
int WINAPI GetWindowTextLengthA(_In_ HWND)
#define SM_CYSMICON
Definition: winuser.h:1013
#define VK_UP
Definition: winuser.h:2225
#define WM_RBUTTONDBLCLK
Definition: winuser.h:1781
BOOL WINAPI IsRectEmpty(_In_ LPCRECT)
#define WM_SETFOCUS
Definition: winuser.h:1613
HCURSOR WINAPI SetCursor(_In_opt_ HCURSOR)
#define SIF_PAGE
Definition: winuser.h:1233
#define SWP_NOSIZE
Definition: winuser.h:1245
#define WM_MOUSEMOVE
Definition: winuser.h:1775
HDC WINAPI GetDCEx(_In_opt_ HWND, _In_opt_ HRGN, _In_ DWORD)
HWND WINAPI GetCapture(void)
Definition: message.c:2881
#define SB_LINERIGHT
Definition: winuser.h:567
#define CS_DBLCLKS
Definition: winuser.h:651
#define SPI_GETICONTITLELOGFONT
Definition: winuser.h:1380
#define WM_LBUTTONDOWN
Definition: winuser.h:1776
#define NF_REQUERY
Definition: winuser.h:2461
#define WM_SYSCOLORCHANGE
Definition: winuser.h:1626
HCURSOR WINAPI LoadCursorW(_In_opt_ HINSTANCE, _In_ LPCWSTR)
Definition: cursoricon.c:2149
#define SIF_TRACKPOS
Definition: winuser.h:1237
int WINAPI MapWindowPoints(_In_opt_ HWND hWndFrom, _In_opt_ HWND hWndTo, _Inout_updates_(cPoints) LPPOINT lpPoints, _In_ UINT cPoints)
#define WM_GETFONT
Definition: winuser.h:1651
#define GWLP_HINSTANCE
Definition: winuser.h:856
UINT WINAPI GetDoubleClickTime(void)
Definition: ntwrapper.h:314
#define SM_CYHSCROLL
Definition: winuser.h:962
#define WM_DRAWITEM
Definition: winuser.h:1645
UINT_PTR WINAPI SetTimer(_In_opt_ HWND, _In_ UINT_PTR, _In_ UINT, _In_opt_ TIMERPROC)
#define VK_NEXT
Definition: winuser.h:2221
#define WM_NCCREATE
Definition: winuser.h:1683
#define HWND_DESKTOP
Definition: winuser.h:1209
#define WM_SHOWWINDOW
Definition: winuser.h:1628
#define WM_RBUTTONDOWN
Definition: winuser.h:1779
BOOL WINAPI PtInRect(_In_ LPCRECT, _In_ POINT)
#define DFCS_MONO
Definition: winuser.h:511
BOOL WINAPI IsWindowUnicode(_In_ HWND)
#define SM_CXSMICON
Definition: winuser.h:1012
#define DT_LEFT
Definition: winuser.h:534
BOOL WINAPI GetClientRect(_In_ HWND, _Out_ LPRECT)
#define DCX_INTERSECTRGN
Definition: winuser.h:2122
#define VK_RETURN
Definition: winuser.h:2201
#define SM_CYICON
Definition: winuser.h:973
#define SB_LINELEFT
Definition: winuser.h:566
HWND WINAPI SetFocus(_In_opt_ HWND)
#define MK_CONTROL
Definition: winuser.h:2370
#define EM_SETLIMITTEXT
Definition: winuser.h:2011
#define PM_NOYIELD
Definition: winuser.h:1197
BOOL WINAPI PeekMessageW(_Out_ LPMSG, _In_opt_ HWND, _In_ UINT, _In_ UINT, _In_ UINT)
#define WM_SETFONT
Definition: winuser.h:1650
#define VK_END
Definition: winuser.h:2222
#define VK_HOME
Definition: winuser.h:2223
BOOL WINAPI EndPaint(_In_ HWND, _In_ const PAINTSTRUCT *)
#define DLGC_WANTARROWS
Definition: winuser.h:2610
#define PM_REMOVE
Definition: winuser.h:1196
BOOL WINAPI IntersectRect(_Out_ LPRECT, _In_ LPCRECT, _In_ LPCRECT)
BOOL WINAPI UpdateWindow(_In_ HWND)
#define SB_PAGEDOWN
Definition: winuser.h:569
#define SIF_ALL
Definition: winuser.h:1232
#define SWP_SHOWWINDOW
Definition: winuser.h:1248
#define SB_BOTH
Definition: winuser.h:555
HDC WINAPI GetDC(_In_opt_ HWND)
#define SB_LINEDOWN
Definition: winuser.h:565
#define EM_SETSEL
Definition: winuser.h:2018
int WINAPI GetWindowTextLengthW(_In_ HWND)
#define PRF_CLIENT
Definition: winuser.h:2525
#define CreateWindowW(a, b, c, d, e, f, g, h, i, j, k)
Definition: winuser.h:4316
#define WM_MEASUREITEM
Definition: winuser.h:1646
#define WM_LBUTTONUP
Definition: winuser.h:1777
BOOL WINAPI SystemParametersInfoW(_In_ UINT uiAction, _In_ UINT uiParam, _Inout_opt_ PVOID pvParam, _In_ UINT fWinIni)
#define WM_CHAR
Definition: winuser.h:1717
BOOL WINAPI SetRectEmpty(_Out_ LPRECT)
HWND WINAPI GetParent(_In_ HWND)
#define GetClassLongPtrW
Definition: winuser.h:4564
#define CS_GLOBALCLASS
Definition: winuser.h:652
#define VK_LEFT
Definition: winuser.h:2224
#define NFR_ANSI
Definition: winuser.h:2458
#define SWP_HIDEWINDOW
Definition: winuser.h:1241
_In_ int _Inout_ LPRECT lprc
Definition: winuser.h:4466
#define WM_NCDESTROY
Definition: winuser.h:1684
#define VK_RIGHT
Definition: winuser.h:2226
LRESULT WINAPI DispatchMessageW(_In_ const MSG *)
#define SIF_POS
Definition: winuser.h:1234
#define VK_DOWN
Definition: winuser.h:2227
#define GWLP_ID
Definition: winuser.h:860
#define PRF_CHECKVISIBLE
Definition: winuser.h:2523
#define WM_SETCURSOR
Definition: winuser.h:1636
#define SW_ERASE
Definition: winuser.h:2580
#define WM_USER
Definition: winuser.h:1895
#define MK_LBUTTON
Definition: winuser.h:2367
#define SB_ENDSCROLL
Definition: winuser.h:574
BOOL WINAPI OffsetRect(_Inout_ LPRECT, _In_ int, _In_ int)
#define VK_SHIFT
Definition: winuser.h:2202
#define VK_PRIOR
Definition: winuser.h:2220
int WINAPI SetScrollInfo(_In_ HWND, _In_ int, _In_ LPCSCROLLINFO, _In_ BOOL)
#define WM_DESTROY
Definition: winuser.h:1609
BOOL WINAPI UnregisterClassW(_In_ LPCWSTR, HINSTANCE)
#define DFCS_CHECKED
Definition: winuser.h:504
BOOL WINAPI ShowScrollBar(_In_ HWND, _In_ int, _In_ BOOL)
#define WM_KEYDOWN
Definition: winuser.h:1715
#define DT_RIGHT
Definition: winuser.h:538
BOOL WINAPI DrawFocusRect(_In_ HDC, _In_ LPCRECT)
int WINAPI GetScrollPos(_In_ HWND, _In_ int)
BOOL WINAPI InvalidateRect(_In_opt_ HWND, _In_opt_ LPCRECT, _In_ BOOL)
LRESULT(CALLBACK * WNDPROC)(HWND, UINT, WPARAM, LPARAM)
Definition: winuser.h:2906
#define SWP_NOZORDER
Definition: winuser.h:1247
#define DT_CALCRECT
Definition: winuser.h:526
HDC WINAPI BeginPaint(_In_ HWND, _Out_ LPPAINTSTRUCT)
BOOL WINAPI KillTimer(_In_opt_ HWND, _In_ UINT_PTR)
BOOL WINAPI UnionRect(_Out_ LPRECT, _In_ LPCRECT, _In_ LPCRECT)
#define SetWindowLongPtrW
Definition: winuser.h:5355
BOOL WINAPI InflateRect(_Inout_ LPRECT, _In_ int, _In_ int)
#define SM_CYDRAG
Definition: winuser.h:1029
LRESULT WINAPI CallWindowProcW(_In_ WNDPROC, _In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define NFR_UNICODE
Definition: winuser.h:2459
#define GWL_STYLE
Definition: winuser.h:852
BOOL WINAPI GetScrollInfo(_In_ HWND, _In_ int, _Inout_ LPSCROLLINFO)
#define SM_CXICON
Definition: winuser.h:972
#define VK_ESCAPE
Definition: winuser.h:2214
#define WM_WINDOWPOSCHANGED
Definition: winuser.h:1662
BOOL WINAPI IsWindowVisible(_In_ HWND)
BOOL WINAPI DestroyWindow(_In_ HWND)
int WINAPI ScrollWindowEx(_In_ HWND, _In_ int, _In_ int, _In_opt_ LPCRECT, _In_opt_ LPCRECT, _In_opt_ HRGN, _Out_opt_ LPRECT, _In_ UINT)
#define WM_KILLFOCUS
Definition: winuser.h:1614
#define GCLP_HBRBACKGROUND
Definition: winuser.h:672
#define ODS_FOCUS
Definition: winuser.h:2549
BOOL WINAPI EqualRect(_In_ LPCRECT, _In_ LPCRECT)
int WINAPI GetSystemMetrics(_In_ int)
#define SB_PAGEUP
Definition: winuser.h:568
#define SW_NORMAL
Definition: winuser.h:769
BOOL WINAPI MoveWindow(_In_ HWND, _In_ int, _In_ int, _In_ int, _In_ int, _In_ BOOL)
LRESULT WINAPI CallWindowProcA(_In_ WNDPROC, _In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define SM_CXICONSPACING
Definition: winuser.h:1001
#define WM_GETDLGCODE
Definition: winuser.h:1689
#define NF_QUERY
Definition: winuser.h:2460
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define SB_HORZ
Definition: winuser.h:552
SHORT WINAPI GetKeyState(_In_ int)
#define VK_MENU
Definition: winuser.h:2204
#define WM_NCPAINT
Definition: winuser.h:1687
BOOL WINAPI SetRect(_Out_ LPRECT, _In_ int, _In_ int, _In_ int, _In_ int)
#define SB_PAGELEFT
Definition: winuser.h:570
#define WM_SETREDRAW
Definition: winuser.h:1616
#define SB_THUMBPOSITION
Definition: winuser.h:572
BOOL WINAPI ScreenToClient(_In_ HWND, _Inout_ LPPOINT)
_In_opt_ PALLOCATE_FUNCTION _In_opt_ PFREE_FUNCTION Free
Definition: exfuncs.h:815
const char * LPCSTR
Definition: xmlstorage.h:183
char * LPSTR
Definition: xmlstorage.h:182
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
char CHAR
Definition: xmlstorage.h:175