ReactOS 0.4.16-dev-1946-g52006dd
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
430{
432 CTRL_KEY = 0x2,
434};
435
436/*
437 * forward declarations
438 */
440static void LISTVIEW_GetItemBox(const LISTVIEW_INFO *, INT, LPRECT);
441static void LISTVIEW_GetItemOrigin(const LISTVIEW_INFO *, INT, LPPOINT);
444static void LISTVIEW_GetOrigin(const LISTVIEW_INFO *, LPPOINT);
459
460/******** Text handling functions *************************************/
461
462/* A text pointer is either NULL, LPSTR_TEXTCALLBACK, or points to a
463 * text string. The string may be ANSI or Unicode, in which case
464 * the boolean isW tells us the type of the string.
465 *
466 * The name of the function tell what type of strings it expects:
467 * W: Unicode, T: ANSI/Unicode - function of isW
468 */
469
470static inline BOOL is_text(LPCWSTR text)
471{
472 return text != NULL && text != LPSTR_TEXTCALLBACKW;
473}
474
475static inline int textlenT(LPCWSTR text, BOOL isW)
476{
477 return !is_text(text) ? 0 :
479}
480
481static inline void textcpynT(LPWSTR dest, BOOL isDestW, LPCWSTR src, BOOL isSrcW, INT max)
482{
483 if (isDestW)
484 if (isSrcW) lstrcpynW(dest, src, max);
485 else MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1, dest, max);
486 else
487 if (isSrcW) WideCharToMultiByte(CP_ACP, 0, src, -1, (LPSTR)dest, max, NULL, NULL);
488 else lstrcpynA((LPSTR)dest, (LPCSTR)src, max);
489}
490
492{
493 LPWSTR wstr = (LPWSTR)text;
494
495 if (!isW && is_text(text))
496 {
498 wstr = Alloc(len * sizeof(WCHAR));
499 if (wstr) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)text, -1, wstr, len);
500 }
501 TRACE(" wstr=%s\n", text == LPSTR_TEXTCALLBACKW ? "(callback)" : debugstr_w(wstr));
502 return wstr;
503}
504
505static inline void textfreeT(LPWSTR wstr, BOOL isW)
506{
507 if (!isW && is_text(wstr)) Free (wstr);
508}
509
510/*
511 * dest is a pointer to a Unicode string
512 * src is a pointer to a string (Unicode if isW, ANSI if !isW)
513 */
515{
516 BOOL bResult = TRUE;
517
519 {
520 if (is_text(*dest)) Free(*dest);
522 }
523 else
524 {
525 LPWSTR pszText = textdupTtoW(src, isW);
526 if (*dest == LPSTR_TEXTCALLBACKW) *dest = NULL;
527 bResult = Str_SetPtrW(dest, pszText);
528 textfreeT(pszText, isW);
529 }
530 return bResult;
531}
532
533/*
534 * compares a Unicode to a Unicode/ANSI text string
535 */
536static inline int textcmpWT(LPCWSTR aw, LPCWSTR bt, BOOL isW)
537{
538 if (!aw) return bt ? -1 : 0;
539 if (!bt) return 1;
540 if (aw == LPSTR_TEXTCALLBACKW)
541 return bt == LPSTR_TEXTCALLBACKW ? 1 : -1;
542 if (bt != LPSTR_TEXTCALLBACKW)
543 {
544 LPWSTR bw = textdupTtoW(bt, isW);
545 int r = bw ? lstrcmpW(aw, bw) : 1;
546 textfreeT(bw, isW);
547 return r;
548 }
549
550 return 1;
551}
552
553/******** Debugging functions *****************************************/
554
556{
557 if (text == LPSTR_TEXTCALLBACKW) return "(callback)";
558 return isW ? debugstr_w(text) : debugstr_a((LPCSTR)text);
559}
560
562{
563 if (text == LPSTR_TEXTCALLBACKW) return "(callback)";
564 n = min(textlenT(text, isW), n);
565 return isW ? debugstr_wn(text, n) : debugstr_an((LPCSTR)text, n);
566}
567
568static char* debug_getbuf(void)
569{
570 static int index = 0;
572 return buffers[index++ % DEBUG_BUFFERS];
573}
574
575static inline const char* debugrange(const RANGE *lprng)
576{
577 if (!lprng) return "(null)";
578 return wine_dbg_sprintf("[%d, %d]", lprng->lower, lprng->upper);
579}
580
581static const char* debugscrollinfo(const SCROLLINFO *pScrollInfo)
582{
583 char* buf = debug_getbuf(), *text = buf;
585
586 if (pScrollInfo == NULL) return "(null)";
587 len = snprintf(buf, size, "{cbSize=%u, ", pScrollInfo->cbSize);
588 if (len == -1) goto end;
589 buf += len; size -= len;
590 if (pScrollInfo->fMask & SIF_RANGE)
591 len = snprintf(buf, size, "nMin=%d, nMax=%d, ", pScrollInfo->nMin, pScrollInfo->nMax);
592 else len = 0;
593 if (len == -1) goto end;
594 buf += len; size -= len;
595 if (pScrollInfo->fMask & SIF_PAGE)
596 len = snprintf(buf, size, "nPage=%u, ", pScrollInfo->nPage);
597 else len = 0;
598 if (len == -1) goto end;
599 buf += len; size -= len;
600 if (pScrollInfo->fMask & SIF_POS)
601 len = snprintf(buf, size, "nPos=%d, ", pScrollInfo->nPos);
602 else len = 0;
603 if (len == -1) goto end;
604 buf += len; size -= len;
605 if (pScrollInfo->fMask & SIF_TRACKPOS)
606 len = snprintf(buf, size, "nTrackPos=%d, ", pScrollInfo->nTrackPos);
607 else len = 0;
608 if (len == -1) goto end;
609 buf += len;
610 goto undo;
611end:
612 buf = text + strlen(text);
613undo:
614 if (buf - text > 2) { buf[-2] = '}'; buf[-1] = 0; }
615 return text;
616}
617
618static const char* debugnmlistview(const NMLISTVIEW *plvnm)
619{
620 if (!plvnm) return "(null)";
621 return wine_dbg_sprintf("iItem=%d, iSubItem=%d, uNewState=0x%x,"
622 " uOldState=0x%x, uChanged=0x%x, ptAction=%s, lParam=%ld",
623 plvnm->iItem, plvnm->iSubItem, plvnm->uNewState, plvnm->uOldState,
624 plvnm->uChanged, wine_dbgstr_point(&plvnm->ptAction), plvnm->lParam);
625}
626
627static const char* debuglvitem_t(const LVITEMW *lpLVItem, BOOL isW)
628{
629 char* buf = debug_getbuf(), *text = buf;
631
632 if (lpLVItem == NULL) return "(null)";
633 len = snprintf(buf, size, "{iItem=%d, iSubItem=%d, ", lpLVItem->iItem, lpLVItem->iSubItem);
634 if (len == -1) goto end;
635 buf += len; size -= len;
636 if (lpLVItem->mask & LVIF_STATE)
637 len = snprintf(buf, size, "state=%x, stateMask=%x, ", lpLVItem->state, lpLVItem->stateMask);
638 else len = 0;
639 if (len == -1) goto end;
640 buf += len; size -= len;
641 if (lpLVItem->mask & LVIF_TEXT)
642 len = snprintf(buf, size, "pszText=%s, cchTextMax=%d, ", debugtext_tn(lpLVItem->pszText, isW, 80), lpLVItem->cchTextMax);
643 else len = 0;
644 if (len == -1) goto end;
645 buf += len; size -= len;
646 if (lpLVItem->mask & LVIF_IMAGE)
647 len = snprintf(buf, size, "iImage=%d, ", lpLVItem->iImage);
648 else len = 0;
649 if (len == -1) goto end;
650 buf += len; size -= len;
651 if (lpLVItem->mask & LVIF_PARAM)
652 len = snprintf(buf, size, "lParam=%lx, ", lpLVItem->lParam);
653 else len = 0;
654 if (len == -1) goto end;
655 buf += len; size -= len;
656 if (lpLVItem->mask & LVIF_INDENT)
657 len = snprintf(buf, size, "iIndent=%d, ", lpLVItem->iIndent);
658 else len = 0;
659 if (len == -1) goto end;
660 buf += len;
661 goto undo;
662end:
663 buf = text + strlen(text);
664undo:
665 if (buf - text > 2) { buf[-2] = '}'; buf[-1] = 0; }
666 return text;
667}
668
669static const char* debuglvcolumn_t(const LVCOLUMNW *lpColumn, BOOL isW)
670{
671 char* buf = debug_getbuf(), *text = buf;
673
674 if (lpColumn == NULL) return "(null)";
675 len = snprintf(buf, size, "{");
676 if (len == -1) goto end;
677 buf += len; size -= len;
678 if (lpColumn->mask & LVCF_SUBITEM)
679 len = snprintf(buf, size, "iSubItem=%d, ", lpColumn->iSubItem);
680 else len = 0;
681 if (len == -1) goto end;
682 buf += len; size -= len;
683 if (lpColumn->mask & LVCF_FMT)
684 len = snprintf(buf, size, "fmt=%x, ", lpColumn->fmt);
685 else len = 0;
686 if (len == -1) goto end;
687 buf += len; size -= len;
688 if (lpColumn->mask & LVCF_WIDTH)
689 len = snprintf(buf, size, "cx=%d, ", lpColumn->cx);
690 else len = 0;
691 if (len == -1) goto end;
692 buf += len; size -= len;
693 if (lpColumn->mask & LVCF_TEXT)
694 len = snprintf(buf, size, "pszText=%s, cchTextMax=%d, ", debugtext_tn(lpColumn->pszText, isW, 80), lpColumn->cchTextMax);
695 else len = 0;
696 if (len == -1) goto end;
697 buf += len; size -= len;
698 if (lpColumn->mask & LVCF_IMAGE)
699 len = snprintf(buf, size, "iImage=%d, ", lpColumn->iImage);
700 else len = 0;
701 if (len == -1) goto end;
702 buf += len; size -= len;
703 if (lpColumn->mask & LVCF_ORDER)
704 len = snprintf(buf, size, "iOrder=%d, ", lpColumn->iOrder);
705 else len = 0;
706 if (len == -1) goto end;
707 buf += len;
708 goto undo;
709end:
710 buf = text + strlen(text);
711undo:
712 if (buf - text > 2) { buf[-2] = '}'; buf[-1] = 0; }
713 return text;
714}
715
716static const char* debuglvhittestinfo(const LVHITTESTINFO *lpht)
717{
718 if (!lpht) return "(null)";
719
720 return wine_dbg_sprintf("{pt=%s, flags=0x%x, iItem=%d, iSubItem=%d}",
721 wine_dbgstr_point(&lpht->pt), lpht->flags, lpht->iItem, lpht->iSubItem);
722}
723
724/* Return the corresponding text for a given scroll value */
725static inline LPCSTR debugscrollcode(int nScrollCode)
726{
727 switch(nScrollCode)
728 {
729 case SB_LINELEFT: return "SB_LINELEFT";
730 case SB_LINERIGHT: return "SB_LINERIGHT";
731 case SB_PAGELEFT: return "SB_PAGELEFT";
732 case SB_PAGERIGHT: return "SB_PAGERIGHT";
733 case SB_THUMBPOSITION: return "SB_THUMBPOSITION";
734 case SB_THUMBTRACK: return "SB_THUMBTRACK";
735 case SB_ENDSCROLL: return "SB_ENDSCROLL";
736 case SB_INTERNAL: return "SB_INTERNAL";
737 default: return "unknown";
738 }
739}
740
741
742/******** Notification functions ************************************/
743
744static int get_ansi_notification(UINT unicodeNotificationCode)
745{
746 switch (unicodeNotificationCode)
747 {
752 case LVN_GETDISPINFOA:
754 case LVN_SETDISPINFOA:
756 case LVN_ODFINDITEMA:
757 case LVN_ODFINDITEMW: return LVN_ODFINDITEMA;
758 case LVN_GETINFOTIPA:
759 case LVN_GETINFOTIPW: return LVN_GETINFOTIPA;
760 /* header forwards */
761 case HDN_TRACKA:
762 case HDN_TRACKW: return HDN_TRACKA;
763 case HDN_ENDTRACKA:
764 case HDN_ENDTRACKW: return HDN_ENDTRACKA;
765 case HDN_BEGINDRAG: return HDN_BEGINDRAG;
766 case HDN_ENDDRAG: return HDN_ENDDRAG;
769 case HDN_ITEMCHANGEDA:
771 case HDN_ITEMCLICKA:
772 case HDN_ITEMCLICKW: return HDN_ITEMCLICKA;
775 default: break;
776 }
777 FIXME("unknown notification %x\n", unicodeNotificationCode);
778 return unicodeNotificationCode;
779}
780
781/* forwards header notifications to listview parent */
783{
785 LRESULT ret;
786 NMHEADERA *lpnmh = (NMHEADERA*) lpnmhW;
787
788 /* on unicode format exit earlier */
789 if (infoPtr->notifyFormat == NFR_UNICODE)
790 return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, lpnmh->hdr.idFrom,
791 (LPARAM)lpnmh);
792
793 /* header always supplies unicode notifications,
794 all we have to do is to convert strings to ANSI */
795 if (lpnmh->pitem)
796 {
797 /* convert item text */
798 if (lpnmh->pitem->mask & HDI_TEXT)
799 {
800 text = (LPCWSTR)lpnmh->pitem->pszText;
801 lpnmh->pitem->pszText = NULL;
802 Str_SetPtrWtoA(&lpnmh->pitem->pszText, text);
803 }
804 /* convert filter text */
805 if ((lpnmh->pitem->mask & HDI_FILTER) && (lpnmh->pitem->type == HDFT_ISSTRING) &&
806 lpnmh->pitem->pvFilter)
807 {
808 filter = (LPCWSTR)((HD_TEXTFILTERA*)lpnmh->pitem->pvFilter)->pszText;
809 ((HD_TEXTFILTERA*)lpnmh->pitem->pvFilter)->pszText = NULL;
810 Str_SetPtrWtoA(&((HD_TEXTFILTERA*)lpnmh->pitem->pvFilter)->pszText, filter);
811 }
812 }
813 lpnmh->hdr.code = get_ansi_notification(lpnmh->hdr.code);
814
815 ret = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, lpnmh->hdr.idFrom,
816 (LPARAM)lpnmh);
817
818 /* cleanup */
819 if(text)
820 {
821 Free(lpnmh->pitem->pszText);
822 lpnmh->pitem->pszText = (LPSTR)text;
823 }
824 if(filter)
825 {
826 Free(((HD_TEXTFILTERA*)lpnmh->pitem->pvFilter)->pszText);
827 ((HD_TEXTFILTERA*)lpnmh->pitem->pvFilter)->pszText = (LPSTR)filter;
828 }
829
830 return ret;
831}
832
833static LRESULT notify_hdr(const LISTVIEW_INFO *infoPtr, INT code, LPNMHDR pnmh)
834{
836
837 TRACE("(code=%d)\n", code);
838
839 pnmh->hwndFrom = infoPtr->hwndSelf;
840 pnmh->idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
841 pnmh->code = code;
842 result = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, pnmh->idFrom, (LPARAM)pnmh);
843
844 TRACE(" <= %ld\n", result);
845
846 return result;
847}
848
849static inline BOOL notify(const LISTVIEW_INFO *infoPtr, INT code)
850{
851 NMHDR nmh;
852 HWND hwnd = infoPtr->hwndSelf;
853 notify_hdr(infoPtr, code, &nmh);
854 return IsWindow(hwnd);
855}
856
857static inline void notify_itemactivate(const LISTVIEW_INFO *infoPtr, const LVHITTESTINFO *htInfo)
858{
859 NMITEMACTIVATE nmia;
861
862 nmia.uNewState = 0;
863 nmia.uOldState = 0;
864 nmia.uChanged = 0;
865 nmia.uKeyFlags = 0;
866
868 item.iItem = htInfo->iItem;
869 item.iSubItem = 0;
870 item.stateMask = (UINT)-1;
871 if (LISTVIEW_GetItemT(infoPtr, &item, TRUE)) {
872 nmia.lParam = item.lParam;
873 nmia.uOldState = item.state;
874 nmia.uNewState = item.state | LVIS_ACTIVATING;
875 nmia.uChanged = LVIF_STATE;
876 }
877
878 nmia.iItem = htInfo->iItem;
879 nmia.iSubItem = htInfo->iSubItem;
880 nmia.ptAction = htInfo->pt;
881
882 if (GetKeyState(VK_SHIFT) & 0x8000) nmia.uKeyFlags |= LVKF_SHIFT;
883 if (GetKeyState(VK_CONTROL) & 0x8000) nmia.uKeyFlags |= LVKF_CONTROL;
884 if (GetKeyState(VK_MENU) & 0x8000) nmia.uKeyFlags |= LVKF_ALT;
885
886 notify_hdr(infoPtr, LVN_ITEMACTIVATE, (LPNMHDR)&nmia);
887}
888
889static inline LRESULT notify_listview(const LISTVIEW_INFO *infoPtr, INT code, LPNMLISTVIEW plvnm)
890{
891 TRACE("(code=%d, plvnm=%s)\n", code, debugnmlistview(plvnm));
892 return notify_hdr(infoPtr, code, (LPNMHDR)plvnm);
893}
894
895/* Handles NM_DBLCLK, NM_CLICK, NM_RDBLCLK, NM_RCLICK. Only NM_RCLICK return value is used. */
896static BOOL notify_click(const LISTVIEW_INFO *infoPtr, INT code, const LVHITTESTINFO *lvht)
897{
898 NMITEMACTIVATE nmia;
900 HWND hwnd = infoPtr->hwndSelf;
901 LRESULT ret;
902
903 TRACE("code=%d, lvht=%s\n", code, debuglvhittestinfo(lvht));
904 ZeroMemory(&nmia, sizeof(nmia));
905 nmia.iItem = lvht->iItem;
906 nmia.iSubItem = lvht->iSubItem;
907 nmia.ptAction = lvht->pt;
908 item.mask = LVIF_PARAM;
909 item.iItem = lvht->iItem;
910 item.iSubItem = 0;
911 if (LISTVIEW_GetItemT(infoPtr, &item, TRUE)) nmia.lParam = item.lParam;
912 ret = notify_hdr(infoPtr, code, (NMHDR*)&nmia);
913 return IsWindow(hwnd) && (code == NM_RCLICK ? !ret : TRUE);
914}
915
916static BOOL notify_deleteitem(const LISTVIEW_INFO *infoPtr, INT nItem)
917{
918 NMLISTVIEW nmlv;
920 HWND hwnd = infoPtr->hwndSelf;
921
922 ZeroMemory(&nmlv, sizeof (NMLISTVIEW));
923 nmlv.iItem = nItem;
924 item.mask = LVIF_PARAM;
925 item.iItem = nItem;
926 item.iSubItem = 0;
927 if (LISTVIEW_GetItemT(infoPtr, &item, TRUE)) nmlv.lParam = item.lParam;
928 notify_listview(infoPtr, LVN_DELETEITEM, &nmlv);
929 return IsWindow(hwnd);
930}
931
932/*
933 Send notification. depends on dispinfoW having same
934 structure as dispinfoA.
935 infoPtr : listview struct
936 code : *Unicode* notification code
937 pdi : dispinfo structure (can be unicode or ansi)
938 isW : TRUE if dispinfo is Unicode
939*/
941{
942 INT length = 0, ret_length;
943 LPWSTR buffer = NULL, ret_text;
944 BOOL return_ansi = FALSE;
945 BOOL return_unicode = FALSE;
946 BOOL ret;
947
948 if ((pdi->item.mask & LVIF_TEXT) && is_text(pdi->item.pszText))
949 {
950 return_unicode = ( isW && infoPtr->notifyFormat == NFR_ANSI);
951 return_ansi = (!isW && infoPtr->notifyFormat == NFR_UNICODE);
952 }
953
954 ret_length = pdi->item.cchTextMax;
955 ret_text = pdi->item.pszText;
956
957 if (return_unicode || return_ansi)
958 {
959 if (code != LVN_GETDISPINFOW)
960 {
961 length = return_ansi ?
962 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pdi->item.pszText, -1, NULL, 0):
963 WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, NULL, 0, NULL, NULL);
964 }
965 else
966 {
967 length = pdi->item.cchTextMax;
968 *pdi->item.pszText = 0; /* make sure we don't process garbage */
969 }
970
971 buffer = Alloc( (return_ansi ? sizeof(WCHAR) : sizeof(CHAR)) * length);
972 if (!buffer) return FALSE;
973
974 if (return_ansi)
975 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pdi->item.pszText, -1,
976 buffer, length);
977 else
978 WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, (LPSTR) buffer,
979 length, NULL, NULL);
980
981 pdi->item.pszText = buffer;
982 pdi->item.cchTextMax = length;
983 }
984
985 if (infoPtr->notifyFormat == NFR_ANSI)
987
988 TRACE(" pdi->item=%s\n", debuglvitem_t(&pdi->item, infoPtr->notifyFormat != NFR_ANSI));
989 ret = notify_hdr(infoPtr, code, &pdi->hdr);
990 TRACE(" resulting code=%d\n", pdi->hdr.code);
991
992 if (return_ansi || return_unicode)
993 {
994 if (return_ansi && (pdi->hdr.code == LVN_GETDISPINFOA))
995 {
996 strcpy((char*)ret_text, (char*)pdi->item.pszText);
997 }
998 else if (return_unicode && (pdi->hdr.code == LVN_GETDISPINFOW))
999 {
1000 lstrcpyW(ret_text, pdi->item.pszText);
1001 }
1002 else if (return_ansi) /* note : pointer can be changed by app ! */
1003 {
1004 WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, (LPSTR) ret_text,
1005 ret_length, NULL, NULL);
1006 }
1007 else
1008 MultiByteToWideChar(CP_ACP, 0, (LPSTR) pdi->item.pszText, -1,
1009 ret_text, ret_length);
1010
1011 pdi->item.pszText = ret_text; /* restores our buffer */
1012 pdi->item.cchTextMax = ret_length;
1013
1014 Free(buffer);
1015 return ret;
1016 }
1017
1018 /* if dispinfo holder changed notification code then convert */
1019 if (!isW && (pdi->hdr.code == LVN_GETDISPINFOW) && (pdi->item.mask & LVIF_TEXT))
1020 {
1021 length = WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, NULL, 0, NULL, NULL);
1022
1023 buffer = Alloc(length * sizeof(CHAR));
1024 if (!buffer) return FALSE;
1025
1026 WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, (LPSTR) buffer,
1027 ret_length, NULL, NULL);
1028
1029 strcpy((LPSTR)pdi->item.pszText, (LPSTR)buffer);
1030 Free(buffer);
1031 }
1032
1033 return ret;
1034}
1035
1036static void customdraw_fill(NMLVCUSTOMDRAW *lpnmlvcd, const LISTVIEW_INFO *infoPtr, HDC hdc,
1037 const RECT *rcBounds, const LVITEMW *lplvItem)
1038{
1039 ZeroMemory(lpnmlvcd, sizeof(NMLVCUSTOMDRAW));
1040 lpnmlvcd->nmcd.hdc = hdc;
1041 lpnmlvcd->nmcd.rc = *rcBounds;
1042 lpnmlvcd->clrTextBk = infoPtr->clrTextBk;
1043 lpnmlvcd->clrText = infoPtr->clrText;
1044 if (!lplvItem) return;
1045 lpnmlvcd->nmcd.dwItemSpec = lplvItem->iItem + 1;
1046 lpnmlvcd->iSubItem = lplvItem->iSubItem;
1047 if (lplvItem->state & LVIS_SELECTED) lpnmlvcd->nmcd.uItemState |= CDIS_SELECTED;
1048 if (lplvItem->state & LVIS_FOCUSED) lpnmlvcd->nmcd.uItemState |= CDIS_FOCUS;
1049 if (lplvItem->iItem == infoPtr->nHotItem) lpnmlvcd->nmcd.uItemState |= CDIS_HOT;
1050 lpnmlvcd->nmcd.lItemlParam = lplvItem->lParam;
1051}
1052
1053static inline DWORD notify_customdraw (const LISTVIEW_INFO *infoPtr, DWORD dwDrawStage, NMLVCUSTOMDRAW *lpnmlvcd)
1054{
1055 BOOL isForItem = (lpnmlvcd->nmcd.dwItemSpec != 0);
1056 DWORD result;
1057
1058 lpnmlvcd->nmcd.dwDrawStage = dwDrawStage;
1059 if (isForItem) lpnmlvcd->nmcd.dwDrawStage |= CDDS_ITEM;
1060 if (lpnmlvcd->iSubItem) lpnmlvcd->nmcd.dwDrawStage |= CDDS_SUBITEM;
1061 if (isForItem) lpnmlvcd->nmcd.dwItemSpec--;
1062 result = notify_hdr(infoPtr, NM_CUSTOMDRAW, &lpnmlvcd->nmcd.hdr);
1063 if (isForItem) lpnmlvcd->nmcd.dwItemSpec++;
1064 return result;
1065}
1066
1067static void prepaint_setup (const LISTVIEW_INFO *infoPtr, HDC hdc, NMLVCUSTOMDRAW *lpnmlvcd, BOOL SubItem)
1068{
1069 COLORREF backcolor, textcolor;
1070
1071 /* apparently, for selected items, we have to override the returned values */
1072 if (!SubItem || (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT))
1073 {
1074 if (lpnmlvcd->nmcd.uItemState & CDIS_SELECTED)
1075 {
1076 if (infoPtr->bFocus)
1077 {
1080 }
1081 else if (infoPtr->dwStyle & LVS_SHOWSELALWAYS)
1082 {
1084 lpnmlvcd->clrText = comctl32_color.clrBtnText;
1085 }
1086 }
1087 }
1088
1089 backcolor = lpnmlvcd->clrTextBk;
1090 textcolor = lpnmlvcd->clrText;
1091
1092 if (backcolor == CLR_DEFAULT)
1093 backcolor = comctl32_color.clrWindow;
1094 if (textcolor == CLR_DEFAULT)
1095 textcolor = comctl32_color.clrWindowText;
1096
1097 /* Set the text attributes */
1098 if (backcolor != CLR_NONE)
1099 {
1101 SetBkColor(hdc, backcolor);
1102 }
1103 else
1105 SetTextColor(hdc, textcolor);
1106}
1107
1108static inline DWORD notify_postpaint (const LISTVIEW_INFO *infoPtr, NMLVCUSTOMDRAW *lpnmlvcd)
1109{
1110 return notify_customdraw(infoPtr, CDDS_POSTPAINT, lpnmlvcd);
1111}
1112
1113/* returns TRUE when repaint needed, FALSE otherwise */
1115{
1117 mis.CtlType = ODT_LISTVIEW;
1118 mis.CtlID = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
1119 mis.itemID = -1;
1120 mis.itemWidth = 0;
1121 mis.itemData = 0;
1122 mis.itemHeight= infoPtr->nItemHeight;
1123 SendMessageW(infoPtr->hwndNotify, WM_MEASUREITEM, mis.CtlID, (LPARAM)&mis);
1124 if (infoPtr->nItemHeight != max(mis.itemHeight, 1))
1125 {
1126 infoPtr->nMeasureItemHeight = infoPtr->nItemHeight = max(mis.itemHeight, 1);
1127 return TRUE;
1128 }
1129 return FALSE;
1130}
1131
1132/******** Item iterator functions **********************************/
1133
1134static RANGES ranges_create(int count);
1135static void ranges_destroy(RANGES ranges);
1136static BOOL ranges_add(RANGES ranges, RANGE range);
1137static BOOL ranges_del(RANGES ranges, RANGE range);
1138static void ranges_dump(RANGES ranges);
1139
1140static inline BOOL ranges_additem(RANGES ranges, INT nItem)
1141{
1142 RANGE range = { nItem, nItem + 1 };
1143
1144 return ranges_add(ranges, range);
1145}
1146
1147static inline BOOL ranges_delitem(RANGES ranges, INT nItem)
1148{
1149 RANGE range = { nItem, nItem + 1 };
1150
1151 return ranges_del(ranges, range);
1152}
1153
1154/***
1155 * ITERATOR DOCUMENTATION
1156 *
1157 * The iterator functions allow for easy, and convenient iteration
1158 * over items of interest in the list. Typically, you create an
1159 * iterator, use it, and destroy it, as such:
1160 * ITERATOR i;
1161 *
1162 * iterator_xxxitems(&i, ...);
1163 * while (iterator_{prev,next}(&i)
1164 * {
1165 * //code which uses i.nItem
1166 * }
1167 * iterator_destroy(&i);
1168 *
1169 * where xxx is either: framed, or visible.
1170 * Note that it is important that the code destroys the iterator
1171 * after it's done with it, as the creation of the iterator may
1172 * allocate memory, which thus needs to be freed.
1173 *
1174 * You can iterate both forwards, and backwards through the list,
1175 * by using iterator_next or iterator_prev respectively.
1176 *
1177 * Lower numbered items are draw on top of higher number items in
1178 * LVS_ICON, and LVS_SMALLICON (which are the only modes where
1179 * items may overlap). So, to test items, you should use
1180 * iterator_next
1181 * which lists the items top to bottom (in Z-order).
1182 * For drawing items, you should use
1183 * iterator_prev
1184 * which lists the items bottom to top (in Z-order).
1185 * If you keep iterating over the items after the end-of-items
1186 * marker (-1) is returned, the iterator will start from the
1187 * beginning. Typically, you don't need to test for -1,
1188 * because iterator_{next,prev} will return TRUE if more items
1189 * are to be iterated over, or FALSE otherwise.
1190 *
1191 * Note: the iterator is defined to be bidirectional. That is,
1192 * any number of prev followed by any number of next, or
1193 * five versa, should leave the iterator at the same item:
1194 * prev * n, next * n = next * n, prev * n
1195 *
1196 * The iterator has a notion of an out-of-order, special item,
1197 * which sits at the start of the list. This is used in
1198 * LVS_ICON, and LVS_SMALLICON mode to handle the focused item,
1199 * which needs to be first, as it may overlap other items.
1200 *
1201 * The code is a bit messy because we have:
1202 * - a special item to deal with
1203 * - simple range, or composite range
1204 * - empty range.
1205 * If you find bugs, or want to add features, please make sure you
1206 * always check/modify *both* iterator_prev, and iterator_next.
1207 */
1208
1209/****
1210 * This function iterates through the items in increasing order,
1211 * but prefixed by the special item, then -1. That is:
1212 * special, 1, 2, 3, ..., n, -1.
1213 * Each item is listed only once.
1214 */
1216{
1217 if (i->nItem == -1)
1218 {
1219 i->nItem = i->nSpecial;
1220 if (i->nItem != -1) return TRUE;
1221 }
1222 if (i->nItem == i->nSpecial)
1223 {
1224 if (i->ranges) i->index = 0;
1225 goto pickarange;
1226 }
1227
1228 i->nItem++;
1229testitem:
1230 if (i->nItem == i->nSpecial) i->nItem++;
1231 if (i->nItem < i->range.upper) return TRUE;
1232
1233pickarange:
1234 if (i->ranges)
1235 {
1236 if (i->index < DPA_GetPtrCount(i->ranges->hdpa))
1237 i->range = *(RANGE*)DPA_GetPtr(i->ranges->hdpa, i->index++);
1238 else goto end;
1239 }
1240 else if (i->nItem >= i->range.upper) goto end;
1241
1242 i->nItem = i->range.lower;
1243 if (i->nItem >= 0) goto testitem;
1244end:
1245 i->nItem = -1;
1246 return FALSE;
1247}
1248
1249/****
1250 * This function iterates through the items in decreasing order,
1251 * followed by the special item, then -1. That is:
1252 * n, n-1, ..., 3, 2, 1, special, -1.
1253 * Each item is listed only once.
1254 */
1256{
1257 BOOL start = FALSE;
1258
1259 if (i->nItem == -1)
1260 {
1261 start = TRUE;
1262 if (i->ranges) i->index = DPA_GetPtrCount(i->ranges->hdpa);
1263 goto pickarange;
1264 }
1265 if (i->nItem == i->nSpecial)
1266 {
1267 i->nItem = -1;
1268 return FALSE;
1269 }
1270
1271testitem:
1272 i->nItem--;
1273 if (i->nItem == i->nSpecial) i->nItem--;
1274 if (i->nItem >= i->range.lower) return TRUE;
1275
1276pickarange:
1277 if (i->ranges)
1278 {
1279 if (i->index > 0)
1280 i->range = *(RANGE*)DPA_GetPtr(i->ranges->hdpa, --i->index);
1281 else goto end;
1282 }
1283 else if (!start && i->nItem < i->range.lower) goto end;
1284
1285 i->nItem = i->range.upper;
1286 if (i->nItem > 0) goto testitem;
1287end:
1288 return (i->nItem = i->nSpecial) != -1;
1289}
1290
1292{
1293 RANGE range;
1294
1295 if (!i->ranges) return i->range;
1296
1297 if (DPA_GetPtrCount(i->ranges->hdpa) > 0)
1298 {
1299 range.lower = (*(RANGE*)DPA_GetPtr(i->ranges->hdpa, 0)).lower;
1300 range.upper = (*(RANGE*)DPA_GetPtr(i->ranges->hdpa, DPA_GetPtrCount(i->ranges->hdpa) - 1)).upper;
1301 }
1302 else range.lower = range.upper = 0;
1303
1304 return range;
1305}
1306
1307/***
1308 * Releases resources associated with this iterator.
1309 */
1310static inline void iterator_destroy(const ITERATOR *i)
1311{
1312 ranges_destroy(i->ranges);
1313}
1314
1315/***
1316 * Create an empty iterator.
1317 */
1318static inline void iterator_empty(ITERATOR* i)
1319{
1320 ZeroMemory(i, sizeof(*i));
1321 i->nItem = i->nSpecial = i->range.lower = i->range.upper = -1;
1322}
1323
1324/***
1325 * Create an iterator over a range.
1326 */
1328{
1330 i->range = range;
1331}
1332
1333/***
1334 * Create an iterator over a bunch of ranges.
1335 * Please note that the iterator will take ownership of the ranges,
1336 * and will free them upon destruction.
1337 */
1338static inline void iterator_rangesitems(ITERATOR* i, RANGES ranges)
1339{
1341 i->ranges = ranges;
1342}
1343
1344/***
1345 * Creates an iterator over the items which intersect frame.
1346 * Uses absolute coordinates rather than compensating for the current offset.
1347 */
1348static BOOL iterator_frameditems_absolute(ITERATOR* i, const LISTVIEW_INFO* infoPtr, const RECT *frame)
1349{
1350 RECT rcItem, rcTemp;
1351 RANGES ranges;
1352
1353 TRACE("(frame=%s)\n", wine_dbgstr_rect(frame));
1354
1355 /* in case we fail, we want to return an empty iterator */
1357
1358 if (infoPtr->nItemCount == 0)
1359 return TRUE;
1360
1361 if (infoPtr->uView == LV_VIEW_ICON || infoPtr->uView == LV_VIEW_SMALLICON)
1362 {
1363 INT nItem;
1364
1365 if (infoPtr->uView == LV_VIEW_ICON && infoPtr->nFocusedItem != -1)
1366 {
1367 LISTVIEW_GetItemBox(infoPtr, infoPtr->nFocusedItem, &rcItem);
1368 if (IntersectRect(&rcTemp, &rcItem, frame))
1369 i->nSpecial = infoPtr->nFocusedItem;
1370 }
1371 if (!(ranges = ranges_create(50))) return FALSE;
1372 iterator_rangesitems(i, ranges);
1373 /* to do better here, we need to have PosX, and PosY sorted */
1374 TRACE("building icon ranges:\n");
1375 for (nItem = 0; nItem < infoPtr->nItemCount; nItem++)
1376 {
1377 rcItem.left = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosX, nItem);
1378 rcItem.top = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosY, nItem);
1379 rcItem.right = rcItem.left + infoPtr->nItemWidth;
1380 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
1381 if (IntersectRect(&rcTemp, &rcItem, frame))
1382 ranges_additem(i->ranges, nItem);
1383 }
1384 return TRUE;
1385 }
1386 else if (infoPtr->uView == LV_VIEW_DETAILS)
1387 {
1388 RANGE range;
1389
1390 if (frame->left >= infoPtr->nItemWidth) return TRUE;
1391 if (frame->top >= infoPtr->nItemHeight * infoPtr->nItemCount) return TRUE;
1392
1393 range.lower = max(frame->top / infoPtr->nItemHeight, 0);
1394 range.upper = min((frame->bottom - 1) / infoPtr->nItemHeight, infoPtr->nItemCount - 1) + 1;
1395 if (range.upper <= range.lower) return TRUE;
1397 TRACE(" report=%s\n", debugrange(&i->range));
1398 }
1399 else
1400 {
1401 INT nPerCol = max((infoPtr->rcList.bottom - infoPtr->rcList.top) / infoPtr->nItemHeight, 1);
1402 INT nFirstRow = max(frame->top / infoPtr->nItemHeight, 0);
1403 INT nLastRow = min((frame->bottom - 1) / infoPtr->nItemHeight, nPerCol - 1);
1404 INT nFirstCol;
1405 INT nLastCol;
1406 INT lower;
1407 RANGE item_range;
1408 INT nCol;
1409
1410 if (infoPtr->nItemWidth)
1411 {
1412 nFirstCol = max(frame->left / infoPtr->nItemWidth, 0);
1413 nLastCol = min((frame->right - 1) / infoPtr->nItemWidth, (infoPtr->nItemCount + nPerCol - 1) / nPerCol);
1414 }
1415 else
1416 {
1417 nFirstCol = max(frame->left, 0);
1418 nLastCol = min(frame->right - 1, (infoPtr->nItemCount + nPerCol - 1) / nPerCol);
1419 }
1420
1421 lower = nFirstCol * nPerCol + nFirstRow;
1422
1423 TRACE("nPerCol=%d, nFirstRow=%d, nLastRow=%d, nFirstCol=%d, nLastCol=%d, lower=%d\n",
1424 nPerCol, nFirstRow, nLastRow, nFirstCol, nLastCol, lower);
1425
1426 if (nLastCol < nFirstCol || nLastRow < nFirstRow) return TRUE;
1427
1428 if (!(ranges = ranges_create(nLastCol - nFirstCol + 1))) return FALSE;
1429 iterator_rangesitems(i, ranges);
1430 TRACE("building list ranges:\n");
1431 for (nCol = nFirstCol; nCol <= nLastCol; nCol++)
1432 {
1433 item_range.lower = nCol * nPerCol + nFirstRow;
1434 if(item_range.lower >= infoPtr->nItemCount) break;
1435 item_range.upper = min(nCol * nPerCol + nLastRow + 1, infoPtr->nItemCount);
1436 TRACE(" list=%s\n", debugrange(&item_range));
1437 ranges_add(i->ranges, item_range);
1438 }
1439 }
1440
1441 return TRUE;
1442}
1443
1444/***
1445 * Creates an iterator over the items which intersect lprc.
1446 */
1448{
1449 RECT frame = *lprc;
1450 POINT Origin;
1451
1452 TRACE("(lprc=%s)\n", wine_dbgstr_rect(lprc));
1453
1454 LISTVIEW_GetOrigin(infoPtr, &Origin);
1455 OffsetRect(&frame, -Origin.x, -Origin.y);
1456
1457 return iterator_frameditems_absolute(i, infoPtr, &frame);
1458}
1459
1460/***
1461 * Creates an iterator over the items which intersect the visible region of hdc.
1462 */
1464{
1465 POINT Origin, Position;
1466 RECT rcItem, rcClip;
1467 INT rgntype;
1468
1469 rgntype = GetClipBox(hdc, &rcClip);
1470 if (rgntype == NULLREGION)
1471 {
1473 return TRUE;
1474 }
1475 if (!iterator_frameditems(i, infoPtr, &rcClip)) return FALSE;
1476 if (rgntype == SIMPLEREGION) return TRUE;
1477
1478 /* first deal with the special item */
1479 if (i->nSpecial != -1)
1480 {
1481 LISTVIEW_GetItemBox(infoPtr, i->nSpecial, &rcItem);
1482 if (!RectVisible(hdc, &rcItem)) i->nSpecial = -1;
1483 }
1484
1485 /* if we can't deal with the region, we'll just go with the simple range */
1486 LISTVIEW_GetOrigin(infoPtr, &Origin);
1487 TRACE("building visible range:\n");
1488 if (!i->ranges && i->range.lower < i->range.upper)
1489 {
1490 if (!(i->ranges = ranges_create(50))) return TRUE;
1491 if (!ranges_add(i->ranges, i->range))
1492 {
1493 ranges_destroy(i->ranges);
1494 i->ranges = 0;
1495 return TRUE;
1496 }
1497 }
1498
1499 /* now delete the invisible items from the list */
1500 while(iterator_next(i))
1501 {
1502 LISTVIEW_GetItemOrigin(infoPtr, i->nItem, &Position);
1503 rcItem.left = (infoPtr->uView == LV_VIEW_DETAILS) ? Origin.x : Position.x + Origin.x;
1504 rcItem.top = Position.y + Origin.y;
1505 rcItem.right = rcItem.left + infoPtr->nItemWidth;
1506 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
1507 if (!RectVisible(hdc, &rcItem))
1508 ranges_delitem(i->ranges, i->nItem);
1509 }
1510 /* the iterator should restart on the next iterator_next */
1511 TRACE("done\n");
1512
1513 return TRUE;
1514}
1515
1516/* Remove common elements from two iterators */
1517/* Passed iterators have to point on the first elements */
1519{
1520 if(!iter1->ranges || !iter2->ranges) {
1521 int lower, upper;
1522
1523 if(iter1->ranges || iter2->ranges ||
1524 (iter1->range.lower<iter2->range.lower && iter1->range.upper>iter2->range.upper) ||
1525 (iter1->range.lower>iter2->range.lower && iter1->range.upper<iter2->range.upper)) {
1526 ERR("result is not a one range iterator\n");
1527 return FALSE;
1528 }
1529
1530 if(iter1->range.lower==-1 || iter2->range.lower==-1)
1531 return TRUE;
1532
1533 lower = iter1->range.lower;
1534 upper = iter1->range.upper;
1535
1536 if(lower < iter2->range.lower)
1537 iter1->range.upper = iter2->range.lower;
1538 else if(upper > iter2->range.upper)
1539 iter1->range.lower = iter2->range.upper;
1540 else
1541 iter1->range.lower = iter1->range.upper = -1;
1542
1543 if(iter2->range.lower < lower)
1544 iter2->range.upper = lower;
1545 else if(iter2->range.upper > upper)
1546 iter2->range.lower = upper;
1547 else
1548 iter2->range.lower = iter2->range.upper = -1;
1549
1550 return TRUE;
1551 }
1552
1553 iterator_next(iter1);
1554 iterator_next(iter2);
1555
1556 while(1) {
1557 if(iter1->nItem==-1 || iter2->nItem==-1)
1558 break;
1559
1560 if(iter1->nItem == iter2->nItem) {
1561 int delete = iter1->nItem;
1562
1563 iterator_prev(iter1);
1564 iterator_prev(iter2);
1565 ranges_delitem(iter1->ranges, delete);
1566 ranges_delitem(iter2->ranges, delete);
1567 iterator_next(iter1);
1568 iterator_next(iter2);
1569 } else if(iter1->nItem > iter2->nItem)
1570 iterator_next(iter2);
1571 else
1572 iterator_next(iter1);
1573 }
1574
1575 iter1->nItem = iter1->range.lower = iter1->range.upper = -1;
1576 iter2->nItem = iter2->range.lower = iter2->range.upper = -1;
1577 return TRUE;
1578}
1579
1580/******** Misc helper functions ************************************/
1581
1584{
1585 if (isW) return CallWindowProcW(proc, hwnd, uMsg, wParam, lParam);
1586 else return CallWindowProcA(proc, hwnd, uMsg, wParam, lParam);
1587}
1588
1589static inline BOOL is_autoarrange(const LISTVIEW_INFO *infoPtr)
1590{
1591 return (infoPtr->dwStyle & LVS_AUTOARRANGE) &&
1592 (infoPtr->uView == LV_VIEW_ICON || infoPtr->uView == LV_VIEW_SMALLICON);
1593}
1594
1595static void toggle_checkbox_state(LISTVIEW_INFO *infoPtr, INT nItem)
1596{
1598 if(state == 1 || state == 2)
1599 {
1600 LVITEMW lvitem;
1601 state ^= 3;
1604 LISTVIEW_SetItemState(infoPtr, nItem, &lvitem);
1605 }
1606}
1607
1608/* this should be called after window style got updated,
1609 it used to reset view state to match current window style */
1610static inline void map_style_view(LISTVIEW_INFO *infoPtr)
1611{
1612 switch (infoPtr->dwStyle & LVS_TYPEMASK)
1613 {
1614 case LVS_ICON:
1615 infoPtr->uView = LV_VIEW_ICON;
1616 break;
1617 case LVS_REPORT:
1618 infoPtr->uView = LV_VIEW_DETAILS;
1619 break;
1620 case LVS_SMALLICON:
1621 infoPtr->uView = LV_VIEW_SMALLICON;
1622 break;
1623 case LVS_LIST:
1624 infoPtr->uView = LV_VIEW_LIST;
1625 }
1626}
1627
1628/* computes next item id value */
1630{
1632
1633 if (count > 0)
1634 {
1635 ITEM_ID *lpID = DPA_GetPtr(infoPtr->hdpaItemIds, count - 1);
1636 return lpID->id + 1;
1637 }
1638 return 0;
1639}
1640
1641/******** Internal API functions ************************************/
1642
1643static inline COLUMN_INFO * LISTVIEW_GetColumnInfo(const LISTVIEW_INFO *infoPtr, INT nSubItem)
1644{
1645 static COLUMN_INFO mainItem;
1646
1647 if (nSubItem == 0 && DPA_GetPtrCount(infoPtr->hdpaColumns) == 0) return &mainItem;
1648 assert (nSubItem >= 0 && nSubItem < DPA_GetPtrCount(infoPtr->hdpaColumns));
1649
1650 /* update cached column rectangles */
1651 if (infoPtr->colRectsDirty)
1652 {
1654 LISTVIEW_INFO *Ptr = (LISTVIEW_INFO*)infoPtr;
1655 INT i;
1656
1657 for (i = 0; i < DPA_GetPtrCount(infoPtr->hdpaColumns); i++) {
1658 info = DPA_GetPtr(infoPtr->hdpaColumns, i);
1659 SendMessageW(infoPtr->hwndHeader, HDM_GETITEMRECT, i, (LPARAM)&info->rcHeader);
1660 }
1661 Ptr->colRectsDirty = FALSE;
1662 }
1663
1664 return DPA_GetPtr(infoPtr->hdpaColumns, nSubItem);
1665}
1666
1668{
1671
1672 if (infoPtr->hwndHeader) return 0;
1673
1674 TRACE("Creating header for list %p\n", infoPtr->hwndSelf);
1675
1676 /* setup creation flags */
1677 dFlags |= (LVS_NOSORTHEADER & infoPtr->dwStyle) ? 0 : HDS_BUTTONS;
1678 dFlags |= (LVS_NOCOLUMNHEADER & infoPtr->dwStyle) ? HDS_HIDDEN : 0;
1679
1681
1682 /* create header */
1683 infoPtr->hwndHeader = CreateWindowW(WC_HEADERW, NULL, dFlags,
1684 0, 0, 0, 0, infoPtr->hwndSelf, NULL, hInst, NULL);
1685 if (!infoPtr->hwndHeader) return -1;
1686
1687 /* set header unicode format */
1689
1690 /* set header font */
1691 SendMessageW(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont, TRUE);
1692
1693 /* set header image list */
1694 if (infoPtr->himlSmall)
1695 SendMessageW(infoPtr->hwndHeader, HDM_SETIMAGELIST, 0, (LPARAM)infoPtr->himlSmall);
1696
1697 LISTVIEW_UpdateSize(infoPtr);
1698
1699 return 0;
1700}
1701
1702static inline void LISTVIEW_GetHeaderRect(const LISTVIEW_INFO *infoPtr, INT nSubItem, LPRECT lprc)
1703{
1704 *lprc = LISTVIEW_GetColumnInfo(infoPtr, nSubItem)->rcHeader;
1705}
1706
1707static inline BOOL LISTVIEW_IsHeaderEnabled(const LISTVIEW_INFO *infoPtr)
1708{
1709 return (infoPtr->uView == LV_VIEW_DETAILS ||
1710 infoPtr->dwLvExStyle & LVS_EX_HEADERINALLVIEWS) &&
1711 !(infoPtr->dwStyle & LVS_NOCOLUMNHEADER);
1712}
1713
1714static inline BOOL LISTVIEW_GetItemW(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem)
1715{
1716 return LISTVIEW_GetItemT(infoPtr, lpLVItem, TRUE);
1717}
1718
1719/* used to handle collapse main item column case */
1720static inline BOOL LISTVIEW_DrawFocusRect(const LISTVIEW_INFO *infoPtr, HDC hdc)
1721{
1722#ifdef __REACTOS__
1723 BOOL Ret = FALSE;
1724
1725 if (infoPtr->rcFocus.left < infoPtr->rcFocus.right)
1726 {
1727 DWORD dwOldBkColor, dwOldTextColor;
1728
1729 dwOldBkColor = SetBkColor(hdc, RGB(255, 255, 255));
1730 dwOldTextColor = SetBkColor(hdc, RGB(0, 0, 0));
1731 Ret = DrawFocusRect(hdc, &infoPtr->rcFocus);
1732 SetBkColor(hdc, dwOldBkColor);
1733 SetBkColor(hdc, dwOldTextColor);
1734 }
1735 return Ret;
1736#else
1737 return (infoPtr->rcFocus.left < infoPtr->rcFocus.right) ?
1738 DrawFocusRect(hdc, &infoPtr->rcFocus) : FALSE;
1739#endif
1740}
1741
1742/* Listview invalidation functions: use _only_ these functions to invalidate */
1743
1744static inline BOOL is_redrawing(const LISTVIEW_INFO *infoPtr)
1745{
1746 return infoPtr->redraw;
1747}
1748
1749static inline void LISTVIEW_InvalidateRect(const LISTVIEW_INFO *infoPtr, const RECT* rect)
1750{
1751 if(!is_redrawing(infoPtr)) return;
1752 TRACE(" invalidating rect=%s\n", wine_dbgstr_rect(rect));
1753 InvalidateRect(infoPtr->hwndSelf, rect, TRUE);
1754}
1755
1756static inline void LISTVIEW_InvalidateItem(const LISTVIEW_INFO *infoPtr, INT nItem)
1757{
1758 RECT rcBox;
1759
1760 if (!is_redrawing(infoPtr) || nItem < 0 || nItem >= infoPtr->nItemCount)
1761 return;
1762
1763 LISTVIEW_GetItemBox(infoPtr, nItem, &rcBox);
1764 LISTVIEW_InvalidateRect(infoPtr, &rcBox);
1765}
1766
1767static inline void LISTVIEW_InvalidateSubItem(const LISTVIEW_INFO *infoPtr, INT nItem, INT nSubItem)
1768{
1769 POINT Origin, Position;
1770 RECT rcBox;
1771
1772 if(!is_redrawing(infoPtr)) return;
1773 assert (infoPtr->uView == LV_VIEW_DETAILS);
1774 LISTVIEW_GetOrigin(infoPtr, &Origin);
1775 LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position);
1776 LISTVIEW_GetHeaderRect(infoPtr, nSubItem, &rcBox);
1777 rcBox.top = 0;
1778 rcBox.bottom = infoPtr->nItemHeight;
1779 OffsetRect(&rcBox, Origin.x, Origin.y + Position.y);
1780 LISTVIEW_InvalidateRect(infoPtr, &rcBox);
1781}
1782
1783static inline void LISTVIEW_InvalidateList(const LISTVIEW_INFO *infoPtr)
1784{
1785 LISTVIEW_InvalidateRect(infoPtr, NULL);
1786}
1787
1788static inline void LISTVIEW_InvalidateColumn(const LISTVIEW_INFO *infoPtr, INT nColumn)
1789{
1790 RECT rcCol;
1791
1792 if(!is_redrawing(infoPtr)) return;
1793 LISTVIEW_GetHeaderRect(infoPtr, nColumn, &rcCol);
1794 rcCol.top = infoPtr->rcList.top;
1795 rcCol.bottom = infoPtr->rcList.bottom;
1796 LISTVIEW_InvalidateRect(infoPtr, &rcCol);
1797}
1798
1799/***
1800 * DESCRIPTION:
1801 * Retrieves the number of items that can fit vertically in the client area.
1802 *
1803 * PARAMETER(S):
1804 * [I] infoPtr : valid pointer to the listview structure
1805 *
1806 * RETURN:
1807 * Number of items per row.
1808 */
1809static inline INT LISTVIEW_GetCountPerRow(const LISTVIEW_INFO *infoPtr)
1810{
1811 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
1812
1813 return max(nListWidth/(infoPtr->nItemWidth ? infoPtr->nItemWidth : 1), 1);
1814}
1815
1816/***
1817 * DESCRIPTION:
1818 * Retrieves the number of items that can fit horizontally in the client
1819 * area.
1820 *
1821 * PARAMETER(S):
1822 * [I] infoPtr : valid pointer to the listview structure
1823 *
1824 * RETURN:
1825 * Number of items per column.
1826 */
1827static inline INT LISTVIEW_GetCountPerColumn(const LISTVIEW_INFO *infoPtr)
1828{
1829 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
1830
1831 return infoPtr->nItemHeight ? max(nListHeight / infoPtr->nItemHeight, 1) : 0;
1832}
1833
1834
1835/*************************************************************************
1836 * LISTVIEW_ProcessLetterKeys
1837 *
1838 * Processes keyboard messages generated by pressing the letter keys
1839 * on the keyboard.
1840 * What this does is perform a case insensitive search from the
1841 * current position with the following quirks:
1842 * - If two chars or more are pressed in quick succession we search
1843 * for the corresponding string (e.g. 'abc').
1844 * - If there is a delay we wipe away the current search string and
1845 * restart with just that char.
1846 * - If the user keeps pressing the same character, whether slowly or
1847 * fast, so that the search string is entirely composed of this
1848 * character ('aaaaa' for instance), then we search for first item
1849 * that starting with that character.
1850 * - If the user types the above character in quick succession, then
1851 * we must also search for the corresponding string ('aaaaa'), and
1852 * go to that string if there is a match.
1853 *
1854 * PARAMETERS
1855 * [I] hwnd : handle to the window
1856 * [I] charCode : the character code, the actual character
1857 * [I] keyData : key data
1858 *
1859 * RETURNS
1860 *
1861 * Zero.
1862 *
1863 * BUGS
1864 *
1865 * - The current implementation has a list of characters it will
1866 * accept and it ignores everything else. In particular it will
1867 * ignore accentuated characters which seems to match what
1868 * Windows does. But I'm not sure it makes sense to follow
1869 * Windows there.
1870 * - We don't sound a beep when the search fails.
1871 *
1872 * SEE ALSO
1873 *
1874 * TREEVIEW_ProcessLetterKeys
1875 */
1876static INT LISTVIEW_ProcessLetterKeys(LISTVIEW_INFO *infoPtr, WPARAM charCode, LPARAM keyData)
1877{
1879 DWORD prevTime;
1880 LVITEMW item;
1881 int startidx;
1882 INT nItem;
1883 INT diff;
1884
1885 /* simple parameter checking */
1886 if (!charCode || !keyData || infoPtr->nItemCount == 0) return 0;
1887
1888 /* only allow the valid WM_CHARs through */
1889 if (!iswalnum(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 charCode != '<' && charCode != ',' && charCode != '~')
1899 return 0;
1900
1901 /* update the search parameters */
1902 prevTime = infoPtr->lastKeyPressTimestamp;
1904 diff = infoPtr->lastKeyPressTimestamp - prevTime;
1905
1906 if (diff >= 0 && diff < KEY_DELAY)
1907 {
1908 if (infoPtr->nSearchParamLength < MAX_PATH - 1)
1909 infoPtr->szSearchParam[infoPtr->nSearchParamLength++] = charCode;
1910
1911 if (infoPtr->charCode != charCode)
1912 infoPtr->charCode = charCode = 0;
1913 }
1914 else
1915 {
1916 infoPtr->charCode = charCode;
1917 infoPtr->szSearchParam[0] = charCode;
1918 infoPtr->nSearchParamLength = 1;
1919 }
1920
1921 /* should start from next after focused item, so next item that matches
1922 will be selected, if there isn't any and focused matches it will be selected
1923 on second search stage from beginning of the list */
1924 if (infoPtr->nFocusedItem >= 0 && infoPtr->nItemCount > 1)
1925 {
1926 /* with some accumulated search data available start with current focus, otherwise
1927 it's excluded from search */
1928 startidx = infoPtr->nSearchParamLength > 1 ? infoPtr->nFocusedItem : infoPtr->nFocusedItem + 1;
1929 if (startidx == infoPtr->nItemCount) startidx = 0;
1930 }
1931 else
1932 startidx = 0;
1933
1934 /* let application handle this for virtual listview */
1935 if (infoPtr->dwStyle & LVS_OWNERDATA)
1936 {
1937 NMLVFINDITEMW nmlv;
1938
1939 memset(&nmlv.lvfi, 0, sizeof(nmlv.lvfi));
1940 nmlv.lvfi.flags = (LVFI_WRAP | LVFI_PARTIAL);
1941 nmlv.lvfi.psz = infoPtr->szSearchParam;
1942 nmlv.iStart = startidx;
1943
1944 infoPtr->szSearchParam[infoPtr->nSearchParamLength] = 0;
1945
1946 nItem = notify_hdr(infoPtr, LVN_ODFINDITEMW, (LPNMHDR)&nmlv.hdr);
1947 }
1948 else
1949 {
1950 int i = startidx, endidx;
1951
1952 /* and search from the current position */
1953 nItem = -1;
1954 endidx = infoPtr->nItemCount;
1955
1956 /* first search in [startidx, endidx), on failure continue in [0, startidx) */
1957 while (1)
1958 {
1959 /* start from first item if not found with >= startidx */
1960 if (i == infoPtr->nItemCount && startidx > 0)
1961 {
1962 endidx = startidx;
1963 startidx = 0;
1964 }
1965
1966 for (i = startidx; i < endidx; i++)
1967 {
1968 /* retrieve text */
1969 item.mask = LVIF_TEXT;
1970 item.iItem = i;
1971 item.iSubItem = 0;
1972 item.pszText = buffer;
1973 item.cchTextMax = MAX_PATH;
1974 if (!LISTVIEW_GetItemW(infoPtr, &item)) return 0;
1975
1976 if (!wcsnicmp(item.pszText, infoPtr->szSearchParam, infoPtr->nSearchParamLength))
1977 {
1978 nItem = i;
1979 break;
1980 }
1981 /* this is used to find first char match when search string is not available yet,
1982 otherwise every WM_CHAR will search to next item by first char, ignoring that we're
1983 already waiting for user to complete a string */
1984 else if (nItem == -1 && infoPtr->nSearchParamLength == 1 && !wcsnicmp(item.pszText, infoPtr->szSearchParam, 1))
1985 {
1986 /* this would work but we must keep looking for a longer match */
1987 nItem = i;
1988 }
1989 }
1990
1991 if ( nItem != -1 || /* found something */
1992 endidx != infoPtr->nItemCount || /* second search done */
1993 (startidx == 0 && endidx == infoPtr->nItemCount) /* full range for first search */ )
1994 break;
1995 };
1996 }
1997
1998 if (nItem != -1)
1999 LISTVIEW_KeySelection(infoPtr, nItem, 0);
2000
2001 return 0;
2002}
2003
2004/*************************************************************************
2005 * LISTVIEW_UpdateHeaderSize [Internal]
2006 *
2007 * Function to resize the header control
2008 *
2009 * PARAMS
2010 * [I] hwnd : handle to a window
2011 * [I] nNewScrollPos : scroll pos to set
2012 *
2013 * RETURNS
2014 * None.
2015 */
2016static void LISTVIEW_UpdateHeaderSize(const LISTVIEW_INFO *infoPtr, INT nNewScrollPos)
2017{
2018 RECT winRect;
2019 POINT point[2];
2020
2021 TRACE("nNewScrollPos=%d\n", nNewScrollPos);
2022
2023 if (!infoPtr->hwndHeader) return;
2024
2025 GetWindowRect(infoPtr->hwndHeader, &winRect);
2026 point[0].x = winRect.left;
2027 point[0].y = winRect.top;
2028 point[1].x = winRect.right;
2029 point[1].y = winRect.bottom;
2030
2032 point[0].x = -nNewScrollPos;
2033 point[1].x += nNewScrollPos;
2034
2035 SetWindowPos(infoPtr->hwndHeader,0,
2036 point[0].x,point[0].y,point[1].x,point[1].y,
2039}
2040
2042{
2043 SCROLLINFO horzInfo;
2044 INT dx;
2045
2046 ZeroMemory(&horzInfo, sizeof(SCROLLINFO));
2047 horzInfo.cbSize = sizeof(SCROLLINFO);
2048 horzInfo.nPage = infoPtr->rcList.right - infoPtr->rcList.left;
2049
2050 /* for now, we'll set info.nMax to the _count_, and adjust it later */
2051 if (infoPtr->uView == LV_VIEW_LIST)
2052 {
2053 INT nPerCol = LISTVIEW_GetCountPerColumn(infoPtr);
2054 horzInfo.nMax = (infoPtr->nItemCount + nPerCol - 1) / nPerCol;
2055
2056 /* scroll by at least one column per page */
2057 if(horzInfo.nPage < infoPtr->nItemWidth)
2058 horzInfo.nPage = infoPtr->nItemWidth;
2059
2060 if (infoPtr->nItemWidth)
2061 horzInfo.nPage /= infoPtr->nItemWidth;
2062 }
2063 else if (infoPtr->uView == LV_VIEW_DETAILS)
2064 {
2065 horzInfo.nMax = infoPtr->nItemWidth;
2066 }
2067 else /* LV_VIEW_ICON, or LV_VIEW_SMALLICON */
2068 {
2069 RECT rcView;
2070
2071 if (LISTVIEW_GetViewRect(infoPtr, &rcView)) horzInfo.nMax = rcView.right - rcView.left;
2072 }
2073
2074 if (LISTVIEW_IsHeaderEnabled(infoPtr))
2075 {
2076 if (DPA_GetPtrCount(infoPtr->hdpaColumns))
2077 {
2078 RECT rcHeader;
2079 INT index;
2080
2082 DPA_GetPtrCount(infoPtr->hdpaColumns) - 1, 0);
2083
2084 LISTVIEW_GetHeaderRect(infoPtr, index, &rcHeader);
2085 horzInfo.nMax = rcHeader.right;
2086 TRACE("horzInfo.nMax=%d\n", horzInfo.nMax);
2087 }
2088 }
2089
2090 horzInfo.fMask = SIF_RANGE | SIF_PAGE;
2091 horzInfo.nMax = max(horzInfo.nMax - 1, 0);
2092#ifdef __REACTOS__ /* CORE-16466 part 1 of 4 */
2093 horzInfo.nMax = (horzInfo.nPage == 0 ? 0 : horzInfo.nMax);
2094#endif
2095 dx = GetScrollPos(infoPtr->hwndSelf, SB_HORZ);
2096 dx -= SetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &horzInfo, TRUE);
2097 TRACE("horzInfo=%s\n", debugscrollinfo(&horzInfo));
2098
2099 /* Update the Header Control */
2100 if (infoPtr->hwndHeader)
2101 {
2102 horzInfo.fMask = SIF_POS;
2103 GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &horzInfo);
2104 LISTVIEW_UpdateHeaderSize(infoPtr, horzInfo.nPos);
2105 }
2106
2107 LISTVIEW_UpdateSize(infoPtr);
2108 return dx;
2109}
2110
2112{
2113 SCROLLINFO vertInfo;
2114 INT dy;
2115
2116 ZeroMemory(&vertInfo, sizeof(SCROLLINFO));
2117 vertInfo.cbSize = sizeof(SCROLLINFO);
2118#ifdef __REACTOS__ /* CORE-16466 part 2 of 4 */
2119 vertInfo.nPage = max(0, infoPtr->rcList.bottom - infoPtr->rcList.top);
2120#else
2121 vertInfo.nPage = infoPtr->rcList.bottom - infoPtr->rcList.top;
2122#endif
2123
2124 if (infoPtr->uView == LV_VIEW_DETAILS)
2125 {
2126#ifdef __REACTOS__ /* CORE-16466 part 3a of 4 */
2127 if (vertInfo.nPage != 0)
2128 {
2129#endif
2130 vertInfo.nMax = infoPtr->nItemCount;
2131
2132 /* scroll by at least one page */
2133 if(vertInfo.nPage < infoPtr->nItemHeight)
2134 vertInfo.nPage = infoPtr->nItemHeight;
2135
2136 if (infoPtr->nItemHeight > 0)
2137 vertInfo.nPage /= infoPtr->nItemHeight;
2138#ifdef __REACTOS__ /* CORE-16466 part 3b of 4 */
2139 }
2140#endif
2141 }
2142 else if (infoPtr->uView != LV_VIEW_LIST) /* LV_VIEW_ICON, or LV_VIEW_SMALLICON */
2143 {
2144 RECT rcView;
2145
2146 if (LISTVIEW_GetViewRect(infoPtr, &rcView)) vertInfo.nMax = rcView.bottom - rcView.top;
2147 }
2148
2149 vertInfo.fMask = SIF_RANGE | SIF_PAGE;
2150 vertInfo.nMax = max(vertInfo.nMax - 1, 0);
2151#ifdef __REACTOS__ /* CORE-16466 part 4 of 4 */
2152 vertInfo.nMax = (vertInfo.nPage == 0 ? 0 : vertInfo.nMax);
2153#endif
2154 dy = GetScrollPos(infoPtr->hwndSelf, SB_VERT);
2155 dy -= SetScrollInfo(infoPtr->hwndSelf, SB_VERT, &vertInfo, TRUE);
2156 TRACE("vertInfo=%s\n", debugscrollinfo(&vertInfo));
2157
2158 LISTVIEW_UpdateSize(infoPtr);
2159 return dy;
2160}
2161
2162/***
2163 * DESCRIPTION:
2164 * Update the scrollbars. This function should be called whenever
2165 * the content, size or view changes.
2166 *
2167 * PARAMETER(S):
2168 * [I] infoPtr : valid pointer to the listview structure
2169 *
2170 * RETURN:
2171 * None
2172 */
2174{
2175 INT dx, dy, pass;
2176
2177 if ((infoPtr->dwStyle & LVS_NOSCROLL) || !is_redrawing(infoPtr)) return;
2178
2179 /* Setting the horizontal scroll can change the listview size
2180 * (and potentially everything else) so we need to recompute
2181 * everything again for the vertical scroll and vice-versa
2182 */
2183 for (dx = 0, dy = 0, pass = 0; pass <= 1; pass++)
2184 {
2185 dx += LISTVIEW_UpdateHScroll(infoPtr);
2186 dy += LISTVIEW_UpdateVScroll(infoPtr);
2187 }
2188
2189 /* Change of the range may have changed the scroll pos. If so move the content */
2190 if (dx != 0 || dy != 0)
2191 {
2192 RECT listRect;
2193 listRect = infoPtr->rcList;
2194 ScrollWindowEx(infoPtr->hwndSelf, dx, dy, &listRect, &listRect, 0, 0,
2196 }
2197}
2198
2199
2200/***
2201 * DESCRIPTION:
2202 * Shows/hides the focus rectangle.
2203 *
2204 * PARAMETER(S):
2205 * [I] infoPtr : valid pointer to the listview structure
2206 * [I] fShow : TRUE to show the focus, FALSE to hide it.
2207 *
2208 * RETURN:
2209 * None
2210 */
2211static void LISTVIEW_ShowFocusRect(const LISTVIEW_INFO *infoPtr, BOOL fShow)
2212{
2213 HDC hdc;
2214
2215 TRACE("fShow=%d, nItem=%d\n", fShow, infoPtr->nFocusedItem);
2216
2217 if (infoPtr->nFocusedItem < 0) return;
2218
2219 /* we need some gymnastics in ICON mode to handle large items */
2220 if (infoPtr->uView == LV_VIEW_ICON)
2221 {
2222 RECT rcBox;
2223
2224 LISTVIEW_GetItemBox(infoPtr, infoPtr->nFocusedItem, &rcBox);
2225 if ((rcBox.bottom - rcBox.top) > infoPtr->nItemHeight)
2226 {
2227 LISTVIEW_InvalidateRect(infoPtr, &rcBox);
2228 return;
2229 }
2230 }
2231
2232 if (!(hdc = GetDC(infoPtr->hwndSelf))) return;
2233
2234 /* for some reason, owner draw should work only in report mode */
2235 if ((infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && (infoPtr->uView == LV_VIEW_DETAILS))
2236 {
2237 DRAWITEMSTRUCT dis;
2238 LVITEMW item;
2239
2240 HFONT hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
2241 HFONT hOldFont = SelectObject(hdc, hFont);
2242
2243 item.iItem = infoPtr->nFocusedItem;
2244 item.iSubItem = 0;
2245 item.mask = LVIF_PARAM;
2246 if (!LISTVIEW_GetItemW(infoPtr, &item)) goto done;
2247
2248 ZeroMemory(&dis, sizeof(dis));
2249 dis.CtlType = ODT_LISTVIEW;
2250 dis.CtlID = (UINT)GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
2251 dis.itemID = item.iItem;
2252 dis.itemAction = ODA_FOCUS;
2253 if (fShow) dis.itemState |= ODS_FOCUS;
2254 dis.hwndItem = infoPtr->hwndSelf;
2255 dis.hDC = hdc;
2256 LISTVIEW_GetItemBox(infoPtr, dis.itemID, &dis.rcItem);
2257 dis.itemData = item.lParam;
2258
2259 SendMessageW(infoPtr->hwndNotify, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis);
2260
2261 SelectObject(hdc, hOldFont);
2262 }
2263 else
2264 LISTVIEW_InvalidateItem(infoPtr, infoPtr->nFocusedItem);
2265
2266done:
2267 ReleaseDC(infoPtr->hwndSelf, hdc);
2268}
2269
2270/***
2271 * Invalidates all visible selected items.
2272 */
2274{
2275 ITERATOR i;
2276
2277 iterator_frameditems(&i, infoPtr, &infoPtr->rcList);
2278 while(iterator_next(&i))
2279 {
2280 if (LISTVIEW_GetItemState(infoPtr, i.nItem, LVIS_SELECTED))
2281 LISTVIEW_InvalidateItem(infoPtr, i.nItem);
2282 }
2284}
2285
2286
2287/***
2288 * DESCRIPTION: [INTERNAL]
2289 * Computes an item's (left,top) corner, relative to rcView.
2290 * That is, the position has NOT been made relative to the Origin.
2291 * This is deliberate, to avoid computing the Origin over, and
2292 * over again, when this function is called in a loop. Instead,
2293 * one can factor the computation of the Origin before the loop,
2294 * and offset the value returned by this function, on every iteration.
2295 *
2296 * PARAMETER(S):
2297 * [I] infoPtr : valid pointer to the listview structure
2298 * [I] nItem : item number
2299 * [O] lpptOrig : item top, left corner
2300 *
2301 * RETURN:
2302 * None.
2303 */
2304static void LISTVIEW_GetItemOrigin(const LISTVIEW_INFO *infoPtr, INT nItem, LPPOINT lpptPosition)
2305{
2306 assert(nItem >= 0 && nItem < infoPtr->nItemCount);
2307
2308 if ((infoPtr->uView == LV_VIEW_SMALLICON) || (infoPtr->uView == LV_VIEW_ICON))
2309 {
2310 lpptPosition->x = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosX, nItem);
2311 lpptPosition->y = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosY, nItem);
2312 }
2313 else if (infoPtr->uView == LV_VIEW_LIST)
2314 {
2315 INT nCountPerColumn = LISTVIEW_GetCountPerColumn(infoPtr);
2316 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
2317 lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight;
2318 }
2319 else /* LV_VIEW_DETAILS */
2320 {
2321 lpptPosition->x = REPORT_MARGINX;
2322 /* item is always at zero indexed column */
2323 if (DPA_GetPtrCount(infoPtr->hdpaColumns) > 0)
2324 lpptPosition->x += LISTVIEW_GetColumnInfo(infoPtr, 0)->rcHeader.left;
2325 lpptPosition->y = nItem * infoPtr->nItemHeight;
2326 }
2327}
2328
2329/***
2330 * DESCRIPTION: [INTERNAL]
2331 * Compute the rectangles of an item. This is to localize all
2332 * the computations in one place. If you are not interested in some
2333 * of these values, simply pass in a NULL -- the function is smart
2334 * enough to compute only what's necessary. The function computes
2335 * the standard rectangles (BOUNDS, ICON, LABEL) plus a non-standard
2336 * one, the BOX rectangle. This rectangle is very cheap to compute,
2337 * and is guaranteed to contain all the other rectangles. Computing
2338 * the ICON rect is also cheap, but all the others are potentially
2339 * expensive. This gives an easy and effective optimization when
2340 * searching (like point inclusion, or rectangle intersection):
2341 * first test against the BOX, and if TRUE, test against the desired
2342 * rectangle.
2343 * If the function does not have all the necessary information
2344 * to computed the requested rectangles, will crash with a
2345 * failed assertion. This is done so we catch all programming
2346 * errors, given that the function is called only from our code.
2347 *
2348 * We have the following 'special' meanings for a few fields:
2349 * * If LVIS_FOCUSED is set, we assume the item has the focus
2350 * This is important in ICON mode, where it might get a larger
2351 * then usual rectangle
2352 *
2353 * Please note that subitem support works only in REPORT mode.
2354 *
2355 * PARAMETER(S):
2356 * [I] infoPtr : valid pointer to the listview structure
2357 * [I] lpLVItem : item to compute the measures for
2358 * [O] lprcBox : ptr to Box rectangle
2359 * Same as LVM_GETITEMRECT with LVIR_BOUNDS
2360 * [0] lprcSelectBox : ptr to select box rectangle
2361 * Same as LVM_GETITEMRECT with LVIR_SELECTEDBOUNDS
2362 * [O] lprcIcon : ptr to Icon rectangle
2363 * Same as LVM_GETITEMRECT with LVIR_ICON
2364 * [O] lprcStateIcon: ptr to State Icon rectangle
2365 * [O] lprcLabel : ptr to Label rectangle
2366 * Same as LVM_GETITEMRECT with LVIR_LABEL
2367 *
2368 * RETURN:
2369 * None.
2370 */
2371static void LISTVIEW_GetItemMetrics(const LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem,
2372 LPRECT lprcBox, LPRECT lprcSelectBox,
2373 LPRECT lprcIcon, LPRECT lprcStateIcon, LPRECT lprcLabel)
2374{
2375 BOOL doSelectBox = FALSE, doIcon = FALSE, doLabel = FALSE, oversizedBox = FALSE;
2376 RECT Box, SelectBox, Icon, Label;
2377 COLUMN_INFO *lpColumnInfo = NULL;
2378 SIZE labelSize = { 0, 0 };
2379
2380 TRACE("(lpLVItem=%s)\n", debuglvitem_t(lpLVItem, TRUE));
2381
2382 /* Be smart and try to figure out the minimum we have to do */
2383 if (lpLVItem->iSubItem) assert(infoPtr->uView == LV_VIEW_DETAILS);
2384 if (infoPtr->uView == LV_VIEW_ICON && (lprcBox || lprcLabel))
2385 {
2386 assert((lpLVItem->mask & LVIF_STATE) && (lpLVItem->stateMask & LVIS_FOCUSED));
2387 if (lpLVItem->state & LVIS_FOCUSED) oversizedBox = doLabel = TRUE;
2388 }
2389 if (lprcSelectBox) doSelectBox = TRUE;
2390 if (lprcLabel) doLabel = TRUE;
2391 if (doLabel || lprcIcon || lprcStateIcon) doIcon = TRUE;
2392 if (doSelectBox)
2393 {
2394 doIcon = TRUE;
2395 doLabel = TRUE;
2396 }
2397
2398 /************************************************************/
2399 /* compute the box rectangle (it should be cheap to do) */
2400 /************************************************************/
2401 if (lpLVItem->iSubItem || infoPtr->uView == LV_VIEW_DETAILS)
2402 lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, lpLVItem->iSubItem);
2403
2404 if (lpLVItem->iSubItem)
2405 {
2406 Box = lpColumnInfo->rcHeader;
2407 }
2408 else
2409 {
2410 Box.left = 0;
2411 Box.right = infoPtr->nItemWidth;
2412 }
2413 Box.top = 0;
2414 Box.bottom = infoPtr->nItemHeight;
2415
2416 /******************************************************************/
2417 /* compute ICON bounding box (ala LVM_GETITEMRECT) and STATEICON */
2418 /******************************************************************/
2419 if (doIcon)
2420 {
2421 LONG state_width = 0;
2422
2423 if (infoPtr->himlState && lpLVItem->iSubItem == 0)
2424 state_width = infoPtr->iconStateSize.cx;
2425
2426 if (infoPtr->uView == LV_VIEW_ICON)
2427 {
2428 Icon.left = Box.left + state_width;
2429 if (infoPtr->himlNormal)
2430 Icon.left += (infoPtr->nItemWidth - infoPtr->iconSize.cx - state_width) / 2;
2431 Icon.top = Box.top + ICON_TOP_PADDING;
2432 Icon.right = Icon.left;
2433 Icon.bottom = Icon.top;
2434 if (infoPtr->himlNormal)
2435 {
2436 Icon.right += infoPtr->iconSize.cx;
2437 Icon.bottom += infoPtr->iconSize.cy;
2438 }
2439 }
2440 else /* LV_VIEW_SMALLICON, LV_VIEW_LIST or LV_VIEW_DETAILS */
2441 {
2442 Icon.left = Box.left + state_width;
2443
2444 if (infoPtr->uView == LV_VIEW_DETAILS && lpLVItem->iSubItem == 0)
2445 {
2446 /* we need the indent in report mode */
2447 assert(lpLVItem->mask & LVIF_INDENT);
2448 Icon.left += infoPtr->iconSize.cx * lpLVItem->iIndent + REPORT_MARGINX;
2449 }
2450
2451 Icon.top = Box.top;
2452 Icon.right = Icon.left;
2453 if (infoPtr->himlSmall &&
2454 (!lpColumnInfo || lpLVItem->iSubItem == 0 ||
2455 ((infoPtr->dwLvExStyle & LVS_EX_SUBITEMIMAGES) && lpLVItem->iImage != I_IMAGECALLBACK)))
2456 Icon.right += infoPtr->iconSize.cx;
2457 Icon.bottom = Icon.top + infoPtr->iconSize.cy;
2458 }
2459 if(lprcIcon) *lprcIcon = Icon;
2460 TRACE(" - icon=%s\n", wine_dbgstr_rect(&Icon));
2461
2462 /* TODO: is this correct? */
2463 if (lprcStateIcon)
2464 {
2465 lprcStateIcon->left = Icon.left - state_width;
2466 lprcStateIcon->right = Icon.left;
2467 lprcStateIcon->top = Icon.top;
2468 lprcStateIcon->bottom = lprcStateIcon->top + infoPtr->iconSize.cy;
2469 TRACE(" - state icon=%s\n", wine_dbgstr_rect(lprcStateIcon));
2470 }
2471 }
2472 else Icon.right = 0;
2473
2474 /************************************************************/
2475 /* compute LABEL bounding box (ala LVM_GETITEMRECT) */
2476 /************************************************************/
2477 if (doLabel)
2478 {
2479 /* calculate how far to the right can the label stretch */
2480 Label.right = Box.right;
2481 if (infoPtr->uView == LV_VIEW_DETAILS)
2482 {
2483 if (lpLVItem->iSubItem == 0)
2484 {
2485 /* we need a zero based rect here */
2486 Label = lpColumnInfo->rcHeader;
2487 OffsetRect(&Label, -Label.left, 0);
2488 }
2489 }
2490
2491 if (lpLVItem->iSubItem || ((infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && infoPtr->uView == LV_VIEW_DETAILS))
2492 {
2493 labelSize.cx = infoPtr->nItemWidth;
2494 labelSize.cy = infoPtr->nItemHeight;
2495 goto calc_label;
2496 }
2497
2498 /* we need the text in non owner draw mode */
2499 assert(lpLVItem->mask & LVIF_TEXT);
2500 if (is_text(lpLVItem->pszText))
2501 {
2502 HFONT hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
2503 HDC hdc = GetDC(infoPtr->hwndSelf);
2504 HFONT hOldFont = SelectObject(hdc, hFont);
2505 UINT uFormat;
2506 RECT rcText;
2507
2508 /* compute rough rectangle where the label will go */
2509 SetRectEmpty(&rcText);
2510 rcText.right = infoPtr->nItemWidth - TRAILING_LABEL_PADDING;
2511 rcText.bottom = infoPtr->nItemHeight;
2512 if (infoPtr->uView == LV_VIEW_ICON)
2513 rcText.bottom -= ICON_TOP_PADDING + infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
2514
2515 /* now figure out the flags */
2516 if (infoPtr->uView == LV_VIEW_ICON)
2517 uFormat = oversizedBox ? LV_FL_DT_FLAGS : LV_ML_DT_FLAGS;
2518 else
2519 uFormat = LV_SL_DT_FLAGS;
2520
2521 DrawTextW (hdc, lpLVItem->pszText, -1, &rcText, uFormat | DT_CALCRECT);
2522
2523 if (rcText.right != rcText.left)
2524 labelSize.cx = min(rcText.right - rcText.left + TRAILING_LABEL_PADDING, infoPtr->nItemWidth);
2525
2526 labelSize.cy = rcText.bottom - rcText.top;
2527
2528 SelectObject(hdc, hOldFont);
2529 ReleaseDC(infoPtr->hwndSelf, hdc);
2530 }
2531
2532calc_label:
2533 if (infoPtr->uView == LV_VIEW_ICON)
2534 {
2535 Label.left = Box.left + (infoPtr->nItemWidth - labelSize.cx) / 2;
2536 Label.top = Box.top + ICON_TOP_PADDING_HITABLE +
2537 infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
2538 Label.right = Label.left + labelSize.cx;
2539 Label.bottom = Label.top + infoPtr->nItemHeight;
2540 if (!oversizedBox && labelSize.cy > infoPtr->ntmHeight)
2541 {
2542 labelSize.cy = min(Box.bottom - Label.top, labelSize.cy);
2543 labelSize.cy /= infoPtr->ntmHeight;
2544 labelSize.cy = max(labelSize.cy, 1);
2545 labelSize.cy *= infoPtr->ntmHeight;
2546 }
2547 Label.bottom = Label.top + labelSize.cy + HEIGHT_PADDING;
2548 }
2549 else if (infoPtr->uView == LV_VIEW_DETAILS)
2550 {
2551 Label.left = Icon.right;
2552 Label.top = Box.top;
2553 Label.right = lpLVItem->iSubItem ? lpColumnInfo->rcHeader.right :
2554 lpColumnInfo->rcHeader.right - lpColumnInfo->rcHeader.left;
2555 Label.bottom = Label.top + infoPtr->nItemHeight;
2556 }
2557 else /* LV_VIEW_SMALLICON or LV_VIEW_LIST */
2558 {
2559 Label.left = Icon.right;
2560 Label.top = Box.top;
2561 Label.right = min(Label.left + labelSize.cx, Label.right);
2562 Label.bottom = Label.top + infoPtr->nItemHeight;
2563 }
2564
2565 if (lprcLabel) *lprcLabel = Label;
2566 TRACE(" - label=%s\n", wine_dbgstr_rect(&Label));
2567 }
2568
2569 /************************************************************/
2570 /* compute SELECT bounding box */
2571 /************************************************************/
2572 if (doSelectBox)
2573 {
2574 if (infoPtr->uView == LV_VIEW_DETAILS)
2575 {
2576 SelectBox.left = Icon.left;
2577 SelectBox.top = Box.top;
2578 SelectBox.bottom = Box.bottom;
2579
2580 if (labelSize.cx)
2581 SelectBox.right = min(Label.left + labelSize.cx, Label.right);
2582 else
2583 SelectBox.right = min(Label.left + MAX_EMPTYTEXT_SELECT_WIDTH, Label.right);
2584 }
2585 else
2586 {
2587 UnionRect(&SelectBox, &Icon, &Label);
2588 }
2589 if (lprcSelectBox) *lprcSelectBox = SelectBox;
2590 TRACE(" - select box=%s\n", wine_dbgstr_rect(&SelectBox));
2591 }
2592
2593 /* Fix the Box if necessary */
2594 if (lprcBox)
2595 {
2596 if (oversizedBox) UnionRect(lprcBox, &Box, &Label);
2597 else *lprcBox = Box;
2598 }
2599 TRACE(" - box=%s\n", wine_dbgstr_rect(&Box));
2600}
2601
2602/***
2603 * DESCRIPTION: [INTERNAL]
2604 *
2605 * PARAMETER(S):
2606 * [I] infoPtr : valid pointer to the listview structure
2607 * [I] nItem : item number
2608 * [O] lprcBox : ptr to Box rectangle
2609 *
2610 * RETURN:
2611 * None.
2612 */
2613static void LISTVIEW_GetItemBox(const LISTVIEW_INFO *infoPtr, INT nItem, LPRECT lprcBox)
2614{
2615 WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
2616 POINT Position, Origin;
2617 LVITEMW lvItem;
2618
2619 LISTVIEW_GetOrigin(infoPtr, &Origin);
2620 LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position);
2621
2622 /* Be smart and try to figure out the minimum we have to do */
2623 lvItem.mask = 0;
2624 if (infoPtr->uView == LV_VIEW_ICON && infoPtr->bFocus && LISTVIEW_GetItemState(infoPtr, nItem, LVIS_FOCUSED))
2625 lvItem.mask |= LVIF_TEXT;
2626 lvItem.iItem = nItem;
2627 lvItem.iSubItem = 0;
2628 lvItem.pszText = szDispText;
2629 lvItem.cchTextMax = DISP_TEXT_SIZE;
2630 if (lvItem.mask) LISTVIEW_GetItemW(infoPtr, &lvItem);
2631 if (infoPtr->uView == LV_VIEW_ICON)
2632 {
2633 lvItem.mask |= LVIF_STATE;
2634 lvItem.stateMask = LVIS_FOCUSED;
2635 lvItem.state = (lvItem.mask & LVIF_TEXT ? LVIS_FOCUSED : 0);
2636 }
2637 LISTVIEW_GetItemMetrics(infoPtr, &lvItem, lprcBox, 0, 0, 0, 0);
2638
2639 if (infoPtr->uView == LV_VIEW_DETAILS && infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT &&
2640 SendMessageW(infoPtr->hwndHeader, HDM_ORDERTOINDEX, 0, 0))
2641 {
2642 OffsetRect(lprcBox, Origin.x, Position.y + Origin.y);
2643 }
2644 else
2645 OffsetRect(lprcBox, Position.x + Origin.x, Position.y + Origin.y);
2646}
2647
2648/* LISTVIEW_MapIdToIndex helper */
2650{
2651 ITEM_ID *id1 = (ITEM_ID*)p1;
2652 ITEM_ID *id2 = (ITEM_ID*)p2;
2653
2654 if (id1->id == id2->id) return 0;
2655
2656 return (id1->id < id2->id) ? -1 : 1;
2657}
2658
2659/***
2660 * DESCRIPTION:
2661 * Returns the item index for id specified.
2662 *
2663 * PARAMETER(S):
2664 * [I] infoPtr : valid pointer to the listview structure
2665 * [I] iID : item id to get index for
2666 *
2667 * RETURN:
2668 * Item index, or -1 on failure.
2669 */
2670static INT LISTVIEW_MapIdToIndex(const LISTVIEW_INFO *infoPtr, UINT iID)
2671{
2672 ITEM_ID ID;
2673 INT index;
2674
2675 TRACE("iID=%d\n", iID);
2676
2677 if (infoPtr->dwStyle & LVS_OWNERDATA) return -1;
2678 if (infoPtr->nItemCount == 0) return -1;
2679
2680 ID.id = iID;
2682
2683 if (index != -1)
2684 {
2685 ITEM_ID *lpID = DPA_GetPtr(infoPtr->hdpaItemIds, index);
2686 return DPA_GetPtrIndex(infoPtr->hdpaItems, lpID->item);
2687 }
2688
2689 return -1;
2690}
2691
2692/***
2693 * DESCRIPTION:
2694 * Returns the item id for index given.
2695 *
2696 * PARAMETER(S):
2697 * [I] infoPtr : valid pointer to the listview structure
2698 * [I] iItem : item index to get id for
2699 *
2700 * RETURN:
2701 * Item id.
2702 */
2703static DWORD LISTVIEW_MapIndexToId(const LISTVIEW_INFO *infoPtr, INT iItem)
2704{
2705 ITEM_INFO *lpItem;
2706 HDPA hdpaSubItems;
2707
2708 TRACE("iItem=%d\n", iItem);
2709
2710 if (infoPtr->dwStyle & LVS_OWNERDATA) return -1;
2711 if (iItem < 0 || iItem >= infoPtr->nItemCount) return -1;
2712
2713 hdpaSubItems = DPA_GetPtr(infoPtr->hdpaItems, iItem);
2714 lpItem = DPA_GetPtr(hdpaSubItems, 0);
2715
2716 return lpItem->id->id;
2717}
2718
2719/***
2720 * DESCRIPTION:
2721 * Returns the current icon position, and advances it along the top.
2722 * The returned position is not offset by Origin.
2723 *
2724 * PARAMETER(S):
2725 * [I] infoPtr : valid pointer to the listview structure
2726 * [O] lpPos : will get the current icon position
2727 * [I] nItem : item id to get position for
2728 *
2729 * RETURN:
2730 * None
2731 */
2732#ifdef __REACTOS__
2733static void LISTVIEW_NextIconPosTop(LISTVIEW_INFO *infoPtr, LPPOINT lpPos, INT nItem)
2734#else
2736#endif
2737{
2738 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
2739
2740 *lpPos = infoPtr->currIconPos;
2741
2742 infoPtr->currIconPos.x += infoPtr->nItemWidth;
2743 if (infoPtr->currIconPos.x + infoPtr->nItemWidth <= nListWidth) return;
2744
2745 infoPtr->currIconPos.x = 0;
2746 infoPtr->currIconPos.y += infoPtr->nItemHeight;
2747}
2748
2749
2750/***
2751 * DESCRIPTION:
2752 * Returns the current icon position, and advances it down the left edge.
2753 * The returned position is not offset by Origin.
2754 *
2755 * PARAMETER(S):
2756 * [I] infoPtr : valid pointer to the listview structure
2757 * [O] lpPos : will get the current icon position
2758 * [I] nItem : item id to get position for
2759 *
2760 * RETURN:
2761 * None
2762 */
2763#ifdef __REACTOS__
2764static void LISTVIEW_NextIconPosLeft(LISTVIEW_INFO *infoPtr, LPPOINT lpPos, INT nItem)
2765#else
2767#endif
2768{
2769 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2770
2771 *lpPos = infoPtr->currIconPos;
2772
2773 infoPtr->currIconPos.y += infoPtr->nItemHeight;
2774 if (infoPtr->currIconPos.y + infoPtr->nItemHeight <= nListHeight) return;
2775
2776 infoPtr->currIconPos.x += infoPtr->nItemWidth;
2777 infoPtr->currIconPos.y = 0;
2778}
2779
2780
2781#ifdef __REACTOS__
2782/***
2783 * DESCRIPTION:
2784 * Returns the grid position closest to the already placed icon.
2785 * The returned position is not offset by Origin.
2786 *
2787 * PARAMETER(S):
2788 * [I] infoPtr : valid pointer to the listview structure
2789 * [O] lpPos : will get the current icon position
2790 * [I] nItem : item id to get position for
2791 *
2792 * RETURN:
2793 * None
2794 */
2795static void LISTVIEW_NextIconPosSnap(LISTVIEW_INFO *infoPtr, LPPOINT lpPos, INT nItem)
2796{
2797 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2798 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
2799 INT nMaxColumns = nListWidth / infoPtr->nItemWidth;
2800 INT nMaxRows = nListHeight / infoPtr->nItemHeight;
2801 POINT oldPosition;
2802
2803 // get the existing x and y position and then snap to the closest grid square
2804 oldPosition.x = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosX, nItem);
2805 oldPosition.y = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosY, nItem);
2806
2807 // FIXME: This could should deal with multiple icons in the same grid square
2808 // equivalent of max(0, round(oldPosition / itemSize) * itemSize), but without need for 'round' function
2809 (*lpPos).x = max(0, oldPosition.x + (infoPtr->nItemWidth >> 1) - (oldPosition.x + (infoPtr->nItemWidth >> 1)) % infoPtr->nItemWidth);
2810 (*lpPos).y = max(0, oldPosition.y + (infoPtr->nItemHeight >> 1) - (oldPosition.y + (infoPtr->nItemHeight >> 1)) % infoPtr->nItemHeight);
2811
2812 // deal with any icons that have gone out of range
2813 if ((*lpPos).x > nListWidth) (*lpPos).x = nMaxColumns * infoPtr->nItemWidth;
2814 if ((*lpPos).y > nListHeight) (*lpPos).y = nMaxRows * infoPtr->nItemHeight;
2815}
2816#endif
2817
2818
2819/***
2820 * DESCRIPTION:
2821 * Moves an icon to the specified position.
2822 * It takes care of invalidating the item, etc.
2823 *
2824 * PARAMETER(S):
2825 * [I] infoPtr : valid pointer to the listview structure
2826 * [I] nItem : the item to move
2827 * [I] lpPos : the new icon position
2828 * [I] isNew : flags the item as being new
2829 *
2830 * RETURN:
2831 * Success: TRUE
2832 * Failure: FALSE
2833 */
2834static BOOL LISTVIEW_MoveIconTo(const LISTVIEW_INFO *infoPtr, INT nItem, const POINT *lppt, BOOL isNew)
2835{
2836 POINT old;
2837
2838 if (!isNew)
2839 {
2840 old.x = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosX, nItem);
2841 old.y = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosY, nItem);
2842
2843 if (lppt->x == old.x && lppt->y == old.y) return TRUE;
2844 LISTVIEW_InvalidateItem(infoPtr, nItem);
2845 }
2846
2847 /* Allocating a POINTER for every item is too resource intensive,
2848 * so we'll keep the (x,y) in different arrays */
2849 if (!DPA_SetPtr(infoPtr->hdpaPosX, nItem, (void *)(LONG_PTR)lppt->x)) return FALSE;
2850 if (!DPA_SetPtr(infoPtr->hdpaPosY, nItem, (void *)(LONG_PTR)lppt->y)) return FALSE;
2851
2852 LISTVIEW_InvalidateItem(infoPtr, nItem);
2853
2854 return TRUE;
2855}
2856
2857/***
2858 * DESCRIPTION:
2859 * Arranges listview items in icon display mode.
2860 *
2861 * PARAMETER(S):
2862 * [I] infoPtr : valid pointer to the listview structure
2863 * [I] nAlignCode : alignment code
2864 *
2865 * RETURN:
2866 * SUCCESS : TRUE
2867 * FAILURE : FALSE
2868 */
2869static BOOL LISTVIEW_Arrange(LISTVIEW_INFO *infoPtr, INT nAlignCode)
2870{
2871#ifdef __REACTOS__
2872 void (*next_pos)(LISTVIEW_INFO *, LPPOINT, INT);
2873#else
2874 void (*next_pos)(LISTVIEW_INFO *, LPPOINT);
2875#endif
2876 POINT pos;
2877 INT i;
2878
2879 if (infoPtr->uView != LV_VIEW_ICON && infoPtr->uView != LV_VIEW_SMALLICON) return FALSE;
2880
2881 TRACE("nAlignCode=%d\n", nAlignCode);
2882
2883 if (nAlignCode == LVA_DEFAULT)
2884 {
2885 if (infoPtr->dwStyle & LVS_ALIGNLEFT) nAlignCode = LVA_ALIGNLEFT;
2886 else nAlignCode = LVA_ALIGNTOP;
2887 }
2888
2889 switch (nAlignCode)
2890 {
2891 case LVA_ALIGNLEFT: next_pos = LISTVIEW_NextIconPosLeft; break;
2892 case LVA_ALIGNTOP: next_pos = LISTVIEW_NextIconPosTop; break;
2893#ifdef __REACTOS__
2894 case LVA_SNAPTOGRID: next_pos = LISTVIEW_NextIconPosSnap; break;
2895#else
2896 case LVA_SNAPTOGRID: next_pos = LISTVIEW_NextIconPosTop; break; /* FIXME */
2897#endif
2898 default: return FALSE;
2899 }
2900
2901 infoPtr->currIconPos.x = infoPtr->currIconPos.y = 0;
2902 for (i = 0; i < infoPtr->nItemCount; i++)
2903 {
2904#ifdef __REACTOS__
2905 next_pos(infoPtr, &pos, i);
2906#else
2907 next_pos(infoPtr, &pos);
2908#endif
2909 LISTVIEW_MoveIconTo(infoPtr, i, &pos, FALSE);
2910 }
2911
2912 return TRUE;
2913}
2914
2915/***
2916 * DESCRIPTION:
2917 * Retrieves the bounding rectangle of all the items, not offset by Origin.
2918 * For LVS_REPORT always returns empty rectangle.
2919 *
2920 * PARAMETER(S):
2921 * [I] infoPtr : valid pointer to the listview structure
2922 * [O] lprcView : bounding rectangle
2923 *
2924 * RETURN:
2925 * SUCCESS : TRUE
2926 * FAILURE : FALSE
2927 */
2928static void LISTVIEW_GetAreaRect(const LISTVIEW_INFO *infoPtr, LPRECT lprcView)
2929{
2930 INT i, x, y;
2931
2932 SetRectEmpty(lprcView);
2933
2934 switch (infoPtr->uView)
2935 {
2936 case LV_VIEW_ICON:
2937 case LV_VIEW_SMALLICON:
2938 for (i = 0; i < infoPtr->nItemCount; i++)
2939 {
2940 x = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosX, i);
2941 y = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosY, i);
2942 lprcView->right = max(lprcView->right, x);
2943 lprcView->bottom = max(lprcView->bottom, y);
2944 }
2945 if (infoPtr->nItemCount > 0)
2946 {
2947 lprcView->right += infoPtr->nItemWidth;
2948 lprcView->bottom += infoPtr->nItemHeight;
2949 }
2950 break;
2951
2952 case LV_VIEW_LIST:
2953 y = LISTVIEW_GetCountPerColumn(infoPtr);
2954 x = infoPtr->nItemCount / y;
2955 if (infoPtr->nItemCount % y) x++;
2956 lprcView->right = x * infoPtr->nItemWidth;
2957 lprcView->bottom = y * infoPtr->nItemHeight;
2958 break;
2959 }
2960}
2961
2962/***
2963 * DESCRIPTION:
2964 * Retrieves the bounding rectangle of all the items.
2965 *
2966 * PARAMETER(S):
2967 * [I] infoPtr : valid pointer to the listview structure
2968 * [O] lprcView : bounding rectangle
2969 *
2970 * RETURN:
2971 * SUCCESS : TRUE
2972 * FAILURE : FALSE
2973 */
2974static BOOL LISTVIEW_GetViewRect(const LISTVIEW_INFO *infoPtr, LPRECT lprcView)
2975{
2976 POINT ptOrigin;
2977
2978 TRACE("(lprcView=%p)\n", lprcView);
2979
2980 if (!lprcView) return FALSE;
2981
2982 LISTVIEW_GetAreaRect(infoPtr, lprcView);
2983
2984 if (infoPtr->uView != LV_VIEW_DETAILS)
2985 {
2986 LISTVIEW_GetOrigin(infoPtr, &ptOrigin);
2987 OffsetRect(lprcView, ptOrigin.x, ptOrigin.y);
2988 }
2989
2990 TRACE("lprcView=%s\n", wine_dbgstr_rect(lprcView));
2991
2992 return TRUE;
2993}
2994
2995/***
2996 * DESCRIPTION:
2997 * Retrieves the subitem pointer associated with the subitem index.
2998 *
2999 * PARAMETER(S):
3000 * [I] hdpaSubItems : DPA handle for a specific item
3001 * [I] nSubItem : index of subitem
3002 *
3003 * RETURN:
3004 * SUCCESS : subitem pointer
3005 * FAILURE : NULL
3006 */
3007static SUBITEM_INFO* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems, INT nSubItem)
3008{
3009 SUBITEM_INFO *lpSubItem;
3010 INT i;
3011
3012 /* we should binary search here if need be */
3013 for (i = 1; i < DPA_GetPtrCount(hdpaSubItems); i++)
3014 {
3015 lpSubItem = DPA_GetPtr(hdpaSubItems, i);
3016 if (lpSubItem->iSubItem == nSubItem)
3017 return lpSubItem;
3018 }
3019
3020 return NULL;
3021}
3022
3023
3024/***
3025 * DESCRIPTION:
3026 * Calculates the desired item width.
3027 *
3028 * PARAMETER(S):
3029 * [I] infoPtr : valid pointer to the listview structure
3030 *
3031 * RETURN:
3032 * The desired item width.
3033 */
3035{
3036 INT nItemWidth = 0;
3037
3038 TRACE("uView=%d\n", infoPtr->uView);
3039
3040 if (infoPtr->uView == LV_VIEW_ICON)
3041 nItemWidth = infoPtr->iconSpacing.cx;
3042 else if (infoPtr->uView == LV_VIEW_DETAILS)
3043 {
3044 if (DPA_GetPtrCount(infoPtr->hdpaColumns) > 0)
3045 {
3046 RECT rcHeader;
3047 INT index;
3048
3050 DPA_GetPtrCount(infoPtr->hdpaColumns) - 1, 0);
3051
3052 LISTVIEW_GetHeaderRect(infoPtr, index, &rcHeader);
3053 nItemWidth = rcHeader.right;
3054 }
3055 }
3056 else /* LV_VIEW_SMALLICON, or LV_VIEW_LIST */
3057 {
3058 WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
3059 LVITEMW lvItem;
3060 INT i;
3061
3062 lvItem.mask = LVIF_TEXT;
3063 lvItem.iSubItem = 0;
3064
3065 for (i = 0; i < infoPtr->nItemCount; i++)
3066 {
3067 lvItem.iItem = i;
3068 lvItem.pszText = szDispText;
3069 lvItem.cchTextMax = DISP_TEXT_SIZE;
3070 if (LISTVIEW_GetItemW(infoPtr, &lvItem))
3071 nItemWidth = max(LISTVIEW_GetStringWidthT(infoPtr, lvItem.pszText, TRUE),
3072 nItemWidth);
3073 }
3074
3075 if (infoPtr->himlSmall) nItemWidth += infoPtr->iconSize.cx;
3076 if (infoPtr->himlState) nItemWidth += infoPtr->iconStateSize.cx;
3077
3078 nItemWidth = max(DEFAULT_COLUMN_WIDTH, nItemWidth + WIDTH_PADDING);
3079 }
3080
3081 return nItemWidth;
3082}
3083
3084/***
3085 * DESCRIPTION:
3086 * Calculates the desired item height.
3087 *
3088 * PARAMETER(S):
3089 * [I] infoPtr : valid pointer to the listview structure
3090 *
3091 * RETURN:
3092 * The desired item height.
3093 */
3095{
3096 INT nItemHeight;
3097
3098 TRACE("uView=%d\n", infoPtr->uView);
3099
3100 if (infoPtr->uView == LV_VIEW_ICON)
3101 nItemHeight = infoPtr->iconSpacing.cy;
3102 else
3103 {
3104 nItemHeight = infoPtr->ntmHeight;
3105 if (infoPtr->himlState)
3106 nItemHeight = max(nItemHeight, infoPtr->iconStateSize.cy);
3107 if (infoPtr->himlSmall)
3108 nItemHeight = max(nItemHeight, infoPtr->iconSize.cy);
3109 nItemHeight += HEIGHT_PADDING;
3110 if (infoPtr->nMeasureItemHeight > 0)
3111 nItemHeight = infoPtr->nMeasureItemHeight;
3112 }
3113
3114 return max(nItemHeight, 1);
3115}
3116
3117/***
3118 * DESCRIPTION:
3119 * Updates the width, and height of an item.
3120 *
3121 * PARAMETER(S):
3122 * [I] infoPtr : valid pointer to the listview structure
3123 *
3124 * RETURN:
3125 * None.
3126 */
3127static inline void LISTVIEW_UpdateItemSize(LISTVIEW_INFO *infoPtr)
3128{
3129 infoPtr->nItemWidth = LISTVIEW_CalculateItemWidth(infoPtr);
3130 infoPtr->nItemHeight = LISTVIEW_CalculateItemHeight(infoPtr);
3131}
3132
3133
3134/***
3135 * DESCRIPTION:
3136 * Retrieves and saves important text metrics info for the current
3137 * Listview font.
3138 *
3139 * PARAMETER(S):
3140 * [I] infoPtr : valid pointer to the listview structure
3141 *
3142 */
3144{
3145 HDC hdc = GetDC(infoPtr->hwndSelf);
3146 HFONT hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
3147 HFONT hOldFont = SelectObject(hdc, hFont);
3149 SIZE sz;
3150
3151 if (GetTextMetricsW(hdc, &tm))
3152 {
3153 infoPtr->ntmHeight = tm.tmHeight;
3154 infoPtr->ntmMaxCharWidth = tm.tmMaxCharWidth;
3155 }
3156
3157 if (GetTextExtentPoint32A(hdc, "...", 3, &sz))
3158 infoPtr->nEllipsisWidth = sz.cx;
3159
3160 SelectObject(hdc, hOldFont);
3161 ReleaseDC(infoPtr->hwndSelf, hdc);
3162
3163 TRACE("tmHeight=%d\n", infoPtr->ntmHeight);
3164}
3165
3166/***
3167 * DESCRIPTION:
3168 * A compare function for ranges
3169 *
3170 * PARAMETER(S)
3171 * [I] range1 : pointer to range 1;
3172 * [I] range2 : pointer to range 2;
3173 * [I] flags : flags
3174 *
3175 * RETURNS:
3176 * > 0 : if range 1 > range 2
3177 * < 0 : if range 2 > range 1
3178 * = 0 : if range intersects range 2
3179 */
3181{
3182 INT cmp;
3183
3184 if (((RANGE*)range1)->upper <= ((RANGE*)range2)->lower)
3185 cmp = -1;
3186 else if (((RANGE*)range2)->upper <= ((RANGE*)range1)->lower)
3187 cmp = 1;
3188 else
3189 cmp = 0;
3190
3191 TRACE("range1=%s, range2=%s, cmp=%d\n", debugrange(range1), debugrange(range2), cmp);
3192
3193 return cmp;
3194}
3195
3196#define ranges_check(ranges, desc) if (TRACE_ON(listview)) ranges_assert(ranges, desc, __FILE__, __LINE__)
3197
3198static void ranges_assert(RANGES ranges, LPCSTR desc, const char *file, int line)
3199{
3200 INT i;
3201 RANGE *prev, *curr;
3202
3203 TRACE("*** Checking %s:%d:%s ***\n", file, line, desc);
3204 assert (ranges);
3205 assert (DPA_GetPtrCount(ranges->hdpa) >= 0);
3206 ranges_dump(ranges);
3207 if (DPA_GetPtrCount(ranges->hdpa) > 0)
3208 {
3209 prev = DPA_GetPtr(ranges->hdpa, 0);
3210 assert (prev->lower >= 0 && prev->lower < prev->upper);
3211 for (i = 1; i < DPA_GetPtrCount(ranges->hdpa); i++)
3212 {
3213 curr = DPA_GetPtr(ranges->hdpa, i);
3214 assert (prev->upper <= curr->lower);
3215 assert (curr->lower < curr->upper);
3216 prev = curr;
3217 }
3218 }
3219 TRACE("--- Done checking---\n");
3220}
3221
3223{
3224 RANGES ranges = Alloc(sizeof(struct tagRANGES));
3225 if (!ranges) return NULL;
3226 ranges->hdpa = DPA_Create(count);
3227 if (ranges->hdpa) return ranges;
3228 Free(ranges);
3229 return NULL;
3230}
3231
3232static void ranges_clear(RANGES ranges)
3233{
3234 INT i;
3235
3236 for(i = 0; i < DPA_GetPtrCount(ranges->hdpa); i++)
3237 Free(DPA_GetPtr(ranges->hdpa, i));
3238 DPA_DeleteAllPtrs(ranges->hdpa);
3239}
3240
3241
3242static void ranges_destroy(RANGES ranges)
3243{
3244 if (!ranges) return;
3245 ranges_clear(ranges);
3246 DPA_Destroy(ranges->hdpa);
3247 Free(ranges);
3248}
3249
3251{
3252 RANGES clone;
3253 INT i;
3254
3255#ifdef __REACTOS__
3256 if (!ranges || !ranges->hdpa)
3257 {
3258 /*
3259 * If a ExplorerBand tree rename operation is completed by left-clicking in
3260 * DefView, the navigation to the newly named item causes the ListView in DefView
3261 * to call LISTVIEW_DeselectAllSkipItems during ListView destruction.
3262 */
3263 return NULL;
3264 }
3265#endif
3266 if (!(clone = ranges_create(DPA_GetPtrCount(ranges->hdpa)))) goto fail;
3267
3268 for (i = 0; i < DPA_GetPtrCount(ranges->hdpa); i++)
3269 {
3270 RANGE *newrng = Alloc(sizeof(RANGE));
3271 if (!newrng) goto fail;
3272 *newrng = *((RANGE*)DPA_GetPtr(ranges->hdpa, i));
3273 if (!DPA_SetPtr(clone->hdpa, i, newrng))
3274 {
3275 Free(newrng);
3276 goto fail;
3277 }
3278 }
3279 return clone;
3280
3281fail:
3282 TRACE ("clone failed\n");
3283 ranges_destroy(clone);
3284 return NULL;
3285}
3286
3287static RANGES ranges_diff(RANGES ranges, RANGES sub)
3288{
3289 INT i;
3290
3291 for (i = 0; i < DPA_GetPtrCount(sub->hdpa); i++)
3292 ranges_del(ranges, *((RANGE *)DPA_GetPtr(sub->hdpa, i)));
3293
3294 return ranges;
3295}
3296
3297static void ranges_dump(RANGES ranges)
3298{
3299 INT i;
3300
3301 for (i = 0; i < DPA_GetPtrCount(ranges->hdpa); i++)
3302 TRACE(" %s\n", debugrange(DPA_GetPtr(ranges->hdpa, i)));
3303}
3304
3305static inline BOOL ranges_contain(RANGES ranges, INT nItem)
3306{
3307 RANGE srchrng = { nItem, nItem + 1 };
3308
3309 TRACE("(nItem=%d)\n", nItem);
3310 ranges_check(ranges, "before contain");
3311 return DPA_Search(ranges->hdpa, &srchrng, 0, ranges_cmp, 0, DPAS_SORTED) != -1;
3312}
3313
3315{
3316 INT i, count = 0;
3317
3318 for (i = 0; i < DPA_GetPtrCount(ranges->hdpa); i++)
3319 {
3320 RANGE *sel = DPA_GetPtr(ranges->hdpa, i);
3321 count += sel->upper - sel->lower;
3322 }
3323
3324 return count;
3325}
3326
3327static BOOL ranges_shift(RANGES ranges, INT nItem, INT delta, INT nUpper)
3328{
3329 RANGE srchrng = { nItem, nItem + 1 }, *chkrng;
3330 INT index;
3331
3332 index = DPA_Search(ranges->hdpa, &srchrng, 0, ranges_cmp, 0, DPAS_SORTED | DPAS_INSERTAFTER);
3333 if (index == -1) return TRUE;
3334
3335 for (; index < DPA_GetPtrCount(ranges->hdpa); index++)
3336 {
3337 chkrng = DPA_GetPtr(ranges->hdpa, index);
3338 if (chkrng->lower >= nItem)
3339 chkrng->lower = max(min(chkrng->lower + delta, nUpper - 1), 0);
3340 if (chkrng->upper > nItem)
3341 chkrng->upper = max(min(chkrng->upper + delta, nUpper), 0);
3342 }
3343 return TRUE;
3344}
3345
3347{
3348 RANGE srchrgn;
3349 INT index;
3350
3351 TRACE("(%s)\n", debugrange(&range));
3352 ranges_check(ranges, "before add");
3353
3354 /* try find overlapping regions first */
3355 srchrgn.lower = range.lower - 1;
3356 srchrgn.upper = range.upper + 1;
3357 index = DPA_Search(ranges->hdpa, &srchrgn, 0, ranges_cmp, 0, DPAS_SORTED);
3358
3359 if (index == -1)
3360 {
3361 RANGE *newrgn;
3362
3363 TRACE("Adding new range\n");
3364
3365 /* create the brand new range to insert */
3366 newrgn = Alloc(sizeof(RANGE));
3367 if(!newrgn) goto fail;
3368 *newrgn = range;
3369
3370 /* figure out where to insert it */
3371 index = DPA_Search(ranges->hdpa, newrgn, 0, ranges_cmp, 0, DPAS_SORTED | DPAS_INSERTAFTER);
3372 TRACE("index=%d\n", index);
3373 if (index == -1) index = 0;
3374
3375 /* and get it over with */
3376 if (DPA_InsertPtr(ranges->hdpa, index, newrgn) == -1)
3377 {
3378 Free(newrgn);
3379 goto fail;
3380 }
3381 }
3382 else
3383 {
3384 RANGE *chkrgn, *mrgrgn;
3385 INT fromindex, mergeindex;
3386
3387 chkrgn = DPA_GetPtr(ranges->hdpa, index);
3388 TRACE("Merge with %s @%d\n", debugrange(chkrgn), index);
3389
3390 chkrgn->lower = min(range.lower, chkrgn->lower);
3391 chkrgn->upper = max(range.upper, chkrgn->upper);
3392
3393 TRACE("New range %s @%d\n", debugrange(chkrgn), index);
3394
3395 /* merge now common ranges */
3396 fromindex = 0;
3397 srchrgn.lower = chkrgn->lower - 1;
3398 srchrgn.upper = chkrgn->upper + 1;
3399
3400 do
3401 {
3402 mergeindex = DPA_Search(ranges->hdpa, &srchrgn, fromindex, ranges_cmp, 0, 0);
3403 if (mergeindex == -1) break;
3404 if (mergeindex == index)
3405 {
3406 fromindex = index + 1;
3407 continue;
3408 }
3409
3410 TRACE("Merge with index %i\n", mergeindex);
3411
3412 mrgrgn = DPA_GetPtr(ranges->hdpa, mergeindex);
3413 chkrgn->lower = min(chkrgn->lower, mrgrgn->lower);
3414 chkrgn->upper = max(chkrgn->upper, mrgrgn->upper);
3415 Free(mrgrgn);
3416 DPA_DeletePtr(ranges->hdpa, mergeindex);
3417 if (mergeindex < index) index --;
3418 } while(1);
3419 }
3420
3421 ranges_check(ranges, "after add");
3422 return TRUE;
3423
3424fail:
3425 ranges_check(ranges, "failed add");
3426 return FALSE;
3427}
3428
3430{
3431 RANGE *chkrgn;
3432 INT index;
3433
3434 TRACE("(%s)\n", debugrange(&range));
3435 ranges_check(ranges, "before del");
3436
3437 /* we don't use DPAS_SORTED here, since we need *
3438 * to find the first overlapping range */
3439 index = DPA_Search(ranges->hdpa, &range, 0, ranges_cmp, 0, 0);
3440 while(index != -1)
3441 {
3442 chkrgn = DPA_GetPtr(ranges->hdpa, index);
3443
3444 TRACE("Matches range %s @%d\n", debugrange(chkrgn), index);
3445
3446 /* case 1: Same range */
3447 if ( (chkrgn->upper == range.upper) &&
3448 (chkrgn->lower == range.lower) )
3449 {
3450 DPA_DeletePtr(ranges->hdpa, index);
3451 Free(chkrgn);
3452 break;
3453 }
3454 /* case 2: engulf */
3455 else if ( (chkrgn->upper <= range.upper) &&
3456 (chkrgn->lower >= range.lower) )
3457 {
3458 DPA_DeletePtr(ranges->hdpa, index);
3459 Free(chkrgn);
3460 }
3461 /* case 3: overlap upper */
3462 else if ( (chkrgn->upper <= range.upper) &&
3463 (chkrgn->lower < range.lower) )
3464 {
3465 chkrgn->upper = range.lower;
3466 }
3467 /* case 4: overlap lower */
3468 else if ( (chkrgn->upper > range.upper) &&
3469 (chkrgn->lower >= range.lower) )
3470 {
3471 chkrgn->lower = range.upper;
3472 break;
3473 }
3474 /* case 5: fully internal */
3475 else
3476 {
3477 RANGE *newrgn;
3478
3479 if (!(newrgn = Alloc(sizeof(RANGE)))) goto fail;
3480 newrgn->lower = chkrgn->lower;
3481 newrgn->upper = range.lower;
3482 chkrgn->lower = range.upper;
3483 if (DPA_InsertPtr(ranges->hdpa, index, newrgn) == -1)
3484 {
3485 Free(newrgn);
3486 goto fail;
3487 }
3488 break;
3489 }
3490
3491 index = DPA_Search(ranges->hdpa, &range, index, ranges_cmp, 0, 0);
3492 }
3493
3494 ranges_check(ranges, "after del");
3495 return TRUE;
3496
3497fail:
3498 ranges_check(ranges, "failed del");
3499 return FALSE;
3500}
3501
3502/***
3503* DESCRIPTION:
3504* Removes all selection ranges
3505*
3506* Parameters(s):
3507* [I] infoPtr : valid pointer to the listview structure
3508* [I] toSkip : item range to skip removing the selection
3509*
3510* RETURNS:
3511* SUCCESS : TRUE
3512* FAILURE : FALSE
3513*/
3515{
3516 LVITEMW lvItem;
3517 ITERATOR i;
3518 RANGES clone;
3519
3520 TRACE("()\n");
3521
3522 lvItem.state = 0;
3523 lvItem.stateMask = LVIS_SELECTED;
3524
3525 /* need to clone the DPA because callbacks can change it */
3526 if (!(clone = ranges_clone(infoPtr->selectionRanges))) return FALSE;
3527 iterator_rangesitems(&i, ranges_diff(clone, toSkip));
3528 while(iterator_next(&i))
3529 LISTVIEW_SetItemState(infoPtr, i.nItem, &lvItem);
3530 /* note that the iterator destructor will free the cloned range */
3532
3533 return TRUE;
3534}
3535
3537{
3538 RANGES toSkip;
3539
3540 if (!(toSkip = ranges_create(1))) return FALSE;
3541 if (nItem != -1) ranges_additem(toSkip, nItem);
3542 LISTVIEW_DeselectAllSkipItems(infoPtr, toSkip);
3543 ranges_destroy(toSkip);
3544 return TRUE;
3545}
3546
3548{
3549 return LISTVIEW_DeselectAllSkipItem(infoPtr, -1);
3550}
3551
3552/***
3553 * DESCRIPTION:
3554 * Retrieves the number of items that are marked as selected.
3555 *
3556 * PARAMETER(S):
3557 * [I] infoPtr : valid pointer to the listview structure
3558 *
3559 * RETURN:
3560 * Number of items selected.
3561 */
3563{
3564 INT nSelectedCount = 0;
3565
3566 if (infoPtr->uCallbackMask & LVIS_SELECTED)
3567 {
3568 INT i;
3569 for (i = 0; i < infoPtr->nItemCount; i++)
3570 {
3571 if (LISTVIEW_GetItemState(infoPtr, i, LVIS_SELECTED))
3572 nSelectedCount++;
3573 }
3574 }
3575 else
3576 nSelectedCount = ranges_itemcount(infoPtr->selectionRanges);
3577
3578 TRACE("nSelectedCount=%d\n", nSelectedCount);
3579 return nSelectedCount;
3580}
3581
3582/***
3583 * DESCRIPTION:
3584 * Manages the item focus.
3585 *
3586 * PARAMETER(S):
3587 * [I] infoPtr : valid pointer to the listview structure
3588 * [I] nItem : item index
3589 *
3590 * RETURN:
3591 * TRUE : focused item changed
3592 * FALSE : focused item has NOT changed
3593 */
3594static inline BOOL LISTVIEW_SetItemFocus(LISTVIEW_INFO *infoPtr, INT nItem)
3595{
3596 INT oldFocus = infoPtr->nFocusedItem;
3597 LVITEMW lvItem;
3598
3599 if (nItem == infoPtr->nFocusedItem) return FALSE;
3600
3601 lvItem.state = nItem == -1 ? 0 : LVIS_FOCUSED;
3602 lvItem.stateMask = LVIS_FOCUSED;
3603 LISTVIEW_SetItemState(infoPtr, nItem == -1 ? infoPtr->nFocusedItem : nItem, &lvItem);
3604
3605 return oldFocus != infoPtr->nFocusedItem;
3606}
3607
3608static INT shift_item(const LISTVIEW_INFO *infoPtr, INT nShiftItem, INT nItem, INT direction)
3609{
3610 if (nShiftItem < nItem) return nShiftItem;
3611
3612 if (nShiftItem > nItem) return nShiftItem + direction;
3613
3614 if (direction > 0) return nShiftItem + direction;
3615
3616 return min(nShiftItem, infoPtr->nItemCount - 1);
3617}
3618
3619/* This function updates focus index.
3620
3621Parameters:
3622 focus : current focus index
3623 item : index of item to be added/removed
3624 direction : add/remove flag
3625*/
3627{
3628 DWORD old_mask = infoPtr->notify_mask & NOTIFY_MASK_ITEM_CHANGE;
3629
3630 infoPtr->notify_mask &= ~NOTIFY_MASK_ITEM_CHANGE;
3631 focus = shift_item(infoPtr, focus, item, direction);
3632 if (focus != infoPtr->nFocusedItem)
3633 LISTVIEW_SetItemFocus(infoPtr, focus);
3634 infoPtr->notify_mask |= old_mask;
3635}
3636
3650{
3651 TRACE("Shifting %i, %i steps\n", nItem, direction);
3652
3653 ranges_shift(infoPtr->selectionRanges, nItem, direction, infoPtr->nItemCount);
3654 assert(abs(direction) == 1);
3655 infoPtr->nSelectionMark = shift_item(infoPtr, infoPtr->nSelectionMark, nItem, direction);
3656
3657 /* But we are not supposed to modify nHotItem! */
3658}
3659
3672{
3673 INT nFirst = min(infoPtr->nSelectionMark, nItem);
3674 INT nLast = max(infoPtr->nSelectionMark, nItem);
3675 HWND hwndSelf = infoPtr->hwndSelf;
3676 NMLVODSTATECHANGE nmlv;
3677 DWORD old_mask;
3678 LVITEMW item;
3679 INT i;
3680
3681 /* Temporarily disable change notification
3682 * If the control is LVS_OWNERDATA, we need to send
3683 * only one LVN_ODSTATECHANGED notification.
3684 * See MSDN documentation for LVN_ITEMCHANGED.
3685 */
3686 old_mask = infoPtr->notify_mask & NOTIFY_MASK_ITEM_CHANGE;
3687 if (infoPtr->dwStyle & LVS_OWNERDATA)
3688 infoPtr->notify_mask &= ~NOTIFY_MASK_ITEM_CHANGE;
3689
3690 if (nFirst == -1) nFirst = nItem;
3691
3692 item.state = LVIS_SELECTED;
3693 item.stateMask = LVIS_SELECTED;
3694
3695 for (i = nFirst; i <= nLast; i++)
3696 LISTVIEW_SetItemState(infoPtr,i,&item);
3697
3698 ZeroMemory(&nmlv, sizeof(nmlv));
3699 nmlv.iFrom = nFirst;
3700 nmlv.iTo = nLast;
3701 nmlv.uOldState = 0;
3702 nmlv.uNewState = item.state;
3703
3704 notify_hdr(infoPtr, LVN_ODSTATECHANGED, (LPNMHDR)&nmlv);
3705 if (!IsWindow(hwndSelf))
3706 return FALSE;
3707 infoPtr->notify_mask |= old_mask;
3708 return TRUE;
3709}
3710
3711
3712/***
3713 * DESCRIPTION:
3714 * Sets a single group selection.
3715 *
3716 * PARAMETER(S):
3717 * [I] infoPtr : valid pointer to the listview structure
3718 * [I] nItem : item index
3719 *
3720 * RETURN:
3721 * None
3722 */
3724{
3726 DWORD old_mask;
3727 LVITEMW item;
3728 ITERATOR i;
3729
3730 if (!(selection = ranges_create(100))) return;
3731
3732 item.state = LVIS_SELECTED;
3733 item.stateMask = LVIS_SELECTED;
3734
3735#ifndef __REACTOS__
3736 if ((infoPtr->uView == LV_VIEW_LIST) || (infoPtr->uView == LV_VIEW_DETAILS))
3737 {
3738#endif
3739 if (infoPtr->nSelectionMark == -1)
3740 {
3741 infoPtr->nSelectionMark = nItem;
3742 ranges_additem(selection, nItem);
3743 }
3744 else
3745 {
3746 RANGE sel;
3747
3748 sel.lower = min(infoPtr->nSelectionMark, nItem);
3749 sel.upper = max(infoPtr->nSelectionMark, nItem) + 1;
3750 ranges_add(selection, sel);
3751 }
3752#ifndef __REACTOS__
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#endif
3779
3780 /* disable per item notifications on LVS_OWNERDATA style
3781 FIXME: single LVN_ODSTATECHANGED should be used */
3782 old_mask = infoPtr->notify_mask & NOTIFY_MASK_ITEM_CHANGE;
3783 if (infoPtr->dwStyle & LVS_OWNERDATA)
3784 infoPtr->notify_mask &= ~NOTIFY_MASK_ITEM_CHANGE;
3785
3787
3788
3790 while(iterator_next(&i))
3791 LISTVIEW_SetItemState(infoPtr, i.nItem, &item);
3792 /* this will also destroy the selection */
3794
3795 infoPtr->notify_mask |= old_mask;
3796 LISTVIEW_SetItemFocus(infoPtr, nItem);
3797}
3798
3799/***
3800 * DESCRIPTION:
3801 * Sets a single selection.
3802 *
3803 * PARAMETER(S):
3804 * [I] infoPtr : valid pointer to the listview structure
3805 * [I] nItem : item index
3806 *
3807 * RETURN:
3808 * None
3809 */
3810static void LISTVIEW_SetSelection(LISTVIEW_INFO *infoPtr, INT nItem)
3811{
3812 LVITEMW lvItem;
3813
3814 TRACE("nItem=%d\n", nItem);
3815
3816 LISTVIEW_DeselectAllSkipItem(infoPtr, nItem);
3817
3818 lvItem.state = LVIS_FOCUSED | LVIS_SELECTED;
3820 LISTVIEW_SetItemState(infoPtr, nItem, &lvItem);
3821
3822 infoPtr->nSelectionMark = nItem;
3823}
3824
3825/* Change item selection with key input. */
3827{
3828 WORD wShift = !!(keys & SHIFT_KEY);
3829 WORD wCtrl = !!(keys & CTRL_KEY);
3830 BOOL bResult = FALSE;
3831
3832 TRACE("nItem=%d, wShift=%d, wCtrl=%d\n", nItem, wShift, wCtrl);
3833 if ((nItem >= 0) && (nItem < infoPtr->nItemCount))
3834 {
3835 bResult = TRUE;
3836
3837 if (infoPtr->dwStyle & LVS_SINGLESEL || (wShift == 0 && wCtrl == 0))
3838 LISTVIEW_SetSelection(infoPtr, nItem);
3839 else
3840 {
3841 if (wShift)
3842 LISTVIEW_SetGroupSelection(infoPtr, nItem);
3843 else if (wCtrl)
3844 {
3845 LVITEMW lvItem;
3846 lvItem.state = ~LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED);
3847 lvItem.stateMask = LVIS_SELECTED;
3848 if (keys & SPACE_KEY)
3849 {
3850 LISTVIEW_SetItemState(infoPtr, nItem, &lvItem);
3851 if (lvItem.state & LVIS_SELECTED)
3852 infoPtr->nSelectionMark = nItem;
3853 }
3854 bResult = LISTVIEW_SetItemFocus(infoPtr, nItem);
3855 }
3856 }
3857 LISTVIEW_EnsureVisible(infoPtr, nItem, FALSE);
3858 }
3859
3860 UpdateWindow(infoPtr->hwndSelf); /* update client area */
3861 return bResult;
3862}
3863
3864static BOOL LISTVIEW_GetItemAtPt(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, POINT pt)
3865{
3866 LVHITTESTINFO lvHitTestInfo;
3867
3868 ZeroMemory(&lvHitTestInfo, sizeof(lvHitTestInfo));
3869 lvHitTestInfo.pt.x = pt.x;
3870 lvHitTestInfo.pt.y = pt.y;
3871
3872 LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, FALSE);
3873
3874 lpLVItem->mask = LVIF_PARAM;
3875 lpLVItem->iItem = lvHitTestInfo.iItem;
3876 lpLVItem->iSubItem = 0;
3877
3878 return LISTVIEW_GetItemT(infoPtr, lpLVItem, TRUE);
3879}
3880
3881static inline BOOL LISTVIEW_IsHotTracking(const LISTVIEW_INFO *infoPtr)
3882{
3883 return ((infoPtr->dwLvExStyle & LVS_EX_TRACKSELECT) ||
3884 (infoPtr->dwLvExStyle & LVS_EX_ONECLICKACTIVATE) ||
3886}
3887
3888/***
3889 * DESCRIPTION:
3890 * Called when the mouse is being actively tracked and has hovered for a specified
3891 * amount of time
3892 *
3893 * PARAMETER(S):
3894 * [I] infoPtr : valid pointer to the listview structure
3895 * [I] fwKeys : key indicator
3896 * [I] x,y : mouse position
3897 *
3898 * RETURN:
3899 * 0 if the message was processed, non-zero if there was an error
3900 *
3901 * INFO:
3902 * LVS_EX_TRACKSELECT: An item is automatically selected when the cursor remains
3903 * over the item for a certain period of time.
3904 *
3905 */
3907{
3908 NMHDR hdr;
3909
3910 if (notify_hdr(infoPtr, NM_HOVER, &hdr)) return 0;
3911
3912 if (LISTVIEW_IsHotTracking(infoPtr))
3913 {
3914 LVITEMW item;
3915 POINT pt;
3916
3917 pt.x = x;
3918 pt.y = y;
3919
3920 if (LISTVIEW_GetItemAtPt(infoPtr, &item, pt))
3921 LISTVIEW_SetSelection(infoPtr, item.iItem);
3922
3923 SetFocus(infoPtr->hwndSelf);
3924 }
3925
3926 return 0;
3927}
3928
3929#define SCROLL_LEFT 0x1
3930#define SCROLL_RIGHT 0x2
3931#define SCROLL_UP 0x4
3932#define SCROLL_DOWN 0x8
3933
3934/***
3935 * DESCRIPTION:
3936 * Utility routine to draw and highlight items within a marquee selection rectangle.
3937 *
3938 * PARAMETER(S):
3939 * [I] infoPtr : valid pointer to the listview structure
3940 * [I] coords_orig : original co-ordinates of the cursor
3941 * [I] coords_offs : offsetted coordinates of the cursor
3942 * [I] offset : offset amount
3943 * [I] scroll : Bitmask of which directions we should scroll, if at all
3944 *
3945 * RETURN:
3946 * None.
3947 */
3948static void LISTVIEW_MarqueeHighlight(LISTVIEW_INFO *infoPtr, const POINT *coords_orig,
3949 INT scroll)
3950{
3951 BOOL controlDown = FALSE;
3952 LVITEMW item;
3953 ITERATOR old_elems, new_elems;
3954 RECT rect;
3955 POINT coords_offs, offset;
3956
3957 /* Ensure coordinates are within client bounds */
3958 coords_offs.x = max(min(coords_orig->x, infoPtr->rcList.right), 0);
3959 coords_offs.y = max(min(coords_orig->y, infoPtr->rcList.bottom), 0);
3960
3961 /* Get offset */
3962 LISTVIEW_GetOrigin(infoPtr, &offset);
3963
3964 /* Offset coordinates by the appropriate amount */
3965 coords_offs.x -= offset.x;
3966 coords_offs.y -= offset.y;
3967
3968 if (coords_offs.x > infoPtr->marqueeOrigin.x)
3969 {
3970 rect.left = infoPtr->marqueeOrigin.x;
3971 rect.right = coords_offs.x;
3972 }
3973 else
3974 {
3975 rect.left = coords_offs.x;
3976 rect.right = infoPtr->marqueeOrigin.x;
3977 }
3978
3979 if (coords_offs.y > infoPtr->marqueeOrigin.y)
3980 {
3981 rect.top = infoPtr->marqueeOrigin.y;
3982 rect.bottom = coords_offs.y;
3983 }
3984 else
3985 {
3986 rect.top = coords_offs.y;
3987 rect.bottom = infoPtr->marqueeOrigin.y;
3988 }
3989
3990 /* Cancel out the old marquee rectangle and draw the new one */
3991 LISTVIEW_InvalidateRect(infoPtr, &infoPtr->marqueeDrawRect);
3992
3993 /* Scroll by the appropriate distance if applicable - speed up scrolling as
3994 the cursor is further away */
3995
3996 if ((scroll & SCROLL_LEFT) && (coords_orig->x <= 0))
3997 LISTVIEW_Scroll(infoPtr, coords_orig->x, 0);
3998
3999 if ((scroll & SCROLL_RIGHT) && (coords_orig->x >= infoPtr->rcList.right))
4000 LISTVIEW_Scroll(infoPtr, (coords_orig->x - infoPtr->rcList.right), 0);
4001
4002 if ((scroll & SCROLL_UP) && (coords_orig->y <= 0))
4003 LISTVIEW_Scroll(infoPtr, 0, coords_orig->y);
4004
4005 if ((scroll & SCROLL_DOWN) && (coords_orig->y >= infoPtr->rcList.bottom))
4006 LISTVIEW_Scroll(infoPtr, 0, (coords_orig->y - infoPtr->rcList.bottom));
4007
4008 iterator_frameditems_absolute(&old_elems, infoPtr, &infoPtr->marqueeRect);
4009
4010 infoPtr->marqueeRect = rect;
4011 infoPtr->marqueeDrawRect = rect;
4012 OffsetRect(&infoPtr->marqueeDrawRect, offset.x, offset.y);
4013
4014 iterator_frameditems_absolute(&new_elems, infoPtr, &infoPtr->marqueeRect);
4015 iterator_remove_common_items(&old_elems, &new_elems);
4016
4017 /* Iterate over no longer selected items */
4018 while (iterator_next(&old_elems))
4019 {
4020 if (old_elems.nItem > -1)
4021 {
4022 if (LISTVIEW_GetItemState(infoPtr, old_elems.nItem, LVIS_SELECTED) == LVIS_SELECTED)
4023 item.state = 0;
4024 else
4025 item.state = LVIS_SELECTED;
4026
4027 item.stateMask = LVIS_SELECTED;
4028
4029 LISTVIEW_SetItemState(infoPtr, old_elems.nItem, &item);
4030 }
4031 }
4032 iterator_destroy(&old_elems);
4033
4034
4035 /* Iterate over newly selected items */
4036 if (GetKeyState(VK_CONTROL) & 0x8000)
4037 controlDown = TRUE;
4038
4039 while (iterator_next(&new_elems))
4040 {
4041 if (new_elems.nItem > -1)
4042 {
4043 /* If CTRL is pressed, invert. If not, always select the item. */
4044 if ((controlDown) && (LISTVIEW_GetItemState(infoPtr, new_elems.nItem, LVIS_SELECTED)))
4045 item.state = 0;
4046 else
4047 item.state = LVIS_SELECTED;
4048
4049 item.stateMask = LVIS_SELECTED;
4050
4051 LISTVIEW_SetItemState(infoPtr, new_elems.nItem, &item);
4052 }
4053 }
4054 iterator_destroy(&new_elems);
4055
4056 LISTVIEW_InvalidateRect(infoPtr, &infoPtr->marqueeDrawRect);
4057}
4058
4059/***
4060 * DESCRIPTION:
4061 * Called when we are in a marquee selection that involves scrolling the listview (ie,
4062 * the cursor is outside the bounds of the client area). This is a TIMERPROC.
4063 *
4064 * PARAMETER(S):
4065 * [I] hwnd : Handle to the listview
4066 * [I] uMsg : WM_TIMER (ignored)
4067 * [I] idEvent : The timer ID interpreted as a pointer to a LISTVIEW_INFO struct
4068 * [I] dwTimer : The elapsed time (ignored)
4069 *
4070 * RETURN:
4071 * None.
4072 */
4074{
4075 LISTVIEW_INFO *infoPtr;
4076 SCROLLINFO scrollInfo;
4077 POINT coords;
4078 INT scroll = 0;
4079
4080 infoPtr = (LISTVIEW_INFO *) idEvent;
4081
4082 if (!infoPtr)
4083 return;
4084
4085 /* Get the current cursor position and convert to client coordinates */
4088
4089 scrollInfo.cbSize = sizeof(SCROLLINFO);
4090 scrollInfo.fMask = SIF_ALL;
4091
4092 /* Work out in which directions we can scroll */
4093 if (GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo))
4094 {
4095 if (scrollInfo.nPos != scrollInfo.nMin)
4096 scroll |= SCROLL_UP;
4097
4098 if (((scrollInfo.nPage + scrollInfo.nPos) - 1) != scrollInfo.nMax)
4099 scroll |= SCROLL_DOWN;
4100 }
4101
4102 if (GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo))
4103 {
4104 if (scrollInfo.nPos != scrollInfo.nMin)
4105 scroll |= SCROLL_LEFT;
4106
4107 if (((scrollInfo.nPage + scrollInfo.nPos) - 1) != scrollInfo.nMax)
4108 scroll |= SCROLL_RIGHT;
4109 }
4110
4111 if (((coords.x <= 0) && (scroll & SCROLL_LEFT)) ||
4112 ((coords.y <= 0) && (scroll & SCROLL_UP)) ||
4113 ((coords.x >= infoPtr->rcList.right) && (scroll & SCROLL_RIGHT)) ||
4114 ((coords.y >= infoPtr->rcList.bottom) && (scroll & SCROLL_DOWN)))
4115 {
4116 LISTVIEW_MarqueeHighlight(infoPtr, &coords, scroll);
4117 }
4118}
4119
4120/***
4121 * DESCRIPTION:
4122 * Called whenever WM_MOUSEMOVE is received.
4123 *
4124 * PARAMETER(S):
4125 * [I] infoPtr : valid pointer to the listview structure
4126 * [I] fwKeys : key indicator
4127 * [I] x,y : mouse position
4128 *
4129 * RETURN:
4130 * 0 if the message is processed, non-zero if there was an error
4131 */
4133{
4135 RECT rect;
4136 POINT pt;
4137
4138 pt.x = x;
4139 pt.y = y;
4140
4141 if (!(fwKeys & MK_LBUTTON))
4142 infoPtr->bLButtonDown = FALSE;
4143
4144 if (infoPtr->bLButtonDown)
4145 {
4146 rect.left = rect.right = infoPtr->ptClickPos.x;
4147 rect.top = rect.bottom = infoPtr->ptClickPos.y;
4148
4150
4151 if (infoPtr->bMarqueeSelect)
4152 {
4153 /* Enable the timer if we're going outside our bounds, in case the user doesn't
4154 move the mouse again */
4155
4156 if ((x <= 0) || (y <= 0) || (x >= infoPtr->rcList.right) ||
4157 (y >= infoPtr->rcList.bottom))
4158 {
4159 if (!infoPtr->bScrolling)
4160 {
4161 infoPtr->bScrolling = TRUE;
4162 SetTimer(infoPtr->hwndSelf, (UINT_PTR) infoPtr, 1, LISTVIEW_ScrollTimer);
4163 }
4164 }
4165 else
4166 {
4167 infoPtr->bScrolling = FALSE;
4168 KillTimer(infoPtr->hwndSelf, (UINT_PTR) infoPtr);
4169 }
4170
4171 LISTVIEW_MarqueeHighlight(infoPtr, &pt, 0);
4172 return 0;
4173 }
4174
4175 ht.pt = pt;
4176 LISTVIEW_HitTest(infoPtr, &ht, TRUE, TRUE);
4177
4178 /* reset item marker */
4179 if (infoPtr->nLButtonDownItem != ht.iItem)
4180 infoPtr->nLButtonDownItem = -1;
4181
4182 if (!PtInRect(&rect, pt))
4183 {
4184 /* this path covers the following:
4185 1. WM_LBUTTONDOWN over selected item (sets focus on it)
4186 2. change focus with keys
4187 3. move mouse over item from step 1 selects it and moves focus on it */
4188 if (infoPtr->nLButtonDownItem != -1 &&
4190 {
4191 LVITEMW lvItem;
4192
4193 lvItem.state = LVIS_FOCUSED | LVIS_SELECTED;
4195
4196 LISTVIEW_SetItemState(infoPtr, infoPtr->nLButtonDownItem, &lvItem);
4197 infoPtr->nLButtonDownItem = -1;
4198 }
4199
4200 if (!infoPtr->bDragging)
4201 {
4202 ht.pt = infoPtr->ptClickPos;
4203 LISTVIEW_HitTest(infoPtr, &ht, TRUE, TRUE);
4204
4205 /* If the click is outside the range of an item, begin a
4206 highlight. If not, begin an item drag. */
4207 if (ht.iItem == -1)
4208 {
4209 NMHDR hdr;
4210
4211 /* If we're allowing multiple selections, send notification.
4212 If return value is non-zero, cancel. */
4213 if (!(infoPtr->dwStyle & LVS_SINGLESEL) && (notify_hdr(infoPtr, LVN_MARQUEEBEGIN, &hdr) == 0))
4214 {
4215 /* Store the absolute coordinates of the click */
4216 POINT offset;
4217 LISTVIEW_GetOrigin(infoPtr, &offset);
4218
4219 infoPtr->marqueeOrigin.x = infoPtr->ptClickPos.x - offset.x;
4220 infoPtr->marqueeOrigin.y = infoPtr->ptClickPos.y - offset.y;
4221
4222 /* Begin selection and capture mouse */
4223 infoPtr->bMarqueeSelect = TRUE;
4224 infoPtr->marqueeRect = rect;
4225 SetCapture(infoPtr->hwndSelf);
4226 }
4227 }
4228 else
4229 {
4230 NMLISTVIEW nmlv;
4231
4232 ZeroMemory(&nmlv, sizeof(nmlv));
4233 nmlv.iItem = ht.iItem;
4234 nmlv.ptAction = infoPtr->ptClickPos;
4235
4236 notify_listview(infoPtr, LVN_BEGINDRAG, &nmlv);
4237 infoPtr->bDragging = TRUE;
4238 }
4239 }
4240
4241 return 0;
4242 }
4243 }
4244
4245 /* see if we are supposed to be tracking mouse hovering */
4246 if (LISTVIEW_IsHotTracking(infoPtr)) {
4247 TRACKMOUSEEVENT trackinfo;
4248 DWORD flags;
4249
4250 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
4251 trackinfo.dwFlags = TME_QUERY;
4252
4253 /* see if we are already tracking this hwnd */
4254 _TrackMouseEvent(&trackinfo);
4255
4256 flags = TME_LEAVE;
4257 if(infoPtr->dwLvExStyle & LVS_EX_TRACKSELECT)
4258 flags |= TME_HOVER;
4259
4260 if((trackinfo.dwFlags & flags) != flags || trackinfo.hwndTrack != infoPtr->hwndSelf) {
4261 trackinfo.dwFlags = flags;
4262 trackinfo.dwHoverTime = infoPtr->dwHoverTime;
4263 trackinfo.hwndTrack = infoPtr->hwndSelf;
4264
4265 /* call TRACKMOUSEEVENT so we receive WM_MOUSEHOVER messages */
4266 _TrackMouseEvent(&trackinfo);
4267 }
4268 }
4269
4270 return 0;
4271}
4272
4273
4274/***
4275 * Tests whether the item is assignable to a list with style lStyle
4276 */
4277static inline BOOL is_assignable_item(const LVITEMW *lpLVItem, LONG lStyle)
4278{
4279 if ( (lpLVItem->mask & LVIF_TEXT) &&
4280 (lpLVItem->pszText == LPSTR_TEXTCALLBACKW) &&
4281 (lStyle & (LVS_SORTASCENDING | LVS_SORTDESCENDING)) ) return FALSE;
4282
4283 return TRUE;
4284}
4285
4286
4287/***
4288 * DESCRIPTION:
4289 * Helper for LISTVIEW_SetItemT and LISTVIEW_InsertItemT: sets item attributes.
4290 *
4291 * PARAMETER(S):
4292 * [I] infoPtr : valid pointer to the listview structure
4293 * [I] lpLVItem : valid pointer to new item attributes
4294 * [I] isNew : the item being set is being inserted
4295 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
4296 * [O] bChanged : will be set to TRUE if the item really changed
4297 *
4298 * RETURN:
4299 * SUCCESS : TRUE
4300 * FAILURE : FALSE
4301 */
4302static BOOL set_main_item(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL isNew, BOOL isW, BOOL *bChanged)
4303{
4304 ITEM_INFO *lpItem;
4305 NMLISTVIEW nmlv;
4306 UINT uChanged = 0;
4307 LVITEMW item;
4308 /* stateMask is ignored for LVM_INSERTITEM */
4309 UINT stateMask = isNew ? ~0 : lpLVItem->stateMask;
4310
4311 TRACE("()\n");
4312
4313 assert(lpLVItem->iItem >= 0 && lpLVItem->iItem < infoPtr->nItemCount);
4314
4315 if (lpLVItem->mask == 0) return TRUE;
4316
4317 if (infoPtr->dwStyle & LVS_OWNERDATA)
4318 {
4319 /* a virtual listview only stores selection and focus */
4320 if (lpLVItem->mask & ~LVIF_STATE)
4321 return FALSE;
4322 lpItem = NULL;
4323 }
4324 else
4325 {
4326 HDPA hdpaSubItems = DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
4327 lpItem = DPA_GetPtr(hdpaSubItems, 0);
4328 assert (lpItem);
4329 }
4330
4331 /* we need to get the lParam and state of the item */
4332 item.iItem = lpLVItem->iItem;
4333 item.iSubItem = lpLVItem->iSubItem;
4334 item.mask = LVIF_STATE | LVIF_PARAM;
4335 item.stateMask = (infoPtr->dwStyle & LVS_OWNERDATA) ? LVIS_FOCUSED | LVIS_SELECTED : ~0;
4336
4337 item.state = 0;
4338 item.lParam = 0;
4339 if (!isNew && !LISTVIEW_GetItemW(infoPtr, &item)) return FALSE;
4340
4341 TRACE("oldState=%x, newState=%x\n", item.state, lpLVItem->state);
4342 /* determine what fields will change */
4343 if ((lpLVItem->mask & LVIF_STATE) && ((item.state ^ lpLVItem->state) & stateMask & ~infoPtr->uCallbackMask))
4344 uChanged |= LVIF_STATE;
4345
4346 if ((lpLVItem->mask & LVIF_IMAGE) && (lpItem->hdr.iImage != lpLVItem->iImage))
4347 uChanged |= LVIF_IMAGE;
4348
4349 if ((lpLVItem->mask & LVIF_PARAM) && (lpItem->lParam != lpLVItem->lParam))
4350 uChanged |= LVIF_PARAM;
4351
4352 if ((lpLVItem->mask & LVIF_INDENT) && (lpItem->iIndent != lpLVItem->iIndent))
4353 uChanged |= LVIF_INDENT;
4354
4355 if ((lpLVItem->mask & LVIF_TEXT) && textcmpWT(lpItem->hdr.pszText, lpLVItem->pszText, isW))
4356 uChanged |= LVIF_TEXT;
4357
4358 TRACE("change mask=0x%x\n", uChanged);
4359
4360 memset(&nmlv, 0, sizeof(NMLISTVIEW));
4361 nmlv.iItem = lpLVItem->iItem;
4362 if (lpLVItem->mask & LVIF_STATE)
4363 {
4364 nmlv.uNewState = (item.state & ~stateMask) | (lpLVItem->state & stateMask);
4365 nmlv.uOldState = item.state;
4366 }
4367 nmlv.uChanged = uChanged ? uChanged : lpLVItem->mask;
4368 nmlv.lParam = item.lParam;
4369
4370 /* Send LVN_ITEMCHANGING notification, if the item is not being inserted
4371 and we are _NOT_ virtual (LVS_OWNERDATA), and change notifications
4372 are enabled. Even nothing really changed we still need to send this,
4373 in this case uChanged mask is just set to passed item mask. */
4374 if (lpItem && !isNew && (infoPtr->notify_mask & NOTIFY_MASK_ITEM_CHANGE))
4375 {
4376 HWND hwndSelf = infoPtr->hwndSelf;
4377
4378 if (notify_listview(infoPtr, LVN_ITEMCHANGING, &nmlv))
4379 return FALSE;
4380 if (!IsWindow(hwndSelf))
4381 return FALSE;
4382 }
4383
4384 /* When item is inserted we need to shift existing focus index if new item has lower index. */
4385 if (isNew && (stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED) &&
4386 /* this means we won't hit a focus change path later */
4387 ((uChanged & LVIF_STATE) == 0 || (!(lpLVItem->state & LVIS_FOCUSED) && (infoPtr->nFocusedItem != lpLVItem->iItem))))
4388 {
4389 if (infoPtr->nFocusedItem != -1 && (lpLVItem->iItem <= infoPtr->nFocusedItem))
4390 infoPtr->nFocusedItem++;
4391 }
4392
4393 if (!uChanged) return TRUE;
4394 *bChanged = TRUE;
4395
4396 /* copy information */
4397 if (lpLVItem->mask & LVIF_TEXT)
4398 textsetptrT(&lpItem->hdr.pszText, lpLVItem->pszText, isW);
4399
4400 if (lpLVItem->mask & LVIF_IMAGE)
4401 lpItem->hdr.iImage = lpLVItem->iImage;
4402
4403 if (lpLVItem->mask & LVIF_PARAM)
4404 lpItem->lParam = lpLVItem->lParam;
4405
4406 if (lpLVItem->mask & LVIF_INDENT)
4407 lpItem->iIndent = lpLVItem->iIndent;
4408
4409 if (uChanged & LVIF_STATE)
4410 {
4411 if (lpItem && (stateMask & ~infoPtr->uCallbackMask))
4412 {
4413 lpItem->state &= ~stateMask;
4414 lpItem->state |= (lpLVItem->state & stateMask);
4415 }
4416 if (lpLVItem->state & stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED)
4417 {
4418 if (infoPtr->dwStyle & LVS_SINGLESEL) LISTVIEW_DeselectAllSkipItem(infoPtr, lpLVItem->iItem);
4419 ranges_additem(infoPtr->selectionRanges, lpLVItem->iItem);
4420 }
4421 else if (stateMask & LVIS_SELECTED)
4422 {
4423 ranges_delitem(infoPtr->selectionRanges, lpLVItem->iItem);
4424 }
4425 /* If we are asked to change focus, and we manage it, do it.
4426 It's important to have all new item data stored at this point,
4427 because changing existing focus could result in a redrawing operation,
4428 which in turn could ask for disp data, application should see all data
4429 for inserted item when processing LVN_GETDISPINFO.
4430
4431 The way this works application will see nested item change notifications -
4432 changed item notifications interrupted by ones from item losing focus. */
4433 if (stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED)
4434 {
4435 if (lpLVItem->state & LVIS_FOCUSED)
4436 {
4437 /* update selection mark */
4438 if (infoPtr->nFocusedItem == -1 && infoPtr->nSelectionMark == -1)
4439 infoPtr->nSelectionMark = lpLVItem->iItem;
4440
4441 if (infoPtr->nFocusedItem != -1)
4442 {
4443 /* remove current focus */
4444 item.mask = LVIF_STATE;
4445 item.state = 0;
4446 item.stateMask = LVIS_FOCUSED;
4447
4448 /* recurse with redrawing an item */
4449 LISTVIEW_SetItemState(infoPtr, infoPtr->nFocusedItem, &item);
4450 }
4451
4452 infoPtr->nFocusedItem = lpLVItem->iItem;
4453 LISTVIEW_EnsureVisible(infoPtr, lpLVItem->iItem, infoPtr->uView == LV_VIEW_LIST);
4454 }
4455 else if (infoPtr->nFocusedItem == lpLVItem->iItem)
4456 {
4457 infoPtr->nFocusedItem = -1;
4458 }
4459 }
4460 }
4461
4462 /* if we're inserting the item, we're done */
4463 if (isNew) return TRUE;
4464
4465 /* send LVN_ITEMCHANGED notification */
4466 if (lpLVItem->mask & LVIF_PARAM) nmlv.lParam = lpLVItem->lParam;
4467 if (infoPtr->notify_mask & NOTIFY_MASK_ITEM_CHANGE)
4468 notify_listview(infoPtr, LVN_ITEMCHANGED, &nmlv);
4469
4470 return TRUE;
4471}
4472
4473/***
4474 * DESCRIPTION:
4475 * Helper for LISTVIEW_{Set,Insert}ItemT *only*: sets subitem attributes.
4476 *
4477 * PARAMETER(S):
4478 * [I] infoPtr : valid pointer to the listview structure
4479 * [I] lpLVItem : valid pointer to new subitem attributes
4480 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
4481 * [O] bChanged : will be set to TRUE if the item really changed
4482 *
4483 * RETURN:
4484 * SUCCESS : TRUE
4485 * FAILURE : FALSE
4486 */
4487static BOOL set_sub_item(const LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL isW, BOOL *bChanged)
4488{
4489 HDPA hdpaSubItems;
4490 SUBITEM_INFO *lpSubItem;
4491
4492 /* we do not support subitems for virtual listviews */
4493 if (infoPtr->dwStyle & LVS_OWNERDATA) return FALSE;
4494
4495 /* set subitem only if column is present */
4496 if (lpLVItem->iSubItem >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return FALSE;
4497
4498 /* First do some sanity checks */
4499 /* The LVIF_STATE flag is valid for subitems, but does not appear to be
4500 particularly useful. We currently do not actually do anything with
4501 the flag on subitems.
4502 */
4503 if (lpLVItem->mask & ~(LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_DI_SETITEM)) return FALSE;
4504 if (!(lpLVItem->mask & (LVIF_TEXT | LVIF_IMAGE | LVIF_STATE))) return TRUE;
4505
4506 /* get the subitem structure, and create it if not there */
4507 hdpaSubItems = DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
4508 assert (hdpaSubItems);
4509
4510 lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem);
4511 if (!lpSubItem)
4512 {
4513 SUBITEM_INFO *tmpSubItem;
4514 INT i;
4515
4516 lpSubItem = Alloc(sizeof(SUBITEM_INFO));
4517 if (!lpSubItem) return FALSE;
4518 /* we could binary search here, if need be...*/
4519 for (i = 1; i < DPA_GetPtrCount(hdpaSubItems); i++)
4520 {
4521 tmpSubItem = DPA_GetPtr(hdpaSubItems, i);
4522 if (tmpSubItem->iSubItem > lpLVItem->iSubItem) break;
4523 }
4524 if (DPA_InsertPtr(hdpaSubItems, i, lpSubItem) == -1)
4525 {
4526 Free(lpSubItem);
4527 return FALSE;
4528 }
4529 lpSubItem->iSubItem = lpLVItem->iSubItem;
4530 lpSubItem->hdr.iImage = I_IMAGECALLBACK;
4531 *bChanged = TRUE;
4532 }
4533
4534 if ((lpLVItem->mask & LVIF_IMAGE) && (lpSubItem->hdr.iImage != lpLVItem->iImage))
4535 {
4536 lpSubItem->hdr.iImage = lpLVItem->iImage;
4537 *bChanged = TRUE;
4538 }
4539
4540 if ((lpLVItem->mask & LVIF_TEXT) && textcmpWT(lpSubItem->hdr.pszText, lpLVItem->pszText, isW))
4541 {
4542 textsetptrT(&lpSubItem->hdr.pszText, lpLVItem->pszText, isW);
4543 *bChanged = TRUE;
4544 }
4545
4546 return TRUE;
4547}
4548
4549/***
4550 * DESCRIPTION:
4551 * Sets item attributes.
4552 *
4553 * PARAMETER(S):
4554 * [I] infoPtr : valid pointer to the listview structure
4555 * [I] lpLVItem : new item attributes
4556 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
4557 *
4558 * RETURN:
4559 * SUCCESS : TRUE
4560 * FAILURE : FALSE
4561 */
4563{
4564 HWND hwndSelf = infoPtr->hwndSelf;
4565 LPWSTR pszText = NULL;
4566 BOOL bResult, bChanged = FALSE;
4567 RECT oldItemArea;
4568
4569 TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW);
4570
4571 if (!lpLVItem || lpLVItem->iItem < 0 || lpLVItem->iItem >= infoPtr->nItemCount)
4572 return FALSE;
4573
4574 /* Store old item area */
4575 LISTVIEW_GetItemBox(infoPtr, lpLVItem->iItem, &oldItemArea);
4576
4577 /* For efficiency, we transform the lpLVItem->pszText to Unicode here */
4578 if ((lpLVItem->mask & LVIF_TEXT) && is_text(lpLVItem->pszText))
4579 {
4580 pszText = lpLVItem->pszText;
4581 lpLVItem->pszText = textdupTtoW(lpLVItem->pszText, isW);
4582 }
4583
4584 /* actually set the fields */
4585 if (!is_assignable_item(lpLVItem, infoPtr->dwStyle)) return FALSE;
4586
4587 if (lpLVItem->iSubItem)
4588 bResult = set_sub_item(infoPtr, lpLVItem, TRUE, &bChanged);
4589 else
4590 bResult = set_main_item(infoPtr, lpLVItem, FALSE, TRUE, &bChanged);
4591 if (!IsWindow(hwndSelf))
4592 return FALSE;
4593
4594 /* redraw item, if necessary */
4595 if (bChanged && !infoPtr->bIsDrawing)
4596 {
4597 /* this little optimization eliminates some nasty flicker */
4598 if ( infoPtr->uView == LV_VIEW_DETAILS && !(infoPtr->dwStyle & LVS_OWNERDRAWFIXED) &&
4599 !(infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) &&
4600 lpLVItem->iSubItem > 0 && lpLVItem->iSubItem <= DPA_GetPtrCount(infoPtr->hdpaColumns) )
4601 LISTVIEW_InvalidateSubItem(infoPtr, lpLVItem->iItem, lpLVItem->iSubItem);
4602 else
4603 {
4604 LISTVIEW_InvalidateRect(infoPtr, &oldItemArea);
4605 LISTVIEW_InvalidateItem(infoPtr, lpLVItem->iItem);
4606 }
4607 }
4608 /* restore text */
4609 if (pszText)
4610 {
4611 textfreeT(lpLVItem->pszText, isW);
4612 lpLVItem->pszText = pszText;
4613 }
4614
4615 return bResult;
4616}
4617
4618/***
4619 * DESCRIPTION:
4620 * Retrieves the index of the item at coordinate (0, 0) of the client area.
4621 *
4622 * PARAMETER(S):
4623 * [I] infoPtr : valid pointer to the listview structure
4624 *
4625 * RETURN:
4626 * item index
4627 */
4629{
4630 INT nItem = 0;
4631 SCROLLINFO scrollInfo;
4632
4633 scrollInfo.cbSize = sizeof(SCROLLINFO);
4634 scrollInfo.fMask = SIF_POS;
4635
4636 if (infoPtr->uView == LV_VIEW_LIST)
4637 {
4638 if (GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo))
4639 nItem = scrollInfo.nPos * LISTVIEW_GetCountPerColumn(infoPtr);
4640 }
4641 else if (infoPtr->uView == LV_VIEW_DETAILS)
4642 {
4643 if (GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo))
4644 nItem = scrollInfo.nPos;
4645 }
4646 else
4647 {
4648 if (GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo))
4649 nItem = LISTVIEW_GetCountPerRow(infoPtr) * (scrollInfo.nPos / infoPtr->nItemHeight);
4650 }
4651
4652 TRACE("nItem=%d\n", nItem);
4653
4654 return nItem;
4655}
4656
4657
4658/***
4659 * DESCRIPTION:
4660 * Erases the background of the given rectangle
4661 *
4662 * PARAMETER(S):
4663 * [I] infoPtr : valid pointer to the listview structure
4664 * [I] hdc : device context handle
4665 * [I] lprcBox : clipping rectangle
4666 *
4667 * RETURN:
4668 * Success: TRUE
4669 * Failure: FALSE
4670 */
4671static inline BOOL LISTVIEW_FillBkgnd(const LISTVIEW_INFO *infoPtr, HDC hdc, const RECT *lprcBox)
4672{
4673 if (!infoPtr->hBkBrush) return FALSE;
4674
4675 TRACE("(hdc=%p, lprcBox=%s, hBkBrush=%p)\n", hdc, wine_dbgstr_rect(lprcBox), infoPtr->hBkBrush);
4676
4677 return FillRect(hdc, lprcBox, infoPtr->hBkBrush);
4678}
4679
4680/* Draw main item or subitem */
4681static void LISTVIEW_DrawItemPart(LISTVIEW_INFO *infoPtr, LVITEMW *item, const NMLVCUSTOMDRAW *nmlvcd, const POINT *pos)
4682{
4683 RECT rcSelect, rcLabel, rcBox, rcStateIcon, rcIcon;
4684 const RECT *background;
4686 UINT format;
4687 RECT *focus;
4688
4689 /* now check if we need to update the focus rectangle */
4690 focus = infoPtr->bFocus && (item->state & LVIS_FOCUSED) ? &infoPtr->rcFocus : 0;
4691 if (!focus) item->state &= ~LVIS_FOCUSED;
4692
4693 LISTVIEW_GetItemMetrics(infoPtr, item, &rcBox, &rcSelect, &rcIcon, &rcStateIcon, &rcLabel);
4694 OffsetRect(&rcBox, pos->x, pos->y);
4695 OffsetRect(&rcSelect, pos->x, pos->y);
4696 OffsetRect(&rcIcon, pos->x, pos->y);
4697 OffsetRect(&rcStateIcon, pos->x, pos->y);
4698 OffsetRect(&rcLabel, pos->x, pos->y);
4699 TRACE("%d: box=%s, select=%s, icon=%s. label=%s\n", item->iSubItem,
4700 wine_dbgstr_rect(&rcBox), wine_dbgstr_rect(&rcSelect),
4701 wine_dbgstr_rect(&rcIcon), wine_dbgstr_rect(&rcLabel));
4702
4703 /* FIXME: temporary hack */
4704 rcSelect.left = rcLabel.left;
4705
4706 if (infoPtr->uView == LV_VIEW_DETAILS && item->iSubItem == 0)
4707 {
4708 if (!(infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT))
4709 OffsetRect(&rcSelect, LISTVIEW_GetColumnInfo(infoPtr, 0)->rcHeader.left, 0);
4710 OffsetRect(&rcIcon, LISTVIEW_GetColumnInfo(infoPtr, 0)->rcHeader.left, 0);
4711 OffsetRect(&rcStateIcon, LISTVIEW_GetColumnInfo(infoPtr, 0)->rcHeader.left, 0);
4712 OffsetRect(&rcLabel, LISTVIEW_GetColumnInfo(infoPtr, 0)->rcHeader.left, 0);
4713 }
4714
4715 /* in icon mode, the label rect is really what we want to draw the
4716 * background for */
4717 /* in detail mode, we want to paint background for label rect when
4718 * item is not selected or listview has full row select; otherwise paint
4719 * background for text only */
4720 if ( infoPtr->uView == LV_VIEW_ICON ||
4721 (infoPtr->uView == LV_VIEW_DETAILS && (!(item->state & LVIS_SELECTED) ||
4722 (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT))))
4723 background = &rcLabel;
4724 else
4725 background = &rcSelect;
4726
4727 if (nmlvcd->clrTextBk != CLR_NONE)
4728 ExtTextOutW(nmlvcd->nmcd.hdc, background->left, background->top, ETO_OPAQUE, background, NULL, 0, NULL);
4729
4730 if (item->state & LVIS_FOCUSED)
4731 {
4732 if (infoPtr->uView == LV_VIEW_DETAILS)
4733 {
4734 if (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT)
4735 {
4736 /* we have to update left focus bound too if item isn't in leftmost column
4737 and reduce right box bound */
4738 if (DPA_GetPtrCount(infoPtr->hdpaColumns) > 0)
4739 {
4740 INT leftmost;
4741
4742 if ((leftmost = SendMessageW(infoPtr->hwndHeader, HDM_ORDERTOINDEX, 0, 0)))
4743 {
4744 INT Originx = pos->x - LISTVIEW_GetColumnInfo(infoPtr, leftmost)->rcHeader.left;
4745 INT rightmost = SendMessageW(infoPtr->hwndHeader, HDM_ORDERTOINDEX,
4746 DPA_GetPtrCount(infoPtr->hdpaColumns) - 1, 0);
4747
4748 rcBox.right = LISTVIEW_GetColumnInfo(infoPtr, rightmost)->rcHeader.right + Originx;
4749 rcSelect.left = LISTVIEW_GetColumnInfo(infoPtr, leftmost)->rcHeader.left + Originx;
4750 }
4751 }
4752 rcSelect.right = rcBox.right;
4753 }
4754 infoPtr->rcFocus = rcSelect;
4755 }
4756 else
4757 infoPtr->rcFocus = rcLabel;
4758 }
4759
4760 /* state icons */
4761 if (infoPtr->himlState && STATEIMAGEINDEX(item->state) && (item->iSubItem == 0))
4762 {
4763 UINT stateimage = STATEIMAGEINDEX(item->state);
4764 if (stateimage)
4765 {
4766 TRACE("stateimage=%d\n", stateimage);
4767 ImageList_Draw(infoPtr->himlState, stateimage-1, nmlvcd->nmcd.hdc, rcStateIcon.left, rcStateIcon.top, ILD_NORMAL);
4768 }
4769 }
4770
4771 /* item icons */
4772 himl = (infoPtr->uView == LV_VIEW_ICON ? infoPtr->himlNormal : infoPtr->himlSmall);
4773 if (himl && item->iImage >= 0 && !IsRectEmpty(&rcIcon))
4774 {
4775 UINT style;
4776
4777 TRACE("iImage=%d\n", item->iImage);
4778
4779#ifdef __REACTOS__
4780 if (item->state & (LVIS_CUT | (infoPtr->bFocus ? LVIS_SELECTED : 0)))
4781#else
4782 if (item->state & (LVIS_SELECTED | LVIS_CUT) && infoPtr->bFocus)
4783#endif
4785 else
4786 style = ILD_NORMAL;
4787
4788 ImageList_DrawEx(himl, item->iImage, nmlvcd->nmcd.hdc, rcIcon.left, rcIcon.top,
4789 rcIcon.right - rcIcon.left, rcIcon.bottom - rcIcon.top, infoPtr->clrBk,
4790 item->state & LVIS_CUT ? RGB(255, 255, 255) : CLR_DEFAULT,
4791 style | (item->state & LVIS_OVERLAYMASK));
4792 }
4793
4794 /* Don't bother painting item being edited */
4795 if (infoPtr->hwndEdit && item->iItem == infoPtr->nEditLabelItem && item->iSubItem == 0) return;
4796
4797 /* figure out the text drawing flags */
4798 format = (infoPtr->uView == LV_VIEW_ICON ? (focus ? LV_FL_DT_FLAGS : LV_ML_DT_FLAGS) : LV_SL_DT_FLAGS);
4799 if (infoPtr->uView == LV_VIEW_ICON)
4800 format = (focus ? LV_FL_DT_FLAGS : LV_ML_DT_FLAGS);
4801 else if (item->iSubItem)
4802 {
4803 switch (LISTVIEW_GetColumnInfo(infoPtr, item->iSubItem)->fmt & LVCFMT_JUSTIFYMASK)
4804 {
4805 case LVCFMT_RIGHT: format |= DT_RIGHT; break;
4806 case LVCFMT_CENTER: format |= DT_CENTER; break;
4807 default: format |= DT_LEFT;
4808 }
4809 }
4810 if (!(format & (DT_RIGHT | DT_CENTER)))
4811 {
4812 if (himl && item->iImage >= 0 && !IsRectEmpty(&rcIcon)) rcLabel.left += IMAGE_PADDING;
4813 else rcLabel.left += LABEL_HOR_PADDING;
4814 }
4815 else if (format & DT_RIGHT) rcLabel.right -= LABEL_HOR_PADDING;
4816
4817 /* for GRIDLINES reduce the bottom so the text formats correctly */
4818 if (infoPtr->uView == LV_VIEW_DETAILS && infoPtr->dwLvExStyle & LVS_EX_GRIDLINES)
4819 rcLabel.bottom--;
4820
4821#ifdef __REACTOS__
4822 if ((!(item->state & LVIS_SELECTED) || !infoPtr->bFocus) && (infoPtr->dwLvExStyle & LVS_EX_TRANSPARENTSHADOWTEXT))
4823 DrawShadowText(nmlvcd->nmcd.hdc, item->pszText, -1, &rcLabel, format, RGB(255, 255, 255), RGB(0, 0, 0), 2, 2);
4824 else
4825#endif
4826 DrawTextW(nmlvcd->nmcd.hdc, item->pszText, -1, &rcLabel, format);
4827}
4828
4829/***
4830 * DESCRIPTION:
4831 * Draws an item.
4832 *
4833 * PARAMETER(S):
4834 * [I] infoPtr : valid pointer to the listview structure
4835 * [I] hdc : device context handle
4836 * [I] nItem : item index
4837 * [I] nSubItem : subitem index
4838 * [I] pos : item position in client coordinates
4839 * [I] cdmode : custom draw mode
4840 *
4841 * RETURN:
4842 * Success: TRUE
4843 * Failure: FALSE
4844 */
4845static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, ITERATOR *subitems, POINT pos, DWORD cdmode)
4846{
4847 WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
4848 static WCHAR callbackW[] = { '(', 'c', 'a', 'l', 'l', 'b', 'a', 'c', 'k', ')', 0 };
4849 DWORD cdsubitemmode = CDRF_DODEFAULT;
4850 RECT *focus, rcBox;
4851 NMLVCUSTOMDRAW nmlvcd;
4852 LVITEMW lvItem;
4853
4854 TRACE("(hdc=%p, nItem=%d, subitems=%p, pos=%s)\n", hdc, nItem, subitems, wine_dbgstr_point(&pos));
4855
4856 /* get information needed for drawing the item */
4858 if (infoPtr->uView == LV_VIEW_DETAILS) lvItem.mask |= LVIF_INDENT;
4860 lvItem.iItem = nItem;
4861 lvItem.iSubItem = 0;
4862 lvItem.state = 0;
4863 lvItem.lParam = 0;
4864 lvItem.cchTextMax = DISP_TEXT_SIZE;
4865 lvItem.pszText = szDispText;
4866 if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE;
4867 if (lvItem.pszText == LPSTR_TEXTCALLBACKW) lvItem.pszText = callbackW;
4868 TRACE(" lvItem=%s\n", debuglvitem_t(&lvItem, TRUE));
4869
4870 /* now check if we need to update the focus rectangle */
4871 focus = infoPtr->bFocus && (lvItem.state & LVIS_FOCUSED) ? &infoPtr->rcFocus : 0;
4872 if (!focus) lvItem.state &= ~LVIS_FOCUSED;
4873
4874 LISTVIEW_GetItemMetrics(infoPtr, &lvItem, &rcBox, NULL, NULL, NULL, NULL);
4875 OffsetRect(&rcBox, pos.x, pos.y);
4876
4877 /* Full custom draw stage sequence looks like this:
4878
4879 LV_VIEW_DETAILS:
4880
4881 - CDDS_ITEMPREPAINT
4882 - CDDS_ITEMPREPAINT|CDDS_SUBITEM | => sent n times, where n is number of subitems,
4883 CDDS_ITEMPOSTPAINT|CDDS_SUBITEM | including item itself
4884 - CDDS_ITEMPOSTPAINT
4885
4886 other styles:
4887
4888 - CDDS_ITEMPREPAINT
4889 - CDDS_ITEMPOSTPAINT
4890 */
4891
4892 /* fill in the custom draw structure */
4893 customdraw_fill(&nmlvcd, infoPtr, hdc, &rcBox, &lvItem);
4894 if (cdmode & CDRF_NOTIFYITEMDRAW)
4895 cdsubitemmode = notify_customdraw(infoPtr, CDDS_ITEMPREPAINT, &nmlvcd);
4896 if (cdsubitemmode & CDRF_SKIPDEFAULT) goto postpaint;
4897
4898 if (subitems)
4899 {
4900 while (iterator_next(subitems))
4901 {
4902 DWORD subitemstage = CDRF_DODEFAULT;
4903 NMLVCUSTOMDRAW temp_nmlvcd;
4904
4905 /* We need to query for each subitem, item's data (subitem == 0) is already here at this point */
4906 if (subitems->nItem)
4907 {
4910 lvItem.iItem = nItem;
4911 lvItem.iSubItem = subitems->nItem;
4912 lvItem.state = 0;
4913 lvItem.lParam = 0;
4914 lvItem.cchTextMax = DISP_TEXT_SIZE;
4915 lvItem.pszText = szDispText;
4916 if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE;
4917 if (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT)
4918 lvItem.state = LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED);
4919 if (lvItem.pszText == LPSTR_TEXTCALLBACKW) lvItem.pszText = callbackW;
4920 TRACE(" lvItem=%s\n", debuglvitem_t(&lvItem, TRUE));
4921
4922 /* update custom draw data */
4923 LISTVIEW_GetItemMetrics(infoPtr, &lvItem, &nmlvcd.nmcd.rc, NULL, NULL, NULL, NULL);
4924 OffsetRect(&nmlvcd.nmcd.rc, pos.x, pos.y);
4925 nmlvcd.iSubItem = subitems->nItem;
4926 }
4927
4928 if (cdsubitemmode & CDRF_NOTIFYSUBITEMDRAW)
4929 subitemstage = notify_customdraw(infoPtr, CDDS_SUBITEM | CDDS_ITEMPREPAINT, &nmlvcd);
4930
4931 /*
4932 * A selection should neither affect the colors in the post paint notification nor
4933 * affect the colors of the next drawn subitem. Copy the structure to prevent this.
4934 */
4935 temp_nmlvcd = nmlvcd;
4936 prepaint_setup(infoPtr, hdc, &temp_nmlvcd, subitems->nItem);
4937
4938 if (!(subitemstage & CDRF_SKIPDEFAULT))
4939 LISTVIEW_DrawItemPart(infoPtr, &lvItem, &temp_nmlvcd, &pos);
4940
4941 if (subitemstage & CDRF_NOTIFYPOSTPAINT)
4942 subitemstage = notify_customdraw(infoPtr, CDDS_SUBITEM | CDDS_ITEMPOSTPAINT, &nmlvcd);
4943 }
4944 }
4945 else
4946 {
4947 prepaint_setup(infoPtr, hdc, &nmlvcd, FALSE);
4948 LISTVIEW_DrawItemPart(infoPtr, &lvItem, &nmlvcd, &pos);
4949 }
4950
4951postpaint:
4952 if (cdsubitemmode & CDRF_NOTIFYPOSTPAINT)
4953 {
4954 nmlvcd.iSubItem = 0;
4955 notify_customdraw(infoPtr, CDDS_ITEMPOSTPAINT, &nmlvcd);
4956 }
4957
4958 return TRUE;
4959}
4960
4961/***
4962 * DESCRIPTION:
4963 * Draws listview items when in owner draw mode.
4964 *
4965 * PARAMETER(S):
4966 * [I] infoPtr : valid pointer to the listview structure
4967 * [I] hdc : device context handle
4968 *
4969 * RETURN:
4970 * None
4971 */
4972static void LISTVIEW_RefreshOwnerDraw(const LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, DWORD cdmode)
4973{
4975 DWORD cditemmode = CDRF_DODEFAULT;
4976 NMLVCUSTOMDRAW nmlvcd;
4977 POINT Origin, Position;
4978 DRAWITEMSTRUCT dis;
4979 LVITEMW item;
4980
4981 TRACE("()\n");
4982
4983 ZeroMemory(&dis, sizeof(dis));
4984
4985 /* Get scroll info once before loop */
4986 LISTVIEW_GetOrigin(infoPtr, &Origin);
4987
4988 /* iterate through the invalidated rows */
4989 while(iterator_next(i))
4990 {
4991 item.iItem = i->nItem;
4992 item.iSubItem = 0;
4993 item.mask = LVIF_PARAM | LVIF_STATE;
4994 item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
4995 if (!LISTVIEW_GetItemW(infoPtr, &item)) continue;
4996
4997 dis.CtlType = ODT_LISTVIEW;
4998 dis.CtlID = uID;
4999 dis.itemID = item.iItem;
5001 dis.itemState = 0;
5002 if (item.state & LVIS_SELECTED) dis.itemState |= ODS_SELECTED;
5003 if (infoPtr->bFocus && (item.state & LVIS_FOCUSED)) dis.itemState |= ODS_FOCUS;
5004 dis.hwndItem = infoPtr->hwndSelf;
5005 dis.hDC = hdc;
5006 LISTVIEW_GetItemOrigin(infoPtr, dis.itemID, &Position);
5007 dis.rcItem.left = Position.x + Origin.x;
5008 dis.rcItem.right = dis.rcItem.left + infoPtr->nItemWidth;
5009 dis.rcItem.top = Position.y + Origin.y;
5010 dis.rcItem.bottom = dis.rcItem.top + infoPtr->nItemHeight;
5011 dis.itemData = item.lParam;
5012
5013 TRACE("item=%s, rcItem=%s\n", debuglvitem_t(&item, TRUE), wine_dbgstr_rect(&dis.rcItem));
5014
5015 /*
5016 * Even if we do not send the CDRF_NOTIFYITEMDRAW we need to fill the nmlvcd
5017 * structure for the rest. of the paint cycle
5018 */
5019 customdraw_fill(&nmlvcd, infoPtr, hdc, &dis.rcItem, &item);
5020 if (cdmode & CDRF_NOTIFYITEMDRAW)
5021 cditemmode = notify_customdraw(infoPtr, CDDS_PREPAINT, &nmlvcd);
5022
5023 if (!(cditemmode & CDRF_SKIPDEFAULT))
5024 {
5025 prepaint_setup (infoPtr, hdc, &nmlvcd, FALSE);
5026 SendMessageW(infoPtr->hwndNotify, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis);
5027 }
5028
5029 if (cditemmode & CDRF_NOTIFYPOSTPAINT)
5030 notify_postpaint(infoPtr, &nmlvcd);
5031 }
5032}
5033
5034/***
5035 * DESCRIPTION:
5036 * Draws listview items when in report display mode.
5037 *
5038 * PARAMETER(S):
5039 * [I] infoPtr : valid pointer to the listview structure
5040 * [I] hdc : device context handle
5041 * [I] cdmode : custom draw mode
5042 *
5043 * RETURN:
5044 * None
5045 */
5047{
5048 INT rgntype;
5049 RECT rcClip, rcItem;
5050 POINT Origin;
5051 RANGES colRanges;
5052 INT col;
5053 ITERATOR j;
5054
5055 TRACE("()\n");
5056
5057 /* figure out what to draw */
5058 rgntype = GetClipBox(hdc, &rcClip);
5059 if (rgntype == NULLREGION) return;
5060
5061 /* Get scroll info once before loop */
5062 LISTVIEW_GetOrigin(infoPtr, &Origin);
5063
5064 colRanges = ranges_create(DPA_GetPtrCount(infoPtr->hdpaColumns));
5065
5066 /* narrow down the columns we need to paint */
5067 for(col = 0; col < DPA_GetPtrCount(infoPtr->hdpaColumns); col++)
5068 {
5069 INT index = SendMessageW(infoPtr->hwndHeader, HDM_ORDERTOINDEX, col, 0);
5070
5071 LISTVIEW_GetHeaderRect(infoPtr, index, &rcItem);
5072 if ((rcItem.right + Origin.x >= rcClip.left) && (rcItem.left + Origin.x < rcClip.right))
5073 ranges_additem(colRanges, index);
5074 }
5075 iterator_rangesitems(&j, colRanges);
5076
5077 /* in full row select, we _have_ to draw the main item */
5078 if (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT)
5079 j.nSpecial = 0;
5080
5081 /* iterate through the invalidated rows */
5082 while(iterator_next(i))
5083 {
5084 RANGES subitems;
5086 ITERATOR k;
5087
5088 SelectObject(hdc, infoPtr->hFont);
5089 LISTVIEW_GetItemOrigin(infoPtr, i->nItem, &Position);
5090 Position.x = Origin.x;
5091 Position.y += Origin.y;
5092
5093 subitems = ranges_create(DPA_GetPtrCount(infoPtr->hdpaColumns));
5094
5095 /* iterate through the invalidated columns */
5096 while(iterator_next(&j))
5097 {
5098 LISTVIEW_GetHeaderRect(infoPtr, j.nItem, &rcItem);
5099
5100 if (rgntype == COMPLEXREGION && !((infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) && j.nItem == 0))
5101 {
5102 rcItem.top = 0;
5103 rcItem.bottom = infoPtr->nItemHeight;
5104 OffsetRect(&rcItem, Origin.x, Position.y);
5105 if (!RectVisible(hdc, &rcItem)) continue;
5106 }
5107
5108 ranges_additem(subitems, j.nItem);
5109 }
5110
5111 iterator_rangesitems(&k, subitems);
5112 LISTVIEW_DrawItem(infoPtr, hdc, i->nItem, &k, Position, cdmode);
5114 }
5116}
5117
5118/***
5119 * DESCRIPTION:
5120 * Draws the gridlines if necessary when in report display mode.
5121 *
5122 * PARAMETER(S):
5123 * [I] infoPtr : valid pointer to the listview structure
5124 * [I] hdc : device context handle
5125 *
5126 * RETURN:
5127 * None
5128 */
5130{
5131 INT rgntype;
5132 INT y, itemheight;
5133 INT col, index;
5134 HPEN hPen, hOldPen;
5135 RECT rcClip, rcItem = {0};
5136 POINT Origin;
5137 RANGES colRanges;
5138 ITERATOR j;
5139 BOOL rmost = FALSE;
5140
5141 TRACE("()\n");
5142
5143 /* figure out what to draw */
5144 rgntype = GetClipBox(hdc, &rcClip);
5145 if (rgntype == NULLREGION) return;
5146
5147 /* Get scroll info once before loop */
5148 LISTVIEW_GetOrigin(infoPtr, &Origin);
5149
5150 colRanges = ranges_create(DPA_GetPtrCount(infoPtr->hdpaColumns));
5151
5152 /* narrow down the columns we need to paint */
5153 for(col = 0; col < DPA_GetPtrCount(infoPtr->hdpaColumns); col++)
5154 {
5155 index = SendMessageW(infoPtr->hwndHeader, HDM_ORDERTOINDEX, col, 0);
5156
5157 LISTVIEW_GetHeaderRect(infoPtr, index, &rcItem);
5158 if ((rcItem.right + Origin.x >= rcClip.left) && (rcItem.left + Origin.x < rcClip.right))
5159 ranges_additem(colRanges, index);
5160 }
5161
5162 /* is right most vertical line visible? */
5163 if (DPA_GetPtrCount(infoPtr->hdpaColumns) > 0)
5164 {
5166 LISTVIEW_GetHeaderRect(infoPtr, index, &rcItem);
5167 rmost = (rcItem.right + Origin.x < rcClip.right);
5168 }
5169
5170 if ((hPen = CreatePen( PS_SOLID, 1, comctl32_color.clr3dFace )))
5171 {
5172 hOldPen = SelectObject ( hdc, hPen );
5173
5174 /* draw the vertical lines for the columns */
5175 iterator_rangesitems(&j, colRanges);
5176 while(iterator_next(&j))
5177 {
5178 LISTVIEW_GetHeaderRect(infoPtr, j.nItem, &rcItem);
5179 if (rcItem.left == 0) continue; /* skip leftmost column */
5180 rcItem.left += Origin.x;
5181 rcItem.right += Origin.x;
5182 rcItem.top = infoPtr->rcList.top;
5183 rcItem.bottom = infoPtr->rcList.bottom;
5184 TRACE("vert col=%d, rcItem=%s\n", j.nItem, wine_dbgstr_rect(&rcItem));
5185 MoveToEx (hdc, rcItem.left, rcItem.top, NULL);
5186 LineTo (hdc, rcItem.left, rcItem.bottom);
5187 }
5189 /* draw rightmost grid line if visible */
5190 if (rmost)
5191 {
5193 DPA_GetPtrCount(infoPtr->hdpaColumns) - 1, 0);
5194 LISTVIEW_GetHeaderRect(infoPtr, index, &rcItem);
5195
5196 rcItem.right += Origin.x;
5197
5198 MoveToEx (hdc, rcItem.right, infoPtr->rcList.top, NULL);
5199 LineTo (hdc, rcItem.right, infoPtr->rcList.bottom);
5200 }
5201
5202 /* draw the horizontal lines for the rows */
5203 itemheight = LISTVIEW_CalculateItemHeight(infoPtr);
5204 rcItem.left = infoPtr->rcList.left;
5205 rcItem.right = infoPtr->rcList.right;
5206 for(y = Origin.y > 1 ? Origin.y - 1 : itemheight - 1 + Origin.y % itemheight; y<=infoPtr->rcList.bottom; y+=itemheight)
5207 {
5208 rcItem.bottom = rcItem.top = y;
5209 TRACE("horz rcItem=%s\n", wine_dbgstr_rect(&rcItem));
5210 MoveToEx (hdc, rcItem.left, rcItem.top, NULL);
5211 LineTo (hdc, rcItem.right, rcItem.top);
5212 }
5213
5214 SelectObject( hdc, hOldPen );
5215 DeleteObject( hPen );
5216 }
5217 else
5218 ranges_destroy(colRanges);
5219}
5220
5221/***
5222 * DESCRIPTION:
5223 * Draws listview items when in list display mode.
5224 *
5225 * PARAMETER(S):
5226 * [I] infoPtr : valid pointer to the listview structure
5227 * [I] hdc : device context handle
5228 * [I] cdmode : custom draw mode
5229 *
5230 * RETURN:
5231 * None
5232 */
5233static void LISTVIEW_RefreshList(LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, DWORD cdmode)
5234{
5235 POINT Origin, Position;
5236
5237 /* Get scroll info once before loop */
5238 LISTVIEW_GetOrigin(infoPtr, &Origin);
5239
5240 while(iterator_prev(i))
5241 {
5242 SelectObject(hdc, infoPtr->hFont);
5243 LISTVIEW_GetItemOrigin(infoPtr, i->nItem, &Position);
5244 Position.x += Origin.x;
5245 Position.y += Origin.y;
5246
5247 LISTVIEW_DrawItem(infoPtr, hdc, i->nItem, NULL, Position, cdmode);
5248 }
5249}
5250
5251
5252/***
5253 * DESCRIPTION:
5254 * Draws listview items.
5255 *
5256 * PARAMETER(S):
5257 * [I] infoPtr : valid pointer to the listview structure
5258 * [I] hdc : device context handle
5259 * [I] prcErase : rect to be erased before refresh (may be NULL)
5260 *
5261 * RETURN:
5262 * NoneX
5263 */
5264static void LISTVIEW_Refresh(LISTVIEW_INFO *infoPtr, HDC hdc, const RECT *prcErase)
5265{
5266 COLORREF oldTextColor = 0, oldBkColor = 0;
5267 NMLVCUSTOMDRAW nmlvcd;
5268 HFONT hOldFont = 0;
5269 DWORD cdmode;
5270 INT oldBkMode = 0;
5271 RECT rcClient;
5272 ITERATOR i;
5273 HDC hdcOrig = hdc;
5274 HBITMAP hbmp = NULL;
5275 RANGE range;
5276
5277 LISTVIEW_DUMP(infoPtr);
5278
5279 if (infoPtr->dwLvExStyle & LVS_EX_DOUBLEBUFFER) {
5280 TRACE("double buffering\n");
5281
5282 hdc = CreateCompatibleDC(hdcOrig);
5283 if (!hdc) {
5284 ERR("Failed to create DC for backbuffer\n");
5285 return;
5286 }
5287 hbmp = CreateCompatibleBitmap(hdcOrig, infoPtr->rcList.right,
5288 infoPtr->rcList.bottom);
5289 if (!hbmp) {
5290 ERR("Failed to create bitmap for backbuffer\n");
5291 DeleteDC(hdc);
5292 return;
5293 }
5294
5296 SelectObject(hdc, infoPtr->hFont);
5297
5298 if(GetClipBox(hdcOrig, &rcClient))
5299 IntersectClipRect(hdc, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
5300 } else {
5301 /* Save dc values we're gonna trash while drawing
5302 * FIXME: Should be done in LISTVIEW_DrawItem() */
5303 hOldFont = SelectObject(hdc, infoPtr->hFont);
5304 oldBkMode = GetBkMode(hdc);
5305 oldBkColor = GetBkColor(hdc);
5306 oldTextColor = GetTextColor(hdc);
5307 }
5308
5309 infoPtr->bIsDrawing = TRUE;
5310
5311 if (prcErase) {
5312 LISTVIEW_FillBkgnd(infoPtr, hdc, prcErase);
5313 } else if (infoPtr->dwLvExStyle & LVS_EX_DOUBLEBUFFER) {
5314 /* If no erasing was done (usually because RedrawWindow was called
5315 * with RDW_INVALIDATE only) we need to copy the old contents into
5316 * the backbuffer before continuing. */
5317 BitBlt(hdc, infoPtr->rcList.left, infoPtr->rcList.top,
5318 infoPtr->rcList.right - infoPtr->rcList.left,
5319 infoPtr->rcList.bottom - infoPtr->rcList.top,
5320 hdcOrig, infoPtr->rcList.left, infoPtr->rcList.top, SRCCOPY);
5321 }
5322
5323 GetClientRect(infoPtr->hwndSelf, &rcClient);
5324 customdraw_fill(&nmlvcd, infoPtr, hdc, &rcClient, 0);
5325 cdmode = notify_customdraw(infoPtr, CDDS_PREPAINT, &nmlvcd);
5326 if (cdmode & CDRF_SKIPDEFAULT) goto enddraw;
5327
5328 /* nothing to draw */
5329 if(infoPtr->nItemCount == 0) goto enddraw;
5330
5331 /* figure out what we need to draw */
5332 iterator_visibleitems(&i, infoPtr, hdc);
5334
5335 /* send cache hint notification */
5336 if (infoPtr->dwStyle & LVS_OWNERDATA)
5337 {
5338 NMLVCACHEHINT nmlv;
5339
5340 ZeroMemory(&nmlv, sizeof(NMLVCACHEHINT));
5341 nmlv.iFrom = range.lower;
5342 nmlv.iTo = range.upper - 1;
5343 notify_hdr(infoPtr, LVN_ODCACHEHINT, &nmlv.hdr);
5344 }
5345
5346 if ((infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && (infoPtr->uView == LV_VIEW_DETAILS))
5347 LISTVIEW_RefreshOwnerDraw(infoPtr, &i, hdc, cdmode);
5348 else
5349 {
5350 if (infoPtr->uView == LV_VIEW_DETAILS)
5351 LISTVIEW_RefreshReport(infoPtr, &i, hdc, cdmode);
5352 else /* LV_VIEW_LIST, LV_VIEW_ICON or LV_VIEW_SMALLICON */
5353 LISTVIEW_RefreshList(infoPtr, &i, hdc, cdmode);
5354
5355 /* if we have a focus rect and it's visible, draw it */
5356 if (infoPtr->bFocus && range.lower <= infoPtr->nFocusedItem &&
5357 (range.upper - 1) >= infoPtr->nFocusedItem)
5358 LISTVIEW_DrawFocusRect(infoPtr, hdc);
5359 }
5361
5362enddraw:
5363 /* For LVS_EX_GRIDLINES go and draw lines */
5364 /* This includes the case where there were *no* items */
5365 if ((infoPtr->uView == LV_VIEW_DETAILS) && infoPtr->dwLvExStyle & LVS_EX_GRIDLINES)
5367
5368 /* Draw marquee rectangle if appropriate */
5369 if (infoPtr->bMarqueeSelect)
5370#ifdef __REACTOS__
5371 {
5372 SetBkColor(hdc, RGB(255, 255, 255));
5373 SetTextColor(hdc, RGB(0, 0, 0));
5374 DrawFocusRect(hdc, &infoPtr->marqueeDrawRect);
5375 }
5376#else
5377 DrawFocusRect(hdc, &infoPtr->marqueeDrawRect);
5378#endif
5379
5380 if (cdmode & CDRF_NOTIFYPOSTPAINT)
5381 notify_postpaint(infoPtr, &nmlvcd);
5382
5383 if(hbmp) {
5384 BitBlt(hdcOrig, infoPtr->rcList.left, infoPtr->rcList.top,
5385 infoPtr->rcList.right - infoPtr->rcList.left,
5386 infoPtr->rcList.bottom - infoPtr->rcList.top,
5387 hdc, infoPtr->rcList.left, infoPtr->rcList.top, SRCCOPY);
5388
5390 DeleteDC(hdc);
5391 } else {
5392 SelectObject(hdc, hOldFont);
5393 SetBkMode(hdc, oldBkMode);
5394 SetBkColor(hdc, oldBkColor);
5395 SetTextColor(hdc, oldTextColor);
5396 }
5397
5398 infoPtr->bIsDrawing = FALSE;
5399}
5400
5401
5402/***
5403 * DESCRIPTION:
5404 * Calculates the approximate width and height of a given number of items.
5405 *
5406 * PARAMETER(S):
5407 * [I] infoPtr : valid pointer to the listview structure
5408 * [I] nItemCount : number of items
5409 * [I] wWidth : width
5410 * [I] wHeight : height
5411 *
5412 * RETURN:
5413 * Returns a DWORD. The width in the low word and the height in high word.
5414 */
5415static DWORD LISTVIEW_ApproximateViewRect(const LISTVIEW_INFO *infoPtr, INT nItemCount,
5416 WORD wWidth, WORD wHeight)
5417{
5418 DWORD dwViewRect = 0;
5419
5420 if (nItemCount == -1)
5421 nItemCount = infoPtr->nItemCount;
5422
5423 if (infoPtr->uView == LV_VIEW_LIST)
5424 {
5425 INT nItemCountPerColumn = 1;
5426 INT nColumnCount = 0;
5427
5428 if (wHeight == 0xFFFF)
5429 {
5430 /* use current height */
5431 wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
5432 }
5433
5434 if (wHeight < infoPtr->nItemHeight)
5435 wHeight = infoPtr->nItemHeight;
5436
5437 if (nItemCount > 0)
5438 {
5439 if (infoPtr->nItemHeight > 0)
5440 {
5441 nItemCountPerColumn = wHeight / infoPtr->nItemHeight;
5442 if (nItemCountPerColumn == 0)
5443 nItemCountPerColumn = 1;
5444
5445 if (nItemCount % nItemCountPerColumn != 0)
5446 nColumnCount = nItemCount / nItemCountPerColumn;
5447 else
5448 nColumnCount = nItemCount / nItemCountPerColumn + 1;
5449 }
5450 }
5451
5452 /* Microsoft padding magic */
5453 wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2;
5454 wWidth = nColumnCount * infoPtr->nItemWidth + 2;
5455
5456 dwViewRect = MAKELONG(wWidth, wHeight);
5457 }
5458 else if (infoPtr->uView == LV_VIEW_DETAILS)
5459 {
5460 RECT rcBox;
5461
5462 if (infoPtr->nItemCount > 0)
5463 {
5464 LISTVIEW_GetItemBox(infoPtr, 0, &rcBox);
5465 wWidth = rcBox.right - rcBox.left;
5466 wHeight = (rcBox.bottom - rcBox.top) * nItemCount;
5467 }
5468 else
5469 {
5470 /* use current height and width */
5471 if (wHeight == 0xffff)
5472 wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
5473 if (wWidth == 0xffff)
5474 wWidth = infoPtr->rcList.right - infoPtr->rcList.left;
5475 }
5476
5477 dwViewRect = MAKELONG(wWidth, wHeight);
5478 }
5479 else if (infoPtr->uView == LV_VIEW_ICON)
5480 {
5481 UINT rows,cols;
5482 UINT nItemWidth;
5483 UINT nItemHeight;
5484
5485 nItemWidth = infoPtr->iconSpacing.cx;
5486 nItemHeight = infoPtr->iconSpacing.cy;
5487
5488 if (wWidth == 0xffff)
5489 wWidth = infoPtr->rcList.right - infoPtr->rcList.left;
5490
5491 if (wWidth < nItemWidth)
5492 wWidth = nItemWidth;
5493
5494 cols = wWidth / nItemWidth;
5495 if (cols > nItemCount)
5496 cols = nItemCount;
5497 if (cols < 1)
5498 cols = 1;
5499
5500 if (nItemCount)
5501 {
5502 rows = nItemCount / cols;
5503 if (nItemCount % cols)
5504 rows++;
5505 }
5506 else
5507 rows = 0;
5508
5509 wHeight = (nItemHeight * rows)+2;
5510 wWidth = (nItemWidth * cols)+2;
5511
5512 dwViewRect = MAKELONG(wWidth, wHeight);
5513 }
5514 else if (infoPtr->uView == LV_VIEW_SMALLICON)
5515 FIXME("uView == LV_VIEW_SMALLICON: not implemented\n");
5516
5517 return dwViewRect;
5518}
5519
5520/***
5521 * DESCRIPTION:
5522 * Cancel edit label with saving item text.
5523 *
5524 * PARAMETER(S):
5525 * [I] infoPtr : valid pointer to the listview structure
5526 *
5527 * RETURN:
5528 * Always returns TRUE.
5529 */
5531{
5532 if (infoPtr->hwndEdit)
5533 {
5534 /* handle value will be lost after LISTVIEW_EndEditLabelT */
5535 HWND edit = infoPtr->hwndEdit;
5536
5538 SendMessageW(edit, WM_CLOSE, 0, 0);
5539 }
5540
5541 return TRUE;
5542}
5543
5544/***
5545 * DESCRIPTION:
5546 * Create a drag image list for the specified item.
5547 *
5548 * PARAMETER(S):
5549 * [I] infoPtr : valid pointer to the listview structure
5550 * [I] iItem : index of item
5551 * [O] lppt : Upper-left corner of the image
5552 *
5553 * RETURN:
5554 * Returns a handle to the image list if successful, NULL otherwise.
5555 */
5557{
5558 RECT rcItem;
5559 SIZE size;
5560 POINT pos;
5561 HDC hdc, hdcOrig;
5562 HBITMAP hbmp, hOldbmp;
5563 HFONT hOldFont;
5564 HIMAGELIST dragList = 0;
5565 TRACE("iItem=%d Count=%d\n", iItem, infoPtr->nItemCount);
5566
5567 if (iItem < 0 || iItem >= infoPtr->nItemCount || !lppt)
5568 return 0;
5569
5570 rcItem.left = LVIR_BOUNDS;
5571 if (!LISTVIEW_GetItemRect(infoPtr, iItem, &rcItem))
5572 return 0;
5573
5574 lppt->x = rcItem.left;
5575 lppt->y = rcItem.top;
5576
5577 size.cx = rcItem.right - rcItem.left;
5578 size.cy = rcItem.bottom - rcItem.top;
5579
5580 hdcOrig = GetDC(infoPtr->hwndSelf);
5581 hdc = CreateCompatibleDC(hdcOrig);
5582 hbmp = CreateCompatibleBitmap(hdcOrig, size.cx, size.cy);
5583 hOldbmp = SelectObject(hdc, hbmp);
5584 hOldFont = SelectObject(hdc, infoPtr->hFont);
5585
5586 SetRect(&rcItem, 0, 0, size.cx, size.cy);
5587 FillRect(hdc, &rcItem, infoPtr->hBkBrush);
5588
5589 pos.x = pos.y = 0;
5590 if (LISTVIEW_DrawItem(infoPtr, hdc, iItem, NULL, pos, CDRF_DODEFAULT))
5591 {
5592 dragList = ImageList_Create(size.cx, size.cy, ILC_COLOR, 10, 10);
5593 SelectObject(hdc, hOldbmp);
5594 ImageList_Add(dragList, hbmp, 0);
5595 }
5596 else
5597 SelectObject(hdc, hOldbmp);
5598
5599 SelectObject(hdc, hOldFont);
5601 DeleteDC(hdc);
5602 ReleaseDC(infoPtr->hwndSelf, hdcOrig);
5603
5604 TRACE("ret=%p\n", dragList);
5605
5606 return dragList;
5607}
5608
5609
5610/***
5611 * DESCRIPTION:
5612 * Removes all listview items and subitems.
5613 *
5614 * PARAMETER(S):
5615 * [I] infoPtr : valid pointer to the listview structure
5616 *
5617 * RETURN:
5618 * SUCCESS : TRUE
5619 * FAILURE : FALSE
5620 */
5622{
5623 HDPA hdpaSubItems = NULL;
5625 ITEMHDR *hdrItem;
5626 ITEM_INFO *lpItem;
5627 ITEM_ID *lpID;
5628 INT i, j;
5629
5630 TRACE("()\n");
5631
5632 /* we do it directly, to avoid notifications */
5633 ranges_clear(infoPtr->selectionRanges);
5634 infoPtr->nSelectionMark = -1;
5635 infoPtr->nFocusedItem = -1;
5636 SetRectEmpty(&infoPtr->rcFocus);
5637 /* But we are supposed to leave nHotItem as is! */
5638
5639 /* send LVN_DELETEALLITEMS notification */
5640 if (!(infoPtr->dwStyle & LVS_OWNERDATA) || !destroy)
5641 {
5642 NMLISTVIEW nmlv;
5643
5644 memset(&nmlv, 0, sizeof(NMLISTVIEW));
5645 nmlv.iItem = -1;
5646 suppress = notify_listview(infoPtr, LVN_DELETEALLITEMS, &nmlv);
5647 }
5648
5649 for (i = infoPtr->nItemCount - 1; i >= 0; i--)
5650 {
5651 if (!(infoPtr->dwStyle & LVS_OWNERDATA))
5652 {
5653 /* send LVN_DELETEITEM notification, if not suppressed
5654 and if it is not a virtual listview */
5655 if (!suppress) notify_deleteitem(infoPtr, i);
5656 hdpaSubItems = DPA_GetPtr(infoPtr->hdpaItems, i);
5657 lpItem = DPA_GetPtr(hdpaSubItems, 0);
5658 /* free id struct */
5659 j = DPA_GetPtrIndex(infoPtr->hdpaItemIds, lpItem->id);
5660 lpID = DPA_GetPtr(infoPtr->hdpaItemIds, j);
5661 DPA_DeletePtr(infoPtr->hdpaItemIds, j);
5662 Free(lpID);
5663 /* both item and subitem start with ITEMHDR header */
5664 for (j = 0; j < DPA_GetPtrCount(hdpaSubItems); j++)
5665 {
5666 hdrItem = DPA_GetPtr(hdpaSubItems, j);
5667 if (is_text(hdrItem->pszText)) Free(hdrItem->pszText);
5668 Free(hdrItem);
5669 }
5670 DPA_Destroy(hdpaSubItems);
5671 DPA_DeletePtr(infoPtr->hdpaItems, i);
5672 }
5673 DPA_DeletePtr(infoPtr->hdpaPosX, i);
5674 DPA_DeletePtr(infoPtr->hdpaPosY, i);
5675 infoPtr->nItemCount --;
5676 }
5677
5678 if (!destroy)
5679 {
5680 LISTVIEW_Arrange(infoPtr, LVA_DEFAULT);
5681 LISTVIEW_UpdateScroll(infoPtr);
5682 }
5683 LISTVIEW_InvalidateList(infoPtr);
5684
5685 return TRUE;
5686}
5687
5688/***
5689 * DESCRIPTION:
5690 * Scrolls, and updates the columns, when a column is changing width.
5691 *
5692 * PARAMETER(S):
5693 * [I] infoPtr : valid pointer to the listview structure
5694 * [I] nColumn : column to scroll
5695 * [I] dx : amount of scroll, in pixels
5696 *
5697 * RETURN:
5698 * None.
5699 */
5700static void LISTVIEW_ScrollColumns(LISTVIEW_INFO *infoPtr, INT nColumn, INT dx)
5701{
5702 COLUMN_INFO *lpColumnInfo;
5703 RECT rcOld, rcCol;
5704 POINT ptOrigin;
5705 INT nCol;
5706 HDITEMW hdi;
5707
5708 if (nColumn < 0 || DPA_GetPtrCount(infoPtr->hdpaColumns) < 1) return;
5709 lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, min(nColumn, DPA_GetPtrCount(infoPtr->hdpaColumns) - 1));
5710 rcCol = lpColumnInfo->rcHeader;
5711 if (nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns))
5712 rcCol.left = rcCol.right;
5713
5714 /* adjust the other columns */
5715 hdi.mask = HDI_ORDER;
5716 if (SendMessageW(infoPtr->hwndHeader, HDM_GETITEMW, nColumn, (LPARAM)&hdi))
5717 {
5718 INT nOrder = hdi.iOrder;
5719 for (nCol = 0; nCol < DPA_GetPtrCount(infoPtr->hdpaColumns); nCol++)
5720 {
5721 hdi.mask = HDI_ORDER;
5722 SendMessageW(infoPtr->hwndHeader, HDM_GETITEMW, nCol, (LPARAM)&hdi);
5723 if (hdi.iOrder >= nOrder) {
5724 lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, nCol);
5725 lpColumnInfo->rcHeader.left += dx;
5726 lpColumnInfo->rcHeader.right += dx;
5727 }
5728 }
5729 }
5730
5731 /* do not update screen if not in report mode */
5732 if (!is_redrawing(infoPtr) || infoPtr->uView != LV_VIEW_DETAILS) return;
5733
5734 /* Need to reset the item width when inserting a new column */
5735 infoPtr->nItemWidth += dx;
5736
5737 LISTVIEW_UpdateScroll(infoPtr);
5738 LISTVIEW_GetOrigin(infoPtr, &ptOrigin);
5739
5740 /* scroll to cover the deleted column, and invalidate for redraw */
5741 rcOld = infoPtr->rcList;
5742 rcOld.left = ptOrigin.x + rcCol.left + dx;
5743 ScrollWindowEx(infoPtr->hwndSelf, dx, 0, &rcOld, &rcOld, 0, 0, SW_ERASE | SW_INVALIDATE);
5744}
5745
5746/***
5747 * DESCRIPTION:
5748 * Removes a column from the listview control.
5749 *
5750 * PARAMETER(S):
5751 * [I] infoPtr : valid pointer to the listview structure
5752 * [I] nColumn : column index
5753 *
5754 * RETURN:
5755 * SUCCESS : TRUE
5756 * FAILURE : FALSE
5757 */
5759{
5760 RECT rcCol;
5761
5762 TRACE("nColumn=%d\n", nColumn);
5763
5764 if (nColumn < 0 || nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns))
5765 return FALSE;
5766
5767 /* While the MSDN specifically says that column zero should not be deleted,
5768 what actually happens is that the column itself is deleted but no items or subitems
5769 are removed.
5770 */
5771
5772 LISTVIEW_GetHeaderRect(infoPtr, nColumn, &rcCol);
5773
5774 if (!SendMessageW(infoPtr->hwndHeader, HDM_DELETEITEM, nColumn, 0))
5775 return FALSE;
5776
5777 Free(DPA_GetPtr(infoPtr->hdpaColumns, nColumn));
5778 DPA_DeletePtr(infoPtr->hdpaColumns, nColumn);
5779
5780 if (!(infoPtr->dwStyle & LVS_OWNERDATA) && nColumn)
5781 {
5782 SUBITEM_INFO *lpSubItem, *lpDelItem;
5783 HDPA hdpaSubItems;
5784 INT nItem, nSubItem, i;
5785
5786 for (nItem = 0; nItem < infoPtr->nItemCount; nItem++)
5787 {
5788 hdpaSubItems = DPA_GetPtr(infoPtr->hdpaItems, nItem);
5789 nSubItem = 0;
5790 lpDelItem = 0;
5791 for (i = 1; i < DPA_GetPtrCount(hdpaSubItems); i++)
5792 {
5793 lpSubItem = DPA_GetPtr(hdpaSubItems, i);
5794 if (lpSubItem->iSubItem == nColumn)
5795 {
5796 nSubItem = i;
5797 lpDelItem = lpSubItem;
5798 }
5799 else if (lpSubItem->iSubItem > nColumn)
5800 {
5801 lpSubItem->iSubItem--;
5802 }
5803 }
5804
5805 /* if we found our subitem, zap it */
5806 if (nSubItem > 0)
5807 {
5808 /* free string */
5809 if (is_text(lpDelItem->hdr.pszText))
5810 Free(lpDelItem->hdr.pszText);
5811
5812 /* free item */
5813 Free(lpDelItem);
5814
5815 /* free dpa memory */
5816 DPA_DeletePtr(hdpaSubItems, nSubItem);
5817 }
5818 }
5819 }
5820
5821 /* update the other column info */
5822 if(DPA_GetPtrCount(infoPtr->hdpaColumns) == 0)
5823 LISTVIEW_InvalidateList(infoPtr);
5824 else
5825 LISTVIEW_ScrollColumns(infoPtr, nColumn, -(rcCol.right - rcCol.left));
5826 LISTVIEW_UpdateItemSize(infoPtr);
5827
5828 return TRUE;
5829}
5830
5831/***
5832 * DESCRIPTION:
5833 * Invalidates the listview after an item's insertion or deletion.
5834 *
5835 * PARAMETER(S):
5836 * [I] infoPtr : valid pointer to the listview structure
5837 * [I] nItem : item index
5838 * [I] dir : -1 if deleting, 1 if inserting
5839 *
5840 * RETURN:
5841 * None
5842 */
5843static void LISTVIEW_ScrollOnInsert(LISTVIEW_INFO *infoPtr, INT nItem, INT dir)
5844{
5845 INT nPerCol, nItemCol, nItemRow;
5846 RECT rcScroll;
5847 POINT Origin;
5848
5849 /* if we don't refresh, what's the point of scrolling? */
5850 if (!is_redrawing(infoPtr)) return;
5851
5852 assert (abs(dir) == 1);
5853
5854 /* arrange icons if autoarrange is on */
5855 if (is_autoarrange(infoPtr))
5856 {
5857 BOOL arrange = TRUE;
5858 if (dir < 0 && nItem >= infoPtr->nItemCount) arrange = FALSE;
5859 if (dir > 0 && nItem == infoPtr->nItemCount - 1) arrange = FALSE;
5860 if (arrange) LISTVIEW_Arrange(infoPtr, LVA_DEFAULT);
5861 }
5862
5863 /* scrollbars need updating */
5864 LISTVIEW_UpdateScroll(infoPtr);
5865
5866 /* figure out the item's position */
5867 if (infoPtr->uView == LV_VIEW_DETAILS)
5868 nPerCol = infoPtr->nItemCount + 1;
5869 else if (infoPtr->uView == LV_VIEW_LIST)
5870 nPerCol = LISTVIEW_GetCountPerColumn(infoPtr);
5871 else /* LV_VIEW_ICON, or LV_VIEW_SMALLICON */
5872 return;
5873
5874 nItemCol = nItem / nPerCol;
5875 nItemRow = nItem % nPerCol;
5876 LISTVIEW_GetOrigin(infoPtr, &Origin);
5877
5878 /* move the items below up a slot */
5879 rcScroll.left = nItemCol * infoPtr->nItemWidth;
5880 rcScroll.top = nItemRow * infoPtr->nItemHeight;
5881 rcScroll.right = rcScroll.left + infoPtr->nItemWidth;
5882 rcScroll.bottom = nPerCol * infoPtr->nItemHeight;
5883 OffsetRect(&rcScroll, Origin.x, Origin.y);
5884 TRACE("rcScroll=%s, dx=%d\n", wine_dbgstr_rect(&rcScroll), dir * infoPtr->nItemHeight);
5885 if (IntersectRect(&rcScroll, &rcScroll, &infoPtr->rcList))
5886 {
5887 TRACE("Invalidating rcScroll=%s, rcList=%s\n", wine_dbgstr_rect(&rcScroll), wine_dbgstr_rect(&infoPtr->rcList));
5888 InvalidateRect(infoPtr->hwndSelf, &rcScroll, TRUE);
5889 }
5890
5891 /* report has only that column, so we're done */
5892 if (infoPtr->uView == LV_VIEW_DETAILS) return;
5893
5894 /* now for LISTs, we have to deal with the columns to the right */
5895 SetRect(&rcScroll, (nItemCol + 1) * infoPtr->nItemWidth, 0,
5896 (infoPtr->nItemCount / nPerCol + 1) * infoPtr->nItemWidth,
5897 nPerCol * infoPtr->nItemHeight);
5898 OffsetRect(&rcScroll, Origin.x, Origin.y);
5899 if (IntersectRect(&rcScroll, &rcScroll, &infoPtr->rcList))
5900 InvalidateRect(infoPtr->hwndSelf, &rcScroll, TRUE);
5901}
5902
5903/***
5904 * DESCRIPTION:
5905 * Removes an item from the listview control.
5906 *
5907 * PARAMETER(S):
5908 * [I] infoPtr : valid pointer to the listview structure
5909 * [I] nItem : item index
5910 *
5911 * RETURN:
5912 * SUCCESS : TRUE
5913 * FAILURE : FALSE
5914 */
5916{
5917 LVITEMW item;
5918 const BOOL is_icon = (infoPtr->uView == LV_VIEW_SMALLICON || infoPtr->uView == LV_VIEW_ICON);
5919 INT focus = infoPtr->nFocusedItem;
5920
5921 TRACE("(nItem=%d)\n", nItem);
5922
5923 if (nItem < 0 || nItem >= infoPtr->nItemCount) return FALSE;
5924
5925 /* remove selection, and focus */
5926 item.state = 0;
5927 item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
5928 LISTVIEW_SetItemState(infoPtr, nItem, &item);
5929
5930 /* send LVN_DELETEITEM notification. */
5931 if (!notify_deleteitem(infoPtr, nItem)) return FALSE;
5932
5933 /* we need to do this here, because we'll be deleting stuff */
5934 if (is_icon)
5935 LISTVIEW_InvalidateItem(infoPtr, nItem);
5936
5937 if (!(infoPtr->dwStyle & LVS_OWNERDATA))
5938 {
5939 HDPA hdpaSubItems;
5940 ITEMHDR *hdrItem;
5941 ITEM_INFO *lpItem;
5942 ITEM_ID *lpID;
5943 INT i;
5944
5945 hdpaSubItems = DPA_DeletePtr(infoPtr->hdpaItems, nItem);
5946 lpItem = DPA_GetPtr(hdpaSubItems, 0);
5947
5948 /* free id struct */
5949 i = DPA_GetPtrIndex(infoPtr->hdpaItemIds, lpItem->id);
5950 lpID = DPA_GetPtr(infoPtr->hdpaItemIds, i);
5951 DPA_DeletePtr(infoPtr->hdpaItemIds, i);
5952 Free(lpID);
5953 for (i = 0; i < DPA_GetPtrCount(hdpaSubItems); i++)
5954 {
5955 hdrItem = DPA_GetPtr(hdpaSubItems, i);
5956 if (is_text(hdrItem->pszText)) Free(hdrItem->pszText);
5957 Free(hdrItem);
5958 }
5959 DPA_Destroy(hdpaSubItems);
5960 }
5961
5962 if (is_icon)
5963 {
5964 DPA_DeletePtr(infoPtr->hdpaPosX, nItem);
5965 DPA_DeletePtr(infoPtr->hdpaPosY, nItem);
5966 }
5967
5968 infoPtr->nItemCount--;
5969 LISTVIEW_ShiftIndices(infoPtr, nItem, -1);
5970 LISTVIEW_ShiftFocus(infoPtr, focus, nItem, -1);
5971
5972 /* now is the invalidation fun */
5973 if (!is_icon)
5974 LISTVIEW_ScrollOnInsert(infoPtr, nItem, -1);
5975 return TRUE;
5976}
5977
5978
5979/***
5980 * DESCRIPTION:
5981 * Callback implementation for editlabel control
5982 *
5983 * PARAMETER(S):
5984 * [I] infoPtr : valid pointer to the listview structure
5985 * [I] storeText : store edit box text as item text
5986 * [I] isW : TRUE if psxText is Unicode, FALSE if it's ANSI
5987 *
5988 * RETURN:
5989 * SUCCESS : TRUE
5990 * FAILURE : FALSE
5991 */
5993{
5994 HWND hwndSelf = infoPtr->hwndSelf;
5995 WCHAR szDispText[DISP_TEXT_SIZE] = { 0 };
5996 NMLVDISPINFOW dispInfo;
5997 INT editedItem = infoPtr->nEditLabelItem;
5998 BOOL same;
5999 WCHAR *pszText = NULL;
6000 BOOL res;
6001
6002 if (storeText)
6003 {
6005
6006 if (len++)
6007 {
6008 if (!(pszText = Alloc(len * (isW ? sizeof(WCHAR) : sizeof(CHAR)))))
6009 return FALSE;
6010
6011 if (isW)
6012 GetWindowTextW(infoPtr->hwndEdit, pszText, len);
6013 else
6014 GetWindowTextA(infoPtr->hwndEdit, (CHAR*)pszText, len);
6015 }
6016 }
6017
6018 TRACE("(pszText=%s, isW=%d)\n", debugtext_t(pszText, isW), isW);
6019
6020 ZeroMemory(&dispInfo, sizeof(dispInfo));
6021 dispInfo.item.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT;
6022 dispInfo.item.iItem = editedItem;
6023 dispInfo.item.iSubItem = 0;
6024 dispInfo.item.stateMask = ~0;
6025 dispInfo.item.pszText = szDispText;
6026 dispInfo.item.cchTextMax = DISP_TEXT_SIZE;
6027 if (!LISTVIEW_GetItemT(infoPtr, &dispInfo.item, isW))
6028 {
6029 res = FALSE;
6030 goto cleanup;
6031 }
6032
6033 if (isW)
6034 same = (lstrcmpW(dispInfo.item.pszText, pszText) == 0);
6035 else
6036 {
6037 LPWSTR tmp = textdupTtoW(pszText, FALSE);
6038 same = (lstrcmpW(dispInfo.item.pszText, tmp) == 0);
6039 textfreeT(tmp, FALSE);
6040 }
6041
6042 /* add the text from the edit in */
6043 dispInfo.item.mask |= LVIF_TEXT;
6044 dispInfo.item.pszText = same ? NULL : pszText;
6045 dispInfo.item.cchTextMax = textlenT(dispInfo.item.pszText, isW);
6046
6047 infoPtr->notify_mask &= ~NOTIFY_MASK_END_LABEL_EDIT;
6048
6049 /* Do we need to update the Item Text */
6050 res = notify_dispinfoT(infoPtr, LVN_ENDLABELEDITW, &dispInfo, isW);
6051
6053
6054 infoPtr->nEditLabelItem = -1;
6055 infoPtr->hwndEdit = 0;
6056
6057 if (!res) goto cleanup;
6058
6059 if (!IsWindow(hwndSelf))
6060 {
6061 res = FALSE;
6062 goto cleanup;
6063 }
6064 if (!pszText) return TRUE;
6065 if (same)
6066 {
6067 res = TRUE;
6068 goto cleanup;
6069 }
6070
6071 if (!(infoPtr->dwStyle & LVS_OWNERDATA))
6072 {
6073 HDPA hdpaSubItems = DPA_GetPtr(infoPtr->hdpaItems, editedItem);
6074 ITEM_INFO* lpItem = DPA_GetPtr(hdpaSubItems, 0);
6075 if (lpItem && lpItem->hdr.pszText == LPSTR_TEXTCALLBACKW)
6076 {
6077 LISTVIEW_InvalidateItem(infoPtr, editedItem);
6078 res = TRUE;
6079 goto cleanup;
6080 }
6081 }
6082
6083 ZeroMemory(&dispInfo, sizeof(dispInfo));
6084 dispInfo.item.mask = LVIF_TEXT;
6085 dispInfo.item.iItem = editedItem;
6086 dispInfo.item.iSubItem = 0;
6087 dispInfo.item.pszText = pszText;
6088 dispInfo.item.cchTextMax = textlenT(pszText, isW);
6089 res = LISTVIEW_SetItemT(infoPtr, &dispInfo.item, isW);
6090
6091cleanup:
6092 Free(pszText);
6093
6094 return res;
6095}
6096
6097/***
6098 * DESCRIPTION:
6099 * Subclassed edit control windproc function
6100 *
6101 * PARAMETER(S):
6102 * [I] hwnd : the edit window handle
6103 * [I] uMsg : the message that is to be processed
6104 * [I] wParam : first message parameter
6105 * [I] lParam : second message parameter
6106 * [I] isW : TRUE if input is Unicode
6107 *
6108 * RETURN:
6109 * Zero.
6110 */
6112{
6114 BOOL save = TRUE;
6115
6116 TRACE("(hwnd=%p, uMsg=%x, wParam=%lx, lParam=%lx, isW=%d)\n",
6117 hwnd, uMsg, wParam, lParam, isW);
6118
6119 switch (uMsg)
6120 {
6121 case WM_GETDLGCODE:
6123
6124 case WM_DESTROY:
6125 {
6126 WNDPROC editProc = infoPtr->EditWndProc;
6127 infoPtr->EditWndProc = 0;
6129 return CallWindowProcT(editProc, hwnd, uMsg, wParam, lParam, isW);
6130 }
6131
6132 case WM_KEYDOWN:
6133 if (VK_ESCAPE == (INT)wParam)
6134 {
6135 save = FALSE;
6136 break;
6137 }
6138 else if (VK_RETURN == (INT)wParam)
6139 break;
6140
6141 default:
6142 return CallWindowProcT(infoPtr->EditWndProc, hwnd, uMsg, wParam, lParam, isW);
6143 }
6144
6145 /* kill the edit */
6146 if (infoPtr->hwndEdit)
6147 LISTVIEW_EndEditLabelT(infoPtr, save, isW);
6148
6149 SendMessageW(hwnd, WM_CLOSE, 0, 0);
6150 return 0;
6151}
6152
6153/***
6154 * DESCRIPTION:
6155 * Subclassed edit control Unicode windproc function
6156 *
6157 * PARAMETER(S):
6158 * [I] hwnd : the edit window handle
6159 * [I] uMsg : the message that is to be processed
6160 * [I] wParam : first message parameter
6161 * [I] lParam : second message parameter
6162 *
6163 * RETURN:
6164 */
6166{
6167 return EditLblWndProcT(hwnd, uMsg, wParam, lParam, TRUE);
6168}
6169
6170/***
6171 * DESCRIPTION:
6172 * Subclassed edit control ANSI windproc function
6173 *
6174 * PARAMETER(S):
6175 * [I] hwnd : the edit window handle
6176 * [I] uMsg : the message that is to be processed
6177 * [I] wParam : first message parameter
6178 * [I] lParam : second message parameter
6179 *
6180 * RETURN:
6181 */
6183{
6184 return EditLblWndProcT(hwnd, uMsg, wParam, lParam, FALSE);
6185}
6186
6187/***
6188 * DESCRIPTION:
6189 * Creates a subclassed edit control
6190 *
6191 * PARAMETER(S):
6192 * [I] infoPtr : valid pointer to the listview structure
6193 * [I] text : initial text for the edit
6194 * [I] style : the window style
6195 * [I] isW : TRUE if input is Unicode
6196 *
6197 * RETURN:
6198 */
6200{
6203 HWND hedit;
6204
6205 TRACE("(%p, text=%s, isW=%d)\n", infoPtr, debugtext_t(text, isW), isW);
6206
6207 /* window will be resized and positioned after LVN_BEGINLABELEDIT */
6208 if (isW)
6209 hedit = CreateWindowW(WC_EDITW, text, style, 0, 0, 0, 0, infoPtr->hwndSelf, 0, hinst, 0);
6210 else
6211 hedit = CreateWindowA(WC_EDITA, (LPCSTR)text, style, 0, 0, 0, 0, infoPtr->hwndSelf, 0, hinst, 0);
6212
6213 if (!hedit) return 0;
6214
6215 infoPtr->EditWndProc = (WNDPROC)
6218
6219 SendMessageW(hedit, WM_SETFONT, (WPARAM)infoPtr->hFont, FALSE);
6221
6222 return hedit;
6223}
6224
6225/***
6226 * DESCRIPTION:
6227 * Begin in place editing of specified list view item
6228 *
6229 * PARAMETER(S):
6230 * [I] infoPtr : valid pointer to the listview structure
6231 * [I] nItem : item index
6232 * [I] isW : TRUE if it's a Unicode req, FALSE if ASCII
6233 *
6234 * RETURN:
6235 * SUCCESS : TRUE
6236 * FAILURE : FALSE
6237 */
6239{
6240 WCHAR disptextW[DISP_TEXT_SIZE] = { 0 };
6241 HWND hwndSelf = infoPtr->hwndSelf;
6242 NMLVDISPINFOW dispInfo;
6243 HFONT hOldFont = NULL;
6245 RECT rect;
6246 SIZE sz;
6247 HDC hdc;
6248
6249 TRACE("(nItem=%d, isW=%d)\n", nItem, isW);
6250
6251 if (~infoPtr->dwStyle & LVS_EDITLABELS) return 0;
6252
6253 /* remove existing edit box */
6254 if (infoPtr->hwndEdit)
6255 {
6256 SetFocus(infoPtr->hwndSelf);
6257 infoPtr->hwndEdit = 0;
6258 }
6259
6260 if (nItem < 0 || nItem >= infoPtr->nItemCount) return 0;
6261
6262 infoPtr->nEditLabelItem = nItem;
6263
6264 LISTVIEW_SetSelection(infoPtr, nItem);
6265 LISTVIEW_SetItemFocus(infoPtr, nItem);
6266 LISTVIEW_InvalidateItem(infoPtr, nItem);
6267
6268 rect.left = LVIR_LABEL;
6269 if (!LISTVIEW_GetItemRect(infoPtr, nItem, &rect)) return 0;
6270
6271 ZeroMemory(&dispInfo, sizeof(dispInfo));
6272 dispInfo.item.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT;
6273 dispInfo.item.iItem = nItem;
6274 dispInfo.item.iSubItem = 0;
6275 dispInfo.item.stateMask = ~0;
6276 dispInfo.item.pszText = disptextW;
6277 dispInfo.item.cchTextMax = DISP_TEXT_SIZE;
6278 if (!LISTVIEW_GetItemT(infoPtr, &dispInfo.item, isW)) return 0;
6279
6280 infoPtr->hwndEdit = CreateEditLabelT(infoPtr, dispInfo.item.pszText, isW);
6281 if (!infoPtr->hwndEdit) return 0;
6282
6283 if (notify_dispinfoT(infoPtr, LVN_BEGINLABELEDITW, &dispInfo, isW))
6284 {
6285 if (!IsWindow(hwndSelf))
6286 return 0;
6287 SendMessageW(infoPtr->hwndEdit, WM_CLOSE, 0, 0);
6288 infoPtr->hwndEdit = 0;
6289 return 0;
6290 }
6291
6292 TRACE("disp text=%s\n", debugtext_t(dispInfo.item.pszText, isW));
6293
6294 /* position and display edit box */
6295 hdc = GetDC(infoPtr->hwndSelf);
6296
6297 /* select the font to get appropriate metric dimensions */
6298 if (infoPtr->hFont)
6299 hOldFont = SelectObject(hdc, infoPtr->hFont);
6300
6301 /* use real edit box content, it could be altered during LVN_BEGINLABELEDIT notification */
6302 GetWindowTextW(infoPtr->hwndEdit, disptextW, DISP_TEXT_SIZE);
6303 TRACE("edit box text=%s\n", debugstr_w(disptextW));
6304
6305 /* get string length in pixels */
6306 GetTextExtentPoint32W(hdc, disptextW, lstrlenW(disptextW), &sz);
6307
6308 /* add extra spacing for the next character */
6310 sz.cx += tm.tmMaxCharWidth * 2;
6311
6312 if (infoPtr->hFont)
6313 SelectObject(hdc, hOldFont);
6314
6315 ReleaseDC(infoPtr->hwndSelf, hdc);
6316
6317 sz.cy = rect.bottom - rect.top + 2;
6318 rect.left -= 2;
6319 rect.top -= 1;
6320 TRACE("moving edit=(%d,%d)-(%d,%d)\n", rect.left, rect.top, sz.cx, sz.cy);
6321 MoveWindow(infoPtr->hwndEdit, rect.left, rect.top, sz.cx, sz.cy, FALSE);
6322 ShowWindow(infoPtr->hwndEdit, SW_NORMAL);
6323 SetFocus(infoPtr->hwndEdit);
6324 SendMessageW(infoPtr->hwndEdit, EM_SETSEL, 0, -1);
6325 return infoPtr->hwndEdit;
6326}
6327
6328
6329/***
6330 * DESCRIPTION:
6331 * Ensures the specified item is visible, scrolling into view if necessary.
6332 *
6333 * PARAMETER(S):
6334 * [I] infoPtr : valid pointer to the listview structure
6335 * [I] nItem : item index
6336 * [I] bPartial : partially or entirely visible
6337 *
6338 * RETURN:
6339 * SUCCESS : TRUE
6340 * FAILURE : FALSE
6341 */
6342static BOOL LISTVIEW_EnsureVisible(LISTVIEW_INFO *infoPtr, INT nItem, BOOL bPartial)
6343{
6344 INT nScrollPosHeight = 0;
6345 INT nScrollPosWidth = 0;
6346 INT nHorzAdjust = 0;
6347 INT nVertAdjust = 0;
6348 INT nHorzDiff = 0;
6349 INT nVertDiff = 0;
6350 RECT rcItem, rcTemp;
6351
6352 rcItem.left = LVIR_BOUNDS;
6353 if (!LISTVIEW_GetItemRect(infoPtr, nItem, &rcItem)) return FALSE;
6354
6355 if (bPartial && IntersectRect(&rcTemp, &infoPtr->rcList, &rcItem)) return TRUE;
6356
6357 if (rcItem.left < infoPtr->rcList.left || rcItem.right > infoPtr->rcList.right)
6358 {
6359 /* scroll left/right, but in LV_VIEW_DETAILS mode */
6360 if (infoPtr->uView == LV_VIEW_LIST)
6361 nScrollPosWidth = infoPtr->nItemWidth;
6362 else if ((infoPtr->uView == LV_VIEW_SMALLICON) || (infoPtr->uView == LV_VIEW_ICON))
6363 nScrollPosWidth = 1;
6364
6365 if (rcItem.left < infoPtr->rcList.left)
6366 {
6367 nHorzAdjust = -1;
6368 if (infoPtr->uView != LV_VIEW_DETAILS) nHorzDiff = rcItem.left - infoPtr->rcList.left;
6369 }
6370 else
6371 {
6372 nHorzAdjust = 1;
6373 if (infoPtr->uView != LV_VIEW_DETAILS) nHorzDiff = rcItem.right - infoPtr->rcList.right;
6374 }
6375 }
6376
6377 if (rcItem.top < infoPtr->rcList.top || rcItem.bottom > infoPtr->rcList.bottom)
6378 {
6379 /* scroll up/down, but not in LVS_LIST mode */
6380 if (infoPtr->uView == LV_VIEW_DETAILS)
6381 nScrollPosHeight = infoPtr->nItemHeight;
6382 else if ((infoPtr->uView == LV_VIEW_ICON) || (infoPtr->uView == LV_VIEW_SMALLICON))
6383 nScrollPosHeight = 1;
6384
6385 if (rcItem.top < infoPtr->rcList.top)
6386 {
6387 nVertAdjust = -1;
6388 if (infoPtr->uView != LV_VIEW_LIST) nVertDiff = rcItem.top - infoPtr->rcList.top;
6389 }
6390 else
6391 {
6392 nVertAdjust = 1;
6393 if (infoPtr->uView != LV_VIEW_LIST) nVertDiff = rcItem.bottom - infoPtr->rcList.bottom;
6394 }
6395 }
6396
6397 if (!nScrollPosWidth && !nScrollPosHeight) return TRUE;
6398
6399 if (nScrollPosWidth)
6400 {
6401 INT diff = nHorzDiff / nScrollPosWidth;
6402 if (nHorzDiff % nScrollPosWidth) diff += nHorzAdjust;
6403 LISTVIEW_HScroll(infoPtr, SB_INTERNAL, diff);
6404 }
6405
6406 if (nScrollPosHeight)
6407 {
6408 INT diff = nVertDiff / nScrollPosHeight;
6409 if (nVertDiff % nScrollPosHeight) diff += nVertAdjust;
6410 LISTVIEW_VScroll(infoPtr, SB_INTERNAL, diff);
6411 }
6412
6413 return TRUE;
6414}
6415
6416/***
6417 * DESCRIPTION:
6418 * Searches for an item with specific characteristics.
6419 *
6420 * PARAMETER(S):
6421 * [I] hwnd : window handle
6422 * [I] nStart : base item index
6423 * [I] lpFindInfo : item information to look for
6424 *
6425 * RETURN:
6426 * SUCCESS : index of item
6427 * FAILURE : -1
6428 */
6429static INT LISTVIEW_FindItemW(const LISTVIEW_INFO *infoPtr, INT nStart,
6430 const LVFINDINFOW *lpFindInfo)
6431{
6432 WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
6433 BOOL bWrap = FALSE, bNearest = FALSE;
6434 INT nItem = nStart + 1, nLast = infoPtr->nItemCount, nNearestItem = -1;
6435 ULONG xdist, ydist, dist, mindist = 0x7fffffff;
6437 LVITEMW lvItem;
6438
6439 /* Search in virtual listviews should be done by application, not by
6440 listview control, so we just send LVN_ODFINDITEMW and return the result */
6441 if (infoPtr->dwStyle & LVS_OWNERDATA)
6442 {
6443 NMLVFINDITEMW nmlv;
6444
6445 nmlv.iStart = nStart;
6446 nmlv.lvfi = *lpFindInfo;
6447 return notify_hdr(infoPtr, LVN_ODFINDITEMW, (LPNMHDR)&nmlv.hdr);
6448 }
6449
6450 if (!lpFindInfo || nItem < 0) return -1;
6451
6452 lvItem.mask = 0;
6453 if (lpFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL | LVFI_SUBSTRING))
6454 {
6455 lvItem.mask |= LVIF_TEXT;
6456 lvItem.pszText = szDispText;
6457 lvItem.cchTextMax = DISP_TEXT_SIZE;
6458 }
6459
6460 if (lpFindInfo->flags & LVFI_WRAP)
6461 bWrap = TRUE;
6462
6463 if ((lpFindInfo->flags & LVFI_NEARESTXY) &&
6464 (infoPtr->uView == LV_VIEW_ICON || infoPtr->uView == LV_VIEW_SMALLICON))
6465 {
6466 POINT Origin;
6467 RECT rcArea;
6468
6469 LISTVIEW_GetOrigin(infoPtr, &Origin);
6470 Destination.x = lpFindInfo->pt.x - Origin.x;
6471 Destination.y = lpFindInfo->pt.y - Origin.y;
6472 switch(lpFindInfo->vkDirection)
6473 {
6474 case VK_DOWN: Destination.y += infoPtr->nItemHeight; break;
6475 case VK_UP: Destination.y -= infoPtr->nItemHeight; break;
6476 case VK_RIGHT: Destination.x += infoPtr->nItemWidth; break;
6477 case VK_LEFT: Destination.x -= infoPtr->nItemWidth; break;
6478 case VK_HOME: Destination.x = Destination.y = 0; break;
6479 case VK_NEXT: Destination.y += infoPtr->rcList.bottom - infoPtr->rcList.top; break;
6480 case VK_PRIOR: Destination.y -= infoPtr->rcList.bottom - infoPtr->rcList.top; break;
6481 case VK_END:
6482 LISTVIEW_GetAreaRect(infoPtr, &rcArea);
6483 Destination.x = rcArea.right;
6484 Destination.y = rcArea.bottom;
6485 break;
6486 default: ERR("Unknown vkDirection=%d\n", lpFindInfo->vkDirection);
6487 }
6488 bNearest = TRUE;
6489 }
6490 else Destination.x = Destination.y = 0;
6491
6492 /* if LVFI_PARAM is specified, all other flags are ignored */
6493 if (lpFindInfo->flags & LVFI_PARAM)
6494 {
6495 lvItem.mask |= LVIF_PARAM;
6496 bNearest = FALSE;
6497 lvItem.mask &= ~LVIF_TEXT;
6498 }
6499
6500 nItem = bNearest ? -1 : nStart + 1;
6501
6502again:
6503 for (; nItem < nLast; nItem++)
6504 {
6505 lvItem.iItem = nItem;
6506 lvItem.iSubItem = 0;
6507 lvItem.pszText = szDispText;
6508 if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) continue;
6509
6510 if (lvItem.mask & LVIF_PARAM)
6511 {
6512 if (lpFindInfo->lParam == lvItem.lParam)
6513 return nItem;
6514 else
6515 continue;
6516 }
6517
6518 if (lvItem.mask & LVIF_TEXT)
6519 {
6520 if (lpFindInfo->flags & (LVFI_PARTIAL | LVFI_SUBSTRING))
6521 {
6522 WCHAR *p = wcsstr(lvItem.pszText, lpFindInfo->psz);
6523 if (!p || p != lvItem.pszText) continue;
6524 }
6525 else
6526 {
6527 if (lstrcmpW(lvItem.pszText, lpFindInfo->psz) != 0) continue;
6528 }
6529 }
6530
6531 if (!bNearest) return nItem;
6532
6533 /* This is very inefficient. To do a good job here,
6534 * we need a sorted array of (x,y) item positions */
6535 LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position);
6536
6537 /* compute the distance^2 to the destination */
6538 xdist = Destination.x - Position.x;
6539 ydist = Destination.y - Position.y;
6540 dist = xdist * xdist + ydist * ydist;
6541
6542 /* remember the distance, and item if it's closer */
6543 if (dist < mindist)
6544 {
6545 mindist = dist;
6546 nNearestItem = nItem;
6547 }
6548 }
6549
6550 if (bWrap)
6551 {
6552 nItem = 0;
6553 nLast = min(nStart + 1, infoPtr->nItemCount);
6554 bWrap = FALSE;
6555 goto again;
6556 }
6557
6558 return nNearestItem;
6559}
6560
6561/***
6562 * DESCRIPTION:
6563 * Searches for an item with specific characteristics.
6564 *
6565 * PARAMETER(S):
6566 * [I] hwnd : window handle
6567 * [I] nStart : base item index
6568 * [I] lpFindInfo : item information to look for
6569 *
6570 * RETURN:
6571 * SUCCESS : index of item
6572 * FAILURE : -1
6573 */
6574static INT LISTVIEW_FindItemA(const LISTVIEW_INFO *infoPtr, INT nStart,
6575 const LVFINDINFOA *lpFindInfo)
6576{
6577 LVFINDINFOW fiw;
6578 INT res;
6579 LPWSTR strW = NULL;
6580
6581 memcpy(&fiw, lpFindInfo, sizeof(fiw));
6582 if (lpFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL | LVFI_SUBSTRING))
6583 fiw.psz = strW = textdupTtoW((LPCWSTR)lpFindInfo->psz, FALSE);
6584 res = LISTVIEW_FindItemW(infoPtr, nStart, &fiw);
6586 return res;
6587}
6588
6589/***
6590 * DESCRIPTION:
6591 * Retrieves column attributes.
6592 *
6593 * PARAMETER(S):
6594 * [I] infoPtr : valid pointer to the listview structure
6595 * [I] nColumn : column index
6596 * [IO] lpColumn : column information
6597 * [I] isW : if TRUE, then lpColumn is a LPLVCOLUMNW
6598 * otherwise it is in fact a LPLVCOLUMNA
6599 *
6600 * RETURN:
6601 * SUCCESS : TRUE
6602 * FAILURE : FALSE
6603 */
6604static BOOL LISTVIEW_GetColumnT(const LISTVIEW_INFO *infoPtr, INT nColumn, LPLVCOLUMNW lpColumn, BOOL isW)
6605{
6606 COLUMN_INFO *lpColumnInfo;
6607 HDITEMW hdi;
6608
6609 if (!lpColumn || nColumn < 0 || nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return FALSE;
6610 lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, nColumn);
6611
6612 /* initialize memory */
6613 ZeroMemory(&hdi, sizeof(hdi));
6614
6615 if (lpColumn->mask & LVCF_TEXT)
6616 {
6617 hdi.mask |= HDI_TEXT;
6618 hdi.pszText = lpColumn->pszText;
6619 hdi.cchTextMax = lpColumn->cchTextMax;
6620 }
6621
6622 if (lpColumn->mask & LVCF_IMAGE)
6623 hdi.mask |= HDI_IMAGE;
6624
6625 if (lpColumn->mask & LVCF_ORDER)
6626 hdi.mask |= HDI_ORDER;
6627
6628 if (lpColumn->mask & LVCF_SUBITEM)
6629 hdi.mask |= HDI_LPARAM;
6630
6631 if (!SendMessageW(infoPtr->hwndHeader, isW ? HDM_GETITEMW : HDM_GETITEMA, nColumn, (LPARAM)&hdi)) return FALSE;
6632
6633 if (lpColumn->mask & LVCF_FMT)
6634 lpColumn->fmt = lpColumnInfo->fmt;
6635
6636 if (lpColumn->mask & LVCF_WIDTH)
6637 lpColumn->cx = lpColumnInfo->rcHeader.right - lpColumnInfo->rcHeader.left;
6638
6639 if (lpColumn->mask & LVCF_IMAGE)
6640 lpColumn->iImage = hdi.iImage;
6641
6642 if (lpColumn->mask & LVCF_ORDER)
6643 lpColumn->iOrder = hdi.iOrder;
6644
6645 if (lpColumn->mask & LVCF_SUBITEM)
6646 lpColumn->iSubItem = hdi.lParam;
6647
6648 if (lpColumn->mask & LVCF_MINWIDTH)
6649 lpColumn->cxMin = lpColumnInfo->cxMin;
6650
6651 return TRUE;
6652}
6653
6654static inline BOOL LISTVIEW_GetColumnOrderArray(const LISTVIEW_INFO *infoPtr, INT iCount, LPINT lpiArray)
6655{
6656 if (!infoPtr->hwndHeader) return FALSE;
6657 return SendMessageW(infoPtr->hwndHeader, HDM_GETORDERARRAY, iCount, (LPARAM)lpiArray);
6658}
6659
6660/***
6661 * DESCRIPTION:
6662 * Retrieves the column width.
6663 *
6664 * PARAMETER(S):
6665 * [I] infoPtr : valid pointer to the listview structure
6666 * [I] int : column index
6667 *
6668 * RETURN:
6669 * SUCCESS : column width
6670 * FAILURE : zero
6671 */
6672static INT LISTVIEW_GetColumnWidth(const LISTVIEW_INFO *infoPtr, INT nColumn)
6673{
6674 INT nColumnWidth = 0;
6675 HDITEMW hdItem;
6676
6677 TRACE("nColumn=%d\n", nColumn);
6678
6679 /* we have a 'column' in LIST and REPORT mode only */
6680 switch(infoPtr->uView)
6681 {
6682 case LV_VIEW_LIST:
6683 nColumnWidth = infoPtr->nItemWidth;
6684 break;
6685 case LV_VIEW_DETAILS:
6686 /* We are not using LISTVIEW_GetHeaderRect as this data is updated only after a HDN_ITEMCHANGED.
6687 * There is an application that subclasses the listview, calls LVM_GETCOLUMNWIDTH in the
6688 * HDN_ITEMCHANGED handler and goes into infinite recursion if it receives old data.
6689 */
6690 hdItem.mask = HDI_WIDTH;
6691 if (!SendMessageW(infoPtr->hwndHeader, HDM_GETITEMW, nColumn, (LPARAM)&hdItem))
6692 {
6693 WARN("(%p): HDM_GETITEMW failed for item %d\n", infoPtr->hwndSelf, nColumn);
6694 return 0;
6695 }
6696 nColumnWidth = hdItem.cxy;
6697 break;
6698 }
6699
6700 TRACE("nColumnWidth=%d\n", nColumnWidth);
6701 return nColumnWidth;
6702}
6703
6704/***
6705 * DESCRIPTION:
6706 * In list or report display mode, retrieves the number of items that can fit
6707 * vertically in the visible area. In icon or small icon display mode,
6708 * retrieves the total number of visible items.
6709 *
6710 * PARAMETER(S):
6711 * [I] infoPtr : valid pointer to the listview structure
6712 *
6713 * RETURN:
6714 * Number of fully visible items.
6715 */
6717{
6718 switch (infoPtr->uView)
6719 {
6720 case LV_VIEW_ICON:
6721 case LV_VIEW_SMALLICON:
6722 return infoPtr->nItemCount;
6723 case LV_VIEW_DETAILS:
6724 return LISTVIEW_GetCountPerColumn(infoPtr);
6725 case LV_VIEW_LIST:
6726 return LISTVIEW_GetCountPerRow(infoPtr) * LISTVIEW_GetCountPerColumn(infoPtr);
6727 }
6728 assert(FALSE);
6729 return 0;
6730}
6731
6732/***
6733 * DESCRIPTION:
6734 * Retrieves an image list handle.
6735 *
6736 * PARAMETER(S):
6737 * [I] infoPtr : valid pointer to the listview structure
6738 * [I] nImageList : image list identifier
6739 *
6740 * RETURN:
6741 * SUCCESS : image list handle
6742 * FAILURE : NULL
6743 */
6744static HIMAGELIST LISTVIEW_GetImageList(const LISTVIEW_INFO *infoPtr, INT nImageList)
6745{
6746 switch (nImageList)
6747 {
6748 case LVSIL_NORMAL: return infoPtr->himlNormal;
6749 case LVSIL_SMALL: return infoPtr->himlSmall;
6750 case LVSIL_STATE: return infoPtr->himlState;
6751 case LVSIL_GROUPHEADER:
6752 FIXME("LVSIL_GROUPHEADER not supported\n");
6753 break;
6754 default:
6755 WARN("got unknown imagelist index - %d\n", nImageList);
6756 }
6757 return NULL;
6758}
6759
6760/* LISTVIEW_GetISearchString */
6761
6762/***
6763 * DESCRIPTION:
6764 * Retrieves item attributes.
6765 *
6766 * PARAMETER(S):
6767 * [I] hwnd : window handle
6768 * [IO] lpLVItem : item info
6769 * [I] isW : if TRUE, then lpLVItem is a LPLVITEMW,
6770 * if FALSE, then lpLVItem is a LPLVITEMA.
6771 *
6772 * NOTE:
6773 * This is the internal 'GetItem' interface -- it tries to
6774 * be smart and avoid text copies, if possible, by modifying
6775 * lpLVItem->pszText to point to the text string. Please note
6776 * that this is not always possible (e.g. OWNERDATA), so on
6777 * entry you *must* supply valid values for pszText, and cchTextMax.
6778 * The only difference to the documented interface is that upon
6779 * return, you should use *only* the lpLVItem->pszText, rather than
6780 * the buffer pointer you provided on input. Most code already does
6781 * that, so it's not a problem.
6782 * For the two cases when the text must be copied (that is,
6783 * for LVM_GETITEM, and LVM_GETITEMTEXT), use LISTVIEW_GetItemExtT.
6784 *
6785 * RETURN:
6786 * SUCCESS : TRUE
6787 * FAILURE : FALSE
6788 */
6789static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
6790{
6791 ITEMHDR callbackHdr = { LPSTR_TEXTCALLBACKW, I_IMAGECALLBACK };
6792 BOOL is_subitem_invalid = FALSE;
6793 NMLVDISPINFOW dispInfo;
6794 ITEM_INFO *lpItem;
6795 ITEMHDR* pItemHdr;
6796 HDPA hdpaSubItems;
6797
6798 TRACE("(item=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW);
6799
6800 if (!lpLVItem || lpLVItem->iItem < 0 || lpLVItem->iItem >= infoPtr->nItemCount)
6801 return FALSE;
6802
6803 if (lpLVItem->mask == 0) return TRUE;
6804 TRACE("mask=%x\n", lpLVItem->mask);
6805
6806 if (lpLVItem->iSubItem && (lpLVItem->mask & LVIF_STATE))
6807 lpLVItem->state = 0;
6808
6809 /* a quick optimization if all we're asked is the focus state
6810 * these queries are worth optimising since they are common,
6811 * and can be answered in constant time, without the heavy accesses */
6812 if ( (lpLVItem->mask == LVIF_STATE) && (lpLVItem->stateMask == LVIS_FOCUSED) &&
6813 !(infoPtr->uCallbackMask & LVIS_FOCUSED) )
6814 {
6815 lpLVItem->state = 0;
6816 if (infoPtr->nFocusedItem == lpLVItem->iItem && !lpLVItem->iSubItem)
6817 lpLVItem->state |= LVIS_FOCUSED;
6818 return TRUE;
6819 }
6820
6821 ZeroMemory(&dispInfo, sizeof(dispInfo));
6822
6823 /* if the app stores all the data, handle it separately */
6824 if (infoPtr->dwStyle & LVS_OWNERDATA)
6825 {
6826 dispInfo.item.state = 0;
6827
6828 /* apparently, we should not callback for lParam in LVS_OWNERDATA */
6829 if ((lpLVItem->mask & ~(LVIF_STATE | LVIF_PARAM)) ||
6830 ((lpLVItem->mask & LVIF_STATE) && (infoPtr->uCallbackMask & lpLVItem->stateMask)))
6831 {
6832 UINT mask = lpLVItem->mask;
6833
6834 /* NOTE: copy only fields which we _know_ are initialized, some apps
6835 * depend on the uninitialized fields being 0 */
6836 dispInfo.item.mask = lpLVItem->mask & ~LVIF_PARAM;
6837 dispInfo.item.iItem = lpLVItem->iItem;
6838 dispInfo.item.iSubItem = lpLVItem->iSubItem;
6839 if (lpLVItem->mask & LVIF_TEXT)
6840 {
6841 if (lpLVItem->mask & LVIF_NORECOMPUTE)
6842 /* reset mask */
6843 dispInfo.item.mask &= ~(LVIF_TEXT | LVIF_NORECOMPUTE);
6844 else
6845 {
6846 dispInfo.item.pszText = lpLVItem->pszText;
6847 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
6848 }
6849 }
6850 if (lpLVItem->mask & LVIF_STATE)
6851 dispInfo.item.stateMask = lpLVItem->stateMask & infoPtr->uCallbackMask;
6852 /* could be zeroed on LVIF_NORECOMPUTE case */
6853 if (dispInfo.item.mask)
6854 {
6855 notify_dispinfoT(infoPtr, LVN_GETDISPINFOW, &dispInfo, isW);
6856 dispInfo.item.stateMask = lpLVItem->stateMask;
6857 if (lpLVItem->mask & (LVIF_GROUPID|LVIF_COLUMNS))
6858 {
6859 /* full size structure expected - _WIN32IE >= 0x560 */
6860 *lpLVItem = dispInfo.item;
6861 }
6862 else if (lpLVItem->mask & LVIF_INDENT)
6863 {
6864 /* indent member expected - _WIN32IE >= 0x300 */
6865 memcpy(lpLVItem, &dispInfo.item, offsetof( LVITEMW, iGroupId ));
6866 }
6867 else
6868 {
6869 /* minimal structure expected */
6870 memcpy(lpLVItem, &dispInfo.item, offsetof( LVITEMW, iIndent ));
6871 }
6872 lpLVItem->mask = mask;
6873 TRACE(" getdispinfo(1):lpLVItem=%s\n", debuglvitem_t(lpLVItem, isW));
6874 }
6875 }
6876
6877 /* make sure lParam is zeroed out */
6878 if (lpLVItem->mask & LVIF_PARAM) lpLVItem->lParam = 0;
6879
6880 /* callback marked pointer required here */
6881 if ((lpLVItem->mask & LVIF_TEXT) && (lpLVItem->mask & LVIF_NORECOMPUTE))
6882 lpLVItem->pszText = LPSTR_TEXTCALLBACKW;
6883
6884 /* we store only a little state, so if we're not asked, we're done */
6885 if (!(lpLVItem->mask & LVIF_STATE) || lpLVItem->iSubItem) return TRUE;
6886
6887 /* if focus is handled by us, report it */
6888 if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED )
6889 {
6890 lpLVItem->state &= ~LVIS_FOCUSED;
6891 if (infoPtr->nFocusedItem == lpLVItem->iItem)
6892 lpLVItem->state |= LVIS_FOCUSED;
6893 }
6894
6895 /* and do the same for selection, if we handle it */
6896 if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED )
6897 {
6898 lpLVItem->state &= ~LVIS_SELECTED;
6899 if (ranges_contain(infoPtr->selectionRanges, lpLVItem->iItem))
6900 lpLVItem->state |= LVIS_SELECTED;
6901 }
6902
6903 return TRUE;
6904 }
6905
6906 /* find the item and subitem structures before we proceed */
6907 hdpaSubItems = DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
6908 lpItem = DPA_GetPtr(hdpaSubItems, 0);
6909 assert (lpItem);
6910
6911 if (lpLVItem->iSubItem)
6912 {
6913 SUBITEM_INFO *lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem);
6914 if (lpSubItem)
6915 pItemHdr = &lpSubItem->hdr;
6916 else
6917 {
6918 pItemHdr = &callbackHdr;
6919 is_subitem_invalid = TRUE;
6920 }
6921 }
6922 else
6923 pItemHdr = &lpItem->hdr;
6924
6925 /* Do we need to query the state from the app? */
6926 if ((lpLVItem->mask & LVIF_STATE) && infoPtr->uCallbackMask && (!lpLVItem->iSubItem || is_subitem_invalid))
6927 {
6928 dispInfo.item.mask |= LVIF_STATE;
6929 dispInfo.item.stateMask = infoPtr->uCallbackMask;
6930 }
6931
6932 /* Do we need to enquire about the image? */
6933 if ((lpLVItem->mask & LVIF_IMAGE) && pItemHdr->iImage == I_IMAGECALLBACK &&
6934 (!lpLVItem->iSubItem || (infoPtr->dwLvExStyle & LVS_EX_SUBITEMIMAGES)))
6935 {
6936 dispInfo.item.mask |= LVIF_IMAGE;
6937 dispInfo.item.iImage = I_IMAGECALLBACK;
6938 }
6939
6940 /* Only items support indentation */
6941 if ((lpLVItem->mask & LVIF_INDENT) && lpItem->iIndent == I_INDENTCALLBACK && !lpLVItem->iSubItem)
6942 {
6943 dispInfo.item.mask |= LVIF_INDENT;
6944 dispInfo.item.iIndent = I_INDENTCALLBACK;
6945 }
6946
6947 /* Apps depend on calling back for text if it is NULL or LPSTR_TEXTCALLBACKW */
6948 if ((lpLVItem->mask & LVIF_TEXT) && !(lpLVItem->mask & LVIF_NORECOMPUTE) &&
6949 !is_text(pItemHdr->pszText))
6950 {
6951 dispInfo.item.mask |= LVIF_TEXT;
6952 dispInfo.item.pszText = lpLVItem->pszText;
6953 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
6954 if (dispInfo.item.pszText && dispInfo.item.cchTextMax > 0)
6955 *dispInfo.item.pszText = '\0';
6956 }
6957
6958 /* If we don't have all the requested info, query the application */
6959 if (dispInfo.item.mask)
6960 {
6961 dispInfo.item.iItem = lpLVItem->iItem;
6962 dispInfo.item.iSubItem = lpLVItem->iSubItem;
6963 dispInfo.item.lParam = lpItem->lParam;
6964 notify_dispinfoT(infoPtr, LVN_GETDISPINFOW, &dispInfo, isW);
6965 TRACE(" getdispinfo(2):item=%s\n", debuglvitem_t(&dispInfo.item, isW));
6966 }
6967
6968 /* we should not store values for subitems */
6969 if (lpLVItem->iSubItem) dispInfo.item.mask &= ~LVIF_DI_SETITEM;
6970
6971 /* Now, handle the iImage field */
6972 if (dispInfo.item.mask & LVIF_IMAGE)
6973 {
6974 lpLVItem->iImage = dispInfo.item.iImage;
6975 if ((dispInfo.item.mask & LVIF_DI_SETITEM) && pItemHdr->iImage == I_IMAGECALLBACK)
6976 pItemHdr->iImage = dispInfo.item.iImage;
6977 }
6978 else if (lpLVItem->mask & LVIF_IMAGE)
6979 {
6980 if (!lpLVItem->iSubItem || (infoPtr->dwLvExStyle & LVS_EX_SUBITEMIMAGES))
6981 lpLVItem->iImage = pItemHdr->iImage;
6982 else
6983 lpLVItem->iImage = 0;
6984 }
6985
6986 /* The pszText field */
6987 if (dispInfo.item.mask & LVIF_TEXT)
6988 {
6989 if ((dispInfo.item.mask & LVIF_DI_SETITEM) && pItemHdr->pszText)
6990 textsetptrT(&pItemHdr->pszText, dispInfo.item.pszText, isW);
6991
6992 lpLVItem->pszText = dispInfo.item.pszText;
6993 }
6994 else if (lpLVItem->mask & LVIF_TEXT)
6995 {
6996 /* if LVN_GETDISPINFO's disabled with LVIF_NORECOMPUTE return callback placeholder */
6997 if (isW || !is_text(pItemHdr->pszText)) lpLVItem->pszText = pItemHdr->pszText;
6998 else textcpynT(lpLVItem->pszText, isW, pItemHdr->pszText, TRUE, lpLVItem->cchTextMax);
6999 }
7000
7001 /* Next is the lParam field */
7002 if (dispInfo.item.mask & LVIF_PARAM)
7003 {
7004 lpLVItem->lParam = dispInfo.item.lParam;
7005 if ((dispInfo.item.mask & LVIF_DI_SETITEM))
7006 lpItem->lParam = dispInfo.item.lParam;
7007 }
7008 else if (lpLVItem->mask & LVIF_PARAM)
7009 lpLVItem->lParam = lpItem->lParam;
7010
7011 /* if this is a subitem, we're done */
7012 if (lpLVItem->iSubItem) return TRUE;
7013
7014 /* ... the state field (this one is different due to uCallbackmask) */
7015 if (lpLVItem->mask & LVIF_STATE)
7016 {
7017 lpLVItem->state = lpItem->state & lpLVItem->stateMask;
7018 if (dispInfo.item.mask & LVIF_STATE)
7019 {
7020 lpLVItem->state &= ~dispInfo.item.stateMask;
7021 lpLVItem->state |= (dispInfo.item.state & dispInfo.item.stateMask);
7022 }
7023 if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED )
7024 {
7025 lpLVItem->state &= ~LVIS_FOCUSED;
7026 if (infoPtr->nFocusedItem == lpLVItem->iItem)
7027 lpLVItem->state |= LVIS_FOCUSED;
7028 }
7029 if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED )
7030 {
7031 lpLVItem->state &= ~LVIS_SELECTED;
7032 if (ranges_contain(infoPtr->selectionRanges, lpLVItem->iItem))
7033 lpLVItem->state |= LVIS_SELECTED;
7034 }
7035 }
7036
7037 /* and last, but not least, the indent field */
7038 if (dispInfo.item.mask & LVIF_INDENT)
7039 {
7040 lpLVItem->iIndent = dispInfo.item.iIndent;
7041 if ((dispInfo.item.mask & LVIF_DI_SETITEM) && lpItem->iIndent == I_INDENTCALLBACK)
7042 lpItem->iIndent = dispInfo.item.iIndent;
7043 }
7044 else if (lpLVItem->mask & LVIF_INDENT)
7045 {
7046 lpLVItem->iIndent = lpItem->iIndent;
7047 }
7048
7049 return TRUE;
7050}
7051
7052/***
7053 * DESCRIPTION:
7054 * Retrieves item attributes.
7055 *
7056 * PARAMETER(S):
7057 * [I] hwnd : window handle
7058 * [IO] lpLVItem : item info
7059 * [I] isW : if TRUE, then lpLVItem is a LPLVITEMW,
7060 * if FALSE, then lpLVItem is a LPLVITEMA.
7061 *
7062 * NOTE:
7063 * This is the external 'GetItem' interface -- it properly copies
7064 * the text in the provided buffer.
7065 *
7066 * RETURN:
7067 * SUCCESS : TRUE
7068 * FAILURE : FALSE
7069 */
7070static BOOL LISTVIEW_GetItemExtT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
7071{
7072 LPWSTR pszText;
7073 BOOL bResult;
7074
7075 if (!lpLVItem || lpLVItem->iItem < 0 || lpLVItem->iItem >= infoPtr->nItemCount)
7076 return FALSE;
7077
7078 pszText = lpLVItem->pszText;
7079 bResult = LISTVIEW_GetItemT(infoPtr, lpLVItem, isW);
7080 if (bResult && (lpLVItem->mask & LVIF_TEXT) && lpLVItem->pszText != pszText)
7081 {
7082 if (lpLVItem->pszText != LPSTR_TEXTCALLBACKW)
7083 textcpynT(pszText, isW, lpLVItem->pszText, isW, lpLVItem->cchTextMax);
7084 else
7085 pszText = LPSTR_TEXTCALLBACKW;
7086 }
7087 lpLVItem->pszText = pszText;
7088
7089 return bResult;
7090}
7091
7092
7093/***
7094 * DESCRIPTION:
7095 * Retrieves the position (upper-left) of the listview control item.
7096 * Note that for LVS_ICON style, the upper-left is that of the icon
7097 * and not the bounding box.
7098 *
7099 * PARAMETER(S):
7100 * [I] infoPtr : valid pointer to the listview structure
7101 * [I] nItem : item index
7102 * [O] lpptPosition : coordinate information
7103 *
7104 * RETURN:
7105 * SUCCESS : TRUE
7106 * FAILURE : FALSE
7107 */
7108static BOOL LISTVIEW_GetItemPosition(const LISTVIEW_INFO *infoPtr, INT nItem, LPPOINT lpptPosition)
7109{
7110 POINT Origin;
7111
7112 TRACE("(nItem=%d, lpptPosition=%p)\n", nItem, lpptPosition);
7113
7114 if (!lpptPosition || nItem < 0 || nItem >= infoPtr->nItemCount) return FALSE;
7115
7116 LISTVIEW_GetOrigin(infoPtr, &Origin);
7117 LISTVIEW_GetItemOrigin(infoPtr, nItem, lpptPosition);
7118
7119 if (infoPtr->uView == LV_VIEW_ICON)
7120 {
7121 lpptPosition->x += (infoPtr->nItemWidth - infoPtr->iconSize.cx) / 2;
7122 lpptPosition->y += ICON_TOP_PADDING;
7123 }
7124 lpptPosition->x += Origin.x;
7125 lpptPosition->y += Origin.y;
7126
7127 TRACE (" lpptPosition=%s\n", wine_dbgstr_point(lpptPosition));
7128 return TRUE;
7129}
7130
7131
7132/***
7133 * DESCRIPTION:
7134 * Retrieves the bounding rectangle for a listview control item.
7135 *
7136 * PARAMETER(S):
7137 * [I] infoPtr : valid pointer to the listview structure
7138 * [I] nItem : item index
7139 * [IO] lprc : bounding rectangle coordinates
7140 * lprc->left specifies the portion of the item for which the bounding
7141 * rectangle will be retrieved.
7142 *
7143 * LVIR_BOUNDS Returns the bounding rectangle of the entire item,
7144 * including the icon and label.
7145 * *
7146 * * For LVS_ICON
7147 * * Experiment shows that native control returns:
7148 * * width = min (48, length of text line)
7149 * * .left = position.x - (width - iconsize.cx)/2
7150 * * .right = .left + width
7151 * * height = #lines of text * ntmHeight + icon height + 8
7152 * * .top = position.y - 2
7153 * * .bottom = .top + height
7154 * * separation between items .y = itemSpacing.cy - height
7155 * * .x = itemSpacing.cx - width
7156 * LVIR_ICON Returns the bounding rectangle of the icon or small icon.
7157 * *
7158 * * For LVS_ICON
7159 * * Experiment shows that native control returns:
7160 * * width = iconSize.cx + 16
7161 * * .left = position.x - (width - iconsize.cx)/2
7162 * * .right = .left + width
7163 * * height = iconSize.cy + 4
7164 * * .top = position.y - 2
7165 * * .bottom = .top + height
7166 * * separation between items .y = itemSpacing.cy - height
7167 * * .x = itemSpacing.cx - width
7168 * LVIR_LABEL Returns the bounding rectangle of the item text.
7169 * *
7170 * * For LVS_ICON
7171 * * Experiment shows that native control returns:
7172 * * width = text length
7173 * * .left = position.x - width/2
7174 * * .right = .left + width
7175 * * height = ntmH * linecount + 2
7176 * * .top = position.y + iconSize.cy + 6
7177 * * .bottom = .top + height
7178 * * separation between items .y = itemSpacing.cy - height
7179 * * .x = itemSpacing.cx - width
7180 * LVIR_SELECTBOUNDS Returns the union of the LVIR_ICON and LVIR_LABEL
7181 * rectangles, but excludes columns in report view.
7182 *
7183 * RETURN:
7184 * SUCCESS : TRUE
7185 * FAILURE : FALSE
7186 *
7187 * NOTES
7188 * Note that the bounding rectangle of the label in the LVS_ICON view depends
7189 * upon whether the window has the focus currently and on whether the item
7190 * is the one with the focus. Ensure that the control's record of which
7191 * item has the focus agrees with the items' records.
7192 */
7194{
7195 WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
7196 BOOL doLabel = TRUE, oversizedBox = FALSE;
7197 POINT Position, Origin;
7198 LVITEMW lvItem;
7199 LONG mode;
7200
7201 TRACE("(hwnd=%p, nItem=%d, lprc=%p)\n", infoPtr->hwndSelf, nItem, lprc);
7202
7203 if (!lprc || nItem < 0 || nItem >= infoPtr->nItemCount) return FALSE;
7204
7205 LISTVIEW_GetOrigin(infoPtr, &Origin);
7206 LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position);
7207
7208 /* Be smart and try to figure out the minimum we have to do */
7209 if (lprc->left == LVIR_ICON) doLabel = FALSE;
7210 if (infoPtr->uView == LV_VIEW_DETAILS && lprc->left == LVIR_BOUNDS) doLabel = FALSE;
7211 if (infoPtr->uView == LV_VIEW_ICON && lprc->left != LVIR_ICON &&
7212 infoPtr->bFocus && LISTVIEW_GetItemState(infoPtr, nItem, LVIS_FOCUSED))
7213 oversizedBox = TRUE;
7214
7215 /* get what we need from the item before hand, so we make
7216 * only one request. This can speed up things, if data
7217 * is stored on the app side */
7218 lvItem.mask = 0;
7219 if (infoPtr->uView == LV_VIEW_DETAILS) lvItem.mask |= LVIF_INDENT;
7220 if (doLabel) lvItem.mask |= LVIF_TEXT;
7221 lvItem.iItem = nItem;
7222 lvItem.iSubItem = 0;
7223 lvItem.pszText = szDispText;
7224 lvItem.cchTextMax = DISP_TEXT_SIZE;
7225 if (lvItem.mask && !LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE;
7226 /* we got the state already up, simulate it here, to avoid a reget */
7227 if (infoPtr->uView == LV_VIEW_ICON && (lprc->left != LVIR_ICON))
7228 {
7229 lvItem.mask |= LVIF_STATE;
7230 lvItem.stateMask = LVIS_FOCUSED;
7231 lvItem.state = (oversizedBox ? LVIS_FOCUSED : 0);
7232 }
7233
7234 if (infoPtr->uView == LV_VIEW_DETAILS && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) && lprc->left == LVIR_SELECTBOUNDS)
7236
7237 mode = lprc->left;
7238 switch(lprc->left)
7239 {
7240 case LVIR_ICON:
7241 LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, NULL, lprc, NULL, NULL);
7242 break;
7243
7244 case LVIR_LABEL:
7245 LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, NULL, NULL, NULL, lprc);
7246 break;
7247
7248 case LVIR_BOUNDS:
7249 LISTVIEW_GetItemMetrics(infoPtr, &lvItem, lprc, NULL, NULL, NULL, NULL);
7250 break;
7251
7252 case LVIR_SELECTBOUNDS:
7253 LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, lprc, NULL, NULL, NULL);
7254 break;
7255
7256 default:
7257 WARN("Unknown value: %d\n", lprc->left);
7258 return FALSE;
7259 }
7260
7261 if (infoPtr->uView == LV_VIEW_DETAILS)
7262 {
7263 if (mode != LVIR_BOUNDS)
7264 OffsetRect(lprc, Origin.x + LISTVIEW_GetColumnInfo(infoPtr, 0)->rcHeader.left,
7265 Position.y + Origin.y);
7266 else
7267 OffsetRect(lprc, Origin.x, Position.y + Origin.y);
7268 }
7269 else
7270 OffsetRect(lprc, Position.x + Origin.x, Position.y + Origin.y);
7271
7272 TRACE(" rect=%s\n", wine_dbgstr_rect(lprc));
7273
7274 return TRUE;
7275}
7276
7277/***
7278 * DESCRIPTION:
7279 * Retrieves the spacing between listview control items.
7280 *
7281 * PARAMETER(S):
7282 * [I] infoPtr : valid pointer to the listview structure
7283 * [IO] lprc : rectangle to receive the output
7284 * on input, lprc->top = nSubItem
7285 * lprc->left = LVIR_ICON | LVIR_BOUNDS | LVIR_LABEL
7286 *
7287 * NOTE: for subItem = 0, we should return the bounds of the _entire_ item,
7288 * not only those of the first column.
7289 *
7290 * RETURN:
7291 * TRUE: success
7292 * FALSE: failure
7293 */
7295{
7296 RECT rect = { 0, 0, 0, 0 };
7297 POINT origin;
7298 INT y;
7299
7300 if (!lprc) return FALSE;
7301
7302 TRACE("(item=%d, subitem=%d, type=%d)\n", item, lprc->top, lprc->left);
7303 /* Subitem of '0' means item itself, and this works for all control view modes */
7304 if (lprc->top == 0)
7305 return LISTVIEW_GetItemRect(infoPtr, item, lprc);
7306
7307 if (infoPtr->uView != LV_VIEW_DETAILS) return FALSE;
7308
7309 LISTVIEW_GetOrigin(infoPtr, &origin);
7310 /* this works for any item index, no matter if it exists or not */
7311 y = item * infoPtr->nItemHeight + origin.y;
7312
7313 if (infoPtr->hwndHeader && SendMessageW(infoPtr->hwndHeader, HDM_GETITEMRECT, lprc->top, (LPARAM)&rect))
7314 {
7315 rect.top = 0;
7316 rect.bottom = infoPtr->nItemHeight;
7317 }
7318 else
7319 {
7320 /* Native implementation is broken for this case and garbage is left for left and right fields,
7321 we zero them to get predictable output */
7322 lprc->left = lprc->right = lprc->top = 0;
7323 lprc->bottom = infoPtr->nItemHeight;
7324 OffsetRect(lprc, origin.x, y);
7325 TRACE("return rect %s\n", wine_dbgstr_rect(lprc));
7326 return TRUE;
7327 }
7328
7329 switch (lprc->left)
7330 {
7331 case LVIR_ICON:
7332 {
7333 /* it doesn't matter if main item actually has an icon, if imagelist is set icon width is returned */
7334 if (infoPtr->himlSmall)
7335 rect.right = rect.left + infoPtr->iconSize.cx;
7336 else
7337 rect.right = rect.left;
7338
7339 rect.bottom = rect.top + infoPtr->iconSize.cy;
7340 break;
7341 }
7342 case LVIR_LABEL:
7343 case LVIR_BOUNDS:
7344 break;
7345
7346 default:
7347 ERR("Unknown bounds=%d\n", lprc->left);
7348 return FALSE;
7349 }
7350
7351 OffsetRect(&rect, origin.x, y);
7352 *lprc = rect;
7353 TRACE("return rect %s\n", wine_dbgstr_rect(lprc));
7354
7355 return TRUE;
7356}
7357
7358/***
7359 * DESCRIPTION:
7360 * Retrieves the spacing between listview control items.
7361 *
7362 * PARAMETER(S):
7363 * [I] infoPtr : valid pointer to the listview structure
7364 * [I] bSmall : flag for small or large icon
7365 *
7366 * RETURN:
7367 * Horizontal + vertical spacing
7368 */
7369static LONG LISTVIEW_GetItemSpacing(const LISTVIEW_INFO *infoPtr, BOOL bSmall)
7370{
7371 LONG lResult;
7372
7373 if (!bSmall)
7374 {
7375 lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
7376 }
7377 else
7378 {
7379 if (infoPtr->uView == LV_VIEW_ICON)
7381 else
7382 lResult = MAKELONG(infoPtr->nItemWidth, infoPtr->nItemHeight);
7383 }
7384 return lResult;
7385}
7386
7387/***
7388 * DESCRIPTION:
7389 * Retrieves the state of a listview control item.
7390 *
7391 * PARAMETER(S):
7392 * [I] infoPtr : valid pointer to the listview structure
7393 * [I] nItem : item index
7394 * [I] uMask : state mask
7395 *
7396 * RETURN:
7397 * State specified by the mask.
7398 */
7399static UINT LISTVIEW_GetItemState(const LISTVIEW_INFO *infoPtr, INT nItem, UINT uMask)
7400{
7401 LVITEMW lvItem;
7402
7403 if (nItem < 0 || nItem >= infoPtr->nItemCount) return 0;
7404
7405 lvItem.iItem = nItem;
7406 lvItem.iSubItem = 0;
7407 lvItem.mask = LVIF_STATE;
7408 lvItem.stateMask = uMask;
7409 if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return 0;
7410
7411 return lvItem.state & uMask;
7412}
7413
7414/***
7415 * DESCRIPTION:
7416 * Retrieves the text of a listview control item or subitem.
7417 *
7418 * PARAMETER(S):
7419 * [I] hwnd : window handle
7420 * [I] nItem : item index
7421 * [IO] lpLVItem : item information
7422 * [I] isW : TRUE if lpLVItem is Unicode
7423 *
7424 * RETURN:
7425 * SUCCESS : string length
7426 * FAILURE : 0
7427 */
7428static INT LISTVIEW_GetItemTextT(const LISTVIEW_INFO *infoPtr, INT nItem, LPLVITEMW lpLVItem, BOOL isW)
7429{
7430 if (!lpLVItem || nItem < 0 || nItem >= infoPtr->nItemCount) return 0;
7431
7432 lpLVItem->mask = LVIF_TEXT;
7433 lpLVItem->iItem = nItem;
7434 if (!LISTVIEW_GetItemExtT(infoPtr, lpLVItem, isW)) return 0;
7435
7436 return textlenT(lpLVItem->pszText, isW);
7437}
7438
7439/***
7440 * DESCRIPTION:
7441 * Searches for an item based on properties + relationships.
7442 *
7443 * PARAMETER(S):
7444 * [I] infoPtr : valid pointer to the listview structure
7445 * [I] nItem : item index
7446 * [I] uFlags : relationship flag
7447 *
7448 * RETURN:
7449 * SUCCESS : item index
7450 * FAILURE : -1
7451 */
7452static INT LISTVIEW_GetNextItem(const LISTVIEW_INFO *infoPtr, INT nItem, UINT uFlags)
7453{
7454 UINT uMask = 0;
7455 LVFINDINFOW lvFindInfo;
7456 INT nCountPerColumn;
7457#ifndef __REACTOS__
7458 INT nCountPerRow;
7459#endif
7460 INT i;
7461
7462 TRACE("nItem=%d, uFlags=%x, nItemCount=%d\n", nItem, uFlags, infoPtr->nItemCount);
7463 if (nItem < -1 || nItem >= infoPtr->nItemCount) return -1;
7464
7465 ZeroMemory(&lvFindInfo, sizeof(lvFindInfo));
7466
7467 if (uFlags & LVNI_CUT)
7468 uMask |= LVIS_CUT;
7469
7471 uMask |= LVIS_DROPHILITED;
7472
7473 if (uFlags & LVNI_FOCUSED)
7474 uMask |= LVIS_FOCUSED;
7475
7476 if (uFlags & LVNI_SELECTED)
7477 uMask |= LVIS_SELECTED;
7478
7479 /* if we're asked for the focused item, that's only one,
7480 * so it's worth optimizing */
7481 if (uFlags & LVNI_FOCUSED)
7482 {
7483 if ((LISTVIEW_GetItemState(infoPtr, infoPtr->nFocusedItem, uMask) & uMask) != uMask) return -1;
7484 return (infoPtr->nFocusedItem == nItem) ? -1 : infoPtr->nFocusedItem;
7485 }
7486
7487 if (uFlags & LVNI_ABOVE)
7488 {
7489 if ((infoPtr->uView == LV_VIEW_LIST) || (infoPtr->uView == LV_VIEW_DETAILS))
7490 {
7491 while (nItem >= 0)
7492 {
7493 nItem--;
7494 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
7495 return nItem;
7496 }
7497 }
7498 else
7499 {
7500#ifndef __REACTOS__
7501 /* Special case for autoarrange - move 'til the top of a list */
7502 if (is_autoarrange(infoPtr))
7503 {
7504 nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr);
7505 while (nItem - nCountPerRow >= 0)
7506 {
7507 nItem -= nCountPerRow;
7508 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
7509 return nItem;
7510 }
7511 return -1;
7512 }
7513#endif
7514 lvFindInfo.flags = LVFI_NEARESTXY;
7515 lvFindInfo.vkDirection = VK_UP;
7516 LISTVIEW_GetItemPosition(infoPtr, nItem, &lvFindInfo.pt);
7517 while ((nItem = LISTVIEW_FindItemW(infoPtr, nItem, &lvFindInfo)) != -1)
7518 {
7519 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
7520 return nItem;
7521 }
7522 }
7523 }
7524 else if (uFlags & LVNI_BELOW)
7525 {
7526 if ((infoPtr->uView == LV_VIEW_LIST) || (infoPtr->uView == LV_VIEW_DETAILS))
7527 {
7528 while (nItem < infoPtr->nItemCount)
7529 {
7530 nItem++;
7531 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
7532 return nItem;
7533 }
7534 }
7535 else
7536 {
7537#ifndef __REACTOS__
7538 /* Special case for autoarrange - move 'til the bottom of a list */
7539 if (is_autoarrange(infoPtr))
7540 {
7541 nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr);
7542 while (nItem + nCountPerRow < infoPtr->nItemCount )
7543 {
7544 nItem += nCountPerRow;
7545 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
7546 return nItem;
7547 }
7548 return -1;
7549 }
7550#endif
7551 lvFindInfo.flags = LVFI_NEARESTXY;
7552 lvFindInfo.vkDirection = VK_DOWN;
7553 LISTVIEW_GetItemPosition(infoPtr, nItem, &lvFindInfo.pt);
7554 while ((nItem = LISTVIEW_FindItemW(infoPtr, nItem, &lvFindInfo)) != -1)
7555 {
7556 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
7557 return nItem;
7558 }
7559 }
7560 }
7561 else if (uFlags & LVNI_TOLEFT)
7562 {
7563 if (infoPtr->uView == LV_VIEW_LIST)
7564 {
7565 nCountPerColumn = LISTVIEW_GetCountPerColumn(infoPtr);
7566 while (nItem - nCountPerColumn >= 0)
7567 {
7568 nItem -= nCountPerColumn;
7569 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
7570 return nItem;
7571 }
7572 }
7573 else if ((infoPtr->uView == LV_VIEW_SMALLICON) || (infoPtr->uView == LV_VIEW_ICON))
7574 {
7575#ifndef __REACTOS__
7576 /* Special case for autoarrange - move 'til the beginning of a row */
7577 if (is_autoarrange(infoPtr))
7578 {
7579 nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr);
7580 while (nItem % nCountPerRow > 0)
7581 {
7582 nItem --;
7583 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
7584 return nItem;
7585 }
7586 return -1;
7587 }
7588#endif
7589 lvFindInfo.flags = LVFI_NEARESTXY;
7590 lvFindInfo.vkDirection = VK_LEFT;
7591 LISTVIEW_GetItemPosition(infoPtr, nItem, &lvFindInfo.pt);
7592 while ((nItem = LISTVIEW_FindItemW(infoPtr, nItem, &lvFindInfo)) != -1)
7593 {
7594 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
7595 return nItem;
7596 }
7597 }
7598 }
7599 else if (uFlags & LVNI_TORIGHT)
7600 {
7601 if (infoPtr->uView == LV_VIEW_LIST)
7602 {
7603 nCountPerColumn = LISTVIEW_GetCountPerColumn(infoPtr);
7604 while (nItem + nCountPerColumn < infoPtr->nItemCount)
7605 {
7606 nItem += nCountPerColumn;
7607 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
7608 return nItem;
7609 }
7610 }
7611 else if ((infoPtr->uView == LV_VIEW_SMALLICON) || (infoPtr->uView == LV_VIEW_ICON))
7612 {
7613#ifndef __REACTOS__
7614 /* Special case for autoarrange - move 'til the end of a row */
7615 if (is_autoarrange(infoPtr))
7616 {
7617 nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr);
7618 while (nItem % nCountPerRow < nCountPerRow - 1 )
7619 {
7620 nItem ++;
7621 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
7622 return nItem;
7623 }
7624 return -1;
7625 }
7626#endif
7627 lvFindInfo.flags = LVFI_NEARESTXY;
7628 lvFindInfo.vkDirection = VK_RIGHT;
7629 LISTVIEW_GetItemPosition(infoPtr, nItem, &lvFindInfo.pt);
7630 while ((nItem = LISTVIEW_FindItemW(infoPtr, nItem, &lvFindInfo)) != -1)
7631 {
7632 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
7633 return nItem;
7634 }
7635 }
7636 }
7637 else
7638 {
7639 nItem++;
7640
7641 /* search by index */
7642 for (i = nItem; i < infoPtr->nItemCount; i++)
7643 {
7644 if ((LISTVIEW_GetItemState(infoPtr, i, uMask) & uMask) == uMask)
7645 return i;
7646 }
7647 }
7648
7649 return -1;
7650}
7651
7652/* LISTVIEW_GetNumberOfWorkAreas */
7653
7654/***
7655 * DESCRIPTION:
7656 * Retrieves the origin coordinates when in icon or small icon display mode.
7657 *
7658 * PARAMETER(S):
7659 * [I] infoPtr : valid pointer to the listview structure
7660 * [O] lpptOrigin : coordinate information
7661 *
7662 * RETURN:
7663 * None.
7664 */
7665static void LISTVIEW_GetOrigin(const LISTVIEW_INFO *infoPtr, LPPOINT lpptOrigin)
7666{
7667 INT nHorzPos = 0, nVertPos = 0;
7668 SCROLLINFO scrollInfo;
7669
7670 scrollInfo.cbSize = sizeof(SCROLLINFO);
7671 scrollInfo.fMask = SIF_POS;
7672
7673 if (GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo))
7674 nHorzPos = scrollInfo.nPos;
7675 if (GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo))
7676 nVertPos = scrollInfo.nPos;
7677
7678 TRACE("nHorzPos=%d, nVertPos=%d\n", nHorzPos, nVertPos);
7679
7680 lpptOrigin->x = infoPtr->rcList.left;
7681 lpptOrigin->y = infoPtr->rcList.top;
7682 if (infoPtr->uView == LV_VIEW_LIST)
7683 nHorzPos *= infoPtr->nItemWidth;
7684 else if (infoPtr->uView == LV_VIEW_DETAILS)
7685 nVertPos *= infoPtr->nItemHeight;
7686
7687 lpptOrigin->x -= nHorzPos;
7688 lpptOrigin->y -= nVertPos;
7689
7690 TRACE(" origin=%s\n", wine_dbgstr_point(lpptOrigin));
7691}
7692
7693/***
7694 * DESCRIPTION:
7695 * Retrieves the width of a string.
7696 *
7697 * PARAMETER(S):
7698 * [I] hwnd : window handle
7699 * [I] lpszText : text string to process
7700 * [I] isW : TRUE if lpszText is Unicode, FALSE otherwise
7701 *
7702 * RETURN:
7703 * SUCCESS : string width (in pixels)
7704 * FAILURE : zero
7705 */
7707{
7708 SIZE stringSize;
7709
7710 stringSize.cx = 0;
7711 if (is_text(lpszText))
7712 {
7713 HFONT hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
7714 HDC hdc = GetDC(infoPtr->hwndSelf);
7715 HFONT hOldFont = SelectObject(hdc, hFont);
7716
7717 if (isW)
7718 GetTextExtentPointW(hdc, lpszText, lstrlenW(lpszText), &stringSize);
7719 else
7720 GetTextExtentPointA(hdc, (LPCSTR)lpszText, lstrlenA((LPCSTR)lpszText), &stringSize);
7721 SelectObject(hdc, hOldFont);
7722 ReleaseDC(infoPtr->hwndSelf, hdc);
7723 }
7724 return stringSize.cx;
7725}
7726
7727/***
7728 * DESCRIPTION:
7729 * Determines which listview item is located at the specified position.
7730 *
7731 * PARAMETER(S):
7732 * [I] infoPtr : valid pointer to the listview structure
7733 * [IO] lpht : hit test information
7734 * [I] subitem : fill out iSubItem.
7735 * [I] select : return the index only if the hit selects the item
7736 *
7737 * NOTE:
7738 * (mm 20001022): We must not allow iSubItem to be touched, for
7739 * an app might pass only a structure with space up to iItem!
7740 * (MS Office 97 does that for instance in the file open dialog)
7741 *
7742 * RETURN:
7743 * SUCCESS : item index
7744 * FAILURE : -1
7745 */
7746static INT LISTVIEW_HitTest(const LISTVIEW_INFO *infoPtr, LPLVHITTESTINFO lpht, BOOL subitem, BOOL select)
7747{
7748 WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
7749 RECT rcBox, rcBounds, rcState, rcIcon, rcLabel, rcSearch;
7750 POINT Origin, Position, opt;
7751 BOOL is_fullrow;
7752 LVITEMW lvItem;
7753 ITERATOR i;
7754 INT iItem;
7755
7756 TRACE("(pt=%s, subitem=%d, select=%d)\n", wine_dbgstr_point(&lpht->pt), subitem, select);
7757
7758 lpht->flags = 0;
7759 lpht->iItem = -1;
7760 if (subitem) lpht->iSubItem = 0;
7761
7762 LISTVIEW_GetOrigin(infoPtr, &Origin);
7763
7764 /* set whole list relation flags */
7765 if (subitem && infoPtr->uView == LV_VIEW_DETAILS)
7766 {
7767 /* LVM_SUBITEMHITTEST checks left bound of possible client area */
7768 if (infoPtr->rcList.left > lpht->pt.x && Origin.x < lpht->pt.x)
7769 lpht->flags |= LVHT_TOLEFT;
7770
7771 if (lpht->pt.y < infoPtr->rcList.top && lpht->pt.y >= 0)
7772 opt.y = lpht->pt.y + infoPtr->rcList.top;
7773 else
7774 opt.y = lpht->pt.y;
7775
7776 if (infoPtr->rcList.bottom < opt.y)
7777 lpht->flags |= LVHT_BELOW;
7778 }
7779 else
7780 {
7781 if (infoPtr->rcList.left > lpht->pt.x)
7782 lpht->flags |= LVHT_TOLEFT;
7783 else if (infoPtr->rcList.right < lpht->pt.x)
7784 lpht->flags |= LVHT_TORIGHT;
7785
7786 if (infoPtr->rcList.top > lpht->pt.y)
7787 lpht->flags |= LVHT_ABOVE;
7788 else if (infoPtr->rcList.bottom < lpht->pt.y)
7789 lpht->flags |= LVHT_BELOW;
7790 }
7791
7792 /* even if item is invalid try to find subitem */
7793 if (infoPtr->uView == LV_VIEW_DETAILS && subitem)
7794 {
7795 RECT *pRect;
7796 INT j;
7797
7798 opt.x = lpht->pt.x - Origin.x;
7799
7800 lpht->iSubItem = -1;
7801 for (j = 0; j < DPA_GetPtrCount(infoPtr->hdpaColumns); j++)
7802 {
7803 pRect = &LISTVIEW_GetColumnInfo(infoPtr, j)->rcHeader;
7804
7805 if ((opt.x >= pRect->left) && (opt.x < pRect->right))
7806 {
7807 lpht->iSubItem = j;
7808 break;
7809 }
7810 }
7811 TRACE("lpht->iSubItem=%d\n", lpht->iSubItem);
7812
7813 /* if we're outside horizontal columns bounds there's nothing to test further */
7814 if (lpht->iSubItem == -1)
7815 {
7816 lpht->iItem = -1;
7817 lpht->flags = LVHT_NOWHERE;
7818 return -1;
7819 }
7820 }
7821
7822 TRACE("lpht->flags=0x%x\n", lpht->flags);
7823 if (lpht->flags) return -1;
7824
7825 lpht->flags |= LVHT_NOWHERE;
7826
7827 /* first deal with the large items */
7828 rcSearch.left = lpht->pt.x;
7829 rcSearch.top = lpht->pt.y;
7830 rcSearch.right = rcSearch.left + 1;
7831 rcSearch.bottom = rcSearch.top + 1;
7832
7833 iterator_frameditems(&i, infoPtr, &rcSearch);
7834 iterator_next(&i); /* go to first item in the sequence */
7835 iItem = i.nItem;
7837
7838 TRACE("lpht->iItem=%d\n", iItem);
7839 if (iItem == -1) return -1;
7840
7841 lvItem.mask = LVIF_STATE | LVIF_TEXT;
7842 if (infoPtr->uView == LV_VIEW_DETAILS) lvItem.mask |= LVIF_INDENT;
7844 if (infoPtr->uView == LV_VIEW_ICON) lvItem.stateMask |= LVIS_FOCUSED;
7845 lvItem.iItem = iItem;
7846 lvItem.iSubItem = subitem ? lpht->iSubItem : 0;
7847 lvItem.pszText = szDispText;
7848 lvItem.cchTextMax = DISP_TEXT_SIZE;
7849 if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return -1;
7850 if (!infoPtr->bFocus) lvItem.state &= ~LVIS_FOCUSED;
7851
7852 LISTVIEW_GetItemMetrics(infoPtr, &lvItem, &rcBox, NULL, &rcIcon, &rcState, &rcLabel);
7853 LISTVIEW_GetItemOrigin(infoPtr, iItem, &Position);
7854 opt.x = lpht->pt.x - Position.x - Origin.x;
7855
7856 if (lpht->pt.y < infoPtr->rcList.top && lpht->pt.y >= 0)
7857 opt.y = lpht->pt.y - Position.y - Origin.y + infoPtr->rcList.top;
7858 else
7859 opt.y = lpht->pt.y - Position.y - Origin.y;
7860
7861 if (infoPtr->uView == LV_VIEW_DETAILS)
7862 {
7863 rcBounds = rcBox;
7864 if (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT)
7865 opt.x = lpht->pt.x - Origin.x;
7866 }
7867 else
7868 {
7869 UnionRect(&rcBounds, &rcIcon, &rcLabel);
7870 UnionRect(&rcBounds, &rcBounds, &rcState);
7871 }
7872 TRACE("rcBounds=%s\n", wine_dbgstr_rect(&rcBounds));
7873 if (!PtInRect(&rcBounds, opt)) return -1;
7874
7875 /* That's a special case - row rectangle is used as item rectangle and
7876 returned flags contain all item parts. */
7877 is_fullrow = (infoPtr->uView == LV_VIEW_DETAILS) && ((infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) || (infoPtr->dwStyle & LVS_OWNERDRAWFIXED));
7878
7879 if (PtInRect(&rcIcon, opt))
7880 lpht->flags |= LVHT_ONITEMICON;
7881 else if (PtInRect(&rcLabel, opt))
7882 lpht->flags |= LVHT_ONITEMLABEL;
7883 else if (infoPtr->himlState && PtInRect(&rcState, opt))
7884 lpht->flags |= LVHT_ONITEMSTATEICON;
7885 if (is_fullrow && !(lpht->flags & LVHT_ONITEM))
7886 {
7887 lpht->flags = LVHT_ONITEM | LVHT_ABOVE;
7888 }
7889 if (lpht->flags & LVHT_ONITEM)
7890 lpht->flags &= ~LVHT_NOWHERE;
7891 TRACE("lpht->flags=0x%x\n", lpht->flags);
7892
7893 if (select && !is_fullrow)
7894 {
7895 if (infoPtr->uView == LV_VIEW_DETAILS)
7896 {
7897 /* get main item bounds */
7898 lvItem.iSubItem = 0;
7899 LISTVIEW_GetItemMetrics(infoPtr, &lvItem, &rcBox, NULL, &rcIcon, &rcState, &rcLabel);
7900 UnionRect(&rcBounds, &rcIcon, &rcLabel);
7901 UnionRect(&rcBounds, &rcBounds, &rcState);
7902 }
7903 if (!PtInRect(&rcBounds, opt)) iItem = -1;
7904 }
7905 return lpht->iItem = iItem;
7906}
7907
7908/***
7909 * DESCRIPTION:
7910 * Inserts a new item in the listview control.
7911 *
7912 * PARAMETER(S):
7913 * [I] infoPtr : valid pointer to the listview structure
7914 * [I] lpLVItem : item information
7915 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
7916 *
7917 * RETURN:
7918 * SUCCESS : new item index
7919 * FAILURE : -1
7920 */
7921static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL isW)
7922{
7923 INT nItem;
7924 HDPA hdpaSubItems;
7925 NMLISTVIEW nmlv;
7926 ITEM_INFO *lpItem;
7927 ITEM_ID *lpID;
7928 BOOL is_sorted, has_changed;
7929 LVITEMW item;
7930 HWND hwndSelf = infoPtr->hwndSelf;
7931
7932 TRACE("(item=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW);
7933
7934 if (infoPtr->dwStyle & LVS_OWNERDATA) return infoPtr->nItemCount++;
7935
7936 /* make sure it's an item, and not a subitem; cannot insert a subitem */
7937 if (!lpLVItem || lpLVItem->iSubItem) return -1;
7938
7939 if (!is_assignable_item(lpLVItem, infoPtr->dwStyle)) return -1;
7940
7941 if (!(lpItem = Alloc(sizeof(ITEM_INFO)))) return -1;
7942
7943 /* insert item in listview control data structure */
7944 if ( !(hdpaSubItems = DPA_Create(8)) ) goto fail;
7945 if ( !DPA_SetPtr(hdpaSubItems, 0, lpItem) ) assert (FALSE);
7946
7947 /* link with id struct */
7948 if (!(lpID = Alloc(sizeof(ITEM_ID)))) goto fail;
7949 lpItem->id = lpID;
7950 lpID->item = hdpaSubItems;
7951 lpID->id = get_next_itemid(infoPtr);
7952 if ( DPA_InsertPtr(infoPtr->hdpaItemIds, infoPtr->nItemCount, lpID) == -1) goto fail;
7953
7955 !(infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && (LPSTR_TEXTCALLBACKW != lpLVItem->pszText);
7956
7957 if (lpLVItem->iItem < 0 && !is_sorted) return -1;
7958
7959 /* calculate new item index */
7960 if (is_sorted)
7961 {
7962 HDPA hItem;
7963 ITEM_INFO *item_s;
7964 INT i = 0, cmpv;
7965 WCHAR *textW;
7966
7967 textW = textdupTtoW(lpLVItem->pszText, isW);
7968
7969 while (i < infoPtr->nItemCount)
7970 {
7971 hItem = DPA_GetPtr( infoPtr->hdpaItems, i);
7972 item_s = DPA_GetPtr(hItem, 0);
7973
7974 cmpv = textcmpWT(item_s->hdr.pszText, textW, TRUE);
7975 if (infoPtr->dwStyle & LVS_SORTDESCENDING) cmpv *= -1;
7976
7977 if (cmpv >= 0) break;
7978 i++;
7979 }
7980
7982
7983 nItem = i;
7984 }
7985 else
7986 nItem = min(lpLVItem->iItem, infoPtr->nItemCount);
7987
7988 TRACE("inserting at %d, sorted=%d, count=%d, iItem=%d\n", nItem, is_sorted, infoPtr->nItemCount, lpLVItem->iItem);
7989 nItem = DPA_InsertPtr( infoPtr->hdpaItems, nItem, hdpaSubItems );
7990 if (nItem == -1) goto fail;
7991 infoPtr->nItemCount++;
7992
7993 /* shift indices first so they don't get tangled */
7994 LISTVIEW_ShiftIndices(infoPtr, nItem, 1);
7995
7996 /* set the item attributes */
7997 if (lpLVItem->mask & (LVIF_GROUPID|LVIF_COLUMNS))
7998 {
7999 /* full size structure expected - _WIN32IE >= 0x560 */
8000 item = *lpLVItem;
8001 }
8002 else if (lpLVItem->mask & LVIF_INDENT)
8003 {
8004 /* indent member expected - _WIN32IE >= 0x300 */
8005 memcpy(&item, lpLVItem, offsetof( LVITEMW, iGroupId ));
8006 }
8007 else
8008 {
8009 /* minimal structure expected */
8010 memcpy(&item, lpLVItem, offsetof( LVITEMW, iIndent ));
8011 }
8012 item.iItem = nItem;
8013 if (infoPtr->dwLvExStyle & LVS_EX_CHECKBOXES)
8014 {
8015 if (item.mask & LVIF_STATE)
8016 {
8017 item.stateMask |= LVIS_STATEIMAGEMASK;
8018 item.state &= ~LVIS_STATEIMAGEMASK;
8019 item.state |= INDEXTOSTATEIMAGEMASK(1);
8020 }
8021 else
8022 {
8023 item.mask |= LVIF_STATE;
8024 item.stateMask = LVIS_STATEIMAGEMASK;
8025 item.state = INDEXTOSTATEIMAGEMASK(1);
8026 }
8027 }
8028
8029 if (!set_main_item(infoPtr, &item, TRUE, isW, &has_changed)) goto undo;
8030
8031 /* make room for the position, if we are in the right mode */
8032 if ((infoPtr->uView == LV_VIEW_SMALLICON) || (infoPtr->uView == LV_VIEW_ICON))
8033 {
8034 if (DPA_InsertPtr(infoPtr->hdpaPosX, nItem, 0) == -1)
8035 goto undo;
8036 if (DPA_InsertPtr(infoPtr->hdpaPosY, nItem, 0) == -1)
8037 {
8038 DPA_DeletePtr(infoPtr->hdpaPosX, nItem);
8039 goto undo;
8040 }
8041 }
8042
8043 /* send LVN_INSERTITEM notification */
8044 memset(&nmlv, 0, sizeof(NMLISTVIEW));
8045 nmlv.iItem = nItem;
8046 nmlv.lParam = lpItem->lParam;
8047 notify_listview(infoPtr, LVN_INSERTITEM, &nmlv);
8048 if (!IsWindow(hwndSelf))
8049 return -1;
8050
8051 /* align items (set position of each item) */
8052 if (infoPtr->uView == LV_VIEW_SMALLICON || infoPtr->uView == LV_VIEW_ICON)
8053 {
8054 POINT pt;
8055
8056#ifdef __REACTOS__
8057 if (infoPtr->dwStyle & LVS_ALIGNLEFT)
8058 LISTVIEW_NextIconPosLeft(infoPtr, &pt, nItem);
8059 else
8060 LISTVIEW_NextIconPosTop(infoPtr, &pt, nItem);
8061#else
8062 if (infoPtr->dwStyle & LVS_ALIGNLEFT)
8063 LISTVIEW_NextIconPosLeft(infoPtr, &pt);
8064 else
8065 LISTVIEW_NextIconPosTop(infoPtr, &pt);
8066#endif
8067
8068 LISTVIEW_MoveIconTo(infoPtr, nItem, &pt, TRUE);
8069 }
8070
8071 /* now is the invalidation fun */
8072 LISTVIEW_ScrollOnInsert(infoPtr, nItem, 1);
8073 return nItem;
8074
8075undo:
8076 LISTVIEW_ShiftIndices(infoPtr, nItem, -1);
8077 LISTVIEW_ShiftFocus(infoPtr, infoPtr->nFocusedItem, nItem, -1);
8078 DPA_DeletePtr(infoPtr->hdpaItems, nItem);
8079 infoPtr->nItemCount--;
8080fail:
8081 DPA_DeletePtr(hdpaSubItems, 0);
8082 DPA_Destroy (hdpaSubItems);
8083 Free (lpItem);
8084 return -1;
8085}
8086
8087/***
8088 * DESCRIPTION:
8089 * Checks item visibility.
8090 *
8091 * PARAMETER(S):
8092 * [I] infoPtr : valid pointer to the listview structure
8093 * [I] nFirst : item index to check for
8094 *
8095 * RETURN:
8096 * Item visible : TRUE
8097 * Item invisible or failure : FALSE
8098 */
8099static BOOL LISTVIEW_IsItemVisible(const LISTVIEW_INFO *infoPtr, INT nItem)
8100{
8101 POINT Origin, Position;
8102 RECT rcItem;
8103 HDC hdc;
8104 BOOL ret;
8105
8106 TRACE("nItem=%d\n", nItem);
8107
8108 if (nItem < 0 || nItem >= DPA_GetPtrCount(infoPtr->hdpaItems)) return FALSE;
8109
8110 LISTVIEW_GetOrigin(infoPtr, &Origin);
8111 LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position);
8112 rcItem.left = Position.x + Origin.x;
8113 rcItem.top = Position.y + Origin.y;
8114 rcItem.right = rcItem.left + infoPtr->nItemWidth;
8115 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
8116
8117 hdc = GetDC(infoPtr->hwndSelf);
8118 if (!hdc) return FALSE;
8119 ret = RectVisible(hdc, &rcItem);
8120 ReleaseDC(infoPtr->hwndSelf, hdc);
8121
8122 return ret;
8123}
8124
8125/***
8126 * DESCRIPTION:
8127 * Redraws a range of items.
8128 *
8129 * PARAMETER(S):
8130 * [I] infoPtr : valid pointer to the listview structure
8131 * [I] nFirst : first item
8132 * [I] nLast : last item
8133 *
8134 * RETURN:
8135 * SUCCESS : TRUE
8136 * FAILURE : FALSE
8137 */
8138static BOOL LISTVIEW_RedrawItems(const LISTVIEW_INFO *infoPtr, INT nFirst, INT nLast)
8139{
8140 INT i;
8141
8142 for (i = max(nFirst, 0); i <= min(nLast, infoPtr->nItemCount - 1); i++)
8143 LISTVIEW_InvalidateItem(infoPtr, i);
8144
8145 return TRUE;
8146}
8147
8148/***
8149 * DESCRIPTION:
8150 * Scroll the content of a listview.
8151 *
8152 * PARAMETER(S):
8153 * [I] infoPtr : valid pointer to the listview structure
8154 * [I] dx : horizontal scroll amount in pixels
8155 * [I] dy : vertical scroll amount in pixels
8156 *
8157 * RETURN:
8158 * SUCCESS : TRUE
8159 * FAILURE : FALSE
8160 *
8161 * COMMENTS:
8162 * If the control is in report view (LV_VIEW_DETAILS) the control can
8163 * be scrolled only in line increments. "dy" will be rounded to the
8164 * nearest number of pixels that are a whole line. Ex: if line height
8165 * is 16 and an 8 is passed, the list will be scrolled by 16. If a 7
8166 * is passed, then the scroll will be 0. (per MSDN 7/2002)
8167 */
8169{
8170 switch(infoPtr->uView) {
8171 case LV_VIEW_DETAILS:
8172 dy += (dy < 0 ? -1 : 1) * infoPtr->nItemHeight/2;
8173 dy /= infoPtr->nItemHeight;
8174 break;
8175 case LV_VIEW_LIST:
8176 if (dy != 0) return FALSE;
8177 break;
8178 default: /* icon */
8179 break;
8180 }
8181
8182 if (dx != 0) LISTVIEW_HScroll(infoPtr, SB_INTERNAL, dx);
8183 if (dy != 0) LISTVIEW_VScroll(infoPtr, SB_INTERNAL, dy);
8184
8185 return TRUE;
8186}
8187
8188/***
8189 * DESCRIPTION:
8190 * Sets the background color.
8191 *
8192 * PARAMETER(S):
8193 * [I] infoPtr : valid pointer to the listview structure
8194 * [I] color : background color
8195 *
8196 * RETURN:
8197 * SUCCESS : TRUE
8198 * FAILURE : FALSE
8199 */
8201{
8202 TRACE("(color=%x)\n", color);
8203
8204#ifdef __REACTOS__
8205 infoPtr->bDefaultBkColor = FALSE;
8206#endif
8207 if(infoPtr->clrBk != color) {
8208 if (infoPtr->clrBk != CLR_NONE) DeleteObject(infoPtr->hBkBrush);
8209 infoPtr->clrBk = color;
8210 if (color == CLR_NONE)
8211 infoPtr->hBkBrush = (HBRUSH)GetClassLongPtrW(infoPtr->hwndSelf, GCLP_HBRBACKGROUND);
8212 else
8213 {
8214 infoPtr->hBkBrush = CreateSolidBrush(color);
8215 infoPtr->dwLvExStyle &= ~LVS_EX_TRANSPARENTBKGND;
8216 }
8217 }
8218
8219 return TRUE;
8220}
8221
8222/* LISTVIEW_SetBkImage */
8223
8224/*** Helper for {Insert,Set}ColumnT *only* */
8225static void column_fill_hditem(const LISTVIEW_INFO *infoPtr, HDITEMW *lphdi, INT nColumn,
8226 const LVCOLUMNW *lpColumn, BOOL isW)
8227{
8228 if (lpColumn->mask & LVCF_FMT)
8229 {
8230 /* format member is valid */
8231 lphdi->mask |= HDI_FORMAT;
8232
8233 /* set text alignment (leftmost column must be left-aligned) */
8234 if (nColumn == 0 || (lpColumn->fmt & LVCFMT_JUSTIFYMASK) == LVCFMT_LEFT)
8235 lphdi->fmt |= HDF_LEFT;
8236 else if ((lpColumn->fmt & LVCFMT_JUSTIFYMASK) == LVCFMT_RIGHT)
8237 lphdi->fmt |= HDF_RIGHT;
8238 else if ((lpColumn->fmt & LVCFMT_JUSTIFYMASK) == LVCFMT_CENTER)
8239 lphdi->fmt |= HDF_CENTER;
8240
8241 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
8242 lphdi->fmt |= HDF_BITMAP_ON_RIGHT;
8243
8244 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
8245 {
8246 lphdi->fmt |= HDF_IMAGE;
8247 lphdi->iImage = I_IMAGECALLBACK;
8248 }
8249
8250 if (lpColumn->fmt & LVCFMT_FIXED_WIDTH)
8251 lphdi->fmt |= HDF_FIXEDWIDTH;
8252 }
8253
8254 if (lpColumn->mask & LVCF_WIDTH)
8255 {
8256 lphdi->mask |= HDI_WIDTH;
8257 if(lpColumn->cx == LVSCW_AUTOSIZE_USEHEADER)
8258 {
8259 /* make it fill the remainder of the controls width */
8260 RECT rcHeader;
8261 INT item_index;
8262
8263 for(item_index = 0; item_index < (nColumn - 1); item_index++)
8264 {
8265 LISTVIEW_GetHeaderRect(infoPtr, item_index, &rcHeader);
8266 lphdi->cxy += rcHeader.right - rcHeader.left;
8267 }
8268
8269 /* retrieve the layout of the header */
8270 GetClientRect(infoPtr->hwndSelf, &rcHeader);
8271 TRACE("start cxy=%d rcHeader=%s\n", lphdi->cxy, wine_dbgstr_rect(&rcHeader));
8272
8273 lphdi->cxy = (rcHeader.right - rcHeader.left) - lphdi->cxy;
8274 }
8275 else
8276 lphdi->cxy = lpColumn->cx;
8277 }
8278
8279 if (lpColumn->mask & LVCF_TEXT)
8280 {
8281 lphdi->mask |= HDI_TEXT | HDI_FORMAT;
8282 lphdi->fmt |= HDF_STRING;
8283 lphdi->pszText = lpColumn->pszText;
8284 lphdi->cchTextMax = textlenT(lpColumn->pszText, isW);
8285 }
8286
8287 if (lpColumn->mask & LVCF_IMAGE)
8288 {
8289 lphdi->mask |= HDI_IMAGE;
8290 lphdi->iImage = lpColumn->iImage;
8291 }
8292
8293 if (lpColumn->mask & LVCF_ORDER)
8294 {
8295 lphdi->mask |= HDI_ORDER;
8296 lphdi->iOrder = lpColumn->iOrder;
8297 }
8298}
8299
8300
8301/***
8302 * DESCRIPTION:
8303 * Inserts a new column.
8304 *
8305 * PARAMETER(S):
8306 * [I] infoPtr : valid pointer to the listview structure
8307 * [I] nColumn : column index
8308 * [I] lpColumn : column information
8309 * [I] isW : TRUE if lpColumn is Unicode, FALSE otherwise
8310 *
8311 * RETURN:
8312 * SUCCESS : new column index
8313 * FAILURE : -1
8314 */
8316 const LVCOLUMNW *lpColumn, BOOL isW)
8317{
8318 COLUMN_INFO *lpColumnInfo;
8319 INT nNewColumn;
8320 HDITEMW hdi;
8321
8322 TRACE("(nColumn=%d, lpColumn=%s, isW=%d)\n", nColumn, debuglvcolumn_t(lpColumn, isW), isW);
8323
8324 if (!lpColumn || nColumn < 0) return -1;
8325 nColumn = min(nColumn, DPA_GetPtrCount(infoPtr->hdpaColumns));
8326
8327 ZeroMemory(&hdi, sizeof(HDITEMW));
8328 column_fill_hditem(infoPtr, &hdi, nColumn, lpColumn, isW);
8329
8330 /*
8331 * A mask not including LVCF_WIDTH turns into a mask of width, width 10
8332 * (can be seen in SPY) otherwise column never gets added.
8333 */
8334 if (!(lpColumn->mask & LVCF_WIDTH)) {
8335 hdi.mask |= HDI_WIDTH;
8336 hdi.cxy = 10;
8337 }
8338
8339 /*
8340 * when the iSubItem is available Windows copies it to the header lParam. It seems
8341 * to happen only in LVM_INSERTCOLUMN - not in LVM_SETCOLUMN
8342 */
8343 if (lpColumn->mask & LVCF_SUBITEM)
8344 {
8345 hdi.mask |= HDI_LPARAM;
8346 hdi.lParam = lpColumn->iSubItem;
8347 }
8348
8349 /* create header if not present */
8350 LISTVIEW_CreateHeader(infoPtr);
8351 if (!(LVS_NOCOLUMNHEADER & infoPtr->dwStyle) &&
8352 (infoPtr->uView == LV_VIEW_DETAILS) && (WS_VISIBLE & infoPtr->dwStyle))
8353 {
8355 }
8356
8357 /* insert item in header control */
8358 nNewColumn = SendMessageW(infoPtr->hwndHeader,
8360 nColumn, (LPARAM)&hdi);
8361 if (nNewColumn == -1) return -1;
8362 if (nNewColumn != nColumn) ERR("nColumn=%d, nNewColumn=%d\n", nColumn, nNewColumn);
8363
8364 /* create our own column info */
8365 if (!(lpColumnInfo = Alloc(sizeof(COLUMN_INFO)))) goto fail;
8366 if (DPA_InsertPtr(infoPtr->hdpaColumns, nNewColumn, lpColumnInfo) == -1) goto fail;
8367
8368 if (lpColumn->mask & LVCF_FMT) lpColumnInfo->fmt = lpColumn->fmt;
8369 if (lpColumn->mask & LVCF_MINWIDTH) lpColumnInfo->cxMin = lpColumn->cxMin;
8370 if (!SendMessageW(infoPtr->hwndHeader, HDM_GETITEMRECT, nNewColumn, (LPARAM)&lpColumnInfo->rcHeader))
8371 goto fail;
8372
8373 /* now we have to actually adjust the data */
8374 if (!(infoPtr->dwStyle & LVS_OWNERDATA) && infoPtr->nItemCount > 0)
8375 {
8376 SUBITEM_INFO *lpSubItem;
8377 HDPA hdpaSubItems;
8378 INT nItem, i;
8379 LVITEMW item;
8380 BOOL changed;
8381
8382 item.iSubItem = nNewColumn;
8383 item.mask = LVIF_TEXT | LVIF_IMAGE;
8384 item.iImage = I_IMAGECALLBACK;
8385 item.pszText = LPSTR_TEXTCALLBACKW;
8386
8387 for (nItem = 0; nItem < infoPtr->nItemCount; nItem++)
8388 {
8389 hdpaSubItems = DPA_GetPtr(infoPtr->hdpaItems, nItem);
8390 for (i = 1; i < DPA_GetPtrCount(hdpaSubItems); i++)
8391 {
8392 lpSubItem = DPA_GetPtr(hdpaSubItems, i);
8393 if (lpSubItem->iSubItem >= nNewColumn)
8394 lpSubItem->iSubItem++;
8395 }
8396
8397 /* add new subitem for each item */
8398 item.iItem = nItem;
8399 set_sub_item(infoPtr, &item, isW, &changed);
8400 }
8401 }
8402
8403 /* make space for the new column */
8404 LISTVIEW_ScrollColumns(infoPtr, nNewColumn + 1, lpColumnInfo->rcHeader.right - lpColumnInfo->rcHeader.left);
8405 LISTVIEW_UpdateItemSize(infoPtr);
8406
8407 return nNewColumn;
8408
8409fail:
8410 if (nNewColumn != -1) SendMessageW(infoPtr->hwndHeader, HDM_DELETEITEM, nNewColumn, 0);
8411 if (lpColumnInfo)
8412 {
8413 DPA_DeletePtr(infoPtr->hdpaColumns, nNewColumn);
8414 Free(lpColumnInfo);
8415 }
8416 return -1;
8417}
8418
8419/***
8420 * DESCRIPTION:
8421 * Sets the attributes of a header item.
8422 *
8423 * PARAMETER(S):
8424 * [I] infoPtr : valid pointer to the listview structure
8425 * [I] nColumn : column index
8426 * [I] lpColumn : column attributes
8427 * [I] isW: if TRUE, then lpColumn is a LPLVCOLUMNW, else it is a LPLVCOLUMNA
8428 *
8429 * RETURN:
8430 * SUCCESS : TRUE
8431 * FAILURE : FALSE
8432 */
8433static BOOL LISTVIEW_SetColumnT(const LISTVIEW_INFO *infoPtr, INT nColumn,
8434 const LVCOLUMNW *lpColumn, BOOL isW)
8435{
8436 HDITEMW hdi, hdiget;
8437 BOOL bResult;
8438
8439 TRACE("(nColumn=%d, lpColumn=%s, isW=%d)\n", nColumn, debuglvcolumn_t(lpColumn, isW), isW);
8440
8441 if (!lpColumn || nColumn < 0 || nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return FALSE;
8442
8443 ZeroMemory(&hdi, sizeof(HDITEMW));
8444 if (lpColumn->mask & LVCF_FMT)
8445 {
8446 hdi.mask |= HDI_FORMAT;
8447 hdiget.mask = HDI_FORMAT;
8448 if (SendMessageW(infoPtr->hwndHeader, HDM_GETITEMW, nColumn, (LPARAM)&hdiget))
8449 hdi.fmt = hdiget.fmt & HDF_STRING;
8450 }
8451 column_fill_hditem(infoPtr, &hdi, nColumn, lpColumn, isW);
8452
8453 /* set header item attributes */
8454 bResult = SendMessageW(infoPtr->hwndHeader, isW ? HDM_SETITEMW : HDM_SETITEMA, nColumn, (LPARAM)&hdi);
8455 if (!bResult) return FALSE;
8456
8457 if (lpColumn->mask & LVCF_FMT)
8458 {
8459 COLUMN_INFO *lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, nColumn);
8460 INT oldFmt = lpColumnInfo->fmt;
8461
8462 lpColumnInfo->fmt = lpColumn->fmt;
8463 if ((oldFmt ^ lpColumn->fmt) & (LVCFMT_JUSTIFYMASK | LVCFMT_IMAGE))
8464 {
8465 if (infoPtr->uView == LV_VIEW_DETAILS) LISTVIEW_InvalidateColumn(infoPtr, nColumn);
8466 }
8467 }
8468
8469 if (lpColumn->mask & LVCF_MINWIDTH)
8470 LISTVIEW_GetColumnInfo(infoPtr, nColumn)->cxMin = lpColumn->cxMin;
8471
8472 return TRUE;
8473}
8474
8475/***
8476 * DESCRIPTION:
8477 * Sets the column order array
8478 *
8479 * PARAMETERS:
8480 * [I] infoPtr : valid pointer to the listview structure
8481 * [I] iCount : number of elements in column order array
8482 * [I] lpiArray : pointer to column order array
8483 *
8484 * RETURN:
8485 * SUCCESS : TRUE
8486 * FAILURE : FALSE
8487 */
8488static BOOL LISTVIEW_SetColumnOrderArray(LISTVIEW_INFO *infoPtr, INT iCount, const INT *lpiArray)
8489{
8490 if (!infoPtr->hwndHeader) return FALSE;
8491 infoPtr->colRectsDirty = TRUE;
8492 return SendMessageW(infoPtr->hwndHeader, HDM_SETORDERARRAY, iCount, (LPARAM)lpiArray);
8493}
8494
8495/***
8496 * DESCRIPTION:
8497 * Sets the width of a column
8498 *
8499 * PARAMETERS:
8500 * [I] infoPtr : valid pointer to the listview structure
8501 * [I] nColumn : column index
8502 * [I] cx : column width
8503 *
8504 * RETURN:
8505 * SUCCESS : TRUE
8506 * FAILURE : FALSE
8507 */
8509{
8510 WCHAR szDispText[DISP_TEXT_SIZE] = { 0 };
8511 INT max_cx = 0;
8512 HDITEMW hdi;
8513
8514 TRACE("(nColumn=%d, cx=%d)\n", nColumn, cx);
8515
8516 /* set column width only if in report or list mode */
8517 if (infoPtr->uView != LV_VIEW_DETAILS && infoPtr->uView != LV_VIEW_LIST) return FALSE;
8518
8519 /* take care of invalid cx values - LVSCW_AUTOSIZE_* values are negative,
8520 with _USEHEADER being the lowest */
8522 else if (infoPtr->uView == LV_VIEW_LIST && cx <= 0) return FALSE;
8523
8524 /* resize all columns if in LV_VIEW_LIST mode */
8525 if(infoPtr->uView == LV_VIEW_LIST)
8526 {
8527 infoPtr->nItemWidth = cx;
8528 LISTVIEW_InvalidateList(infoPtr);
8529 return TRUE;
8530 }
8531
8532 if (nColumn < 0 || nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return FALSE;
8533
8534 if (cx == LVSCW_AUTOSIZE || (cx == LVSCW_AUTOSIZE_USEHEADER && nColumn < DPA_GetPtrCount(infoPtr->hdpaColumns) -1))
8535 {
8536 INT nLabelWidth;
8537 LVITEMW lvItem;
8538
8539 lvItem.mask = LVIF_TEXT;
8540 lvItem.iItem = 0;
8541 lvItem.iSubItem = nColumn;
8542 lvItem.cchTextMax = DISP_TEXT_SIZE;
8543 for (; lvItem.iItem < infoPtr->nItemCount; lvItem.iItem++)
8544 {
8545 lvItem.pszText = szDispText;
8546 if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) continue;
8547 nLabelWidth = LISTVIEW_GetStringWidthT(infoPtr, lvItem.pszText, TRUE);
8548 if (max_cx < nLabelWidth) max_cx = nLabelWidth;
8549 }
8550 if (infoPtr->himlSmall && (nColumn == 0 || (LISTVIEW_GetColumnInfo(infoPtr, nColumn)->fmt & LVCFMT_IMAGE)))
8551 max_cx += infoPtr->iconSize.cx;
8552 max_cx += TRAILING_LABEL_PADDING;
8553#ifdef __REACTOS__
8554 if (nColumn == 0 && infoPtr->himlState)
8555 max_cx += infoPtr->iconStateSize.cx;
8556#else
8557 if (nColumn == 0 && (infoPtr->dwLvExStyle & LVS_EX_CHECKBOXES))
8558 max_cx += GetSystemMetrics(SM_CXSMICON);
8559#endif
8560 }
8561
8562 /* autosize based on listview items width */
8563 if(cx == LVSCW_AUTOSIZE)
8564 cx = max_cx;
8565 else if(cx == LVSCW_AUTOSIZE_USEHEADER)
8566 {
8567 /* if iCol is the last column make it fill the remainder of the controls width */
8568 if(nColumn == DPA_GetPtrCount(infoPtr->hdpaColumns) - 1)
8569 {
8570 RECT rcHeader;
8571 POINT Origin;
8572
8573 LISTVIEW_GetOrigin(infoPtr, &Origin);
8574 LISTVIEW_GetHeaderRect(infoPtr, nColumn, &rcHeader);
8575
8576 cx = infoPtr->rcList.right - Origin.x - rcHeader.left;
8577 }
8578 else
8579 {
8580 /* Despite what the MS docs say, if this is not the last
8581 column, then MS resizes the column to the width of the
8582 largest text string in the column, including headers
8583 and items. This is different from LVSCW_AUTOSIZE in that
8584 LVSCW_AUTOSIZE ignores the header string length. */
8585 cx = 0;
8586
8587 /* retrieve header text */
8590 hdi.pszText = szDispText;
8591 if (SendMessageW(infoPtr->hwndHeader, HDM_GETITEMW, nColumn, (LPARAM)&hdi))
8592 {
8593 HDC hdc = GetDC(infoPtr->hwndSelf);
8594 HFONT old_font = SelectObject(hdc, (HFONT)SendMessageW(infoPtr->hwndHeader, WM_GETFONT, 0, 0));
8596 INT bitmap_margin = 0;
8597 SIZE size;
8598
8599 if (GetTextExtentPoint32W(hdc, hdi.pszText, lstrlenW(hdi.pszText), &size))
8601
8602 if (hdi.fmt & (HDF_IMAGE|HDF_BITMAP))
8603 bitmap_margin = SendMessageW(infoPtr->hwndHeader, HDM_GETBITMAPMARGIN, 0, 0);
8604
8605 if ((hdi.fmt & HDF_IMAGE) && himl)
8606 {
8607 INT icon_cx, icon_cy;
8608
8609 if (!ImageList_GetIconSize(himl, &icon_cx, &icon_cy))
8610 cx += icon_cx + 2*bitmap_margin;
8611 }
8612 else if (hdi.fmt & HDF_BITMAP)
8613 {
8614 BITMAP bmp;
8615
8616 GetObjectW(hdi.hbm, sizeof(BITMAP), &bmp);
8617 cx += bmp.bmWidth + 2*bitmap_margin;
8618 }
8619
8620 SelectObject(hdc, old_font);
8621 ReleaseDC(infoPtr->hwndSelf, hdc);
8622 }
8623 cx = max (cx, max_cx);
8624 }
8625 }
8626
8627 if (cx < 0) return FALSE;
8628
8629 /* call header to update the column change */
8630 hdi.mask = HDI_WIDTH;
8631 hdi.cxy = max(cx, LISTVIEW_GetColumnInfo(infoPtr, nColumn)->cxMin);
8632 TRACE("hdi.cxy=%d\n", hdi.cxy);
8633 return SendMessageW(infoPtr->hwndHeader, HDM_SETITEMW, nColumn, (LPARAM)&hdi);
8634}
8635
8636/***
8637 * Creates the checkbox imagelist. Helper for LISTVIEW_SetExtendedListViewStyle
8638 *
8639 */
8641{
8642 HDC hdc_wnd, hdc;
8643 HBITMAP hbm_im, hbm_mask, hbm_orig;
8644 RECT rc;
8645 HBRUSH hbr_white = GetStockObject(WHITE_BRUSH);
8646 HBRUSH hbr_black = GetStockObject(BLACK_BRUSH);
8648
8650 ILC_COLOR | ILC_MASK, 2, 2);
8651 hdc_wnd = GetDC(infoPtr->hwndSelf);
8652 hdc = CreateCompatibleDC(hdc_wnd);
8655 ReleaseDC(infoPtr->hwndSelf, hdc_wnd);
8656
8658 hbm_orig = SelectObject(hdc, hbm_mask);
8659 FillRect(hdc, &rc, hbr_white);
8660 InflateRect(&rc, -2, -2);
8661 FillRect(hdc, &rc, hbr_black);
8662
8663 SelectObject(hdc, hbm_im);
8665 SelectObject(hdc, hbm_orig);
8666 ImageList_Add(himl, hbm_im, hbm_mask);
8667
8668 SelectObject(hdc, hbm_im);
8670 SelectObject(hdc, hbm_orig);
8671 ImageList_Add(himl, hbm_im, hbm_mask);
8672
8673 DeleteObject(hbm_mask);
8674 DeleteObject(hbm_im);
8675 DeleteDC(hdc);
8676
8677 return himl;
8678}
8679
8680/***
8681 * DESCRIPTION:
8682 * Sets the extended listview style.
8683 *
8684 * PARAMETERS:
8685 * [I] infoPtr : valid pointer to the listview structure
8686 * [I] dwMask : mask
8687 * [I] dwStyle : style
8688 *
8689 * RETURN:
8690 * SUCCESS : previous style
8691 * FAILURE : 0
8692 */
8694{
8695 DWORD old_ex_style = infoPtr->dwLvExStyle;
8696
8697 TRACE("mask=0x%08x, ex_style=0x%08x\n", mask, ex_style);
8698
8699 /* set new style */
8700 if (mask)
8701 infoPtr->dwLvExStyle = (old_ex_style & ~mask) | (ex_style & mask);
8702 else
8703 infoPtr->dwLvExStyle = ex_style;
8704
8705 if((infoPtr->dwLvExStyle ^ old_ex_style) & LVS_EX_CHECKBOXES)
8706 {
8707 HIMAGELIST himl = 0;
8708 if(infoPtr->dwLvExStyle & LVS_EX_CHECKBOXES)
8709 {
8710 LVITEMW item;
8711 item.mask = LVIF_STATE;
8712 item.stateMask = LVIS_STATEIMAGEMASK;
8713 item.state = INDEXTOSTATEIMAGEMASK(1);
8714 LISTVIEW_SetItemState(infoPtr, -1, &item);
8715
8717 if(!(infoPtr->dwStyle & LVS_SHAREIMAGELISTS))
8718 ImageList_Destroy(infoPtr->himlState);
8719 }
8721 /* checkbox list replaces previous custom list or... */
8722 if(((infoPtr->dwLvExStyle & LVS_EX_CHECKBOXES) &&
8723 !(infoPtr->dwStyle & LVS_SHAREIMAGELISTS)) ||
8724 /* ...previous was checkbox list */
8725 (old_ex_style & LVS_EX_CHECKBOXES))
8727 }
8728
8729 if((infoPtr->dwLvExStyle ^ old_ex_style) & LVS_EX_HEADERDRAGDROP)
8730 {
8731 DWORD style;
8732
8733 /* if not already created */
8734 LISTVIEW_CreateHeader(infoPtr);
8735
8737 if (infoPtr->dwLvExStyle & LVS_EX_HEADERDRAGDROP)
8739 else
8740 style &= ~HDS_DRAGDROP;
8742 }
8743
8744 /* GRIDLINES adds decoration at top so changes sizes */
8745 if((infoPtr->dwLvExStyle ^ old_ex_style) & LVS_EX_GRIDLINES)
8746 {
8747 LISTVIEW_CreateHeader(infoPtr);
8748 LISTVIEW_UpdateSize(infoPtr);
8749 }
8750
8751 if((infoPtr->dwLvExStyle ^ old_ex_style) & LVS_EX_FULLROWSELECT)
8752 {
8753 LISTVIEW_CreateHeader(infoPtr);
8754 }
8755
8756 if((infoPtr->dwLvExStyle ^ old_ex_style) & LVS_EX_TRANSPARENTBKGND)
8757 {
8758 if (infoPtr->dwLvExStyle & LVS_EX_TRANSPARENTBKGND)
8759 LISTVIEW_SetBkColor(infoPtr, CLR_NONE);
8760 }
8761
8762 if((infoPtr->dwLvExStyle ^ old_ex_style) & LVS_EX_HEADERINALLVIEWS)
8763 {
8764 if (infoPtr->dwLvExStyle & LVS_EX_HEADERINALLVIEWS)
8765 LISTVIEW_CreateHeader(infoPtr);
8766 else
8767 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
8768 LISTVIEW_UpdateSize(infoPtr);
8769 LISTVIEW_UpdateScroll(infoPtr);
8770 }
8771
8772#ifdef __REACTOS__
8773 if ((infoPtr->dwLvExStyle & LVS_EX_SNAPTOGRID) > (old_ex_style & LVS_EX_SNAPTOGRID))
8774 {
8776 }
8777#endif
8778
8779 LISTVIEW_InvalidateList(infoPtr);
8780 return old_ex_style;
8781}
8782
8783/***
8784 * DESCRIPTION:
8785 * Sets the new hot cursor used during hot tracking and hover selection.
8786 *
8787 * PARAMETER(S):
8788 * [I] infoPtr : valid pointer to the listview structure
8789 * [I] hCursor : the new hot cursor handle
8790 *
8791 * RETURN:
8792 * Returns the previous hot cursor
8793 */
8795{
8796 HCURSOR oldCursor = infoPtr->hHotCursor;
8797
8798 infoPtr->hHotCursor = hCursor;
8799
8800 return oldCursor;
8801}
8802
8803
8804/***
8805 * DESCRIPTION:
8806 * Sets the hot item index.
8807 *
8808 * PARAMETERS:
8809 * [I] infoPtr : valid pointer to the listview structure
8810 * [I] iIndex : index
8811 *
8812 * RETURN:
8813 * SUCCESS : previous hot item index
8814 * FAILURE : -1 (no hot item)
8815 */
8817{
8818 INT iOldIndex = infoPtr->nHotItem;
8819
8820 infoPtr->nHotItem = iIndex;
8821
8822 return iOldIndex;
8823}
8824
8825
8826/***
8827 * DESCRIPTION:
8828 * Sets the amount of time the cursor must hover over an item before it is selected.
8829 *
8830 * PARAMETER(S):
8831 * [I] infoPtr : valid pointer to the listview structure
8832 * [I] dwHoverTime : hover time, if -1 the hover time is set to the default
8833 *
8834 * RETURN:
8835 * Returns the previous hover time
8836 */
8837static DWORD LISTVIEW_SetHoverTime(LISTVIEW_INFO *infoPtr, DWORD dwHoverTime)
8838{
8839 DWORD oldHoverTime = infoPtr->dwHoverTime;
8840
8841 infoPtr->dwHoverTime = dwHoverTime;
8842
8843 return oldHoverTime;
8844}
8845
8846/***
8847 * DESCRIPTION:
8848 * Sets spacing for icons of LVS_ICON style.
8849 *
8850 * PARAMETER(S):
8851 * [I] infoPtr : valid pointer to the listview structure
8852 * [I] cx : horizontal spacing (-1 = system spacing, 0 = autosize)
8853 * [I] cy : vertical spacing (-1 = system spacing, 0 = autosize)
8854 *
8855 * RETURN:
8856 * MAKELONG(oldcx, oldcy)
8857 */
8859{
8860 INT iconWidth = 0, iconHeight = 0;
8861 DWORD oldspacing = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
8862
8863 TRACE("requested=(%d,%d)\n", cx, cy);
8864
8865 /* set to defaults, if instructed to */
8866 if (cx == -1 && cy == -1)
8867 {
8868 infoPtr->autoSpacing = TRUE;
8869 if (infoPtr->himlNormal)
8870 ImageList_GetIconSize(infoPtr->himlNormal, &iconWidth, &iconHeight);
8873 }
8874 else
8875 infoPtr->autoSpacing = FALSE;
8876
8877 /* if 0 then keep width */
8878 if (cx != 0)
8879 infoPtr->iconSpacing.cx = cx;
8880
8881 /* if 0 then keep height */
8882 if (cy != 0)
8883 infoPtr->iconSpacing.cy = cy;
8884
8885 TRACE("old=(%d,%d), new=(%d,%d), iconSize=(%d,%d), ntmH=%d\n",
8886 LOWORD(oldspacing), HIWORD(oldspacing), infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy,
8887 infoPtr->iconSize.cx, infoPtr->iconSize.cy,
8888 infoPtr->ntmHeight);
8889
8890 /* these depend on the iconSpacing */
8891 LISTVIEW_UpdateItemSize(infoPtr);
8892
8893 return oldspacing;
8894}
8895
8896static inline void set_icon_size(SIZE *size, HIMAGELIST himl, BOOL is_small)
8897{
8898 INT cx, cy;
8899
8900 if (himl && ImageList_GetIconSize(himl, &cx, &cy))
8901 {
8902 size->cx = cx;
8903 size->cy = cy;
8904 }
8905 else
8906 {
8907 size->cx = GetSystemMetrics(is_small ? SM_CXSMICON : SM_CXICON);
8908 size->cy = GetSystemMetrics(is_small ? SM_CYSMICON : SM_CYICON);
8909 }
8910}
8911
8912/***
8913 * DESCRIPTION:
8914 * Sets image lists.
8915 *
8916 * PARAMETER(S):
8917 * [I] infoPtr : valid pointer to the listview structure
8918 * [I] nType : image list type
8919 * [I] himl : image list handle
8920 *
8921 * RETURN:
8922 * SUCCESS : old image list
8923 * FAILURE : NULL
8924 */
8926{
8927 INT oldHeight = infoPtr->nItemHeight;
8928 HIMAGELIST himlOld = 0;
8929
8930 TRACE("(nType=%d, himl=%p)\n", nType, himl);
8931
8932 switch (nType)
8933 {
8934 case LVSIL_NORMAL:
8935 himlOld = infoPtr->himlNormal;
8936 infoPtr->himlNormal = himl;
8937 if (infoPtr->uView == LV_VIEW_ICON) set_icon_size(&infoPtr->iconSize, himl, FALSE);
8938 if (infoPtr->autoSpacing)
8939 LISTVIEW_SetIconSpacing(infoPtr, -1, -1);
8940 break;
8941
8942 case LVSIL_SMALL:
8943 himlOld = infoPtr->himlSmall;
8944 infoPtr->himlSmall = himl;
8945 if (infoPtr->uView != LV_VIEW_ICON) set_icon_size(&infoPtr->iconSize, himl, TRUE);
8946 if (infoPtr->hwndHeader)
8948 break;
8949
8950 case LVSIL_STATE:
8951 himlOld = infoPtr->himlState;
8952 infoPtr->himlState = himl;
8953 set_icon_size(&infoPtr->iconStateSize, himl, TRUE);
8955 break;
8956
8957 default:
8958 ERR("Unknown icon type=%d\n", nType);
8959 return NULL;
8960 }
8961
8962 infoPtr->nItemHeight = LISTVIEW_CalculateItemHeight(infoPtr);
8963 if (infoPtr->nItemHeight != oldHeight)
8964 LISTVIEW_UpdateScroll(infoPtr);
8965
8966 return himlOld;
8967}
8968
8969/***
8970 * DESCRIPTION:
8971 * Preallocates memory (does *not* set the actual count of items !)
8972 *
8973 * PARAMETER(S):
8974 * [I] infoPtr : valid pointer to the listview structure
8975 * [I] nItems : item count (projected number of items to allocate)
8976 * [I] dwFlags : update flags
8977 *
8978 * RETURN:
8979 * SUCCESS : TRUE
8980 * FAILURE : FALSE
8981 */
8983{
8984 TRACE("(nItems=%d, dwFlags=%x)\n", nItems, dwFlags);
8985
8986 if (infoPtr->dwStyle & LVS_OWNERDATA)
8987 {
8988 INT nOldCount = infoPtr->nItemCount;
8989 infoPtr->nItemCount = nItems;
8990
8991 if (nItems < nOldCount)
8992 {
8993 RANGE range = { nItems, nOldCount };
8994 ranges_del(infoPtr->selectionRanges, range);
8995 if (infoPtr->nFocusedItem >= nItems)
8996 {
8997 LISTVIEW_SetItemFocus(infoPtr, -1);
8998 infoPtr->nFocusedItem = -1;
8999 SetRectEmpty(&infoPtr->rcFocus);
9000 }
9001 }
9002
9003 LISTVIEW_UpdateScroll(infoPtr);
9004
9005 /* the flags are valid only in ownerdata report and list modes */
9006 if (infoPtr->uView == LV_VIEW_ICON || infoPtr->uView == LV_VIEW_SMALLICON) dwFlags = 0;
9007
9008 if (!(dwFlags & LVSICF_NOSCROLL) && infoPtr->nFocusedItem != -1)
9009 LISTVIEW_EnsureVisible(infoPtr, infoPtr->nFocusedItem, FALSE);
9010
9012 LISTVIEW_InvalidateList(infoPtr);
9013 else
9014 {
9015 INT nFrom, nTo;
9016 POINT Origin;
9017 RECT rcErase;
9018
9019 LISTVIEW_GetOrigin(infoPtr, &Origin);
9020 nFrom = min(nOldCount, nItems);
9021 nTo = max(nOldCount, nItems);
9022
9023 if (infoPtr->uView == LV_VIEW_DETAILS)
9024 {
9025 SetRect(&rcErase, 0, nFrom * infoPtr->nItemHeight, infoPtr->nItemWidth,
9026 nTo * infoPtr->nItemHeight);
9027 OffsetRect(&rcErase, Origin.x, Origin.y);
9028 if (IntersectRect(&rcErase, &rcErase, &infoPtr->rcList))
9029 LISTVIEW_InvalidateRect(infoPtr, &rcErase);
9030 }
9031 else /* LV_VIEW_LIST */
9032 {
9033 INT nPerCol = LISTVIEW_GetCountPerColumn(infoPtr);
9034
9035 rcErase.left = (nFrom / nPerCol) * infoPtr->nItemWidth;
9036 rcErase.top = (nFrom % nPerCol) * infoPtr->nItemHeight;
9037 rcErase.right = rcErase.left + infoPtr->nItemWidth;
9038 rcErase.bottom = nPerCol * infoPtr->nItemHeight;
9039 OffsetRect(&rcErase, Origin.x, Origin.y);
9040 if (IntersectRect(&rcErase, &rcErase, &infoPtr->rcList))
9041 LISTVIEW_InvalidateRect(infoPtr, &rcErase);
9042
9043 rcErase.left = (nFrom / nPerCol + 1) * infoPtr->nItemWidth;
9044 rcErase.top = 0;
9045 rcErase.right = (nTo / nPerCol + 1) * infoPtr->nItemWidth;
9046 rcErase.bottom = nPerCol * infoPtr->nItemHeight;
9047 OffsetRect(&rcErase, Origin.x, Origin.y);
9048 if (IntersectRect(&rcErase, &rcErase, &infoPtr->rcList))
9049 LISTVIEW_InvalidateRect(infoPtr, &rcErase);
9050 }
9051 }
9052 }
9053 else
9054 {
9055 /* According to MSDN for non-LVS_OWNERDATA this is just
9056 * a performance issue. The control allocates its internal
9057 * data structures for the number of items specified. It
9058 * cuts down on the number of memory allocations. Therefore
9059 * we will just issue a WARN here
9060 */
9061 WARN("for non-ownerdata performance option not implemented.\n");
9062 }
9063
9064 return TRUE;
9065}
9066
9067/***
9068 * DESCRIPTION:
9069 * Sets the position of an item.
9070 *
9071 * PARAMETER(S):
9072 * [I] infoPtr : valid pointer to the listview structure
9073 * [I] nItem : item index
9074 * [I] pt : coordinate
9075 *
9076 * RETURN:
9077 * SUCCESS : TRUE
9078 * FAILURE : FALSE
9079 */
9081{
9082 POINT Origin, Pt;
9083
9084 TRACE("(nItem=%d, pt=%s)\n", nItem, wine_dbgstr_point(pt));
9085
9086 if (!pt || nItem < 0 || nItem >= infoPtr->nItemCount ||
9087 !(infoPtr->uView == LV_VIEW_ICON || infoPtr->uView == LV_VIEW_SMALLICON)) return FALSE;
9088
9089#ifdef __REACTOS__
9090 /* FIXME: This should really call snap to grid if auto-arrange is enabled
9091 and limit the size of the grid to nItemCount elements */
9092 if (is_autoarrange(infoPtr)) return FALSE;
9093#endif
9094
9095 Pt = *pt;
9096 LISTVIEW_GetOrigin(infoPtr, &Origin);
9097
9098 /* This point value seems to be an undocumented feature.
9099 * The best guess is that it means either at the origin,
9100 * or at true beginning of the list. I will assume the origin. */
9101 if ((Pt.x == -1) && (Pt.y == -1))
9102 Pt = Origin;
9103
9104 if (infoPtr->uView == LV_VIEW_ICON)
9105 {
9106 Pt.x -= (infoPtr->nItemWidth - infoPtr->iconSize.cx) / 2;
9107 Pt.y -= ICON_TOP_PADDING;
9108 }
9109 Pt.x -= Origin.x;
9110 Pt.y -= Origin.y;
9111
9112#ifdef __REACTOS__
9113 if (infoPtr->dwLvExStyle & LVS_EX_SNAPTOGRID)
9114 {
9115 Pt.x = max(0, Pt.x + (infoPtr->nItemWidth >> 1) - (Pt.x + (infoPtr->nItemWidth >> 1)) % infoPtr->nItemWidth);
9116 Pt.y = max(0, Pt.y + (infoPtr->nItemHeight >> 1) - (Pt.y + (infoPtr->nItemHeight >> 1)) % infoPtr->nItemHeight);
9117 }
9118#endif
9119
9120 return LISTVIEW_MoveIconTo(infoPtr, nItem, &Pt, FALSE);
9121}
9122
9123/***
9124 * DESCRIPTION:
9125 * Sets the state of one or many items.
9126 *
9127 * PARAMETER(S):
9128 * [I] infoPtr : valid pointer to the listview structure
9129 * [I] nItem : item index
9130 * [I] item : item or subitem info
9131 *
9132 * RETURN:
9133 * SUCCESS : TRUE
9134 * FAILURE : FALSE
9135 */
9137{
9138 BOOL ret = TRUE;
9139 LVITEMW lvItem;
9140
9141 if (!item) return FALSE;
9142
9143 lvItem.iItem = nItem;
9144 lvItem.iSubItem = 0;
9145 lvItem.mask = LVIF_STATE;
9146 lvItem.state = item->state;
9147 lvItem.stateMask = item->stateMask;
9148 TRACE("item=%s\n", debuglvitem_t(&lvItem, TRUE));
9149
9150 if (nItem == -1)
9151 {
9152 UINT oldstate = 0;
9153 DWORD old_mask;
9154
9155 /* special case optimization for recurring attempt to deselect all */
9156 if (lvItem.state == 0 && lvItem.stateMask == LVIS_SELECTED && !LISTVIEW_GetSelectedCount(infoPtr))
9157 return TRUE;
9158
9159 /* select all isn't allowed in LVS_SINGLESEL */
9160 if ((lvItem.state & lvItem.stateMask & LVIS_SELECTED) && (infoPtr->dwStyle & LVS_SINGLESEL))
9161 return FALSE;
9162
9163 /* focus all isn't allowed */
9164 if (lvItem.state & lvItem.stateMask & LVIS_FOCUSED) return FALSE;
9165
9166 old_mask = infoPtr->notify_mask & NOTIFY_MASK_ITEM_CHANGE;
9167 if (infoPtr->dwStyle & LVS_OWNERDATA)
9168 {
9169 infoPtr->notify_mask &= ~NOTIFY_MASK_ITEM_CHANGE;
9170 if (!(lvItem.state & LVIS_SELECTED) && LISTVIEW_GetSelectedCount(infoPtr))
9171 oldstate |= LVIS_SELECTED;
9172 if (infoPtr->nFocusedItem != -1) oldstate |= LVIS_FOCUSED;
9173 }
9174
9175 /* apply to all items */
9176 for (lvItem.iItem = 0; lvItem.iItem < infoPtr->nItemCount; lvItem.iItem++)
9177 if (!LISTVIEW_SetItemT(infoPtr, &lvItem, TRUE)) ret = FALSE;
9178
9179 if (infoPtr->dwStyle & LVS_OWNERDATA)
9180 {
9181 NMLISTVIEW nmlv;
9182
9183 infoPtr->notify_mask |= old_mask;
9184
9185 nmlv.iItem = -1;
9186 nmlv.iSubItem = 0;
9187 nmlv.uNewState = lvItem.state & lvItem.stateMask;
9188 nmlv.uOldState = oldstate & lvItem.stateMask;
9189 nmlv.uChanged = LVIF_STATE;
9190 nmlv.ptAction.x = nmlv.ptAction.y = 0;
9191 nmlv.lParam = 0;
9192
9193 notify_listview(infoPtr, LVN_ITEMCHANGED, &nmlv);
9194 }
9195 }
9196 else
9197 ret = LISTVIEW_SetItemT(infoPtr, &lvItem, TRUE);
9198
9199 return ret;
9200}
9201
9202/***
9203 * DESCRIPTION:
9204 * Sets the text of an item or subitem.
9205 *
9206 * PARAMETER(S):
9207 * [I] hwnd : window handle
9208 * [I] nItem : item index
9209 * [I] lpLVItem : item or subitem info
9210 * [I] isW : TRUE if input is Unicode
9211 *
9212 * RETURN:
9213 * SUCCESS : TRUE
9214 * FAILURE : FALSE
9215 */
9216static BOOL LISTVIEW_SetItemTextT(LISTVIEW_INFO *infoPtr, INT nItem, const LVITEMW *lpLVItem, BOOL isW)
9217{
9218 LVITEMW lvItem;
9219
9220 if (!lpLVItem || nItem < 0 || nItem >= infoPtr->nItemCount) return FALSE;
9221 if (infoPtr->dwStyle & LVS_OWNERDATA) return FALSE;
9222
9223 lvItem.iItem = nItem;
9224 lvItem.iSubItem = lpLVItem->iSubItem;
9225 lvItem.mask = LVIF_TEXT;
9226 lvItem.pszText = lpLVItem->pszText;
9227 lvItem.cchTextMax = lpLVItem->cchTextMax;
9228
9229 TRACE("(nItem=%d, lpLVItem=%s, isW=%d)\n", nItem, debuglvitem_t(&lvItem, isW), isW);
9230
9231 return LISTVIEW_SetItemT(infoPtr, &lvItem, isW);
9232}
9233
9234/***
9235 * DESCRIPTION:
9236 * Set item index that marks the start of a multiple selection.
9237 *
9238 * PARAMETER(S):
9239 * [I] infoPtr : valid pointer to the listview structure
9240 * [I] nIndex : index
9241 *
9242 * RETURN:
9243 * Index number or -1 if there is no selection mark.
9244 */
9246{
9247 INT nOldIndex = infoPtr->nSelectionMark;
9248
9249 TRACE("(nIndex=%d)\n", nIndex);
9250
9251 if (nIndex >= -1 && nIndex < infoPtr->nItemCount)
9252 infoPtr->nSelectionMark = nIndex;
9253
9254 return nOldIndex;
9255}
9256
9257/***
9258 * DESCRIPTION:
9259 * Sets the text background color.
9260 *
9261 * PARAMETER(S):
9262 * [I] infoPtr : valid pointer to the listview structure
9263 * [I] color : text background color
9264 *
9265 * RETURN:
9266 * SUCCESS : TRUE
9267 * FAILURE : FALSE
9268 */
9270{
9271 TRACE("(color=%x)\n", color);
9272
9273 infoPtr->clrTextBk = color;
9274 return TRUE;
9275}
9276
9277/***
9278 * DESCRIPTION:
9279 * Sets the text foreground color.
9280 *
9281 * PARAMETER(S):
9282 * [I] infoPtr : valid pointer to the listview structure
9283 * [I] color : text color
9284 *
9285 * RETURN:
9286 * SUCCESS : TRUE
9287 * FAILURE : FALSE
9288 */
9290{
9291 TRACE("(color=%x)\n", color);
9292
9293 infoPtr->clrText = color;
9294 return TRUE;
9295}
9296
9297/***
9298 * DESCRIPTION:
9299 * Sets new ToolTip window to ListView control.
9300 *
9301 * PARAMETER(S):
9302 * [I] infoPtr : valid pointer to the listview structure
9303 * [I] hwndNewToolTip : handle to new ToolTip
9304 *
9305 * RETURN:
9306 * old tool tip
9307 */
9308static HWND LISTVIEW_SetToolTips( LISTVIEW_INFO *infoPtr, HWND hwndNewToolTip)
9309{
9310 HWND hwndOldToolTip = infoPtr->hwndToolTip;
9311 infoPtr->hwndToolTip = hwndNewToolTip;
9312 return hwndOldToolTip;
9313}
9314
9315/*
9316 * DESCRIPTION:
9317 * sets the Unicode character format flag for the control
9318 * PARAMETER(S):
9319 * [I] infoPtr :valid pointer to the listview structure
9320 * [I] fUnicode :true to switch to UNICODE false to switch to ANSI
9321 *
9322 * RETURN:
9323 * Old Unicode Format
9324 */
9326{
9327 SHORT rc = infoPtr->notifyFormat;
9328 infoPtr->notifyFormat = (unicode) ? NFR_UNICODE : NFR_ANSI;
9329 return rc == NFR_UNICODE;
9330}
9331
9332/*
9333 * DESCRIPTION:
9334 * sets the control view mode
9335 * PARAMETER(S):
9336 * [I] infoPtr :valid pointer to the listview structure
9337 * [I] nView :new view mode value
9338 *
9339 * RETURN:
9340 * SUCCESS: 1
9341 * FAILURE: -1
9342 */
9344{
9346
9347 if (infoPtr->uView == nView) return 1;
9348
9349 if ((INT)nView < 0 || nView > LV_VIEW_MAX) return -1;
9350 if (nView == LV_VIEW_TILE)
9351 {
9352 FIXME("View LV_VIEW_TILE unimplemented\n");
9353 return -1;
9354 }
9355
9356 infoPtr->uView = nView;
9357
9358 SendMessageW(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
9359 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
9360
9361 ShowScrollBar(infoPtr->hwndSelf, SB_BOTH, FALSE);
9362 SetRectEmpty(&infoPtr->rcFocus);
9363
9364 himl = (nView == LV_VIEW_ICON ? infoPtr->himlNormal : infoPtr->himlSmall);
9365 set_icon_size(&infoPtr->iconSize, himl, nView != LV_VIEW_ICON);
9366
9367 switch (nView)
9368 {
9369 case LV_VIEW_ICON:
9370 case LV_VIEW_SMALLICON:
9371 LISTVIEW_Arrange(infoPtr, LVA_DEFAULT);
9372 break;
9373 case LV_VIEW_DETAILS:
9374 {
9375 HDLAYOUT hl;
9376 WINDOWPOS wp;
9377
9378 LISTVIEW_CreateHeader( infoPtr );
9379
9380 hl.prc = &infoPtr->rcList;
9381 hl.pwpos = &wp;
9382 SendMessageW(infoPtr->hwndHeader, HDM_LAYOUT, 0, (LPARAM)&hl);
9383 SetWindowPos(infoPtr->hwndHeader, infoPtr->hwndSelf, wp.x, wp.y, wp.cx, wp.cy,
9385 break;
9386 }
9387 case LV_VIEW_LIST:
9388 break;
9389 }
9390
9391 LISTVIEW_UpdateItemSize(infoPtr);
9392 LISTVIEW_UpdateSize(infoPtr);
9393 LISTVIEW_UpdateScroll(infoPtr);
9394 LISTVIEW_InvalidateList(infoPtr);
9395
9396 TRACE("nView=%d\n", nView);
9397
9398 return 1;
9399}
9400
9401/* LISTVIEW_SetWorkAreas */
9402
9403/***
9404 * DESCRIPTION:
9405 * Callback internally used by LISTVIEW_SortItems() in response of LVM_SORTITEMS
9406 *
9407 * PARAMETER(S):
9408 * [I] first : pointer to first ITEM_INFO to compare
9409 * [I] second : pointer to second ITEM_INFO to compare
9410 * [I] lParam : HWND of control
9411 *
9412 * RETURN:
9413 * if first comes before second : negative
9414 * if first comes after second : positive
9415 * if first and second are equivalent : zero
9416 */
9418{
9419 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)lParam;
9420 ITEM_INFO* lv_first = DPA_GetPtr( first, 0 );
9421 ITEM_INFO* lv_second = DPA_GetPtr( second, 0 );
9422
9423 /* Forward the call to the client defined callback */
9424 return (infoPtr->pfnCompare)( lv_first->lParam , lv_second->lParam, infoPtr->lParamSort );
9425}
9426
9427/***
9428 * DESCRIPTION:
9429 * Callback internally used by LISTVIEW_SortItems() in response of LVM_SORTITEMSEX
9430 *
9431 * PARAMETER(S):
9432 * [I] first : pointer to first ITEM_INFO to compare
9433 * [I] second : pointer to second ITEM_INFO to compare
9434 * [I] lParam : HWND of control
9435 *
9436 * RETURN:
9437 * if first comes before second : negative
9438 * if first comes after second : positive
9439 * if first and second are equivalent : zero
9440 */
9442{
9443 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)lParam;
9444 INT first_idx = DPA_GetPtrIndex( infoPtr->hdpaItems, first );
9445 INT second_idx = DPA_GetPtrIndex( infoPtr->hdpaItems, second );
9446
9447 /* Forward the call to the client defined callback */
9448 return (infoPtr->pfnCompare)( first_idx, second_idx, infoPtr->lParamSort );
9449}
9450
9451/***
9452 * DESCRIPTION:
9453 * Sorts the listview items.
9454 *
9455 * PARAMETER(S):
9456 * [I] infoPtr : valid pointer to the listview structure
9457 * [I] pfnCompare : application-defined value
9458 * [I] lParamSort : pointer to comparison callback
9459 * [I] IsEx : TRUE when LVM_SORTITEMSEX used
9460 *
9461 * RETURN:
9462 * SUCCESS : TRUE
9463 * FAILURE : FALSE
9464 */
9466 LPARAM lParamSort, BOOL IsEx)
9467{
9468 HDPA hdpaSubItems;
9469 ITEM_INFO *lpItem;
9470 LPVOID selectionMarkItem = NULL;
9471 LPVOID focusedItem = NULL;
9472 int i;
9473
9474 TRACE("(pfnCompare=%p, lParamSort=%lx)\n", pfnCompare, lParamSort);
9475
9476 if (infoPtr->dwStyle & LVS_OWNERDATA) return FALSE;
9477
9478 if (!pfnCompare) return FALSE;
9479 if (!infoPtr->hdpaItems) return FALSE;
9480
9481 /* if there are 0 or 1 items, there is no need to sort */
9482 if (infoPtr->nItemCount < 2) return TRUE;
9483
9484 /* clear selection */
9485 ranges_clear(infoPtr->selectionRanges);
9486
9487 /* save selection mark and focused item */
9488 if (infoPtr->nSelectionMark >= 0)
9489 selectionMarkItem = DPA_GetPtr(infoPtr->hdpaItems, infoPtr->nSelectionMark);
9490 if (infoPtr->nFocusedItem >= 0)
9491 focusedItem = DPA_GetPtr(infoPtr->hdpaItems, infoPtr->nFocusedItem);
9492
9493 infoPtr->pfnCompare = pfnCompare;
9494 infoPtr->lParamSort = lParamSort;
9495 if (IsEx)
9497 else
9499
9500 /* restore selection ranges */
9501 for (i=0; i < infoPtr->nItemCount; i++)
9502 {
9503 hdpaSubItems = DPA_GetPtr(infoPtr->hdpaItems, i);
9504 lpItem = DPA_GetPtr(hdpaSubItems, 0);
9505
9506 if (lpItem->state & LVIS_SELECTED)
9507 ranges_additem(infoPtr->selectionRanges, i);
9508 }
9509 /* restore selection mark and focused item */
9510 infoPtr->nSelectionMark = DPA_GetPtrIndex(infoPtr->hdpaItems, selectionMarkItem);
9511 infoPtr->nFocusedItem = DPA_GetPtrIndex(infoPtr->hdpaItems, focusedItem);
9512
9513 /* I believe nHotItem should be left alone, see LISTVIEW_ShiftIndices */
9514
9515 /* refresh the display */
9516 LISTVIEW_InvalidateList(infoPtr);
9517 return TRUE;
9518}
9519
9520/***
9521 * DESCRIPTION:
9522 * Update theme handle after a theme change.
9523 *
9524 * PARAMETER(S):
9525 * [I] infoPtr : valid pointer to the listview structure
9526 *
9527 * RETURN:
9528 * SUCCESS : 0
9529 * FAILURE : something else
9530 */
9532{
9533 HTHEME theme = GetWindowTheme(infoPtr->hwndSelf);
9534 CloseThemeData(theme);
9536 return 0;
9537}
9538
9539/***
9540 * DESCRIPTION:
9541 * Updates an items or rearranges the listview control.
9542 *
9543 * PARAMETER(S):
9544 * [I] infoPtr : valid pointer to the listview structure
9545 * [I] nItem : item index
9546 *
9547 * RETURN:
9548 * SUCCESS : TRUE
9549 * FAILURE : FALSE
9550 */
9551static BOOL LISTVIEW_Update(LISTVIEW_INFO *infoPtr, INT nItem)
9552{
9553 TRACE("(nItem=%d)\n", nItem);
9554
9555 if (nItem < 0 || nItem >= infoPtr->nItemCount) return FALSE;
9556
9557 /* rearrange with default alignment style */
9558 if (is_autoarrange(infoPtr))
9559 LISTVIEW_Arrange(infoPtr, LVA_DEFAULT);
9560 else
9561 LISTVIEW_InvalidateItem(infoPtr, nItem);
9562
9563 return TRUE;
9564}
9565
9566/***
9567 * DESCRIPTION:
9568 * Draw the track line at the place defined in the infoPtr structure.
9569 * The line is drawn with a XOR pen so drawing the line for the second time
9570 * in the same place erases the line.
9571 *
9572 * PARAMETER(S):
9573 * [I] infoPtr : valid pointer to the listview structure
9574 *
9575 * RETURN:
9576 * SUCCESS : TRUE
9577 * FAILURE : FALSE
9578 */
9580{
9581 HDC hdc;
9582
9583 if (infoPtr->xTrackLine == -1)
9584 return FALSE;
9585
9586 if (!(hdc = GetDC(infoPtr->hwndSelf)))
9587 return FALSE;
9588 PatBlt( hdc, infoPtr->xTrackLine, infoPtr->rcList.top,
9589 1, infoPtr->rcList.bottom - infoPtr->rcList.top, DSTINVERT );
9590 ReleaseDC(infoPtr->hwndSelf, hdc);
9591 return TRUE;
9592}
9593
9594/***
9595 * DESCRIPTION:
9596 * Called when an edit control should be displayed. This function is called after
9597 * we are sure that there was a single click - not a double click (this is a TIMERPROC).
9598 *
9599 * PARAMETER(S):
9600 * [I] hwnd : Handle to the listview
9601 * [I] uMsg : WM_TIMER (ignored)
9602 * [I] idEvent : The timer ID interpreted as a pointer to a DELAYED_EDIT_ITEM struct
9603 * [I] dwTimer : The elapsed time (ignored)
9604 *
9605 * RETURN:
9606 * None.
9607 */
9609{
9610 DELAYED_ITEM_EDIT *editItem = (DELAYED_ITEM_EDIT *)idEvent;
9612
9613 KillTimer(hwnd, idEvent);
9614 editItem->fEnabled = FALSE;
9615 /* check if the item is still selected */
9616 if (infoPtr->bFocus && LISTVIEW_GetItemState(infoPtr, editItem->iItem, LVIS_SELECTED))
9617 LISTVIEW_EditLabelT(infoPtr, editItem->iItem, TRUE);
9618}
9619
9620/***
9621 * DESCRIPTION:
9622 * Creates the listview control - the WM_NCCREATE phase.
9623 *
9624 * PARAMETER(S):
9625 * [I] hwnd : window handle
9626 * [I] lpcs : the create parameters
9627 *
9628 * RETURN:
9629 * Success: TRUE
9630 * Failure: FALSE
9631 */
9633{
9634 LISTVIEW_INFO *infoPtr;
9635 LOGFONTW logFont;
9636
9637 TRACE("(lpcs=%p)\n", lpcs);
9638
9639 /* initialize info pointer */
9640 infoPtr = Alloc(sizeof(LISTVIEW_INFO));
9641 if (!infoPtr) return FALSE;
9642
9643 SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)infoPtr);
9644
9645 infoPtr->hwndSelf = hwnd;
9646 infoPtr->dwStyle = lpcs->style; /* Note: may be changed in WM_CREATE */
9647 map_style_view(infoPtr);
9648 /* determine the type of structures to use */
9649 infoPtr->hwndNotify = lpcs->hwndParent;
9650 /* infoPtr->notifyFormat will be filled in WM_CREATE */
9651
9652 /* initialize color information */
9653 infoPtr->clrBk = CLR_NONE;
9654 infoPtr->clrText = CLR_DEFAULT;
9655 infoPtr->clrTextBk = CLR_DEFAULT;
9657#ifdef __REACTOS__
9658 infoPtr->bDefaultBkColor = TRUE;
9659#endif
9660
9661 /* set default values */
9662 infoPtr->nFocusedItem = -1;
9663 infoPtr->nSelectionMark = -1;
9664 infoPtr->nHotItem = -1;
9665 infoPtr->redraw = TRUE;
9666 infoPtr->bNoItemMetrics = TRUE;
9668 infoPtr->autoSpacing = TRUE;
9671 infoPtr->nEditLabelItem = -1;
9672 infoPtr->nLButtonDownItem = -1;
9673 infoPtr->dwHoverTime = HOVER_DEFAULT; /* default system hover time */
9674 infoPtr->cWheelRemainder = 0;
9675 infoPtr->nMeasureItemHeight = 0;
9676 infoPtr->xTrackLine = -1; /* no track line */
9677 infoPtr->itemEdit.fEnabled = FALSE;
9678 infoPtr->iVersion = COMCTL32_VERSION;
9679 infoPtr->colRectsDirty = FALSE;
9680
9681 /* get default font (icon title) */
9683 infoPtr->hDefaultFont = CreateFontIndirectW(&logFont);
9684 infoPtr->hFont = infoPtr->hDefaultFont;
9685 LISTVIEW_SaveTextMetrics(infoPtr);
9686
9687 /* allocate memory for the data structure */
9688 if (!(infoPtr->selectionRanges = ranges_create(10))) goto fail;
9689 if (!(infoPtr->hdpaItems = DPA_Create(10))) goto fail;
9690 if (!(infoPtr->hdpaItemIds = DPA_Create(10))) goto fail;
9691 if (!(infoPtr->hdpaPosX = DPA_Create(10))) goto fail;
9692 if (!(infoPtr->hdpaPosY = DPA_Create(10))) goto fail;
9693 if (!(infoPtr->hdpaColumns = DPA_Create(10))) goto fail;
9694
9695 return DefWindowProcW(hwnd, WM_NCCREATE, wParam, (LPARAM)lpcs);
9696
9697fail:
9698 DestroyWindow(infoPtr->hwndHeader);
9700 DPA_Destroy(infoPtr->hdpaItems);
9701 DPA_Destroy(infoPtr->hdpaItemIds);
9702 DPA_Destroy(infoPtr->hdpaPosX);
9703 DPA_Destroy(infoPtr->hdpaPosY);
9704 DPA_Destroy(infoPtr->hdpaColumns);
9705 Free(infoPtr);
9706 return FALSE;
9707}
9708
9709/***
9710 * DESCRIPTION:
9711 * Creates the listview control - the WM_CREATE phase. Most of the data is
9712 * already set up in LISTVIEW_NCCreate
9713 *
9714 * PARAMETER(S):
9715 * [I] hwnd : window handle
9716 * [I] lpcs : the create parameters
9717 *
9718 * RETURN:
9719 * Success: 0
9720 * Failure: -1
9721 */
9723{
9725
9726 TRACE("(lpcs=%p, style=0x%08x)\n", lpcs, lpcs->style);
9727
9728 infoPtr->dwStyle = lpcs->style;
9729 map_style_view(infoPtr);
9730
9731 infoPtr->notifyFormat = SendMessageW(infoPtr->hwndNotify, WM_NOTIFYFORMAT,
9732 (WPARAM)infoPtr->hwndSelf, NF_QUERY);
9733 /* on error defaulting to ANSI notifications */
9734 if (infoPtr->notifyFormat == 0) infoPtr->notifyFormat = NFR_ANSI;
9735 TRACE("notify format=%d\n", infoPtr->notifyFormat);
9736
9737 if ((infoPtr->uView == LV_VIEW_DETAILS) && (lpcs->style & WS_VISIBLE))
9738 {
9739 if (LISTVIEW_CreateHeader(infoPtr) < 0) return -1;
9740 }
9741 else
9742 infoPtr->hwndHeader = 0;
9743
9744 /* init item size to avoid division by 0 */
9745 LISTVIEW_UpdateItemSize (infoPtr);
9746 LISTVIEW_UpdateSize (infoPtr);
9747
9748 if (infoPtr->uView == LV_VIEW_DETAILS)
9749 {
9750 if (!(LVS_NOCOLUMNHEADER & lpcs->style) && (WS_VISIBLE & lpcs->style))
9751 {
9753 }
9754 LISTVIEW_UpdateScroll(infoPtr);
9755 /* send WM_MEASUREITEM notification */
9756 if (infoPtr->dwStyle & LVS_OWNERDRAWFIXED) notify_measureitem(infoPtr);
9757 }
9758
9760
9761 /* initialize the icon sizes */
9762 set_icon_size(&infoPtr->iconSize, infoPtr->himlNormal, infoPtr->uView != LV_VIEW_ICON);
9763 set_icon_size(&infoPtr->iconStateSize, infoPtr->himlState, TRUE);
9764 return 0;
9765}
9766
9767/***
9768 * DESCRIPTION:
9769 * Destroys the listview control.
9770 *
9771 * PARAMETER(S):
9772 * [I] infoPtr : valid pointer to the listview structure
9773 *
9774 * RETURN:
9775 * Success: 0
9776 * Failure: -1
9777 */
9779{
9780 HTHEME theme = GetWindowTheme(infoPtr->hwndSelf);
9781 CloseThemeData(theme);
9782
9783 /* delete all items */
9784 LISTVIEW_DeleteAllItems(infoPtr, TRUE);
9785
9786 return 0;
9787}
9788
9789/***
9790 * DESCRIPTION:
9791 * Enables the listview control.
9792 *
9793 * PARAMETER(S):
9794 * [I] infoPtr : valid pointer to the listview structure
9795 * [I] bEnable : specifies whether to enable or disable the window
9796 *
9797 * RETURN:
9798 * SUCCESS : TRUE
9799 * FAILURE : FALSE
9800 */
9801static BOOL LISTVIEW_Enable(const LISTVIEW_INFO *infoPtr)
9802{
9803 if (infoPtr->dwStyle & LVS_OWNERDRAWFIXED)
9804 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
9805 return TRUE;
9806}
9807
9808/***
9809 * DESCRIPTION:
9810 * Erases the background of the listview control.
9811 *
9812 * PARAMETER(S):
9813 * [I] infoPtr : valid pointer to the listview structure
9814 * [I] hdc : device context handle
9815 *
9816 * RETURN:
9817 * SUCCESS : TRUE
9818 * FAILURE : FALSE
9819 */
9820static inline BOOL LISTVIEW_EraseBkgnd(const LISTVIEW_INFO *infoPtr, HDC hdc)
9821{
9822 RECT rc;
9823
9824 TRACE("(hdc=%p)\n", hdc);
9825
9826 if (!GetClipBox(hdc, &rc)) return FALSE;
9827
9828 if (infoPtr->clrBk == CLR_NONE)
9829 {
9830 if (infoPtr->dwLvExStyle & LVS_EX_TRANSPARENTBKGND)
9831 return SendMessageW(infoPtr->hwndNotify, WM_PRINTCLIENT,
9833 else
9834 return SendMessageW(infoPtr->hwndNotify, WM_ERASEBKGND, (WPARAM)hdc, 0);
9835 }
9836
9837 /* for double buffered controls we need to do this during refresh */
9838 if (infoPtr->dwLvExStyle & LVS_EX_DOUBLEBUFFER) return FALSE;
9839
9840 return LISTVIEW_FillBkgnd(infoPtr, hdc, &rc);
9841}
9842
9843
9844/***
9845 * DESCRIPTION:
9846 * Helper function for LISTVIEW_[HV]Scroll *only*.
9847 * Performs vertical/horizontal scrolling by a give amount.
9848 *
9849 * PARAMETER(S):
9850 * [I] infoPtr : valid pointer to the listview structure
9851 * [I] dx : amount of horizontal scroll
9852 * [I] dy : amount of vertical scroll
9853 */
9854static void scroll_list(LISTVIEW_INFO *infoPtr, INT dx, INT dy)
9855{
9856 /* now we can scroll the list */
9857 ScrollWindowEx(infoPtr->hwndSelf, dx, dy, &infoPtr->rcList,
9858 &infoPtr->rcList, 0, 0, SW_ERASE | SW_INVALIDATE);
9859 /* if we have focus, adjust rect */
9860 OffsetRect(&infoPtr->rcFocus, dx, dy);
9861 UpdateWindow(infoPtr->hwndSelf);
9862}
9863
9864/***
9865 * DESCRIPTION:
9866 * Performs vertical scrolling.
9867 *
9868 * PARAMETER(S):
9869 * [I] infoPtr : valid pointer to the listview structure
9870 * [I] nScrollCode : scroll code
9871 * [I] nScrollDiff : units to scroll in SB_INTERNAL mode, 0 otherwise
9872 * [I] hScrollWnd : scrollbar control window handle
9873 *
9874 * RETURN:
9875 * Zero
9876 *
9877 * NOTES:
9878 * SB_LINEUP/SB_LINEDOWN:
9879 * for LVS_ICON, LVS_SMALLICON is 37 by experiment
9880 * for LVS_REPORT is 1 line
9881 * for LVS_LIST cannot occur
9882 *
9883 */
9884static LRESULT LISTVIEW_VScroll(LISTVIEW_INFO *infoPtr, INT nScrollCode,
9885 INT nScrollDiff)
9886{
9887 INT nOldScrollPos, nNewScrollPos;
9888 SCROLLINFO scrollInfo;
9889 BOOL is_an_icon;
9890
9891 TRACE("(nScrollCode=%d(%s), nScrollDiff=%d)\n", nScrollCode,
9892 debugscrollcode(nScrollCode), nScrollDiff);
9893
9894 if (infoPtr->hwndEdit) SendMessageW(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
9895
9896 scrollInfo.cbSize = sizeof(SCROLLINFO);
9897 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS;
9898
9899 is_an_icon = ((infoPtr->uView == LV_VIEW_ICON) || (infoPtr->uView == LV_VIEW_SMALLICON));
9900
9901 if (!GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo)) return 1;
9902
9903 nOldScrollPos = scrollInfo.nPos;
9904 switch (nScrollCode)
9905 {
9906 case SB_INTERNAL:
9907 break;
9908
9909 case SB_LINEUP:
9910 nScrollDiff = (is_an_icon) ? -LISTVIEW_SCROLL_ICON_LINE_SIZE : -1;
9911 break;
9912
9913 case SB_LINEDOWN:
9914 nScrollDiff = (is_an_icon) ? LISTVIEW_SCROLL_ICON_LINE_SIZE : 1;
9915 break;
9916
9917 case SB_PAGEUP:
9918 nScrollDiff = -scrollInfo.nPage;
9919 break;
9920
9921 case SB_PAGEDOWN:
9922 nScrollDiff = scrollInfo.nPage;
9923 break;
9924
9925 case SB_THUMBPOSITION:
9926 case SB_THUMBTRACK:
9927 nScrollDiff = scrollInfo.nTrackPos - scrollInfo.nPos;
9928 break;
9929
9930 default:
9931 nScrollDiff = 0;
9932 }
9933
9934 /* quit right away if pos isn't changing */
9935 if (nScrollDiff == 0) return 0;
9936
9937 /* calculate new position, and handle overflows */
9938 nNewScrollPos = scrollInfo.nPos + nScrollDiff;
9939 if (nScrollDiff > 0) {
9940 if (nNewScrollPos < nOldScrollPos ||
9941 nNewScrollPos > scrollInfo.nMax)
9942 nNewScrollPos = scrollInfo.nMax;
9943 } else {
9944 if (nNewScrollPos > nOldScrollPos ||
9945 nNewScrollPos < scrollInfo.nMin)
9946 nNewScrollPos = scrollInfo.nMin;
9947 }
9948
9949 /* set the new position, and reread in case it changed */
9950 scrollInfo.fMask = SIF_POS;
9951 scrollInfo.nPos = nNewScrollPos;
9952 nNewScrollPos = SetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo, TRUE);
9953
9954 /* carry on only if it really changed */
9955 if (nNewScrollPos == nOldScrollPos) return 0;
9956
9957 /* now adjust to client coordinates */
9958 nScrollDiff = nOldScrollPos - nNewScrollPos;
9959 if (infoPtr->uView == LV_VIEW_DETAILS) nScrollDiff *= infoPtr->nItemHeight;
9960
9961 /* and scroll the window */
9962 scroll_list(infoPtr, 0, nScrollDiff);
9963
9964 return 0;
9965}
9966
9967/***
9968 * DESCRIPTION:
9969 * Performs horizontal scrolling.
9970 *
9971 * PARAMETER(S):
9972 * [I] infoPtr : valid pointer to the listview structure
9973 * [I] nScrollCode : scroll code
9974 * [I] nScrollDiff : units to scroll in SB_INTERNAL mode, 0 otherwise
9975 * [I] hScrollWnd : scrollbar control window handle
9976 *
9977 * RETURN:
9978 * Zero
9979 *
9980 * NOTES:
9981 * SB_LINELEFT/SB_LINERIGHT:
9982 * for LVS_ICON, LVS_SMALLICON 1 pixel
9983 * for LVS_REPORT is 1 pixel
9984 * for LVS_LIST is 1 column --> which is a 1 because the
9985 * scroll is based on columns not pixels
9986 *
9987 */
9988static LRESULT LISTVIEW_HScroll(LISTVIEW_INFO *infoPtr, INT nScrollCode,
9989 INT nScrollDiff)
9990{
9991 INT nOldScrollPos, nNewScrollPos;
9992 SCROLLINFO scrollInfo;
9993 BOOL is_an_icon;
9994
9995 TRACE("(nScrollCode=%d(%s), nScrollDiff=%d)\n", nScrollCode,
9996 debugscrollcode(nScrollCode), nScrollDiff);
9997
9998 if (infoPtr->hwndEdit) SendMessageW(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
9999
10000 scrollInfo.cbSize = sizeof(SCROLLINFO);
10001 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS;
10002
10003 is_an_icon = ((infoPtr->uView == LV_VIEW_ICON) || (infoPtr->uView == LV_VIEW_SMALLICON));
10004
10005 if (!GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo)) return 1;
10006
10007 nOldScrollPos = scrollInfo.nPos;
10008
10009 switch (nScrollCode)
10010 {
10011 case SB_INTERNAL:
10012 break;
10013
10014 case SB_LINELEFT:
10015 nScrollDiff = (is_an_icon) ? -LISTVIEW_SCROLL_ICON_LINE_SIZE : -1;
10016 break;
10017
10018 case SB_LINERIGHT:
10019 nScrollDiff = (is_an_icon) ? LISTVIEW_SCROLL_ICON_LINE_SIZE : 1;
10020 break;
10021
10022 case SB_PAGELEFT:
10023 nScrollDiff = -scrollInfo.nPage;
10024 break;
10025
10026 case SB_PAGERIGHT:
10027 nScrollDiff = scrollInfo.nPage;
10028 break;
10029
10030 case SB_THUMBPOSITION:
10031 case SB_THUMBTRACK:
10032 nScrollDiff = scrollInfo.nTrackPos - scrollInfo.nPos;
10033 break;
10034
10035 default:
10036 nScrollDiff = 0;
10037 }
10038
10039 /* quit right away if pos isn't changing */
10040 if (nScrollDiff == 0) return 0;
10041
10042 /* calculate new position, and handle overflows */
10043 nNewScrollPos = scrollInfo.nPos + nScrollDiff;
10044 if (nScrollDiff > 0) {
10045 if (nNewScrollPos < nOldScrollPos ||
10046 nNewScrollPos > scrollInfo.nMax)
10047 nNewScrollPos = scrollInfo.nMax;
10048 } else {
10049 if (nNewScrollPos > nOldScrollPos ||
10050 nNewScrollPos < scrollInfo.nMin)
10051 nNewScrollPos = scrollInfo.nMin;
10052 }
10053
10054 /* set the new position, and reread in case it changed */
10055 scrollInfo.fMask = SIF_POS;
10056 scrollInfo.nPos = nNewScrollPos;
10057 nNewScrollPos = SetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo, TRUE);
10058
10059 /* carry on only if it really changed */
10060 if (nNewScrollPos == nOldScrollPos) return 0;
10061
10062 LISTVIEW_UpdateHeaderSize(infoPtr, nNewScrollPos);
10063
10064 /* now adjust to client coordinates */
10065 nScrollDiff = nOldScrollPos - nNewScrollPos;
10066 if (infoPtr->uView == LV_VIEW_LIST) nScrollDiff *= infoPtr->nItemWidth;
10067
10068 /* and scroll the window */
10069 scroll_list(infoPtr, nScrollDiff, 0);
10070
10071 return 0;
10072}
10073
10074static LRESULT LISTVIEW_MouseWheel(LISTVIEW_INFO *infoPtr, INT wheelDelta)
10075{
10076 INT pulScrollLines = 3;
10077
10078 TRACE("(wheelDelta=%d)\n", wheelDelta);
10079
10080 switch(infoPtr->uView)
10081 {
10082 case LV_VIEW_ICON:
10083 case LV_VIEW_SMALLICON:
10084 /*
10085 * listview should be scrolled by a multiple of 37 dependently on its dimension or its visible item number
10086 * should be fixed in the future.
10087 */
10088 LISTVIEW_VScroll(infoPtr, SB_INTERNAL, (wheelDelta > 0) ?
10090 break;
10091
10092 case LV_VIEW_DETAILS:
10093 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
10094
10095 /* if scrolling changes direction, ignore left overs */
10096 if ((wheelDelta < 0 && infoPtr->cWheelRemainder < 0) ||
10097 (wheelDelta > 0 && infoPtr->cWheelRemainder > 0))
10098 infoPtr->cWheelRemainder += wheelDelta;
10099 else
10100 infoPtr->cWheelRemainder = wheelDelta;
10101 if (infoPtr->cWheelRemainder && pulScrollLines)
10102 {
10103 int cLineScroll;
10104 pulScrollLines = min((UINT)LISTVIEW_GetCountPerColumn(infoPtr), pulScrollLines);
10105 cLineScroll = pulScrollLines * infoPtr->cWheelRemainder / WHEEL_DELTA;
10106 infoPtr->cWheelRemainder -= WHEEL_DELTA * cLineScroll / pulScrollLines;
10107 LISTVIEW_VScroll(infoPtr, SB_INTERNAL, -cLineScroll);
10108 }
10109 break;
10110
10111 case LV_VIEW_LIST:
10112 LISTVIEW_HScroll(infoPtr, (wheelDelta > 0) ? SB_LINELEFT : SB_LINERIGHT, 0);
10113 break;
10114 }
10115 return 0;
10116}
10117
10118/***
10119 * DESCRIPTION:
10120 * ???
10121 *
10122 * PARAMETER(S):
10123 * [I] infoPtr : valid pointer to the listview structure
10124 * [I] nVirtualKey : virtual key
10125 * [I] lKeyData : key data
10126 *
10127 * RETURN:
10128 * Zero
10129 */
10130static LRESULT LISTVIEW_KeyDown(LISTVIEW_INFO *infoPtr, INT nVirtualKey, LONG lKeyData)
10131{
10132 HWND hwndSelf = infoPtr->hwndSelf;
10133 INT nItem = -1;
10134 NMLVKEYDOWN nmKeyDown;
10135
10136 TRACE("(nVirtualKey=%d, lKeyData=%d)\n", nVirtualKey, lKeyData);
10137
10138 /* send LVN_KEYDOWN notification */
10139 nmKeyDown.wVKey = nVirtualKey;
10140 nmKeyDown.flags = 0;
10141 notify_hdr(infoPtr, LVN_KEYDOWN, &nmKeyDown.hdr);
10142 if (!IsWindow(hwndSelf))
10143 return 0;
10144
10145 switch (nVirtualKey)
10146 {
10147 case VK_SPACE:
10148 nItem = infoPtr->nFocusedItem;
10149 if (infoPtr->dwLvExStyle & LVS_EX_CHECKBOXES)
10150 toggle_checkbox_state(infoPtr, infoPtr->nFocusedItem);
10151 break;
10152
10153 case VK_RETURN:
10154 if ((infoPtr->nItemCount > 0) && (infoPtr->nFocusedItem != -1))
10155 {
10156 if (!notify(infoPtr, NM_RETURN)) return 0;
10157 if (!notify(infoPtr, LVN_ITEMACTIVATE)) return 0;
10158 }
10159 break;
10160
10161 case VK_HOME:
10162 if (infoPtr->nItemCount > 0)
10163 nItem = 0;
10164 break;
10165
10166 case VK_END:
10167 if (infoPtr->nItemCount > 0)
10168 nItem = infoPtr->nItemCount - 1;
10169 break;
10170
10171 case VK_LEFT:
10172 nItem = LISTVIEW_GetNextItem(infoPtr, infoPtr->nFocusedItem, LVNI_TOLEFT);
10173 break;
10174
10175 case VK_UP:
10176 nItem = LISTVIEW_GetNextItem(infoPtr, infoPtr->nFocusedItem, LVNI_ABOVE);
10177 break;
10178
10179 case VK_RIGHT:
10180 nItem = LISTVIEW_GetNextItem(infoPtr, infoPtr->nFocusedItem, LVNI_TORIGHT);
10181 break;
10182
10183 case VK_DOWN:
10184 nItem = LISTVIEW_GetNextItem(infoPtr, infoPtr->nFocusedItem, LVNI_BELOW);
10185 break;
10186
10187 case VK_PRIOR:
10188 if (infoPtr->uView == LV_VIEW_DETAILS)
10189 {
10190 INT topidx = LISTVIEW_GetTopIndex(infoPtr);
10191 if (infoPtr->nFocusedItem == topidx)
10192 nItem = topidx - LISTVIEW_GetCountPerColumn(infoPtr) + 1;
10193 else
10194 nItem = topidx;
10195 }
10196 else
10197 nItem = infoPtr->nFocusedItem - LISTVIEW_GetCountPerColumn(infoPtr)
10198 * LISTVIEW_GetCountPerRow(infoPtr);
10199 if(nItem < 0) nItem = 0;
10200 break;
10201
10202 case VK_NEXT:
10203 if (infoPtr->uView == LV_VIEW_DETAILS)
10204 {
10205 INT topidx = LISTVIEW_GetTopIndex(infoPtr);
10207 if (infoPtr->nFocusedItem == topidx + cnt - 1)
10208 nItem = infoPtr->nFocusedItem + cnt - 1;
10209 else
10210 nItem = topidx + cnt - 1;
10211 }
10212 else
10213 nItem = infoPtr->nFocusedItem + LISTVIEW_GetCountPerColumn(infoPtr)
10214 * LISTVIEW_GetCountPerRow(infoPtr);
10215 if(nItem >= infoPtr->nItemCount) nItem = infoPtr->nItemCount - 1;
10216 break;
10217 }
10218
10219 if ((nItem != -1) && (nItem != infoPtr->nFocusedItem || nVirtualKey == VK_SPACE))
10220 {
10221 DWORD keys = 0;
10222
10223 if (GetKeyState(VK_SHIFT) & 0x8000)
10224 keys |= SHIFT_KEY;
10225 if (GetKeyState(VK_CONTROL) & 0x8000)
10226 keys |= CTRL_KEY;
10227 if (nVirtualKey == VK_SPACE)
10228 keys |= SPACE_KEY;
10229
10230 LISTVIEW_KeySelection(infoPtr, nItem, keys);
10231 }
10232
10233 return 0;
10234}
10235
10236/***
10237 * DESCRIPTION:
10238 * Kills the focus.
10239 *
10240 * PARAMETER(S):
10241 * [I] infoPtr : valid pointer to the listview structure
10242 *
10243 * RETURN:
10244 * Zero
10245 */
10247{
10248 TRACE("()\n");
10249
10250 /* drop any left over scroll amount */
10251 infoPtr->cWheelRemainder = 0;
10252
10253 /* if we did not have the focus, there's nothing more to do */
10254 if (!infoPtr->bFocus) return 0;
10255
10256 /* send NM_KILLFOCUS notification */
10257 if (!notify(infoPtr, NM_KILLFOCUS)) return 0;
10258
10259 /* if we have a focus rectangle, get rid of it */
10260 LISTVIEW_ShowFocusRect(infoPtr, FALSE);
10261
10262 /* if have a marquee selection, stop it */
10263 if (infoPtr->bMarqueeSelect)
10264 {
10265 /* Remove the marquee rectangle and release our mouse capture */
10266 LISTVIEW_InvalidateRect(infoPtr, &infoPtr->marqueeRect);
10268
10269 SetRectEmpty(&infoPtr->marqueeRect);
10270
10271 infoPtr->bMarqueeSelect = FALSE;
10272 infoPtr->bScrolling = FALSE;
10273 KillTimer(infoPtr->hwndSelf, (UINT_PTR) infoPtr);
10274 }
10275
10276 /* set window focus flag */
10277 infoPtr->bFocus = FALSE;
10278
10279 /* invalidate the selected items before resetting focus flag */
10281
10282 return 0;
10283}
10284
10285/***
10286 * DESCRIPTION:
10287 * Processes double click messages (left mouse button).
10288 *
10289 * PARAMETER(S):
10290 * [I] infoPtr : valid pointer to the listview structure
10291 * [I] wKey : key flag
10292 * [I] x,y : mouse coordinate
10293 *
10294 * RETURN:
10295 * Zero
10296 */
10298{
10299 LVHITTESTINFO htInfo;
10300
10301 TRACE("(key=%hu, X=%u, Y=%u)\n", wKey, x, y);
10302
10303 /* Cancel the item edition if any */
10304 if (infoPtr->itemEdit.fEnabled)
10305 {
10306 KillTimer(infoPtr->hwndSelf, (UINT_PTR)&infoPtr->itemEdit);
10307 infoPtr->itemEdit.fEnabled = FALSE;
10308 }
10309
10310 /* send NM_RELEASEDCAPTURE notification */
10311 if (!notify(infoPtr, NM_RELEASEDCAPTURE)) return 0;
10312
10313 htInfo.pt.x = x;
10314 htInfo.pt.y = y;
10315
10316 /* send NM_DBLCLK notification */
10317 LISTVIEW_HitTest(infoPtr, &htInfo, TRUE, FALSE);
10318 if (!notify_click(infoPtr, NM_DBLCLK, &htInfo)) return 0;
10319
10320 /* To send the LVN_ITEMACTIVATE, it must be on an Item */
10321 if(htInfo.iItem != -1) notify_itemactivate(infoPtr,&htInfo);
10322
10323 return 0;
10324}
10325
10327{
10328 MSG msg;
10329 RECT r;
10330
10331 r.top = r.bottom = pt.y;
10332 r.left = r.right = pt.x;
10333
10335
10336 SetCapture(infoPtr->hwndSelf);
10337
10338 while (1)
10339 {
10340 if (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD))
10341 {
10342 if (msg.message == WM_MOUSEMOVE)
10343 {
10344 pt.x = (short)LOWORD(msg.lParam);
10345 pt.y = (short)HIWORD(msg.lParam);
10346 if (PtInRect(&r, pt))
10347 continue;
10348 else
10349 {
10351 return 1;
10352 }
10353 }
10354 else if (msg.message >= WM_LBUTTONDOWN &&
10355 msg.message <= WM_RBUTTONDBLCLK)
10356 {
10357 break;
10358 }
10359
10361 }
10362
10363 if (GetCapture() != infoPtr->hwndSelf)
10364 return 0;
10365 }
10366
10368 return 0;
10369}
10370
10371
10372/***
10373 * DESCRIPTION:
10374 * Processes mouse down messages (left mouse button).
10375 *
10376 * PARAMETERS:
10377 * infoPtr [I ] valid pointer to the listview structure
10378 * wKey [I ] key flag
10379 * x,y [I ] mouse coordinate
10380 *
10381 * RETURN:
10382 * Zero
10383 */
10385{
10386 LVHITTESTINFO lvHitTestInfo;
10387 static BOOL bGroupSelect = TRUE;
10388 POINT pt = { x, y };
10389 INT nItem;
10390
10391 TRACE("(key=%hu, X=%u, Y=%u)\n", wKey, x, y);
10392
10393 /* send NM_RELEASEDCAPTURE notification */
10394 if (!notify(infoPtr, NM_RELEASEDCAPTURE)) return 0;
10395
10396 /* set left button down flag and record the click position */
10397 infoPtr->bLButtonDown = TRUE;
10398 infoPtr->ptClickPos = pt;
10399 infoPtr->bDragging = FALSE;
10400 infoPtr->bMarqueeSelect = FALSE;
10401 infoPtr->bScrolling = FALSE;
10402
10403 lvHitTestInfo.pt.x = x;
10404 lvHitTestInfo.pt.y = y;
10405
10406 nItem = LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE);
10407 TRACE("at %s, nItem=%d\n", wine_dbgstr_point(&pt), nItem);
10408 if ((nItem >= 0) && (nItem < infoPtr->nItemCount))
10409 {
10410 if ((infoPtr->dwLvExStyle & LVS_EX_CHECKBOXES) && (lvHitTestInfo.flags & LVHT_ONITEMSTATEICON))
10411 {
10412 notify_click(infoPtr, NM_CLICK, &lvHitTestInfo);
10413 toggle_checkbox_state(infoPtr, nItem);
10414 infoPtr->bLButtonDown = FALSE;
10415 return 0;
10416 }
10417
10418 if (infoPtr->dwStyle & LVS_SINGLESEL)
10419 {
10420 if (LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED))
10421 infoPtr->nEditLabelItem = nItem;
10422 else
10423 LISTVIEW_SetSelection(infoPtr, nItem);
10424 }
10425 else
10426 {
10427 if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
10428 {
10429 if (bGroupSelect)
10430 {
10431 if (!LISTVIEW_AddGroupSelection(infoPtr, nItem)) return 0;
10432 LISTVIEW_SetItemFocus(infoPtr, nItem);
10433 infoPtr->nSelectionMark = nItem;
10434 }
10435 else
10436 {
10437 LVITEMW item;
10438
10440 item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
10441
10442 LISTVIEW_SetItemState(infoPtr,nItem,&item);
10443 infoPtr->nSelectionMark = nItem;
10444 }
10445 }
10446 else if (wKey & MK_CONTROL)
10447 {
10448 LVITEMW item;
10449
10450 bGroupSelect = (LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED) == 0);
10451
10452 item.state = (bGroupSelect ? LVIS_SELECTED : 0) | LVIS_FOCUSED;
10453 item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
10454 LISTVIEW_SetItemState(infoPtr, nItem, &item);
10455 infoPtr->nSelectionMark = nItem;
10456 }
10457 else if (wKey & MK_SHIFT)
10458 {
10459 LISTVIEW_SetGroupSelection(infoPtr, nItem);
10460 }
10461 else
10462 {
10463 if (LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED))
10464 {
10465 infoPtr->nEditLabelItem = nItem;
10466 infoPtr->nLButtonDownItem = nItem;
10467
10468 LISTVIEW_SetItemFocus(infoPtr, nItem);
10469 }
10470 else
10471 /* set selection (clears other pre-existing selections) */
10472 LISTVIEW_SetSelection(infoPtr, nItem);
10473 }
10474 }
10475
10476 if (!infoPtr->bFocus)
10477 SetFocus(infoPtr->hwndSelf);
10478
10479 if (infoPtr->dwLvExStyle & LVS_EX_ONECLICKACTIVATE)
10480 if(lvHitTestInfo.iItem != -1) notify_itemactivate(infoPtr,&lvHitTestInfo);
10481 }
10482 else
10483 {
10484 if (!infoPtr->bFocus)
10485 SetFocus(infoPtr->hwndSelf);
10486
10487 /* remove all selections */
10488 if (!(wKey & MK_CONTROL) && !(wKey & MK_SHIFT))
10489 LISTVIEW_DeselectAll(infoPtr);
10491 }
10492
10493 return 0;
10494}
10495
10496/***
10497 * DESCRIPTION:
10498 * Processes mouse up messages (left mouse button).
10499 *
10500 * PARAMETERS:
10501 * infoPtr [I ] valid pointer to the listview structure
10502 * wKey [I ] key flag
10503 * x,y [I ] mouse coordinate
10504 *
10505 * RETURN:
10506 * Zero
10507 */
10509{
10510 LVHITTESTINFO lvHitTestInfo;
10511
10512 TRACE("(key=%hu, X=%u, Y=%u)\n", wKey, x, y);
10513
10514 if (!infoPtr->bLButtonDown) return 0;
10515
10516 lvHitTestInfo.pt.x = x;
10517 lvHitTestInfo.pt.y = y;
10518
10519 /* send NM_CLICK notification */
10520 LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, FALSE);
10521 if (!notify_click(infoPtr, NM_CLICK, &lvHitTestInfo)) return 0;
10522
10523 /* set left button flag */
10524 infoPtr->bLButtonDown = FALSE;
10525
10526 /* set a single selection, reset others */
10527 if(lvHitTestInfo.iItem == infoPtr->nLButtonDownItem && lvHitTestInfo.iItem != -1)
10528 LISTVIEW_SetSelection(infoPtr, infoPtr->nLButtonDownItem);
10529 infoPtr->nLButtonDownItem = -1;
10530
10531 if (infoPtr->bDragging || infoPtr->bMarqueeSelect)
10532 {
10533 /* Remove the marquee rectangle and release our mouse capture */
10534 if (infoPtr->bMarqueeSelect)
10535 {
10536 LISTVIEW_InvalidateRect(infoPtr, &infoPtr->marqueeDrawRect);
10538 }
10539
10540 SetRectEmpty(&infoPtr->marqueeRect);
10541 SetRectEmpty(&infoPtr->marqueeDrawRect);
10542
10543 infoPtr->bDragging = FALSE;
10544 infoPtr->bMarqueeSelect = FALSE;
10545 infoPtr->bScrolling = FALSE;
10546
10547 KillTimer(infoPtr->hwndSelf, (UINT_PTR) infoPtr);
10548 return 0;
10549 }
10550
10551 /* if we clicked on a selected item, edit the label */
10552 if(lvHitTestInfo.iItem == infoPtr->nEditLabelItem && (lvHitTestInfo.flags & LVHT_ONITEMLABEL))
10553 {
10554 /* we want to make sure the user doesn't want to do a double click. So we will
10555 * delay the edit. WM_LBUTTONDBLCLICK will cancel the timer
10556 */
10557 infoPtr->itemEdit.fEnabled = TRUE;
10558 infoPtr->itemEdit.iItem = lvHitTestInfo.iItem;
10559 SetTimer(infoPtr->hwndSelf,
10560 (UINT_PTR)&infoPtr->itemEdit,
10563 }
10564
10565 return 0;
10566}
10567
10568/***
10569 * DESCRIPTION:
10570 * Destroys the listview control (called after WM_DESTROY).
10571 *
10572 * PARAMETER(S):
10573 * [I] infoPtr : valid pointer to the listview structure
10574 *
10575 * RETURN:
10576 * Zero
10577 */
10579{
10580 INT i;
10581
10582 TRACE("()\n");
10583
10584 /* destroy data structure */
10585 DPA_Destroy(infoPtr->hdpaItems);
10586 DPA_Destroy(infoPtr->hdpaItemIds);
10587 DPA_Destroy(infoPtr->hdpaPosX);
10588 DPA_Destroy(infoPtr->hdpaPosY);
10589 /* columns */
10590 for (i = 0; i < DPA_GetPtrCount(infoPtr->hdpaColumns); i++)
10591 Free(DPA_GetPtr(infoPtr->hdpaColumns, i));
10592 DPA_Destroy(infoPtr->hdpaColumns);
10594#ifdef __REACTOS__
10595 infoPtr->selectionRanges = NULL; /* See note in ranges_clone */
10596#endif
10597
10598 /* destroy image lists */
10599 if (!(infoPtr->dwStyle & LVS_SHAREIMAGELISTS))
10600 {
10601 ImageList_Destroy(infoPtr->himlNormal);
10602 ImageList_Destroy(infoPtr->himlSmall);
10603 ImageList_Destroy(infoPtr->himlState);
10604 }
10605
10606 /* destroy font, bkgnd brush */
10607 infoPtr->hFont = 0;
10608 if (infoPtr->hDefaultFont) DeleteObject(infoPtr->hDefaultFont);
10609 if (infoPtr->clrBk != CLR_NONE) DeleteObject(infoPtr->hBkBrush);
10610
10611 SetWindowLongPtrW(infoPtr->hwndSelf, 0, 0);
10612
10613 /* free listview info pointer*/
10614 Free(infoPtr);
10615
10616 return 0;
10617}
10618
10619/***
10620 * DESCRIPTION:
10621 * Handles notifications.
10622 *
10623 * PARAMETER(S):
10624 * [I] infoPtr : valid pointer to the listview structure
10625 * [I] lpnmhdr : notification information
10626 *
10627 * RETURN:
10628 * Zero
10629 */
10630static LRESULT LISTVIEW_Notify(LISTVIEW_INFO *infoPtr, NMHDR *lpnmhdr)
10631{
10632 NMHEADERW *lpnmh;
10633
10634 TRACE("(lpnmhdr=%p)\n", lpnmhdr);
10635
10636 if (!lpnmhdr || lpnmhdr->hwndFrom != infoPtr->hwndHeader) return 0;
10637
10638 /* remember: HDN_LAST < HDN_FIRST */
10639 if (lpnmhdr->code > HDN_FIRST || lpnmhdr->code < HDN_LAST) return 0;
10640 lpnmh = (NMHEADERW *)lpnmhdr;
10641
10642 if (lpnmh->iItem < 0 || lpnmh->iItem >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return 0;
10643
10644 switch (lpnmhdr->code)
10645 {
10646 case HDN_TRACKW:
10647 case HDN_TRACKA:
10648 {
10649 COLUMN_INFO *lpColumnInfo;
10650 POINT ptOrigin;
10651 INT x;
10652
10653 if (!lpnmh->pitem || !(lpnmh->pitem->mask & HDI_WIDTH))
10654 break;
10655
10656 /* remove the old line (if any) */
10657 LISTVIEW_DrawTrackLine(infoPtr);
10658
10659 /* compute & draw the new line */
10660 lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, lpnmh->iItem);
10661 x = lpColumnInfo->rcHeader.left + lpnmh->pitem->cxy;
10662 LISTVIEW_GetOrigin(infoPtr, &ptOrigin);
10663 infoPtr->xTrackLine = x + ptOrigin.x;
10664 LISTVIEW_DrawTrackLine(infoPtr);
10665 return notify_forward_header(infoPtr, lpnmh);
10666 }
10667
10668 case HDN_ENDTRACKA:
10669 case HDN_ENDTRACKW:
10670 /* remove the track line (if any) */
10671 LISTVIEW_DrawTrackLine(infoPtr);
10672 infoPtr->xTrackLine = -1;
10673 return notify_forward_header(infoPtr, lpnmh);
10674
10675 case HDN_BEGINDRAG:
10676 if ((infoPtr->dwLvExStyle & LVS_EX_HEADERDRAGDROP) == 0) return 1;
10677 return notify_forward_header(infoPtr, lpnmh);
10678
10679 case HDN_ENDDRAG:
10680 infoPtr->colRectsDirty = TRUE;
10681 LISTVIEW_InvalidateList(infoPtr);
10682 return notify_forward_header(infoPtr, lpnmh);
10683
10684 case HDN_ITEMCHANGEDW:
10685 case HDN_ITEMCHANGEDA:
10686 {
10687 COLUMN_INFO *lpColumnInfo;
10688 HDITEMW hdi;
10689 INT dx, cxy;
10690
10691 if (!lpnmh->pitem || !(lpnmh->pitem->mask & HDI_WIDTH))
10692 {
10693 hdi.mask = HDI_WIDTH;
10694 if (!SendMessageW(infoPtr->hwndHeader, HDM_GETITEMW, lpnmh->iItem, (LPARAM)&hdi)) return 0;
10695 cxy = hdi.cxy;
10696 }
10697 else
10698 cxy = lpnmh->pitem->cxy;
10699
10700 /* determine how much we change since the last know position */
10701 lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, lpnmh->iItem);
10702 dx = cxy - (lpColumnInfo->rcHeader.right - lpColumnInfo->rcHeader.left);
10703 if (dx != 0)
10704 {
10705 lpColumnInfo->rcHeader.right += dx;
10706
10707 hdi.mask = HDI_ORDER;
10708 SendMessageW(infoPtr->hwndHeader, HDM_GETITEMW, lpnmh->iItem, (LPARAM)&hdi);
10709
10710 /* not the rightmost one */
10711 if (hdi.iOrder + 1 < DPA_GetPtrCount(infoPtr->hdpaColumns))
10712 {
10713 INT nIndex = SendMessageW(infoPtr->hwndHeader, HDM_ORDERTOINDEX,
10714 hdi.iOrder + 1, 0);
10715 LISTVIEW_ScrollColumns(infoPtr, nIndex, dx);
10716 }
10717 else
10718 {
10719 /* only needs to update the scrolls */
10720 infoPtr->nItemWidth += dx;
10721 LISTVIEW_UpdateScroll(infoPtr);
10722 }
10723 LISTVIEW_UpdateItemSize(infoPtr);
10724 if (infoPtr->uView == LV_VIEW_DETAILS && is_redrawing(infoPtr))
10725 {
10726 POINT ptOrigin;
10727 RECT rcCol = lpColumnInfo->rcHeader;
10728
10729 LISTVIEW_GetOrigin(infoPtr, &ptOrigin);
10730 OffsetRect(&rcCol, ptOrigin.x, 0);
10731
10732 rcCol.top = infoPtr->rcList.top;
10733 rcCol.bottom = infoPtr->rcList.bottom;
10734
10735 /* resizing left-aligned columns leaves most of the left side untouched */
10736 if ((lpColumnInfo->fmt & LVCFMT_JUSTIFYMASK) == LVCFMT_LEFT)
10737 {
10738 INT nMaxDirty = infoPtr->nEllipsisWidth + infoPtr->ntmMaxCharWidth;
10739 if (dx > 0)
10740 nMaxDirty += dx;
10741 rcCol.left = max (rcCol.left, rcCol.right - nMaxDirty);
10742 }
10743
10744 /* when shrinking the last column clear the now unused field */
10745 if (hdi.iOrder == DPA_GetPtrCount(infoPtr->hdpaColumns) - 1)
10746 {
10747 RECT right;
10748
10749 rcCol.right -= dx;
10750
10751 /* deal with right from rightmost column area */
10752 right.left = rcCol.right;
10753 right.top = rcCol.top;
10754 right.bottom = rcCol.bottom;
10755 right.right = infoPtr->rcList.right;
10756
10757 LISTVIEW_InvalidateRect(infoPtr, &right);
10758 }
10759
10760 LISTVIEW_InvalidateRect(infoPtr, &rcCol);
10761 }
10762 }
10763 break;
10764 }
10765
10766 case HDN_ITEMCLICKW:
10767 case HDN_ITEMCLICKA:
10768 {
10769 /* Handle sorting by Header Column */
10770 NMLISTVIEW nmlv;
10771
10772 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
10773 nmlv.iItem = -1;
10774 nmlv.iSubItem = lpnmh->iItem;
10775 notify_listview(infoPtr, LVN_COLUMNCLICK, &nmlv);
10776 return notify_forward_header(infoPtr, lpnmh);
10777 }
10778
10781 /* FIXME: for LVS_EX_HEADERINALLVIEWS and not LV_VIEW_DETAILS
10782 we should use LVSCW_AUTOSIZE_USEHEADER, helper rework or
10783 split needed for that */
10785 return notify_forward_header(infoPtr, lpnmh);
10786 }
10787 return 0;
10788}
10789
10790/***
10791 * DESCRIPTION:
10792 * Paint non-client area of control.
10793 *
10794 * PARAMETER(S):
10795 * [I] infoPtr : valid pointer to the listview structureof the sender
10796 * [I] region : update region
10797 *
10798 * RETURN:
10799 * TRUE - frame was painted
10800 * FALSE - call default window proc
10801 */
10802static BOOL LISTVIEW_NCPaint(const LISTVIEW_INFO *infoPtr, HRGN region)
10803{
10804 HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
10805 HDC dc;
10806 RECT r;
10807 HRGN cliprgn;
10808 int cxEdge = GetSystemMetrics (SM_CXEDGE),
10809 cyEdge = GetSystemMetrics (SM_CYEDGE);
10810
10811 if (!theme)
10812 return DefWindowProcW (infoPtr->hwndSelf, WM_NCPAINT, (WPARAM)region, 0);
10813
10814 GetWindowRect(infoPtr->hwndSelf, &r);
10815
10816 cliprgn = CreateRectRgn (r.left + cxEdge, r.top + cyEdge,
10817 r.right - cxEdge, r.bottom - cyEdge);
10818 if (region != (HRGN)1)
10819 CombineRgn (cliprgn, cliprgn, region, RGN_AND);
10820 OffsetRect(&r, -r.left, -r.top);
10821
10822#ifdef __REACTOS__ /* r73789 */
10823 dc = GetWindowDC(infoPtr->hwndSelf);
10824 /* Exclude client part */
10825 ExcludeClipRect(dc, r.left + cxEdge, r.top + cyEdge,
10826 r.right - cxEdge, r.bottom -cyEdge);
10827#else
10828 dc = GetDCEx(infoPtr->hwndSelf, region, DCX_WINDOW|DCX_INTERSECTRGN);
10829 OffsetRect(&r, -r.left, -r.top);
10830#endif
10831
10832 if (IsThemeBackgroundPartiallyTransparent (theme, 0, 0))
10834 DrawThemeBackground (theme, dc, 0, 0, &r, 0);
10835 ReleaseDC(infoPtr->hwndSelf, dc);
10836
10837 /* Call default proc to get the scrollbars etc. painted */
10838 DefWindowProcW (infoPtr->hwndSelf, WM_NCPAINT, (WPARAM)cliprgn, 0);
10839 DeleteObject(cliprgn);
10840
10841 return FALSE;
10842}
10843
10844/***
10845 * DESCRIPTION:
10846 * Determines the type of structure to use.
10847 *
10848 * PARAMETER(S):
10849 * [I] infoPtr : valid pointer to the listview structureof the sender
10850 * [I] hwndFrom : listview window handle
10851 * [I] nCommand : command specifying the nature of the WM_NOTIFYFORMAT
10852 *
10853 * RETURN:
10854 * Zero
10855 */
10856static LRESULT LISTVIEW_NotifyFormat(LISTVIEW_INFO *infoPtr, HWND hwndFrom, INT nCommand)
10857{
10858 TRACE("(hwndFrom=%p, nCommand=%d)\n", hwndFrom, nCommand);
10859
10860 if (nCommand == NF_REQUERY)
10861 infoPtr->notifyFormat = SendMessageW(infoPtr->hwndNotify, WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY);
10862
10863 return infoPtr->notifyFormat;
10864}
10865
10866/***
10867 * DESCRIPTION:
10868 * Paints/Repaints the listview control. Internal use.
10869 *
10870 * PARAMETER(S):
10871 * [I] infoPtr : valid pointer to the listview structure
10872 * [I] hdc : device context handle
10873 *
10874 * RETURN:
10875 * Zero
10876 */
10878{
10879 TRACE("(hdc=%p)\n", hdc);
10880
10881 if (infoPtr->bNoItemMetrics && infoPtr->nItemCount)
10882 {
10883 infoPtr->bNoItemMetrics = FALSE;
10884 LISTVIEW_UpdateItemSize(infoPtr);
10885 if (infoPtr->uView == LV_VIEW_ICON || infoPtr->uView == LV_VIEW_SMALLICON)
10886 LISTVIEW_Arrange(infoPtr, LVA_DEFAULT);
10887 LISTVIEW_UpdateScroll(infoPtr);
10888 }
10889
10890 if (infoPtr->hwndHeader) UpdateWindow(infoPtr->hwndHeader);
10891
10892 if (hdc)
10893 LISTVIEW_Refresh(infoPtr, hdc, NULL);
10894 else
10895 {
10896 PAINTSTRUCT ps;
10897
10898 hdc = BeginPaint(infoPtr->hwndSelf, &ps);
10899 if (!hdc) return 1;
10900 LISTVIEW_Refresh(infoPtr, hdc, ps.fErase ? &ps.rcPaint : NULL);
10901 EndPaint(infoPtr->hwndSelf, &ps);
10902 }
10903
10904 return 0;
10905}
10906
10907/***
10908 * DESCRIPTION:
10909 * Paints/Repaints the listview control, WM_PAINT handler.
10910 *
10911 * PARAMETER(S):
10912 * [I] infoPtr : valid pointer to the listview structure
10913 * [I] hdc : device context handle
10914 *
10915 * RETURN:
10916 * Zero
10917 */
10919{
10920 TRACE("(hdc=%p)\n", hdc);
10921
10922 if (!is_redrawing(infoPtr))
10923 return DefWindowProcW (infoPtr->hwndSelf, WM_PAINT, (WPARAM)hdc, 0);
10924
10925 return LISTVIEW_Paint(infoPtr, hdc);
10926}
10927
10928/***
10929 * DESCRIPTION:
10930 * Paints/Repaints the listview control.
10931 *
10932 * PARAMETER(S):
10933 * [I] infoPtr : valid pointer to the listview structure
10934 * [I] hdc : device context handle
10935 * [I] options : drawing options
10936 *
10937 * RETURN:
10938 * Zero
10939 */
10941{
10942 if ((options & PRF_CHECKVISIBLE) && !IsWindowVisible(infoPtr->hwndSelf))
10943 return 0;
10944
10946 FIXME("(hdc=%p options=0x%08x) partial stub\n", hdc, options);
10947
10948 if (options & PRF_ERASEBKGND)
10949 LISTVIEW_EraseBkgnd(infoPtr, hdc);
10950
10951 if (options & PRF_CLIENT)
10952 LISTVIEW_Paint(infoPtr, hdc);
10953
10954 return 0;
10955}
10956
10957
10958/***
10959 * DESCRIPTION:
10960 * Processes double click messages (right mouse button).
10961 *
10962 * PARAMETER(S):
10963 * [I] infoPtr : valid pointer to the listview structure
10964 * [I] wKey : key flag
10965 * [I] x,y : mouse coordinate
10966 *
10967 * RETURN:
10968 * Zero
10969 */
10971{
10972 LVHITTESTINFO lvHitTestInfo;
10973
10974 TRACE("(key=%hu,X=%u,Y=%u)\n", wKey, x, y);
10975
10976 /* send NM_RELEASEDCAPTURE notification */
10977 if (!notify(infoPtr, NM_RELEASEDCAPTURE)) return 0;
10978
10979 /* send NM_RDBLCLK notification */
10980 lvHitTestInfo.pt.x = x;
10981 lvHitTestInfo.pt.y = y;
10982 LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, FALSE);
10983 notify_click(infoPtr, NM_RDBLCLK, &lvHitTestInfo);
10984
10985 return 0;
10986}
10987
10988/***
10989 * DESCRIPTION:
10990 * Processes WM_RBUTTONDOWN message and corresponding drag operation.
10991 *
10992 * PARAMETER(S):
10993 * [I] infoPtr : valid pointer to the listview structure
10994 * [I] wKey : key flag
10995 * [I] x, y : mouse coordinate
10996 *
10997 * RETURN:
10998 * Zero
10999 */
11001{
11003 INT item;
11004
11005 TRACE("(key=%hu, x=%d, y=%d)\n", wKey, x, y);
11006
11007 /* send NM_RELEASEDCAPTURE notification */
11008 if (!notify(infoPtr, NM_RELEASEDCAPTURE)) return 0;
11009
11010 /* determine the index of the selected item */
11011 ht.pt.x = x;
11012 ht.pt.y = y;
11013 item = LISTVIEW_HitTest(infoPtr, &ht, TRUE, TRUE);
11014
11015 /* make sure the listview control window has the focus */
11016 if (!infoPtr->bFocus) SetFocus(infoPtr->hwndSelf);
11017
11018 if ((item >= 0) && (item < infoPtr->nItemCount))
11019 {
11020 LISTVIEW_SetItemFocus(infoPtr, item);
11021 if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)) &&
11023 LISTVIEW_SetSelection(infoPtr, item);
11024 }
11025 else
11026 LISTVIEW_DeselectAll(infoPtr);
11027
11028 if (LISTVIEW_TrackMouse(infoPtr, ht.pt))
11029 {
11030 if (ht.iItem != -1)
11031 {
11032 NMLISTVIEW nmlv;
11033
11034 memset(&nmlv, 0, sizeof(nmlv));
11035 nmlv.iItem = ht.iItem;
11036 nmlv.ptAction = ht.pt;
11037
11038 notify_listview(infoPtr, LVN_BEGINRDRAG, &nmlv);
11039 }
11040 }
11041 else
11042 {
11043 SetFocus(infoPtr->hwndSelf);
11044
11045 ht.pt.x = x;
11046 ht.pt.y = y;
11047 LISTVIEW_HitTest(infoPtr, &ht, TRUE, FALSE);
11048
11049 if (notify_click(infoPtr, NM_RCLICK, &ht))
11050 {
11051 /* Send a WM_CONTEXTMENU message in response to the WM_RBUTTONUP */
11053 (WPARAM)infoPtr->hwndSelf, (LPARAM)GetMessagePos());
11054 }
11055 }
11056
11057 return 0;
11058}
11059
11060/***
11061 * DESCRIPTION:
11062 * Sets the cursor.
11063 *
11064 * PARAMETER(S):
11065 * [I] infoPtr : valid pointer to the listview structure
11066 * [I] hwnd : window handle of window containing the cursor
11067 * [I] nHittest : hit-test code
11068 * [I] wMouseMsg : ideintifier of the mouse message
11069 *
11070 * RETURN:
11071 * TRUE if cursor is set
11072 * FALSE otherwise
11073 */
11075{
11076 LVHITTESTINFO lvHitTestInfo;
11077
11078 if (!LISTVIEW_IsHotTracking(infoPtr)) goto forward;
11079
11080 if (!infoPtr->hHotCursor) goto forward;
11081
11082 GetCursorPos(&lvHitTestInfo.pt);
11083 if (LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, FALSE, FALSE) < 0) goto forward;
11084
11085 SetCursor(infoPtr->hHotCursor);
11086
11087 return TRUE;
11088
11089forward:
11090
11091 return DefWindowProcW(infoPtr->hwndSelf, WM_SETCURSOR, wParam, lParam);
11092}
11093
11094/***
11095 * DESCRIPTION:
11096 * Sets the focus.
11097 *
11098 * PARAMETER(S):
11099 * [I] infoPtr : valid pointer to the listview structure
11100 * [I] hwndLoseFocus : handle of previously focused window
11101 *
11102 * RETURN:
11103 * Zero
11104 */
11105static LRESULT LISTVIEW_SetFocus(LISTVIEW_INFO *infoPtr, HWND hwndLoseFocus)
11106{
11107 TRACE("(hwndLoseFocus=%p)\n", hwndLoseFocus);
11108
11109 /* if we have the focus already, there's nothing to do */
11110 if (infoPtr->bFocus) return 0;
11111
11112 /* send NM_SETFOCUS notification */
11113 if (!notify(infoPtr, NM_SETFOCUS)) return 0;
11114
11115 /* set window focus flag */
11116 infoPtr->bFocus = TRUE;
11117
11118 /* put the focus rect back on */
11119 LISTVIEW_ShowFocusRect(infoPtr, TRUE);
11120
11121 /* redraw all visible selected items */
11123
11124 return 0;
11125}
11126
11127/***
11128 * DESCRIPTION:
11129 * Sets the font.
11130 *
11131 * PARAMETER(S):
11132 * [I] infoPtr : valid pointer to the listview structure
11133 * [I] fRedraw : font handle
11134 * [I] fRedraw : redraw flag
11135 *
11136 * RETURN:
11137 * Zero
11138 */
11140{
11141 HFONT oldFont = infoPtr->hFont;
11142 INT oldHeight = infoPtr->nItemHeight;
11143
11144 TRACE("(hfont=%p,redraw=%hu)\n", hFont, fRedraw);
11145
11146 infoPtr->hFont = hFont ? hFont : infoPtr->hDefaultFont;
11147 if (infoPtr->hFont == oldFont) return 0;
11148
11149 LISTVIEW_SaveTextMetrics(infoPtr);
11150
11151 infoPtr->nItemHeight = LISTVIEW_CalculateItemHeight(infoPtr);
11152
11153 if (infoPtr->uView == LV_VIEW_DETAILS)
11154 {
11155 SendMessageW(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(fRedraw, 0));
11156 LISTVIEW_UpdateSize(infoPtr);
11157 LISTVIEW_UpdateScroll(infoPtr);
11158 }
11159 else if (infoPtr->nItemHeight != oldHeight)
11160 LISTVIEW_UpdateScroll(infoPtr);
11161
11162 if (fRedraw) LISTVIEW_InvalidateList(infoPtr);
11163
11164 return 0;
11165}
11166
11167/***
11168 * DESCRIPTION:
11169 * Message handling for WM_SETREDRAW.
11170 * For the Listview, it invalidates the entire window (the doc specifies otherwise)
11171 *
11172 * PARAMETER(S):
11173 * [I] infoPtr : valid pointer to the listview structure
11174 * [I] redraw: state of redraw flag
11175 *
11176 * RETURN:
11177 * Zero.
11178 */
11180{
11181 TRACE("old=%d, new=%d\n", infoPtr->redraw, redraw);
11182
11183 if (infoPtr->redraw == !!redraw)
11184 return 0;
11185
11186 if (!(infoPtr->redraw = !!redraw))
11187 return 0;
11188
11189 if (is_autoarrange(infoPtr))
11190 LISTVIEW_Arrange(infoPtr, LVA_DEFAULT);
11191 LISTVIEW_UpdateScroll(infoPtr);
11192
11193 /* despite what the WM_SETREDRAW docs says, apps expect us
11194 * to invalidate the listview here... stupid! */
11195 LISTVIEW_InvalidateList(infoPtr);
11196
11197 return 0;
11198}
11199
11200/***
11201 * DESCRIPTION:
11202 * Resizes the listview control. This function processes WM_SIZE
11203 * messages. At this time, the width and height are not used.
11204 *
11205 * PARAMETER(S):
11206 * [I] infoPtr : valid pointer to the listview structure
11207 * [I] Width : new width
11208 * [I] Height : new height
11209 *
11210 * RETURN:
11211 * Zero
11212 */
11214{
11215 RECT rcOld = infoPtr->rcList;
11216
11217 TRACE("(width=%d, height=%d)\n", Width, Height);
11218
11219 LISTVIEW_UpdateSize(infoPtr);
11220 if (EqualRect(&rcOld, &infoPtr->rcList)) return 0;
11221
11222 /* do not bother with display related stuff if we're not redrawing */
11223 if (!is_redrawing(infoPtr)) return 0;
11224
11225 if (is_autoarrange(infoPtr))
11226 LISTVIEW_Arrange(infoPtr, LVA_DEFAULT);
11227
11228 LISTVIEW_UpdateScroll(infoPtr);
11229
11230 /* refresh all only for lists whose height changed significantly */
11231 if ((infoPtr->uView == LV_VIEW_LIST) &&
11232 (rcOld.bottom - rcOld.top) / infoPtr->nItemHeight !=
11233 (infoPtr->rcList.bottom - infoPtr->rcList.top) / infoPtr->nItemHeight)
11234 LISTVIEW_InvalidateList(infoPtr);
11235
11236 return 0;
11237}
11238
11239/***
11240 * DESCRIPTION:
11241 * Sets the size information.
11242 *
11243 * PARAMETER(S):
11244 * [I] infoPtr : valid pointer to the listview structure
11245 *
11246 * RETURN:
11247 * None
11248 */
11250{
11251 TRACE("uView=%d, rcList(old)=%s\n", infoPtr->uView, wine_dbgstr_rect(&infoPtr->rcList));
11252
11253 GetClientRect(infoPtr->hwndSelf, &infoPtr->rcList);
11254
11255 if (infoPtr->uView == LV_VIEW_LIST)
11256 {
11257 /* Apparently the "LIST" style is supposed to have the same
11258 * number of items in a column even if there is no scroll bar.
11259 * Since if a scroll bar already exists then the bottom is already
11260 * reduced, only reduce if the scroll bar does not currently exist.
11261 * The "2" is there to mimic the native control. I think it may be
11262 * related to either padding or edges. (GLA 7/2002)
11263 */
11264 if (!(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & WS_HSCROLL))
11266 infoPtr->rcList.bottom = max (infoPtr->rcList.bottom - 2, 0);
11267 }
11268
11269 /* When ListView control is created invisible, header isn't created right away. */
11270 if (infoPtr->hwndHeader)
11271 {
11272 POINT origin;
11273 WINDOWPOS wp;
11274 HDLAYOUT hl;
11275 RECT rect;
11276
11277 LISTVIEW_GetOrigin(infoPtr, &origin);
11278
11279 rect = infoPtr->rcList;
11280 rect.left += origin.x;
11281
11282 hl.prc = &rect;
11283 hl.pwpos = &wp;
11284 SendMessageW( infoPtr->hwndHeader, HDM_LAYOUT, 0, (LPARAM)&hl );
11285 TRACE(" wp.flags=0x%08x, wp=%d,%d (%dx%d)\n", wp.flags, wp.x, wp.y, wp.cx, wp.cy);
11286
11287 if (LISTVIEW_IsHeaderEnabled(infoPtr))
11288 wp.flags |= SWP_SHOWWINDOW;
11289 else
11290 {
11291 wp.flags |= SWP_HIDEWINDOW;
11292 wp.cy = 0;
11293 }
11294
11295 SetWindowPos(wp.hwnd, wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
11296 TRACE(" after SWP wp=%d,%d (%dx%d)\n", wp.x, wp.y, wp.cx, wp.cy);
11297
11298 infoPtr->rcList.top = max(wp.cy, 0);
11299 }
11300 /* extra padding for grid */
11301 if (infoPtr->uView == LV_VIEW_DETAILS && infoPtr->dwLvExStyle & LVS_EX_GRIDLINES)
11302 infoPtr->rcList.top += 2;
11303
11304 TRACE(" rcList=%s\n", wine_dbgstr_rect(&infoPtr->rcList));
11305}
11306
11307/***
11308 * DESCRIPTION:
11309 * Processes WM_STYLECHANGED messages.
11310 *
11311 * PARAMETER(S):
11312 * [I] infoPtr : valid pointer to the listview structure
11313 * [I] wStyleType : window style type (normal or extended)
11314 * [I] lpss : window style information
11315 *
11316 * RETURN:
11317 * Zero
11318 */
11319static INT LISTVIEW_StyleChanged(LISTVIEW_INFO *infoPtr, WPARAM wStyleType,
11320 const STYLESTRUCT *lpss)
11321{
11322 UINT uNewView, uOldView;
11323 UINT style;
11324
11325 TRACE("(styletype=%lx, styleOld=0x%08x, styleNew=0x%08x)\n",
11326 wStyleType, lpss->styleOld, lpss->styleNew);
11327
11328 if (wStyleType != GWL_STYLE || lpss->styleNew == infoPtr->dwStyle) return 0;
11329
11330 infoPtr->dwStyle = lpss->styleNew;
11331
11332 if (((lpss->styleOld & WS_HSCROLL) != 0)&&
11333 ((lpss->styleNew & WS_HSCROLL) == 0))
11334 ShowScrollBar(infoPtr->hwndSelf, SB_HORZ, FALSE);
11335
11336 if (((lpss->styleOld & WS_VSCROLL) != 0)&&
11337 ((lpss->styleNew & WS_VSCROLL) == 0))
11338 ShowScrollBar(infoPtr->hwndSelf, SB_VERT, FALSE);
11339
11340 uNewView = lpss->styleNew & LVS_TYPEMASK;
11341 uOldView = lpss->styleOld & LVS_TYPEMASK;
11342
11343 if (uNewView != uOldView)
11344 {
11346
11347 /* LVM_SETVIEW doesn't change window style bits within LVS_TYPEMASK,
11348 changing style updates current view only when view bits change. */
11349 map_style_view(infoPtr);
11350 SendMessageW(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
11351 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
11352
11353 ShowScrollBar(infoPtr->hwndSelf, SB_BOTH, FALSE);
11354 SetRectEmpty(&infoPtr->rcFocus);
11355
11356 himl = (uNewView == LVS_ICON ? infoPtr->himlNormal : infoPtr->himlSmall);
11357 set_icon_size(&infoPtr->iconSize, himl, uNewView != LVS_ICON);
11358
11359 if (uNewView == LVS_REPORT)
11360 {
11361 HDLAYOUT hl;
11362 WINDOWPOS wp;
11363
11364 LISTVIEW_CreateHeader( infoPtr );
11365
11366 hl.prc = &infoPtr->rcList;
11367 hl.pwpos = &wp;
11368 SendMessageW( infoPtr->hwndHeader, HDM_LAYOUT, 0, (LPARAM)&hl );
11369 SetWindowPos(infoPtr->hwndHeader, infoPtr->hwndSelf, wp.x, wp.y, wp.cx, wp.cy,
11370 wp.flags | ((infoPtr->dwStyle & LVS_NOCOLUMNHEADER)
11372 }
11373
11374 LISTVIEW_UpdateItemSize(infoPtr);
11375 }
11376
11377 if (uNewView == LVS_REPORT || infoPtr->dwLvExStyle & LVS_EX_HEADERINALLVIEWS)
11378 {
11379 if ((lpss->styleOld ^ lpss->styleNew) & LVS_NOCOLUMNHEADER)
11380 {
11381 if (lpss->styleNew & LVS_NOCOLUMNHEADER)
11382 {
11383 /* Turn off the header control */
11385 TRACE("Hide header control, was 0x%08x\n", style);
11387 } else {
11388 /* Turn on the header control */
11389 if ((style = GetWindowLongW(infoPtr->hwndHeader, GWL_STYLE)) & HDS_HIDDEN)
11390 {
11391 TRACE("Show header control, was 0x%08x\n", style);
11393 }
11394 }
11395 }
11396 }
11397
11398 if ( (uNewView == LVS_ICON || uNewView == LVS_SMALLICON) &&
11399 (uNewView != uOldView || ((lpss->styleNew ^ lpss->styleOld) & LVS_ALIGNMASK)) )
11400 LISTVIEW_Arrange(infoPtr, LVA_DEFAULT);
11401
11402 /* update the size of the client area */
11403 LISTVIEW_UpdateSize(infoPtr);
11404
11405 /* add scrollbars if needed */
11406 LISTVIEW_UpdateScroll(infoPtr);
11407
11408 /* invalidate client area + erase background */
11409 LISTVIEW_InvalidateList(infoPtr);
11410
11411 return 0;
11412}
11413
11414/***
11415 * DESCRIPTION:
11416 * Processes WM_STYLECHANGING messages.
11417 *
11418 * PARAMETER(S):
11419 * [I] wStyleType : window style type (normal or extended)
11420 * [I0] lpss : window style information
11421 *
11422 * RETURN:
11423 * Zero
11424 */
11426 STYLESTRUCT *lpss)
11427{
11428 TRACE("(styletype=%lx, styleOld=0x%08x, styleNew=0x%08x)\n",
11429 wStyleType, lpss->styleOld, lpss->styleNew);
11430
11431 /* don't forward LVS_OWNERDATA only if not already set to */
11432 if ((lpss->styleNew ^ lpss->styleOld) & LVS_OWNERDATA)
11433 {
11434 if (lpss->styleOld & LVS_OWNERDATA)
11435 lpss->styleNew |= LVS_OWNERDATA;
11436 else
11437 lpss->styleNew &= ~LVS_OWNERDATA;
11438 }
11439
11440 return 0;
11441}
11442
11443/***
11444 * DESCRIPTION:
11445 * Processes WM_SHOWWINDOW messages.
11446 *
11447 * PARAMETER(S):
11448 * [I] infoPtr : valid pointer to the listview structure
11449 * [I] bShown : window is being shown (FALSE when hidden)
11450 * [I] iStatus : window show status
11451 *
11452 * RETURN:
11453 * Zero
11454 */
11455static LRESULT LISTVIEW_ShowWindow(LISTVIEW_INFO *infoPtr, WPARAM bShown, LPARAM iStatus)
11456{
11457 /* header delayed creation */
11458 if ((infoPtr->uView == LV_VIEW_DETAILS) && bShown)
11459 {
11460 LISTVIEW_CreateHeader(infoPtr);
11461
11462 if (!(LVS_NOCOLUMNHEADER & infoPtr->dwStyle))
11464 }
11465
11466 return DefWindowProcW(infoPtr->hwndSelf, WM_SHOWWINDOW, bShown, iStatus);
11467}
11468
11469/***
11470 * DESCRIPTION:
11471 * Processes CCM_GETVERSION messages.
11472 *
11473 * PARAMETER(S):
11474 * [I] infoPtr : valid pointer to the listview structure
11475 *
11476 * RETURN:
11477 * Current version
11478 */
11479static inline LRESULT LISTVIEW_GetVersion(const LISTVIEW_INFO *infoPtr)
11480{
11481 return infoPtr->iVersion;
11482}
11483
11484/***
11485 * DESCRIPTION:
11486 * Processes CCM_SETVERSION messages.
11487 *
11488 * PARAMETER(S):
11489 * [I] infoPtr : valid pointer to the listview structure
11490 * [I] iVersion : version to be set
11491 *
11492 * RETURN:
11493 * -1 when requested version is greater than DLL version;
11494 * previous version otherwise
11495 */
11497{
11498 INT iOldVersion = infoPtr->iVersion;
11499
11500 if (iVersion > COMCTL32_VERSION)
11501 return -1;
11502
11503 infoPtr->iVersion = iVersion;
11504
11505 TRACE("new version %d\n", iVersion);
11506
11507 return iOldVersion;
11508}
11509
11510/***
11511 * DESCRIPTION:
11512 * Window procedure of the listview control.
11513 *
11514 */
11515static LRESULT WINAPI
11517{
11519
11520 TRACE("(hwnd=%p uMsg=%x wParam=%lx lParam=%lx)\n", hwnd, uMsg, wParam, lParam);
11521
11522 if (!infoPtr && (uMsg != WM_NCCREATE))
11523 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
11524
11525 switch (uMsg)
11526 {
11528 return LISTVIEW_ApproximateViewRect(infoPtr, (INT)wParam,
11530 case LVM_ARRANGE:
11531 return LISTVIEW_Arrange(infoPtr, (INT)wParam);
11532
11534 return LISTVIEW_CancelEditLabel(infoPtr);
11535
11538
11539 case LVM_DELETEALLITEMS:
11540 return LISTVIEW_DeleteAllItems(infoPtr, FALSE);
11541
11542 case LVM_DELETECOLUMN:
11543 return LISTVIEW_DeleteColumn(infoPtr, (INT)wParam);
11544
11545 case LVM_DELETEITEM:
11546 return LISTVIEW_DeleteItem(infoPtr, (INT)wParam);
11547
11548 case LVM_EDITLABELA:
11549 case LVM_EDITLABELW:
11550 return (LRESULT)LISTVIEW_EditLabelT(infoPtr, (INT)wParam,
11551 uMsg == LVM_EDITLABELW);
11552 /* case LVM_ENABLEGROUPVIEW: */
11553
11554 case LVM_ENSUREVISIBLE:
11555 return LISTVIEW_EnsureVisible(infoPtr, (INT)wParam, (BOOL)lParam);
11556
11557 case LVM_FINDITEMW:
11558 return LISTVIEW_FindItemW(infoPtr, (INT)wParam, (LPLVFINDINFOW)lParam);
11559
11560 case LVM_FINDITEMA:
11561 return LISTVIEW_FindItemA(infoPtr, (INT)wParam, (LPLVFINDINFOA)lParam);
11562
11563 case LVM_GETBKCOLOR:
11564 return infoPtr->clrBk;
11565
11566 /* case LVM_GETBKIMAGE: */
11567
11569 return infoPtr->uCallbackMask;
11570
11571 case LVM_GETCOLUMNA:
11572 case LVM_GETCOLUMNW:
11573 return LISTVIEW_GetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam,
11574 uMsg == LVM_GETCOLUMNW);
11575
11578
11579 case LVM_GETCOLUMNWIDTH:
11580 return LISTVIEW_GetColumnWidth(infoPtr, (INT)wParam);
11581
11583 return LISTVIEW_GetCountPerPage(infoPtr);
11584
11585 case LVM_GETEDITCONTROL:
11586 return (LRESULT)infoPtr->hwndEdit;
11587
11589 return infoPtr->dwLvExStyle;
11590
11591 /* case LVM_GETGROUPINFO: */
11592
11593 /* case LVM_GETGROUPMETRICS: */
11594
11595 case LVM_GETHEADER:
11596 return (LRESULT)infoPtr->hwndHeader;
11597
11598 case LVM_GETHOTCURSOR:
11599 return (LRESULT)infoPtr->hHotCursor;
11600
11601 case LVM_GETHOTITEM:
11602 return infoPtr->nHotItem;
11603
11604 case LVM_GETHOVERTIME:
11605 return infoPtr->dwHoverTime;
11606
11607 case LVM_GETIMAGELIST:
11608 return (LRESULT)LISTVIEW_GetImageList(infoPtr, (INT)wParam);
11609
11610 /* case LVM_GETINSERTMARK: */
11611
11612 /* case LVM_GETINSERTMARKCOLOR: */
11613
11614 /* case LVM_GETINSERTMARKRECT: */
11615
11618 FIXME("LVM_GETISEARCHSTRING: unimplemented\n");
11619 return FALSE;
11620
11621 case LVM_GETITEMA:
11622 case LVM_GETITEMW:
11623 return LISTVIEW_GetItemExtT(infoPtr, (LPLVITEMW)lParam, uMsg == LVM_GETITEMW);
11624
11625 case LVM_GETITEMCOUNT:
11626 return infoPtr->nItemCount;
11627
11629 return LISTVIEW_GetItemPosition(infoPtr, (INT)wParam, (LPPOINT)lParam);
11630
11631 case LVM_GETITEMRECT:
11632 return LISTVIEW_GetItemRect(infoPtr, (INT)wParam, (LPRECT)lParam);
11633
11634 case LVM_GETITEMSPACING:
11635 return LISTVIEW_GetItemSpacing(infoPtr, (BOOL)wParam);
11636
11637 case LVM_GETITEMSTATE:
11638 return LISTVIEW_GetItemState(infoPtr, (INT)wParam, (UINT)lParam);
11639
11640 case LVM_GETITEMTEXTA:
11641 case LVM_GETITEMTEXTW:
11642 return LISTVIEW_GetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam,
11643 uMsg == LVM_GETITEMTEXTW);
11644
11645 case LVM_GETNEXTITEM:
11646 return LISTVIEW_GetNextItem(infoPtr, (INT)wParam, LOWORD(lParam));
11647
11649 FIXME("LVM_GETNUMBEROFWORKAREAS: unimplemented\n");
11650 return 1;
11651
11652 case LVM_GETORIGIN:
11653 if (!lParam) return FALSE;
11654 if (infoPtr->uView == LV_VIEW_DETAILS ||
11655 infoPtr->uView == LV_VIEW_LIST) return FALSE;
11657 return TRUE;
11658
11659 /* case LVM_GETOUTLINECOLOR: */
11660
11661 /* case LVM_GETSELECTEDCOLUMN: */
11662
11664 return LISTVIEW_GetSelectedCount(infoPtr);
11665
11667 return infoPtr->nSelectionMark;
11668
11671 return LISTVIEW_GetStringWidthT(infoPtr, (LPCWSTR)lParam,
11672 uMsg == LVM_GETSTRINGWIDTHW);
11673
11674 case LVM_GETSUBITEMRECT:
11675 return LISTVIEW_GetSubItemRect(infoPtr, (UINT)wParam, (LPRECT)lParam);
11676
11677 case LVM_GETTEXTBKCOLOR:
11678 return infoPtr->clrTextBk;
11679
11680 case LVM_GETTEXTCOLOR:
11681 return infoPtr->clrText;
11682
11683 /* case LVM_GETTILEINFO: */
11684
11685 /* case LVM_GETTILEVIEWINFO: */
11686
11687 case LVM_GETTOOLTIPS:
11688 if( !infoPtr->hwndToolTip )
11690 return (LRESULT)infoPtr->hwndToolTip;
11691
11692 case LVM_GETTOPINDEX:
11693 return LISTVIEW_GetTopIndex(infoPtr);
11694
11696 return (infoPtr->notifyFormat == NFR_UNICODE);
11697
11698 case LVM_GETVIEW:
11699 return infoPtr->uView;
11700
11701 case LVM_GETVIEWRECT:
11702 return LISTVIEW_GetViewRect(infoPtr, (LPRECT)lParam);
11703
11704 case LVM_GETWORKAREAS:
11705 FIXME("LVM_GETWORKAREAS: unimplemented\n");
11706 return FALSE;
11707
11708 /* case LVM_HASGROUP: */
11709
11710 case LVM_HITTEST:
11711 return LISTVIEW_HitTest(infoPtr, (LPLVHITTESTINFO)lParam, FALSE, TRUE);
11712
11713 case LVM_INSERTCOLUMNA:
11714 case LVM_INSERTCOLUMNW:
11716 uMsg == LVM_INSERTCOLUMNW);
11717
11718 /* case LVM_INSERTGROUP: */
11719
11720 /* case LVM_INSERTGROUPSORTED: */
11721
11722 case LVM_INSERTITEMA:
11723 case LVM_INSERTITEMW:
11724 return LISTVIEW_InsertItemT(infoPtr, (LPLVITEMW)lParam, uMsg == LVM_INSERTITEMW);
11725
11726 /* case LVM_INSERTMARKHITTEST: */
11727
11728 /* case LVM_ISGROUPVIEWENABLED: */
11729
11730 case LVM_ISITEMVISIBLE:
11731 return LISTVIEW_IsItemVisible(infoPtr, (INT)wParam);
11732
11733 case LVM_MAPIDTOINDEX:
11734 return LISTVIEW_MapIdToIndex(infoPtr, (UINT)wParam);
11735
11736 case LVM_MAPINDEXTOID:
11737 return LISTVIEW_MapIndexToId(infoPtr, (INT)wParam);
11738
11739 /* case LVM_MOVEGROUP: */
11740
11741 /* case LVM_MOVEITEMTOGROUP: */
11742
11743 case LVM_REDRAWITEMS:
11744 return LISTVIEW_RedrawItems(infoPtr, (INT)wParam, (INT)lParam);
11745
11746 /* case LVM_REMOVEALLGROUPS: */
11747
11748 /* case LVM_REMOVEGROUP: */
11749
11750 case LVM_SCROLL:
11751 return LISTVIEW_Scroll(infoPtr, (INT)wParam, (INT)lParam);
11752
11753 case LVM_SETBKCOLOR:
11754 return LISTVIEW_SetBkColor(infoPtr, (COLORREF)lParam);
11755
11756 /* case LVM_SETBKIMAGE: */
11757
11759 infoPtr->uCallbackMask = (UINT)wParam;
11760 return TRUE;
11761
11762 case LVM_SETCOLUMNA:
11763 case LVM_SETCOLUMNW:
11764 return LISTVIEW_SetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam,
11765 uMsg == LVM_SETCOLUMNW);
11766
11769
11770 case LVM_SETCOLUMNWIDTH:
11771 return LISTVIEW_SetColumnWidth(infoPtr, (INT)wParam, (short)LOWORD(lParam));
11772
11775
11776 /* case LVM_SETGROUPINFO: */
11777
11778 /* case LVM_SETGROUPMETRICS: */
11779
11780 case LVM_SETHOTCURSOR:
11781 return (LRESULT)LISTVIEW_SetHotCursor(infoPtr, (HCURSOR)lParam);
11782
11783 case LVM_SETHOTITEM:
11784 return LISTVIEW_SetHotItem(infoPtr, (INT)wParam);
11785
11786 case LVM_SETHOVERTIME:
11787 return LISTVIEW_SetHoverTime(infoPtr, (DWORD)lParam);
11788
11789 case LVM_SETICONSPACING:
11790 if(lParam == -1)
11791 return LISTVIEW_SetIconSpacing(infoPtr, -1, -1);
11793
11794 case LVM_SETIMAGELIST:
11796
11797 /* case LVM_SETINFOTIP: */
11798
11799 /* case LVM_SETINSERTMARK: */
11800
11801 /* case LVM_SETINSERTMARKCOLOR: */
11802
11803 case LVM_SETITEMA:
11804 case LVM_SETITEMW:
11805 {
11806 if (infoPtr->dwStyle & LVS_OWNERDATA) return FALSE;
11807 return LISTVIEW_SetItemT(infoPtr, (LPLVITEMW)lParam, (uMsg == LVM_SETITEMW));
11808 }
11809
11810 case LVM_SETITEMCOUNT:
11811 return LISTVIEW_SetItemCount(infoPtr, (INT)wParam, (DWORD)lParam);
11812
11814 {
11815 POINT pt;
11816 pt.x = (short)LOWORD(lParam);
11817 pt.y = (short)HIWORD(lParam);
11818 return LISTVIEW_SetItemPosition(infoPtr, (INT)wParam, &pt);
11819 }
11820
11822 return LISTVIEW_SetItemPosition(infoPtr, (INT)wParam, (POINT*)lParam);
11823
11824 case LVM_SETITEMSTATE:
11825 return LISTVIEW_SetItemState(infoPtr, (INT)wParam, (LPLVITEMW)lParam);
11826
11827 case LVM_SETITEMTEXTA:
11828 case LVM_SETITEMTEXTW:
11829 return LISTVIEW_SetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam,
11830 uMsg == LVM_SETITEMTEXTW);
11831
11832 /* case LVM_SETOUTLINECOLOR: */
11833
11834 /* case LVM_SETSELECTEDCOLUMN: */
11835
11837 return LISTVIEW_SetSelectionMark(infoPtr, (INT)lParam);
11838
11839 case LVM_SETTEXTBKCOLOR:
11840 return LISTVIEW_SetTextBkColor(infoPtr, (COLORREF)lParam);
11841
11842 case LVM_SETTEXTCOLOR:
11843 return LISTVIEW_SetTextColor(infoPtr, (COLORREF)lParam);
11844
11845 /* case LVM_SETTILEINFO: */
11846
11847 /* case LVM_SETTILEVIEWINFO: */
11848
11849 /* case LVM_SETTILEWIDTH: */
11850
11851 case LVM_SETTOOLTIPS:
11852 return (LRESULT)LISTVIEW_SetToolTips(infoPtr, (HWND)lParam);
11853
11855 return LISTVIEW_SetUnicodeFormat(infoPtr, wParam);
11856
11857 case LVM_SETVIEW:
11858 return LISTVIEW_SetView(infoPtr, wParam);
11859
11860 /* case LVM_SETWORKAREAS: */
11861
11862 /* case LVM_SORTGROUPS: */
11863
11864 case LVM_SORTITEMS:
11865 case LVM_SORTITEMSEX:
11866 return LISTVIEW_SortItems(infoPtr, (PFNLVCOMPARE)lParam, wParam,
11867 uMsg == LVM_SORTITEMSEX);
11868 case LVM_SUBITEMHITTEST:
11869 return LISTVIEW_HitTest(infoPtr, (LPLVHITTESTINFO)lParam, TRUE, FALSE);
11870
11871 case LVM_UPDATE:
11872 return LISTVIEW_Update(infoPtr, (INT)wParam);
11873
11874 case CCM_GETVERSION:
11875 return LISTVIEW_GetVersion(infoPtr);
11876
11877 case CCM_SETVERSION:
11878 return LISTVIEW_SetVersion(infoPtr, wParam);
11879
11880 case WM_CHAR:
11881 return LISTVIEW_ProcessLetterKeys( infoPtr, wParam, lParam );
11882
11883 case WM_COMMAND:
11884 return LISTVIEW_Command(infoPtr, wParam, lParam);
11885
11886 case WM_NCCREATE:
11888
11889 case WM_CREATE:
11891
11892 case WM_DESTROY:
11893 return LISTVIEW_Destroy(infoPtr);
11894
11895 case WM_ENABLE:
11896 return LISTVIEW_Enable(infoPtr);
11897
11898 case WM_ERASEBKGND:
11899 return LISTVIEW_EraseBkgnd(infoPtr, (HDC)wParam);
11900
11901 case WM_GETDLGCODE:
11903
11904 case WM_GETFONT:
11905 return (LRESULT)infoPtr->hFont;
11906
11907 case WM_HSCROLL:
11908 return LISTVIEW_HScroll(infoPtr, (INT)LOWORD(wParam), 0);
11909
11910 case WM_KEYDOWN:
11911 return LISTVIEW_KeyDown(infoPtr, (INT)wParam, (LONG)lParam);
11912
11913 case WM_KILLFOCUS:
11914 return LISTVIEW_KillFocus(infoPtr);
11915
11916 case WM_LBUTTONDBLCLK:
11918
11919 case WM_LBUTTONDOWN:
11921
11922 case WM_LBUTTONUP:
11924
11925 case WM_MOUSEMOVE:
11927
11928 case WM_MOUSEHOVER:
11930
11931 case WM_NCDESTROY:
11932 return LISTVIEW_NCDestroy(infoPtr);
11933
11934 case WM_NCPAINT:
11935 return LISTVIEW_NCPaint(infoPtr, (HRGN)wParam);
11936
11937 case WM_NOTIFY:
11938 return LISTVIEW_Notify(infoPtr, (LPNMHDR)lParam);
11939
11940 case WM_NOTIFYFORMAT:
11941 return LISTVIEW_NotifyFormat(infoPtr, (HWND)wParam, (INT)lParam);
11942
11943 case WM_PRINTCLIENT:
11944 return LISTVIEW_PrintClient(infoPtr, (HDC)wParam, (DWORD)lParam);
11945
11946 case WM_PAINT:
11947 return LISTVIEW_WMPaint(infoPtr, (HDC)wParam);
11948
11949 case WM_RBUTTONDBLCLK:
11951
11952 case WM_RBUTTONDOWN:
11954
11955 case WM_SETCURSOR:
11956 return LISTVIEW_SetCursor(infoPtr, wParam, lParam);
11957
11958 case WM_SETFOCUS:
11959 return LISTVIEW_SetFocus(infoPtr, (HWND)wParam);
11960
11961 case WM_SETFONT:
11962 return LISTVIEW_SetFont(infoPtr, (HFONT)wParam, (WORD)lParam);
11963
11964 case WM_SETREDRAW:
11965 return LISTVIEW_SetRedraw(infoPtr, (BOOL)wParam);
11966
11967 case WM_SHOWWINDOW:
11968 return LISTVIEW_ShowWindow(infoPtr, wParam, lParam);
11969
11970 case WM_STYLECHANGED:
11972
11973 case WM_STYLECHANGING:
11975
11976 case WM_SYSCOLORCHANGE:
11978#ifdef __REACTOS__
11979 if (infoPtr->bDefaultBkColor)
11980 {
11982 infoPtr->bDefaultBkColor = TRUE;
11983 LISTVIEW_InvalidateList(infoPtr);
11984 }
11985#endif
11986 return 0;
11987
11988/* case WM_TIMER: */
11989 case WM_THEMECHANGED:
11990 return LISTVIEW_ThemeChanged(infoPtr);
11991
11992 case WM_VSCROLL:
11993 return LISTVIEW_VScroll(infoPtr, (INT)LOWORD(wParam), 0);
11994
11995 case WM_MOUSEWHEEL:
11996 if (wParam & (MK_SHIFT | MK_CONTROL))
11997 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
11998 return LISTVIEW_MouseWheel(infoPtr, (short int)HIWORD(wParam));
11999
12001 if (!(((WINDOWPOS *)lParam)->flags & SWP_NOSIZE))
12002 {
12003 SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE |
12005
12006 if ((infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && (infoPtr->uView == LV_VIEW_DETAILS))
12007 {
12008 if (notify_measureitem(infoPtr)) LISTVIEW_InvalidateList(infoPtr);
12009 }
12010 LISTVIEW_Size(infoPtr, ((WINDOWPOS *)lParam)->cx, ((WINDOWPOS *)lParam)->cy);
12011 }
12012 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
12013
12014#ifdef __REACTOS__
12015 case WM_SETTINGCHANGE: /* Same as WM_WININICHANGE */
12016 if (wParam == SPI_SETICONMETRICS ||
12018 wParam == SPI_SETNONCLIENTMETRICS ||
12019 (!wParam && !lParam))
12020 {
12021 HFONT hOldDefaultFont = infoPtr->hDefaultFont;
12022 BOOL bDefaultOrNullFont = (infoPtr->hDefaultFont == infoPtr->hFont || !infoPtr->hFont);
12023 LOGFONTW logFont;
12025
12026 if (infoPtr->autoSpacing)
12027 LISTVIEW_SetIconSpacing(infoPtr, -1, -1);
12028
12029 if (infoPtr->hDefaultFont)
12030 DeleteObject(infoPtr->hDefaultFont);
12031 infoPtr->hDefaultFont = CreateFontIndirectW(&logFont);
12032
12033 if (bDefaultOrNullFont)
12034 {
12035 infoPtr->hFont = infoPtr->hDefaultFont;
12036 // Check if we just deleted the font the header is using
12037 if (infoPtr->hwndHeader && hOldDefaultFont == GetWindowFont(infoPtr->hwndHeader))
12038 SendMessageW(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont, TRUE);
12039 }
12040
12041 LISTVIEW_SaveTextMetrics(infoPtr);
12042 LISTVIEW_UpdateItemSize(infoPtr);
12043 LISTVIEW_UpdateScroll(infoPtr);
12044 LISTVIEW_InvalidateRect(infoPtr, NULL);
12045 }
12046 return 0;
12047#else
12048/* case WM_WININICHANGE: */
12049#endif
12050
12051 default:
12052 if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
12053 ERR("unknown msg %04x wp=%08lx lp=%08lx\n", uMsg, wParam, lParam);
12054
12055 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
12056 }
12057
12058}
12059
12060/***
12061 * DESCRIPTION:
12062 * Registers the window class.
12063 *
12064 * PARAMETER(S):
12065 * None
12066 *
12067 * RETURN:
12068 * None
12069 */
12071{
12072 WNDCLASSW wndClass;
12073
12074 ZeroMemory(&wndClass, sizeof(WNDCLASSW));
12075 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
12077 wndClass.cbClsExtra = 0;
12078 wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *);
12079 wndClass.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
12080 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
12081 wndClass.lpszClassName = WC_LISTVIEWW;
12082 RegisterClassW(&wndClass);
12083}
12084
12085/***
12086 * DESCRIPTION:
12087 * Unregisters the window class.
12088 *
12089 * PARAMETER(S):
12090 * None
12091 *
12092 * RETURN:
12093 * None
12094 */
12096{
12098}
12099
12100/***
12101 * DESCRIPTION:
12102 * Handle any WM_COMMAND messages
12103 *
12104 * PARAMETER(S):
12105 * [I] infoPtr : valid pointer to the listview structure
12106 * [I] wParam : the first message parameter
12107 * [I] lParam : the second message parameter
12108 *
12109 * RETURN:
12110 * Zero.
12111 */
12113{
12114
12115 TRACE("(%p %x %x %lx)\n", infoPtr, HIWORD(wParam), LOWORD(wParam), lParam);
12116
12117 if (!infoPtr->hwndEdit) return 0;
12118
12119 switch (HIWORD(wParam))
12120 {
12121 case EN_UPDATE:
12122 {
12123 /*
12124 * Adjust the edit window size
12125 */
12126 WCHAR buffer[1024];
12127 HDC hdc = GetDC(infoPtr->hwndEdit);
12128 HFONT hFont, hOldFont = 0;
12129 RECT rect;
12130 SIZE sz;
12131
12132 if (!infoPtr->hwndEdit || !hdc) return 0;
12134 GetWindowRect(infoPtr->hwndEdit, &rect);
12135
12136 /* Select font to get the right dimension of the string */
12137 hFont = (HFONT)SendMessageW(infoPtr->hwndEdit, WM_GETFONT, 0, 0);
12138 if (hFont)
12139 {
12140 hOldFont = SelectObject(hdc, hFont);
12141 }
12142
12144 {
12145 TEXTMETRICW textMetric;
12146
12147 /* Add Extra spacing for the next character */
12148 GetTextMetricsW(hdc, &textMetric);
12149 sz.cx += (textMetric.tmMaxCharWidth * 2);
12150
12151 SetWindowPos(infoPtr->hwndEdit, NULL, 0, 0, sz.cx,
12152 rect.bottom - rect.top, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOZORDER);
12153 }
12154 if (hFont)
12155 SelectObject(hdc, hOldFont);
12156
12157 ReleaseDC(infoPtr->hwndEdit, hdc);
12158
12159 break;
12160 }
12161 case EN_KILLFOCUS:
12162 {
12164 LISTVIEW_CancelEditLabel(infoPtr);
12165 break;
12166 }
12167
12168 default:
12169 return SendMessageW (infoPtr->hwndNotify, WM_COMMAND, wParam, lParam);
12170 }
12171
12172 return 0;
12173}
_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
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:55
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:20
#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:1759
BOOL Str_SetPtrWtoA(LPSTR *lppDest, LPCWSTR lpSrc) DECLSPEC_HIDDEN
HWND COMCTL32_CreateToolTip(HWND) DECLSPEC_HIDDEN
Definition: commctrl.c:1555
VOID COMCTL32_RefreshSysColors(void) DECLSPEC_HIDDEN
Definition: commctrl.c:1597
COMCTL32_SysColor comctl32_color
Definition: commctrl.c:82
BOOL WINAPI _TrackMouseEvent(TRACKMOUSEEVENT *ptme)
Definition: commctrl.c:1218
int WINAPI DrawShadowText(HDC hdc, LPCWSTR pszText, UINT cch, RECT *prc, DWORD dwFlags, COLORREF crText, COLORREF crShadow, int ixOffset, int iyOffset)
Definition: commctrl.c:1856
int selection
Definition: ctm.c:92
HDC dc
Definition: cylfrac.c:34
#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:1246
COLORREF WINAPI ImageList_SetBkColor(HIMAGELIST himl, COLORREF clrBk)
Definition: imagelist.c:2949
INT WINAPI ImageList_Add(HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
Definition: imagelist.c:458
BOOL WINAPI ImageList_Destroy(HIMAGELIST himl)
Definition: imagelist.c:941
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:1282
HIMAGELIST WINAPI ImageList_Create(INT cx, INT cy, UINT flags, INT cInitial, INT cGrow)
Definition: imagelist.c:814
BOOL WINAPI ImageList_GetIconSize(HIMAGELIST himl, INT *cx, INT *cy)
Definition: imagelist.c:2055
static LRESULT LISTVIEW_Notify(LISTVIEW_INFO *infoPtr, NMHDR *lpnmhdr)
Definition: listview.c:10630
static void LISTVIEW_UpdateScroll(LISTVIEW_INFO *infoPtr)
Definition: listview.c:2173
static void LISTVIEW_SetSelection(LISTVIEW_INFO *infoPtr, INT nItem)
Definition: listview.c:3810
static void LISTVIEW_SaveTextMetrics(LISTVIEW_INFO *infoPtr)
Definition: listview.c:3143
struct tagRANGE RANGE
#define MAX_EMPTYTEXT_SELECT_WIDTH
Definition: listview.c:384
static void LISTVIEW_InvalidateSelectedItems(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:2273
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:10508
#define LV_FL_DT_FLAGS
Definition: listview.c:404
static BOOL is_text(LPCWSTR text)
Definition: listview.c:470
static INT LISTVIEW_FindItemW(const LISTVIEW_INFO *infoPtr, INT nStart, const LVFINDINFOW *lpFindInfo)
Definition: listview.c:6429
static int textcmpWT(LPCWSTR aw, LPCWSTR bt, BOOL isW)
Definition: listview.c:536
static LRESULT LISTVIEW_PrintClient(LISTVIEW_INFO *infoPtr, HDC hdc, DWORD options)
Definition: listview.c:10940
static DWORD LISTVIEW_MapIndexToId(const LISTVIEW_INFO *infoPtr, INT iItem)
Definition: listview.c:2703
static void map_style_view(LISTVIEW_INFO *infoPtr)
Definition: listview.c:1610
static INT LISTVIEW_GetSelectedCount(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:3562
static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, ITERATOR *subitems, POINT pos, DWORD cdmode)
Definition: listview.c:4845
static BOOL LISTVIEW_Enable(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:9801
#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:1702
static BOOL LISTVIEW_DeleteItem(LISTVIEW_INFO *infoPtr, INT nItem)
Definition: listview.c:5915
struct tagRANGES * RANGES
static DWORD LISTVIEW_SetExtendedListViewStyle(LISTVIEW_INFO *infoPtr, DWORD mask, DWORD ex_style)
Definition: listview.c:8693
#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:1327
static LRESULT LISTVIEW_SetFocus(LISTVIEW_INFO *infoPtr, HWND hwndLoseFocus)
Definition: listview.c:11105
static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT item, LPRECT lprc)
Definition: listview.c:7294
static VOID CALLBACK LISTVIEW_ScrollTimer(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
Definition: listview.c:4073
static BOOL LISTVIEW_SetCursor(const LISTVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
Definition: listview.c:11074
static VOID CALLBACK LISTVIEW_DelayedEditItem(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
Definition: listview.c:9608
static void textcpynT(LPWSTR dest, BOOL isDestW, LPCWSTR src, BOOL isSrcW, INT max)
Definition: listview.c:481
struct tagITEM_INFO ITEM_INFO
static INT LISTVIEW_MapIdToIndex(const LISTVIEW_INFO *infoPtr, UINT iID)
Definition: listview.c:2670
static DWORD notify_customdraw(const LISTVIEW_INFO *infoPtr, DWORD dwDrawStage, NMLVCUSTOMDRAW *lpnmlvcd)
Definition: listview.c:1053
void LISTVIEW_Unregister(void)
Definition: listview.c:12095
static RANGES ranges_diff(RANGES ranges, RANGES sub)
Definition: listview.c:3287
static LRESULT CallWindowProcT(WNDPROC proc, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL isW)
Definition: listview.c:1582
static LRESULT LISTVIEW_Create(HWND hwnd, const CREATESTRUCTW *lpcs)
Definition: listview.c:9722
static HWND CreateEditLabelT(LISTVIEW_INFO *infoPtr, LPCWSTR text, BOOL isW)
Definition: listview.c:6199
static BOOL LISTVIEW_NCPaint(const LISTVIEW_INFO *infoPtr, HRGN region)
Definition: listview.c:10802
static BOOL LISTVIEW_GetColumnOrderArray(const LISTVIEW_INFO *infoPtr, INT iCount, LPINT lpiArray)
Definition: listview.c:6654
void LISTVIEW_Register(void)
Definition: listview.c:12070
static INT LISTVIEW_ProcessLetterKeys(LISTVIEW_INFO *infoPtr, WPARAM charCode, LPARAM keyData)
Definition: listview.c:1876
static INT LISTVIEW_HitTest(const LISTVIEW_INFO *, LPLVHITTESTINFO, BOOL, BOOL)
Definition: listview.c:7746
#define ICON_TOP_PADDING_HITABLE
Definition: listview.c:373
static LPWSTR textdupTtoW(LPCWSTR text, BOOL isW)
Definition: listview.c:491
static LPCSTR debugtext_tn(LPCWSTR text, BOOL isW, INT n)
Definition: listview.c:561
static BOOL LISTVIEW_SortItems(LISTVIEW_INFO *infoPtr, PFNLVCOMPARE pfnCompare, LPARAM lParamSort, BOOL IsEx)
Definition: listview.c:9465
static void iterator_destroy(const ITERATOR *i)
Definition: listview.c:1310
static void LISTVIEW_NextIconPosLeft(LISTVIEW_INFO *infoPtr, LPPOINT lpPos)
Definition: listview.c:2766
static INT LISTVIEW_GetItemTextT(const LISTVIEW_INFO *infoPtr, INT nItem, LPLVITEMW lpLVItem, BOOL isW)
Definition: listview.c:7428
static void prepaint_setup(const LISTVIEW_INFO *infoPtr, HDC hdc, NMLVCUSTOMDRAW *lpnmlvcd, BOOL SubItem)
Definition: listview.c:1067
static INT LISTVIEW_GetColumnWidth(const LISTVIEW_INFO *infoPtr, INT nColumn)
Definition: listview.c:6672
static LRESULT notify_hdr(const LISTVIEW_INFO *infoPtr, INT code, LPNMHDR pnmh)
Definition: listview.c:833
static void LISTVIEW_InvalidateColumn(const LISTVIEW_INFO *infoPtr, INT nColumn)
Definition: listview.c:1788
static LRESULT LISTVIEW_VScroll(LISTVIEW_INFO *, INT, INT)
Definition: listview.c:9884
static LRESULT LISTVIEW_SetRedraw(LISTVIEW_INFO *infoPtr, BOOL redraw)
Definition: listview.c:11179
static BOOL LISTVIEW_SetItemCount(LISTVIEW_INFO *infoPtr, INT nItems, DWORD dwFlags)
Definition: listview.c:8982
static char * debug_getbuf(void)
Definition: listview.c:568
static BOOL LISTVIEW_SetBkColor(LISTVIEW_INFO *infoPtr, COLORREF color)
Definition: listview.c:8200
static LPCSTR debugtext_t(LPCWSTR text, BOOL isW)
Definition: listview.c:555
static BOOL is_autoarrange(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:1589
static HIMAGELIST LISTVIEW_CreateDragImage(LISTVIEW_INFO *infoPtr, INT iItem, LPPOINT lppt)
Definition: listview.c:5556
#define ranges_check(ranges, desc)
Definition: listview.c:3196
static LRESULT CALLBACK EditLblWndProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: listview.c:6165
static int textlenT(LPCWSTR text, BOOL isW)
Definition: listview.c:475
static LRESULT LISTVIEW_ThemeChanged(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:9531
static BOOL set_sub_item(const LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL isW, BOOL *bChanged)
Definition: listview.c:4487
static BOOL LISTVIEW_SetItemFocus(LISTVIEW_INFO *infoPtr, INT nItem)
Definition: listview.c:3594
#define DEBUG_BUFFERS
Definition: listview.c:341
static void LISTVIEW_UpdateHeaderSize(const LISTVIEW_INFO *infoPtr, INT nNewScrollPos)
Definition: listview.c:2016
static BOOL LISTVIEW_MoveIconTo(const LISTVIEW_INFO *infoPtr, INT nItem, const POINT *lppt, BOOL isNew)
Definition: listview.c:2834
static INT LISTVIEW_GetNextItem(const LISTVIEW_INFO *infoPtr, INT nItem, UINT uFlags)
Definition: listview.c:7452
static BOOL ranges_contain(RANGES ranges, INT nItem)
Definition: listview.c:3305
static void LISTVIEW_Refresh(LISTVIEW_INFO *infoPtr, HDC hdc, const RECT *prcErase)
Definition: listview.c:5264
#define LV_SL_DT_FLAGS
Definition: listview.c:405
static BOOL LISTVIEW_IsHeaderEnabled(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:1707
#define KEY_DELAY
Definition: listview.c:411
static LRESULT LISTVIEW_Size(LISTVIEW_INFO *infoPtr, int Width, int Height)
Definition: listview.c:11213
static DWORD LISTVIEW_SetHoverTime(LISTVIEW_INFO *infoPtr, DWORD dwHoverTime)
Definition: listview.c:8837
static BOOL LISTVIEW_SetTextBkColor(LISTVIEW_INFO *infoPtr, COLORREF color)
Definition: listview.c:9269
static LRESULT LISTVIEW_MouseWheel(LISTVIEW_INFO *infoPtr, INT wheelDelta)
Definition: listview.c:10074
static HIMAGELIST LISTVIEW_GetImageList(const LISTVIEW_INFO *infoPtr, INT nImageList)
Definition: listview.c:6744
#define LABEL_HOR_PADDING
Definition: listview.c:376
static BOOL ranges_del(RANGES ranges, RANGE range)
Definition: listview.c:3429
static INT LISTVIEW_UpdateVScroll(LISTVIEW_INFO *infoPtr)
Definition: listview.c:2111
static LRESULT LISTVIEW_ShowWindow(LISTVIEW_INFO *infoPtr, WPARAM bShown, LPARAM iStatus)
Definition: listview.c:11455
static INT LISTVIEW_StyleChanged(LISTVIEW_INFO *infoPtr, WPARAM wStyleType, const STYLESTRUCT *lpss)
Definition: listview.c:11319
static BOOL LISTVIEW_DrawTrackLine(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:9579
static void LISTVIEW_DrawItemPart(LISTVIEW_INFO *infoPtr, LVITEMW *item, const NMLVCUSTOMDRAW *nmlvcd, const POINT *pos)
Definition: listview.c:4681
static DWORD LISTVIEW_ApproximateViewRect(const LISTVIEW_INFO *infoPtr, INT nItemCount, WORD wWidth, WORD wHeight)
Definition: listview.c:5415
static BOOL LISTVIEW_FillBkgnd(const LISTVIEW_INFO *infoPtr, HDC hdc, const RECT *lprcBox)
Definition: listview.c:4671
static RANGES ranges_create(int count)
Definition: listview.c:3222
#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:3346
static void ranges_dump(RANGES ranges)
Definition: listview.c:3297
static BOOL LISTVIEW_GetItemW(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem)
Definition: listview.c:1714
static BOOL LISTVIEW_EraseBkgnd(const LISTVIEW_INFO *infoPtr, HDC hdc)
Definition: listview.c:9820
static BOOL LISTVIEW_IsItemVisible(const LISTVIEW_INFO *infoPtr, INT nItem)
Definition: listview.c:8099
static BOOL LISTVIEW_Update(LISTVIEW_INFO *infoPtr, INT nItem)
Definition: listview.c:9551
static BOOL ranges_additem(RANGES ranges, INT nItem)
Definition: listview.c:1140
static BOOL LISTVIEW_GetItemExtT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
Definition: listview.c:7070
static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL isW)
Definition: listview.c:7921
static RANGE iterator_range(const ITERATOR *i)
Definition: listview.c:1291
static LRESULT LISTVIEW_NotifyFormat(LISTVIEW_INFO *infoPtr, HWND hwndFrom, INT nCommand)
Definition: listview.c:10856
static LRESULT LISTVIEW_NCDestroy(LISTVIEW_INFO *infoPtr)
Definition: listview.c:10578
static BOOL LISTVIEW_GetItemAtPt(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, POINT pt)
Definition: listview.c:3864
static void ranges_clear(RANGES ranges)
Definition: listview.c:3232
static BOOL LISTVIEW_GetColumnT(const LISTVIEW_INFO *infoPtr, INT nColumn, LPLVCOLUMNW lpColumn, BOOL isW)
Definition: listview.c:6604
static BOOL LISTVIEW_DeleteColumn(LISTVIEW_INFO *infoPtr, INT nColumn)
Definition: listview.c:5758
static LRESULT LISTVIEW_CancelEditLabel(LISTVIEW_INFO *infoPtr)
Definition: listview.c:5530
static LRESULT notify_listview(const LISTVIEW_INFO *infoPtr, INT code, LPNMLISTVIEW plvnm)
Definition: listview.c:889
static LRESULT EditLblWndProcT(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL isW)
Definition: listview.c:6111
static int get_ansi_notification(UINT unicodeNotificationCode)
Definition: listview.c:744
static BOOL LISTVIEW_KeySelection(LISTVIEW_INFO *, INT, DWORD)
Definition: listview.c:3826
static LRESULT notify_forward_header(const LISTVIEW_INFO *infoPtr, NMHEADERW *lpnmhW)
Definition: listview.c:782
static void scroll_list(LISTVIEW_INFO *infoPtr, INT dx, INT dy)
Definition: listview.c:9854
static void LISTVIEW_RefreshReport(LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, DWORD cdmode)
Definition: listview.c:5046
static HIMAGELIST LISTVIEW_CreateCheckBoxIL(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:8640
static const char * debugnmlistview(const NMLISTVIEW *plvnm)
Definition: listview.c:618
static void column_fill_hditem(const LISTVIEW_INFO *infoPtr, HDITEMW *lphdi, INT nColumn, const LVCOLUMNW *lpColumn, BOOL isW)
Definition: listview.c:8225
static HIMAGELIST LISTVIEW_SetImageList(LISTVIEW_INFO *, INT, HIMAGELIST)
Definition: listview.c:8925
static BOOL LISTVIEW_Arrange(LISTVIEW_INFO *infoPtr, INT nAlignCode)
Definition: listview.c:2869
static BOOL is_redrawing(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:1744
static void LISTVIEW_GetItemMetrics(const LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, LPRECT lprcBox, LPRECT lprcSelectBox, LPRECT lprcIcon, LPRECT lprcStateIcon, LPRECT lprcLabel)
Definition: listview.c:2371
static INT LISTVIEW_SetView(LISTVIEW_INFO *infoPtr, DWORD nView)
Definition: listview.c:9343
static HCURSOR LISTVIEW_SetHotCursor(LISTVIEW_INFO *infoPtr, HCURSOR hCursor)
Definition: listview.c:8794
static BOOL ranges_shift(RANGES ranges, INT nItem, INT delta, INT nUpper)
Definition: listview.c:3327
static void textfreeT(LPWSTR wstr, BOOL isW)
Definition: listview.c:505
static BOOL LISTVIEW_SetItemT(LISTVIEW_INFO *infoPtr, LVITEMW *lpLVItem, BOOL isW)
Definition: listview.c:4562
static void iterator_empty(ITERATOR *i)
Definition: listview.c:1318
static LRESULT LISTVIEW_GetVersion(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:11479
static BOOL LISTVIEW_DrawFocusRect(const LISTVIEW_INFO *infoPtr, HDC hdc)
Definition: listview.c:1720
static void iterator_rangesitems(ITERATOR *i, RANGES ranges)
Definition: listview.c:1338
static LPCSTR debugscrollcode(int nScrollCode)
Definition: listview.c:725
static void LISTVIEW_ShowFocusRect(const LISTVIEW_INFO *infoPtr, BOOL fShow)
Definition: listview.c:2211
static INT LISTVIEW_CalculateItemWidth(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:3034
static LRESULT LISTVIEW_WMPaint(LISTVIEW_INFO *infoPtr, HDC hdc)
Definition: listview.c:10918
static INT CALLBACK ranges_cmp(LPVOID range1, LPVOID range2, LPARAM flags)
Definition: listview.c:3180
static void ranges_destroy(RANGES ranges)
Definition: listview.c:3242
static BOOL notify_deleteitem(const LISTVIEW_INFO *infoPtr, INT nItem)
Definition: listview.c:916
static BOOL LISTVIEW_EndEditLabelT(LISTVIEW_INFO *, BOOL, BOOL)
Definition: listview.c:5992
static LRESULT LISTVIEW_RButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y)
Definition: listview.c:11000
static BOOL LISTVIEW_DeselectAllSkipItems(LISTVIEW_INFO *infoPtr, RANGES toSkip)
Definition: listview.c:3514
static BOOL LISTVIEW_DeselectAll(LISTVIEW_INFO *infoPtr)
Definition: listview.c:3547
#define LV_ML_DT_FLAGS
Definition: listview.c:403
static LRESULT LISTVIEW_Paint(LISTVIEW_INFO *infoPtr, HDC hdc)
Definition: listview.c:10877
static BOOL notify_measureitem(LISTVIEW_INFO *infoPtr)
Definition: listview.c:1114
static LRESULT LISTVIEW_Destroy(LISTVIEW_INFO *infoPtr)
Definition: listview.c:9778
static LRESULT LISTVIEW_LButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y)
Definition: listview.c:10384
static COLUMN_INFO * LISTVIEW_GetColumnInfo(const LISTVIEW_INFO *infoPtr, INT nSubItem)
Definition: listview.c:1643
static void LISTVIEW_InvalidateItem(const LISTVIEW_INFO *infoPtr, INT nItem)
Definition: listview.c:1756
static BOOL textsetptrT(LPWSTR *dest, LPCWSTR src, BOOL isW)
Definition: listview.c:514
static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, INT y)
Definition: listview.c:4132
static BOOL notify_click(const LISTVIEW_INFO *infoPtr, INT code, const LVHITTESTINFO *lvht)
Definition: listview.c:896
static LRESULT LISTVIEW_MouseHover(LISTVIEW_INFO *infoPtr, INT x, INT y)
Definition: listview.c:3906
static DWORD LISTVIEW_SetIconSpacing(LISTVIEW_INFO *infoPtr, INT cx, INT cy)
Definition: listview.c:8858
static void LISTVIEW_MarqueeHighlight(LISTVIEW_INFO *infoPtr, const POINT *coords_orig, INT scroll)
Definition: listview.c:3948
static void LISTVIEW_RefreshOwnerDraw(const LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, DWORD cdmode)
Definition: listview.c:4972
static const WCHAR themeClass[]
Definition: listview.c:427
static const char * debugrange(const RANGE *lprng)
Definition: listview.c:575
#define TRAILING_HEADER_PADDING
Definition: listview.c:397
static BOOL iterator_frameditems(ITERATOR *i, const LISTVIEW_INFO *infoPtr, const RECT *lprc)
Definition: listview.c:1447
static const char * debuglvitem_t(const LVITEMW *lpLVItem, BOOL isW)
Definition: listview.c:627
static BOOL LISTVIEW_SetColumnT(const LISTVIEW_INFO *infoPtr, INT nColumn, const LVCOLUMNW *lpColumn, BOOL isW)
Definition: listview.c:8433
static const char * debugscrollinfo(const SCROLLINFO *pScrollInfo)
Definition: listview.c:581
static BOOL iterator_next(ITERATOR *i)
Definition: listview.c:1215
static LRESULT LISTVIEW_KillFocus(LISTVIEW_INFO *infoPtr)
Definition: listview.c:10246
#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:4302
static void LISTVIEW_NextIconPosTop(LISTVIEW_INFO *infoPtr, LPPOINT lpPos)
Definition: listview.c:2735
#define SB_INTERNAL
Definition: listview.c:346
static BOOL LISTVIEW_GetItemRect(const LISTVIEW_INFO *, INT, LPRECT)
Definition: listview.c:7193
static BOOL LISTVIEW_SetItemState(LISTVIEW_INFO *, INT, const LVITEMW *)
Definition: listview.c:9136
static INT WINAPI LISTVIEW_CallBackCompare(LPVOID first, LPVOID second, LPARAM lParam)
Definition: listview.c:9417
static BOOL LISTVIEW_RedrawItems(const LISTVIEW_INFO *infoPtr, INT nFirst, INT nLast)
Definition: listview.c:8138
static const char * debuglvcolumn_t(const LVCOLUMNW *lpColumn, BOOL isW)
Definition: listview.c:669
static RANGES ranges_clone(RANGES ranges)
Definition: listview.c:3250
static DWORD notify_postpaint(const LISTVIEW_INFO *infoPtr, NMLVCUSTOMDRAW *lpnmlvcd)
Definition: listview.c:1108
#define WIDTH_PADDING
Definition: listview.c:352
static BOOL LISTVIEW_SetColumnOrderArray(LISTVIEW_INFO *infoPtr, INT iCount, const INT *lpiArray)
Definition: listview.c:8488
static INT LISTVIEW_SetSelectionMark(LISTVIEW_INFO *infoPtr, INT nIndex)
Definition: listview.c:9245
static BOOL LISTVIEW_SetUnicodeFormat(LISTVIEW_INFO *infoPtr, BOOL unicode)
Definition: listview.c:9325
static INT LISTVIEW_SetHotItem(LISTVIEW_INFO *infoPtr, INT iIndex)
Definition: listview.c:8816
static BOOL LISTVIEW_GetViewRect(const LISTVIEW_INFO *, LPRECT)
Definition: listview.c:2974
static BOOL LISTVIEW_SetItemPosition(LISTVIEW_INFO *infoPtr, INT nItem, const POINT *pt)
Definition: listview.c:9080
static void LISTVIEW_ShiftFocus(LISTVIEW_INFO *infoPtr, INT focus, INT item, INT direction)
Definition: listview.c:3626
static LRESULT LISTVIEW_KeyDown(LISTVIEW_INFO *infoPtr, INT nVirtualKey, LONG lKeyData)
Definition: listview.c:10130
static BOOL iterator_remove_common_items(ITERATOR *iter1, ITERATOR *iter2)
Definition: listview.c:1518
static BOOL LISTVIEW_SetItemTextT(LISTVIEW_INFO *infoPtr, INT nItem, const LVITEMW *lpLVItem, BOOL isW)
Definition: listview.c:9216
#define DEFAULT_COLUMN_WIDTH
Definition: listview.c:387
static LRESULT LISTVIEW_TrackMouse(const LISTVIEW_INFO *infoPtr, POINT pt)
Definition: listview.c:10326
static BOOL LISTVIEW_DeselectAllSkipItem(LISTVIEW_INFO *infoPtr, INT nItem)
Definition: listview.c:3536
static void LISTVIEW_GetOrigin(const LISTVIEW_INFO *, LPPOINT)
Definition: listview.c:7665
static BOOL notify_dispinfoT(const LISTVIEW_INFO *infoPtr, UINT code, LPNMLVDISPINFOW pdi, BOOL isW)
Definition: listview.c:940
#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:8315
static UINT LISTVIEW_GetItemState(const LISTVIEW_INFO *, INT, UINT)
Definition: listview.c:7399
static INT LISTVIEW_GetStringWidthT(const LISTVIEW_INFO *, LPCWSTR, BOOL)
Definition: listview.c:7706
static LRESULT LISTVIEW_HScroll(LISTVIEW_INFO *, INT, INT)
Definition: listview.c:9988
static void LISTVIEW_InvalidateSubItem(const LISTVIEW_INFO *infoPtr, INT nItem, INT nSubItem)
Definition: listview.c:1767
#define SCROLL_DOWN
Definition: listview.c:3932
static INT WINAPI LISTVIEW_CallBackCompareEx(LPVOID first, LPVOID second, LPARAM lParam)
Definition: listview.c:9441
static INT LISTVIEW_GetCountPerColumn(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:1827
static void set_icon_size(SIZE *size, HIMAGELIST himl, BOOL is_small)
Definition: listview.c:8896
static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *, LPLVITEMW, BOOL)
Definition: listview.c:6789
static BOOL LISTVIEW_IsHotTracking(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:3881
static void LISTVIEW_GetAreaRect(const LISTVIEW_INFO *infoPtr, LPRECT lprcView)
Definition: listview.c:2928
static void LISTVIEW_RefreshReportGrid(LISTVIEW_INFO *infoPtr, HDC hdc)
Definition: listview.c:5129
struct tagDELAYED_ITEM_EDIT DELAYED_ITEM_EDIT
static void LISTVIEW_SetGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem)
Definition: listview.c:3723
static LONG LISTVIEW_GetItemSpacing(const LISTVIEW_INFO *infoPtr, BOOL bSmall)
Definition: listview.c:7369
#define SCROLL_LEFT
Definition: listview.c:3929
static BOOL LISTVIEW_GetItemPosition(const LISTVIEW_INFO *, INT, LPPOINT)
Definition: listview.c:7108
struct tagITERATOR ITERATOR
static INT CALLBACK MapIdSearchCompare(LPVOID p1, LPVOID p2, LPARAM lParam)
Definition: listview.c:2649
static void LISTVIEW_UpdateItemSize(LISTVIEW_INFO *infoPtr)
Definition: listview.c:3127
static INT LISTVIEW_GetTopIndex(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:4628
static LRESULT LISTVIEW_SetVersion(LISTVIEW_INFO *infoPtr, DWORD iVersion)
Definition: listview.c:11496
static BOOL iterator_frameditems_absolute(ITERATOR *i, const LISTVIEW_INFO *infoPtr, const RECT *frame)
Definition: listview.c:1348
static DWORD get_next_itemid(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:1629
static BOOL LISTVIEW_Scroll(LISTVIEW_INFO *, INT, INT)
Definition: listview.c:8168
static BOOL ranges_delitem(RANGES ranges, INT nItem)
Definition: listview.c:1147
#define TRAILING_LABEL_PADDING
Definition: listview.c:396
static void notify_itemactivate(const LISTVIEW_INFO *infoPtr, const LVHITTESTINFO *htInfo)
Definition: listview.c:857
static void LISTVIEW_ShiftIndices(LISTVIEW_INFO *infoPtr, INT nItem, INT direction)
Definition: listview.c:3649
static BOOL is_assignable_item(const LVITEMW *lpLVItem, LONG lStyle)
Definition: listview.c:4277
static void toggle_checkbox_state(LISTVIEW_INFO *infoPtr, INT nItem)
Definition: listview.c:1595
static INT LISTVIEW_GetCountPerRow(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:1809
static void LISTVIEW_GetItemOrigin(const LISTVIEW_INFO *, INT, LPPOINT)
Definition: listview.c:2304
static LRESULT LISTVIEW_SetFont(LISTVIEW_INFO *infoPtr, HFONT hFont, WORD fRedraw)
Definition: listview.c:11139
static INT LISTVIEW_CreateHeader(LISTVIEW_INFO *infoPtr)
Definition: listview.c:1667
static BOOL LISTVIEW_SetColumnWidth(LISTVIEW_INFO *infoPtr, INT nColumn, INT cx)
Definition: listview.c:8508
static INT LISTVIEW_StyleChanging(WPARAM wStyleType, STYLESTRUCT *lpss)
Definition: listview.c:11425
static HWND LISTVIEW_SetToolTips(LISTVIEW_INFO *infoPtr, HWND hwndNewToolTip)
Definition: listview.c:9308
static void LISTVIEW_RefreshList(LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, DWORD cdmode)
Definition: listview.c:5233
static void LISTVIEW_InvalidateList(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:1783
static LRESULT LISTVIEW_Command(LISTVIEW_INFO *, WPARAM, LPARAM)
Definition: listview.c:12112
static BOOL LISTVIEW_SetTextColor(LISTVIEW_INFO *infoPtr, COLORREF color)
Definition: listview.c:9289
#define DEBUG_BUFFER_SIZE
Definition: listview.c:343
static void LISTVIEW_ScrollColumns(LISTVIEW_INFO *infoPtr, INT nColumn, INT dx)
Definition: listview.c:5700
#define SCROLL_RIGHT
Definition: listview.c:3930
static void LISTVIEW_InvalidateRect(const LISTVIEW_INFO *infoPtr, const RECT *rect)
Definition: listview.c:1749
static LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: listview.c:11516
struct tagITEMHDR * LPITEMHDR
static HWND LISTVIEW_EditLabelT(LISTVIEW_INFO *infoPtr, INT nItem, BOOL isW)
Definition: listview.c:6238
static INT LISTVIEW_FindItemA(const LISTVIEW_INFO *infoPtr, INT nStart, const LVFINDINFOA *lpFindInfo)
Definition: listview.c:6574
key_state
Definition: listview.c:430
@ CTRL_KEY
Definition: listview.c:432
@ SHIFT_KEY
Definition: listview.c:431
@ SPACE_KEY
Definition: listview.c:433
struct tagLISTVIEW_INFO LISTVIEW_INFO
static INT LISTVIEW_GetCountPerPage(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:6716
static LRESULT LISTVIEW_RButtonDblClk(const LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y)
Definition: listview.c:10970
static void ranges_assert(RANGES ranges, LPCSTR desc, const char *file, int line)
Definition: listview.c:3198
static BOOL LISTVIEW_AddGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem)
Definition: listview.c:3671
static void LISTVIEW_GetItemBox(const LISTVIEW_INFO *, INT, LPRECT)
Definition: listview.c:2613
static BOOL iterator_visibleitems(ITERATOR *i, const LISTVIEW_INFO *infoPtr, HDC hdc)
Definition: listview.c:1463
static BOOL LISTVIEW_EnsureVisible(LISTVIEW_INFO *, INT, BOOL)
Definition: listview.c:6342
#define SCROLL_UP
Definition: listview.c:3931
static INT ranges_itemcount(RANGES ranges)
Definition: listview.c:3314
static void LISTVIEW_UpdateSize(LISTVIEW_INFO *)
Definition: listview.c:11249
static LRESULT LISTVIEW_LButtonDblClk(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y)
Definition: listview.c:10297
static BOOL iterator_prev(ITERATOR *i)
Definition: listview.c:1255
static void customdraw_fill(NMLVCUSTOMDRAW *lpnmlvcd, const LISTVIEW_INFO *infoPtr, HDC hdc, const RECT *rcBounds, const LVITEMW *lplvItem)
Definition: listview.c:1036
static void LISTVIEW_ScrollOnInsert(LISTVIEW_INFO *infoPtr, INT nItem, INT dir)
Definition: listview.c:5843
static INT shift_item(const LISTVIEW_INFO *infoPtr, INT nShiftItem, INT nItem, INT direction)
Definition: listview.c:3608
static const char * debuglvhittestinfo(const LVHITTESTINFO *lpht)
Definition: listview.c:716
static INT LISTVIEW_CalculateItemHeight(const LISTVIEW_INFO *infoPtr)
Definition: listview.c:3094
static INT LISTVIEW_UpdateHScroll(LISTVIEW_INFO *infoPtr)
Definition: listview.c:2041
#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:9632
static BOOL LISTVIEW_DeleteAllItems(LISTVIEW_INFO *infoPtr, BOOL destroy)
Definition: listview.c:5621
static LRESULT CALLBACK EditLblWndProcA(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: listview.c:6182
struct tagSUBITEM_INFO SUBITEM_INFO
static SUBITEM_INFO * LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems, INT nSubItem)
Definition: listview.c:3007
#define COMCTL32_VERSION
Definition: resource.h:72
BOOL WINAPI Str_SetPtrW(LPWSTR *lppDest, LPCWSTR lpSrc)
Definition: string.c:232
const char * wine_dbg_sprintf(const char *format,...)
Definition: compat.c:296
#define wcsnicmp
Definition: compat.h:14
#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
int WINAPI lstrcmpW(LPCWSTR str1, LPCWSTR str2)
Definition: locale.c:4246
const UINT * keys
Definition: locale.c:416
ULONG WINAPI DECLSPEC_HOTPATCH GetTickCount(void)
Definition: sync.c:182
const WCHAR * text
Definition: package.c:1794
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:1927
HRESULT WINAPI DrawThemeParentBackground(HWND hwnd, HDC hdc, RECT *prc)
Definition: draw.c:72
HTHEME WINAPI GetWindowTheme(HWND hwnd)
Definition: system.c:920
HRESULT WINAPI CloseThemeData(HTHEME hTheme)
Definition: system.c:1036
HTHEME WINAPI OpenThemeData(HWND hwnd, LPCWSTR pszClassList)
Definition: system.c:890
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
return ret
Definition: mutex.c:146
HINSTANCE hInst
Definition: dxdiag.c:13
POINTL point
Definition: edittest.c:50
static INT cxMin
Definition: eventvwr.c:4340
#define WM_APP
Definition: eventvwr.h:73
#define abs(i)
Definition: fconv.c:206
unsigned short WORD
Definition: ntddk_ex.h:93
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
_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
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
GLuint GLuint end
Definition: gl.h:1545
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLdouble n
Definition: glext.h:7729
GLuint res
Definition: glext.h:9613
GLenum src
Definition: glext.h:6340
GLuint buffer
Definition: glext.h:5915
GLsizeiptr size
Definition: glext.h:5919
GLintptr offset
Definition: glext.h:5920
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
GLuint64EXT * result
Definition: glext.h:11304
GLfloat GLfloat p
Definition: glext.h:8902
GLenum GLsizei len
Definition: glext.h:6722
const GLuint * buffers
Definition: glext.h:5916
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
#define ZeroMemory
Definition: minwinbase.h:31
LONG_PTR LPARAM
Definition: minwindef.h:175
LONG_PTR LRESULT
Definition: minwindef.h:176
UINT_PTR WPARAM
Definition: minwindef.h:174
int * LPINT
Definition: minwindef.h:151
#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:88
static const WCHAR textW[]
Definition: itemdlg.c:1559
D3D11_SHADER_VARIABLE_DESC desc
Definition: reflection.c:1204
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:2025
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:3051
direction
Definition: netio.c:882
_In_ LPWSTR _In_ DWORD _In_ DWORD _In_ DWORD dwFlags
Definition: netsh.h:141
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:2478
#define NM_RELEASEDCAPTURE
Definition: commctrl.h:141
#define CDDS_ITEMPOSTPAINT
Definition: commctrl.h:286
#define LVM_GETCALLBACKMASK
Definition: commctrl.h:2421
#define LVM_DELETEALLITEMS
Definition: commctrl.h:2418
#define LVM_CREATEDRAGIMAGE
Definition: commctrl.h:2657
#define LVCF_ORDER
Definition: commctrl.h:2596
#define LV_VIEW_DETAILS
Definition: commctrl.h:2846
#define LVIS_OVERLAYMASK
Definition: commctrl.h:2330
#define LVSIL_SMALL
Definition: commctrl.h:2304
#define I_IMAGECALLBACK
Definition: commctrl.h:2390
#define LVM_GETITEMA
Definition: commctrl.h:2394
#define NM_RDBLCLK
Definition: commctrl.h:134
#define LVM_ARRANGE
Definition: commctrl.h:2537
#define LVN_GETDISPINFOA
Definition: commctrl.h:3158
_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:2740
#define HDS_HIDDEN
Definition: commctrl.h:631
#define LVCFMT_IMAGE
Definition: commctrl.h:2607
#define LVM_SETITEMTEXTW
Definition: commctrl.h:2692
#define CDDS_ITEM
Definition: commctrl.h:284
#define HDF_LEFT
Definition: commctrl.h:713
#define LVM_SETHOVERTIME
Definition: commctrl.h:2797
#define ILD_NORMAL
Definition: commctrl.h:417
#define LVN_ODFINDITEMW
Definition: commctrl.h:3150
#define LVS_SINGLESEL
Definition: commctrl.h:2271
#define LVM_SETCOLUMNW
Definition: commctrl.h:2630
#define TME_LEAVE
Definition: commctrl.h:4998
#define HDN_LAST
Definition: commctrl.h:206
#define LVM_SETTEXTCOLOR
Definition: commctrl.h:2663
#define LVCFMT_COL_HAS_IMAGES
Definition: commctrl.h:2609
#define LVS_ICON
Definition: commctrl.h:2266
#define HDI_TEXT
Definition: commctrl.h:704
#define LVFI_STRING
Definition: commctrl.h:2442
#define LVS_SHAREIMAGELISTS
Definition: commctrl.h:2275
#define LVM_INSERTCOLUMNA
Definition: commctrl.h:2636
#define LVM_GETITEMCOUNT
Definition: commctrl.h:2311
#define LVN_BEGINRDRAG
Definition: commctrl.h:3146
#define LVM_GETITEMSTATE
Definition: commctrl.h:2680
#define LVN_COLUMNCLICK
Definition: commctrl.h:3144
#define CDDS_ITEMPREPAINT
Definition: commctrl.h:285
#define LVIF_NORECOMPUTE
Definition: commctrl.h:2319
#define LVIS_ACTIVATING
Definition: commctrl.h:2328
#define LVS_NOCOLUMNHEADER
Definition: commctrl.h:2289
#define NM_DBLCLK
Definition: commctrl.h:131
#define LVFI_SUBSTRING
Definition: commctrl.h:2443
#define LVM_GETCOLUMNORDERARRAY
Definition: commctrl.h:2773
#define LVM_GETHEADER
Definition: commctrl.h:2655
#define LVCFMT_CENTER
Definition: commctrl.h:2605
#define HDF_CENTER
Definition: commctrl.h:715
#define LVM_GETTOPINDEX
Definition: commctrl.h:2669
#define LVM_GETITEMSPACING
Definition: commctrl.h:2716
#define HDN_ITEMCHANGEDW
Definition: commctrl.h:840
#define LPSTR_TEXTCALLBACKW
Definition: commctrl.h:2385
#define LVM_SETCOLUMNA
Definition: commctrl.h:2629
#define HDM_GETBITMAPMARGIN
Definition: commctrl.h:818
#define LVM_SETCOLUMNWIDTH
Definition: commctrl.h:2651
#define LVM_SETBKCOLOR
Definition: commctrl.h:2298
#define LVFI_WRAP
Definition: commctrl.h:2445
#define LVIF_STATE
Definition: commctrl.h:2317
#define LVS_EX_GRIDLINES
Definition: commctrl.h:2734
#define LVCF_IMAGE
Definition: commctrl.h:2595
#define LVS_EX_SNAPTOGRID
Definition: commctrl.h:2753
#define LVS_OWNERDATA
Definition: commctrl.h:2279
#define WC_LISTVIEWW
Definition: commctrl.h:2262
#define HOVER_DEFAULT
Definition: commctrl.h:5003
#define HDM_SETITEMA
Definition: commctrl.h:753
#define LVKF_CONTROL
Definition: commctrl.h:3061
#define CDDS_SUBITEM
Definition: commctrl.h:289
#define HDM_SETUNICODEFORMAT
Definition: commctrl.h:821
#define LVHT_BELOW
Definition: commctrl.h:2505
#define CDRF_NOTIFYSUBITEMDRAW
Definition: commctrl.h:276
#define LVS_EX_TWOCLICKACTIVATE
Definition: commctrl.h:2741
#define LVS_TYPEMASK
Definition: commctrl.h:2270
#define LVS_OWNERDRAWFIXED
Definition: commctrl.h:2288
#define LVNI_SELECTED
Definition: commctrl.h:2429
#define WC_EDITW
Definition: commctrl.h:4692
#define LVM_GETITEMPOSITION
Definition: commctrl.h:2488
#define HDF_RIGHT
Definition: commctrl.h:714
#define LVIF_COLUMNS
Definition: commctrl.h:2321
#define LVN_GETINFOTIPA
Definition: commctrl.h:3227
#define HDFT_ISSTRING
Definition: commctrl.h:642
#define LVM_SETITEMSTATE
Definition: commctrl.h:2677
#define LVHT_ONITEM
Definition: commctrl.h:2502
#define LVS_EX_HEADERDRAGDROP
Definition: commctrl.h:2738
#define LVKF_SHIFT
Definition: commctrl.h:3062
#define CLR_NONE
Definition: commctrl.h:319
#define LVHT_TOLEFT
Definition: commctrl.h:2507
#define CCM_GETVERSION
Definition: commctrl.h:115
#define LVFI_PARAM
Definition: commctrl.h:2441
#define LVNI_TOLEFT
Definition: commctrl.h:2435
#define LVM_EDITLABELW
Definition: commctrl.h:2541
#define LVN_SETDISPINFOW
Definition: commctrl.h:3161
#define HDM_INSERTITEMA
Definition: commctrl.h:736
#define HDS_FULLDRAG
Definition: commctrl.h:633
#define LVN_ODSTATECHANGED
Definition: commctrl.h:3153
#define CDRF_NOTIFYITEMDRAW
Definition: commctrl.h:275
#define LVM_GETHOTITEM
Definition: commctrl.h:2777
#define LVS_SHOWSELALWAYS
Definition: commctrl.h:2272
#define LVM_DELETECOLUMN
Definition: commctrl.h:2643
#define LVS_REPORT
Definition: commctrl.h:2267
#define LVM_SETITEMPOSITION
Definition: commctrl.h:2485
#define LVS_SMALLICON
Definition: commctrl.h:2268
#define HDM_LAYOUT
Definition: commctrl.h:767
#define LVM_FINDITEMW
Definition: commctrl.h:2471
#define LVN_GETINFOTIPW
Definition: commctrl.h:3228
#define LVN_DELETEALLITEMS
Definition: commctrl.h:3139
#define LVM_SETCALLBACKMASK
Definition: commctrl.h:2424
#define LVM_SETUNICODEFORMAT
Definition: commctrl.h:2292
#define LVA_DEFAULT
Definition: commctrl.h:2532
#define LVM_GETEDITCONTROL
Definition: commctrl.h:2547
#define LVM_EDITLABELA
Definition: commctrl.h:2540
#define LVM_GETNUMBEROFWORKAREAS
Definition: commctrl.h:2791
#define LVM_UPDATE
Definition: commctrl.h:2675
#define WC_EDITA
Definition: commctrl.h:4691
#define CDRF_DODEFAULT
Definition: commctrl.h:268
#define LVM_REDRAWITEMS
Definition: commctrl.h:2529
struct _IMAGELIST * HIMAGELIST
Definition: commctrl.h:324
#define LVCF_WIDTH
Definition: commctrl.h:2592
#define LVM_GETCOLUMNA
Definition: commctrl.h:2622
#define LVM_APPROXIMATEVIEWRECT
Definition: commctrl.h:2783
#define LVM_GETHOVERTIME
Definition: commctrl.h:2799
#define LVNI_TORIGHT
Definition: commctrl.h:2436
#define LVA_ALIGNLEFT
Definition: commctrl.h:2533
#define HDF_IMAGE
Definition: commctrl.h:723
#define LVNI_FOCUSED
Definition: commctrl.h:2428
#define LVM_GETSTRINGWIDTHA
Definition: commctrl.h:2491
#define LVNI_BELOW
Definition: commctrl.h:2434
#define LVM_SETIMAGELIST
Definition: commctrl.h:2308
_Out_opt_ int * cx
Definition: commctrl.h:585
#define LVA_ALIGNTOP
Definition: commctrl.h:2534
#define LVCFMT_BITMAP_ON_RIGHT
Definition: commctrl.h:2608
#define LVIF_INDENT
Definition: commctrl.h:2318
#define HDN_BEGINDRAG
Definition: commctrl.h:855
#define LVN_INSERTITEM
Definition: commctrl.h:3137
#define ODT_LISTVIEW
Definition: commctrl.h:80
#define HDM_GETITEMA
Definition: commctrl.h:746
#define LVM_SETITEMW
Definition: commctrl.h:2402
#define LVS_NOSCROLL
Definition: commctrl.h:2280
#define LVM_SETTOOLTIPS
Definition: commctrl.h:2801
#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:3135
#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:2659
#define LVM_GETNEXTITEM
Definition: commctrl.h:2438
#define LV_VIEW_LIST
Definition: commctrl.h:2848
#define LVS_EX_CHECKBOXES
Definition: commctrl.h:2736
#define LVHT_TORIGHT
Definition: commctrl.h:2506
#define LVN_ODCACHEHINT
Definition: commctrl.h:3148
#define LVFI_PARTIAL
Definition: commctrl.h:2444
#define NM_CLICK
Definition: commctrl.h:130
#define LVM_MAPIDTOINDEX
Definition: commctrl.h:3021
#define LVN_BEGINDRAG
Definition: commctrl.h:3145
#define LVM_MAPINDEXTOID
Definition: commctrl.h:3019
#define LVS_EX_FULLROWSELECT
Definition: commctrl.h:2739
#define NM_KILLFOCUS
Definition: commctrl.h:136
#define LVS_SORTASCENDING
Definition: commctrl.h:2273
#define LVM_GETSUBITEMRECT
Definition: commctrl.h:2767
#define LV_VIEW_TILE
Definition: commctrl.h:2849
#define LVM_ENSUREVISIBLE
Definition: commctrl.h:2523
#define LVS_EX_TRACKSELECT
Definition: commctrl.h:2737
#define LVM_GETTOOLTIPS
Definition: commctrl.h:2803
#define LVS_SORTDESCENDING
Definition: commctrl.h:2274
#define LVM_GETWORKAREAS
Definition: commctrl.h:2789
#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:3140
#define HDN_FIRST
Definition: commctrl.h:205
#define LVM_GETVIEW
Definition: commctrl.h:2853
#define LVM_SETSELECTIONMARK
Definition: commctrl.h:2795
#define LVM_SETITEMTEXTA
Definition: commctrl.h:2691
#define LVM_CANCELEDITLABEL
Definition: commctrl.h:3017
#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:2623
#define LVIS_DROPHILITED
Definition: commctrl.h:2326
#define DPAS_SORTED
Definition: commctrl.h:4867
#define HDN_TRACKW
Definition: commctrl.h:852
#define HDN_ENDDRAG
Definition: commctrl.h:856
#define LVSCW_AUTOSIZE
Definition: commctrl.h:2649
#define LVN_ENDLABELEDITW
Definition: commctrl.h:3143
#define LVM_SETITEMCOUNT
Definition: commctrl.h:2701
#define LVN_SETDISPINFOA
Definition: commctrl.h:3160
#define LVIR_LABEL
Definition: commctrl.h:2479
#define HDM_SETIMAGELIST
Definition: commctrl.h:794
#define LVM_SCROLL
Definition: commctrl.h:2526
#define LVM_GETIMAGELIST
Definition: commctrl.h:2300
#define WC_HEADERW
Definition: commctrl.h:624
#define LVNI_DROPHILITED
Definition: commctrl.h:2431
#define LVM_ISITEMVISIBLE
Definition: commctrl.h:3023
#define LVM_INSERTITEMA
Definition: commctrl.h:2408
#define LVM_GETCOUNTPERPAGE
Definition: commctrl.h:2671
#define LVIS_SELECTED
Definition: commctrl.h:2324
#define LVN_BEGINLABELEDITW
Definition: commctrl.h:3141
#define LVSIL_GROUPHEADER
Definition: commctrl.h:2306
#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:2606
#define LVM_SETHOTCURSOR
Definition: commctrl.h:2779
#define HDM_GETORDERARRAY
Definition: commctrl.h:806
#define LVM_SUBITEMHITTEST
Definition: commctrl.h:2769
#define LVN_ENDLABELEDITA
Definition: commctrl.h:3142
#define LVIF_PARAM
Definition: commctrl.h:2316
#define LVM_GETITEMTEXTW
Definition: commctrl.h:2685
#define HDI_FORMAT
Definition: commctrl.h:705
#define LVM_GETITEMRECT
Definition: commctrl.h:2482
#define LVS_NOSORTHEADER
Definition: commctrl.h:2290
#define LVM_GETITEMTEXTA
Definition: commctrl.h:2684
#define LVS_EDITLABELS
Definition: commctrl.h:2278
#define LVM_GETBKCOLOR
Definition: commctrl.h:2296
#define CLR_DEFAULT
Definition: commctrl.h:320
#define HDS_HORZ
Definition: commctrl.h:628
#define LVM_INSERTCOLUMNW
Definition: commctrl.h:2637
#define LVM_GETISEARCHSTRINGA
Definition: commctrl.h:2719
#define LVHT_ONITEMICON
Definition: commctrl.h:2499
#define LVIF_TEXT
Definition: commctrl.h:2314
#define LVM_DELETEITEM
Definition: commctrl.h:2415
#define LVSICF_NOSCROLL
Definition: commctrl.h:2699
#define LVIR_SELECTBOUNDS
Definition: commctrl.h:2480
#define HDM_GETITEMW
Definition: commctrl.h:747
#define LVM_GETEXTENDEDLISTVIEWSTYLE
Definition: commctrl.h:2732
#define LVM_SETITEMA
Definition: commctrl.h:2401
#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:2535
#define LVM_SETVIEW
Definition: commctrl.h:2851
#define LVNI_CUT
Definition: commctrl.h:2430
struct tagTRACKMOUSEEVENT TRACKMOUSEEVENT
#define LVCF_FMT
Definition: commctrl.h:2591
#define LVS_ALIGNMASK
Definition: commctrl.h:2286
#define LVM_GETSELECTIONMARK
Definition: commctrl.h:2793
#define LVM_GETORIGIN
Definition: commctrl.h:2673
#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:2735
#define HDI_LPARAM
Definition: commctrl.h:706
#define LVM_SETICONSPACING
Definition: commctrl.h:2726
#define LVN_ODFINDITEMA
Definition: commctrl.h:3149
#define LVCF_SUBITEM
Definition: commctrl.h:2594
#define LVCFMT_LEFT
Definition: commctrl.h:2603
#define LVNI_ABOVE
Definition: commctrl.h:2433
#define ILC_MASK
Definition: commctrl.h:351
#define INDEXTOSTATEIMAGEMASK(i)
Definition: commctrl.h:2333
#define LV_VIEW_MAX
Definition: commctrl.h:2850
#define WM_MOUSEHOVER
Definition: commctrl.h:4991
#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:4972
#define HDM_INSERTITEMW
Definition: commctrl.h:737
#define LVN_GETDISPINFOW
Definition: commctrl.h:3159
#define LVN_KEYDOWN
Definition: commctrl.h:3189
#define HDM_ORDERTOINDEX
Definition: commctrl.h:800
#define LVM_SETHOTITEM
Definition: commctrl.h:2775
#define LVM_GETSELECTEDCOUNT
Definition: commctrl.h:2713
#define LVS_EX_DOUBLEBUFFER
Definition: commctrl.h:2750
#define LVM_GETUNICODEFORMAT
Definition: commctrl.h:2294
#define LVM_GETTEXTCOLOR
Definition: commctrl.h:2661
#define LVSIL_STATE
Definition: commctrl.h:2305
#define LVCFMT_RIGHT
Definition: commctrl.h:2604
#define LVM_SETITEMPOSITION32
Definition: commctrl.h:2710
#define LVM_SETTEXTBKCOLOR
Definition: commctrl.h:2667
#define LVHT_ABOVE
Definition: commctrl.h:2504
#define TME_QUERY
Definition: commctrl.h:5000
#define LVIF_IMAGE
Definition: commctrl.h:2315
#define CDRF_SKIPDEFAULT
Definition: commctrl.h:270
#define LVM_SORTITEMSEX
Definition: commctrl.h:2805
#define LVN_MARQUEEBEGIN
Definition: commctrl.h:3203
#define DPAS_INSERTAFTER
Definition: commctrl.h:4869
#define HDN_TRACKA
Definition: commctrl.h:851
#define LVM_SETCOLUMNORDERARRAY
Definition: commctrl.h:2771
#define LV_VIEW_SMALLICON
Definition: commctrl.h:2847
#define LVS_ALIGNLEFT
Definition: commctrl.h:2285
#define LVKF_ALT
Definition: commctrl.h:3060
#define LVHT_ONITEMSTATEICON
Definition: commctrl.h:2501
#define LVHT_NOWHERE
Definition: commctrl.h:2498
#define LVN_ITEMCHANGED
Definition: commctrl.h:3136
#define HDI_IMAGE
Definition: commctrl.h:708
#define LVIF_DI_SETITEM
Definition: commctrl.h:3171
#define CDIS_HOT
Definition: commctrl.h:297
#define HDN_ITEMCHANGEDA
Definition: commctrl.h:839
#define LVM_INSERTITEMW
Definition: commctrl.h:2409
#define LVSCW_AUTOSIZE_USEHEADER
Definition: commctrl.h:2650
#define LVCF_TEXT
Definition: commctrl.h:2593
#define HDM_GETIMAGELIST
Definition: commctrl.h:797
#define LVIS_STATEIMAGEMASK
Definition: commctrl.h:2331
#define LVM_GETITEMW
Definition: commctrl.h:2395
#define HDN_ITEMCLICKW
Definition: commctrl.h:842
#define LVN_DELETEITEM
Definition: commctrl.h:3138
#define LVM_SORTITEMS
Definition: commctrl.h:2707
#define LVIS_FOCUSED
Definition: commctrl.h:2323
#define LV_VIEW_ICON
Definition: commctrl.h:2845
#define LVM_FINDITEMA
Definition: commctrl.h:2470
#define HDN_DIVIDERDBLCLICKA
Definition: commctrl.h:845
#define TME_HOVER
Definition: commctrl.h:4997
#define LVM_GETCOLUMNWIDTH
Definition: commctrl.h:2646
#define LVHT_ONITEMLABEL
Definition: commctrl.h:2500
int(CALLBACK * PFNLVCOMPARE)(LPARAM, LPARAM, LPARAM)
Definition: commctrl.h:2705
#define LVM_HITTEST
Definition: commctrl.h:2520
#define LVIF_GROUPID
Definition: commctrl.h:2320
#define LVM_GETTEXTBKCOLOR
Definition: commctrl.h:2665
#define LVS_AUTOARRANGE
Definition: commctrl.h:2277
#define LVS_LIST
Definition: commctrl.h:2269
#define LVM_GETISEARCHSTRINGW
Definition: commctrl.h:2720
#define ILC_COLOR
Definition: commctrl.h:352
#define LVN_ITEMACTIVATE
Definition: commctrl.h:3152
#define HDM_DELETEITEM
Definition: commctrl.h:743
#define LVSICF_NOINVALIDATEALL
Definition: commctrl.h:2698
#define HDI_ORDER
Definition: commctrl.h:710
#define LVM_GETSTRINGWIDTHW
Definition: commctrl.h:2492
#define LVM_GETHOTCURSOR
Definition: commctrl.h:2781
#define LVIR_BOUNDS
Definition: commctrl.h:2477
#define ILD_SELECTED
Definition: commctrl.h:430
#define I_INDENTCALLBACK
Definition: commctrl.h:2335
#define LVM_SETEXTENDEDLISTVIEWSTYLE
Definition: commctrl.h:2729
#define LVSIL_NORMAL
Definition: commctrl.h:2303
#define LVFI_NEARESTXY
Definition: commctrl.h:2446
#define LVIS_CUT
Definition: commctrl.h:2325
_In_ UINT uID
Definition: shlwapi.h:156
void redraw(int x, int y, int cx, int cy)
Definition: qtewin.cpp:1248
#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)
strcpy
Definition: string.h:131
#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:176
COLORREF clrBtnText
Definition: comctl32.h:173
COLORREF clrWindow
Definition: comctl32.h:182
COLORREF clr3dFace
Definition: comctl32.h:181
COLORREF clrWindowText
Definition: comctl32.h:183
COLORREF clrHighlight
Definition: comctl32.h:175
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:124
LONG x
Definition: windef.h:123
LONG cx
Definition: kdterminal.h:27
LONG cy
Definition: kdterminal.h:28
HWND hwnd
Definition: winuser.h:3690
UINT flags
Definition: winuser.h:3696
HWND hwndInsertAfter
Definition: winuser.h:3691
LPCWSTR lpszClassName
Definition: winuser.h:3287
HBRUSH hbrBackground
Definition: winuser.h:3285
int cbClsExtra
Definition: winuser.h:3280
UINT style
Definition: winuser.h:3278
WNDPROC lpfnWndProc
Definition: winuser.h:3279
int cbWndExtra
Definition: winuser.h:3281
HCURSOR hCursor
Definition: winuser.h:3284
Definition: inflate.c:139
Definition: fci.c:127
Definition: dsound.c:943
Definition: format.c:58
Definition: parser.c:49
ULONG_PTR itemData
Definition: winuser.h:3195
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:2573
LPWSTR pszText
Definition: commctrl.h:2572
LVITEMW item
Definition: commctrl.h:3184
UINT vkDirection
Definition: commctrl.h:2465
LPCWSTR psz
Definition: commctrl.h:2462
LPARAM lParam
Definition: commctrl.h:2463
LPWSTR pszText
Definition: commctrl.h:2370
int iSubItem
Definition: commctrl.h:2367
int cchTextMax
Definition: commctrl.h:2371
UINT state
Definition: commctrl.h:2368
UINT mask
Definition: commctrl.h:2365
LPARAM lParam
Definition: commctrl.h:2373
UINT stateMask
Definition: commctrl.h:2369
int iImage
Definition: commctrl.h:2372
int iIndent
Definition: commctrl.h:2374
ULONG_PTR itemData
Definition: winuser.h:3748
DWORD_PTR dwItemSpec
Definition: commctrl.h:307
UINT_PTR idFrom
Definition: winuser.h:3260
UINT code
Definition: winuser.h:3261
HWND hwndFrom
Definition: winuser.h:3259
NMHDR hdr
Definition: commctrl.h:881
HDITEMA * pitem
Definition: commctrl.h:884
HDITEMW * pitem
Definition: commctrl.h:891
POINT ptAction
Definition: commctrl.h:3044
UINT uNewState
Definition: commctrl.h:3041
LPARAM lParam
Definition: commctrl.h:3045
UINT uOldState
Definition: commctrl.h:3042
COLORREF clrTextBk
Definition: commctrl.h:3069
NMCUSTOMDRAW nmcd
Definition: commctrl.h:3067
COLORREF clrText
Definition: commctrl.h:3068
LVFINDINFOW lvfi
Definition: commctrl.h:3106
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
Definition: windef.h:99
LONG right
Definition: windef.h:102
LONG bottom
Definition: windef.h:103
LONG top
Definition: windef.h:101
LONG left
Definition: windef.h:100
DWORD styleNew
Definition: winuser.h:3795
DWORD styleOld
Definition: winuser.h:3794
ITEMHDR hdr
Definition: listview.c:163
LONG tmMaxCharWidth
Definition: wingdi.h:2835
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
_In_ size_t cnt
Definition: wcstombs.cpp:43
#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:1300
int WINAPI GetWindowTextW(HWND hWnd, LPWSTR lpString, int nMaxCount)
Definition: window.c:1382
_In_ LPWSTR _In_ ULONG _In_ ULONG _In_ ULONG _Out_ DEVINFO * pdi
Definition: winddi.h:3554
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4023
DWORD COLORREF
Definition: windef.h:94
HICON HCURSOR
Definition: windef.h:93
#define WINAPI
Definition: msvc.h:6
#define GetWindowFont(hwnd)
Definition: windowsx.h:311
#define DPA_GetPtr
Definition: commctrl.h:5
#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:860
#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:917
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 snprintf
Definition: wintirpc.h:48
#define SW_SHOWNORMAL
Definition: winuser.h:781
#define WM_PAINT
Definition: winuser.h:1648
HWND WINAPI SetCapture(_In_ HWND hWnd)
int WINAPI ReleaseDC(_In_opt_ HWND, _In_ HDC)
#define WM_ERASEBKGND
Definition: winuser.h:1653
#define SetWindowLongPtrA
Definition: winuser.h:5456
BOOL WINAPI IsWindow(_In_opt_ HWND)
#define MK_SHIFT
Definition: winuser.h:2405
#define ODS_SELECTED
Definition: winuser.h:2581
#define SW_HIDE
Definition: winuser.h:779
#define WM_CLOSE
Definition: winuser.h:1649
#define SWP_NOACTIVATE
Definition: winuser.h:1253
#define SB_THUMBTRACK
Definition: winuser.h:573
#define GetWindowLongPtrW
Definition: winuser.h:4931
HDC WINAPI GetWindowDC(_In_opt_ HWND)
#define WM_ENABLE
Definition: winuser.h:1643
#define SM_CYEDGE
Definition: winuser.h:1020
#define SM_CXDRAG
Definition: winuser.h:1039
#define SB_LINEUP
Definition: winuser.h:564
#define WM_HSCROLL
Definition: winuser.h:1771
#define SWP_FRAMECHANGED
Definition: winuser.h:1251
#define MAKELPARAM(l, h)
Definition: winuser.h:4110
#define EN_KILLFOCUS
Definition: winuser.h:2054
#define COLOR_WINDOW
Definition: winuser.h:929
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:2578
#define DCX_WINDOW
Definition: winuser.h:2149
LRESULT WINAPI DefWindowProcW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define SM_CXEDGE
Definition: winuser.h:1019
struct tagSCROLLINFO SCROLLINFO
#define WM_VSCROLL
Definition: winuser.h:1772
#define CreateWindowA(a, b, c, d, e, f, g, h, i, j, k)
Definition: winuser.h:4417
BOOL WINAPI GetWindowRect(_In_ HWND, _Out_ LPRECT)
#define SIF_RANGE
Definition: winuser.h:1246
#define WM_CREATE
Definition: winuser.h:1636
#define DLGC_WANTCHARS
Definition: winuser.h:2660
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:2057
#define SB_PAGERIGHT
Definition: winuser.h:571
#define SWP_DRAWFRAME
Definition: winuser.h:1250
#define VK_SPACE
Definition: winuser.h:2255
#define PRF_ERASEBKGND
Definition: winuser.h:2562
#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:2654
#define WM_LBUTTONDBLCLK
Definition: winuser.h:1806
#define SWP_NOMOVE
Definition: winuser.h:1255
#define WM_COMMAND
Definition: winuser.h:1768
#define DFCS_BUTTONCHECK
Definition: winuser.h:496
#define SW_INVALIDATE
Definition: winuser.h:2615
#define SM_CYICONSPACING
Definition: winuser.h:1013
#define ODA_FOCUS
Definition: winuser.h:2580
ATOM WINAPI RegisterClassW(_In_ CONST WNDCLASSW *)
#define IDC_ARROW
Definition: winuser.h:695
#define VK_CONTROL
Definition: winuser.h:2239
BOOL WINAPI GetCursorPos(_Out_ LPPOINT)
Definition: cursoricon.c:3047
#define DFC_BUTTON
Definition: winuser.h:476
int WINAPI GetWindowTextLengthA(_In_ HWND)
#define SM_CYSMICON
Definition: winuser.h:1024
#define VK_UP
Definition: winuser.h:2261
#define WM_RBUTTONDBLCLK
Definition: winuser.h:1809
BOOL WINAPI IsRectEmpty(_In_ LPCRECT)
#define WM_SETFOCUS
Definition: winuser.h:1641
HCURSOR WINAPI SetCursor(_In_opt_ HCURSOR)
#define SIF_PAGE
Definition: winuser.h:1244
#define SWP_NOSIZE
Definition: winuser.h:1256
#define WM_MOUSEMOVE
Definition: winuser.h:1803
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:659
#define SPI_GETICONTITLELOGFONT
Definition: winuser.h:1391
#define WM_LBUTTONDOWN
Definition: winuser.h:1804
#define NF_REQUERY
Definition: winuser.h:2497
#define WM_SYSCOLORCHANGE
Definition: winuser.h:1654
HCURSOR WINAPI LoadCursorW(_In_opt_ HINSTANCE, _In_ LPCWSTR)
Definition: cursoricon.c:2457
#define SIF_TRACKPOS
Definition: winuser.h:1248
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:1679
#define GWLP_HINSTANCE
Definition: winuser.h:867
UINT WINAPI GetDoubleClickTime(void)
Definition: ntwrapper.h:314
#define SM_CYHSCROLL
Definition: winuser.h:973
#define WM_DRAWITEM
Definition: winuser.h:1673
UINT_PTR WINAPI SetTimer(_In_opt_ HWND, _In_ UINT_PTR, _In_ UINT, _In_opt_ TIMERPROC)
#define VK_NEXT
Definition: winuser.h:2257
#define WM_NCCREATE
Definition: winuser.h:1711
#define HWND_DESKTOP
Definition: winuser.h:1220
#define WM_SHOWWINDOW
Definition: winuser.h:1656
#define WM_RBUTTONDOWN
Definition: winuser.h:1807
#define WM_SETTINGCHANGE
Definition: winuser.h:1657
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:1023
#define DT_LEFT
Definition: winuser.h:534
BOOL WINAPI GetClientRect(_In_ HWND, _Out_ LPRECT)
#define DCX_INTERSECTRGN
Definition: winuser.h:2158
#define VK_RETURN
Definition: winuser.h:2237
#define SM_CYICON
Definition: winuser.h:984
#define SB_LINELEFT
Definition: winuser.h:566
HWND WINAPI SetFocus(_In_opt_ HWND)
#define SPI_SETICONTITLELOGFONT
Definition: winuser.h:1394
#define MK_CONTROL
Definition: winuser.h:2406
#define EM_SETLIMITTEXT
Definition: winuser.h:2040
#define PM_NOYIELD
Definition: winuser.h:1208
BOOL WINAPI PeekMessageW(_Out_ LPMSG, _In_opt_ HWND, _In_ UINT, _In_ UINT, _In_ UINT)
#define WM_SETFONT
Definition: winuser.h:1678
#define VK_END
Definition: winuser.h:2258
#define VK_HOME
Definition: winuser.h:2259
BOOL WINAPI EndPaint(_In_ HWND, _In_ const PAINTSTRUCT *)
#define DLGC_WANTARROWS
Definition: winuser.h:2652
#define PM_REMOVE
Definition: winuser.h:1207
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:1243
#define SWP_SHOWWINDOW
Definition: winuser.h:1259
#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:2047
int WINAPI GetWindowTextLengthW(_In_ HWND)
#define PRF_CLIENT
Definition: winuser.h:2561
#define CreateWindowW(a, b, c, d, e, f, g, h, i, j, k)
Definition: winuser.h:4418
#define WM_MEASUREITEM
Definition: winuser.h:1674
#define WM_LBUTTONUP
Definition: winuser.h:1805
BOOL WINAPI SystemParametersInfoW(_In_ UINT uiAction, _In_ UINT uiParam, _Inout_opt_ PVOID pvParam, _In_ UINT fWinIni)
#define WM_CHAR
Definition: winuser.h:1745
BOOL WINAPI SetRectEmpty(_Out_ LPRECT)
HWND WINAPI GetParent(_In_ HWND)
#define GetClassLongPtrW
Definition: winuser.h:4666
#define CS_GLOBALCLASS
Definition: winuser.h:660
#define VK_LEFT
Definition: winuser.h:2260
#define NFR_ANSI
Definition: winuser.h:2494
#define SWP_HIDEWINDOW
Definition: winuser.h:1252
_In_ int _Inout_ LPRECT lprc
Definition: winuser.h:4568
#define WM_NCDESTROY
Definition: winuser.h:1712
#define VK_RIGHT
Definition: winuser.h:2262
LRESULT WINAPI DispatchMessageW(_In_ const MSG *)
#define SIF_POS
Definition: winuser.h:1245
#define VK_DOWN
Definition: winuser.h:2263
#define GWLP_ID
Definition: winuser.h:871
#define PRF_CHECKVISIBLE
Definition: winuser.h:2559
#define WM_SETCURSOR
Definition: winuser.h:1664
#define SW_ERASE
Definition: winuser.h:2616
#define WM_USER
Definition: winuser.h:1923
#define MK_LBUTTON
Definition: winuser.h:2403
#define SB_ENDSCROLL
Definition: winuser.h:574
BOOL WINAPI OffsetRect(_Inout_ LPRECT, _In_ int, _In_ int)
#define VK_SHIFT
Definition: winuser.h:2238
#define VK_PRIOR
Definition: winuser.h:2256
int WINAPI SetScrollInfo(_In_ HWND, _In_ int, _In_ LPCSCROLLINFO, _In_ BOOL)
#define WM_DESTROY
Definition: winuser.h:1637
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:1743
#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:3008
#define SWP_NOZORDER
Definition: winuser.h:1258
#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:5457
BOOL WINAPI InflateRect(_Inout_ LPRECT, _In_ int, _In_ int)
#define SM_CYDRAG
Definition: winuser.h:1040
LRESULT WINAPI CallWindowProcW(_In_ WNDPROC, _In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define NFR_UNICODE
Definition: winuser.h:2495
#define GWL_STYLE
Definition: winuser.h:863
BOOL WINAPI GetScrollInfo(_In_ HWND, _In_ int, _Inout_ LPSCROLLINFO)
#define SM_CXICON
Definition: winuser.h:983
#define VK_ESCAPE
Definition: winuser.h:2250
#define WM_WINDOWPOSCHANGED
Definition: winuser.h:1690
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:1642
#define GCLP_HBRBACKGROUND
Definition: winuser.h:680
#define ODS_FOCUS
Definition: winuser.h:2585
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:780
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:1012
#define WM_GETDLGCODE
Definition: winuser.h:1717
#define NF_QUERY
Definition: winuser.h:2496
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:2240
#define WM_NCPAINT
Definition: winuser.h:1715
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:1644
#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
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184
char * LPSTR
Definition: xmlstorage.h:182
char CHAR
Definition: xmlstorage.h:175