Ignore:
Timestamp:
May 15, 2003, 4:25:14 PM (22 years ago)
Author:
sandervl
Message:

Wine resync

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/comctl32/listview.c

    r9370 r10097  
    2323 *
    2424 * NOTES
    25  * Listview control implementation.
    26  *
     25 *
     26 * This code was audited for completeness against the documented features
     27 * of Comctl32.dll version 6.0 on Oct. 21, 2002, by Dimitrie O. Paun.
     28 *
     29 * Unless otherwise noted, we belive this code to be complete, as per
     30 * the specification mentioned above.
     31 * If you discover missing features, or bugs, please note them below.
     32 *
    2733 * TODO:
    28  *   1. No horizontal scrolling when header is larger than the client area.
    29  *   2. Drawing optimizations.
    30  *   3. Hot item handling.
    31  *
     34 *
     35 * Features
     36 *   -- Hot item handling, mouse hovering
     37 *   -- Workareas support
     38 *   -- Tilemode support
     39 *   -- Groups support
     40 *
     41 * Bugs
     42 *   -- Expand large item in ICON mode when the cursor is flying over the icon or text.
     43 *   -- Support CustonDraw options for _WIN32_IE >= 0x560 (see NMLVCUSTOMDRAW docs.
     44 *   -- in LISTVIEW_AddGroupSelection, se whould send LVN_ODSTATECHANGED
     45 *   -- LVA_SNAPTOGRID not implemented
     46 *   -- LISTVIEW_ApproximateViewRect partially implemented
     47 *   -- LISTVIEW_[GS]etColumnOrderArray stubs
     48 *   -- LISTVIEW_SetColumnWidth ignores header images & bitmap
     49 *   -- LISTVIEW_SetIconSpacing is incomplete
     50 *   -- LISTVIEW_SortItems is broken
     51 *   -- LISTVIEW_StyleChanged doesn't handle some changes too well
     52 *
     53 * Speedups
     54 *   -- LISTVIEW_GetNextItem needs to be rewritten. It is currently
     55 *      linear in the number of items in the list, and this is
     56 *      unacceptable for large lists.
     57 *   -- in sorted mode, LISTVIEW_InsertItemT sorts the array,
     58 *      instead of inserting in the right spot
     59 *   -- we should keep an ordered array of coordinates in iconic mode
     60 *      this would allow to frame items (iterator_frameditems),
     61 *      and find nearest item (LVFI_NEARESTXY) a lot more efficiently
     62 *
     63 * Flags
     64 *   -- LVIF_COLUMNS
     65 *   -- LVIF_GROUPID
     66 *   -- LVIF_NORECOMPUTE
     67 *
     68 * States
     69 *   -- LVIS_ACTIVATING (not currently supported by comctl32.dll version 6.0)
     70 *   -- LVIS_CUT
     71 *   -- LVIS_DROPHILITED
     72 *   -- LVIS_OVERLAYMASK
     73 *
     74 * Styles
     75 *   -- LVS_NOLABELWRAP
     76 *   -- LVS_NOSCROLL (see Q137520)
     77 *   -- LVS_SORTASCENDING, LVS_SORTDESCENDING
     78 *
     79 * Extended Styles
     80 *   -- LVS_EX_BORDERSELECT
     81 *   -- LVS_EX_CHECKBOXES
     82 *   -- LVS_EX_FLATSB
     83 *   -- LVS_EX_GRIDLINES
     84 *   -- LVS_EX_HEADERDRAGDROP
     85 *   -- LVS_EX_INFOTIP
     86 *   -- LVS_EX_LABELTIP
     87 *   -- LVS_EX_MULTIWORKAREAS
     88 *   -- LVS_EX_ONECLICKACTIVATE
     89 *   -- LVS_EX_REGIONAL
     90 *   -- LVS_EX_SIMPLESELECT
     91 *   -- LVS_EX_SUBITEMIMAGES
     92 *   -- LVS_EX_TRACKSELECT
     93 *   -- LVS_EX_TWOCLICKACTIVATE
     94 *   -- LVS_EX_UNDERLINECOLD
     95 *   -- LVS_EX_UNDERLINEHOT
     96 *   
    3297 * Notifications:
    33  *   LISTVIEW_Notify : most notifications from children (editbox and header)
    34  *
    35  * Data structure:
    36  *   LISTVIEW_SetItemCount : not completed for non OWNERDATA
    37  *
    38  * Advanced functionality:
    39  *   LISTVIEW_GetNumberOfWorkAreas : not implemented
    40  *   LISTVIEW_GetHotCursor : not implemented
    41  *   LISTVIEW_GetISearchString : not implemented
    42  *   LISTVIEW_GetBkImage : not implemented
    43  *   LISTVIEW_SetBkImage : not implemented
    44  *   LISTVIEW_GetColumnOrderArray : simple hack only
    45  *   LISTVIEW_SetColumnOrderArray : simple hack only
    46  *   LISTVIEW_Arrange : empty stub
    47  *   LISTVIEW_ApproximateViewRect : incomplete
    48  *   LISTVIEW_Scroll : not implemented
    49  *   LISTVIEW_Update : not completed
     98 *   -- LVN_BEGINDRAG, LVN_BEGINRDRAG
     99 *   -- LVN_BEGINSCROLL, LVN_ENDSCROLL
     100 *   -- LVN_GETINFOTIP
     101 *   -- LVN_HOTTRACK
     102 *   -- LVN_MARQUEEBEGIN
     103 *   -- LVN_ODFINDITEM
     104 *   -- LVN_ODSTATECHANGED
     105 *   -- LVN_SETDISPINFO
     106 *   -- NM_HOVER
     107 *
     108 * Messages:
     109 *   -- LVM_CANCELEDITLABEL
     110 *   -- LVM_CREATEDRAGIMAGE
     111 *   -- LVM_ENABLEGROUPVIEW
     112 *   -- LVM_GETBKIMAGE, LVM_SETBKIMAGE
     113 *   -- LVM_GETGROUPINFO, LVM_SETGROUPINFO
     114 *   -- LVM_GETGROUPMETRICS, LVM_SETGROUPMETRICS
     115 *   -- LVM_GETINSERTMARK, LVM_SETINSERTMARK
     116 *   -- LVM_GETINSERTMARKCOLOR, LVM_SETINSERTMARKCOLOR
     117 *   -- LVM_GETINSERTMARKRECT
     118 *   -- LVM_GETNUMBEROFWORKAREAS
     119 *   -- LVM_GETOUTLINECOLOR, LVM_SETOUTLINECOLOR
     120 *   -- LVM_GETSELECTEDCOLUMN, LVM_SETSELECTEDCOLUMN
     121 *   -- LVM_GETISEARCHSTRINGW, LVM_GETISEARCHSTRINGA
     122 *   -- LVM_GETTILEINFO, LVM_SETTILEINFO
     123 *   -- LVM_GETTILEVIEWINFO, LVM_SETTILEVIEWINFO
     124 *   -- LVM_GETTOOLTIPS, LVM_SETTOOLTIPS
     125 *   -- LVM_GETUNICODEFORMAT, LVM_SETUNICODEFORMAT
     126 *   -- LVM_GETVIEW, LVM_SETVIEW
     127 *   -- LVM_GETWORKAREAS, LVM_SETWORKAREAS
     128 *   -- LVM_HASGROUP, LVM_INSERTGROUP, LVM_REMOVEGROUP, LVM_REMOVEALLGROUPS
     129 *   -- LVM_INSERTGROUPSORTED
     130 *   -- LVM_INSERTMARKHITTEST
     131 *   -- LVM_ISGROUPVIEWENABLED
     132 *   -- LVM_MAPIDTOINDEX, LVM_MAPINDEXTOID
     133 *   -- LVM_MOVEGROUP
     134 *   -- LVM_MOVEITEMTOGROUP
     135 *   -- LVM_SETINFOTIP
     136 *   -- LVM_SETTILEWIDTH
     137 *   -- LVM_SORTGROUPS
     138 *   -- LVM_SORTITEMSEX
    50139 *
    51140 * Known differences in message stream from native control (not known if
     
    53142 *   LVM_INSERTITEM issues LVM_SETITEMSTATE and LVM_SETITEM in certain cases.
    54143 *   LVM_SETITEM does not always issue LVN_ITEMCHANGING/LVN_ITEMCHANGED.
    55  *   WM_PAINT does LVN_GETDISPINFO in item order 0->n, native does n->0.
    56  *   WM_SETREDRAW(True) native does LVN_GETDISPINFO for all items and
    57  *     does *not* invoke DefWindowProc
    58144 *   WM_CREATE does not issue WM_QUERYUISTATE and associated registry
    59145 *     processing for "USEDOUBLECLICKTIME".
    60146 */
    61147
     148#include "config.h"
     149#include "wine/port.h"
     150
     151#include <assert.h>
    62152#include <ctype.h>
    63153#include <string.h>
     
    67157#include "winbase.h"
    68158#include "winnt.h"
    69 #include "heap.h"
    70159#include "commctrl.h"
     160#include "comctl32.h"
     161
    71162#include "wine/debug.h"
     163#include "wine/unicode.h"
    72164
    73165WINE_DEFAULT_DEBUG_CHANNEL(listview);
    74166
    75 #ifdef __WIN32OS2__
    76 #include <heapstring.h>
    77 #include "ccbase.h"
    78 
    79 typedef struct
    80 {
    81   LVITEMW header;
    82   BOOL mustFree;
    83   BOOL unicode;
    84 } LVINTERNALITEMW, *LPLVINTERNALITEMW;
    85 
    86 #define IF_NOREDRAW     1
    87 
    88 #endif
    89 
    90 /* Some definitions for inline edit control */   
    91 typedef BOOL (*EditlblCallbackW)(HWND, LPWSTR, DWORD);
    92 typedef BOOL (*EditlblCallbackA)(HWND, LPWSTR, DWORD);
    93 
    94 typedef struct tagLV_INTHIT
    95 {
    96   LVHITTESTINFO  ht;
    97   DWORD          distance;     /* distance to closest item    */
    98   INT            iDistItem;    /* item number that is closest */
    99 } LV_INTHIT, *LPLV_INTHIT;
    100        
    101 
    102 typedef struct tagEDITLABEL_ITEM
    103 {
    104   WNDPROC EditWndProc;
    105   DWORD param;
    106   EditlblCallbackW EditLblCb;
    107 } EDITLABEL_ITEM;
    108 
    109 typedef struct tagLISTVIEW_SUBITEM
     167/* make sure you set this to 0 for production use! */
     168#define DEBUG_RANGES 1
     169
     170typedef struct tagCOLUMN_INFO
     171{
     172  RECT rcHeader;        /* tracks the header's rectangle */
     173  int fmt;              /* same as LVCOLUMN.fmt */
     174} COLUMN_INFO;
     175
     176typedef struct tagITEMHDR
    110177{
    111178  LPWSTR pszText;
    112179  INT iImage;
     180} ITEMHDR, *LPITEMHDR;
     181
     182typedef struct tagSUBITEM_INFO
     183{
     184  ITEMHDR hdr;
    113185  INT iSubItem;
    114 } LISTVIEW_SUBITEM;
    115 
    116 typedef struct tagLISTVIEW_ITEM
    117 {
     186} SUBITEM_INFO;
     187
     188typedef struct tagITEM_INFO
     189{
     190  ITEMHDR hdr;
    118191  UINT state;
    119   LPWSTR pszText;
    120   INT iImage;
    121192  LPARAM lParam;
    122193  INT iIndent;
    123   POINT ptPosition;
    124 
    125 } LISTVIEW_ITEM;
    126 
    127 typedef struct tagLISTVIEW_SELECTION
    128 {
    129   DWORD lower;
    130   DWORD upper;
    131 } LISTVIEW_SELECTION;
     194} ITEM_INFO;
     195
     196typedef struct tagRANGE
     197{
     198  INT lower;
     199  INT upper;
     200} RANGE;
     201
     202typedef struct tagRANGES
     203{
     204  HDPA hdpa;
     205} *RANGES;
     206
     207typedef struct tagITERATOR
     208{
     209  INT nItem;
     210  INT nSpecial;
     211  RANGE range;
     212  RANGES ranges;
     213  INT index;
     214} ITERATOR;
    132215
    133216typedef struct tagLISTVIEW_INFO
    134217{
    135 #ifdef __WIN32OS2__
    136     COMCTL32_HEADER   header;
    137     HCURSOR           hHotCursor;
    138     LPWSTR            pszISearch;
    139     UINT              uISearchLen;
    140     DWORD             dwISearchTime;
    141     INT               nWorkAreas;
    142     RECT             *rcWorkAreas;
    143     HWND              hwndToolTip;
    144     POINT             lefttop;      //in scroll units
    145     POINT             maxScroll;    //in scroll units
    146     POINT             scrollPage;   //in scroll units
    147     POINT             scrollStep;   //in pixels
    148     DWORD             internalFlags;
    149     BOOL              bDragInProcess;
    150 #endif
    151218  HWND hwndSelf;
     219  HBRUSH hBkBrush;
    152220  COLORREF clrBk;
    153221  COLORREF clrText;
    154222  COLORREF clrTextBk;
     223  COLORREF clrTextBkDefault;
    155224  HIMAGELIST himlNormal;
    156225  HIMAGELIST himlSmall;
     
    158227  BOOL bLButtonDown;
    159228  BOOL bRButtonDown;
    160   INT nFocusedItem;
    161   HDPA hdpaSelectionRanges;
     229  BOOL bNoItemMetrics;          /* flags if item metrics are not yet computed */
    162230  INT nItemHeight;
    163231  INT nItemWidth;
     232  RANGES selectionRanges;
    164233  INT nSelectionMark;
    165234  INT nHotItem;
    166235  SHORT notifyFormat;
    167   RECT rcList;
    168   RECT rcView;
     236  RECT rcList;                 /* This rectangle is really the window
     237                                * client rectangle possibly reduced by the
     238                                * horizontal scroll bar and/or header - see
     239                                * LISTVIEW_UpdateSize. This rectangle offset
     240                                * by the LISTVIEW_GetOrigin value is in
     241                                * client coordinates   */
    169242  SIZE iconSize;
    170243  SIZE iconSpacing;
     244  SIZE iconStateSize;
    171245  UINT uCallbackMask;
    172246  HWND hwndHeader;
     247  HCURSOR hHotCursor;
    173248  HFONT hDefaultFont;
    174249  HFONT hFont;
    175   INT ntmHeight;               /*  from GetTextMetrics from above font */
    176   INT ntmAveCharWidth;         /*  from GetTextMetrics from above font */
     250  INT ntmHeight;                /* Some cached metrics of the font used */
     251  INT ntmAveCharWidth;          /* by the listview to draw items */
     252  BOOL bRedraw;                 /* Turns on/off repaints & invalidations */
     253  BOOL bFirstPaint;             /* Flags if the control has never painted before */
     254  BOOL bAutoarrange;            /* Autoarrange flag when NOT in LVS_AUTOARRANGE */
    177255  BOOL bFocus;
    178   DWORD dwExStyle;             /* extended listview style */
    179   HDPA hdpaItems;
     256  BOOL bDoChangeNotify;                /* send change notification messages? */
     257  INT nFocusedItem;
     258  RECT rcFocus;
     259  DWORD dwStyle;                /* the cached window GWL_STYLE */
     260  DWORD dwLvExStyle;            /* extended listview style */
     261  INT nItemCount;               /* the number of items in the list */
     262  HDPA hdpaItems;               /* array ITEM_INFO pointers */
     263  HDPA hdpaPosX;                /* maintains the (X, Y) coordinates of the */
     264  HDPA hdpaPosY;                /* items in LVS_ICON, and LVS_SMALLICON modes */
     265  HDPA hdpaColumns;             /* array of COLUMN_INFO pointers */
     266  POINT currIconPos;            /* this is the position next icon will be placed */
    180267  PFNLVCOMPARE pfnCompare;
    181268  LPARAM lParamSort;
    182269  HWND hwndEdit;
     270  WNDPROC EditWndProc;
    183271  INT nEditLabelItem;
    184   EDITLABEL_ITEM *pedititem;
    185272  DWORD dwHoverTime;
    186   INT nColumnCount;            /* the number of columns in this control */
    187 
    188   DWORD lastKeyPressTimestamp; /* Added */
    189   WPARAM charCode;             /* Added */
    190   INT nSearchParamLength;      /* Added */
    191   WCHAR szSearchParam[ MAX_PATH ]; /* Added */
     273  HWND hwndToolTip;
     274
     275  DWORD lastKeyPressTimestamp;
     276  WPARAM charCode;
     277  INT nSearchParamLength;
     278  WCHAR szSearchParam[ MAX_PATH ];
     279  BOOL bIsDrawing;
    192280} LISTVIEW_INFO;
    193281
    194282/*
    195  * constants
    196  */
     283 * constants
     284 */
     285/* How many we debug buffer to allocate */
     286#define DEBUG_BUFFERS 20
     287/* The size of a single debug bbuffer */
     288#define DEBUG_BUFFER_SIZE 256
     289
     290/* Internal interface to LISTVIEW_HScroll and LISTVIEW_VScroll */
     291#define SB_INTERNAL      -1
    197292
    198293/* maximum size of a label */
     
    214309 *   ICON_TOP_PADDING - sum of the two above.
    215310 *   ICON_BOTTOM_PADDING - between bottom of icon and top of text
    216  *   LABEL_VERT_OFFSET - between bottom of text and end of box
     311 *   LABEL_HOR_PADDING - between text and sides of box
     312 *   LABEL_VERT_PADDING - between bottom of text and end of box
     313 *
     314 *   ICON_LR_PADDING - additional width above icon size.
     315 *   ICON_LR_HALF - half of the above value
    217316 */
    218317#define ICON_TOP_PADDING_NOTHITABLE  2
    219318#define ICON_TOP_PADDING_HITABLE     2
    220 #define ICON_TOP_PADDING ICON_TOP_PADDING_NOTHITABLE + ICON_TOP_PADDING_HITABLE
    221 #define ICON_BOTTOM_PADDING 4
    222 #define LABEL_VERT_OFFSET 10
     319#define ICON_TOP_PADDING (ICON_TOP_PADDING_NOTHITABLE + ICON_TOP_PADDING_HITABLE)
     320#define ICON_BOTTOM_PADDING          4
     321#define LABEL_HOR_PADDING            5
     322#define LABEL_VERT_PADDING           7
     323#define ICON_LR_PADDING              16
     324#define ICON_LR_HALF                 (ICON_LR_PADDING/2)
    223325
    224326/* default label width for items in list and small icon display modes */
     
    226328
    227329/* default column width for items in list display mode */
    228 #define DEFAULT_COLUMN_WIDTH 96
    229 
    230 /* Increment size of the horizontal scroll bar */
    231 #define LISTVIEW_SCROLL_DIV_SIZE 10
     330#define DEFAULT_COLUMN_WIDTH 128
     331
     332/* Size of "line" scroll for V & H scrolls */
     333#define LISTVIEW_SCROLL_ICON_LINE_SIZE 37
    232334
    233335/* Padding betwen image and label */
     
    235337
    236338/* Padding behind the label */
    237 #define TRAILING_PADDING  5
     339#define TRAILING_LABEL_PADDING  12
     340#define TRAILING_HEADER_PADDING  11
    238341
    239342/* Border for the icon caption */
    240343#define CAPTION_BORDER  2
    241 /*
    242  * macros
    243  */
    244 /* retrieve the number of items in the listview */
    245 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
    246 #define HDM_INSERTITEMT(isW) ( (isW) ? HDM_INSERTITEMW : HDM_INSERTITEMA )
    247 
    248 HWND CreateEditLabelT(LPCWSTR text, DWORD style, INT x, INT y,
    249         INT width, INT height, HWND parent, HINSTANCE hinst,
    250         EditlblCallbackW EditLblCb, DWORD param, BOOL isW);
    251  
    252 /*
    253  * forward declarations
    254  */
    255 static LRESULT LISTVIEW_GetItemT(HWND hwnd, LPLVITEMW lpLVItem, BOOL internal, BOOL isW);
    256 static INT LISTVIEW_SuperHitTestItem(HWND, LPLV_INTHIT, BOOL);
    257 static INT LISTVIEW_HitTestItem(HWND, LPLVHITTESTINFO, BOOL);
    258 static INT LISTVIEW_GetCountPerRow(HWND);
    259 static INT LISTVIEW_GetCountPerColumn(HWND);
    260 static VOID LISTVIEW_AlignLeft(HWND);
    261 static VOID LISTVIEW_AlignTop(HWND);
    262 static VOID LISTVIEW_AddGroupSelection(HWND, INT);
    263 static VOID LISTVIEW_AddSelection(HWND, INT);
    264 static BOOL LISTVIEW_AddSubItemT(HWND, LPLVITEMW, BOOL);
    265 static INT LISTVIEW_FindInsertPosition(HDPA, INT);
    266 static INT LISTVIEW_GetItemHeight(HWND);
    267 static BOOL LISTVIEW_GetItemBoundBox(HWND, INT, LPRECT);
    268 static BOOL LISTVIEW_GetItemPosition(HWND, INT, LPPOINT);
    269 static LRESULT LISTVIEW_GetItemRect(HWND, INT, LPRECT);
    270 static INT LISTVIEW_GetItemWidth(HWND);
    271 static INT LISTVIEW_GetLabelWidth(HWND, INT);
    272 static LRESULT LISTVIEW_GetOrigin(HWND, LPPOINT);
    273 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem);
    274 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA, INT);
    275 static LRESULT LISTVIEW_GetViewRect(HWND, LPRECT);
    276 static BOOL LISTVIEW_InitItemT(HWND, LISTVIEW_ITEM *, LPLVITEMW, BOOL);
    277 static BOOL LISTVIEW_InitSubItemT(HWND, LISTVIEW_SUBITEM *, LPLVITEMW, BOOL);
    278 static LRESULT LISTVIEW_MouseSelection(HWND, POINT);
    279 static BOOL LISTVIEW_RemoveColumn(HDPA, INT);
    280 static BOOL LISTVIEW_RemoveSubItem(HDPA, INT);
    281 static VOID LISTVIEW_SetGroupSelection(HWND, INT);
    282 static BOOL LISTVIEW_SetItemT(HWND, LPLVITEMW, BOOL);
    283 static BOOL LISTVIEW_SetItemFocus(HWND, INT);
    284 static BOOL LISTVIEW_SetItemPosition(HWND, INT, LONG, LONG);
    285 static VOID LISTVIEW_UpdateScroll(HWND);
    286 static VOID LISTVIEW_SetSelection(HWND, INT);
    287 static BOOL LISTVIEW_UpdateSize(HWND);
    288 static BOOL LISTVIEW_SetSubItemT(HWND, LPLVITEMW, BOOL);
    289 static LRESULT LISTVIEW_SetViewRect(HWND, LPRECT);
    290 static BOOL LISTVIEW_ToggleSelection(HWND, INT);
    291 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle);
    292 static HWND LISTVIEW_EditLabelT(HWND hwnd, INT nItem, BOOL isW);
    293 static BOOL LISTVIEW_EndEditLabelW(HWND hwnd, LPWSTR pszText, DWORD nItem);
    294 static BOOL LISTVIEW_EndEditLabelA(HWND hwnd, LPSTR pszText, DWORD nItem);
    295 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam);
    296 static LRESULT LISTVIEW_SortItems(HWND hwnd, PFNLVCOMPARE pfnCompare, LPARAM lParamSort);
    297 static LRESULT LISTVIEW_GetStringWidthT(HWND hwnd, LPCWSTR lpszText, BOOL isW);
    298 static INT LISTVIEW_ProcessLetterKeys( HWND hwnd, WPARAM charCode, LPARAM keyData );
    299 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem);
    300 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask);
    301 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMW lpLVItem);
    302 static BOOL LISTVIEW_IsSelected(HWND hwnd, INT nItem);
    303 static VOID LISTVIEW_RemoveSelectionRange(HWND hwnd, INT lItem, INT uItem);
    304 static void LISTVIEW_FillBackground(HWND hwnd, HDC hdc, LPRECT rc);
    305 static void ListView_UpdateLargeItemLabelRect (HWND hwnd, const LISTVIEW_INFO* infoPtr, int nItem, RECT *rect);
    306 static LRESULT LISTVIEW_GetColumnT(HWND, INT, LPLVCOLUMNW, BOOL);
    307 
    308 /******** Defines that LISTVIEW_ProcessLetterKeys uses ****************/
     344
     345/* Standard DrawText flags */
     346#define LV_ML_DT_FLAGS  (DT_TOP | DT_NOPREFIX | DT_EDITCONTROL | DT_CENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS | DT_END_ELLIPSIS)
     347#define LV_FL_DT_FLAGS  (DT_TOP | DT_NOPREFIX | DT_EDITCONTROL | DT_CENTER | DT_WORDBREAK | DT_NOCLIP)
     348#define LV_SL_DT_FLAGS  (DT_TOP | DT_EDITCONTROL | DT_SINGLELINE | DT_WORD_ELLIPSIS | DT_END_ELLIPSIS)
     349
     350/* The time in milliseconds to reset the search in the list */
    309351#define KEY_DELAY       450
    310352
    311 #define COUNTOF(array) (sizeof(array)/sizeof(array[0]))
     353/* Dump the LISTVIEW_INFO structure to the debug channel */
     354#define LISTVIEW_DUMP(iP) do { \
     355  TRACE("hwndSelf=%p, clrBk=0x%06lx, clrText=0x%06lx, clrTextBk=0x%06lx, ItemHeight=%d, ItemWidth=%d, Style=0x%08lx\n", \
     356        iP->hwndSelf, iP->clrBk, iP->clrText, iP->clrTextBk, \
     357        iP->nItemHeight, iP->nItemWidth, infoPtr->dwStyle); \
     358  TRACE("hwndSelf=%p, himlNor=%p, himlSml=%p, himlState=%p, Focused=%d, Hot=%d, exStyle=0x%08lx, Focus=%d\n", \
     359        iP->hwndSelf, iP->himlNormal, iP->himlSmall, iP->himlState, \
     360        iP->nFocusedItem, iP->nHotItem, iP->dwLvExStyle, iP->bFocus ); \
     361  TRACE("hwndSelf=%p, ntmH=%d, icSz.cx=%ld, icSz.cy=%ld, icSp.cx=%ld, icSp.cy=%ld, notifyFmt=%d\n", \
     362        iP->hwndSelf, iP->ntmHeight, iP->iconSize.cx, iP->iconSize.cy, \
     363        iP->iconSpacing.cx, iP->iconSpacing.cy, iP->notifyFormat); \
     364  TRACE("hwndSelf=%p, rcList=%s\n", iP->hwndSelf, debugrect(&iP->rcList)); \
     365} while(0)
     366
     367/*
     368 * forward declarations
     369 */
     370static BOOL LISTVIEW_GetItemT(LISTVIEW_INFO *, LPLVITEMW, BOOL);
     371static void LISTVIEW_GetItemBox(LISTVIEW_INFO *, INT, LPRECT);
     372static void LISTVIEW_GetItemOrigin(LISTVIEW_INFO *, INT, LPPOINT);
     373static BOOL LISTVIEW_GetItemPosition(LISTVIEW_INFO *, INT, LPPOINT);
     374static BOOL LISTVIEW_GetItemRect(LISTVIEW_INFO *, INT, LPRECT);
     375static INT LISTVIEW_GetLabelWidth(LISTVIEW_INFO *, INT);
     376static void LISTVIEW_GetOrigin(LISTVIEW_INFO *, LPPOINT);
     377static BOOL LISTVIEW_GetViewRect(LISTVIEW_INFO *, LPRECT);
     378static void LISTVIEW_SetGroupSelection(LISTVIEW_INFO *, INT);
     379static BOOL LISTVIEW_SetItemT(LISTVIEW_INFO *, const LVITEMW *, BOOL);
     380static void LISTVIEW_UpdateScroll(LISTVIEW_INFO *);
     381static void LISTVIEW_SetSelection(LISTVIEW_INFO *, INT);
     382static void LISTVIEW_UpdateSize(LISTVIEW_INFO *);
     383static HWND LISTVIEW_EditLabelT(LISTVIEW_INFO *, INT, BOOL);
     384static LRESULT LISTVIEW_Command(LISTVIEW_INFO *, WPARAM, LPARAM);
     385static BOOL LISTVIEW_SortItems(LISTVIEW_INFO *, PFNLVCOMPARE, LPARAM);
     386static INT LISTVIEW_GetStringWidthT(LISTVIEW_INFO *, LPCWSTR, BOOL);
     387static BOOL LISTVIEW_KeySelection(LISTVIEW_INFO *, INT);
     388static UINT LISTVIEW_GetItemState(LISTVIEW_INFO *, INT, UINT);
     389static BOOL LISTVIEW_SetItemState(LISTVIEW_INFO *, INT, const LVITEMW *);
     390static LRESULT LISTVIEW_VScroll(LISTVIEW_INFO *, INT, INT, HWND);
     391static LRESULT LISTVIEW_HScroll(LISTVIEW_INFO *, INT, INT, HWND);
     392static INT LISTVIEW_GetTopIndex(LISTVIEW_INFO *);
     393static BOOL LISTVIEW_EnsureVisible(LISTVIEW_INFO *, INT, BOOL);
     394static HWND CreateEditLabelT(LISTVIEW_INFO *, LPCWSTR, DWORD, INT, INT, INT, INT, BOOL);
     395
     396/******** Text handling functions *************************************/
     397
     398/* A text pointer is either NULL, LPSTR_TEXTCALLBACK, or points to a
     399 * text string. The string may be ANSI or Unicode, in which case
     400 * the boolean isW tells us the type of the string.
     401 *
     402 * The name of the function tell what type of strings it expects:
     403 *   W: Unicode, T: ANSI/Unicode - function of isW
     404 */
    312405
    313406static inline BOOL is_textW(LPCWSTR text)
    314407{
    315   return text != NULL && text != LPSTR_TEXTCALLBACKW;
     408    return text != NULL && text != LPSTR_TEXTCALLBACKW;
    316409}
    317410
    318411static inline BOOL is_textT(LPCWSTR text, BOOL isW)
    319412{
    320   /* we can ignore isW since LPSTR_TEXTCALLBACKW == LPSTR_TEXTCALLBACKA */
    321   return is_textW(text);
     413    /* we can ignore isW since LPSTR_TEXTCALLBACKW == LPSTR_TEXTCALLBACKA */
     414    return is_textW(text);
    322415}
    323416
    324417static inline int textlenT(LPCWSTR text, BOOL isW)
    325418{
    326   return !is_textT(text, isW) ? 0 :
    327          isW ? lstrlenW(text) : lstrlenA((LPCSTR)text);
     419    return !is_textT(text, isW) ? 0 :
     420           isW ? lstrlenW(text) : lstrlenA((LPCSTR)text);
    328421}
    329422
    330423static inline void textcpynT(LPWSTR dest, BOOL isDestW, LPCWSTR src, BOOL isSrcW, INT max)
    331424{
    332   if (isDestW)
    333     if (isSrcW) lstrcpynW(dest, src, max);
    334     else MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1, dest, max);
    335   else
    336     if (isSrcW) WideCharToMultiByte(CP_ACP, 0, src, -1, (LPSTR)dest, max, NULL, NULL);
    337     else lstrcpynA((LPSTR)dest, (LPCSTR)src, max);
    338 }
    339 
    340 static inline LPCSTR debugstr_t(LPCWSTR text, BOOL isW)
    341 {
    342   return NULL;
    343 }
    344 
    345 static inline LPCSTR debugstr_tn(LPCWSTR text, BOOL isW, INT n)
    346 {
    347   return NULL;
     425    if (isDestW)
     426        if (isSrcW) lstrcpynW(dest, src, max);
     427        else MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1, dest, max);
     428    else
     429        if (isSrcW) WideCharToMultiByte(CP_ACP, 0, src, -1, (LPSTR)dest, max, NULL, NULL);
     430        else lstrcpynA((LPSTR)dest, (LPCSTR)src, max);
    348431}
    349432
    350433static inline LPWSTR textdupTtoW(LPCWSTR text, BOOL isW)
    351434{
    352   LPWSTR wstr = (LPWSTR)text;
    353  
    354   TRACE("(text=%s, isW=%d)\n", debugstr_t(text, isW), isW); 
    355   if (!isW && text)
    356   {
    357     INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)text, -1, NULL, 0);
    358     wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
    359     if (wstr) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)text, -1, wstr, len);
    360   }
    361   TRACE("   wstr=%s\n", debugstr_w(wstr));
    362   return wstr;
     435    LPWSTR wstr = (LPWSTR)text;
     436
     437    if (!isW && is_textT(text, isW))
     438    {
     439        INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)text, -1, NULL, 0);
     440        wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
     441        if (wstr) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)text, -1, wstr, len);
     442    }
     443    TRACE("   wstr=%s\n", text == LPSTR_TEXTCALLBACKW ?  "(callback)" : debugstr_w(wstr));
     444    return wstr;
    363445}
    364446
    365447static inline void textfreeT(LPWSTR wstr, BOOL isW)
    366448{
    367   if (!isW && wstr) HeapFree(GetProcessHeap(), 0, wstr);
     449    if (!isW && is_textT(wstr, isW)) HeapFree(GetProcessHeap(), 0, wstr);
    368450}
    369451
     
    372454 * src is a pointer to a string (Unicode if isW, ANSI if !isW)
    373455 */
    374 static inline BOOL textsetptrT(LPWSTR *dest, LPWSTR src, BOOL isW)
    375 {
    376     LPWSTR pszText = textdupTtoW(src, isW);
     456static BOOL textsetptrT(LPWSTR *dest, LPWSTR src, BOOL isW)
     457{
    377458    BOOL bResult = TRUE;
    378     if (*dest == LPSTR_TEXTCALLBACKW) *dest = NULL;
    379     bResult = Str_SetPtrW(dest, pszText);
    380     textfreeT(pszText, isW);
     459   
     460    if (src == LPSTR_TEXTCALLBACKW)
     461    {
     462        if (is_textW(*dest)) COMCTL32_Free(*dest);
     463        *dest = LPSTR_TEXTCALLBACKW;
     464    }
     465    else
     466    {
     467        LPWSTR pszText = textdupTtoW(src, isW);
     468        if (*dest == LPSTR_TEXTCALLBACKW) *dest = NULL;
     469        bResult = Str_SetPtrW(dest, pszText);
     470        textfreeT(pszText, isW);
     471    }
    381472    return bResult;
    382473}
    383474
    384 static inline LRESULT CallWindowProcT(WNDPROC proc, HWND hwnd, UINT uMsg,
    385                                       WPARAM wParam, LPARAM lParam, BOOL isW)
    386 {
    387   if (isW)
    388     return CallWindowProcW(proc, hwnd, uMsg, wParam, lParam);
    389   else
    390     return CallWindowProcA(proc, hwnd, uMsg, wParam, lParam);
    391 }
    392 
    393 static inline BOOL notify(HWND self, INT code, LPNMHDR pnmh)
    394 {
    395   pnmh->hwndFrom = self;
    396   pnmh->idFrom = GetWindowLongW(self, GWL_ID);
    397   pnmh->code = code;
    398   return (BOOL)SendMessageW(GetParent(self), WM_NOTIFY,
    399                             (WPARAM)pnmh->idFrom, (LPARAM)pnmh);
    400 }
    401 
    402 static inline BOOL hdr_notify(HWND self, INT code)
    403 {
    404   NMHDR nmh;
    405   return notify(self, code, &nmh);
    406 }
    407 
    408 static inline BOOL listview_notify(HWND self, INT code, LPNMLISTVIEW plvnm)
    409 {
    410   return notify(self, code, (LPNMHDR)plvnm);
    411 }
    412 
    413 static int tabNotification[] = {
    414   LVN_BEGINLABELEDITW, LVN_BEGINLABELEDITA,
    415   LVN_ENDLABELEDITW, LVN_ENDLABELEDITA,
    416   LVN_GETDISPINFOW, LVN_GETDISPINFOA,
    417   LVN_SETDISPINFOW, LVN_SETDISPINFOA,
    418   LVN_ODFINDITEMW, LVN_ODFINDITEMA,
    419   LVN_GETINFOTIPW, LVN_GETINFOTIPA,
    420   0
    421 };
     475/*
     476 * compares a Unicode to a Unicode/ANSI text string
     477 */
     478static inline int textcmpWT(LPCWSTR aw, LPCWSTR bt, BOOL isW)
     479{
     480    if (!aw) return bt ? -1 : 0;
     481    if (!bt) return aw ? 1 : 0;
     482    if (aw == LPSTR_TEXTCALLBACKW)
     483        return bt == LPSTR_TEXTCALLBACKW ? 0 : -1;
     484    if (bt != LPSTR_TEXTCALLBACKW)
     485    {
     486        LPWSTR bw = textdupTtoW(bt, isW);
     487        int r = bw ? lstrcmpW(aw, bw) : 1;
     488        textfreeT(bw, isW);
     489        return r;
     490    }       
     491           
     492    return 1;
     493}
     494   
     495static inline int lstrncmpiW(LPCWSTR s1, LPCWSTR s2, int n)
     496{
     497    int res;
     498
     499    n = min(min(n, strlenW(s1)), strlenW(s2));
     500    res = CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, s1, n, s2, n);
     501    return res ? res - sizeof(WCHAR) : res;
     502}
     503
     504/******** Debugging functions *****************************************/
     505
     506#if defined(__WIN32OS2__) && !defined(DEBUG)
     507//can be removed when switching to GCC
     508#define debugtext_t( text,  isW)        0
     509#define debugtext_tn( text,  isW,  n)   0
     510#define debug_getbuf() 0
     511#define debugrange(lprng) 0
     512#define debugpoint(lppt)  0
     513#define debugrect(rect)   0
     514#define debugscrollinfo(pScrollInfo) 0
     515#define debugnmlistview(plvnm) 0
     516#define debuglvitem_t(lpLVItem,  isW) 0
     517#define debuglvcolumn_t(lpColumn,  isW) 0
     518#define debuglvhittestinfo(lpht) 0
     519#define debugscrollcode(nScrollCode) 0
     520#else
     521static inline LPCSTR debugtext_t(LPCWSTR text, BOOL isW)
     522{
     523    if (text == LPSTR_TEXTCALLBACKW) return "(callback)";
     524    return isW ? debugstr_w(text) : debugstr_a((LPCSTR)text);
     525}
     526
     527static inline LPCSTR debugtext_tn(LPCWSTR text, BOOL isW, INT n)
     528{
     529    if (text == LPSTR_TEXTCALLBACKW) return "(callback)";
     530    n = min(textlenT(text, isW), n);
     531    return isW ? debugstr_wn(text, n) : debugstr_an((LPCSTR)text, n);
     532}
     533
     534static char* debug_getbuf()
     535{
     536    static int index = 0;
     537    static char buffers[DEBUG_BUFFERS][DEBUG_BUFFER_SIZE];
     538    return buffers[index++ % DEBUG_BUFFERS];
     539}
     540
     541static inline char* debugrange(const RANGE *lprng)
     542{
     543    if (lprng)
     544    {
     545        char* buf = debug_getbuf();
     546        snprintf(buf, DEBUG_BUFFER_SIZE, "[%d, %d)", lprng->lower, lprng->upper);
     547        return buf;
     548    } else return "(null)";
     549}
     550
     551static inline char* debugpoint(const POINT *lppt)
     552{
     553    if (lppt)
     554    {
     555        char* buf = debug_getbuf();
     556        snprintf(buf, DEBUG_BUFFER_SIZE, "(%ld, %ld)", lppt->x, lppt->y);
     557        return buf;
     558    } else return "(null)";
     559}
     560
     561static inline char* debugrect(const RECT *rect)
     562{
     563    if (rect)
     564    {
     565        char* buf = debug_getbuf();
     566        snprintf(buf, DEBUG_BUFFER_SIZE, "[(%ld, %ld);(%ld, %ld)]",
     567                 rect->left, rect->top, rect->right, rect->bottom);
     568        return buf;
     569    } else return "(null)";
     570}
     571
     572static char * debugscrollinfo(const SCROLLINFO *pScrollInfo)
     573{
     574    char* buf = debug_getbuf(), *text = buf;
     575    int len, size = DEBUG_BUFFER_SIZE;
     576   
     577    if (pScrollInfo == NULL) return "(null)";
     578    len = snprintf(buf, size, "{cbSize=%d, ", pScrollInfo->cbSize);
     579    if (len == -1) goto end; buf += len; size -= len;
     580    if (pScrollInfo->fMask & SIF_RANGE)
     581        len = snprintf(buf, size, "nMin=%d, nMax=%d, ", pScrollInfo->nMin, pScrollInfo->nMax);
     582    else len = 0;
     583    if (len == -1) goto end; buf += len; size -= len;
     584    if (pScrollInfo->fMask & SIF_PAGE)
     585        len = snprintf(buf, size, "nPage=%u, ", pScrollInfo->nPage);
     586    else len = 0;
     587    if (len == -1) goto end; buf += len; size -= len;
     588    if (pScrollInfo->fMask & SIF_POS)
     589        len = snprintf(buf, size, "nPos=%d, ", pScrollInfo->nPos);
     590    else len = 0;
     591    if (len == -1) goto end; buf += len; size -= len;
     592    if (pScrollInfo->fMask & SIF_TRACKPOS)
     593        len = snprintf(buf, size, "nTrackPos=%d, ", pScrollInfo->nTrackPos);
     594    else len = 0;
     595    if (len == -1) goto end; buf += len; size -= len;
     596    goto undo;
     597end:
     598    buf = text + strlen(text);
     599undo:
     600    if (buf - text > 2) { buf[-2] = '}'; buf[-1] = 0; }
     601    return text;
     602}
     603
     604static char* debugnmlistview(const NMLISTVIEW *plvnm)
     605{
     606    if (plvnm)
     607    {
     608        char* buf = debug_getbuf();
     609        snprintf(buf, DEBUG_BUFFER_SIZE, "iItem=%d, iSubItem=%d, uNewState=0x%x,"
     610                 " uOldState=0x%x, uChanged=0x%x, ptAction=%s, lParam=%ld\n",
     611                 plvnm->iItem, plvnm->iSubItem, plvnm->uNewState, plvnm->uOldState,
     612                 plvnm->uChanged, debugpoint(&plvnm->ptAction), plvnm->lParam);
     613        return buf;
     614    } else return "(null)";
     615}
     616
     617static char* debuglvitem_t(const LVITEMW *lpLVItem, BOOL isW)
     618{
     619    char* buf = debug_getbuf(), *text = buf;
     620    int len, size = DEBUG_BUFFER_SIZE;
     621   
     622    if (lpLVItem == NULL) return "(null)";
     623    len = snprintf(buf, size, "{iItem=%d, iSubItem=%d, ", lpLVItem->iItem, lpLVItem->iSubItem);
     624    if (len == -1) goto end; buf += len; size -= len;
     625    if (lpLVItem->mask & LVIF_STATE)
     626        len = snprintf(buf, size, "state=%x, stateMask=%x, ", lpLVItem->state, lpLVItem->stateMask);
     627    else len = 0;
     628    if (len == -1) goto end; buf += len; size -= len;
     629    if (lpLVItem->mask & LVIF_TEXT)
     630        len = snprintf(buf, size, "pszText=%s, cchTextMax=%d, ", debugtext_tn(lpLVItem->pszText, isW, 80), lpLVItem->cchTextMax);
     631    else len = 0;
     632    if (len == -1) goto end; buf += len; size -= len;
     633    if (lpLVItem->mask & LVIF_IMAGE)
     634        len = snprintf(buf, size, "iImage=%d, ", lpLVItem->iImage);
     635    else len = 0;
     636    if (len == -1) goto end; buf += len; size -= len;
     637    if (lpLVItem->mask & LVIF_PARAM)
     638        len = snprintf(buf, size, "lParam=%lx, ", lpLVItem->lParam);
     639    else len = 0;
     640    if (len == -1) goto end; buf += len; size -= len;
     641    if (lpLVItem->mask & LVIF_INDENT)
     642        len = snprintf(buf, size, "iIndent=%d, ", lpLVItem->iIndent);
     643    else len = 0;
     644    if (len == -1) goto end; buf += len; size -= len;
     645    goto undo;
     646end:
     647    buf = text + strlen(text);
     648undo:
     649    if (buf - text > 2) { buf[-2] = '}'; buf[-1] = 0; }
     650    return text;
     651}
     652
     653static char* debuglvcolumn_t(const LVCOLUMNW *lpColumn, BOOL isW)
     654{
     655    char* buf = debug_getbuf(), *text = buf;
     656    int len, size = DEBUG_BUFFER_SIZE;
     657   
     658    if (lpColumn == NULL) return "(null)";
     659    len = snprintf(buf, size, "{");
     660    if (len == -1) goto end; buf += len; size -= len;
     661    if (lpColumn->mask & LVCF_SUBITEM)
     662        len = snprintf(buf, size, "iSubItem=%d, ",  lpColumn->iSubItem);
     663    else len = 0;
     664    if (len == -1) goto end; buf += len; size -= len;
     665    if (lpColumn->mask & LVCF_FMT)
     666        len = snprintf(buf, size, "fmt=%x, ", lpColumn->fmt);
     667    else len = 0;
     668    if (len == -1) goto end; buf += len; size -= len;
     669    if (lpColumn->mask & LVCF_WIDTH)
     670        len = snprintf(buf, size, "cx=%d, ", lpColumn->cx);
     671    else len = 0;
     672    if (len == -1) goto end; buf += len; size -= len;
     673    if (lpColumn->mask & LVCF_TEXT)
     674        len = snprintf(buf, size, "pszText=%s, cchTextMax=%d, ", debugtext_tn(lpColumn->pszText, isW, 80), lpColumn->cchTextMax);
     675    else len = 0;
     676    if (len == -1) goto end; buf += len; size -= len;
     677    if (lpColumn->mask & LVCF_IMAGE)
     678        len = snprintf(buf, size, "iImage=%d, ", lpColumn->iImage);
     679    else len = 0;
     680    if (len == -1) goto end; buf += len; size -= len;
     681    if (lpColumn->mask & LVCF_ORDER)
     682        len = snprintf(buf, size, "iOrder=%d, ", lpColumn->iOrder);
     683    else len = 0;
     684    if (len == -1) goto end; buf += len; size -= len;
     685    goto undo;
     686end:
     687    buf = text + strlen(text);
     688undo:
     689    if (buf - text > 2) { buf[-2] = '}'; buf[-1] = 0; }
     690    return text;
     691}
     692
     693static char* debuglvhittestinfo(const LVHITTESTINFO *lpht)
     694{
     695    if (lpht)
     696    {
     697        char* buf = debug_getbuf();
     698        snprintf(buf, DEBUG_BUFFER_SIZE, "{pt=%s, flags=0x%x, iItem=%d, iSubItem=%d}",
     699                 debugpoint(&lpht->pt), lpht->flags, lpht->iItem, lpht->iSubItem);
     700        return buf;
     701    } else return "(null)";
     702}
     703
     704/* Return the corresponding text for a given scroll value */
     705static inline LPCSTR debugscrollcode(int nScrollCode)
     706{
     707  switch(nScrollCode)
     708  {
     709  case SB_LINELEFT: return "SB_LINELEFT";
     710  case SB_LINERIGHT: return "SB_LINERIGHT";
     711  case SB_PAGELEFT: return "SB_PAGELEFT";
     712  case SB_PAGERIGHT: return "SB_PAGERIGHT";
     713  case SB_THUMBPOSITION: return "SB_THUMBPOSITION";
     714  case SB_THUMBTRACK: return "SB_THUMBTRACK";
     715  case SB_ENDSCROLL: return "SB_ENDSCROLL";
     716  case SB_INTERNAL: return "SB_INTERNAL";
     717  default: return "unknown";
     718  }
     719}
     720#endif
     721
     722/******** Notification functions i************************************/
     723
     724static LRESULT notify_hdr(LISTVIEW_INFO *infoPtr, INT code, LPNMHDR pnmh)
     725{
     726    LRESULT result;
     727   
     728    TRACE("(code=%d)\n", code);
     729
     730    pnmh->hwndFrom = infoPtr->hwndSelf;
     731    pnmh->idFrom = GetWindowLongW(infoPtr->hwndSelf, GWL_ID);
     732    pnmh->code = code;
     733    result = SendMessageW(GetParent(infoPtr->hwndSelf), WM_NOTIFY,
     734                          (WPARAM)pnmh->idFrom, (LPARAM)pnmh);
     735
     736    TRACE("  <= %ld\n", result);
     737
     738    return result;
     739}
     740
     741static inline LRESULT notify(LISTVIEW_INFO *infoPtr, INT code)
     742{
     743    NMHDR nmh;
     744    return notify_hdr(infoPtr, code, &nmh);
     745}
     746
     747static inline void notify_itemactivate(LISTVIEW_INFO *infoPtr)
     748{
     749    notify(infoPtr, LVN_ITEMACTIVATE);
     750}
     751
     752static inline LRESULT notify_listview(LISTVIEW_INFO *infoPtr, INT code, LPNMLISTVIEW plvnm)
     753{
     754    TRACE("(code=%d, plvnm=%s)\n", code, debugnmlistview(plvnm));
     755    return notify_hdr(infoPtr, code, (LPNMHDR)plvnm);
     756}
     757
     758static LRESULT notify_click(LISTVIEW_INFO *infoPtr,  INT code, LVHITTESTINFO *lvht)
     759{
     760    NMLISTVIEW nmlv;
     761    LVITEMW item;
     762   
     763    TRACE("code=%d, lvht=%s\n", code, debuglvhittestinfo(lvht));
     764    ZeroMemory(&nmlv, sizeof(nmlv));
     765    nmlv.iItem = lvht->iItem;
     766    nmlv.iSubItem = lvht->iSubItem;
     767    nmlv.ptAction = lvht->pt;
     768    item.mask = LVIF_PARAM;
     769    item.iItem = lvht->iItem;
     770    item.iSubItem = 0;
     771    if (LISTVIEW_GetItemT(infoPtr, &item, TRUE)) nmlv.lParam = item.lParam;
     772    return notify_listview(infoPtr, code, &nmlv);
     773}
     774
     775static void notify_deleteitem(LISTVIEW_INFO *infoPtr, INT nItem)
     776{
     777    NMLISTVIEW nmlv;
     778    LVITEMW item;
     779   
     780    ZeroMemory(&nmlv, sizeof (NMLISTVIEW));
     781    nmlv.iItem = nItem;
     782    item.mask = LVIF_PARAM;
     783    item.iItem = nItem;
     784    item.iSubItem = 0;
     785    if (LISTVIEW_GetItemT(infoPtr, &item, TRUE)) nmlv.lParam = item.lParam;
     786    notify_listview(infoPtr, LVN_DELETEITEM, &nmlv);
     787}
    422788
    423789static int get_ansi_notification(INT unicodeNotificationCode)
    424790{
    425   int *pTabNotif = tabNotification;
    426   while (*pTabNotif && (unicodeNotificationCode != *pTabNotif++));
    427   if (*pTabNotif) return *pTabNotif;
    428   ERR("unknown notification %x\n", unicodeNotificationCode);
    429   return unicodeNotificationCode;
     791    switch (unicodeNotificationCode)
     792    {
     793    case LVN_BEGINLABELEDITW: return LVN_BEGINLABELEDITA;
     794    case LVN_ENDLABELEDITW: return LVN_ENDLABELEDITA;
     795    case LVN_GETDISPINFOW: return LVN_GETDISPINFOA;
     796    case LVN_SETDISPINFOW: return LVN_SETDISPINFOA;
     797    case LVN_ODFINDITEMW: return LVN_ODFINDITEMA;
     798    case LVN_GETINFOTIPW: return LVN_GETINFOTIPA;
     799    }
     800    ERR("unknown notification %x\n", unicodeNotificationCode);
     801    assert(FALSE);
     802    return 0;
    430803}
    431804
    432805/*
    433   Send notification. depends on dispinfoW having same
    434   structure as dispinfoA.
    435   self : listview handle
     806  With testing on Windows 2000 it looks like the notify format
     807  has nothing to do with this message. It ALWAYS seems to be
     808  in ansi format.
     809
     810  infoPtr : listview struct
    436811  notificationCode : *Unicode* notification code
    437812  pdi : dispinfo structure (can be unicode or ansi)
    438813  isW : TRUE if dispinfo is Unicode
    439814*/
    440 static BOOL dispinfo_notifyT(HWND self, INT notificationCode, LPNMLVDISPINFOW pdi, BOOL isW)
    441 {
    442   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(self, 0);
    443   BOOL bResult = FALSE;
    444   BOOL convertToAnsi = FALSE, convertToUnicode = FALSE;
    445   INT realNotifCode;
    446   INT cchTempBufMax = 0, savCchTextMax = 0;
    447   LPWSTR pszTempBuf = NULL, savPszText = NULL;
    448 
    449   TRACE("(self=%x, code=%x, pdi=%p, isW=%d)\n", self, notificationCode, pdi, isW);
    450   TRACE("   notifyFormat=%s\n",
    451         infoPtr->notifyFormat == NFR_UNICODE ? "NFR_UNICODE" :
    452         infoPtr->notifyFormat == NFR_ANSI ? "NFR_ANSI" : "(not set)");
    453   if (infoPtr->notifyFormat == NFR_ANSI)
    454     realNotifCode = get_ansi_notification(notificationCode);
    455   else
    456     realNotifCode = notificationCode;
    457 
    458   if (is_textT(pdi->item.pszText, isW))
    459   {
    460     if (isW && infoPtr->notifyFormat == NFR_ANSI)
    461         convertToAnsi = TRUE;
    462     if (!isW && infoPtr->notifyFormat == NFR_UNICODE)
    463         convertToUnicode = TRUE;
    464   }
    465  
    466   if (convertToAnsi || convertToUnicode)
    467   {
    468     TRACE("   we have to convert the text to the correct format\n");
    469     if (notificationCode != LVN_GETDISPINFOW)
    470     { /* length of existing text */
    471       cchTempBufMax = convertToUnicode ?
    472       MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pdi->item.pszText, -1, NULL, 0):
    473       WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, NULL, 0, NULL, NULL);
     815static BOOL notify_dispinfoT(LISTVIEW_INFO *infoPtr, INT notificationCode, LPNMLVDISPINFOW pdi, BOOL isW)
     816{
     817    BOOL bResult = FALSE;
     818    BOOL convertToAnsi = FALSE;
     819    INT cchTempBufMax = 0, savCchTextMax = 0;
     820    LPWSTR pszTempBuf = NULL, savPszText = NULL;
     821
     822    if ((pdi->item.mask & LVIF_TEXT) && is_textT(pdi->item.pszText, isW))
     823            convertToAnsi = isW;
     824
     825    if (convertToAnsi)
     826    {
     827        if (notificationCode != LVN_GETDISPINFOW)
     828        {
     829            cchTempBufMax = WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText,
     830                                                -1, NULL, 0, NULL, NULL);
     831        }
     832        else
     833        {
     834            cchTempBufMax = pdi->item.cchTextMax;
     835            *pdi->item.pszText = 0; /* make sure we don't process garbage */
     836        }
     837
     838        pszTempBuf = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR) *
     839                               cchTempBufMax);
     840        if (!pszTempBuf) return FALSE;
     841
     842        WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, (LPSTR)
     843                             pszTempBuf, cchTempBufMax, NULL, NULL);
     844
     845        savCchTextMax = pdi->item.cchTextMax;
     846        savPszText = pdi->item.pszText;
     847        pdi->item.pszText = pszTempBuf;
     848        pdi->item.cchTextMax = cchTempBufMax;
     849    }
     850
     851    TRACE(" pdi->item=%s\n", debuglvitem_t(&pdi->item, infoPtr->notifyFormat !=
     852           NFR_ANSI));
     853
     854    bResult = notify_hdr(infoPtr, get_ansi_notification(notificationCode),
     855                        (LPNMHDR)pdi);
     856
     857    if (convertToAnsi)
     858    {
     859        MultiByteToWideChar(CP_ACP, 0, (LPSTR) pdi->item.pszText, -1,
     860                            savPszText, savCchTextMax);
     861        pdi->item.pszText = savPszText; /* restores our buffer */
     862        pdi->item.cchTextMax = savCchTextMax;
     863        HeapFree(GetProcessHeap(), 0, pszTempBuf);
     864    }
     865    return bResult;
     866}
     867
     868static void customdraw_fill(NMLVCUSTOMDRAW *lpnmlvcd, LISTVIEW_INFO *infoPtr, HDC hdc,
     869                            const RECT *rcBounds, const LVITEMW *lplvItem)
     870{
     871    ZeroMemory(lpnmlvcd, sizeof(NMLVCUSTOMDRAW));
     872    lpnmlvcd->nmcd.hdc = hdc;
     873    lpnmlvcd->nmcd.rc = *rcBounds;
     874    lpnmlvcd->clrTextBk = infoPtr->clrTextBk;
     875    lpnmlvcd->clrText   = infoPtr->clrText;
     876    if (!lplvItem) return;
     877    lpnmlvcd->nmcd.dwItemSpec = lplvItem->iItem + 1;
     878    lpnmlvcd->iSubItem = lplvItem->iSubItem;
     879    if (lplvItem->state & LVIS_SELECTED) lpnmlvcd->nmcd.uItemState |= CDIS_SELECTED;
     880    if (lplvItem->state & LVIS_FOCUSED) lpnmlvcd->nmcd.uItemState |= CDIS_FOCUS;
     881    if (lplvItem->iItem == infoPtr->nHotItem) lpnmlvcd->nmcd.uItemState |= CDIS_HOT;
     882    lpnmlvcd->nmcd.lItemlParam = lplvItem->lParam;
     883}
     884
     885static inline DWORD notify_customdraw (LISTVIEW_INFO *infoPtr, DWORD dwDrawStage, NMLVCUSTOMDRAW *lpnmlvcd)
     886{
     887    BOOL isForItem = (lpnmlvcd->nmcd.dwItemSpec != 0);
     888    DWORD result;
     889
     890    lpnmlvcd->nmcd.dwDrawStage = dwDrawStage;
     891    if (isForItem) lpnmlvcd->nmcd.dwDrawStage |= CDDS_ITEM;
     892    if (lpnmlvcd->iSubItem) lpnmlvcd->nmcd.dwDrawStage |= CDDS_SUBITEM;
     893    if (isForItem) lpnmlvcd->nmcd.dwItemSpec--;
     894    result = notify_hdr(infoPtr, NM_CUSTOMDRAW, &lpnmlvcd->nmcd.hdr);
     895    if (isForItem) lpnmlvcd->nmcd.dwItemSpec++;
     896    return result;
     897}
     898
     899static DWORD notify_prepaint (LISTVIEW_INFO *infoPtr, HDC hdc, NMLVCUSTOMDRAW *lpnmlvcd)
     900{
     901    BOOL isSelected = lpnmlvcd->nmcd.uItemState & CDIS_SELECTED;
     902    DWORD cditemmode = notify_customdraw(infoPtr, CDDS_PREPAINT, lpnmlvcd);
     903
     904    if (cditemmode & CDRF_SKIPDEFAULT) return cditemmode;
     905
     906    /* apprently, for selected items, we have to override the returned values */
     907    if (isSelected)
     908    {
     909        if (infoPtr->bFocus)
     910        {
     911            lpnmlvcd->clrTextBk = comctl32_color.clrHighlight;
     912            lpnmlvcd->clrText   = comctl32_color.clrHighlightText;
     913        }
     914        else if (infoPtr->dwStyle & LVS_SHOWSELALWAYS)
     915        {
     916            lpnmlvcd->clrTextBk = comctl32_color.clr3dFace;
     917            lpnmlvcd->clrText   = comctl32_color.clrBtnText;
     918        }
     919    }
     920
     921    /* Set the text attributes */
     922    if (lpnmlvcd->clrTextBk != CLR_NONE)
     923    {
     924        SetBkMode(hdc, OPAQUE);
     925        if (lpnmlvcd->clrTextBk == CLR_DEFAULT)
     926            SetBkColor(hdc, infoPtr->clrTextBkDefault);
     927        else
     928            SetBkColor(hdc,lpnmlvcd->clrTextBk);
    474929    }
    475930    else
    476       cchTempBufMax = pdi->item.cchTextMax;
    477 
    478     pszTempBuf = HeapAlloc(GetProcessHeap(), 0,
    479         (convertToUnicode ? sizeof(WCHAR) : sizeof(CHAR)) * cchTempBufMax);
    480     if (!pszTempBuf) return FALSE;
    481     if (convertToUnicode)
    482       MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pdi->item.pszText, -1,
    483                           pszTempBuf, cchTempBufMax);
     931        SetBkMode(hdc, TRANSPARENT);
     932    SetTextColor(hdc, lpnmlvcd->clrText);
     933
     934    return cditemmode;
     935}
     936
     937static inline DWORD notify_postpaint (LISTVIEW_INFO *infoPtr, NMLVCUSTOMDRAW *lpnmlvcd)
     938{
     939    return notify_customdraw(infoPtr, CDDS_POSTPAINT, lpnmlvcd);
     940}
     941
     942/******** Item iterator functions **********************************/
     943
     944static RANGES ranges_create(int count);
     945static void ranges_destroy(RANGES ranges);
     946static BOOL ranges_add(RANGES ranges, RANGE range);
     947static BOOL ranges_del(RANGES ranges, RANGE range);
     948static void ranges_dump(RANGES ranges);
     949
     950static inline BOOL ranges_additem(RANGES ranges, INT nItem)
     951{
     952    RANGE range = { nItem, nItem + 1 };
     953
     954    return ranges_add(ranges, range);
     955}
     956
     957static inline BOOL ranges_delitem(RANGES ranges, INT nItem)
     958{
     959    RANGE range = { nItem, nItem + 1 };
     960
     961    return ranges_del(ranges, range);
     962}
     963
     964/***
     965 * ITERATOR DOCUMENTATION
     966 *
     967 * The iterator functions allow for easy, and convenient iteration
     968 * over items of iterest in the list. Typically, you create a
     969 * iterator, use it, and destroy it, as such:
     970 *   ITERATOR i;
     971 *
     972 *   iterator_xxxitems(&i, ...);
     973 *   while (iterator_{prev,next}(&i)
     974 *   {
     975 *       //code which uses i.nItem
     976 *   }
     977 *   iterator_destroy(&i);
     978 *
     979 *   where xxx is either: framed, or visible.
     980 * Note that it is important that the code destroys the iterator
     981 * after it's done with it, as the creation of the iterator may
     982 * allocate memory, which thus needs to be freed.
     983 *
     984 * You can iterate both forwards, and backwards through the list,
     985 * by using iterator_next or iterator_prev respectively.
     986 *
     987 * Lower numbered items are draw on top of higher number items in
     988 * LVS_ICON, and LVS_SMALLICON (which are the only modes where
     989 * items may overlap). So, to test items, you should use
     990 *    iterator_next
     991 * which lists the items top to bottom (in Z-order).
     992 * For drawing items, you should use
     993 *    iterator_prev
     994 * which lists the items bottom to top (in Z-order).
     995 * If you keep iterating over the items after the end-of-items
     996 * marker (-1) is returned, the iterator will start from the
     997 * beginning. Typically, you don't need to test for -1,
     998 * because iterator_{next,prev} will return TRUE if more items
     999 * are to be iterated over, or FALSE otherwise.
     1000 *
     1001 * Note: the iterator is defined to be bidirectional. That is,
     1002 *       any number of prev followed by any number of next, or
     1003 *       five versa, should leave the iterator at the same item:
     1004 *           prev * n, next * n = next * n, prev * n
     1005 *
     1006 * The iterator has a notion of a out-of-order, special item,
     1007 * which sits at the start of the list. This is used in
     1008 * LVS_ICON, and LVS_SMALLICON mode to handle the focused item,
     1009 * which needs to be first, as it may overlap other items.
     1010 *           
     1011 * The code is a bit messy because we have:
     1012 *   - a special item to deal with
     1013 *   - simple range, or composite range
     1014 *   - empty range.
     1015 * If you find bugs, or want to add features, please make sure you
     1016 * always check/modify *both* iterator_prev, and iterator_next.
     1017 */
     1018
     1019/****
     1020 * This function iterates through the items in increasing order,
     1021 * but prefixed by the special item, then -1. That is:
     1022 *    special, 1, 2, 3, ..., n, -1.
     1023 * Each item is listed only once.
     1024 */
     1025static inline BOOL iterator_next(ITERATOR* i)
     1026{
     1027    if (i->nItem == -1)
     1028    {
     1029        i->nItem = i->nSpecial;
     1030        if (i->nItem != -1) return TRUE;
     1031    }
     1032    if (i->nItem == i->nSpecial)
     1033    {
     1034        if (i->ranges) i->index = 0;
     1035        goto pickarange;
     1036    }
     1037
     1038    i->nItem++;
     1039testitem:
     1040    if (i->nItem == i->nSpecial) i->nItem++;
     1041    if (i->nItem < i->range.upper) return TRUE;
     1042
     1043pickarange:
     1044    if (i->ranges)
     1045    {
     1046        if (i->index < i->ranges->hdpa->nItemCount)
     1047            i->range = *(RANGE*)DPA_GetPtr(i->ranges->hdpa, i->index++);
     1048        else goto end;
     1049    }
     1050    else if (i->nItem >= i->range.upper) goto end;
     1051
     1052    i->nItem = i->range.lower;
     1053    if (i->nItem >= 0) goto testitem;
     1054end:
     1055    i->nItem = -1;
     1056    return FALSE;
     1057}
     1058
     1059/****
     1060 * This function iterates through the items in decreasing order,
     1061 * followed by the special item, then -1. That is:
     1062 *    n, n-1, ..., 3, 2, 1, special, -1.
     1063 * Each item is listed only once.
     1064 */
     1065static inline BOOL iterator_prev(ITERATOR* i)
     1066{
     1067    BOOL start = FALSE;
     1068
     1069    if (i->nItem == -1)
     1070    {
     1071        start = TRUE;
     1072        if (i->ranges) i->index = i->ranges->hdpa->nItemCount;
     1073        goto pickarange;
     1074    }
     1075    if (i->nItem == i->nSpecial)
     1076    {
     1077        i->nItem = -1;
     1078        return FALSE;
     1079    }
     1080
     1081testitem:
     1082    i->nItem--;
     1083    if (i->nItem == i->nSpecial) i->nItem--;
     1084    if (i->nItem >= i->range.lower) return TRUE;
     1085
     1086pickarange:
     1087    if (i->ranges)
     1088    {
     1089        if (i->index > 0)
     1090            i->range = *(RANGE*)DPA_GetPtr(i->ranges->hdpa, --i->index);
     1091        else goto end;
     1092    }
     1093    else if (!start && i->nItem < i->range.lower) goto end;
     1094
     1095    i->nItem = i->range.upper;
     1096    if (i->nItem > 0) goto testitem;
     1097end:
     1098    return (i->nItem = i->nSpecial) != -1;
     1099}
     1100
     1101static RANGE iterator_range(ITERATOR* i)
     1102{
     1103    RANGE range;
     1104
     1105    if (!i->ranges) return i->range;
     1106
     1107    range.lower = (*(RANGE*)DPA_GetPtr(i->ranges->hdpa, 0)).lower;
     1108    range.upper = (*(RANGE*)DPA_GetPtr(i->ranges->hdpa, i->ranges->hdpa->nItemCount - 1)).upper;
     1109    return range;
     1110}
     1111
     1112/***
     1113 * Releases resources associated with this ierator.
     1114 */
     1115static inline void iterator_destroy(ITERATOR* i)
     1116{
     1117    ranges_destroy(i->ranges);
     1118}
     1119
     1120/***
     1121 * Create an empty iterator.
     1122 */
     1123static inline BOOL iterator_empty(ITERATOR* i)
     1124{
     1125    ZeroMemory(i, sizeof(*i));
     1126    i->nItem = i->nSpecial = i->range.lower = i->range.upper = -1;
     1127    return TRUE;
     1128}
     1129
     1130/***
     1131 * Create an iterator over a range.
     1132 */
     1133static inline BOOL iterator_rangeitems(ITERATOR* i, RANGE range)
     1134{
     1135    iterator_empty(i);
     1136    i->range = range;
     1137    return TRUE;
     1138}
     1139
     1140/***
     1141 * Create an iterator over a bunch of ranges.
     1142 * Please note that the iterator will take ownership of the ranges,
     1143 * and will free them upon destruction.
     1144 */
     1145static inline BOOL iterator_rangesitems(ITERATOR* i, RANGES ranges)
     1146{
     1147    iterator_empty(i);
     1148    i->ranges = ranges;
     1149    return TRUE;
     1150}
     1151
     1152/***
     1153 * Creates an iterator over the items which intersect lprc.
     1154 */
     1155static BOOL iterator_frameditems(ITERATOR* i, LISTVIEW_INFO* infoPtr, const RECT *lprc)
     1156{
     1157    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     1158    RECT frame = *lprc, rcItem, rcTemp;
     1159    POINT Origin;
     1160   
     1161    /* in case we fail, we want to return an empty iterator */
     1162    if (!iterator_empty(i)) return FALSE;
     1163
     1164    LISTVIEW_GetOrigin(infoPtr, &Origin);
     1165
     1166    TRACE("(lprc=%s)\n", debugrect(lprc));
     1167    OffsetRect(&frame, -Origin.x, -Origin.y);
     1168
     1169    if (uView == LVS_ICON || uView == LVS_SMALLICON)
     1170    {
     1171        INT nItem;
     1172       
     1173        if (uView == LVS_ICON && infoPtr->nFocusedItem != -1)
     1174        {
     1175            LISTVIEW_GetItemBox(infoPtr, infoPtr->nFocusedItem, &rcItem);
     1176            if (IntersectRect(&rcTemp, &rcItem, lprc))
     1177                i->nSpecial = infoPtr->nFocusedItem;
     1178        }
     1179        if (!(iterator_rangesitems(i, ranges_create(50)))) return FALSE;
     1180        /* to do better here, we need to have PosX, and PosY sorted */
     1181        TRACE("building icon ranges:\n");
     1182        for (nItem = 0; nItem < infoPtr->nItemCount; nItem++)
     1183        {
     1184            rcItem.left = (LONG)DPA_GetPtr(infoPtr->hdpaPosX, nItem);
     1185            rcItem.top = (LONG)DPA_GetPtr(infoPtr->hdpaPosY, nItem);
     1186            rcItem.right = rcItem.left + infoPtr->nItemWidth;
     1187            rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
     1188            if (IntersectRect(&rcTemp, &rcItem, &frame))
     1189                ranges_additem(i->ranges, nItem);
     1190        }
     1191        return TRUE;
     1192    }
     1193    else if (uView == LVS_REPORT)
     1194    {
     1195        RANGE range;
     1196       
     1197        if (frame.left >= infoPtr->nItemWidth) return TRUE;
     1198        if (frame.top >= infoPtr->nItemHeight * infoPtr->nItemCount) return TRUE;
     1199       
     1200        range.lower = max(frame.top / infoPtr->nItemHeight, 0);
     1201        range.upper = min((frame.bottom - 1) / infoPtr->nItemHeight, infoPtr->nItemCount - 1) + 1;
     1202        if (range.upper <= range.lower) return TRUE;
     1203        if (!iterator_rangeitems(i, range)) return FALSE;
     1204        TRACE("    report=%s\n", debugrange(&i->range));
     1205    }
    4841206    else
    485       WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, (LPSTR) pszTempBuf,
    486                           cchTempBufMax, NULL, NULL);
    487     TRACE("   text=%s\n", debugstr_t(pszTempBuf, convertToUnicode));
    488     savCchTextMax = pdi->item.cchTextMax;
    489     savPszText = pdi->item.pszText;
    490     pdi->item.pszText = pszTempBuf;
    491     pdi->item.cchTextMax = cchTempBufMax;
    492   }
    493  
    494   bResult = notify(self, realNotifCode, (LPNMHDR)pdi);
    495  
    496   if (convertToUnicode || convertToAnsi)
    497   { /* convert back result */
    498     TRACE("   returned text=%s\n", debugstr_t(pdi->item.pszText, convertToUnicode));
    499     if (convertToUnicode) /* note : pointer can be changed by app ! */
    500       WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, (LPSTR) savPszText,
    501                           savCchTextMax, NULL, NULL);
    502     else
    503       MultiByteToWideChar(CP_ACP, 0, (LPSTR) pdi->item.pszText, -1,
    504                           savPszText, savCchTextMax);
    505     pdi->item.pszText = savPszText; /* restores our buffer */
    506     pdi->item.cchTextMax = savCchTextMax;
    507     HeapFree(GetProcessHeap(), 0, pszTempBuf);
    508   }
    509   return bResult;
    510 }
    511 
    512 static inline LRESULT LISTVIEW_GetItemW(HWND hwnd, LPLVITEMW lpLVItem, BOOL internal)
    513 {
    514   return LISTVIEW_GetItemT(hwnd, lpLVItem, internal, TRUE);
    515 }
    516 
    517 static inline int lstrncmpiW(LPCWSTR s1, LPCWSTR s2, int n)
    518 {
    519   int res;
    520 
    521   n = min(min(n, strlenW(s1)), strlenW(s2));
    522   res = CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, s1, n, s2, n);
    523   return res ? res - 2 : res;
    524 }
    525 
    526 static char* debuglvitem_t(LPLVITEMW lpLVItem, BOOL isW)
    527 {
    528   static int index = 0;
    529   static char buffers[20][256];
    530   char* buf = buffers[index++ % 20];
    531   if (lpLVItem == NULL) return "(null)";
    532   return buf;
    533 }
    534 
    535 static char* debuglvcolumn_t(LPLVCOLUMNW lpColumn, BOOL isW)
    536 {
    537   static int index = 0;
    538   static char buffers[20][256];
    539   char* buf = buffers[index++ % 20];
    540   if (lpColumn == NULL) return "(null)";
    541   return buf;
    542 }
    543 
    544 static void LISTVIEW_DumpListview(LISTVIEW_INFO *iP, INT line)
    545 {
    546   DWORD dwStyle = GetWindowLongW (iP->hwndSelf, GWL_STYLE);
    547   TRACE("listview %08x at line %d, clrBk=0x%06lx, clrText=0x%06lx, clrTextBk=0x%06lx, ItemHeight=%d, ItemWidth=%d, Style=0x%08lx\n",
    548         iP->hwndSelf, line, iP->clrBk, iP->clrText, iP->clrTextBk,
    549         iP->nItemHeight, iP->nItemWidth, dwStyle);
    550   TRACE("listview %08x at line %d, himlNor=%p, himlSml=%p, himlState=%p, Focused=%d, Hot=%d, exStyle=0x%08lx\n",
    551         iP->hwndSelf, line, iP->himlNormal, iP->himlSmall, iP->himlState,
    552         iP->nFocusedItem, iP->nHotItem, iP->dwExStyle);
    553 }
    554 
    555 static BOOL
    556 LISTVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
    557                                RECT rc)
    558 {
    559   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    560   NMLVCUSTOMDRAW nmcdhdr;
    561   LPNMCUSTOMDRAW nmcd;
    562 
    563   TRACE("(hwnd=%x, dwDrawStage=%lx, hdc=%x, rc=?)\n", hwnd, dwDrawStage, hdc);
    564 
    565   nmcd= & nmcdhdr.nmcd;
    566   nmcd->hdr.hwndFrom = hwnd;
    567   nmcd->hdr.idFrom =  GetWindowLongW( hwnd, GWL_ID);
    568   nmcd->hdr.code   = NM_CUSTOMDRAW;
    569   nmcd->dwDrawStage= dwDrawStage;
    570   nmcd->hdc        = hdc;
    571   nmcd->rc.left    = rc.left;
    572   nmcd->rc.right   = rc.right;
    573   nmcd->rc.bottom  = rc.bottom;
    574   nmcd->rc.top     = rc.top;
    575   nmcd->dwItemSpec = 0;
    576   nmcd->uItemState = 0;
    577   nmcd->lItemlParam= 0;
    578   nmcdhdr.clrText  = infoPtr->clrText;
    579   nmcdhdr.clrTextBk= infoPtr->clrBk;
    580 
    581   return (BOOL)SendMessageW (GetParent (hwnd), WM_NOTIFY,
    582               (WPARAM) GetWindowLongW( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
    583 }
    584 
    585 static BOOL
    586 LISTVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
    587                                    UINT iItem, UINT iSubItem,
    588                                    UINT uItemDrawState)
    589 {
    590  LISTVIEW_INFO *infoPtr;
    591  NMLVCUSTOMDRAW nmcdhdr;
    592  LPNMCUSTOMDRAW nmcd;
    593  DWORD dwDrawStage,dwItemSpec;
    594  UINT uItemState;
    595  INT retval;
    596  RECT itemRect;
    597  LVITEMW item;
    598 
    599  infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    600 
    601  ZeroMemory(&item,sizeof(item));
    602  item.iItem = iItem;
    603  item.mask = LVIF_PARAM;
    604  ListView_GetItemW(hwnd,&item);
    605 
    606  dwDrawStage=CDDS_ITEM | uItemDrawState;
    607  dwItemSpec=iItem;
    608  uItemState=0;
    609 
    610  if (LISTVIEW_IsSelected(hwnd,iItem)) uItemState|=CDIS_SELECTED;
    611  if (iItem==infoPtr->nFocusedItem)   uItemState|=CDIS_FOCUS;
    612  if (iItem==infoPtr->nHotItem)       uItemState|=CDIS_HOT;
    613 
    614  itemRect.left = LVIR_BOUNDS;
    615  LISTVIEW_GetItemRect(hwnd, iItem, &itemRect);
    616 
    617  nmcd= & nmcdhdr.nmcd;
    618  nmcd->hdr.hwndFrom = hwnd;
    619  nmcd->hdr.idFrom =  GetWindowLongW( hwnd, GWL_ID);
    620  nmcd->hdr.code   = NM_CUSTOMDRAW;
    621  nmcd->dwDrawStage= dwDrawStage;
    622  nmcd->hdc        = hdc;
    623  nmcd->rc.left    = itemRect.left;
    624  nmcd->rc.right   = itemRect.right;
    625  nmcd->rc.bottom  = itemRect.bottom;
    626  nmcd->rc.top     = itemRect.top;
    627  nmcd->dwItemSpec = dwItemSpec;
    628  nmcd->uItemState = uItemState;
    629  nmcd->lItemlParam= item.lParam;
    630  nmcdhdr.clrText  = infoPtr->clrText;
    631  nmcdhdr.clrTextBk= infoPtr->clrBk;
    632  nmcdhdr.iSubItem   =iSubItem;
    633 
    634  TRACE("drawstage=%lx hdc=%x item=%lx, itemstate=%x, lItemlParam=%lx\n",
    635        nmcd->dwDrawStage, nmcd->hdc, nmcd->dwItemSpec,
    636        nmcd->uItemState, nmcd->lItemlParam);
    637 
    638  retval=SendMessageW (GetParent (hwnd), WM_NOTIFY,
    639                  (WPARAM) GetWindowLongW( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
    640 
    641  infoPtr->clrText=nmcdhdr.clrText;
    642  infoPtr->clrBk  =nmcdhdr.clrTextBk;
    643  return (BOOL) retval;
     1207    {
     1208        INT nPerCol = max((infoPtr->rcList.bottom - infoPtr->rcList.top) / infoPtr->nItemHeight, 1);
     1209        INT nFirstRow = max(frame.top / infoPtr->nItemHeight, 0);
     1210        INT nLastRow = min((frame.bottom - 1) / infoPtr->nItemHeight, nPerCol - 1);
     1211        INT nFirstCol = max(frame.left / infoPtr->nItemWidth, 0);
     1212        INT nLastCol = min((frame.right - 1) / infoPtr->nItemWidth, (infoPtr->nItemCount + nPerCol - 1) / nPerCol);
     1213        INT lower = nFirstCol * nPerCol + nFirstRow;
     1214        RANGE item_range;
     1215        INT nCol;
     1216
     1217        TRACE("nPerCol=%d, nFirstRow=%d, nLastRow=%d, nFirstCol=%d, nLastCol=%d, lower=%d\n",
     1218              nPerCol, nFirstRow, nLastRow, nFirstCol, nLastCol, lower);
     1219       
     1220        if (nLastCol < nFirstCol || nLastRow < nFirstRow) return TRUE;
     1221
     1222        if (!(iterator_rangesitems(i, ranges_create(nLastCol - nFirstCol + 1)))) return FALSE;
     1223        TRACE("building list ranges:\n");
     1224        for (nCol = nFirstCol; nCol <= nLastCol; nCol++)
     1225        {
     1226            item_range.lower = nCol * nPerCol + nFirstRow;
     1227            if(item_range.lower >= infoPtr->nItemCount) break;
     1228            item_range.upper = min(nCol * nPerCol + nLastRow + 1, infoPtr->nItemCount);
     1229            TRACE("   list=%s\n", debugrange(&item_range));
     1230            ranges_add(i->ranges, item_range);
     1231        }
     1232    }
     1233
     1234    return TRUE;
     1235}
     1236
     1237/***
     1238 * Creates an iterator over the items which intersect the visible region of hdc.
     1239 */
     1240static BOOL iterator_visibleitems(ITERATOR *i, LISTVIEW_INFO *infoPtr, HDC  hdc)
     1241{
     1242    POINT Origin, Position;
     1243    RECT rcItem, rcClip;
     1244    INT rgntype;
     1245   
     1246    rgntype = GetClipBox(hdc, &rcClip);
     1247    if (rgntype == NULLREGION) return iterator_empty(i);
     1248    if (!iterator_frameditems(i, infoPtr, &rcClip)) return FALSE;
     1249    if (rgntype == SIMPLEREGION) return TRUE;
     1250
     1251    /* first deal with the special item */
     1252    if (i->nSpecial != -1)
     1253    {
     1254        LISTVIEW_GetItemBox(infoPtr, i->nSpecial, &rcItem);
     1255        if (!RectVisible(hdc, &rcItem)) i->nSpecial = -1;
     1256    }
     1257   
     1258    /* if we can't deal with the region, we'll just go with the simple range */
     1259    LISTVIEW_GetOrigin(infoPtr, &Origin);
     1260    TRACE("building visible range:\n");
     1261    if (!i->ranges && i->range.lower < i->range.upper)
     1262    {
     1263        if (!(i->ranges = ranges_create(50))) return TRUE;
     1264        if (!ranges_add(i->ranges, i->range))
     1265        {
     1266            ranges_destroy(i->ranges);
     1267            i->ranges = 0;
     1268            return TRUE;
     1269        }
     1270    }
     1271
     1272    /* now delete the invisible items from the list */
     1273    while(iterator_next(i))
     1274    {
     1275        LISTVIEW_GetItemOrigin(infoPtr, i->nItem, &Position);
     1276        rcItem.left = Position.x + Origin.x;
     1277        rcItem.top = Position.y + Origin.y;
     1278        rcItem.right = rcItem.left + infoPtr->nItemWidth;
     1279        rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
     1280        if (!RectVisible(hdc, &rcItem))
     1281            ranges_delitem(i->ranges, i->nItem);
     1282    }
     1283    /* the iterator should restart on the next iterator_next */
     1284    TRACE("done\n");
     1285   
     1286    return TRUE;
     1287}
     1288
     1289/******** Misc helper functions ************************************/
     1290
     1291static inline LRESULT CallWindowProcT(WNDPROC proc, HWND hwnd, UINT uMsg,
     1292                                      WPARAM wParam, LPARAM lParam, BOOL isW)
     1293{
     1294    if (isW) return CallWindowProcW(proc, hwnd, uMsg, wParam, lParam);
     1295    else return CallWindowProcA(proc, hwnd, uMsg, wParam, lParam);
     1296}
     1297
     1298static inline BOOL is_autoarrange(LISTVIEW_INFO *infoPtr)
     1299{
     1300    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     1301   
     1302    return ((infoPtr->dwStyle & LVS_AUTOARRANGE) || infoPtr->bAutoarrange) &&
     1303           (uView == LVS_ICON || uView == LVS_SMALLICON);
     1304}
     1305
     1306/******** Internal API functions ************************************/
     1307
     1308static inline COLUMN_INFO * LISTVIEW_GetColumnInfo(LISTVIEW_INFO *infoPtr, INT nSubItem)
     1309{
     1310    static COLUMN_INFO mainItem;
     1311
     1312    if (nSubItem == 0 && infoPtr->hdpaColumns->nItemCount == 0) return &mainItem;
     1313    assert (nSubItem >= 0 && nSubItem < infoPtr->hdpaColumns->nItemCount);
     1314    return (COLUMN_INFO *)DPA_GetPtr(infoPtr->hdpaColumns, nSubItem);
     1315}
     1316       
     1317static inline void LISTVIEW_GetHeaderRect(LISTVIEW_INFO *infoPtr, INT nSubItem, RECT *lprc)
     1318{
     1319    *lprc = LISTVIEW_GetColumnInfo(infoPtr, nSubItem)->rcHeader;
     1320}
     1321       
     1322static inline BOOL LISTVIEW_GetItemW(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem)
     1323{
     1324    return LISTVIEW_GetItemT(infoPtr, lpLVItem, TRUE);
     1325}
     1326
     1327/* Listview invalidation functions: use _only_ these functions to invalidate */
     1328
     1329static inline BOOL is_redrawing(LISTVIEW_INFO *infoPtr)
     1330{
     1331    return infoPtr->bRedraw && !infoPtr->bFirstPaint;
     1332}
     1333
     1334static inline void LISTVIEW_InvalidateRect(LISTVIEW_INFO *infoPtr, const RECT* rect)
     1335{
     1336    if(!is_redrawing(infoPtr)) return;
     1337    TRACE(" invalidating rect=%s\n", debugrect(rect));
     1338    InvalidateRect(infoPtr->hwndSelf, rect, TRUE);
     1339}
     1340
     1341static inline void LISTVIEW_InvalidateItem(LISTVIEW_INFO *infoPtr, INT nItem)
     1342{
     1343    RECT rcBox;
     1344
     1345    if(!is_redrawing(infoPtr)) return;
     1346    LISTVIEW_GetItemBox(infoPtr, nItem, &rcBox);
     1347    LISTVIEW_InvalidateRect(infoPtr, &rcBox);
     1348}
     1349
     1350static inline void LISTVIEW_InvalidateSubItem(LISTVIEW_INFO *infoPtr, INT nItem, INT nSubItem)
     1351{
     1352    POINT Origin, Position;
     1353    RECT rcBox;
     1354   
     1355    if(!is_redrawing(infoPtr)) return;
     1356    assert ((infoPtr->dwStyle & LVS_TYPEMASK) == LVS_REPORT);
     1357    LISTVIEW_GetOrigin(infoPtr, &Origin);
     1358    LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position);
     1359    LISTVIEW_GetHeaderRect(infoPtr, nSubItem, &rcBox);
     1360    rcBox.top = 0;
     1361    rcBox.bottom = infoPtr->nItemHeight;
     1362    OffsetRect(&rcBox, Origin.x + Position.x, Origin.y + Position.y);
     1363    LISTVIEW_InvalidateRect(infoPtr, &rcBox);
     1364}
     1365
     1366static inline void LISTVIEW_InvalidateList(LISTVIEW_INFO *infoPtr)
     1367{
     1368    LISTVIEW_InvalidateRect(infoPtr, NULL);
     1369}
     1370
     1371static inline void LISTVIEW_InvalidateColumn(LISTVIEW_INFO *infoPtr, INT nColumn)
     1372{
     1373    RECT rcCol;
     1374   
     1375    if(!is_redrawing(infoPtr)) return;
     1376    LISTVIEW_GetHeaderRect(infoPtr, nColumn, &rcCol);
     1377    rcCol.top = infoPtr->rcList.top;
     1378    rcCol.bottom = infoPtr->rcList.bottom;
     1379    LISTVIEW_InvalidateRect(infoPtr, &rcCol);
     1380}
     1381
     1382/***
     1383 * DESCRIPTION:
     1384 * Retrieves the number of items that can fit vertically in the client area.
     1385 *
     1386 * PARAMETER(S):
     1387 * [I] infoPtr : valid pointer to the listview structure
     1388 *
     1389 * RETURN:
     1390 * Number of items per row.
     1391 */
     1392static inline INT LISTVIEW_GetCountPerRow(LISTVIEW_INFO *infoPtr)
     1393{
     1394    INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
     1395
     1396    return max(nListWidth/infoPtr->nItemWidth, 1);
     1397}
     1398
     1399/***
     1400 * DESCRIPTION:
     1401 * Retrieves the number of items that can fit horizontally in the client
     1402 * area.
     1403 *
     1404 * PARAMETER(S):
     1405 * [I] infoPtr : valid pointer to the listview structure
     1406 *
     1407 * RETURN:
     1408 * Number of items per column.
     1409 */
     1410static inline INT LISTVIEW_GetCountPerColumn(LISTVIEW_INFO *infoPtr)
     1411{
     1412    INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
     1413
     1414    return max(nListHeight / infoPtr->nItemHeight, 1);
    6441415}
    6451416
     
    6481419 *              LISTVIEW_ProcessLetterKeys
    6491420 *
    650  *  Processes keyboard messages generated by pressing the letter keys 
     1421 *  Processes keyboard messages generated by pressing the letter keys
    6511422 *  on the keyboard.
    652  *  What this does is perform a case insensitive search from the 
     1423 *  What this does is perform a case insensitive search from the
    6531424 *  current position with the following quirks:
    654  *  - If two chars or more are pressed in quick succession we search 
     1425 *  - If two chars or more are pressed in quick succession we search
    6551426 *    for the corresponding string (e.g. 'abc').
    656  *  - If there is a delay we wipe away the current search string and 
     1427 *  - If there is a delay we wipe away the current search string and
    6571428 *    restart with just that char.
    658  *  - If the user keeps pressing the same character, whether slowly or 
    659  *    fast, so that the search string is entirely composed of this 
    660  *    character ('aaaaa' for instance), then we search for first item 
     1429 *  - If the user keeps pressing the same character, whether slowly or
     1430 *    fast, so that the search string is entirely composed of this
     1431 *    character ('aaaaa' for instance), then we search for first item
    6611432 *    that starting with that character.
    662  *  - If the user types the above character in quick succession, then 
    663  *    we must also search for the corresponding string ('aaaaa'), and 
     1433 *  - If the user types the above character in quick succession, then
     1434 *    we must also search for the corresponding string ('aaaaa'), and
    6641435 *    go to that string if there is a match.
    6651436 *
     1437 * PARAMETERS
     1438 *   [I] hwnd : handle to the window
     1439 *   [I] charCode : the character code, the actual character
     1440 *   [I] keyData : key data
     1441 *
    6661442 * RETURNS
    6671443 *
     
    6701446 * BUGS
    6711447 *
    672  *  - The current implementation has a list of characters it will 
    673  *    accept and it ignores averything else. In particular it will 
    674  *    ignore accentuated characters which seems to match what 
    675  *    Windows does. But I'm not sure it makes sense to follow 
     1448 *  - The current implementation has a list of characters it will
     1449 *    accept and it ignores averything else. In particular it will
     1450 *    ignore accentuated characters which seems to match what
     1451 *    Windows does. But I'm not sure it makes sense to follow
    6761452 *    Windows there.
    6771453 *  - We don't sound a beep when the search fails.
     
    6811457 *  TREEVIEW_ProcessLetterKeys
    6821458 */
    683 static INT LISTVIEW_ProcessLetterKeys(
    684     HWND hwnd, /* handle to the window */
    685     WPARAM charCode, /* the character code, the actual character */
    686     LPARAM keyData /* key data */
    687     )
    688 {
    689     LISTVIEW_INFO *infoPtr;
     1459static INT LISTVIEW_ProcessLetterKeys(LISTVIEW_INFO *infoPtr, WPARAM charCode, LPARAM keyData)
     1460{
    6901461    INT nItem;
    691     INT nSize;
    6921462    INT endidx,idx;
    6931463    LVITEMW item;
    6941464    WCHAR buffer[MAX_PATH];
    695     DWORD timestamp,elapsed;
     1465    DWORD lastKeyPressTimestamp = infoPtr->lastKeyPressTimestamp;
    6961466
    6971467    /* simple parameter checking */
    698     if (!hwnd || !charCode || !keyData)
    699         return 0;
    700 
    701     infoPtr=(LISTVIEW_INFO*)GetWindowLongW(hwnd, 0);
    702     if (!infoPtr)
    703         return 0;
     1468    if (!charCode || !keyData) return 0;
    7041469
    7051470    /* only allow the valid WM_CHARs through */
     
    7161481        return 0;
    7171482
    718     nSize=GETITEMCOUNT(infoPtr);
    7191483    /* if there's one item or less, there is no where to go */
    720     if (nSize <= 1)
    721         return 0;
    722 
    723     /* compute how much time elapsed since last keypress */
    724     timestamp=GetTickCount();
    725     if (timestamp > infoPtr->lastKeyPressTimestamp) {
    726         elapsed=timestamp-infoPtr->lastKeyPressTimestamp;
    727     } else {
    728         elapsed=infoPtr->lastKeyPressTimestamp-timestamp;
    729     }
     1484    if (infoPtr->nItemCount <= 1) return 0;
    7301485
    7311486    /* update the search parameters */
    732     infoPtr->lastKeyPressTimestamp=timestamp;
    733     if (elapsed < KEY_DELAY) {
    734         if (infoPtr->nSearchParamLength < COUNTOF(infoPtr->szSearchParam)) {
     1487    infoPtr->lastKeyPressTimestamp = GetTickCount();
     1488    if (infoPtr->lastKeyPressTimestamp - lastKeyPressTimestamp < KEY_DELAY) {
     1489        if (infoPtr->nSearchParamLength < MAX_PATH)
    7351490            infoPtr->szSearchParam[infoPtr->nSearchParamLength++]=charCode;
    736         }
    737         if (infoPtr->charCode != charCode) {
    738             infoPtr->charCode=charCode=0;
    739         }
     1491        if (infoPtr->charCode != charCode)
     1492            infoPtr->charCode = charCode = 0;
    7401493    } else {
    7411494        infoPtr->charCode=charCode;
     
    7571510            idx++;
    7581511    } else {
    759         endidx=nSize;
     1512        endidx=infoPtr->nItemCount;
    7601513        idx=0;
    7611514    }
    7621515    do {
    763         if (idx == nSize) {
    764 #ifdef __WIN32OS2__
    765             if (endidx == nSize || endidx == 0)
    766 #else
    767             if (endidx == nSize)
    768 #endif
     1516        if (idx == infoPtr->nItemCount) {
     1517            if (endidx == infoPtr->nItemCount || endidx == 0)
    7691518                break;
    7701519            idx=0;
     
    7721521
    7731522        /* get item */
    774         ZeroMemory(&item, sizeof(item));
    7751523        item.mask = LVIF_TEXT;
    7761524        item.iItem = idx;
    7771525        item.iSubItem = 0;
    7781526        item.pszText = buffer;
    779         item.cchTextMax = COUNTOF(buffer);
    780         ListView_GetItemW( hwnd, &item );
     1527        item.cchTextMax = MAX_PATH;
     1528        if (!LISTVIEW_GetItemW(infoPtr, &item)) return 0;
    7811529
    7821530        /* check for a match */
     
    7921540    } while (idx != endidx);
    7931541
    794     if (nItem != -1) {
    795         if (LISTVIEW_KeySelection(hwnd, nItem) != FALSE) {
    796             /* refresh client area */
    797             InvalidateRect(hwnd, NULL, TRUE);
    798             UpdateWindow(hwnd);
    799         }
    800     }
     1542    if (nItem != -1)
     1543        LISTVIEW_KeySelection(infoPtr, nItem);
    8011544
    8021545    return 0;
     
    8041547
    8051548/*************************************************************************
    806  * LISTVIEW_UpdateHeaderSize [Internal] 
     1549 * LISTVIEW_UpdateHeaderSize [Internal]
    8071550 *
    8081551 * Function to resize the header control
    8091552 *
    8101553 * PARAMS
    811  *     hwnd             [I] handle to a window
    812  *     nNewScrollPos    [I] Scroll Pos to Set
     1554 * [I]  hwnd : handle to a window
     1555 * [I]  nNewScrollPos : scroll pos to set
    8131556 *
    8141557 * RETURNS
    815  *     nothing
    816  *
    817  * NOTES
    818  */
    819 static VOID LISTVIEW_UpdateHeaderSize(HWND hwnd, INT nNewScrollPos)
    820 {
    821     LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
     1558 * None.
     1559 */
     1560static void LISTVIEW_UpdateHeaderSize(LISTVIEW_INFO *infoPtr, INT nNewScrollPos)
     1561{
    8221562    RECT winRect;
    8231563    POINT point[2];
     1564
     1565    TRACE("nNewScrollPos=%d\n", nNewScrollPos);
    8241566
    8251567    GetWindowRect(infoPtr->hwndHeader, &winRect);
     
    8291571    point[1].y = winRect.bottom;
    8301572
    831     MapWindowPoints(HWND_DESKTOP, hwnd, point, 2);
    832 #ifdef __WIN32OS2__
    833     point[0].x = -nNewScrollPos*infoPtr->scrollStep.x;
    834     point[1].x += nNewScrollPos*infoPtr->scrollStep.x;
    835 #else
    836     point[0].x = -(nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
    837     point[1].x += (nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
    838 #endif
     1573    MapWindowPoints(HWND_DESKTOP, infoPtr->hwndSelf, point, 2);
     1574    point[0].x = -nNewScrollPos;
     1575    point[1].x += nNewScrollPos;
     1576
    8391577    SetWindowPos(infoPtr->hwndHeader,0,
    8401578        point[0].x,point[0].y,point[1].x,point[1].y,
     
    8441582/***
    8451583 * DESCRIPTION:
    846  * Update the scrollbars. This functions should be called whenever 
     1584 * Update the scrollbars. This functions should be called whenever
    8471585 * the content, size or view changes.
     1586 *
     1587 * PARAMETER(S):
     1588 * [I] infoPtr : valid pointer to the listview structure
     1589 *
     1590 * RETURN:
     1591 * None
     1592 */
     1593static void LISTVIEW_UpdateScroll(LISTVIEW_INFO *infoPtr)
     1594{
     1595    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     1596    SCROLLINFO horzInfo, vertInfo;
     1597
     1598    if ((infoPtr->dwStyle & LVS_NOSCROLL) || !is_redrawing(infoPtr)) return;
     1599
     1600    ZeroMemory(&horzInfo, sizeof(SCROLLINFO));
     1601    horzInfo.cbSize = sizeof(SCROLLINFO);
     1602    horzInfo.nPage = infoPtr->rcList.right - infoPtr->rcList.left;
     1603
     1604    /* for now, we'll set info.nMax to the _count_, and adjust it later */
     1605    if (uView == LVS_LIST)
     1606    {
     1607        INT nPerCol = LISTVIEW_GetCountPerColumn(infoPtr);
     1608        horzInfo.nMax = (infoPtr->nItemCount + nPerCol - 1) / nPerCol;
     1609
     1610        /* scroll by at least one column per page */
     1611        if(horzInfo.nPage < infoPtr->nItemWidth)
     1612                horzInfo.nPage = infoPtr->nItemWidth;
     1613
     1614        horzInfo.nPage /= infoPtr->nItemWidth;
     1615    }
     1616    else if (uView == LVS_REPORT)
     1617    {
     1618        horzInfo.nMax = infoPtr->nItemWidth;
     1619    }
     1620    else /* LVS_ICON, or LVS_SMALLICON */
     1621    {
     1622        RECT rcView;
     1623
     1624        if (LISTVIEW_GetViewRect(infoPtr, &rcView)) horzInfo.nMax = rcView.right - rcView.left;
     1625    }
     1626 
     1627    horzInfo.fMask = SIF_RANGE | SIF_PAGE;
     1628    horzInfo.nMax = max(horzInfo.nMax - 1, 0);
     1629    SetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &horzInfo, TRUE);
     1630    TRACE("horzInfo=%s\n", debugscrollinfo(&horzInfo));
     1631
     1632    /* Setting the horizontal scroll can change the listview size
     1633     * (and potentially everything else) so we need to recompute
     1634     * everything again for the vertical scroll
     1635     */
     1636
     1637    ZeroMemory(&vertInfo, sizeof(SCROLLINFO));
     1638    vertInfo.cbSize = sizeof(SCROLLINFO);
     1639    vertInfo.nPage = infoPtr->rcList.bottom - infoPtr->rcList.top;
     1640
     1641    if (uView == LVS_REPORT)
     1642    {
     1643        vertInfo.nMax = infoPtr->nItemCount;
     1644       
     1645        /* scroll by at least one page */
     1646        if(vertInfo.nPage < infoPtr->nItemHeight)
     1647          vertInfo.nPage = infoPtr->nItemHeight;
     1648
     1649        vertInfo.nPage /= infoPtr->nItemHeight;
     1650    }
     1651    else if (uView != LVS_LIST) /* LVS_ICON, or LVS_SMALLICON */
     1652    {
     1653        RECT rcView;
     1654
     1655        if (LISTVIEW_GetViewRect(infoPtr, &rcView)) vertInfo.nMax = rcView.bottom - rcView.top;
     1656    }
     1657
     1658    vertInfo.fMask = SIF_RANGE | SIF_PAGE;
     1659    vertInfo.nMax = max(vertInfo.nMax - 1, 0);
     1660    SetScrollInfo(infoPtr->hwndSelf, SB_VERT, &vertInfo, TRUE);
     1661    TRACE("vertInfo=%s\n", debugscrollinfo(&vertInfo));
     1662
     1663    /* Update the Header Control */
     1664    if (uView == LVS_REPORT)
     1665    {
     1666        horzInfo.fMask = SIF_POS;
     1667        GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &horzInfo);
     1668        LISTVIEW_UpdateHeaderSize(infoPtr, horzInfo.nPos);
     1669    }
     1670}
     1671
     1672
     1673/***
     1674 * DESCRIPTION:
     1675 * Shows/hides the focus rectangle.
     1676 *
     1677 * PARAMETER(S):
     1678 * [I] infoPtr : valid pointer to the listview structure
     1679 * [I] fShow : TRUE to show the focus, FALSE to hide it.
     1680 *
     1681 * RETURN:
     1682 * None
     1683 */
     1684static void LISTVIEW_ShowFocusRect(LISTVIEW_INFO *infoPtr, BOOL fShow)
     1685{
     1686    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     1687    HDC hdc;
     1688
     1689    TRACE("fShow=%d, nItem=%d\n", fShow, infoPtr->nFocusedItem);
     1690
     1691    if (infoPtr->nFocusedItem < 0) return;
     1692
     1693    /* we need some gymnastics in ICON mode to handle large items */
     1694    if ( (infoPtr->dwStyle & LVS_TYPEMASK) == LVS_ICON )
     1695    {
     1696        RECT rcBox;
     1697
     1698        LISTVIEW_GetItemBox(infoPtr, infoPtr->nFocusedItem, &rcBox);
     1699        if ((rcBox.bottom - rcBox.top) > infoPtr->nItemHeight)
     1700        {
     1701            LISTVIEW_InvalidateRect(infoPtr, &rcBox);
     1702            return;
     1703        }
     1704    }
     1705
     1706    if (!(hdc = GetDC(infoPtr->hwndSelf))) return;
     1707
     1708    /* for some reason, owner draw should work only in report mode */
     1709    if ((infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && (uView == LVS_REPORT))
     1710    {
     1711        DRAWITEMSTRUCT dis;
     1712        LVITEMW item;
     1713
     1714        item.iItem = infoPtr->nFocusedItem;
     1715        item.iSubItem = 0;
     1716        item.mask = LVIF_PARAM;
     1717        if (!LISTVIEW_GetItemW(infoPtr, &item)) goto done;
     1718           
     1719        ZeroMemory(&dis, sizeof(dis));
     1720        dis.CtlType = ODT_LISTVIEW;
     1721        dis.CtlID = GetWindowLongW(infoPtr->hwndSelf, GWL_ID);
     1722        dis.itemID = item.iItem;
     1723        dis.itemAction = ODA_FOCUS;
     1724        if (fShow) dis.itemState |= ODS_FOCUS;
     1725        dis.hwndItem = infoPtr->hwndSelf;
     1726        dis.hDC = hdc;
     1727        LISTVIEW_GetItemBox(infoPtr, dis.itemID, &dis.rcItem);
     1728        dis.itemData = item.lParam;
     1729
     1730        SendMessageW(GetParent(infoPtr->hwndSelf), WM_DRAWITEM, dis.CtlID, (LPARAM)&dis);
     1731    }
     1732    else
     1733    {
     1734        DrawFocusRect(hdc, &infoPtr->rcFocus);
     1735    }
     1736done:
     1737    ReleaseDC(infoPtr->hwndSelf, hdc);
     1738}
     1739
     1740/***
     1741 * Invalidates all visible selected items.
     1742 */
     1743static void LISTVIEW_InvalidateSelectedItems(LISTVIEW_INFO *infoPtr)
     1744{
     1745    ITERATOR i;
     1746   
     1747    iterator_frameditems(&i, infoPtr, &infoPtr->rcList);
     1748    while(iterator_next(&i))
     1749    {
     1750        if (LISTVIEW_GetItemState(infoPtr, i.nItem, LVIS_SELECTED))
     1751            LISTVIEW_InvalidateItem(infoPtr, i.nItem);
     1752    }
     1753    iterator_destroy(&i);
     1754}
     1755
     1756           
     1757/***
     1758 * DESCRIPTION:            [INTERNAL]
     1759 * Computes an item's (left,top) corner, relative to rcView.
     1760 * That is, the position has NOT been made relative to the Origin.
     1761 * This is deliberate, to avoid computing the Origin over, and
     1762 * over again, when this function is call in a loop. Instead,
     1763 * one ca factor the computation of the Origin before the loop,
     1764 * and offset the value retured by this function, on every iteration.
    8481765 *
    8491766 * PARAMETER(S):
    850  * [I] HWND : window handle
     1767 * [I] infoPtr : valid pointer to the listview structure
     1768 * [I] nItem  : item number
     1769 * [O] lpptOrig : item top, left corner
     1770 *
     1771 * RETURN:
     1772 *   None.
     1773 */
     1774static void LISTVIEW_GetItemOrigin(LISTVIEW_INFO *infoPtr, INT nItem, LPPOINT lpptPosition)
     1775{
     1776    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     1777
     1778    assert(nItem >= 0 && nItem < infoPtr->nItemCount);
     1779
     1780    if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
     1781    {
     1782        lpptPosition->x = (LONG)DPA_GetPtr(infoPtr->hdpaPosX, nItem);
     1783        lpptPosition->y = (LONG)DPA_GetPtr(infoPtr->hdpaPosY, nItem);
     1784    }
     1785    else if (uView == LVS_LIST)
     1786    {
     1787        INT nCountPerColumn = LISTVIEW_GetCountPerColumn(infoPtr);
     1788        lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
     1789        lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight;
     1790    }
     1791    else /* LVS_REPORT */
     1792    {
     1793        lpptPosition->x = 0;
     1794        lpptPosition->y = nItem * infoPtr->nItemHeight;
     1795    }
     1796}
     1797   
     1798/***
     1799 * DESCRIPTION:            [INTERNAL]
     1800 * Compute the rectangles of an item.  This is to localize all
     1801 * the computations in one place. If you are not interested in some
     1802 * of these values, simply pass in a NULL -- the fucntion is smart
     1803 * enough to compute only what's necessary. The function computes
     1804 * the standard rectangles (BOUNDS, ICON, LABEL) plus a non-standard
     1805 * one, the BOX rectangle. This rectangle is very cheap to compute,
     1806 * and is guaranteed to contain all the other rectangles. Computing
     1807 * the ICON rect is also cheap, but all the others are potentaily
     1808 * expensive. This gives an easy and effective optimization when
     1809 * searching (like point inclusion, or rectangle intersection):
     1810 * first test against the BOX, and if TRUE, test agains the desired
     1811 * rectangle.
     1812 * If the function does not have all the necessary information
     1813 * to computed the requested rectangles, will crash with a
     1814 * failed assertion. This is done so we catch all programming
     1815 * errors, given that the function is called only from our code.
     1816 *
     1817 * We have the following 'special' meanings for a few fields:
     1818 *   * If LVIS_FOCUSED is set, we assume the item has the focus
     1819 *     This is important in ICON mode, where it might get a larger
     1820 *     then usual rectange
     1821 *
     1822 * Please note that subitem support works only in REPORT mode.
     1823 *
     1824 * PARAMETER(S):
     1825 * [I] infoPtr : valid pointer to the listview structure
     1826 * [I] lpLVItem : item to compute the measures for
     1827 * [O] lprcBox : ptr to Box rectangle
     1828 *                The internal LVIR_BOX rectangle
     1829 * [0] lprcState : ptr to State icon rectangle
     1830 *                The internal LVIR_STATE rectangle
     1831 * [O] lprcIcon : ptr to Icon rectangle
     1832 *                Same as LVM_GETITEMRECT with LVIR_ICON
     1833 * [O] lprcLabel : ptr to Label rectangle
     1834 *                Same as LVM_GETITEMRECT with LVIR_LABEL
     1835 *
     1836 * RETURN:
     1837 *   None.
     1838 */
     1839static void LISTVIEW_GetItemMetrics(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem,
     1840                                    LPRECT lprcBox, LPRECT lprcState,
     1841                                    LPRECT lprcIcon, LPRECT lprcLabel)
     1842{
     1843    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     1844    BOOL doState = FALSE, doIcon = FALSE, doLabel = FALSE, oversizedBox = FALSE;
     1845    RECT Box, State, Icon, Label;
     1846    COLUMN_INFO *lpColumnInfo = NULL;
     1847
     1848    TRACE("(lpLVItem=%s)\n", debuglvitem_t(lpLVItem, TRUE));
     1849       
     1850    /* Be smart and try to figure out the minimum we have to do */
     1851    if (lpLVItem->iSubItem) assert(uView == LVS_REPORT);
     1852    if (uView == LVS_ICON && (lprcBox || lprcLabel))
     1853    {
     1854        assert((lpLVItem->mask & LVIF_STATE) && (lpLVItem->stateMask & LVIS_FOCUSED));
     1855        if (lpLVItem->state & LVIS_FOCUSED) oversizedBox = doLabel = TRUE;
     1856    }
     1857    if (lprcLabel) doLabel = TRUE;
     1858    if (doLabel || lprcIcon) doIcon = TRUE;
     1859    if (doIcon || lprcState) doState = TRUE;
     1860   
     1861    /************************************************************/
     1862    /* compute the box rectangle (it should be cheap to do)     */
     1863    /************************************************************/
     1864    if (lpLVItem->iSubItem || uView == LVS_REPORT)
     1865        lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, lpLVItem->iSubItem);
     1866
     1867    if (lpLVItem->iSubItem)   
     1868    {
     1869        Box = lpColumnInfo->rcHeader;
     1870    }
     1871    else
     1872    {
     1873        Box.left = 0;
     1874        Box.right = infoPtr->nItemWidth;
     1875    }
     1876    Box.top = 0;
     1877    Box.bottom = infoPtr->nItemHeight;
     1878               
     1879    /************************************************************/
     1880    /* compute STATEICON bounding box                           */
     1881    /************************************************************/
     1882    if (doState)
     1883    {
     1884        if (uView == LVS_ICON)
     1885        {
     1886            State.left = Box.left - infoPtr->iconStateSize.cx - 2;
     1887            if (infoPtr->himlNormal)
     1888                State.left += (infoPtr->nItemWidth - infoPtr->iconSize.cx) / 2;
     1889            State.top  = Box.top + infoPtr->iconSize.cy - infoPtr->iconStateSize.cy + 4;
     1890        }
     1891        else
     1892        {
     1893            /* we need the ident in report mode, if we don't have it, we fail */
     1894            State.left = Box.left;
     1895            if (uView == LVS_REPORT)
     1896            {
     1897                if (lpLVItem->iSubItem == 0)
     1898                {
     1899                    State.left += REPORT_MARGINX;
     1900                    assert(lpLVItem->mask & LVIF_INDENT);
     1901                    State.left += infoPtr->iconSize.cx * lpLVItem->iIndent;
     1902                }
     1903            }
     1904            State.top  = Box.top;
     1905        }       
     1906        State.right    = State.left;
     1907        State.bottom   = State.top;
     1908        if (infoPtr->himlState && lpLVItem->iSubItem == 0)
     1909        {
     1910            State.right  += infoPtr->iconStateSize.cx;
     1911            State.bottom += infoPtr->iconStateSize.cy;
     1912        }
     1913        if (lprcState) *lprcState = State;
     1914        TRACE("    - state=%s\n", debugrect(&State));
     1915    }
     1916
     1917    /************************************************************/
     1918    /* compute ICON bounding box (ala LVM_GETITEMRECT)          */
     1919    /************************************************************/
     1920    if (doIcon)
     1921    {
     1922        if (uView == LVS_ICON)
     1923        {
     1924            Icon.left   = Box.left;
     1925            if (infoPtr->himlNormal)
     1926                Icon.left += (infoPtr->nItemWidth - infoPtr->iconSize.cx) / 2;
     1927            Icon.top    = Box.top + ICON_TOP_PADDING;
     1928            Icon.right  = Icon.left;
     1929            Icon.bottom = Icon.top;
     1930            if (infoPtr->himlNormal)
     1931            {
     1932                Icon.right  += infoPtr->iconSize.cx;
     1933                Icon.bottom += infoPtr->iconSize.cy;
     1934            }
     1935        }
     1936        else /* LVS_SMALLICON, LVS_LIST or LVS_REPORT */
     1937        {
     1938            Icon.left = State.right;
     1939            Icon.top    = Box.top;
     1940            Icon.right  = Icon.left;
     1941            if (infoPtr->himlSmall && (!lpColumnInfo || lpLVItem->iSubItem == 0 || (lpColumnInfo->fmt & LVCFMT_IMAGE)))
     1942                Icon.right += infoPtr->iconSize.cx;
     1943            Icon.bottom = Icon.top + infoPtr->nItemHeight;
     1944        }
     1945        if(lprcIcon) *lprcIcon = Icon;
     1946        TRACE("    - icon=%s\n", debugrect(&Icon));
     1947     }
     1948
     1949    /************************************************************/
     1950    /* compute LABEL bounding box (ala LVM_GETITEMRECT)         */
     1951    /************************************************************/
     1952    if (doLabel)
     1953    {
     1954        SIZE labelSize = { 0, 0 };
     1955
     1956        /* calculate how far to the right can the label strech */
     1957        Label.right = Box.right;
     1958        if (uView == LVS_REPORT)
     1959        {
     1960            if (lpLVItem->iSubItem == 0) Label = lpColumnInfo->rcHeader;
     1961        }
     1962
     1963        if (lpLVItem->iSubItem || ((infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && uView == LVS_REPORT))
     1964        {
     1965           labelSize.cx = infoPtr->nItemWidth;
     1966           labelSize.cy = infoPtr->nItemHeight;
     1967           goto calc_label;
     1968        }
     1969       
     1970        /* we need the text in non owner draw mode */
     1971        assert(lpLVItem->mask & LVIF_TEXT);
     1972        if (is_textT(lpLVItem->pszText, TRUE))
     1973        {
     1974            HFONT hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
     1975            HDC hdc = GetDC(infoPtr->hwndSelf);
     1976            HFONT hOldFont = SelectObject(hdc, hFont);
     1977            UINT uFormat;
     1978            RECT rcText;
     1979
     1980            /* compute rough rectangle where the label will go */
     1981            SetRectEmpty(&rcText);
     1982            rcText.right = infoPtr->nItemWidth - TRAILING_LABEL_PADDING;
     1983            rcText.bottom = infoPtr->nItemHeight;
     1984            if (uView == LVS_ICON)
     1985                rcText.bottom -= ICON_TOP_PADDING + infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
     1986
     1987            /* now figure out the flags */
     1988            if (uView == LVS_ICON)
     1989                uFormat = oversizedBox ? LV_FL_DT_FLAGS : LV_ML_DT_FLAGS;
     1990            else
     1991                uFormat = LV_SL_DT_FLAGS;
     1992           
     1993            DrawTextW (hdc, lpLVItem->pszText, -1, &rcText, uFormat | DT_CALCRECT);
     1994
     1995            labelSize.cx = min(rcText.right - rcText.left + TRAILING_LABEL_PADDING, infoPtr->nItemWidth);
     1996            labelSize.cy = rcText.bottom - rcText.top;
     1997
     1998            SelectObject(hdc, hOldFont);
     1999            ReleaseDC(infoPtr->hwndSelf, hdc);
     2000        }
     2001
     2002calc_label:
     2003        if (uView == LVS_ICON)
     2004        {
     2005            Label.left = Box.left + (infoPtr->nItemWidth - labelSize.cx) / 2;
     2006            Label.top  = Box.top + ICON_TOP_PADDING_HITABLE +
     2007                         infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
     2008            Label.right = Label.left + labelSize.cx;
     2009            Label.bottom = Label.top + infoPtr->nItemHeight;
     2010            if (!oversizedBox && labelSize.cy > infoPtr->ntmHeight)
     2011            {
     2012                labelSize.cy = min(Box.bottom - Label.top, labelSize.cy);
     2013                labelSize.cy /= infoPtr->ntmHeight;
     2014                labelSize.cy = max(labelSize.cy, 1);
     2015                labelSize.cy *= infoPtr->ntmHeight;
     2016             }
     2017             Label.bottom = Label.top + labelSize.cy + HEIGHT_PADDING;
     2018        }
     2019        else /* LVS_SMALLICON, LVS_LIST or LVS_REPORT */
     2020        {
     2021            Label.left = Icon.right;
     2022            Label.top = Box.top;
     2023            Label.right = min(Label.left + labelSize.cx, Label.right);
     2024            Label.bottom = Label.top + infoPtr->nItemHeight;
     2025        }
     2026 
     2027        if (lprcLabel) *lprcLabel = Label;
     2028        TRACE("    - label=%s\n", debugrect(&Label));
     2029    }
     2030
     2031    /* Fix the Box if necessary */
     2032    if (lprcBox)
     2033    {
     2034        if (oversizedBox) UnionRect(lprcBox, &Box, &Label);
     2035        else *lprcBox = Box;
     2036    }
     2037    TRACE("    - box=%s\n", debugrect(&Box));
     2038}
     2039
     2040/***
     2041 * DESCRIPTION:            [INTERNAL]
     2042 *
     2043 * PARAMETER(S):
     2044 * [I] infoPtr : valid pointer to the listview structure
     2045 * [I] nItem : item number
     2046 * [O] lprcBox : ptr to Box rectangle
     2047 *
     2048 * RETURN:
     2049 *   None.
     2050 */
     2051static void LISTVIEW_GetItemBox(LISTVIEW_INFO *infoPtr, INT nItem, LPRECT lprcBox)
     2052{
     2053    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     2054    WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
     2055    POINT Position, Origin;
     2056    LVITEMW lvItem;
     2057
     2058    LISTVIEW_GetOrigin(infoPtr, &Origin);
     2059    LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position);
     2060
     2061    /* Be smart and try to figure out the minimum we have to do */
     2062    lvItem.mask = 0;
     2063    if (uView == LVS_ICON && infoPtr->bFocus && LISTVIEW_GetItemState(infoPtr, nItem, LVIS_FOCUSED))
     2064        lvItem.mask |= LVIF_TEXT;
     2065    lvItem.iItem = nItem;
     2066    lvItem.iSubItem = 0;
     2067    lvItem.pszText = szDispText;
     2068    lvItem.cchTextMax = DISP_TEXT_SIZE;
     2069    if (lvItem.mask) LISTVIEW_GetItemW(infoPtr, &lvItem);
     2070    if (uView == LVS_ICON)
     2071    {
     2072        lvItem.mask |= LVIF_STATE;
     2073        lvItem.stateMask = LVIS_FOCUSED;
     2074        lvItem.state = (lvItem.mask & LVIF_TEXT ? LVIS_FOCUSED : 0);
     2075    }
     2076    LISTVIEW_GetItemMetrics(infoPtr, &lvItem, lprcBox, 0, 0, 0);
     2077
     2078    OffsetRect(lprcBox, Position.x + Origin.x, Position.y + Origin.y);
     2079}
     2080
     2081
     2082/***
     2083 * DESCRIPTION:
     2084 * Returns the current icon position, and advances it along the top.
     2085 * The returned position is not offset by Origin.
     2086 *
     2087 * PARAMETER(S):
     2088 * [I] infoPtr : valid pointer to the listview structure
     2089 * [O] lpPos : will get the current icon position
    8512090 *
    8522091 * RETURN:
    8532092 * None
    8542093 */
    855 #ifdef __WIN32OS2__
    856 static VOID LISTVIEW_UpdateScroll(HWND hwnd)
    857 {
    858   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    859   INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
    860   INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
    861   SCROLLINFO scrollInfo;
    862   LONG dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
    863   UINT uView =  dwStyle & LVS_TYPEMASK;
    864 
    865   if (dwStyle & LVS_NOSCROLL)
    866   {
    867     infoPtr->lefttop.x = 0;
    868     infoPtr->lefttop.y = 0;
    869     infoPtr->maxScroll = infoPtr->lefttop;
    870     infoPtr->scrollPage = infoPtr->lefttop;
    871     infoPtr->scrollStep = infoPtr->lefttop;
    872     ShowScrollBar(hwnd,SB_BOTH,FALSE);
    873     return;
    874   }
    875 
    876   ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
    877   scrollInfo.cbSize = sizeof(SCROLLINFO);
    878 
    879   if (uView == LVS_LIST)
    880   {
    881     /* update horizontal scrollbar */
    882     INT nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
    883     INT nCountPerRow = LISTVIEW_GetCountPerRow(hwnd);
    884     INT nNumOfItems = GETITEMCOUNT(infoPtr);
    885 
    886     infoPtr->maxScroll.x = nNumOfItems/nCountPerColumn;
    887     if (nNumOfItems % nCountPerColumn)
    888       infoPtr->maxScroll.x++;
    889 
    890     infoPtr->lefttop.x = ListView_GetTopIndex(hwnd)/nCountPerColumn;
    891     infoPtr->scrollPage.x = nCountPerRow;
    892     infoPtr->scrollStep.x = infoPtr->nItemWidth;
    893 
    894     scrollInfo.nMin  = 0;
    895     scrollInfo.nMax  = infoPtr->maxScroll.x-1;
    896     scrollInfo.nPos  = infoPtr->lefttop.x;
    897     scrollInfo.nPage = infoPtr->scrollPage.x;
    898     scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
    899     SetScrollInfo(hwnd,SB_HORZ,&scrollInfo,TRUE);
    900   } else if (uView == LVS_REPORT)
    901   {
    902     /* update vertical scrollbar */
    903     infoPtr->maxScroll.y = GETITEMCOUNT(infoPtr);
    904     infoPtr->lefttop.y = ListView_GetTopIndex(hwnd);
    905     infoPtr->scrollPage.y = LISTVIEW_GetCountPerColumn(hwnd);
    906     infoPtr->scrollStep.y = infoPtr->nItemHeight;
    907 
    908     scrollInfo.nMin  = 0;
    909     scrollInfo.nMax  = infoPtr->maxScroll.y-1;
    910     scrollInfo.nPos  = infoPtr->lefttop.y;
    911     scrollInfo.nPage = infoPtr->scrollPage.y;
    912     scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
    913     SetScrollInfo(hwnd,SB_VERT,&scrollInfo,TRUE);
    914 
    915     /* update horizontal scrollbar */
    916     nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
    917     if (!(dwStyle & WS_HSCROLL) || !GETITEMCOUNT(infoPtr))
    918       infoPtr->lefttop.x = 0;
    919 
    920     infoPtr->scrollPage.x = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
    921     infoPtr->maxScroll.x = max(infoPtr->nItemWidth / LISTVIEW_SCROLL_DIV_SIZE, 0);
    922     infoPtr->scrollStep.x = LISTVIEW_SCROLL_DIV_SIZE;
    923 
    924     scrollInfo.nMin  = 0;
    925     scrollInfo.nMax  = infoPtr->maxScroll.x-1;
    926     scrollInfo.nPos  = infoPtr->lefttop.x;
    927     scrollInfo.nPage = infoPtr->scrollPage.x;
    928     scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
    929     SetScrollInfo(hwnd,SB_HORZ,&scrollInfo,TRUE);
    930 
    931     /* Update the Header Control */
    932     LISTVIEW_UpdateHeaderSize(hwnd,infoPtr->lefttop.x);
    933   } else
    934   {
    935     RECT rcView;
    936 
    937     if (LISTVIEW_GetViewRect(hwnd,&rcView))
    938     {
    939       INT nViewWidth = rcView.right - rcView.left;
    940       INT nViewHeight = rcView.bottom - rcView.top;
    941 
    942       /* Update Horizontal Scrollbar */
    943       if (!(dwStyle & WS_HSCROLL) || !GETITEMCOUNT(infoPtr))
    944         infoPtr->lefttop.x = 0;
    945       infoPtr->maxScroll.x = max(nViewWidth / LISTVIEW_SCROLL_DIV_SIZE, 0);
    946       infoPtr->scrollPage.x = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
    947       infoPtr->scrollStep.x = LISTVIEW_SCROLL_DIV_SIZE;
    948 
    949       scrollInfo.nMin  = 0;
    950       scrollInfo.nMax  = infoPtr->maxScroll.x-1;
    951       scrollInfo.nPos  = infoPtr->lefttop.x;
    952       scrollInfo.nPage = infoPtr->scrollPage.x;
    953       scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
    954       SetScrollInfo(hwnd,SB_HORZ,&scrollInfo,TRUE);
    955 
    956       /* Update Vertical Scrollbar */
    957       nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
    958       if (!(dwStyle & WS_VSCROLL) || !GETITEMCOUNT(infoPtr))
    959         infoPtr->lefttop.x = 0;
    960       infoPtr->maxScroll.y = max(nViewHeight / LISTVIEW_SCROLL_DIV_SIZE,0);
    961       infoPtr->scrollPage.y = nListHeight / LISTVIEW_SCROLL_DIV_SIZE;
    962       infoPtr->scrollStep.y = LISTVIEW_SCROLL_DIV_SIZE;
    963 
    964       scrollInfo.nMin  = 0;
    965       scrollInfo.nMax  = infoPtr->maxScroll.y-1;
    966       scrollInfo.nPos  = infoPtr->lefttop.y;
    967       scrollInfo.nPage = infoPtr->scrollPage.y;
    968       scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
    969       SetScrollInfo(hwnd,SB_VERT,&scrollInfo,TRUE);
    970     }
    971   }
    972 }
    973 #else
    974 static VOID LISTVIEW_UpdateScroll(HWND hwnd)
    975 {
    976   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    977   LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    978   UINT uView =  lStyle & LVS_TYPEMASK;
    979   INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
    980   INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
    981   SCROLLINFO scrollInfo;
    982 
    983   if (lStyle & LVS_NOSCROLL) return;
    984  
    985   ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
    986   scrollInfo.cbSize = sizeof(SCROLLINFO);
    987 
    988   if (uView == LVS_LIST)
    989   {
    990     /* update horizontal scrollbar */
    991 
    992     INT nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
    993     INT nCountPerRow = LISTVIEW_GetCountPerRow(hwnd);
    994     INT nNumOfItems = GETITEMCOUNT(infoPtr);
    995 
    996     scrollInfo.nMax = nNumOfItems / nCountPerColumn;
    997     if((nNumOfItems % nCountPerColumn) == 0)
    998     {
    999         scrollInfo.nMax--;
    1000     }
    1001     else
    1002     {
    1003         scrollInfo.nMax++;
    1004     }
    1005     scrollInfo.nPos = ListView_GetTopIndex(hwnd) / nCountPerColumn;
    1006     scrollInfo.nPage = nCountPerRow;
    1007     scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
    1008     SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
    1009     ShowScrollBar(hwnd, SB_VERT, FALSE);
    1010   }
    1011   else if (uView == LVS_REPORT)
    1012   {
    1013     /* update vertical scrollbar */
    1014     scrollInfo.nMin = 0;
    1015     scrollInfo.nMax = GETITEMCOUNT(infoPtr) - 1;
    1016     scrollInfo.nPos = ListView_GetTopIndex(hwnd);
    1017     scrollInfo.nPage = LISTVIEW_GetCountPerColumn(hwnd);
    1018     scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
    1019     SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
    1020 
    1021     /* update horizontal scrollbar */
    1022     nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
    1023     if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE
    1024        || GETITEMCOUNT(infoPtr) == 0)
    1025     {
    1026       scrollInfo.nPos = 0;
    1027     }
    1028     scrollInfo.nMin = 0;
    1029     scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE  ;
    1030     scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
    1031     scrollInfo.nMax = max(infoPtr->nItemWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
    1032     SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
    1033 
    1034     /* Update the Header Control */
    1035     scrollInfo.fMask = SIF_POS;
    1036     GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
    1037     LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
    1038 
    1039   }
    1040   else
    1041   {
    1042     RECT rcView;
    1043 
    1044     if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
    1045     {
    1046       INT nViewWidth = rcView.right - rcView.left;
    1047       INT nViewHeight = rcView.bottom - rcView.top;
    1048 
    1049       /* Update Horizontal Scrollbar */
    1050       scrollInfo.fMask = SIF_POS;
    1051       if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE
    1052         || GETITEMCOUNT(infoPtr) == 0)
    1053       {
    1054         scrollInfo.nPos = 0;
    1055       }
    1056       scrollInfo.nMax = max(nViewWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
    1057       scrollInfo.nMin = 0;
    1058       scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
    1059       scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
    1060       SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
    1061 
    1062       /* Update Vertical Scrollbar */
    1063       nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
    1064       scrollInfo.fMask = SIF_POS;
    1065       if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) == FALSE
    1066         || GETITEMCOUNT(infoPtr) == 0)
    1067       {
    1068         scrollInfo.nPos = 0;
    1069       }
    1070       scrollInfo.nMax = max(nViewHeight / LISTVIEW_SCROLL_DIV_SIZE,0)-1;
    1071       scrollInfo.nMin = 0;
    1072       scrollInfo.nPage = nListHeight / LISTVIEW_SCROLL_DIV_SIZE;
    1073       scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
    1074       SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
    1075     }
    1076   }
    1077 }
    1078 #endif
    1079 
    1080 /***
    1081  * DESCRIPTION:
    1082  * Prints a message for unsupported window styles.
    1083  * A kind of TODO list for window styles.
    1084  *
    1085  * PARAMETER(S):
    1086  * [I] LONG : window style
     2094static void LISTVIEW_NextIconPosTop(LISTVIEW_INFO *infoPtr, LPPOINT lpPos)
     2095{
     2096    INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
     2097   
     2098    *lpPos = infoPtr->currIconPos;
     2099   
     2100    infoPtr->currIconPos.x += infoPtr->nItemWidth;
     2101    if (infoPtr->currIconPos.x + infoPtr->nItemWidth <= nListWidth) return;
     2102
     2103    infoPtr->currIconPos.x  = 0;
     2104    infoPtr->currIconPos.y += infoPtr->nItemHeight;
     2105}
     2106
     2107   
     2108/***
     2109 * DESCRIPTION:
     2110 * Returns the current icon position, and advances it down the left edge.
     2111 * The returned position is not offset by Origin.
     2112 *
     2113 * PARAMETER(S):
     2114 * [I] infoPtr : valid pointer to the listview structure
     2115 * [O] lpPos : will get the current icon position
    10872116 *
    10882117 * RETURN:
    10892118 * None
    10902119 */
    1091 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle)
    1092 {
    1093   if ((LVS_TYPESTYLEMASK & lStyle) == LVS_NOSCROLL)
    1094     FIXME("  LVS_NOSCROLL\n");
    1095 
    1096   if (lStyle & LVS_EDITLABELS)
    1097     FIXME("  LVS_EDITLABELS\n");
    1098 
    1099   if (lStyle & LVS_NOLABELWRAP)
    1100     FIXME("  LVS_NOLABELWRAP\n");
    1101 
    1102   if (lStyle & LVS_SHAREIMAGELISTS)
    1103     FIXME("  LVS_SHAREIMAGELISTS\n");
    1104 
    1105   if (lStyle & LVS_SORTASCENDING)
    1106     FIXME("  LVS_SORTASCENDING\n");
    1107 
    1108   if (lStyle & LVS_SORTDESCENDING)
    1109     FIXME("  LVS_SORTDESCENDING\n");
    1110 }
    1111 
    1112 /***
    1113  * DESCRIPTION:
    1114  * Aligns the items with the top edge of the window.
    1115  *
    1116  * PARAMETER(S):
    1117  * [I] HWND : window handle
    1118  *
    1119  * RETURN:
    1120  * None
    1121  */
    1122 static VOID LISTVIEW_AlignTop(HWND hwnd)
    1123 {
    1124   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    1125   UINT uView = GetWindowLongW(hwnd, GWL_STYLE) & LVS_TYPEMASK;
    1126   INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
    1127   POINT ptItem;
    1128   RECT rcView;
    1129   INT i, off_x=0, off_y=0;
    1130  
    1131   if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
    1132   {
    1133     /* Since SetItemPosition uses upper-left of icon, and for
    1134        style=LVS_ICON the icon is not left adjusted, get the offset */
    1135     if (uView == LVS_ICON)
    1136     {
    1137       off_y = ICON_TOP_PADDING;
    1138       off_x = (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
    1139     }
    1140     ptItem.x = off_x;
    1141     ptItem.y = off_y;
    1142     ZeroMemory(&rcView, sizeof(RECT));
    1143 
    1144     if (nListWidth > infoPtr->nItemWidth)
    1145     {
    1146       for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
    1147       {
    1148         if (ptItem.x + infoPtr->nItemWidth > nListWidth)
    1149         {
    1150           ptItem.x = off_x;
    1151           ptItem.y += infoPtr->nItemHeight;
    1152         }
    1153        
    1154         LISTVIEW_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
    1155         ptItem.x += infoPtr->nItemWidth;
    1156         rcView.right = max(rcView.right, ptItem.x);
    1157       }
    1158 
    1159       rcView.bottom = ptItem.y + infoPtr->nItemHeight;
    1160     }
    1161     else
    1162     {
    1163       for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
    1164       {
    1165         LISTVIEW_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
    1166         ptItem.y += infoPtr->nItemHeight;
    1167       }
    1168 
    1169       rcView.right = infoPtr->nItemWidth;
    1170       rcView.bottom = ptItem.y;
    1171     }
    1172 
    1173     LISTVIEW_SetViewRect(hwnd, &rcView);
    1174   }
    1175 }
    1176 
    1177 /***
    1178  * DESCRIPTION:
    1179  * Aligns the items with the left edge of the window.
    1180  *
    1181  * PARAMETER(S):
    1182  * [I] HWND : window handle
    1183  *
    1184  * RETURN:
    1185  * None
    1186  */
    1187 static VOID LISTVIEW_AlignLeft(HWND hwnd)
    1188 {
    1189   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    1190   UINT uView = GetWindowLongW(hwnd, GWL_STYLE) & LVS_TYPEMASK;
    1191   INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
    1192   POINT ptItem;
    1193   RECT rcView;
    1194   INT i, off_x=0, off_y=0;
    1195  
    1196   if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
    1197   {
    1198     /* Since SetItemPosition uses upper-left of icon, and for
    1199        style=LVS_ICON the icon is not left adjusted, get the offset */
    1200     if (uView == LVS_ICON)
    1201     {
    1202       off_y = ICON_TOP_PADDING;
    1203       off_x = (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
    1204     }
    1205     ptItem.x = off_x;
    1206     ptItem.y = off_y;
    1207     ZeroMemory(&rcView, sizeof(RECT));
    1208 
    1209     if (nListHeight > infoPtr->nItemHeight)
    1210     {
    1211       for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
    1212       {
    1213         if (ptItem.y + infoPtr->nItemHeight > nListHeight)
    1214         {
    1215           ptItem.y = off_y;
    1216           ptItem.x += infoPtr->nItemWidth;
    1217         }
    1218 
    1219         LISTVIEW_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
    1220         ptItem.y += infoPtr->nItemHeight;
    1221         rcView.bottom = max(rcView.bottom, ptItem.y);
    1222       }
    1223 
    1224       rcView.right = ptItem.x + infoPtr->nItemWidth;
    1225     }
    1226     else
    1227     {
    1228       for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
    1229       {
    1230         LISTVIEW_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
    1231         ptItem.x += infoPtr->nItemWidth;
    1232       }
    1233 
    1234       rcView.bottom = infoPtr->nItemHeight;
    1235       rcView.right = ptItem.x;
    1236     }
    1237 
    1238     LISTVIEW_SetViewRect(hwnd, &rcView);
    1239   }
    1240 }
    1241 
    1242 /***
    1243  * DESCRIPTION:
    1244  * Set the bounding rectangle of all the items.
    1245  *
    1246  * PARAMETER(S):
    1247  * [I] HWND : window handle
    1248  * [I] LPRECT : bounding rectangle
     2120static void LISTVIEW_NextIconPosLeft(LISTVIEW_INFO *infoPtr, LPPOINT lpPos)
     2121{
     2122    INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
     2123   
     2124    *lpPos = infoPtr->currIconPos;
     2125   
     2126    infoPtr->currIconPos.y += infoPtr->nItemHeight;
     2127    if (infoPtr->currIconPos.y + infoPtr->nItemHeight <= nListHeight) return;
     2128
     2129    infoPtr->currIconPos.x += infoPtr->nItemWidth;
     2130    infoPtr->currIconPos.y  = 0;
     2131}
     2132
     2133   
     2134/***
     2135 * DESCRIPTION:
     2136 * Moves an icon to the specified position.
     2137 * It takes care of invalidating the item, etc.
     2138 *
     2139 * PARAMETER(S):
     2140 * [I] infoPtr : valid pointer to the listview structure
     2141 * [I] nItem : the item to move
     2142 * [I] lpPos : the new icon position
     2143 * [I] isNew : flags the item as being new
     2144 *
     2145 * RETURN:
     2146 *   Success: TRUE
     2147 *   Failure: FALSE
     2148 */
     2149static BOOL LISTVIEW_MoveIconTo(LISTVIEW_INFO *infoPtr, INT nItem, const POINT *lppt, BOOL isNew)
     2150{
     2151    POINT old;
     2152   
     2153    if (!isNew)
     2154    {
     2155        old.x = (LONG)DPA_GetPtr(infoPtr->hdpaPosX, nItem);
     2156        old.y = (LONG)DPA_GetPtr(infoPtr->hdpaPosY, nItem);
     2157   
     2158        if (lppt->x == old.x && lppt->y == old.y) return TRUE;
     2159        LISTVIEW_InvalidateItem(infoPtr, nItem);
     2160    }
     2161
     2162    /* Allocating a POINTER for every item is too resource intensive,
     2163     * so we'll keep the (x,y) in different arrays */
     2164    if (!DPA_SetPtr(infoPtr->hdpaPosX, nItem, (void *)lppt->x)) return FALSE;
     2165    if (!DPA_SetPtr(infoPtr->hdpaPosY, nItem, (void *)lppt->y)) return FALSE;
     2166
     2167    LISTVIEW_InvalidateItem(infoPtr, nItem);
     2168
     2169    return TRUE;
     2170}
     2171
     2172/***
     2173 * DESCRIPTION:
     2174 * Arranges listview items in icon display mode.
     2175 *
     2176 * PARAMETER(S):
     2177 * [I] infoPtr : valid pointer to the listview structure
     2178 * [I] nAlignCode : alignment code
    12492179 *
    12502180 * RETURN:
     
    12522182 *   FAILURE : FALSE
    12532183 */
    1254 static LRESULT LISTVIEW_SetViewRect(HWND hwnd, LPRECT lprcView)
    1255 {
    1256   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongW(hwnd, 0);
    1257   BOOL bResult = FALSE;
    1258 
    1259   TRACE("(hwnd=%x, left=%d, top=%d, right=%d, bottom=%d)\n", hwnd,
    1260         lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
     2184static BOOL LISTVIEW_Arrange(LISTVIEW_INFO *infoPtr, INT nAlignCode)
     2185{
     2186    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     2187    void (*next_pos)(LISTVIEW_INFO *, LPPOINT);
     2188    POINT pos;
     2189    INT i;
     2190
     2191    if (uView != LVS_ICON && uView != LVS_SMALLICON) return FALSE;
    12612192 
    1262   if (lprcView != NULL)
    1263   {
    1264     bResult = TRUE;
    1265     infoPtr->rcView.left = lprcView->left;
    1266     infoPtr->rcView.top = lprcView->top;
    1267     infoPtr->rcView.right = lprcView->right;
    1268     infoPtr->rcView.bottom = lprcView->bottom;
    1269   }
    1270 
    1271   return bResult;
    1272 }
    1273 
    1274 /***
    1275  * DESCRIPTION:
    1276  * Retrieves the bounding rectangle of all the items.
    1277  *
    1278  * PARAMETER(S):
    1279  * [I] HWND : window handle
    1280  * [O] LPRECT : bounding rectangle
     2193    TRACE("nAlignCode=%d\n", nAlignCode);
     2194
     2195    if (nAlignCode == LVA_DEFAULT)
     2196    {
     2197        if (infoPtr->dwStyle & LVS_ALIGNLEFT) nAlignCode = LVA_ALIGNLEFT;
     2198        else nAlignCode = LVA_ALIGNTOP;
     2199    }
     2200   
     2201    switch (nAlignCode)
     2202    {
     2203    case LVA_ALIGNLEFT:  next_pos = LISTVIEW_NextIconPosLeft; break;
     2204    case LVA_ALIGNTOP:   next_pos = LISTVIEW_NextIconPosTop;  break;
     2205    case LVA_SNAPTOGRID: next_pos = LISTVIEW_NextIconPosTop;  break; /* FIXME */
     2206    default: return FALSE;
     2207    }
     2208   
     2209    infoPtr->bAutoarrange = TRUE;
     2210    infoPtr->currIconPos.x = infoPtr->currIconPos.y = 0;
     2211    for (i = 0; i < infoPtr->nItemCount; i++)
     2212    {
     2213        next_pos(infoPtr, &pos);
     2214        LISTVIEW_MoveIconTo(infoPtr, i, &pos, FALSE);
     2215    }
     2216
     2217    return TRUE;
     2218}
     2219 
     2220/***
     2221 * DESCRIPTION:
     2222 * Retrieves the bounding rectangle of all the items, not offset by Origin.
     2223 *
     2224 * PARAMETER(S):
     2225 * [I] infoPtr : valid pointer to the listview structure
     2226 * [O] lprcView : bounding rectangle
    12812227 *
    12822228 * RETURN:
     
    12842230 *   FAILURE : FALSE
    12852231 */
    1286 static LRESULT LISTVIEW_GetViewRect(HWND hwnd, LPRECT lprcView)
    1287 {
    1288   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongW(hwnd, 0);
    1289   BOOL bResult = FALSE;
    1290   POINT ptOrigin;
    1291 
    1292   TRACE("(hwnd=%x, lprcView=%p)\n", hwnd, lprcView);
    1293 
    1294   if (lprcView != NULL)
    1295   {
    1296     bResult = LISTVIEW_GetOrigin(hwnd, &ptOrigin);
    1297     if (bResult != FALSE)
    1298     {
    1299       lprcView->left = infoPtr->rcView.left + ptOrigin.x;
    1300       lprcView->top = infoPtr->rcView.top + ptOrigin.y;
    1301       lprcView->right = infoPtr->rcView.right + ptOrigin.x;
    1302       lprcView->bottom = infoPtr->rcView.bottom + ptOrigin.y;
    1303     }
    1304 
    1305     TRACE("(left=%d, top=%d, right=%d, bottom=%d)\n",
    1306           lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
    1307   }
    1308 
    1309   return bResult;
     2232static void LISTVIEW_GetAreaRect(LISTVIEW_INFO *infoPtr, LPRECT lprcView)
     2233{
     2234    INT i, x, y;
     2235
     2236    SetRectEmpty(lprcView);
     2237
     2238    switch (infoPtr->dwStyle & LVS_TYPEMASK)
     2239    {
     2240    case LVS_ICON:
     2241    case LVS_SMALLICON:
     2242        for (i = 0; i < infoPtr->nItemCount; i++)
     2243        {
     2244            x = (LONG)DPA_GetPtr(infoPtr->hdpaPosX, i);
     2245           y = (LONG)DPA_GetPtr(infoPtr->hdpaPosY, i);
     2246            lprcView->right = max(lprcView->right, x);
     2247            lprcView->bottom = max(lprcView->bottom, y);
     2248        }
     2249        if (infoPtr->nItemCount > 0)
     2250        {
     2251            lprcView->right += infoPtr->nItemWidth;
     2252            lprcView->bottom += infoPtr->nItemHeight;
     2253        }
     2254        break;
     2255
     2256    case LVS_LIST:
     2257        y = LISTVIEW_GetCountPerColumn(infoPtr);
     2258        x = infoPtr->nItemCount / y;
     2259        if (infoPtr->nItemCount % y) x++;
     2260        lprcView->right = x * infoPtr->nItemWidth;
     2261        lprcView->bottom = y * infoPtr->nItemHeight;
     2262        break;
     2263       
     2264    case LVS_REPORT:       
     2265        lprcView->right = infoPtr->nItemWidth;
     2266        lprcView->bottom = infoPtr->nItemCount * infoPtr->nItemHeight;
     2267        break;
     2268    }
     2269}
     2270
     2271/***
     2272 * DESCRIPTION:
     2273 * Retrieves the bounding rectangle of all the items.
     2274 *
     2275 * PARAMETER(S):
     2276 * [I] infoPtr : valid pointer to the listview structure
     2277 * [O] lprcView : bounding rectangle
     2278 *
     2279 * RETURN:
     2280 *   SUCCESS : TRUE
     2281 *   FAILURE : FALSE
     2282 */
     2283static BOOL LISTVIEW_GetViewRect(LISTVIEW_INFO *infoPtr, LPRECT lprcView)
     2284{
     2285    POINT ptOrigin;
     2286
     2287    TRACE("(lprcView=%p)\n", lprcView);
     2288
     2289    if (!lprcView) return FALSE;
     2290 
     2291    LISTVIEW_GetOrigin(infoPtr, &ptOrigin);
     2292    LISTVIEW_GetAreaRect(infoPtr, lprcView);
     2293    OffsetRect(lprcView, ptOrigin.x, ptOrigin.y);
     2294
     2295    TRACE("lprcView=%s\n", debugrect(lprcView));
     2296
     2297    return TRUE;
    13102298}
    13112299
     
    13132301 * DESCRIPTION:
    13142302 * Retrieves the subitem pointer associated with the subitem index.
    1315  * 
    1316  * PARAMETER(S):
    1317  * [I] HDPA : DPA handle for a specific item
    1318  * [I] INT : index of subitem
     2303 *
     2304 * PARAMETER(S):
     2305 * [I] hdpaSubItems : DPA handle for a specific item
     2306 * [I] nSubItem : index of subitem
    13192307 *
    13202308 * RETURN:
     
    13222310 *   FAILURE : NULL
    13232311 */
    1324 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems,
    1325                                                 INT nSubItem)
    1326 {
    1327   LISTVIEW_SUBITEM *lpSubItem;
    1328   INT i;
    1329 
    1330   for (i = 1; i < hdpaSubItems->nItemCount; i++)
    1331   {
    1332     lpSubItem = (LISTVIEW_SUBITEM *) DPA_GetPtr(hdpaSubItems, i);
    1333     if (lpSubItem != NULL)
    1334     {
    1335       if (lpSubItem->iSubItem == nSubItem)
    1336       {
    1337         return lpSubItem;
    1338       }
    1339     }
    1340   }
    1341 
    1342   return NULL;
    1343 }
    1344 
    1345 /***
    1346  * DESCRIPTION:
    1347  * Calculates the width of an item.
    1348  *
    1349  * PARAMETER(S):
    1350  * [I] HWND : window handle
    1351  * [I] LONG : window style
    1352  *
    1353  * RETURN:
    1354  * Returns item width.
    1355  */
    1356 static INT LISTVIEW_GetItemWidth(HWND hwnd)
    1357 {
    1358   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    1359   LONG style = GetWindowLongW(hwnd, GWL_STYLE);
    1360   UINT uView = style & LVS_TYPEMASK;
    1361   INT nHeaderItemCount;
    1362   RECT rcHeaderItem;
    1363   INT nItemWidth = 0;
    1364   INT nLabelWidth;
    1365   INT i;
    1366 
    1367   TRACE("(hwnd=%x)\n", hwnd);
    1368 
    1369   if (uView == LVS_ICON)
    1370   {
    1371     nItemWidth = infoPtr->iconSpacing.cx;
    1372   }
    1373   else if (uView == LVS_REPORT)
    1374   {
    1375     RECT rect;
    1376     /* calculate width of header */
    1377     nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
    1378     for (i = 0; i < nHeaderItemCount; i++)
    1379     {
    1380       if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
    1381       {
    1382         nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
    1383       }
    1384     }
    1385 #ifdef __WIN32OS2__
    1386     //SvL: An item can never be bigger than the client area
    1387     if(GetClientRect(hwnd, &rect)) {
    1388         nItemWidth = MIN(rect.right - rect.left, nItemWidth);
    1389     }
    1390 #endif
    1391   }
    1392   else
    1393   {
    1394     for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
    1395     {
    1396       nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, i);
    1397       nItemWidth = max(nItemWidth, nLabelWidth);
    1398     }
    1399    
    1400     /* default label size */
    1401     if (GETITEMCOUNT(infoPtr) == 0)
    1402     {
    1403       nItemWidth = DEFAULT_COLUMN_WIDTH;
    1404     }
     2312static SUBITEM_INFO* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems, INT nSubItem)
     2313{
     2314    SUBITEM_INFO *lpSubItem;
     2315    INT i;
     2316
     2317    /* we should binary search here if need be */
     2318    for (i = 1; i < hdpaSubItems->nItemCount; i++)
     2319    {
     2320        lpSubItem = (SUBITEM_INFO *)DPA_GetPtr(hdpaSubItems, i);
     2321        if (lpSubItem->iSubItem == nSubItem)
     2322            return lpSubItem;
     2323    }
     2324
     2325    return NULL;
     2326}
     2327
     2328
     2329/***
     2330 * DESCRIPTION:
     2331 * Caclulates the desired item width.
     2332 *
     2333 * PARAMETER(S):
     2334 * [I] infoPtr : valid pointer to the listview structure
     2335 *
     2336 * RETURN:
     2337 *  The desired item width.
     2338 */
     2339static INT LISTVIEW_CalculateItemWidth(LISTVIEW_INFO *infoPtr)
     2340{
     2341    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     2342    INT nItemWidth = 0;
     2343
     2344    TRACE("uView=%d\n", uView);
     2345
     2346    if (uView == LVS_ICON)
     2347        nItemWidth = infoPtr->iconSpacing.cx;
     2348    else if (uView == LVS_REPORT)
     2349    {
     2350        RECT rcHeader;
     2351
     2352        if (infoPtr->hdpaColumns->nItemCount > 0)
     2353        {
     2354            LISTVIEW_GetHeaderRect(infoPtr, infoPtr->hdpaColumns->nItemCount - 1, &rcHeader);
     2355            nItemWidth = rcHeader.right;
     2356        }
     2357    }
     2358    else /* LVS_SMALLICON, or LVS_LIST */
     2359    {
     2360        INT i;
     2361       
     2362        for (i = 0; i < infoPtr->nItemCount; i++)
     2363            nItemWidth = max(LISTVIEW_GetLabelWidth(infoPtr, i), nItemWidth);
     2364
     2365        if (infoPtr->himlSmall) nItemWidth += infoPtr->iconSize.cx;
     2366        if (infoPtr->himlState) nItemWidth += infoPtr->iconStateSize.cx;
     2367
     2368        nItemWidth = max(DEFAULT_COLUMN_WIDTH, nItemWidth + WIDTH_PADDING);
     2369    }
     2370
     2371    return max(nItemWidth, 1);
     2372}
     2373
     2374/***
     2375 * DESCRIPTION:
     2376 * Caclulates the desired item height.
     2377 *
     2378 * PARAMETER(S):
     2379 * [I] infoPtr : valid pointer to the listview structure
     2380 *
     2381 * RETURN:
     2382 *  The desired item height.
     2383 */
     2384static INT LISTVIEW_CalculateItemHeight(LISTVIEW_INFO *infoPtr)
     2385{
     2386    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     2387    INT nItemHeight;
     2388
     2389    TRACE("uView=%d\n", uView);
     2390
     2391    if (uView == LVS_ICON)
     2392        nItemHeight = infoPtr->iconSpacing.cy;
    14052393    else
    14062394    {
    1407       if (nItemWidth == 0)
    1408       {
    1409         nItemWidth = DEFAULT_LABEL_WIDTH;
    1410       }
    1411       else
    1412       {
    1413         /* add padding */
    1414         nItemWidth += WIDTH_PADDING;
    1415      
    1416         if (infoPtr->himlSmall != NULL)
    1417         {
    1418           nItemWidth += infoPtr->iconSize.cx;
    1419         }
    1420 
    1421         if (infoPtr->himlState != NULL)
    1422         {
    1423           nItemWidth += infoPtr->iconSize.cx;
    1424         }
    1425       }
    1426     }
    1427   }
    1428   if(nItemWidth == 0)
    1429   {
    1430       /* nItemWidth Cannot be Zero */
    1431       nItemWidth = 1;
    1432   }
    1433   return nItemWidth;
    1434 }
    1435 
    1436 /***
    1437  * DESCRIPTION:
    1438  * Calculates the width of a specific item.
    1439  *
    1440  * PARAMETER(S):
    1441  * [I] HWND : window handle
    1442  * [I] LPSTR : string 
    1443  *
    1444  * RETURN:
    1445  * Returns the width of an item width a specified string.
    1446  */
    1447 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem)
    1448 {
    1449   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    1450   UINT uView = GetWindowLongW(hwnd, GWL_STYLE) & LVS_TYPEMASK;
    1451   INT nHeaderItemCount;
    1452   RECT rcHeaderItem;
    1453   INT nItemWidth = 0;
    1454   INT i;
    1455 
    1456   TRACE("(hwnd=%x)\n", hwnd);
    1457 
    1458   if (uView == LVS_ICON)
    1459   {
    1460     nItemWidth = infoPtr->iconSpacing.cx;
    1461   }
    1462   else if (uView == LVS_REPORT)
    1463   {
    1464     /* calculate width of header */
    1465     nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
    1466     for (i = 0; i < nHeaderItemCount; i++)
    1467     {
    1468       if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
    1469       {
    1470         nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
    1471       }
    1472     }
    1473   }
    1474   else
    1475   {
    1476     /* get width of string */
    1477     nItemWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
    1478 
    1479     /* default label size */
    1480     if (GETITEMCOUNT(infoPtr) == 0)
    1481     {
    1482       nItemWidth = DEFAULT_COLUMN_WIDTH;
    1483     }
    1484     else
    1485     {
    1486       if (nItemWidth == 0)
    1487       {
    1488         nItemWidth = DEFAULT_LABEL_WIDTH;
    1489       }
    1490       else
    1491       {
    1492         /* add padding */
    1493         nItemWidth += WIDTH_PADDING;
    1494      
    1495         if (infoPtr->himlSmall != NULL)
    1496         {
    1497           nItemWidth += infoPtr->iconSize.cx;
    1498         }
    1499 
    1500         if (infoPtr->himlState != NULL)
    1501         {
    1502           nItemWidth += infoPtr->iconSize.cx;
    1503         }
    1504       }
    1505     }
    1506   }
    1507  
    1508   return nItemWidth;
    1509 }
     2395        nItemHeight = infoPtr->ntmHeight;
     2396        if (infoPtr->himlState)
     2397            nItemHeight = max(nItemHeight, infoPtr->iconStateSize.cy);
     2398        if (infoPtr->himlSmall)
     2399            nItemHeight = max(nItemHeight, infoPtr->iconSize.cy);
     2400        if (infoPtr->himlState || infoPtr->himlSmall)
     2401            nItemHeight += HEIGHT_PADDING;
     2402    }
     2403
     2404    return max(nItemHeight, 1);
     2405}
     2406
     2407/***
     2408 * DESCRIPTION:
     2409 * Updates the width, and height of an item.
     2410 *
     2411 * PARAMETER(S):
     2412 * [I] infoPtr : valid pointer to the listview structure
     2413 *
     2414 * RETURN:
     2415 *  None.
     2416 */
     2417static inline void LISTVIEW_UpdateItemSize(LISTVIEW_INFO *infoPtr)
     2418{
     2419    infoPtr->nItemWidth = LISTVIEW_CalculateItemWidth(infoPtr);
     2420    infoPtr->nItemHeight = LISTVIEW_CalculateItemHeight(infoPtr);
     2421}
     2422
    15102423
    15112424/***
     
    15152428 *
    15162429 * PARAMETER(S):
    1517  * [I] HWND : window handle
    1518  *
    1519  */
    1520 static VOID LISTVIEW_SaveTextMetrics(HWND hwnd)
    1521 {
    1522   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    1523   TEXTMETRICW tm;
    1524   HDC hdc = GetDC(hwnd);
    1525   HFONT hOldFont = SelectObject(hdc, infoPtr->hFont);
    1526   INT oldHeight, oldACW;
    1527 
    1528   GetTextMetricsW(hdc, &tm);
    1529 
    1530   oldHeight = infoPtr->ntmHeight;
    1531   oldACW = infoPtr->ntmAveCharWidth;
    1532   infoPtr->ntmHeight = tm.tmHeight;
    1533   infoPtr->ntmAveCharWidth = tm.tmAveCharWidth;
    1534 
    1535   SelectObject(hdc, hOldFont);
    1536   ReleaseDC(hwnd, hdc);
    1537   TRACE("tmHeight old=%d,new=%d; tmAveCharWidth old=%d,new=%d\n",
    1538         oldHeight, infoPtr->ntmHeight, oldACW, infoPtr->ntmAveCharWidth);
    1539 }
    1540 
    1541 
    1542 /***
    1543  * DESCRIPTION:
    1544  * Calculates the height of an item.
    1545  *
    1546  * PARAMETER(S):
    1547  * [I] HWND : window handle
    1548  *
    1549  * RETURN:
    1550  * Returns item height.
    1551  */
    1552 static INT LISTVIEW_GetItemHeight(HWND hwnd)
    1553 {
    1554   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    1555 #ifdef __WIN32OS2__
    1556   DWORD dwStyle = GetWindowLongA(hwnd, GWL_STYLE);
    1557   UINT uView = dwStyle & LVS_TYPEMASK;
     2430 * [I] infoPtr : valid pointer to the listview structure
     2431 *
     2432 */
     2433static void LISTVIEW_SaveTextMetrics(LISTVIEW_INFO *infoPtr)
     2434{
     2435    HDC hdc = GetDC(infoPtr->hwndSelf);
     2436    HFONT hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
     2437    HFONT hOldFont = SelectObject(hdc, hFont);
     2438    TEXTMETRICW tm;
     2439
     2440    if (GetTextMetricsW(hdc, &tm))
     2441    {
     2442        infoPtr->ntmHeight = tm.tmHeight;
     2443        infoPtr->ntmAveCharWidth = tm.tmAveCharWidth;
     2444    }
     2445    SelectObject(hdc, hOldFont);
     2446    ReleaseDC(infoPtr->hwndSelf, hdc);
     2447   
     2448    TRACE("tmHeight=%d\n", infoPtr->ntmHeight);
     2449}
     2450
     2451/***
     2452 * DESCRIPTION:
     2453 * A compare function for ranges
     2454 *
     2455 * PARAMETER(S)
     2456 * [I] range1 : pointer to range 1;
     2457 * [I] range2 : pointer to range 2;
     2458 * [I] flags : flags
     2459 *
     2460 * RETURNS:
     2461 * > 0 : if range 1 > range 2
     2462 * < 0 : if range 2 > range 1
     2463 * = 0 : if range intersects range 2
     2464 */
     2465static INT CALLBACK ranges_cmp(LPVOID range1, LPVOID range2, LPARAM flags)
     2466{
     2467    INT cmp;
     2468   
     2469    if (((RANGE*)range1)->upper <= ((RANGE*)range2)->lower)
     2470        cmp = -1;
     2471    else if (((RANGE*)range2)->upper <= ((RANGE*)range1)->lower)
     2472        cmp = 1;
     2473    else
     2474        cmp = 0;
     2475   
     2476    TRACE("range1=%s, range2=%s, cmp=%d\n", debugrange((RANGE*)range1), debugrange((RANGE*)range2), cmp);
     2477
     2478    return cmp;
     2479}
     2480
     2481#if DEBUG_RANGES
     2482#define ranges_check(ranges, desc) ranges_assert(ranges, desc, __FUNCTION__, __LINE__)
    15582483#else
    1559   UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
     2484#define ranges_check(ranges, desc) do { } while(0)
    15602485#endif
    1561   INT nItemHeight = 0;
    1562 
    1563   if (uView == LVS_ICON)
    1564   {
    1565     nItemHeight = infoPtr->iconSpacing.cy;
    1566   }
    1567   else
    1568   {
    1569     if(infoPtr->himlState || infoPtr->himlSmall)
    1570       nItemHeight = max(infoPtr->ntmHeight, infoPtr->iconSize.cy) + HEIGHT_PADDING;
     2486
     2487static void ranges_assert(RANGES ranges, LPCSTR desc, const char *func, int line)
     2488{
     2489    INT i;
     2490    RANGE *prev, *curr;
     2491   
     2492    TRACE("*** Checking %s:%d:%s ***\n", func, line, desc);
     2493    assert (ranges);
     2494    assert (ranges->hdpa->nItemCount >= 0);
     2495    ranges_dump(ranges);
     2496    prev = (RANGE *)DPA_GetPtr(ranges->hdpa, 0);
     2497    if (ranges->hdpa->nItemCount > 0)
     2498        assert (prev->lower >= 0 && prev->lower < prev->upper);
     2499    for (i = 1; i < ranges->hdpa->nItemCount; i++)
     2500    {
     2501        curr = (RANGE *)DPA_GetPtr(ranges->hdpa, i);
     2502        assert (prev->upper <= curr->lower);
     2503        assert (curr->lower < curr->upper);
     2504        prev = curr;
     2505    }
     2506    TRACE("--- Done checking---\n");
     2507}
     2508
     2509static RANGES ranges_create(int count)
     2510{
     2511    RANGES ranges = (RANGES)COMCTL32_Alloc(sizeof(struct tagRANGES));
     2512    if (!ranges) return NULL;
     2513    ranges->hdpa = DPA_Create(count);
     2514    if (ranges->hdpa) return ranges;
     2515    COMCTL32_Free(ranges);
     2516    return NULL;
     2517}
     2518
     2519static void ranges_clear(RANGES ranges)
     2520{
     2521    INT i;
     2522       
     2523    for(i = 0; i < ranges->hdpa->nItemCount; i++)
     2524        COMCTL32_Free(DPA_GetPtr(ranges->hdpa, i));
     2525    DPA_DeleteAllPtrs(ranges->hdpa);
     2526}
     2527
     2528
     2529static void ranges_destroy(RANGES ranges)
     2530{
     2531    if (!ranges) return;
     2532    ranges_clear(ranges);
     2533    DPA_Destroy(ranges->hdpa);
     2534    COMCTL32_Free(ranges);
     2535}
     2536
     2537static RANGES ranges_clone(RANGES ranges)
     2538{
     2539    RANGES clone;
     2540    INT i;
     2541           
     2542    if (!(clone = ranges_create(ranges->hdpa->nItemCount))) goto fail;
     2543
     2544    for (i = 0; i < ranges->hdpa->nItemCount; i++)
     2545    {
     2546        RANGE *newrng = (RANGE *)COMCTL32_Alloc(sizeof(RANGE));
     2547        if (!newrng) goto fail;
     2548        *newrng = *((RANGE*)DPA_GetPtr(ranges->hdpa, i));
     2549        DPA_SetPtr(clone->hdpa, i, newrng);
     2550    }
     2551    return clone;
     2552   
     2553fail:
     2554    TRACE ("clone failed\n");
     2555    ranges_destroy(clone);
     2556    return NULL;
     2557}
     2558
     2559static RANGES ranges_diff(RANGES ranges, RANGES sub)
     2560{
     2561    INT i;
     2562
     2563    for (i = 0; i < sub->hdpa->nItemCount; i++)
     2564        ranges_del(ranges, *((RANGE *)DPA_GetPtr(sub->hdpa, i)));
     2565
     2566    return ranges;
     2567}
     2568
     2569static void ranges_dump(RANGES ranges)
     2570{
     2571    INT i;
     2572
     2573    for (i = 0; i < ranges->hdpa->nItemCount; i++)
     2574        TRACE("   %s\n", debugrange(DPA_GetPtr(ranges->hdpa, i)));
     2575}
     2576
     2577static inline BOOL ranges_contain(RANGES ranges, INT nItem)
     2578{
     2579    RANGE srchrng = { nItem, nItem + 1 };
     2580
     2581    TRACE("(nItem=%d)\n", nItem);
     2582    ranges_check(ranges, "before contain");
     2583    return DPA_Search(ranges->hdpa, &srchrng, 0, ranges_cmp, 0, DPAS_SORTED) != -1;
     2584}
     2585
     2586static INT ranges_itemcount(RANGES ranges)
     2587{
     2588    INT i, count = 0;
     2589   
     2590    for (i = 0; i < ranges->hdpa->nItemCount; i++)
     2591    {
     2592        RANGE *sel = DPA_GetPtr(ranges->hdpa, i);
     2593        count += sel->upper - sel->lower;
     2594    }
     2595
     2596    return count;
     2597}
     2598
     2599static BOOL ranges_shift(RANGES ranges, INT nItem, INT delta, INT nUpper)
     2600{
     2601    RANGE srchrng = { nItem, nItem + 1 }, *chkrng;
     2602    INT index;
     2603
     2604    index = DPA_Search(ranges->hdpa, &srchrng, 0, ranges_cmp, 0, DPAS_SORTED | DPAS_INSERTAFTER);
     2605    if (index == -1) return TRUE;
     2606
     2607    for (; index < ranges->hdpa->nItemCount; index++)
     2608    {
     2609        chkrng = DPA_GetPtr(ranges->hdpa, index);
     2610        if (chkrng->lower >= nItem)
     2611            chkrng->lower = max(min(chkrng->lower + delta, nUpper - 1), 0);
     2612        if (chkrng->upper > nItem)
     2613            chkrng->upper = max(min(chkrng->upper + delta, nUpper), 0);
     2614    }
     2615    return TRUE;
     2616}
     2617
     2618static BOOL ranges_add(RANGES ranges, RANGE range)
     2619{
     2620    RANGE srchrgn;
     2621    INT index;
     2622
     2623    TRACE("(%s)\n", debugrange(&range));
     2624    ranges_check(ranges, "before add");
     2625
     2626    /* try find overlapping regions first */
     2627    srchrgn.lower = range.lower - 1;
     2628    srchrgn.upper = range.upper + 1;
     2629    index = DPA_Search(ranges->hdpa, &srchrgn, 0, ranges_cmp, 0, DPAS_SORTED);
     2630   
     2631    if (index == -1)
     2632    {
     2633        RANGE *newrgn;
     2634
     2635        TRACE("Adding new range\n");
     2636
     2637        /* create the brand new range to insert */     
     2638        newrgn = (RANGE *)COMCTL32_Alloc(sizeof(RANGE));
     2639        if(!newrgn) goto fail;
     2640        *newrgn = range;
     2641       
     2642        /* figure out where to insert it */
     2643        index = DPA_Search(ranges->hdpa, newrgn, 0, ranges_cmp, 0, DPAS_SORTED | DPAS_INSERTAFTER);
     2644        TRACE("index=%d\n", index);
     2645        if (index == -1) index = 0;
     2646       
     2647        /* and get it over with */
     2648        if (DPA_InsertPtr(ranges->hdpa, index, newrgn) == -1)
     2649        {
     2650            COMCTL32_Free(newrgn);
     2651            goto fail;
     2652        }
     2653    }
    15712654    else
    1572       nItemHeight = infoPtr->ntmHeight;
    1573 #ifdef __WIN32OS2__
    1574   if(dwStyle & LVS_OWNERDRAWFIXED) {
    1575         /* Get item height */
    1576 
    1577         MEASUREITEMSTRUCT mis;
    1578         UINT              id = GetWindowLongA(hwnd,GWL_ID);
    1579 
    1580         mis.CtlType    = ODT_LISTVIEW;
    1581         mis.CtlID      = id;
    1582         mis.itemID     = 0;
    1583         mis.itemData   = 0;     //TODO:!!!!
    1584         mis.itemHeight = nItemHeight;
    1585         SendMessageA(GetParent(hwnd), WM_MEASUREITEM, id, (LPARAM)&mis );
    1586         nItemHeight = mis.itemHeight;
    1587     }
    1588 #endif
    1589   }
    1590   return nItemHeight;
    1591 }
    1592 
    1593 
    1594 static void LISTVIEW_PrintSelectionRanges(HWND hwnd)
    1595 {
    1596   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    1597   LISTVIEW_SELECTION *selection;
    1598   INT topSelection = infoPtr->hdpaSelectionRanges->nItemCount;
    1599   INT i;
    1600 
    1601   TRACE("Selections are:\n");
    1602   for (i = 0; i < topSelection; i++)
    1603   {
    1604     selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,i);
    1605     TRACE("     %lu - %lu\n",selection->lower,selection->upper);
    1606   }
    1607 }
    1608 
    1609 /***
    1610  * DESCRIPTION:
    1611  * A compare function for selection ranges
    1612  *
    1613  *PARAMETER(S)
    1614  * [I] LPVOID : Item 1;
    1615  * [I] LPVOID : Item 2;
    1616  * [I] LPARAM : flags
    1617  *
    1618  *RETURNS:
    1619  * >0 : if Item 1 > Item 2
    1620  * <0 : if Item 2 > Item 1
    1621  * 0 : if Item 1 == Item 2
    1622  */
    1623 static INT CALLBACK LISTVIEW_CompareSelectionRanges(LPVOID range1, LPVOID range2,
    1624                                                     LPARAM flags)
    1625 {
    1626   int l1 = ((LISTVIEW_SELECTION*)(range1))->lower;
    1627   int l2 = ((LISTVIEW_SELECTION*)(range2))->lower;
    1628   int u1 = ((LISTVIEW_SELECTION*)(range1))->upper;
    1629   int u2 = ((LISTVIEW_SELECTION*)(range2))->upper;
    1630   int rc=0;
    1631 
    1632   if (u1 < l2)
    1633     rc= -1;
    1634  
    1635   if (u2 < l1)
    1636      rc= 1;
    1637 
    1638   return rc;
    1639 }
    1640 
    1641 /**
    1642 * DESCRIPTION:
    1643 * Adds a selection range.
    1644 *
    1645 * PARAMETER(S):
    1646 * [I] HWND : window handle
    1647 * [I] INT : lower item index
    1648 * [I] INT : upper item index
    1649 *
    1650 * RETURN:
    1651 * None
    1652 */
    1653 static VOID LISTVIEW_AddSelectionRange(HWND hwnd, INT lItem, INT uItem)
    1654 {
    1655  LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    1656  LISTVIEW_SELECTION *selection;
    1657  INT topSelection = infoPtr->hdpaSelectionRanges->nItemCount;
    1658  BOOL lowerzero=FALSE;
    1659 
    1660  selection = (LISTVIEW_SELECTION *)COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION));
    1661  selection->lower = lItem;
    1662  selection->upper = uItem;
    1663 
    1664  TRACE("Add range %i - %i\n", lItem, uItem);
    1665  if (topSelection)
    1666  {
    1667    LISTVIEW_SELECTION *checkselection,*checkselection2;
    1668    INT index,mergeindex;
    1669 
    1670    /* find overlapping selections */
    1671    /* we want to catch adjacent ranges so expand our range by 1 */
    1672 
    1673    selection->upper++;
    1674    if (selection->lower == 0)
    1675      lowerzero = TRUE;
    1676    else
    1677      selection->lower--;
    1678 
    1679    index = DPA_Search(infoPtr->hdpaSelectionRanges, selection, 0,
    1680                       LISTVIEW_CompareSelectionRanges,
    1681                       0,0);
    1682    selection->upper --;
    1683    if (lowerzero)
    1684      lowerzero=FALSE;
    1685    else
    1686      selection->lower ++;
    1687 
    1688    if (index >=0)
    1689    {
    1690      checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,index);
    1691      TRACE("Merge with index %i (%lu - %lu)\n",index,checkselection->lower,
    1692            checkselection->upper);
    1693      
    1694      checkselection->lower = min(selection->lower,checkselection->lower);
    1695      checkselection->upper = max(selection->upper,checkselection->upper);
    1696    
    1697      TRACE("New range (%lu - %lu)\n", checkselection->lower,
    1698            checkselection->upper);
    1699 
    1700      COMCTL32_Free(selection);   
    1701  
    1702      /* merge now common selection ranges in the lower group*/
    1703      do
    1704      {
    1705         checkselection->upper ++;
    1706         if (checkselection->lower == 0)
    1707           lowerzero = TRUE;
    1708         else
    1709           checkselection->lower --;
    1710 
    1711         TRACE("search lower range (%lu - %lu)\n", checkselection->lower,
    1712               checkselection->upper);
    1713 
    1714         /* not sorted yet */
    1715         mergeindex = DPA_Search(infoPtr->hdpaSelectionRanges, checkselection, 0,
    1716                                 LISTVIEW_CompareSelectionRanges, 0,
    1717                                 0);
    1718 
    1719         checkselection->upper --;
    1720         if (lowerzero)
    1721           lowerzero = FALSE;
    1722         else
    1723           checkselection->lower ++;
    1724 
    1725         if (mergeindex >=0  && mergeindex != index)
    1726         {
    1727           TRACE("Merge with index %i\n",mergeindex);
    1728           checkselection2 = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
    1729                                        mergeindex);
    1730           checkselection->lower = min(checkselection->lower,
    1731                                       checkselection2->lower);
    1732           checkselection->upper = max(checkselection->upper,
    1733                                       checkselection2->upper);
    1734           COMCTL32_Free(checkselection2);
    1735           DPA_DeletePtr(infoPtr->hdpaSelectionRanges,mergeindex);
    1736           index --;
    1737         }
    1738      }
    1739      while (mergeindex > -1 && mergeindex <index);
    1740 
    1741      /* merge now common selection ranges in the upper group*/
    1742     do
    1743     {
    1744        checkselection->upper ++;
    1745        if (checkselection->lower == 0)
    1746          lowerzero = TRUE;
    1747        else
    1748          checkselection->lower --;
    1749 
    1750        TRACE("search upper range %i (%lu - %lu)\n",index,
    1751              checkselection->lower, checkselection->upper);
    1752 
    1753        /* not sorted yet */
    1754        mergeindex = DPA_Search(infoPtr->hdpaSelectionRanges, checkselection,
    1755                                index+1,
    1756                                LISTVIEW_CompareSelectionRanges, 0,
    1757                                0);
    1758 
    1759        checkselection->upper --;
    1760        if (lowerzero)
    1761          lowerzero = FALSE;
    1762        else
    1763          checkselection->lower ++;
    1764 
    1765        if (mergeindex >=0 && mergeindex !=index)
    1766        {
    1767          TRACE("Merge with index %i\n",mergeindex);
    1768          checkselection2 = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
    1769                                       mergeindex);
    1770          checkselection->lower = min(checkselection->lower,
    1771                                      checkselection2->lower);
    1772          checkselection->upper = max(checkselection->upper,
    1773                                      checkselection2->upper);
    1774          COMCTL32_Free(checkselection2);
    1775          DPA_DeletePtr(infoPtr->hdpaSelectionRanges,mergeindex);
    1776        }
    1777     }
    1778     while (mergeindex > -1);
    1779    }
    1780    else
    1781    {
    1782 
    1783      index = DPA_Search(infoPtr->hdpaSelectionRanges, selection, 0,
    1784                        LISTVIEW_CompareSelectionRanges, 0,
    1785                        DPAS_INSERTAFTER);
    1786 
    1787      TRACE("Insert before index %i\n",index);
    1788      if (index == -1)
    1789        index = 0;
    1790      DPA_InsertPtr(infoPtr->hdpaSelectionRanges,index,selection);
    1791    }
    1792  }
    1793  else
    1794  {
    1795    DPA_InsertPtr(infoPtr->hdpaSelectionRanges,0,selection);
    1796  }
    1797  /*
    1798   * Incase of error
    1799   */
    1800  DPA_Sort(infoPtr->hdpaSelectionRanges,LISTVIEW_CompareSelectionRanges,0);
    1801  LISTVIEW_PrintSelectionRanges(hwnd);
    1802 }
    1803 
    1804 /**
    1805 * DESCRIPTION:
    1806 * check if a specified index is selected.
    1807 *
    1808 * PARAMETER(S):
    1809 * [I] HWND : window handle
    1810 * [I] INT : item index
    1811 *
    1812 * RETURN:
    1813 * None
    1814 */
    1815 static BOOL LISTVIEW_IsSelected(HWND hwnd, INT nItem)
    1816 {
    1817   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    1818   LISTVIEW_SELECTION selection;
    1819   INT index;
    1820 
    1821   selection.upper = nItem;
    1822   selection.lower = nItem;
    1823 
    1824   index = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, 0,
    1825                       LISTVIEW_CompareSelectionRanges,
    1826                       0,DPAS_SORTED);
    1827   if (index != -1)
     2655    {
     2656        RANGE *chkrgn, *mrgrgn;
     2657        INT fromindex, mergeindex;
     2658
     2659        chkrgn = DPA_GetPtr(ranges->hdpa, index);
     2660        TRACE("Merge with %s @%d\n", debugrange(chkrgn), index);
     2661
     2662        chkrgn->lower = min(range.lower, chkrgn->lower);
     2663        chkrgn->upper = max(range.upper, chkrgn->upper);
     2664       
     2665        TRACE("New range %s @%d\n", debugrange(chkrgn), index);
     2666
     2667        /* merge now common anges */
     2668        fromindex = 0;
     2669        srchrgn.lower = chkrgn->lower - 1;
     2670        srchrgn.upper = chkrgn->upper + 1;
     2671           
     2672        do
     2673        {
     2674            mergeindex = DPA_Search(ranges->hdpa, &srchrgn, fromindex, ranges_cmp, 0, 0);
     2675            if (mergeindex == -1) break;
     2676            if (mergeindex == index)
     2677            {
     2678                fromindex = index + 1;
     2679                continue;
     2680            }
     2681         
     2682            TRACE("Merge with index %i\n", mergeindex);
     2683           
     2684            mrgrgn = DPA_GetPtr(ranges->hdpa, mergeindex);
     2685            chkrgn->lower = min(chkrgn->lower, mrgrgn->lower);
     2686            chkrgn->upper = max(chkrgn->upper, mrgrgn->upper);
     2687            COMCTL32_Free(mrgrgn);
     2688            DPA_DeletePtr(ranges->hdpa, mergeindex);
     2689            if (mergeindex < index) index --;
     2690        } while(1);
     2691    }
     2692
     2693    ranges_check(ranges, "after add");
    18282694    return TRUE;
    1829   else
     2695   
     2696fail:
     2697    ranges_check(ranges, "failed add");
     2698    return FALSE;
     2699}
     2700
     2701static BOOL ranges_del(RANGES ranges, RANGE range)
     2702{
     2703    RANGE *chkrgn;
     2704    INT index;
     2705
     2706    TRACE("(%s)\n", debugrange(&range));
     2707    ranges_check(ranges, "before del");
     2708   
     2709    /* we don't use DPAS_SORTED here, since we need *
     2710     * to find the first overlapping range          */
     2711    index = DPA_Search(ranges->hdpa, &range, 0, ranges_cmp, 0, 0);
     2712    while(index != -1)
     2713    {
     2714        chkrgn = DPA_GetPtr(ranges->hdpa, index);
     2715       
     2716        TRACE("Matches range %s @%d\n", debugrange(chkrgn), index);
     2717
     2718        /* case 1: Same range */
     2719        if ( (chkrgn->upper == range.upper) &&
     2720             (chkrgn->lower == range.lower) )
     2721        {
     2722            DPA_DeletePtr(ranges->hdpa, index);
     2723            break;
     2724        }
     2725        /* case 2: engulf */
     2726        else if ( (chkrgn->upper <= range.upper) &&
     2727                  (chkrgn->lower >= range.lower) )
     2728        {
     2729            DPA_DeletePtr(ranges->hdpa, index);
     2730        }
     2731        /* case 3: overlap upper */
     2732        else if ( (chkrgn->upper <= range.upper) &&
     2733                  (chkrgn->lower < range.lower) )
     2734        {
     2735            chkrgn->upper = range.lower;
     2736        }
     2737        /* case 4: overlap lower */
     2738        else if ( (chkrgn->upper > range.upper) &&
     2739                  (chkrgn->lower >= range.lower) )
     2740        {
     2741            chkrgn->lower = range.upper;
     2742            break;
     2743        }
     2744        /* case 5: fully internal */
     2745        else
     2746        {
     2747            RANGE tmprgn = *chkrgn, *newrgn;
     2748
     2749            if (!(newrgn = (RANGE *)COMCTL32_Alloc(sizeof(RANGE)))) goto fail;
     2750            newrgn->lower = chkrgn->lower;
     2751            newrgn->upper = range.lower;
     2752            chkrgn->lower = range.upper;
     2753            if (DPA_InsertPtr(ranges->hdpa, index, newrgn) == -1)
     2754            {
     2755                COMCTL32_Free(newrgn);
     2756                goto fail;
     2757            }
     2758            chkrgn = &tmprgn;
     2759            break;
     2760        }
     2761
     2762        index = DPA_Search(ranges->hdpa, &range, index, ranges_cmp, 0, 0);
     2763    }
     2764
     2765    ranges_check(ranges, "after del");
     2766    return TRUE;
     2767
     2768fail:
     2769    ranges_check(ranges, "failed del");
    18302770    return FALSE;
    18312771}
     
    18362776*
    18372777* Parameters(s):
    1838 *   HWND: window handle
     2778* [I] infoPtr : valid pointer to the listview structure
     2779* [I] toSkip : item range to skip removing the selection
    18392780*
    18402781* RETURNS:
     
    18422783*   FAILURE : TRUE
    18432784*/
    1844 static LRESULT LISTVIEW_RemoveAllSelections(HWND hwnd)
    1845 {
    1846   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    1847   LISTVIEW_SELECTION *selection;
    1848   INT i;
    1849   LVITEMW item;
    1850  
    1851   TRACE("(0x%x)\n",hwnd);
    1852 
    1853   ZeroMemory(&item,sizeof(item));
    1854   item.stateMask = LVIS_SELECTED;
    1855 
    1856   do
    1857   {
    1858     selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,0);
    1859     if (selection)
    1860     {
    1861       TRACE("Removing %lu to %lu\n",selection->lower, selection->upper);
    1862       for (i = selection->lower; i<=selection->upper; i++)
    1863         LISTVIEW_SetItemState(hwnd,i,&item);
    1864       LISTVIEW_RemoveSelectionRange(hwnd,selection->lower,selection->upper);
    1865     }
    1866   }
    1867   while (infoPtr->hdpaSelectionRanges->nItemCount>0);
    1868 
    1869   TRACE("done\n");
    1870   return TRUE;
     2785static BOOL LISTVIEW_DeselectAllSkipItems(LISTVIEW_INFO *infoPtr, RANGES toSkip)
     2786{
     2787    LVITEMW lvItem;
     2788    ITERATOR i;
     2789    RANGES clone;
     2790
     2791    TRACE("()\n");
     2792
     2793    lvItem.state = 0;
     2794    lvItem.stateMask = LVIS_SELECTED;
     2795   
     2796    /* need to clone the DPA because callbacks can change it */
     2797    if (!(clone = ranges_clone(infoPtr->selectionRanges))) return FALSE;
     2798    iterator_rangesitems(&i, ranges_diff(clone, toSkip));
     2799    while(iterator_next(&i))
     2800        LISTVIEW_SetItemState(infoPtr, i.nItem, &lvItem);
     2801    /* note that the iterator destructor will free the cloned range */
     2802    iterator_destroy(&i);
     2803
     2804    return TRUE;
     2805}
     2806
     2807static inline BOOL LISTVIEW_DeselectAllSkipItem(LISTVIEW_INFO *infoPtr, INT nItem)
     2808{
     2809    RANGES toSkip;
     2810   
     2811    if (!(toSkip = ranges_create(1))) return FALSE;
     2812    if (nItem != -1) ranges_additem(toSkip, nItem);
     2813    LISTVIEW_DeselectAllSkipItems(infoPtr, toSkip);
     2814    ranges_destroy(toSkip);
     2815    return TRUE;
     2816}
     2817
     2818static inline BOOL LISTVIEW_DeselectAll(LISTVIEW_INFO *infoPtr)
     2819{
     2820    return LISTVIEW_DeselectAllSkipItem(infoPtr, -1);
     2821}
     2822
     2823/***
     2824 * DESCRIPTION:
     2825 * Retrieves the number of items that are marked as selected.
     2826 *
     2827 * PARAMETER(S):
     2828 * [I] infoPtr : valid pointer to the listview structure
     2829 *
     2830 * RETURN:
     2831 * Number of items selected.
     2832 */
     2833static INT LISTVIEW_GetSelectedCount(LISTVIEW_INFO *infoPtr)
     2834{
     2835    INT nSelectedCount = 0;
     2836
     2837    if (infoPtr->uCallbackMask & LVIS_SELECTED)
     2838    {
     2839        INT i;
     2840        for (i = 0; i < infoPtr->nItemCount; i++)
     2841        {
     2842            if (LISTVIEW_GetItemState(infoPtr, i, LVIS_SELECTED))
     2843                nSelectedCount++;
     2844        }
     2845    }
     2846    else
     2847        nSelectedCount = ranges_itemcount(infoPtr->selectionRanges);
     2848
     2849    TRACE("nSelectedCount=%d\n", nSelectedCount);
     2850    return nSelectedCount;
     2851}
     2852
     2853/***
     2854 * DESCRIPTION:
     2855 * Manages the item focus.
     2856 *
     2857 * PARAMETER(S):
     2858 * [I] infoPtr : valid pointer to the listview structure
     2859 * [I] nItem : item index
     2860 *
     2861 * RETURN:
     2862 *   TRUE : focused item changed
     2863 *   FALSE : focused item has NOT changed
     2864 */
     2865static inline BOOL LISTVIEW_SetItemFocus(LISTVIEW_INFO *infoPtr, INT nItem)
     2866{
     2867    INT oldFocus = infoPtr->nFocusedItem;
     2868    LVITEMW lvItem;
     2869
     2870    if (nItem == infoPtr->nFocusedItem) return FALSE;
     2871   
     2872    lvItem.state =  nItem == -1 ? 0 : LVIS_FOCUSED;
     2873    lvItem.stateMask = LVIS_FOCUSED;
     2874    LISTVIEW_SetItemState(infoPtr, nItem == -1 ? infoPtr->nFocusedItem : nItem, &lvItem);
     2875
     2876    return oldFocus != infoPtr->nFocusedItem;
     2877}
     2878
     2879/* Helper function for LISTVIEW_ShiftIndices *only* */
     2880static INT shift_item(LISTVIEW_INFO *infoPtr, INT nShiftItem, INT nItem, INT direction)
     2881{
     2882    if (nShiftItem < nItem) return nShiftItem;
     2883
     2884    if (nShiftItem > nItem) return nShiftItem + direction;
     2885
     2886    if (direction > 0) return nShiftItem + direction;
     2887
     2888    return min(nShiftItem, infoPtr->nItemCount - 1);
    18712889}
    18722890
    18732891/**
    18742892* DESCRIPTION:
    1875 * Removes a range selections.
    1876 * 
     2893* Updates the various indices after an item has been inserted or deleted.
     2894*
    18772895* PARAMETER(S):
    1878 * [I] HWND : window handle
    1879 * [I] INT : lower item index
    1880 * [I] INT : upper item index
     2896* [I] infoPtr : valid pointer to the listview structure
     2897* [I] nItem : item index
     2898* [I] direction : Direction of shift, +1 or -1.
    18812899*
    18822900* RETURN:
    18832901* None
    18842902*/
    1885 static VOID LISTVIEW_RemoveSelectionRange(HWND hwnd, INT lItem, INT uItem)
    1886 {
    1887   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    1888   LISTVIEW_SELECTION removeselection,*checkselection;
    1889   INT index;
    1890 
    1891   removeselection.lower = lItem;
    1892   removeselection.upper = uItem;
    1893 
    1894   TRACE("Remove range %lu - %lu\n",removeselection.lower,removeselection.upper);
    1895   LISTVIEW_PrintSelectionRanges(hwnd);
    1896 
    1897   index = DPA_Search(infoPtr->hdpaSelectionRanges, &removeselection, 0,
    1898                      LISTVIEW_CompareSelectionRanges,
    1899                      0,0);
    1900  
    1901   if (index == -1)
    1902     return;
    1903 
    1904  
    1905   checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
    1906                               index);
    1907 
    1908   TRACE("Matches range index %i (%lu-%lu)\n",index,checkselection->lower,
    1909         checkselection->upper);
    1910 
    1911   /* case 1: Same */
    1912   if ((checkselection->upper == removeselection.upper) &&
    1913      (checkselection->lower == removeselection.lower))
    1914   {
    1915     DPA_DeletePtr(infoPtr->hdpaSelectionRanges,index);
    1916     TRACE("Case 1\n");
    1917   }
    1918   /* case 2: engulf */
    1919   else if (((checkselection->upper < removeselection.upper) &&
    1920       (checkselection->lower > removeselection.lower))||
    1921      ((checkselection->upper <= removeselection.upper) &&
    1922       (checkselection->lower > removeselection.lower)) ||
    1923      ((checkselection->upper < removeselection.upper) &&
    1924       (checkselection->lower >= removeselection.lower)))
    1925 
    1926   {
    1927     DPA_DeletePtr(infoPtr->hdpaSelectionRanges,index);
    1928     /* do it again because others may also get caught */
    1929     TRACE("Case 2\n");
    1930     LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
    1931   }
    1932   /* case 3: overlap upper */
    1933   else if ((checkselection->upper < removeselection.upper) &&
    1934       (checkselection->lower < removeselection.lower))
    1935   {
    1936     checkselection->upper = removeselection.lower - 1;
    1937     TRACE("Case 3\n");
    1938     LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
    1939   }
    1940   /* case 4: overlap lower */
    1941   else if ((checkselection->upper > removeselection.upper) &&
    1942       (checkselection->lower > removeselection.lower))
    1943   {
    1944     checkselection->lower = removeselection.upper + 1;
    1945     TRACE("Case 4\n");
    1946     LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
    1947   }
    1948   /* case 5: fully internal */
    1949   else if (checkselection->upper == removeselection.upper)
    1950     checkselection->upper = removeselection.lower - 1;
    1951   else if (checkselection->lower == removeselection.lower)
    1952     checkselection->lower = removeselection.upper + 1;
    1953   else
    1954   {
    1955     /* bisect the range */
    1956     LISTVIEW_SELECTION *newselection;
    1957    
    1958     newselection = (LISTVIEW_SELECTION *)
    1959                           COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION));
    1960     newselection -> lower = checkselection->lower;
    1961     newselection -> upper = removeselection.lower - 1;
    1962     checkselection -> lower = removeselection.upper + 1;
    1963     DPA_InsertPtr(infoPtr->hdpaSelectionRanges,index,newselection);
    1964     TRACE("Case 5\n");
    1965     DPA_Sort(infoPtr->hdpaSelectionRanges,LISTVIEW_CompareSelectionRanges,0);
    1966   }
    1967   LISTVIEW_PrintSelectionRanges(hwnd);
    1968 }
     2903static void LISTVIEW_ShiftIndices(LISTVIEW_INFO *infoPtr, INT nItem, INT direction)
     2904{
     2905    INT nNewFocus;
     2906    BOOL bOldChange;
     2907
     2908    /* temporarily disable change notification while shifting items */
     2909    bOldChange = infoPtr->bDoChangeNotify;
     2910    infoPtr->bDoChangeNotify = FALSE;
     2911
     2912    TRACE("Shifting %iu, %i steps\n", nItem, direction);
     2913
     2914    ranges_shift(infoPtr->selectionRanges, nItem, direction, infoPtr->nItemCount);
     2915
     2916    assert(abs(direction) == 1);
     2917
     2918    infoPtr->nSelectionMark = shift_item(infoPtr, infoPtr->nSelectionMark, nItem, direction);
     2919
     2920    nNewFocus = shift_item(infoPtr, infoPtr->nFocusedItem, nItem, direction);
     2921    if (nNewFocus != infoPtr->nFocusedItem)
     2922        LISTVIEW_SetItemFocus(infoPtr, nNewFocus);
     2923   
     2924    /* But we are not supposed to modify nHotItem! */
     2925
     2926    infoPtr->bDoChangeNotify = bOldChange;
     2927}
     2928
    19692929
    19702930/**
    1971 * DESCRIPTION:
    1972 * Updates the various indices after an item has been inserted or deleted.
    1973 *
    1974 * PARAMETER(S):
    1975 * [I] HWND : window handle
    1976 * [I] INT : item index
    1977 * [I] INT : Direction of shift, +1 or -1.
    1978 *
    1979 * RETURN:
    1980 * None
    1981 */
    1982 static VOID LISTVIEW_ShiftIndices(HWND hwnd, INT nItem, INT direction)
    1983 {
    1984   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    1985   LISTVIEW_SELECTION selection,*checkselection;
    1986   INT index;
    1987 
    1988   TRACE("Shifting %iu, %i steps\n",nItem,direction);
    1989 
    1990   selection.upper = nItem;
    1991   selection.lower = nItem;
    1992 
    1993   index = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, 0,
    1994                      LISTVIEW_CompareSelectionRanges,
    1995                      0,DPAS_SORTED|DPAS_INSERTAFTER);
    1996 
    1997   while ((index < infoPtr->hdpaSelectionRanges->nItemCount)&&(index != -1))
    1998   {
    1999     checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,index);
    2000     if ((checkselection->lower >= nItem)&&
    2001        (checkselection->lower + direction >= 0))
    2002         checkselection->lower += direction;
    2003     if ((checkselection->upper >= nItem)&&
    2004        (checkselection->upper + direction >=0))
    2005         checkselection->upper += direction;
    2006     index ++;
    2007   }
    2008 
    2009   /* Note that the following will fail if direction != +1 and -1 */
    2010   if (infoPtr->nSelectionMark > nItem)
    2011       infoPtr->nSelectionMark += direction;
    2012   else if (infoPtr->nSelectionMark == nItem)
    2013   {
    2014     if (direction > 0)
    2015       infoPtr->nSelectionMark += direction;
    2016     else if (infoPtr->nSelectionMark >= GETITEMCOUNT(infoPtr))
    2017       infoPtr->nSelectionMark = GETITEMCOUNT(infoPtr) - 1;
    2018   }
    2019 
    2020   if (infoPtr->nFocusedItem > nItem)
    2021     infoPtr->nFocusedItem += direction;
    2022   else if (infoPtr->nFocusedItem == nItem)
    2023   {
    2024     if (direction > 0)
    2025       infoPtr->nFocusedItem += direction;
     2931 * DESCRIPTION:
     2932 * Adds a block of selections.
     2933 *
     2934 * PARAMETER(S):
     2935 * [I] infoPtr : valid pointer to the listview structure
     2936 * [I] nItem : item index
     2937 *
     2938 * RETURN:
     2939 * None
     2940 */
     2941static void LISTVIEW_AddGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem)
     2942{
     2943    INT nFirst = min(infoPtr->nSelectionMark, nItem);
     2944    INT nLast = max(infoPtr->nSelectionMark, nItem);
     2945    INT i;
     2946    LVITEMW item;
     2947
     2948    if (nFirst == -1) nFirst = nItem;
     2949
     2950    item.state = LVIS_SELECTED;
     2951    item.stateMask = LVIS_SELECTED;
     2952
     2953    /* FIXME: this is not correct LVS_OWNERDATA
     2954     * setting the item states individually will generate
     2955     * a LVN_ITEMCHANGED notification for each one. Instead,
     2956     * we have to send a LVN_ODSTATECHANGED notification.
     2957     * See MSDN documentation for LVN_ITEMCHANGED.
     2958     */
     2959    for (i = nFirst; i <= nLast; i++)
     2960        LISTVIEW_SetItemState(infoPtr,i,&item);
     2961}
     2962
     2963
     2964/***
     2965 * DESCRIPTION:
     2966 * Sets a single group selection.
     2967 *
     2968 * PARAMETER(S):
     2969 * [I] infoPtr : valid pointer to the listview structure
     2970 * [I] nItem : item index
     2971 *
     2972 * RETURN:
     2973 * None
     2974 */
     2975static void LISTVIEW_SetGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem)
     2976{
     2977    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     2978    RANGES selection;
     2979    LVITEMW item;
     2980    ITERATOR i;
     2981
     2982    if (!(selection = ranges_create(100))) return;
     2983
     2984    item.state = LVIS_SELECTED;
     2985    item.stateMask = LVIS_SELECTED;
     2986
     2987    if ((uView == LVS_LIST) || (uView == LVS_REPORT))
     2988    {
     2989        if (infoPtr->nSelectionMark == -1)
     2990        {
     2991            infoPtr->nSelectionMark = nItem;
     2992            ranges_additem(selection, nItem);
     2993        }
     2994        else
     2995        {
     2996            RANGE sel;
     2997           
     2998            sel.lower = min(infoPtr->nSelectionMark, nItem);
     2999            sel.upper = max(infoPtr->nSelectionMark, nItem) + 1;
     3000            ranges_add(selection, sel);
     3001        }
     3002    }
    20263003    else
    20273004    {
    2028       if (infoPtr->nFocusedItem >= GETITEMCOUNT(infoPtr))
    2029         infoPtr->nFocusedItem = GETITEMCOUNT(infoPtr) - 1;
    2030       if (infoPtr->nFocusedItem >= 0)
    2031         LISTVIEW_SetItemFocus(hwnd, infoPtr->nFocusedItem);
    2032     }
    2033   }
    2034   /* But we are not supposed to modify nHotItem! */
    2035 }
    2036 
    2037 
    2038 /**
    2039  * DESCRIPTION:
    2040  * Adds a block of selections.
    2041  *
    2042  * PARAMETER(S):
    2043  * [I] HWND : window handle
    2044  * [I] INT : item index
     3005        RECT rcItem, rcSel, rcSelMark;
     3006        POINT ptItem;
     3007       
     3008        rcItem.left = LVIR_BOUNDS;
     3009        if (!LISTVIEW_GetItemRect(infoPtr, nItem, &rcItem)) return;
     3010        rcSelMark.left = LVIR_BOUNDS;
     3011        if (!LISTVIEW_GetItemRect(infoPtr, infoPtr->nSelectionMark, &rcSelMark)) return;
     3012        UnionRect(&rcSel, &rcItem, &rcSelMark);
     3013        iterator_frameditems(&i, infoPtr, &rcSel);
     3014        while(iterator_next(&i))
     3015        {
     3016            LISTVIEW_GetItemPosition(infoPtr, i.nItem, &ptItem);
     3017            if (PtInRect(&rcSel, ptItem)) ranges_additem(selection, i.nItem);
     3018        }
     3019        iterator_destroy(&i);
     3020    }
     3021
     3022    LISTVIEW_DeselectAllSkipItems(infoPtr, selection);
     3023    iterator_rangesitems(&i, selection);
     3024    while(iterator_next(&i))
     3025        LISTVIEW_SetItemState(infoPtr, i.nItem, &item);
     3026    /* this will also destroy the selection */
     3027    iterator_destroy(&i);
     3028   
     3029    LISTVIEW_SetItemFocus(infoPtr, nItem);
     3030}
     3031
     3032/***
     3033 * DESCRIPTION:
     3034 * Sets a single selection.
     3035 *
     3036 * PARAMETER(S):
     3037 * [I] infoPtr : valid pointer to the listview structure
     3038 * [I] nItem : item index
    20453039 *
    20463040 * RETURN:
    20473041 * None
    20483042 */
    2049 static VOID LISTVIEW_AddGroupSelection(HWND hwnd, INT nItem)
    2050 {
    2051   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    2052   INT nFirst = min(infoPtr->nSelectionMark, nItem);
    2053   INT nLast = max(infoPtr->nSelectionMark, nItem);
    2054   INT i;
    2055   LVITEMW item;
    2056 
    2057   if (nFirst == -1)
    2058     nFirst = nItem;
    2059 
    2060   ZeroMemory(&item,sizeof(item));
    2061   item.stateMask = LVIS_SELECTED;
    2062   item.state = LVIS_SELECTED;
    2063 
    2064   for (i = nFirst; i <= nLast; i++)
    2065     LISTVIEW_SetItemState(hwnd,i,&item);
    2066 
    2067   LISTVIEW_SetItemFocus(hwnd, nItem);
    2068   infoPtr->nSelectionMark = nItem;
    2069 }
    2070 
    2071 
    2072 /***
    2073  * DESCRIPTION:
    2074  * Adds a single selection.
    2075  *
    2076  * PARAMETER(S):
    2077  * [I] HWND : window handle
    2078  * [I] INT : item index
    2079  *
    2080  * RETURN:
    2081  * None
    2082  */
    2083 static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem)
    2084 {
    2085   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    2086   LVITEMW item;
    2087 
    2088   ZeroMemory(&item,sizeof(item));
    2089   item.state = LVIS_SELECTED;
    2090   item.stateMask = LVIS_SELECTED;
    2091 
    2092   LISTVIEW_SetItemState(hwnd,nItem,&item);
    2093 
    2094   LISTVIEW_SetItemFocus(hwnd, nItem);
    2095   infoPtr->nSelectionMark = nItem;
    2096 }
    2097 
    2098 /***
    2099  * DESCRIPTION:
    2100  * Selects or unselects an item.
    2101  *
    2102  * PARAMETER(S):
    2103  * [I] HWND : window handle
    2104  * [I] INT : item index
    2105  *
    2106  * RETURN:
    2107  *   SELECT: TRUE
    2108  *   UNSELECT : FALSE
    2109  */
    2110 static BOOL LISTVIEW_ToggleSelection(HWND hwnd, INT nItem)
    2111 {
    2112   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    2113   BOOL bResult;
    2114   LVITEMW item;
    2115 
    2116   ZeroMemory(&item,sizeof(item));
    2117   item.stateMask = LVIS_SELECTED;
    2118 
    2119   if (LISTVIEW_IsSelected(hwnd,nItem))
    2120   {
    2121     LISTVIEW_SetItemState(hwnd,nItem,&item);
    2122     bResult = FALSE;
    2123   }
    2124   else
    2125   {
    2126     item.state = LVIS_SELECTED;
    2127     LISTVIEW_SetItemState(hwnd,nItem,&item);
    2128     bResult = TRUE;
    2129   }
    2130 
    2131   LISTVIEW_SetItemFocus(hwnd, nItem);
    2132   infoPtr->nSelectionMark = nItem;
    2133 
    2134   return bResult;
    2135 }
    2136 
    2137 /***
    2138  * DESCRIPTION:
    2139  * Selects items based on view coordinates.
    2140  *
    2141  * PARAMETER(S):
    2142  * [I] HWND : window handle
    2143  * [I] RECT : selection rectangle 
    2144  *
    2145  * RETURN:
    2146  * None
    2147  */
    2148 static VOID LISTVIEW_SetSelectionRect(HWND hwnd, RECT rcSelRect)
    2149 {
    2150   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    2151   POINT ptItem;
    2152   INT i;
    2153   LVITEMW item;
    2154 
    2155   ZeroMemory(&item,sizeof(item));
    2156   item.stateMask = LVIS_SELECTED;
    2157 
    2158   for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
    2159   {
    2160     LISTVIEW_GetItemPosition(hwnd, i, &ptItem);
    2161 
    2162     if (PtInRect(&rcSelRect, ptItem) != FALSE)
    2163       item.state = LVIS_SELECTED;
    2164     else
    2165       item.state = 0;
    2166     LISTVIEW_SetItemState(hwnd,i,&item);
    2167   }
    2168 }
    2169 
    2170 /***
    2171  * DESCRIPTION:
    2172  * Sets a single group selection.
    2173  *
    2174  * PARAMETER(S):
    2175  * [I] HWND : window handle
    2176  * [I] INT : item index
    2177  *
    2178  * RETURN:
    2179  * None
    2180  */
    2181 static VOID LISTVIEW_SetGroupSelection(HWND hwnd, INT nItem)
    2182 {
    2183   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    2184   UINT uView = GetWindowLongW(hwnd, GWL_STYLE) & LVS_TYPEMASK;
    2185   LVITEMW item;
    2186 
    2187   ZeroMemory(&item,sizeof(item));
    2188   item.stateMask = LVIS_SELECTED;
    2189 
    2190   if ((uView == LVS_LIST) || (uView == LVS_REPORT))
    2191   {
    2192     INT i;
    2193     INT nFirst, nLast;
    2194 
    2195     if (infoPtr->nSelectionMark == -1)
    2196     {
    2197       infoPtr->nSelectionMark = nFirst = nLast = nItem;
    2198     }
    2199     else
    2200     {
    2201       nFirst = min(infoPtr->nSelectionMark, nItem);
    2202       nLast = max(infoPtr->nSelectionMark, nItem);
    2203     }
    2204 
    2205     for (i = 0; i <= GETITEMCOUNT(infoPtr); i++)
    2206     {
    2207       if ((i < nFirst) || (i > nLast))
    2208         item.state = 0;
    2209       else
    2210         item.state = LVIS_SELECTED;
    2211       LISTVIEW_SetItemState(hwnd,i,&item);
    2212     }
    2213   }
    2214   else
    2215   {
    2216     RECT rcItem;
    2217     RECT rcSelMark;
    2218     RECT rcSel;
    2219     LISTVIEW_GetItemBoundBox(hwnd, nItem, &rcItem);
    2220     LISTVIEW_GetItemBoundBox(hwnd, infoPtr->nSelectionMark, &rcSelMark);
    2221     rcSel.left = min(rcSelMark.left, rcItem.left);
    2222     rcSel.top = min(rcSelMark.top, rcItem.top);
    2223     rcSel.right = max(rcSelMark.right, rcItem.right);
    2224     rcSel.bottom = max(rcSelMark.bottom, rcItem.bottom);
    2225     LISTVIEW_SetSelectionRect(hwnd, rcSel);
    2226     TRACE("item %d (%d,%d)-(%d,%d), mark %d (%d,%d)-(%d,%d), sel (%d,%d)-(%d,%d)\n",
    2227           nItem, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom,
    2228           infoPtr->nSelectionMark,
    2229           rcSelMark.left, rcSelMark.top, rcSelMark.right, rcSelMark.bottom,
    2230           rcSel.left, rcSel.top, rcSel.right, rcSel.bottom);
    2231 
    2232   }
    2233 
    2234   LISTVIEW_SetItemFocus(hwnd, nItem);
    2235 }
    2236 
    2237 /***
    2238  * DESCRIPTION:
    2239  * Manages the item focus.
    2240  *
    2241  * PARAMETER(S):
    2242  * [I] HWND : window handle
    2243  * [I] INT : item index
    2244  *
    2245  * RETURN:
    2246  *   TRUE : focused item changed
    2247  *   FALSE : focused item has NOT changed
    2248  */
    2249 static BOOL LISTVIEW_SetItemFocus(HWND hwnd, INT nItem)
    2250 {
    2251   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    2252   BOOL bResult = FALSE;
    2253   LVITEMW lvItem;
    2254 
    2255   if (infoPtr->nFocusedItem != nItem)
    2256   {
    2257     if (infoPtr->nFocusedItem >= 0)
    2258     {
    2259       INT oldFocus = infoPtr->nFocusedItem;
    2260       bResult = TRUE;
    2261       infoPtr->nFocusedItem = -1;
    2262       ZeroMemory(&lvItem, sizeof(lvItem));
    2263       lvItem.stateMask = LVIS_FOCUSED;
    2264       ListView_SetItemState(hwnd, oldFocus, &lvItem);
    2265 
    2266     }
    2267 
    2268     lvItem.state =  LVIS_FOCUSED;
    2269     lvItem.stateMask = LVIS_FOCUSED;
    2270     ListView_SetItemState(hwnd, nItem, &lvItem);
    2271 
    2272     infoPtr->nFocusedItem = nItem;
    2273     ListView_EnsureVisible(hwnd, nItem, FALSE);
    2274   }
    2275  
    2276   return bResult;
    2277 }
    2278 
    2279 /***
    2280  * DESCRIPTION:
    2281  * Sets a single selection.
    2282  *
    2283  * PARAMETER(S):
    2284  * [I] HWND : window handle
    2285  * [I] INT : item index
    2286  *
    2287  * RETURN:
    2288  * None
    2289  */
    2290 static VOID LISTVIEW_SetSelection(HWND hwnd, INT nItem)
    2291 {
    2292   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    2293   LVITEMW lvItem;
    2294 
    2295   ZeroMemory(&lvItem, sizeof(lvItem));
    2296   lvItem.stateMask = LVIS_FOCUSED;
    2297   ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
    2298 
    2299   LISTVIEW_RemoveAllSelections(hwnd);
    2300 
    2301   lvItem.state =   LVIS_FOCUSED|LVIS_SELECTED;
    2302   lvItem.stateMask = LVIS_FOCUSED|LVIS_SELECTED;
    2303   ListView_SetItemState(hwnd, nItem, &lvItem);
    2304 
    2305   infoPtr->nFocusedItem = nItem;
    2306   infoPtr->nSelectionMark = nItem;
     3043static void LISTVIEW_SetSelection(LISTVIEW_INFO *infoPtr, INT nItem)
     3044{
     3045    LVITEMW lvItem;
     3046
     3047    TRACE("nItem=%d\n", nItem);
     3048   
     3049    LISTVIEW_DeselectAllSkipItem(infoPtr, nItem);
     3050
     3051    lvItem.state = LVIS_FOCUSED | LVIS_SELECTED;
     3052    lvItem.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
     3053    LISTVIEW_SetItemState(infoPtr, nItem, &lvItem);
     3054
     3055    infoPtr->nSelectionMark = nItem;
    23073056}
    23083057
     
    23103059 * DESCRIPTION:
    23113060 * Set selection(s) with keyboard.
    2312  * 
    2313  * PARAMETER(S):
    2314  * [I] HWND : window handle
    2315  * [I] INT : item index
     3061 *
     3062 * PARAMETER(S):
     3063 * [I] infoPtr : valid pointer to the listview structure
     3064 * [I] nItem : item index
    23163065 *
    23173066 * RETURN:
     
    23193068 *   FAILURE : FALSE (nothing has changed)
    23203069 */
    2321 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem)
    2322 {
    2323   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    2324   LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
     3070static BOOL LISTVIEW_KeySelection(LISTVIEW_INFO *infoPtr, INT nItem)
     3071{
     3072  /* FIXME: pass in the state */
    23253073  WORD wShift = HIWORD(GetKeyState(VK_SHIFT));
    23263074  WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL));
    23273075  BOOL bResult = FALSE;
    23283076
    2329   if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
     3077  if ((nItem >= 0) && (nItem < infoPtr->nItemCount))
    23303078  {
    2331     if (lStyle & LVS_SINGLESEL)
     3079    if (infoPtr->dwStyle & LVS_SINGLESEL)
    23323080    {
    23333081      bResult = TRUE;
    2334       LISTVIEW_SetSelection(hwnd, nItem);
    2335       ListView_EnsureVisible(hwnd, nItem, FALSE);
     3082      LISTVIEW_SetSelection(infoPtr, nItem);
    23363083    }
    23373084    else
     
    23403087      {
    23413088        bResult = TRUE;
    2342         LISTVIEW_SetGroupSelection(hwnd, nItem);
     3089        LISTVIEW_SetGroupSelection(infoPtr, nItem);
    23433090      }
    23443091      else if (wCtrl)
    23453092      {
    2346         bResult = LISTVIEW_SetItemFocus(hwnd, nItem);
     3093        bResult = LISTVIEW_SetItemFocus(infoPtr, nItem);
    23473094      }
    23483095      else
    23493096      {
    23503097        bResult = TRUE;
    2351         LISTVIEW_SetSelection(hwnd, nItem);
    2352         ListView_EnsureVisible(hwnd, nItem, FALSE);
     3098        LISTVIEW_SetSelection(infoPtr, nItem);
    23533099      }
    23543100    }
     3101    LISTVIEW_EnsureVisible(infoPtr, nItem, FALSE);
    23553102  }
    23563103
     3104  UpdateWindow(infoPtr->hwndSelf); /* update client area */
    23573105  return bResult;
    23583106}
     3107
    23593108
    23603109/***
     
    23643113 *
    23653114 * PARAMETER(S):
    2366  * [I] HWND : window handle
    2367  * [I] wParam : key indicator
    2368  * [I] lParam : mouse position
     3115 * [I] infoPtr : valid pointer to the listview structure
     3116 * [I] fwKeys : key indicator
     3117 * [I] pts : mouse position
    23693118 *
    23703119 * RETURN:
     
    23743123 * LVS_EX_TRACKSELECT: An item is automatically selected when the cursor remains
    23753124 * over the item for a certain period of time.
    2376  *
    2377  */
    2378 static LRESULT LISTVIEW_MouseHover(HWND hwnd, WPARAM wParam, LPARAM lParam)
    2379 {
    2380   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    2381   POINT pt;
    2382 
    2383   pt.x = (INT)LOWORD(lParam);
    2384   pt.y = (INT)HIWORD(lParam);
    2385 
    2386   if(infoPtr->dwExStyle & LVS_EX_TRACKSELECT) {
    2387     /* select the item under the cursor */
    2388     LISTVIEW_MouseSelection(hwnd, pt);
    2389   }
    2390 
    2391   return 0;
     3125 *
     3126 */
     3127static LRESULT LISTVIEW_MouseHover(LISTVIEW_INFO *infoPtr, WORD fwKyes, POINTS pts)
     3128{
     3129    if(infoPtr->dwLvExStyle & LVS_EX_TRACKSELECT)
     3130        /* FIXME: select the item!!! */
     3131        /*LISTVIEW_GetItemAtPt(infoPtr, pt)*/;
     3132
     3133    return 0;
    23923134}
    23933135
     
    23973139 *
    23983140 * PARAMETER(S):
    2399  * [I] HWND : window handle
    2400  * [I] wParam : key indicators
    2401  * [I] lParam : cursor position
     3141 * [I] infoPtr : valid pointer to the listview structure
     3142 * [I] fwKeys : key indicator
     3143 * [I] pts : mouse position
    24023144 *
    24033145 * RETURN:
    24043146 *   0 if the message is processed, non-zero if there was an error
    24053147 */
    2406 static LRESULT LISTVIEW_MouseMove(HWND hwnd, WPARAM wParam, LPARAM lParam)
    2407 {
    2408   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
     3148static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, POINTS pts)
     3149{
    24093150  TRACKMOUSEEVENT trackinfo;
    2410  
     3151
    24113152  /* see if we are supposed to be tracking mouse hovering */
    2412   if(infoPtr->dwExStyle & LVS_EX_TRACKSELECT) {
     3153  if(infoPtr->dwLvExStyle & LVS_EX_TRACKSELECT) {
    24133154     /* fill in the trackinfo struct */
    24143155     trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
    24153156     trackinfo.dwFlags = TME_QUERY;
    2416      trackinfo.hwndTrack = hwnd;
     3157     trackinfo.hwndTrack = infoPtr->hwndSelf;
    24173158     trackinfo.dwHoverTime = infoPtr->dwHoverTime;
    24183159
     
    24273168    }
    24283169  }
    2429 #ifdef __WIN32OS2__
    2430   else
    2431   if(!infoPtr->bDragInProcess && (infoPtr->bLButtonDown || infoPtr->bRButtonDown) && infoPtr->nSelectionMark != -1) {
    2432       NMLISTVIEW nml = {0};
    2433       nml.iItem = infoPtr->nSelectionMark;
    2434       listview_notify(hwnd, (infoPtr->bLButtonDown) ? LVN_BEGINDRAG : LVN_BEGINRDRAG, &nml);
    2435       infoPtr->bDragInProcess = TRUE;
    2436   }
    2437 #endif 
     3170
    24383171  return 0;
    24393172}
    24403173
    2441 /***
    2442  * DESCRIPTION:
    2443  * Selects an item based on coordinates.
    2444  *
    2445  * PARAMETER(S):
    2446  * [I] HWND : window handle
    2447  * [I] POINT : mouse click ccordinates
    2448  *
    2449  * RETURN:
    2450  *   SUCCESS : item index
    2451  *   FAILURE : -1
    2452  */
    2453 static LRESULT LISTVIEW_MouseSelection(HWND hwnd, POINT pt)
    2454 {
    2455   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    2456   RECT rcItem;
    2457   INT i,topindex,bottomindex;
    2458   LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    2459   UINT uView = lStyle & LVS_TYPEMASK;
    2460 
    2461   topindex = ListView_GetTopIndex(hwnd);
    2462   if (uView == LVS_REPORT)
    2463   {
    2464     bottomindex = topindex + LISTVIEW_GetCountPerColumn(hwnd) + 1; 
    2465     bottomindex = min(bottomindex,GETITEMCOUNT(infoPtr));
    2466   }
    2467   else
    2468   {
    2469     bottomindex = GETITEMCOUNT(infoPtr);
    2470   }
    2471 
    2472   for (i = topindex; i < bottomindex; i++)
    2473   {
    2474     rcItem.left = LVIR_SELECTBOUNDS;
    2475     if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) == TRUE)
    2476     {
    2477       if (PtInRect(&rcItem, pt) != FALSE)
    2478       {
    2479         return i;
    2480       }
    2481     }
    2482   }
    2483 
    2484   return -1;
    2485 }
    2486 
    2487 /***
    2488  * DESCRIPTION:
    2489  * Removes a column.
    2490  *
    2491  * PARAMETER(S):
    2492  * [IO] HDPA : dynamic pointer array handle
    2493  * [I] INT : column index (subitem index)
    2494  *
    2495  * RETURN:
    2496  *   SUCCCESS : TRUE
    2497  *   FAILURE : FALSE
    2498  */
    2499 static BOOL LISTVIEW_RemoveColumn(HDPA hdpaItems, INT nSubItem)
    2500 {
    2501   BOOL bResult = TRUE;
    2502   HDPA hdpaSubItems;
    2503   INT i;
    2504 
    2505   for (i = 0; i < hdpaItems->nItemCount; i++)
    2506   {
    2507     hdpaSubItems = (HDPA)DPA_GetPtr(hdpaItems, i);
    2508     if (hdpaSubItems != NULL)
    2509     {
    2510       if (LISTVIEW_RemoveSubItem(hdpaSubItems, nSubItem) == FALSE)
    2511       {
    2512         bResult = FALSE;
    2513       }
    2514     }
    2515   }
    2516    
    2517   return bResult;
    2518 }
    2519 
    2520 /***
    2521  * DESCRIPTION:
    2522  * Removes a subitem at a given position.
    2523  *
    2524  * PARAMETER(S):
    2525  * [IO] HDPA : dynamic pointer array handle
    2526  * [I] INT : subitem index
    2527  *
    2528  * RETURN:
    2529  *   SUCCCESS : TRUE
    2530  *   FAILURE : FALSE
    2531  */
    2532 static BOOL LISTVIEW_RemoveSubItem(HDPA hdpaSubItems, INT nSubItem)
    2533 {
    2534   LISTVIEW_SUBITEM *lpSubItem;
    2535   INT i;
    2536 
    2537   for (i = 1; i < hdpaSubItems->nItemCount; i++)
    2538   {
    2539     lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
    2540     if (lpSubItem != NULL)
    2541     {
    2542       if (lpSubItem->iSubItem == nSubItem)
    2543       {
    2544         /* free string */
    2545         if (is_textW(lpSubItem->pszText))
    2546           COMCTL32_Free(lpSubItem->pszText);
    2547        
    2548         /* free item */
    2549         COMCTL32_Free(lpSubItem);
    2550 
    2551         /* free dpa memory */
    2552         if (DPA_DeletePtr(hdpaSubItems, i) == NULL)
    2553           return FALSE;
    2554       }
    2555       else if (lpSubItem->iSubItem > nSubItem)
    2556         return TRUE;
    2557     }
    2558   }   
    2559  
    2560   return TRUE;
    2561 }
    2562 
    2563 /***
    2564  * DESCRIPTION:
    2565  * Compares the item information.
    2566  *
    2567  * PARAMETER(S):
    2568  * [I] LISTVIEW_ITEM *: destination item
    2569  * [I] LPLVITEM : source item
    2570  * [I] isW : TRUE if lpLVItem is Unicode, FALSE it it's ANSI
    2571  *
    2572  * RETURN:
    2573  *   SUCCCESS : TRUE (EQUAL)
    2574  *   FAILURE : FALSE (NOT EQUAL)
    2575  */
    2576 #ifdef __WIN32OS2__
    2577 static UINT LISTVIEW_GetItemChangesT(LISTVIEW_ITEM *lpItem, LPLVITEMW lpLVItem, BOOL isW, DWORD lStyle)
    2578 #else
    2579 static UINT LISTVIEW_GetItemChangesT(LISTVIEW_ITEM *lpItem, LPLVITEMW lpLVItem, BOOL isW)
    2580 #endif
    2581 {
    2582   UINT uChanged = 0;
    2583 
    2584   if ((lpItem != NULL) && (lpLVItem != NULL))
    2585   {
    2586     if (lpLVItem->mask & LVIF_STATE)
    2587     {
    2588       if ((lpItem->state & lpLVItem->stateMask) !=
    2589           (lpLVItem->state & lpLVItem->stateMask))
    2590         uChanged |= LVIF_STATE;
    2591     }
    2592 
    2593     if (lpLVItem->mask & LVIF_IMAGE)
    2594     {
    2595       if (lpItem->iImage != lpLVItem->iImage)
    2596         uChanged |= LVIF_IMAGE;
    2597     }
    2598  
    2599     if (lpLVItem->mask & LVIF_PARAM)
    2600     {
    2601       if (lpItem->lParam != lpLVItem->lParam)
    2602         uChanged |= LVIF_PARAM;
    2603     }
    2604    
    2605     if (lpLVItem->mask & LVIF_INDENT)
    2606     {
    2607       if (lpItem->iIndent != lpLVItem->iIndent)
    2608         uChanged |= LVIF_INDENT;
    2609     }
    2610 
    2611     if (lpLVItem->mask & LVIF_TEXT)
    2612     {
    2613       if (lpLVItem->pszText == LPSTR_TEXTCALLBACKW)
    2614       {
    2615         if (lpItem->pszText != LPSTR_TEXTCALLBACKW)
    2616           uChanged |= LVIF_TEXT;
    2617       }
    2618       else
    2619       {
    2620         if (lpItem->pszText == LPSTR_TEXTCALLBACKW)
    2621         {
    2622           uChanged |= LVIF_TEXT;
    2623         }
    2624         else
    2625         {
    2626           if (lpLVItem->pszText)
    2627           {
    2628 #ifdef __WIN32OS2__
    2629         if(lStyle & LVS_OWNERDRAWFIXED) {
    2630             //SvL: NT's COMCTL32 seems to always update the item, regardless of
    2631             //     whether the string is different or not.
    2632             //     Some apps depends on this (CVP)
    2633             //TODO: Might need to send some kind of notification to determine
    2634             //      if a redraw is really necessary
    2635             uChanged |= LVIF_TEXT;
    2636         }
    2637         else
    2638 #endif
    2639             if (lpItem->pszText)
    2640             {
    2641               LPWSTR pszText = textdupTtoW(lpLVItem->pszText, isW);
    2642               if (pszText && strcmpW(pszText, lpItem->pszText))
    2643                 uChanged |= LVIF_TEXT;
    2644               textfreeT(pszText, isW);
    2645             }
    2646             else
    2647             {
    2648               uChanged |= LVIF_TEXT;
    2649             }
    2650           }
    2651           else
    2652           {
    2653             if (lpItem->pszText)
    2654               uChanged |= LVIF_TEXT;
    2655           }
    2656         }
    2657       }
    2658     }
    2659   }
    2660   return uChanged;
    2661 }
    2662 
    2663 /***
    2664  * DESCRIPTION:
    2665  * Initializes item attributes.
    2666  *
    2667  * PARAMETER(S):
    2668  * [I] HWND : window handle
    2669  * [O] LISTVIEW_ITEM *: destination item
    2670  * [I] LPLVITEM : source item
     3174
     3175/***
     3176 * Tests wheather the item is assignable to a list with style lStyle
     3177 */
     3178static inline BOOL is_assignable_item(const LVITEMW *lpLVItem, LONG lStyle)
     3179{
     3180    if ( (lpLVItem->mask & LVIF_TEXT) &&
     3181        (lpLVItem->pszText == LPSTR_TEXTCALLBACKW) &&
     3182        (lStyle & (LVS_SORTASCENDING | LVS_SORTDESCENDING)) ) return FALSE;
     3183   
     3184    return TRUE;
     3185}
     3186
     3187
     3188/***
     3189 * DESCRIPTION:
     3190 * Helper for LISTVIEW_SetItemT *only*: sets item attributes.
     3191 *
     3192 * PARAMETER(S):
     3193 * [I] infoPtr : valid pointer to the listview structure
     3194 * [I] lpLVItem : valid pointer to new item atttributes
     3195 * [I] isNew : the item being set is being inserted
    26713196 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
    2672  *
    2673  * RETURN:
    2674  *   SUCCCESS : TRUE
    2675  *   FAILURE : FALSE
    2676  */
    2677 static BOOL LISTVIEW_InitItemT(HWND hwnd, LISTVIEW_ITEM *lpItem,
    2678                               LPLVITEMW lpLVItem, BOOL isW)
    2679 {
    2680   LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    2681   BOOL bResult = FALSE;
    2682 
    2683   if ((lpItem != NULL) && (lpLVItem != NULL))
    2684   {
    2685     bResult = TRUE;
    2686    
    2687     if (lpLVItem->mask & LVIF_STATE)
    2688     {
    2689       lpItem->state &= ~lpLVItem->stateMask;
    2690       lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
    2691     }
    2692    
    2693     if (lpLVItem->mask & LVIF_IMAGE)
    2694       lpItem->iImage = lpLVItem->iImage;
    2695  
    2696     if (lpLVItem->mask & LVIF_PARAM)
    2697       lpItem->lParam = lpLVItem->lParam;
    2698    
    2699     if (lpLVItem->mask & LVIF_INDENT)
    2700       lpItem->iIndent = lpLVItem->iIndent;
    2701 
    2702     if (lpLVItem->mask & LVIF_TEXT)
    2703     {
    2704       if (lpLVItem->pszText == LPSTR_TEXTCALLBACKW)
    2705       {
    2706         if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
    2707           return FALSE;
    2708 
    2709         if (is_textW(lpItem->pszText))
    2710           COMCTL32_Free(lpItem->pszText);
    2711    
    2712         lpItem->pszText = LPSTR_TEXTCALLBACKW;
    2713       }
    2714       else
    2715         bResult = textsetptrT(&lpItem->pszText, lpLVItem->pszText, isW);
    2716     }
    2717   }
    2718 
    2719   return bResult;
    2720 }
    2721 
    2722 /***
    2723  * DESCRIPTION:
    2724  * Initializes subitem attributes.
    2725  *
    2726  * NOTE: The documentation specifies that the operation fails if the user
    2727  * tries to set the indent of a subitem.
    2728  *
    2729  * PARAMETER(S):
    2730  * [I] HWND : window handle
    2731  * [O] LISTVIEW_SUBITEM *: destination subitem
    2732  * [I] LPLVITEM : source subitem
    2733  * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
    2734  *
    2735  * RETURN:
    2736  *   SUCCCESS : TRUE
    2737  *   FAILURE : FALSE
    2738  */
    2739 static BOOL LISTVIEW_InitSubItemT(HWND hwnd, LISTVIEW_SUBITEM *lpSubItem,
    2740                                   LPLVITEMW lpLVItem, BOOL isW)
    2741 {
    2742   LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    2743   BOOL bResult = FALSE;
    2744  
    2745   TRACE("(hwnd=%x, lpSubItem=%p, lpLVItem=%s, isW=%d)\n",
    2746         hwnd, lpSubItem, debuglvitem_t(lpLVItem, isW), isW);
    2747  
    2748   if ((lpSubItem != NULL) && (lpLVItem != NULL))
    2749   {
    2750     if (!(lpLVItem->mask & LVIF_INDENT))
    2751     {
    2752       bResult = TRUE;
    2753 
    2754       lpSubItem->iSubItem = lpLVItem->iSubItem;
    2755 
    2756       if (lpLVItem->mask & LVIF_IMAGE)
    2757         lpSubItem->iImage = lpLVItem->iImage;
    2758      
    2759       if (lpLVItem->mask & LVIF_TEXT)
    2760       {
    2761         if (lpLVItem->pszText == LPSTR_TEXTCALLBACKW)
    2762         {
    2763           if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
    2764             return FALSE;
    2765 
    2766           if (is_textW(lpSubItem->pszText))
    2767             COMCTL32_Free(lpSubItem->pszText);
    2768    
    2769           lpSubItem->pszText = LPSTR_TEXTCALLBACKW;
    2770         }
    2771         else
    2772           bResult = textsetptrT(&lpSubItem->pszText, lpLVItem->pszText, isW);
    2773       }
    2774     }
    2775   }
    2776 
    2777   return bResult;
    2778 }
    2779 
    2780 /***
    2781  * DESCRIPTION:
    2782  * Adds a subitem at a given position (column index).
    2783  *
    2784  * PARAMETER(S):
    2785  * [I] HWND : window handle
    2786  * [I] LPLVITEM : new subitem atttributes
    2787  * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
     3197 * [O] bChanged : will be set to TRUE if the item really changed
    27883198 *
    27893199 * RETURN:
     
    27913201 *   FAILURE : FALSE
    27923202 */
    2793 static BOOL LISTVIEW_AddSubItemT(HWND hwnd, LPLVITEMW lpLVItem, BOOL isW)
    2794 {
    2795   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    2796   LISTVIEW_SUBITEM *lpSubItem = NULL;
    2797   BOOL bResult = FALSE;
    2798   HDPA hdpaSubItems;
    2799   INT nPosition, nItem;
    2800   LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    2801 
    2802   TRACE("(hwnd=%x, lpLVItem=%s, isW=%d)\n", hwnd, debuglvitem_t(lpLVItem, isW), isW);
    2803  
    2804   if (lStyle & LVS_OWNERDATA)
    2805     return FALSE;
    2806 
    2807   if (lpLVItem != NULL)
    2808   {
    2809     hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
    2810     if (hdpaSubItems != NULL)
    2811     {
    2812       lpSubItem = (LISTVIEW_SUBITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM));
    2813       if (lpSubItem != NULL)
    2814       {
    2815         ZeroMemory(lpSubItem, sizeof(LISTVIEW_SUBITEM));
    2816         if (LISTVIEW_InitSubItemT(hwnd, lpSubItem, lpLVItem, isW))
    2817         {
    2818           nPosition = LISTVIEW_FindInsertPosition(hdpaSubItems,
    2819                                                   lpSubItem->iSubItem);
    2820           nItem = DPA_InsertPtr(hdpaSubItems, nPosition, lpSubItem);
    2821           if (nItem != -1) bResult = TRUE;
    2822         }
    2823       }
    2824     }
    2825   }
    2826  
    2827   /* cleanup if unsuccessful */   
    2828   if (!bResult && lpSubItem) COMCTL32_Free(lpSubItem);
    2829  
    2830   return bResult;
    2831 }
    2832 
    2833 /***
    2834  * DESCRIPTION:
    2835  * Finds the dpa insert position (array index).
    2836  *
    2837  * PARAMETER(S):
    2838  * [I] HWND : window handle
    2839  * [I] INT : subitem index
     3203static BOOL set_main_item(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL isNew, BOOL isW, BOOL *bChanged)
     3204{
     3205    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     3206    ITEM_INFO *lpItem;
     3207    NMLISTVIEW nmlv;
     3208    UINT uChanged = 0;
     3209    LVITEMW item;
     3210
     3211    TRACE("()\n");
     3212
     3213    assert(lpLVItem->iItem >= 0 && lpLVItem->iItem < infoPtr->nItemCount);
     3214   
     3215    if (lpLVItem->mask == 0) return TRUE;   
     3216
     3217    if (infoPtr->dwStyle & LVS_OWNERDATA)
     3218    {
     3219        /* a virtual listview we stores only selection and focus */
     3220        if (lpLVItem->mask & ~LVIF_STATE)
     3221            return FALSE;
     3222        lpItem = NULL;
     3223    }
     3224    else
     3225    {
     3226        HDPA hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
     3227        lpItem = (ITEM_INFO *)DPA_GetPtr(hdpaSubItems, 0);
     3228        assert (lpItem);
     3229    }
     3230
     3231    /* we need to get the lParam and state of the item */
     3232    item.iItem = lpLVItem->iItem;
     3233    item.iSubItem = lpLVItem->iSubItem;
     3234    item.mask = LVIF_STATE | LVIF_PARAM;
     3235    item.stateMask = ~0;
     3236    item.state = 0;
     3237    item.lParam = 0;
     3238    if (!isNew && !LISTVIEW_GetItemW(infoPtr, &item)) return FALSE;
     3239
     3240    TRACE("oldState=%x, newState=%x\n", item.state, lpLVItem->state);
     3241    /* determine what fields will change */   
     3242    if ((lpLVItem->mask & LVIF_STATE) && ((item.state ^ lpLVItem->state) & lpLVItem->stateMask & ~infoPtr->uCallbackMask))
     3243        uChanged |= LVIF_STATE;
     3244
     3245    if ((lpLVItem->mask & LVIF_IMAGE) && (lpItem->hdr.iImage != lpLVItem->iImage))
     3246        uChanged |= LVIF_IMAGE;
     3247
     3248    if ((lpLVItem->mask & LVIF_PARAM) && (lpItem->lParam != lpLVItem->lParam))
     3249        uChanged |= LVIF_PARAM;
     3250
     3251    if ((lpLVItem->mask & LVIF_INDENT) && (lpItem->iIndent != lpLVItem->iIndent))
     3252        uChanged |= LVIF_INDENT;
     3253
     3254    if ((lpLVItem->mask & LVIF_TEXT) && textcmpWT(lpItem->hdr.pszText, lpLVItem->pszText, isW))
     3255        uChanged |= LVIF_TEXT;
     3256   
     3257    TRACE("uChanged=0x%x\n", uChanged);
     3258    if (!uChanged) return TRUE;
     3259    *bChanged = TRUE;
     3260   
     3261    ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
     3262    nmlv.iItem = lpLVItem->iItem;
     3263    nmlv.uNewState = (item.state & ~lpLVItem->stateMask) | (lpLVItem->state & lpLVItem->stateMask);
     3264    nmlv.uOldState = item.state;
     3265    nmlv.uChanged = uChanged;
     3266    nmlv.lParam = item.lParam;
     3267   
     3268    /* send LVN_ITEMCHANGING notification, if the item is not being inserted */
     3269    /* and we are _NOT_ virtual (LVS_OWERNDATA), and change notifications */
     3270    /* are enabled */
     3271    if(lpItem && !isNew && infoPtr->bDoChangeNotify &&
     3272       notify_listview(infoPtr, LVN_ITEMCHANGING, &nmlv))
     3273        return FALSE;
     3274
     3275    /* copy information */
     3276    if (lpLVItem->mask & LVIF_TEXT)
     3277        textsetptrT(&lpItem->hdr.pszText, lpLVItem->pszText, isW);
     3278
     3279    if (lpLVItem->mask & LVIF_IMAGE)
     3280        lpItem->hdr.iImage = lpLVItem->iImage;
     3281
     3282    if (lpLVItem->mask & LVIF_PARAM)
     3283        lpItem->lParam = lpLVItem->lParam;
     3284
     3285    if (lpLVItem->mask & LVIF_INDENT)
     3286        lpItem->iIndent = lpLVItem->iIndent;
     3287
     3288    if (uChanged & LVIF_STATE)
     3289    {
     3290        if (lpItem && (lpLVItem->stateMask & ~infoPtr->uCallbackMask & ~(LVIS_FOCUSED | LVIS_SELECTED)))
     3291        {
     3292            lpItem->state &= ~lpLVItem->stateMask;
     3293            lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
     3294        }
     3295        if (lpLVItem->state & lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED)
     3296        {
     3297            if (infoPtr->dwStyle & LVS_SINGLESEL) LISTVIEW_DeselectAllSkipItem(infoPtr, lpLVItem->iItem);
     3298            ranges_additem(infoPtr->selectionRanges, lpLVItem->iItem);
     3299        }
     3300        else if (lpLVItem->stateMask & LVIS_SELECTED)
     3301            ranges_delitem(infoPtr->selectionRanges, lpLVItem->iItem);
     3302       
     3303        /* if we are asked to change focus, and we manage it, do it */
     3304        if (lpLVItem->state & lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED)
     3305        {
     3306            if (lpLVItem->state & LVIS_FOCUSED)
     3307            {
     3308                LISTVIEW_SetItemFocus(infoPtr, -1);
     3309                infoPtr->nFocusedItem = lpLVItem->iItem;
     3310                LISTVIEW_EnsureVisible(infoPtr, lpLVItem->iItem, uView == LVS_LIST);
     3311            }
     3312            else if (infoPtr->nFocusedItem == lpLVItem->iItem)
     3313                infoPtr->nFocusedItem = -1;
     3314        }
     3315    }
     3316
     3317    /* if we're inserting the item, we're done */
     3318    if (isNew) return TRUE;
     3319   
     3320    /* send LVN_ITEMCHANGED notification */
     3321    if (lpLVItem->mask & LVIF_PARAM) nmlv.lParam = lpLVItem->lParam;
     3322    if (infoPtr->bDoChangeNotify) notify_listview(infoPtr, LVN_ITEMCHANGED, &nmlv);
     3323
     3324    return TRUE;
     3325}
     3326
     3327/***
     3328 * DESCRIPTION:
     3329 * Helper for LISTVIEW_{Set,Insert}ItemT *only*: sets subitem attributes.
     3330 *
     3331 * PARAMETER(S):
     3332 * [I] infoPtr : valid pointer to the listview structure
     3333 * [I] lpLVItem : valid pointer to new subitem atttributes
     3334 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
     3335 * [O] bChanged : will be set to TRUE if the item really changed
    28403336 *
    28413337 * RETURN:
     
    28433339 *   FAILURE : FALSE
    28443340 */
    2845 static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem)
    2846 {
    2847   LISTVIEW_SUBITEM *lpSubItem;
    2848   INT i;
    2849 
    2850   for (i = 1; i < hdpaSubItems->nItemCount; i++)
    2851   {
    2852     lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
    2853     if (lpSubItem && lpSubItem->iSubItem > nSubItem)
    2854       return i;
    2855   }
    2856 
    2857   return hdpaSubItems->nItemCount;
    2858 }
    2859 
    2860 /***
    2861  * DESCRIPTION:
    2862  * Retrieves a listview subitem at a given position (column index).
    2863  *
    2864  * PARAMETER(S):
    2865  * [I] HWND : window handle
    2866  * [I] INT : subitem index
     3341static BOOL set_sub_item(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL isW, BOOL *bChanged)
     3342{
     3343    HDPA hdpaSubItems;
     3344    SUBITEM_INFO *lpSubItem;
     3345
     3346    /* we do not support subitems for virtual listviews */
     3347    if (infoPtr->dwStyle & LVS_OWNERDATA) return FALSE;
     3348   
     3349    /* set subitem only if column is present */
     3350    if (lpLVItem->iSubItem >= infoPtr->hdpaColumns->nItemCount) return FALSE;
     3351   
     3352    /* First do some sanity checks */
     3353    if (lpLVItem->mask & ~(LVIF_TEXT | LVIF_IMAGE)) return FALSE;
     3354    if (!(lpLVItem->mask & (LVIF_TEXT | LVIF_IMAGE))) return TRUE;
     3355   
     3356    /* get the subitem structure, and create it if not there */
     3357    hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
     3358    assert (hdpaSubItems);
     3359   
     3360    lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem);
     3361    if (!lpSubItem)
     3362    {
     3363        SUBITEM_INFO *tmpSubItem;
     3364        INT i;
     3365
     3366        lpSubItem = (SUBITEM_INFO *)COMCTL32_Alloc(sizeof(SUBITEM_INFO));
     3367        if (!lpSubItem) return FALSE;
     3368        /* we could binary search here, if need be...*/
     3369        for (i = 1; i < hdpaSubItems->nItemCount; i++)
     3370        {
     3371            tmpSubItem = (SUBITEM_INFO *)DPA_GetPtr(hdpaSubItems, i);
     3372            if (tmpSubItem->iSubItem > lpLVItem->iSubItem) break;
     3373        }
     3374        if (DPA_InsertPtr(hdpaSubItems, i, lpSubItem) == -1)
     3375        {
     3376            COMCTL32_Free(lpSubItem);
     3377            return FALSE;
     3378        }
     3379        lpSubItem->iSubItem = lpLVItem->iSubItem;
     3380        *bChanged = TRUE;
     3381    }
     3382   
     3383    if (lpLVItem->mask & LVIF_IMAGE)
     3384        if (lpSubItem->hdr.iImage != lpLVItem->iImage)
     3385        {
     3386            lpSubItem->hdr.iImage = lpLVItem->iImage;
     3387            *bChanged = TRUE;
     3388        }
     3389
     3390    if (lpLVItem->mask & LVIF_TEXT)
     3391        if (lpSubItem->hdr.pszText != lpLVItem->pszText)
     3392        {
     3393            textsetptrT(&lpSubItem->hdr.pszText, lpLVItem->pszText, isW);
     3394            *bChanged = TRUE;
     3395        }
     3396
     3397    return TRUE;
     3398}
     3399
     3400/***
     3401 * DESCRIPTION:
     3402 * Sets item attributes.
     3403 *
     3404 * PARAMETER(S):
     3405 * [I] infoPtr : valid pointer to the listview structure
     3406 * [I] lpLVItem : new item atttributes
     3407 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
    28673408 *
    28683409 * RETURN:
     
    28703411 *   FAILURE : FALSE
    28713412 */
    2872 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem)
    2873 {
    2874   LISTVIEW_SUBITEM *lpSubItem;
    2875   INT i;
    2876 
    2877   for (i = 1; i < hdpaSubItems->nItemCount; i++)
    2878   {
    2879     lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
    2880     if (lpSubItem != NULL)
    2881     {
    2882       if (lpSubItem->iSubItem == nSubItem)
    2883         return lpSubItem;
    2884       else if (lpSubItem->iSubItem > nSubItem)
    2885         return NULL;
    2886     }
    2887   }
     3413static BOOL LISTVIEW_SetItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL isW)
     3414{
     3415    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     3416    LPWSTR pszText = NULL;
     3417    BOOL bResult, bChanged = FALSE;
     3418   
     3419    TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW);
     3420
     3421    if (!lpLVItem || lpLVItem->iItem < 0 || lpLVItem->iItem >= infoPtr->nItemCount)
     3422        return FALSE;
     3423
     3424    /* For efficiency, we transform the lpLVItem->pszText to Unicode here */
     3425    if ((lpLVItem->mask & LVIF_TEXT) && is_textW(lpLVItem->pszText))
     3426    {
     3427        pszText = lpLVItem->pszText;
     3428        ((LVITEMW *)lpLVItem)->pszText = textdupTtoW(lpLVItem->pszText, isW);
     3429    }
     3430   
     3431    /* actually set the fields */
     3432    if (!is_assignable_item(lpLVItem, infoPtr->dwStyle)) return FALSE;
     3433   
     3434    if (lpLVItem->iSubItem)
     3435        bResult = set_sub_item(infoPtr, lpLVItem, TRUE, &bChanged);
     3436    else
     3437        bResult = set_main_item(infoPtr, lpLVItem, FALSE, TRUE, &bChanged);
     3438
     3439    /* redraw item, if necessary */
     3440    if (bChanged && !infoPtr->bIsDrawing)
     3441    {
     3442        /* this little optimization eliminates some nasty flicker */
     3443        if ( uView == LVS_REPORT && !(infoPtr->dwStyle & LVS_OWNERDRAWFIXED) &&
     3444             (!(infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) || lpLVItem->iSubItem) )
     3445            LISTVIEW_InvalidateSubItem(infoPtr, lpLVItem->iItem, lpLVItem->iSubItem);
     3446        else
     3447            LISTVIEW_InvalidateItem(infoPtr, lpLVItem->iItem);
     3448    }
     3449    /* restore text */
     3450    if (pszText)
     3451    {
     3452        textfreeT(lpLVItem->pszText, isW);
     3453        ((LVITEMW *)lpLVItem)->pszText = pszText;
     3454    }
     3455
     3456    return bResult;
     3457}
     3458
     3459/***
     3460 * DESCRIPTION:
     3461 * Retrieves the index of the item at coordinate (0, 0) of the client area.
     3462 *
     3463 * PARAMETER(S):
     3464 * [I] infoPtr : valid pointer to the listview structure
     3465 *
     3466 * RETURN:
     3467 * item index
     3468 */
     3469static INT LISTVIEW_GetTopIndex(LISTVIEW_INFO *infoPtr)
     3470{
     3471    LONG lStyle = infoPtr->dwStyle;
     3472    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     3473    INT nItem = 0;
     3474    SCROLLINFO scrollInfo;
     3475
     3476    scrollInfo.cbSize = sizeof(SCROLLINFO);
     3477    scrollInfo.fMask = SIF_POS;
     3478
     3479    if (uView == LVS_LIST)
     3480    {
     3481        if ((lStyle & WS_HSCROLL) && GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo))
     3482            nItem = scrollInfo.nPos * LISTVIEW_GetCountPerColumn(infoPtr);
     3483    }
     3484    else if (uView == LVS_REPORT)
     3485    {
     3486        if ((lStyle & WS_VSCROLL) && GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo))
     3487            nItem = scrollInfo.nPos;
     3488    }
     3489    else
     3490    {
     3491        if ((lStyle & WS_VSCROLL) && GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo))
     3492            nItem = LISTVIEW_GetCountPerRow(infoPtr) * (scrollInfo.nPos / infoPtr->nItemHeight);
     3493    }
     3494
     3495    TRACE("nItem=%d\n", nItem);
     3496   
     3497    return nItem;
     3498}
     3499
     3500
     3501/***
     3502 * DESCRIPTION:
     3503 * Erases the background of the given rectangle
     3504 *
     3505 * PARAMETER(S):
     3506 * [I] infoPtr : valid pointer to the listview structure
     3507 * [I] hdc : device context handle
     3508 * [I] lprcBox : clipping rectangle
     3509 *
     3510 * RETURN:
     3511 *   Success: TRUE
     3512 *   Failure: FALSE
     3513 */
     3514static inline BOOL LISTVIEW_FillBkgnd(LISTVIEW_INFO *infoPtr, HDC hdc, const RECT *lprcBox)
     3515{
     3516    if (!infoPtr->hBkBrush) return FALSE;
     3517
     3518    TRACE("(hdc=%p, lprcBox=%s, hBkBrush=%p)\n", hdc, debugrect(lprcBox), infoPtr->hBkBrush);
     3519
     3520    return FillRect(hdc, lprcBox, infoPtr->hBkBrush);
     3521}
     3522
     3523/***
     3524 * DESCRIPTION:
     3525 * Draws an item.
     3526 *
     3527 * PARAMETER(S):
     3528 * [I] infoPtr : valid pointer to the listview structure
     3529 * [I] hdc : device context handle
     3530 * [I] nItem : item index
     3531 * [I] nSubItem : subitem index
     3532 * [I] pos : item position in client coordinates
     3533 * [I] cdmode : custom draw mode
     3534 *
     3535 * RETURN:
     3536 *   Success: TRUE
     3537 *   Failure: FALSE
     3538 */
     3539static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, INT nSubItem, POINT pos, DWORD cdmode)
     3540{
     3541    UINT uFormat, uView = infoPtr->dwStyle & LVS_TYPEMASK;
     3542    WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
     3543    WCHAR szCallback[] = { '(', 'c', 'a', 'l', 'l', 'b', 'a', 'c', 'k', ')', 0 };
     3544    DWORD cditemmode = CDRF_DODEFAULT;
     3545    RECT* lprcFocus, rcSelect, rcBox, rcState, rcIcon, rcLabel;
     3546    NMLVCUSTOMDRAW nmlvcd;
     3547    HIMAGELIST himl;
     3548    LVITEMW lvItem;
     3549
     3550    TRACE("(hdc=%p, nItem=%d, nSubItem=%d, pos=%s)\n", hdc, nItem, nSubItem, debugpoint(&pos));
     3551
     3552    /* get information needed for drawing the item */
     3553    lvItem.mask = LVIF_TEXT | LVIF_IMAGE;
     3554    if (nSubItem == 0) lvItem.mask |= LVIF_STATE | LVIF_PARAM;
     3555    if (uView == LVS_REPORT) lvItem.mask |= LVIF_INDENT;
     3556    lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED | LVIS_STATEIMAGEMASK;
     3557    lvItem.iItem = nItem;
     3558    lvItem.iSubItem = nSubItem;
     3559    lvItem.state = 0;
     3560    lvItem.lParam = 0;
     3561    lvItem.cchTextMax = DISP_TEXT_SIZE;
     3562    lvItem.pszText = szDispText;
     3563    if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE;
     3564    if (nSubItem > 0 && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT))
     3565        lvItem.state = LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED);
     3566    if (lvItem.pszText == LPSTR_TEXTCALLBACKW) lvItem.pszText = szCallback;
     3567    TRACE("   lvItem=%s\n", debuglvitem_t(&lvItem, TRUE));
     3568
     3569    /* now check if we need to update the focus rectangle */
     3570    lprcFocus = infoPtr->bFocus && (lvItem.state & LVIS_FOCUSED) ? &infoPtr->rcFocus : 0;
     3571   
     3572    if (!lprcFocus) lvItem.state &= ~LVIS_FOCUSED;
     3573    LISTVIEW_GetItemMetrics(infoPtr, &lvItem, &rcBox, &rcState, &rcIcon, &rcLabel);
     3574    OffsetRect(&rcBox, pos.x, pos.y);
     3575    OffsetRect(&rcState, pos.x, pos.y);
     3576    OffsetRect(&rcIcon, pos.x, pos.y);
     3577    OffsetRect(&rcLabel, pos.x, pos.y);
     3578    TRACE("    rcBox=%s, rcState=%s, rcIcon=%s. rcLabel=%s\n",
     3579        debugrect(&rcBox), debugrect(&rcState), debugrect(&rcIcon), debugrect(&rcLabel));
     3580
     3581    /* fill in the custom draw structure */
     3582    customdraw_fill(&nmlvcd, infoPtr, hdc, &rcBox, &lvItem);
     3583
     3584    if (cdmode & CDRF_NOTIFYITEMDRAW)
     3585        cditemmode = notify_prepaint (infoPtr, hdc, &nmlvcd);
     3586    if (cditemmode & CDRF_SKIPDEFAULT) goto postpaint;
     3587
     3588    /* in full row select, subitems, will just use main item's colors */
     3589    if (nSubItem && uView == LVS_REPORT && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT))
     3590        nmlvcd.clrTextBk = CLR_NONE;
     3591   
     3592    /* state icons */
     3593    if (infoPtr->himlState && !IsRectEmpty(&rcState))
     3594    {
     3595        UINT uStateImage = (lvItem.state & LVIS_STATEIMAGEMASK) >> 12;
     3596        if (uStateImage)
     3597        {
     3598             TRACE("uStateImage=%d\n", uStateImage);
     3599             ImageList_Draw(infoPtr->himlState, uStateImage - 1, hdc, rcState.left, rcState.top, ILD_NORMAL);
     3600        }
     3601    }
     3602
     3603    /* small icons */
     3604    himl = (uView == LVS_ICON ? infoPtr->himlNormal : infoPtr->himlSmall);
     3605    if (himl && lvItem.iImage >= 0 && !IsRectEmpty(&rcIcon))
     3606    {
     3607        TRACE("iImage=%d\n", lvItem.iImage);
     3608        ImageList_Draw(himl, lvItem.iImage, hdc, rcIcon.left, rcIcon.top,
     3609                        (lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus) ? ILD_SELECTED : ILD_NORMAL);
     3610    }
     3611
     3612    /* Don't bother painting item being edited */
     3613    if (infoPtr->hwndEdit && nItem == infoPtr->nEditLabelItem && nSubItem == 0) goto postpaint;
     3614
     3615    /* draw the selection background, if we're drawing the main item */
     3616    if (nSubItem == 0)
     3617    {
     3618        rcSelect = rcLabel;
     3619        if (uView == LVS_REPORT && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT))
     3620            rcSelect.right = rcBox.right;
     3621   
     3622        if (nmlvcd.clrTextBk != CLR_NONE)
     3623            ExtTextOutW(hdc, rcSelect.left, rcSelect.top, ETO_OPAQUE, &rcSelect, 0, 0, 0);
     3624        if(lprcFocus) *lprcFocus = rcSelect;
     3625    }
     3626   
     3627    /* figure out the text drawing flags */
     3628    uFormat = (uView == LVS_ICON ? (lprcFocus ? LV_FL_DT_FLAGS : LV_ML_DT_FLAGS) : LV_SL_DT_FLAGS);
     3629    if (uView == LVS_ICON)
     3630        uFormat = (lprcFocus ? LV_FL_DT_FLAGS : LV_ML_DT_FLAGS);
     3631    else if (nSubItem)
     3632    {
     3633        switch (LISTVIEW_GetColumnInfo(infoPtr, nSubItem)->fmt & LVCFMT_JUSTIFYMASK)
     3634        {
     3635        case LVCFMT_RIGHT:  uFormat |= DT_RIGHT;  break;
     3636        case LVCFMT_CENTER: uFormat |= DT_CENTER; break;
     3637        default:            uFormat |= DT_LEFT;
     3638        }
     3639    }
     3640    if (!(uFormat & (DT_RIGHT | DT_CENTER)))
     3641    {
     3642        if (himl && lvItem.iImage >= 0 && !IsRectEmpty(&rcIcon)) rcLabel.left += IMAGE_PADDING;
     3643        else rcLabel.left += LABEL_HOR_PADDING;
     3644    }
     3645    else if (uFormat & DT_RIGHT) rcLabel.right -= LABEL_HOR_PADDING;
     3646    DrawTextW(hdc, lvItem.pszText, -1, &rcLabel, uFormat);
     3647
     3648postpaint:
     3649    if (cditemmode & CDRF_NOTIFYPOSTPAINT)
     3650        notify_postpaint(infoPtr, &nmlvcd);
     3651    return TRUE;
     3652}
     3653
     3654/***
     3655 * DESCRIPTION:
     3656 * Draws listview items when in owner draw mode.
     3657 *
     3658 * PARAMETER(S):
     3659 * [I] infoPtr : valid pointer to the listview structure
     3660 * [I] hdc : device context handle
     3661 *
     3662 * RETURN:
     3663 * None
     3664 */
     3665static void LISTVIEW_RefreshOwnerDraw(LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, DWORD cdmode)
     3666{
     3667    UINT uID = GetWindowLongW(infoPtr->hwndSelf, GWL_ID);
     3668    HWND hwndParent = GetParent(infoPtr->hwndSelf);
     3669    DWORD cditemmode = CDRF_DODEFAULT;
     3670    NMLVCUSTOMDRAW nmlvcd;
     3671    POINT Origin, Position;
     3672    DRAWITEMSTRUCT dis;
     3673    LVITEMW item;
     3674   
     3675    TRACE("()\n");
     3676
     3677    ZeroMemory(&dis, sizeof(dis));
     3678   
     3679    /* Get scroll info once before loop */
     3680    LISTVIEW_GetOrigin(infoPtr, &Origin);
     3681   
     3682    /* iterate through the invalidated rows */
     3683    while(iterator_next(i))
     3684    {
     3685        item.iItem = i->nItem;
     3686        item.iSubItem = 0;
     3687        item.mask = LVIF_PARAM | LVIF_STATE;
     3688        item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
     3689        if (!LISTVIEW_GetItemW(infoPtr, &item)) continue;
     3690           
     3691        dis.CtlType = ODT_LISTVIEW;
     3692        dis.CtlID = uID;
     3693        dis.itemID = item.iItem;
     3694        dis.itemAction = ODA_DRAWENTIRE;
     3695        dis.itemState = 0;
     3696        if (item.state & LVIS_SELECTED) dis.itemState |= ODS_SELECTED;
     3697        if (infoPtr->bFocus && (item.state & LVIS_FOCUSED)) dis.itemState |= ODS_FOCUS;
     3698        dis.hwndItem = infoPtr->hwndSelf;
     3699        dis.hDC = hdc;
     3700        LISTVIEW_GetItemOrigin(infoPtr, dis.itemID, &Position);
     3701        dis.rcItem.left = Position.x + Origin.x;
     3702        dis.rcItem.right = dis.rcItem.left + infoPtr->nItemWidth;
     3703        dis.rcItem.top = Position.y + Origin.y;
     3704        dis.rcItem.bottom = dis.rcItem.top + infoPtr->nItemHeight;
     3705        dis.itemData = item.lParam;
     3706
     3707        TRACE("item=%s, rcItem=%s\n", debuglvitem_t(&item, TRUE), debugrect(&dis.rcItem));
     3708
     3709        if (cdmode & CDRF_NOTIFYITEMDRAW)
     3710        {
     3711            customdraw_fill(&nmlvcd, infoPtr, hdc, &dis.rcItem, &item);
     3712            cditemmode = notify_prepaint (infoPtr, hdc, &nmlvcd);
     3713        }
     3714   
     3715        if (!(cditemmode & CDRF_SKIPDEFAULT))
     3716            SendMessageW(hwndParent, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis);
     3717
     3718        if (cditemmode & CDRF_NOTIFYPOSTPAINT)
     3719            notify_postpaint(infoPtr, &nmlvcd);
     3720    }
     3721}
     3722
     3723/***
     3724 * DESCRIPTION:
     3725 * Draws listview items when in report display mode.
     3726 *
     3727 * PARAMETER(S):
     3728 * [I] infoPtr : valid pointer to the listview structure
     3729 * [I] hdc : device context handle
     3730 * [I] cdmode : custom draw mode
     3731 *
     3732 * RETURN:
     3733 * None
     3734 */
     3735static void LISTVIEW_RefreshReport(LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, DWORD cdmode)
     3736{
     3737    INT rgntype;
     3738    RECT rcClip, rcItem;
     3739    POINT Origin, Position;
     3740    RANGE colRange;
     3741    ITERATOR j;
     3742
     3743    TRACE("()\n");
     3744
     3745    /* figure out what to draw */
     3746    rgntype = GetClipBox(hdc, &rcClip);
     3747    if (rgntype == NULLREGION) return;
     3748   
     3749    /* Get scroll info once before loop */
     3750    LISTVIEW_GetOrigin(infoPtr, &Origin);
     3751   
     3752    /* narrow down the columns we need to paint */
     3753    for(colRange.lower = 0; colRange.lower < infoPtr->hdpaColumns->nItemCount; colRange.lower++)
     3754    {
     3755        LISTVIEW_GetHeaderRect(infoPtr, colRange.lower, &rcItem);
     3756        if (rcItem.right + Origin.x >= rcClip.left) break;
     3757    }
     3758    for(colRange.upper = infoPtr->hdpaColumns->nItemCount; colRange.upper > 0; colRange.upper--)
     3759    {
     3760        LISTVIEW_GetHeaderRect(infoPtr, colRange.upper - 1, &rcItem);
     3761        if (rcItem.left + Origin.x < rcClip.right) break;
     3762    }
     3763    iterator_rangeitems(&j, colRange);
     3764
     3765    /* in full row select, we _have_ to draw the main item */
     3766    if (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT)
     3767        j.nSpecial = 0;
     3768
     3769    /* iterate through the invalidated rows */
     3770    while(iterator_next(i))
     3771    {
     3772        /* iterate through the invalidated columns */
     3773        while(iterator_next(&j))
     3774        {
     3775            LISTVIEW_GetItemOrigin(infoPtr, i->nItem, &Position);
     3776            Position.x += Origin.x;
     3777            Position.y += Origin.y;
     3778
     3779            if (rgntype == COMPLEXREGION && !((infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) && j.nItem == 0))
     3780            {
     3781                LISTVIEW_GetHeaderRect(infoPtr, j.nItem, &rcItem);
     3782                rcItem.top = 0;
     3783                rcItem.bottom = infoPtr->nItemHeight;
     3784                OffsetRect(&rcItem, Position.x, Position.y);
     3785                if (!RectVisible(hdc, &rcItem)) continue;
     3786            }
     3787
     3788            LISTVIEW_DrawItem(infoPtr, hdc, i->nItem, j.nItem, Position, cdmode);
     3789        }
     3790    }
     3791    iterator_destroy(&j);
     3792}
     3793
     3794/***
     3795 * DESCRIPTION:
     3796 * Draws listview items when in list display mode.
     3797 *
     3798 * PARAMETER(S):
     3799 * [I] infoPtr : valid pointer to the listview structure
     3800 * [I] hdc : device context handle
     3801 * [I] cdmode : custom draw mode
     3802 *
     3803 * RETURN:
     3804 * None
     3805 */
     3806static void LISTVIEW_RefreshList(LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, DWORD cdmode)
     3807{
     3808    POINT Origin, Position;
     3809
     3810    /* Get scroll info once before loop */
     3811    LISTVIEW_GetOrigin(infoPtr, &Origin);
     3812   
     3813    while(iterator_prev(i))
     3814    {
     3815        LISTVIEW_GetItemOrigin(infoPtr, i->nItem, &Position);
     3816        Position.x += Origin.x;
     3817        Position.y += Origin.y;
     3818
     3819        LISTVIEW_DrawItem(infoPtr, hdc, i->nItem, 0, Position, cdmode);
     3820    }
     3821}
     3822
     3823
     3824/***
     3825 * DESCRIPTION:
     3826 * Draws listview items.
     3827 *
     3828 * PARAMETER(S):
     3829 * [I] infoPtr : valid pointer to the listview structure
     3830 * [I] hdc : device context handle
     3831 *
     3832 * RETURN:
     3833 * NoneX
     3834 */
     3835static void LISTVIEW_Refresh(LISTVIEW_INFO *infoPtr, HDC hdc)
     3836{
     3837    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     3838    COLORREF oldTextColor, oldClrTextBk, oldClrText;
     3839    NMLVCUSTOMDRAW nmlvcd;
     3840    HFONT hOldFont;
     3841    DWORD cdmode;
     3842    INT oldBkMode;
     3843    RECT rcClient;
     3844    ITERATOR i;
     3845
     3846    LISTVIEW_DUMP(infoPtr);
    28883847 
    2889   return NULL;
    2890 }
    2891 
    2892 /***
    2893  * DESCRIPTION:
    2894  * Sets item attributes.
    2895  *
    2896  * PARAMETER(S):
    2897  * [I] HWND : window handle
    2898  * [I] LPLVITEM : new item atttributes
    2899  * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
    2900  *
    2901  * RETURN:
    2902  *   SUCCESS : TRUE
    2903  *   FAILURE : FALSE
    2904  */
    2905 static BOOL LISTVIEW_SetMainItemT(HWND hwnd, LPLVITEMW lpLVItem, BOOL isW)
    2906 {
    2907   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    2908   BOOL bResult = FALSE;
    2909   HDPA hdpaSubItems;
    2910   LISTVIEW_ITEM *lpItem;
    2911   NMLISTVIEW nmlv;
    2912   LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    2913   UINT uChanged;
    2914   UINT uView = lStyle & LVS_TYPEMASK;
    2915   INT item_width;
    2916   RECT rcItem;
    2917 
    2918   TRACE("(hwnd=%x, lpLVItem=%s, isW=%d)\n", hwnd, debuglvitem_t(lpLVItem, isW), isW);
    2919    
    2920   if (lStyle & LVS_OWNERDATA)
    2921   {
    2922     if ((lpLVItem->iSubItem == 0)&&(lpLVItem->mask == LVIF_STATE))
    2923     {
    2924       LVITEMW itm;
    2925 
    2926       ZeroMemory(&itm, sizeof(itm));
    2927       itm.mask = LVIF_STATE | LVIF_PARAM;
    2928       itm.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
    2929       itm.iItem = lpLVItem->iItem;
    2930       itm.iSubItem = 0;
    2931       ListView_GetItemW(hwnd, &itm);
    2932      
    2933 
    2934       ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
    2935       nmlv.uNewState = lpLVItem->state;
    2936       nmlv.uOldState = itm.state;
    2937       nmlv.uChanged = LVIF_STATE;
    2938       nmlv.lParam = itm.lParam;
    2939       nmlv.iItem = lpLVItem->iItem;
    2940 
    2941       if ((itm.state & lpLVItem->stateMask) !=
    2942           (lpLVItem->state & lpLVItem->stateMask))
    2943       {
    2944         /* send LVN_ITEMCHANGING notification */
    2945         if (!listview_notify(hwnd, LVN_ITEMCHANGING, &nmlv))
    2946         {
    2947           if (lpLVItem->stateMask & LVIS_FOCUSED)
    2948           {
    2949             if (lpLVItem->state & LVIS_FOCUSED)
    2950               infoPtr->nFocusedItem = lpLVItem->iItem;
    2951             else if (infoPtr->nFocusedItem == lpLVItem->iItem)
    2952               infoPtr->nFocusedItem = -1;
    2953           }
    2954           if (lpLVItem->stateMask & LVIS_SELECTED)
    2955           {
    2956             if (lpLVItem->state & LVIS_SELECTED)
    2957             {
    2958               if (lStyle & LVS_SINGLESEL) LISTVIEW_RemoveAllSelections(hwnd);
    2959               LISTVIEW_AddSelectionRange(hwnd,lpLVItem->iItem,lpLVItem->iItem);
    2960             }
    2961             else
    2962               LISTVIEW_RemoveSelectionRange(hwnd,lpLVItem->iItem,
    2963                                             lpLVItem->iItem);
    2964           }
    2965 
    2966           listview_notify(hwnd, LVN_ITEMCHANGED, &nmlv);
    2967 
    2968           rcItem.left = LVIR_BOUNDS;
    2969           LISTVIEW_GetItemRect(hwnd, lpLVItem->iItem, &rcItem);
    2970 #ifdef __WIN32OS2__
    2971             if(lStyle & LVS_OWNERDRAWFIXED && rcItem.left == REPORT_MARGINX) {
    2972                rcItem.left = 0;
    2973             }
    2974 #endif
    2975           InvalidateRect(hwnd, &rcItem, TRUE);
    2976         }
    2977       }
    2978       return TRUE;
    2979     }
    2980     return FALSE;
    2981   }
    2982 
    2983   if (lpLVItem != NULL)
    2984   {
    2985     if (lpLVItem->iSubItem == 0)
    2986     {
    2987       hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
    2988       if (hdpaSubItems != NULL && hdpaSubItems != (HDPA)-1)
    2989       {
    2990         lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem);
    2991         if (lpItem != NULL)
    2992         {
    2993           ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
    2994           nmlv.lParam = lpItem->lParam;
    2995 #ifdef __WIN32OS2__
    2996           uChanged = LISTVIEW_GetItemChangesT(lpItem, lpLVItem, isW, lStyle);
    2997 #else
    2998           uChanged = LISTVIEW_GetItemChangesT(lpItem, lpLVItem, isW);
    2999 #endif
    3000           if (uChanged != 0)
    3001           {
    3002             if (uChanged & LVIF_STATE)
    3003             {
    3004               nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask;
    3005               nmlv.uOldState = lpItem->state & lpLVItem->stateMask;
    3006 
    3007               if (nmlv.uNewState & LVIS_SELECTED)
    3008               {
    3009                 /*
    3010                  * This is redundant if called through SetSelection
    3011                  *
    3012                  * however is required if the used directly calls SetItem
    3013                  * to set the selection.
    3014                  */
    3015                 if (lStyle & LVS_SINGLESEL)
    3016                   LISTVIEW_RemoveAllSelections(hwnd);
    3017 
    3018                 LISTVIEW_AddSelectionRange(hwnd,lpLVItem->iItem,
    3019                                              lpLVItem->iItem);
    3020               }
    3021               else if (lpLVItem->stateMask & LVIS_SELECTED)
    3022               {
    3023                 LISTVIEW_RemoveSelectionRange(hwnd,lpLVItem->iItem,
    3024                                               lpLVItem->iItem);
    3025               }
    3026               if (nmlv.uNewState & LVIS_FOCUSED)
    3027               {
    3028                 /*
    3029                  * This is a fun hoop to jump to try to catch if
    3030                  * the user is calling us directly to call focus or if
    3031                  * this function is being called as a result of a
    3032                  * SetItemFocus call.
    3033                  */
    3034 #ifdef __WIN32OS2__
    3035                 //SvL: Allow focus change the first time (nFocusedItem set to -2
    3036                 //     in WM_CREATE
    3037                 if (infoPtr->nFocusedItem >= 0 || infoPtr->nFocusedItem == -2) {
    3038                    if(infoPtr->nFocusedItem == -2) infoPtr->nFocusedItem = -1;
    3039                    LISTVIEW_SetItemFocus(hwnd, lpLVItem->iItem);
    3040                 }
    3041 #else
    3042                 if (infoPtr->nFocusedItem >= 0)
    3043                   LISTVIEW_SetItemFocus(hwnd, lpLVItem->iItem);
    3044 #endif
    3045               }           
    3046             }
    3047            
    3048             nmlv.uChanged = uChanged;
    3049             nmlv.iItem = lpLVItem->iItem;
    3050             nmlv.lParam = lpItem->lParam;
    3051             /* send LVN_ITEMCHANGING notification */
    3052             listview_notify(hwnd, LVN_ITEMCHANGING, &nmlv);
    3053 
    3054             /* copy information */
    3055             bResult = LISTVIEW_InitItemT(hwnd, lpItem, lpLVItem, isW);
    3056 
    3057             /* if LVS_LIST or LVS_SMALLICON, update the width of the items
    3058                based on the width of the items text */
    3059             if((uView == LVS_LIST) || (uView == LVS_SMALLICON))
    3060             {
    3061               item_width = LISTVIEW_GetStringWidthT(hwnd, lpItem->pszText, TRUE);
    3062 
    3063               if(item_width > infoPtr->nItemWidth)
    3064                   infoPtr->nItemWidth = item_width;
    3065             }
    3066 
    3067             /* send LVN_ITEMCHANGED notification */
    3068             listview_notify(hwnd, LVN_ITEMCHANGED, &nmlv);
    3069           }
    3070           else
    3071           {
    3072             bResult = TRUE;
    3073           }
    3074          
    3075           if (uChanged)
    3076           {
    3077             rcItem.left = LVIR_BOUNDS;
    3078             LISTVIEW_GetItemRect(hwnd, lpLVItem->iItem, &rcItem);
    3079 #ifdef __WIN32OS2__
    3080             if(lStyle & LVS_OWNERDRAWFIXED && rcItem.left == REPORT_MARGINX) {
    3081                rcItem.left = 0;
    3082             }
    3083 #endif
    3084             InvalidateRect(hwnd, &rcItem, TRUE);
    3085           }
    3086         }
    3087       }
    3088     }
    3089   }
    3090 
    3091   return bResult;
    3092 }
    3093 
    3094 /***
    3095  * DESCRIPTION:
    3096  * Sets subitem attributes.
    3097  *
    3098  * PARAMETER(S):
    3099  * [I] HWND : window handle
    3100  * [I] LPLVITEM : new subitem atttributes
    3101  * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
    3102  *
    3103  * RETURN:
    3104  *   SUCCESS : TRUE
    3105  *   FAILURE : FALSE
    3106  */
    3107 static BOOL LISTVIEW_SetSubItemT(HWND hwnd, LPLVITEMW lpLVItem, BOOL isW)
    3108 {
    3109   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    3110   LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    3111   BOOL bResult = FALSE;
    3112   HDPA hdpaSubItems;
    3113   LISTVIEW_SUBITEM *lpSubItem;
    3114   RECT rcItem;
    3115 
    3116   TRACE("(hwnd=%x, lpLVItem=%s, isW=%d)\n", hwnd, debuglvitem_t(lpLVItem, isW), isW);
    3117  
    3118   if (lStyle & LVS_OWNERDATA)
    3119     return FALSE;
    3120 
    3121   if (lpLVItem != NULL)
    3122   {
    3123     if (lpLVItem->iSubItem > 0)
    3124     {
    3125       hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
    3126       if (hdpaSubItems != NULL)
    3127       {
    3128         /* set subitem only if column is present */
    3129         if (Header_GetItemCount(infoPtr->hwndHeader) > lpLVItem->iSubItem)
    3130         {
    3131           lpSubItem = LISTVIEW_GetSubItem(hdpaSubItems, lpLVItem->iSubItem);
    3132           if (lpSubItem != NULL)
    3133             bResult = LISTVIEW_InitSubItemT(hwnd, lpSubItem, lpLVItem, isW);
    3134           else
    3135             bResult = LISTVIEW_AddSubItemT(hwnd, lpLVItem, isW);
    3136 #ifdef __WIN32OS2__
    3137           if(bResult) {
    3138 #endif
    3139           rcItem.left = LVIR_BOUNDS;
    3140           LISTVIEW_GetItemRect(hwnd, lpLVItem->iItem, &rcItem);
    3141           InvalidateRect(hwnd, &rcItem, FALSE);
    3142 #ifdef __WIN32OS2__
    3143           }
    3144 #endif
    3145         }
    3146       }
    3147     }
    3148   }
    3149 
    3150   return bResult;
    3151 }
    3152 
    3153 /***
    3154  * DESCRIPTION:
    3155  * Sets item attributes.
    3156  *
    3157  * PARAMETER(S):
    3158  * [I] HWND : window handle
    3159  * [I] LPLVITEM : new item atttributes
    3160  * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
    3161  *
    3162  * RETURN:
    3163  *   SUCCESS : TRUE
    3164  *   FAILURE : FALSE
    3165  */
    3166 static BOOL LISTVIEW_SetItemT(HWND hwnd, LPLVITEMW lpLVItem, BOOL isW)
    3167 {
    3168   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    3169 
    3170   if (!lpLVItem || lpLVItem->iItem < 0 ||
    3171       lpLVItem->iItem>=GETITEMCOUNT(infoPtr))
    3172     return FALSE;
    3173   if (lpLVItem->iSubItem == 0)
    3174     return LISTVIEW_SetMainItemT(hwnd, lpLVItem, isW);
    3175   else
    3176     return LISTVIEW_SetSubItemT(hwnd, lpLVItem, isW);
    3177 }
    3178 
    3179 /***
    3180  * DESCRIPTION:
    3181  * Retrieves the index of the item at coordinate (0, 0) of the client area.
    3182  *
    3183  * PARAMETER(S):
    3184  * [I] HWND : window handle
    3185  *
    3186  * RETURN:
    3187  * item index
    3188  */
    3189 static INT LISTVIEW_GetTopIndex(HWND hwnd)
    3190 {
    3191   LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    3192   UINT uView = lStyle & LVS_TYPEMASK;
    3193   INT nItem = 0;
    3194   SCROLLINFO scrollInfo;
    3195 
    3196   ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
    3197   scrollInfo.cbSize = sizeof(SCROLLINFO);
    3198   scrollInfo.fMask = SIF_POS;
    3199  
    3200   if (uView == LVS_LIST)
    3201   {
    3202     if ((lStyle & WS_HSCROLL) && GetScrollInfo(hwnd, SB_HORZ, &scrollInfo))
    3203       nItem = scrollInfo.nPos * LISTVIEW_GetCountPerColumn(hwnd);
    3204   }
    3205   else if (uView == LVS_REPORT)
    3206   {
    3207     if ((lStyle & WS_VSCROLL) && GetScrollInfo(hwnd, SB_VERT, &scrollInfo))
    3208       nItem = scrollInfo.nPos;
    3209   }
    3210  
    3211   return nItem;
    3212 }
    3213 
    3214 /***
    3215  * DESCRIPTION:
    3216  * Draws a subitem.
    3217  *
    3218  * PARAMETER(S):
    3219  * [I] HWND : window handle
    3220  * [I] HDC : device context handle
    3221  * [I] INT : item index
    3222  * [I] INT : subitem index
    3223  * [I] RECT * : clipping rectangle
    3224  *
    3225  * RETURN:
    3226  * None
    3227  */
    3228 static VOID LISTVIEW_DrawSubItem(HWND hwnd, HDC hdc, INT nItem, INT nSubItem,
    3229                                  RECT rcItem, BOOL Selected)
    3230 {
    3231   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    3232   WCHAR szDispText[DISP_TEXT_SIZE];
    3233   LVITEMW lvItem;
    3234   LVCOLUMNW lvColumn;
    3235   UINT textoutOptions = ETO_CLIPPED | ETO_OPAQUE;
    3236   RECT rcTemp;
    3237   INT textLeft;
    3238   INT nLabelWidth = 0;
    3239 
    3240   TRACE("(hwnd=%x, hdc=%x, nItem=%d, nSubItem=%d)\n", hwnd, hdc,
    3241         nItem, nSubItem);
    3242 
    3243   /* get information needed for drawing the item */
    3244   ZeroMemory(&lvItem, sizeof(lvItem));
    3245   lvItem.mask = LVIF_TEXT;
    3246   lvItem.iItem = nItem;
    3247   lvItem.iSubItem = nSubItem;
    3248   lvItem.cchTextMax = DISP_TEXT_SIZE;
    3249   lvItem.pszText = szDispText;
    3250   *lvItem.pszText = '\0';
    3251   LISTVIEW_GetItemW(hwnd, &lvItem, TRUE);
    3252   TRACE("   lvItem=%s\n", debuglvitem_t(&lvItem, TRUE));
    3253  
    3254   ZeroMemory(&lvColumn, sizeof(lvColumn));
    3255   lvColumn.mask = LVCF_FMT;
    3256   LISTVIEW_GetColumnT(hwnd, nSubItem, &lvColumn, TRUE);
    3257   textLeft = rcItem.left;
    3258   if (lvColumn.fmt != LVCFMT_LEFT)
    3259   {
    3260     if ((nLabelWidth = LISTVIEW_GetStringWidthT(hwnd, lvItem.pszText, TRUE)))
    3261     {
    3262       if (lvColumn.fmt == LVCFMT_RIGHT)
    3263         textLeft = rcItem.right - nLabelWidth;
    3264       else
    3265         textLeft = rcItem.left + (rcItem.right-rcItem.left-nLabelWidth)/2;
    3266     }
    3267   }
    3268    
    3269 
    3270   /* redraw the background of the item */
    3271   rcTemp = rcItem;
    3272   if(infoPtr->nColumnCount == (nSubItem + 1))
    3273     rcTemp.right  = infoPtr->rcList.right;
    3274   else
    3275     rcTemp.right += WIDTH_PADDING;
    3276 
    3277   LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
    3278 
    3279   /* set item colors */
    3280   if (ListView_GetItemState(hwnd,nItem,LVIS_SELECTED) && Selected)
    3281   {
    3282     if (infoPtr->bFocus)
    3283     {
    3284       SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
    3285       SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
    3286     }
     3848    infoPtr->bIsDrawing = TRUE;
     3849
     3850    /* save dc values we're gonna trash while drawing */
     3851    hOldFont = SelectObject(hdc, infoPtr->hFont);
     3852    oldBkMode = GetBkMode(hdc);
     3853    infoPtr->clrTextBkDefault = GetBkColor(hdc);
     3854    oldTextColor = GetTextColor(hdc);
     3855
     3856    oldClrTextBk = infoPtr->clrTextBk;
     3857    oldClrText   = infoPtr->clrText;
     3858   
     3859    GetClientRect(infoPtr->hwndSelf, &rcClient);
     3860    customdraw_fill(&nmlvcd, infoPtr, hdc, &rcClient, 0);
     3861    cdmode = notify_prepaint(infoPtr, hdc, &nmlvcd);
     3862    if (cdmode & CDRF_SKIPDEFAULT) goto enddraw;
     3863
     3864    /* Use these colors to draw the items */
     3865    infoPtr->clrTextBk = nmlvcd.clrTextBk;
     3866    infoPtr->clrText = nmlvcd.clrText;
     3867
     3868    /* nothing to draw */
     3869    if(infoPtr->nItemCount == 0) goto enddraw;
     3870
     3871    /* figure out what we need to draw */
     3872    iterator_visibleitems(&i, infoPtr, hdc);
     3873   
     3874    /* send cache hint notification */
     3875    if (infoPtr->dwStyle & LVS_OWNERDATA)
     3876    {
     3877        RANGE range = iterator_range(&i);
     3878        NMLVCACHEHINT nmlv;
     3879       
     3880        ZeroMemory(&nmlv, sizeof(NMLVCACHEHINT));
     3881        nmlv.iFrom = range.lower;
     3882        nmlv.iTo   = range.upper - 1;
     3883        notify_hdr(infoPtr, LVN_ODCACHEHINT, &nmlv.hdr);
     3884    }
     3885
     3886    if ((infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && (uView == LVS_REPORT))
     3887        LISTVIEW_RefreshOwnerDraw(infoPtr, &i, hdc, cdmode);
    32873888    else
    32883889    {
    3289       SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
    3290       SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
    3291     }
    3292   }
    3293   else
    3294   {
    3295     if ( (infoPtr->clrTextBk == CLR_DEFAULT) || (infoPtr->clrTextBk == CLR_NONE) )
    3296     {
    3297        SetBkMode(hdc, TRANSPARENT);
    3298        textoutOptions &= ~ETO_OPAQUE;
    3299     }
    3300     else
    3301     {
    3302       SetBkMode(hdc, OPAQUE);
    3303       SetBkColor(hdc, infoPtr->clrTextBk);
    3304     }
    3305 
    3306     SetTextColor(hdc, infoPtr->clrText);
    3307   }
    3308 
    3309   ExtTextOutW(hdc, textLeft, rcItem.top, textoutOptions,
    3310               &rcItem, lvItem.pszText, lstrlenW(lvItem.pszText), NULL);
    3311 
    3312   if (Selected)
    3313   {
    3314     /* fill in the gap */
    3315     RECT rec;
    3316     if (nSubItem < Header_GetItemCount(infoPtr->hwndHeader)-1)
    3317     {
    3318       CopyRect(&rec,&rcItem);
    3319       rec.left = rec.right;
    3320       rec.right = rec.left+REPORT_MARGINX;
    3321       ExtTextOutW(hdc, rec.left , rec.top, textoutOptions,
    3322         &rec, NULL, 0, NULL);
    3323     }
    3324     CopyRect(&rec,&rcItem);
    3325     rec.right = rec.left;
    3326     rec.left = rec.left - REPORT_MARGINX;
    3327     ExtTextOutW(hdc, rec.left , rec.top, textoutOptions,
    3328     &rec, NULL, 0, NULL);
    3329   }
    3330 }
    3331 
    3332 
    3333 /***
    3334  * DESCRIPTION:
    3335  * Draws an item.
    3336  *
    3337  * PARAMETER(S):
    3338  * [I] HWND : window handle
    3339  * [I] HDC : device context handle
    3340  * [I] INT : item index
    3341  * [I] RECT * : clipping rectangle
    3342  *
    3343  * RETURN:
    3344  * None
    3345  */
    3346 static VOID LISTVIEW_DrawItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem, BOOL FullSelect, RECT* SuggestedFocus)
    3347 {
    3348   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    3349   WCHAR szDispText[DISP_TEXT_SIZE];
    3350   INT nLabelWidth;
    3351   LVITEMW lvItem;
    3352   INT nMixMode;
    3353   DWORD dwBkColor;
    3354   DWORD dwTextColor,dwTextX;
    3355   BOOL bImage = FALSE;
    3356   INT   iBkMode = -1;
    3357   UINT  textoutOptions = ETO_OPAQUE | ETO_CLIPPED;
    3358   RECT rcTemp;
    3359 
    3360   TRACE("(hwnd=%x, hdc=%x, nItem=%d)\n", hwnd, hdc, nItem);
    3361 
    3362 
    3363   /* get information needed for drawing the item */
    3364   ZeroMemory(&lvItem, sizeof(lvItem));
    3365   lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_INDENT;
    3366   lvItem.stateMask = LVIS_SELECTED |  LVIS_STATEIMAGEMASK;
    3367   lvItem.iItem = nItem;
    3368   lvItem.iSubItem = 0;
    3369   lvItem.cchTextMax = DISP_TEXT_SIZE;
    3370   lvItem.pszText = szDispText;
    3371   *lvItem.pszText = '\0';
    3372   LISTVIEW_GetItemW(hwnd, &lvItem, TRUE);
    3373   TRACE("   lvItem=%s\n", debuglvitem_t(&lvItem, TRUE));
    3374 
    3375   /* redraw the background of the item */
    3376   rcTemp = rcItem;
    3377   if(infoPtr->nColumnCount == (nItem + 1))
    3378     rcTemp.right = infoPtr->rcList.right;
    3379   else
    3380     rcTemp.right+=WIDTH_PADDING;
    3381 
    3382   LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
    3383 
    3384   /* do indent */
    3385   if (lvItem.iIndent>0 && infoPtr->iconSize.cx > 0)
    3386   {
    3387     rcItem.left += infoPtr->iconSize.cx * lvItem.iIndent;
    3388 
    3389     if (SuggestedFocus)
    3390       SuggestedFocus->left += infoPtr->iconSize.cx * lvItem.iIndent;
    3391   }
    3392 
    3393   /* state icons */
    3394   if (infoPtr->himlState != NULL)
    3395   {
    3396      UINT uStateImage = (lvItem.state & LVIS_STATEIMAGEMASK) >> 12;
    3397      if (uStateImage > 0)
    3398      {
    3399        ImageList_Draw(infoPtr->himlState, uStateImage - 1, hdc, rcItem.left,
    3400                       rcItem.top, ILD_NORMAL);
    3401      }
    3402  
    3403      rcItem.left += infoPtr->iconSize.cx;
    3404      if (SuggestedFocus)
    3405        SuggestedFocus->left += infoPtr->iconSize.cx;
    3406      bImage = TRUE;
    3407   }
    3408  
    3409   /* small icons */
    3410   if (infoPtr->himlSmall != NULL)
    3411   {
    3412     if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE) &&
    3413         (lvItem.iImage>=0))
    3414     {
    3415       ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
    3416       ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
    3417                      rcItem.top, ILD_SELECTED);
    3418     }
    3419     else if (lvItem.iImage>=0)
    3420     {
    3421       ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
    3422       ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
    3423                      rcItem.top, ILD_NORMAL);
    3424     }
    3425    
    3426     rcItem.left += infoPtr->iconSize.cx;
    3427 
    3428     if (SuggestedFocus)
    3429       SuggestedFocus->left += infoPtr->iconSize.cx;
    3430     bImage = TRUE;
    3431   }
    3432 
    3433   /* Don't bother painting item being edited */
    3434   if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED && !FullSelect)
    3435       return;
    3436 
    3437   if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
    3438   {
    3439     /* set item colors */
    3440     dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
    3441     dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
    3442     /* set raster mode */
    3443     nMixMode = SetROP2(hdc, R2_XORPEN);
    3444   }
    3445   else if ((GetWindowLongW(hwnd, GWL_STYLE) & LVS_SHOWSELALWAYS) &&
    3446            (lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus == FALSE))
    3447   {
    3448     dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
    3449     dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
    3450     /* set raster mode */
    3451     nMixMode = SetROP2(hdc, R2_COPYPEN);
    3452   }
    3453   else
    3454   {
    3455     /* set item colors */
    3456     if ( (infoPtr->clrTextBk == CLR_DEFAULT) || (infoPtr->clrTextBk == CLR_NONE) )
    3457     {
    3458       dwBkColor = GetBkColor(hdc);
    3459       iBkMode = SetBkMode(hdc, TRANSPARENT);
    3460       textoutOptions &= ~ETO_OPAQUE;
    3461     }
    3462     else
    3463     {
    3464       dwBkColor = SetBkColor(hdc, infoPtr->clrTextBk);
    3465       iBkMode = SetBkMode(hdc, OPAQUE);
    3466     }
    3467 
    3468     dwTextColor = SetTextColor(hdc, infoPtr->clrText);
    3469     /* set raster mode */
    3470     nMixMode = SetROP2(hdc, R2_COPYPEN);
    3471   }
    3472  
    3473   nLabelWidth = ListView_GetStringWidthW(hwnd, lvItem.pszText);
    3474   if (rcItem.left + nLabelWidth < rcItem.right)
    3475   {
    3476     if (!FullSelect)
    3477       rcItem.right = rcItem.left + nLabelWidth + TRAILING_PADDING;
    3478     if (bImage)
    3479       rcItem.right += IMAGE_PADDING;
    3480   }
    3481  
    3482   /* draw label */ 
    3483   dwTextX = rcItem.left + 1;
    3484   if (bImage)
    3485     dwTextX += IMAGE_PADDING;
    3486 
    3487   if (lvItem.pszText)
    3488     ExtTextOutW(hdc, dwTextX, rcItem.top, textoutOptions,
    3489                 &rcItem, lvItem.pszText, lstrlenW(lvItem.pszText), NULL);
    3490 
    3491   if ((FullSelect)&&(Header_GetItemCount(infoPtr->hwndHeader) > 1))
    3492   {
    3493     /* fill in the gap */
    3494     RECT rec;
    3495     CopyRect(&rec,&rcItem);
    3496     rec.left = rec.right;
    3497     rec.right = rec.left+REPORT_MARGINX;
    3498     ExtTextOutW(hdc, rec.left , rec.top, textoutOptions,
    3499     &rec, NULL, 0, NULL);
    3500   }
    3501  
    3502   if (!FullSelect)
    3503       CopyRect(SuggestedFocus,&rcItem);
    3504 
    3505   if (nMixMode != 0)
    3506   {
    3507     SetROP2(hdc, R2_COPYPEN);
    3508     SetBkColor(hdc, dwBkColor);
    3509     SetTextColor(hdc, dwTextColor);
    3510     if (iBkMode != -1)
    3511       SetBkMode(hdc, iBkMode);
    3512   }
    3513 }
    3514 
    3515 /***
    3516  * DESCRIPTION:
    3517  * Draws an item when in large icon display mode.
    3518  *
    3519  * PARAMETER(S):
    3520  * [I] HWND : window handle
    3521  * [I] HDC : device context handle
    3522  * [I] INT : item index
    3523  * [I] RECT : clipping rectangle
    3524  * [O] RECT * : The text rectangle about which to draw the focus
    3525  *
    3526  * RETURN:
    3527  * None
    3528  */
    3529 static VOID LISTVIEW_DrawLargeItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem,
    3530                                    RECT *SuggestedFocus)
    3531 {
    3532   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    3533   WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
    3534   LVITEMW lvItem;
    3535   UINT uFormat = DT_TOP | DT_CENTER | DT_WORDBREAK | DT_NOPREFIX |
    3536                  DT_EDITCONTROL ;
    3537   /* Maintain this format in line with the one in LISTVIEW_UpdateLargeItemLabelRect*/
    3538   RECT rcTemp;
    3539 
    3540   TRACE("(hwnd=%x, hdc=%x, nItem=%d, left=%d, top=%d, right=%d, bottom=%d)\n",
    3541         hwnd, hdc, nItem, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
    3542 
    3543   /* get information needed for drawing the item */
    3544   ZeroMemory(&lvItem, sizeof(lvItem));
    3545   lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
    3546   lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
    3547   lvItem.iItem = nItem;
    3548   lvItem.iSubItem = 0;
    3549   lvItem.cchTextMax = DISP_TEXT_SIZE;
    3550   lvItem.pszText = szDispText;
    3551   *lvItem.pszText = '\0';
    3552   LISTVIEW_GetItemW(hwnd, &lvItem, FALSE);
    3553   TRACE("   lvItem=%s\n", debuglvitem_t(&lvItem, TRUE));
    3554 
    3555   /* redraw the background of the item */
    3556   rcTemp = rcItem;
    3557   if(infoPtr->nColumnCount == (nItem + 1))
    3558     rcTemp.right = infoPtr->rcList.right;
    3559   else
    3560     rcTemp.right+=WIDTH_PADDING;
    3561     /* The comment doesn't say WIDTH_PADDING applies to large icons */
    3562  
    3563   TRACE("background rect (%d,%d)-(%d,%d)\n",
    3564         rcTemp.left, rcTemp.top, rcTemp.right, rcTemp.bottom);
    3565  
    3566   LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
    3567 
    3568 
    3569   /* Figure out text colours etc. depending on state
    3570    * At least the following states exist; there may be more.
    3571    * Many items may be selected
    3572    * At most one item may have the focus
    3573    * The application may not actually be active currently
    3574    * 1. The item is not selected in any way
    3575    * 2. The cursor is flying over the icon or text and the text is being
    3576    *    expanded because it is not fully displayed currently.
    3577    * 3. The item is selected and is focussed, i.e. the user has not clicked
    3578    *    in the blank area of the window, and the window (or application?)
    3579    *    still has the focus.
    3580    * 4. As 3 except that a different window has the focus
    3581    * 5. The item is the selected item of all the items, but the user has
    3582    *    clicked somewhere else on the window.
    3583    * Only a few of these are handled currently. In particular 2 is not yet
    3584    * handled since we do not support the functionality currently (or at least
    3585    * we didn't when I wrote this)
    3586    */
    3587 
    3588   if (lvItem.state & LVIS_SELECTED)
    3589   {
    3590     /* set item colors */
    3591     SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
    3592     SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
    3593     SetBkMode (hdc, OPAQUE);
    3594     /* set raster mode */
    3595     SetROP2(hdc, R2_XORPEN);
    3596     /* When exactly is it in XOR? while being dragged? */
    3597   }
    3598   else
    3599   {
    3600     /* set item colors */
    3601     if ( (infoPtr->clrTextBk == CLR_DEFAULT) || (infoPtr->clrTextBk == CLR_NONE) )
    3602     {
    3603        SetBkMode(hdc, TRANSPARENT);
    3604     }
    3605     else
    3606     {
    3607       SetBkMode(hdc, OPAQUE);
    3608       SetBkColor(hdc, infoPtr->clrTextBk);
    3609     }
    3610 
    3611     SetTextColor(hdc, infoPtr->clrText);
    3612     /* set raster mode */
    3613     SetROP2(hdc, R2_COPYPEN);
    3614   }
    3615 
    3616   /* In cases 2,3 and 5 (see above) the full text is displayed, with word
    3617    * wrapping and long words split.
    3618    * In cases 1 and 4 only a portion of the text is displayed with word
    3619    * wrapping and both word and end ellipsis.  (I don't yet know about path
    3620    * ellipsis)
    3621    */
    3622   uFormat |= ( (lvItem.state & LVIS_FOCUSED) && infoPtr->bFocus) ?
    3623           DT_NOCLIP
    3624       :
    3625           DT_WORD_ELLIPSIS | DT_END_ELLIPSIS;
    3626 
    3627   /* draw the icon */
    3628   if (infoPtr->himlNormal != NULL)
    3629   {
    3630     if (lvItem.iImage >= 0)
    3631     {
    3632       ImageList_Draw (infoPtr->himlNormal, lvItem.iImage, hdc, rcItem.left,
    3633                       rcItem.top,
    3634                       (lvItem.state & LVIS_SELECTED) ? ILD_SELECTED : ILD_NORMAL);
    3635     }
    3636   }
    3637 
    3638   /* Draw the text below the icon */
    3639 
    3640   /* Don't bother painting item being edited */
    3641   if ((infoPtr->hwndEdit && (lvItem.state & LVIS_FOCUSED)) ||
    3642       !lstrlenW(lvItem.pszText))
    3643   {
    3644     SetRectEmpty(SuggestedFocus);
    3645     return;
    3646   }
    3647 
    3648   /* Since rcItem.left is left point of icon, compute left point of item box */
    3649   rcItem.left -= ((infoPtr->nItemWidth - infoPtr->iconSize.cx) / 2);
    3650   rcItem.right = rcItem.left + infoPtr->nItemWidth;
    3651   rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
    3652   TRACE("bound box for text+icon (%d,%d)-(%d,%d), iS.cx=%ld, nItemWidth=%d\n",
    3653         rcItem.left, rcItem.top, rcItem.right, rcItem.bottom,
    3654         infoPtr->iconSize.cx, infoPtr->nItemWidth);
    3655   TRACE("rcList (%d,%d)-(%d,%d), rcView (%d,%d)-(%d,%d)\n",
    3656         infoPtr->rcList.left,    infoPtr->rcList.top,
    3657         infoPtr->rcList.right,   infoPtr->rcList.bottom,
    3658         infoPtr->rcView.left,    infoPtr->rcView.top,
    3659         infoPtr->rcView.right,   infoPtr->rcView.bottom);
    3660  
    3661   InflateRect(&rcItem, -(2*CAPTION_BORDER), 0);
    3662   rcItem.top += infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
    3663 
    3664 
    3665   /* draw label */ 
    3666 
    3667   /* I am sure of most of the uFormat values.  However I am not sure about
    3668    * whether we need or do not need the following:
    3669    * DT_EXTERNALLEADING, DT_INTERNAL, DT_CALCRECT, DT_NOFULLWIDTHCHARBREAK,
    3670    * DT_PATH_ELLIPSIS, DT_RTLREADING,
    3671    * We certainly do not need
    3672    * DT_BOTTOM, DT_VCENTER, DT_MODIFYSTRING, DT_LEFT, DT_RIGHT, DT_PREFIXONLY,
    3673    * DT_SINGLELINE, DT_TABSTOP, DT_EXPANDTABS
    3674    */
    3675 
    3676   /* If the text is being drawn without clipping (i.e. the full text) then we
    3677    * need to jump through a few hoops to ensure that it all gets displayed and
    3678    * that the background is complete
    3679    */
    3680   if (uFormat & DT_NOCLIP)
    3681   {
    3682       RECT rcBack=rcItem;
    3683       HBRUSH hBrush = CreateSolidBrush(GetBkColor (hdc));
    3684       int dx, dy, old_wid, new_wid;
    3685       DrawTextW (hdc, lvItem.pszText, -1, &rcItem, uFormat | DT_CALCRECT);
    3686       /* Microsoft, in their great wisdom, have decided that the rectangle
    3687        * returned by DrawText on DT_CALCRECT will only guarantee the dimension,
    3688        * not the location.  So we have to do the centring ourselves (and take
    3689        * responsibility for agreeing off-by-one consistency with them).
    3690        */
    3691       old_wid = rcItem.right-rcItem.left;
    3692       new_wid = rcBack.right - rcBack.left;
    3693       dx = rcBack.left - rcItem.left + (new_wid-old_wid)/2;
    3694       dy = rcBack.top - rcItem.top;
    3695       OffsetRect (&rcItem, dx, dy);
    3696       FillRect(hdc, &rcItem, hBrush);
    3697       DeleteObject(hBrush);
    3698   }
    3699   /* else ? What if we are losing the focus? will we not get a complete
    3700    * background?
    3701    */
    3702   DrawTextW (hdc, lvItem.pszText, -1, &rcItem, uFormat);
    3703 
    3704   CopyRect(SuggestedFocus, &rcItem);
    3705 }
    3706 
    3707 /***
    3708  * DESCRIPTION:
    3709  * Draws listview items when in report display mode.
    3710  *
    3711  * PARAMETER(S):
    3712  * [I] HWND : window handle
    3713  * [I] HDC : device context handle
    3714  *
    3715  * RETURN:
    3716  * None
    3717  */
    3718 static VOID LISTVIEW_RefreshReport(HWND hwnd, HDC hdc, DWORD cdmode)
    3719 {
    3720   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd,0);
    3721   SCROLLINFO scrollInfo;
    3722   INT nDrawPosY = infoPtr->rcList.top;
    3723   INT nColumnCount;
    3724   RECT rcItem, rcTemp;
    3725   INT  j;
    3726   INT nItem;
    3727   INT nLast;
    3728   BOOL FullSelected;
    3729   DWORD cditemmode = CDRF_DODEFAULT;
    3730   LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    3731   INT scrollOffset;
    3732 
    3733   ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
    3734   scrollInfo.cbSize = sizeof(SCROLLINFO);
    3735   scrollInfo.fMask = SIF_POS;
    3736 
    3737   nItem = ListView_GetTopIndex(hwnd);
    3738 
    3739   /* add 1 for displaying a partial item at the bottom */
    3740   nLast = nItem + LISTVIEW_GetCountPerColumn(hwnd) + 1;
    3741   nLast = min(nLast, GETITEMCOUNT(infoPtr));
    3742 
    3743   /* send cache hint notification */
    3744   if (GetWindowLongW(hwnd,GWL_STYLE) & LVS_OWNERDATA)
    3745   {
    3746     NMLVCACHEHINT nmlv;
    3747 
    3748     nmlv.hdr.hwndFrom = hwnd;
    3749     nmlv.hdr.idFrom = GetWindowLongW(hwnd,GWL_ID);
    3750     nmlv.hdr.code = LVN_ODCACHEHINT;
    3751     nmlv.iFrom = nItem;
    3752     nmlv.iTo   = nLast;
    3753 
    3754     SendMessageW(GetParent(hwnd), WM_NOTIFY, (WPARAM)nmlv.hdr.idFrom,
    3755                  (LPARAM)&nmlv);
    3756   }
    3757 
    3758   nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
    3759   infoPtr->nColumnCount = nColumnCount; /* update nColumnCount */
    3760   FullSelected = infoPtr->dwExStyle & LVS_EX_FULLROWSELECT;
    3761 
    3762 #ifdef __WIN32OS2__
    3763   //@PF OwnerDraw does not need background clearing, it is supposed to be
    3764   //done by application itself.
    3765   if (!(lStyle & LVS_OWNERDRAWFIXED))
    3766   {
    3767 #endif
    3768     /* clear the background of any part of the control that doesn't contain items */
    3769     SubtractRect(&rcTemp, &infoPtr->rcList, &infoPtr->rcView);
    3770     LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
    3771 #ifdef __WIN32OS2__
    3772   }
    3773 #endif
    3774 
    3775   /* nothing to draw */
    3776   if(GETITEMCOUNT(infoPtr) == 0)
    3777     return;
    3778 
    3779   /* Get scroll bar info once before loop */
    3780   GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
    3781   scrollOffset = scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
    3782 
    3783   for (; nItem < nLast; nItem++)
    3784   {
    3785     RECT SuggestedFocusRect;
    3786 
    3787     /* Do Owner Draw */
    3788     if (lStyle & LVS_OWNERDRAWFIXED)
    3789     {
    3790         UINT uID = GetWindowLongW( hwnd, GWL_ID);
    3791         DRAWITEMSTRUCT dis;
    3792         LVITEMW item;
    3793         RECT br;
    3794 
    3795         TRACE("Owner Drawn\n");   
    3796         dis.CtlType = ODT_LISTVIEW;
    3797         dis.CtlID = uID;
    3798         dis.itemID = nItem;
    3799         dis.itemAction = ODA_DRAWENTIRE;
    3800         dis.itemState = 0;
    3801        
    3802         if (LISTVIEW_IsSelected(hwnd,nItem)) dis.itemState|=ODS_SELECTED;
    3803         if (nItem==infoPtr->nFocusedItem)   dis.itemState|=ODS_FOCUS;
    3804 
    3805         dis.hwndItem = hwnd;
    3806         dis.hDC = hdc;
    3807 
    3808         Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
    3809 
    3810         dis.rcItem.left = -scrollOffset;
    3811         dis.rcItem.right = max(dis.rcItem.left, br.right - scrollOffset);
    3812         dis.rcItem.top = nDrawPosY;
    3813         dis.rcItem.bottom = dis.rcItem.top + infoPtr->nItemHeight;
    3814        
    3815         ZeroMemory(&item,sizeof(item));
    3816         item.iItem = nItem;
    3817         item.mask = LVIF_PARAM;
    3818         ListView_GetItemW(hwnd, &item);
    3819 
    3820         dis.itemData = item.lParam;
    3821 
    3822         if (SendMessageW(GetParent(hwnd),WM_DRAWITEM,(WPARAM)uID,(LPARAM)&dis))
    3823         {
    3824           nDrawPosY += infoPtr->nItemHeight;
    3825           continue;
    3826         }
    3827     }
    3828 
    3829     if (FullSelected)
    3830     {
    3831       RECT ir,br;
    3832 
    3833       Header_GetItemRect(infoPtr->hwndHeader, 0, &ir);
    3834       Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
    3835 
    3836       ir.left += REPORT_MARGINX;
    3837       ir.right = max(ir.left, br.right - REPORT_MARGINX);
    3838       ir.top = nDrawPosY;
    3839       ir.bottom = ir.top + infoPtr->nItemHeight;
    3840      
    3841       CopyRect(&SuggestedFocusRect,&ir);
    3842     }
    3843 
    3844     for (j = 0; j < nColumnCount; j++)
    3845     {
    3846       if (cdmode & CDRF_NOTIFYITEMDRAW)
    3847         cditemmode = LISTVIEW_SendCustomDrawItemNotify (hwnd, hdc, nItem, j,
    3848                                                       CDDS_ITEMPREPAINT);
    3849       if (cditemmode & CDRF_SKIPDEFAULT)
    3850         continue;
    3851 
    3852       Header_GetItemRect(infoPtr->hwndHeader, j, &rcItem);
    3853 
    3854       rcItem.left += REPORT_MARGINX;
    3855       rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX);
    3856       rcItem.top = nDrawPosY;
    3857       rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
    3858 
    3859       /* Offset the Scroll Bar Pos */
    3860       rcItem.left -= scrollOffset;
    3861       rcItem.right -= scrollOffset;
    3862 
    3863       if (j == 0)
    3864       {
    3865         LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem, FullSelected,
    3866                           &SuggestedFocusRect);
    3867       }
    3868       else
    3869       {
    3870         LISTVIEW_DrawSubItem(hwnd, hdc, nItem, j, rcItem, FullSelected);
    3871       }
    3872 
    3873       if (cditemmode & CDRF_NOTIFYPOSTPAINT)
    3874         LISTVIEW_SendCustomDrawItemNotify(hwnd, hdc, nItem, 0,
    3875                                       CDDS_ITEMPOSTPAINT);
    3876     }
    3877     /*
    3878      * Draw Focus Rect
    3879      */
    3880     if (LISTVIEW_GetItemState(hwnd,nItem,LVIS_FOCUSED) && infoPtr->bFocus)
    3881     {
    3882       BOOL rop=FALSE;
    3883       if (FullSelected && LISTVIEW_GetItemState(hwnd,nItem,LVIS_SELECTED))
    3884         rop = SetROP2(hdc, R2_XORPEN);
    3885 
    3886       Rectangle(hdc, SuggestedFocusRect.left, SuggestedFocusRect.top,
    3887                 SuggestedFocusRect.right,SuggestedFocusRect.bottom);
    3888 
    3889       if (rop)
    3890         SetROP2(hdc, R2_COPYPEN);
    3891     }
    3892     nDrawPosY += infoPtr->nItemHeight;
    3893   }
    3894 
    3895 #ifdef __WIN32OS2__
    3896   /* we have to fill leftovers of what was NOT filled by application, otherwise
    3897      we will have gaps */
    3898   if ((lStyle & LVS_OWNERDRAWFIXED))
    3899   {
    3900     RECT tempRect;
    3901     CopyRect(&tempRect, &infoPtr->rcList);
    3902     tempRect.top = nDrawPosY;
    3903     if (tempRect.top < tempRect.bottom)
    3904       LISTVIEW_FillBackground(hwnd, hdc, &tempRect);
    3905   }
    3906 #endif
    3907 }
    3908 
    3909 /***
    3910  * DESCRIPTION:
    3911  * Retrieves the number of items that can fit vertically in the client area.
    3912  *
    3913  * PARAMETER(S):
    3914  * [I] HWND : window handle
    3915  *
    3916  * RETURN:
    3917  * Number of items per row.
    3918  */
    3919 static INT LISTVIEW_GetCountPerRow(HWND hwnd)
    3920 {
    3921   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd,0);
    3922   UINT uView = GetWindowLongW(hwnd, GWL_STYLE) & LVS_TYPEMASK;
    3923   INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
    3924   INT nCountPerRow = 1;
    3925 
    3926   if (nListWidth > 0)
    3927   {
    3928     if (uView != LVS_REPORT)
    3929     {
    3930       nCountPerRow =  nListWidth / infoPtr->nItemWidth;
    3931       if (nCountPerRow == 0) nCountPerRow = 1;
    3932     }
    3933   }
    3934 
    3935   return nCountPerRow;
    3936 }
    3937 
    3938 /***
    3939  * DESCRIPTION:
    3940  * Retrieves the number of items that can fit horizontally in the client
    3941  * area.
    3942  *
    3943  * PARAMETER(S):
    3944  * [I] HWND : window handle
    3945  *
    3946  * RETURN:
    3947  * Number of items per column.
    3948  */
    3949 static INT LISTVIEW_GetCountPerColumn(HWND hwnd)
    3950 {
    3951   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd,0);
    3952   INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
    3953   INT nCountPerColumn = 1;
    3954 
    3955 #ifdef __WIN32OS2__
    3956   if(infoPtr->nItemHeight == 0)
    3957       return 1;
    3958 #endif
    3959 
    3960   if (nListHeight > 0)
    3961   {
    3962     nCountPerColumn =  nListHeight / infoPtr->nItemHeight;
    3963     if (nCountPerColumn == 0) nCountPerColumn = 1;
    3964   }
    3965 
    3966   return nCountPerColumn;
    3967 }
    3968 
    3969 /***
    3970  * DESCRIPTION:
    3971  * Retrieves the number of columns needed to display all the items when in
    3972  * list display mode.
    3973  *
    3974  * PARAMETER(S):
    3975  * [I] HWND : window handle
    3976  *
    3977  * RETURN:
    3978  * Number of columns.
    3979  */
    3980 static INT LISTVIEW_GetColumnCount(HWND hwnd)
    3981 {
    3982   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    3983   LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    3984   INT nColumnCount = 0;
    3985 
    3986   if ((lStyle & LVS_TYPEMASK) == LVS_LIST)
    3987   {
    3988     nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth;
    3989     if (infoPtr->rcList.right % infoPtr->nItemWidth) nColumnCount++;
    3990   }
    3991 
    3992   return nColumnCount;
    3993 
    3994  
    3995 
    3996 /***
    3997  * DESCRIPTION:
    3998  * Draws listview items when in list display mode.
    3999  *
    4000  * PARAMETER(S):
    4001  * [I] HWND : window handle
    4002  * [I] HDC : device context handle
    4003  *
    4004  * RETURN:
    4005  * None
    4006  */
    4007 static VOID LISTVIEW_RefreshList(HWND hwnd, HDC hdc, DWORD cdmode)
    4008 {
    4009   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    4010   RECT rcItem, FocusRect, rcTemp;
    4011   INT i, j;
    4012   INT nItem;
    4013   INT nColumnCount;
    4014   INT nCountPerColumn;
    4015   INT nItemWidth = infoPtr->nItemWidth;
    4016   INT nItemHeight = infoPtr->nItemHeight;
    4017   DWORD cditemmode = CDRF_DODEFAULT;
    4018 
    4019   /* get number of fully visible columns */
    4020   nColumnCount = LISTVIEW_GetColumnCount(hwnd);
    4021   infoPtr->nColumnCount = nColumnCount;
    4022   nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
    4023   nItem = ListView_GetTopIndex(hwnd);
    4024 
    4025   /* paint the background of the control that doesn't contain any items */
    4026   SubtractRect(&rcTemp, &infoPtr->rcList, &infoPtr->rcView);
    4027   LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
    4028 
    4029   /* nothing to draw, return here */
    4030   if(GETITEMCOUNT(infoPtr) == 0)
    4031     return;
    4032 
    4033   for (i = 0; i < nColumnCount; i++)
    4034   {
    4035     for (j = 0; j < nCountPerColumn; j++, nItem++)
    4036     {
    4037       if (nItem >= GETITEMCOUNT(infoPtr))
    4038         return;
    4039 
    4040       if (cdmode & CDRF_NOTIFYITEMDRAW)
    4041         cditemmode = LISTVIEW_SendCustomDrawItemNotify (hwnd, hdc, nItem, 0,
    4042                                                       CDDS_ITEMPREPAINT);
    4043       if (cditemmode & CDRF_SKIPDEFAULT)
    4044         continue;
    4045 
    4046       rcItem.top = j * nItemHeight;
    4047       rcItem.left = i * nItemWidth;
    4048       rcItem.bottom = rcItem.top + nItemHeight;
    4049       rcItem.right = rcItem.left + nItemWidth;
    4050       LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem, FALSE, &FocusRect);
    4051       /*
    4052        * Draw Focus Rect
    4053        */
    4054       if (LISTVIEW_GetItemState(hwnd,nItem,LVIS_FOCUSED) && infoPtr->bFocus)
    4055       Rectangle(hdc, FocusRect.left, FocusRect.top,
    4056                 FocusRect.right,FocusRect.bottom);
    4057 
    4058       if (cditemmode & CDRF_NOTIFYPOSTPAINT)
    4059         LISTVIEW_SendCustomDrawItemNotify(hwnd, hdc, nItem, 0,
    4060                                           CDDS_ITEMPOSTPAINT);
    4061  
    4062     }
    4063   }
    4064 }
    4065 
    4066 /***
    4067  * DESCRIPTION:
    4068  * Draws listview items when in icon or small icon display mode.
    4069  *
    4070  * PARAMETER(S):
    4071  * [I] HWND : window handle
    4072  * [I] HDC : device context handle
    4073  *
    4074  * RETURN:
    4075  * None
    4076  */
    4077 static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc, BOOL bSmall, DWORD cdmode)
    4078 {
    4079   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    4080   POINT ptPosition;
    4081   POINT ptOrigin;
    4082   RECT rcItem, SuggestedFocus, rcTemp;
    4083   INT i;
    4084   DWORD cditemmode = CDRF_DODEFAULT;
    4085 
    4086   infoPtr->nColumnCount = 1; /* set this to an arbitrary value to prevent */
    4087                              /* DrawItem from erasing the incorrect background area */
    4088 
    4089   /* paint the background of the control that doesn't contain any items */
    4090   SubtractRect(&rcTemp, &infoPtr->rcList, &infoPtr->rcView);
    4091   LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
    4092 
    4093   /* nothing to draw, return here */
    4094   if(GETITEMCOUNT(infoPtr) == 0)
    4095     return;
    4096 
    4097   LISTVIEW_GetOrigin(hwnd, &ptOrigin);
    4098   for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
    4099   {
    4100     if (cdmode & CDRF_NOTIFYITEMDRAW)
    4101       cditemmode = LISTVIEW_SendCustomDrawItemNotify (hwnd, hdc, i, 0,
    4102                                                       CDDS_ITEMPREPAINT);
    4103     if (cditemmode & CDRF_SKIPDEFAULT)
    4104         continue;
    4105 
    4106     LISTVIEW_GetItemPosition(hwnd, i, &ptPosition);
    4107     ptPosition.x += ptOrigin.x;
    4108     ptPosition.y += ptOrigin.y;
    4109      
    4110     if (ptPosition.y + infoPtr->nItemHeight > infoPtr->rcList.top)
    4111     {
    4112       if (ptPosition.x + infoPtr->nItemWidth > infoPtr->rcList.left)
    4113       {
    4114         if (ptPosition.y < infoPtr->rcList.bottom)
    4115         {
    4116           if (ptPosition.x < infoPtr->rcList.right)
    4117           {
    4118             rcItem.top = ptPosition.y;
    4119             rcItem.left = ptPosition.x;
    4120             rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
    4121             rcItem.right = rcItem.left + infoPtr->nItemWidth;
    4122             if (bSmall)
    4123               LISTVIEW_DrawItem(hwnd, hdc, i, rcItem, FALSE, &SuggestedFocus);
    4124             else
    4125               LISTVIEW_DrawLargeItem(hwnd, hdc, i, rcItem, &SuggestedFocus);
    4126             /*
    4127              * Draw Focus Rect
    4128              */
    4129             if (LISTVIEW_GetItemState(hwnd,i,LVIS_FOCUSED) &&
    4130                 infoPtr->bFocus && !IsRectEmpty(&SuggestedFocus))
    4131               Rectangle(hdc, SuggestedFocus.left, SuggestedFocus.top,
    4132                         SuggestedFocus.right,SuggestedFocus.bottom);
    4133           }
    4134         }
    4135       }
    4136     }
    4137     if (cditemmode & CDRF_NOTIFYPOSTPAINT)
    4138         LISTVIEW_SendCustomDrawItemNotify(hwnd, hdc, i, 0,
    4139                                           CDDS_ITEMPOSTPAINT);
    4140   }
    4141 }
    4142 
    4143 /***
    4144  * DESCRIPTION:
    4145  * Draws listview items.
    4146  *
    4147  * PARAMETER(S):
    4148  * [I] HWND : window handle
    4149  * [I] HDC : device context handle
    4150  *
    4151  * RETURN:
    4152  * NoneX
    4153  */
    4154 static VOID LISTVIEW_Refresh(HWND hwnd, HDC hdc)
    4155 {
    4156   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    4157   UINT uView = GetWindowLongW(hwnd, GWL_STYLE) & LVS_TYPEMASK;
    4158   HFONT hOldFont;
    4159   HPEN hPen, hOldPen;
    4160   DWORD cdmode;
    4161   RECT rect;
    4162 
    4163 #ifdef __WIN32OS2__
    4164   if (infoPtr->internalFlags & IF_NOREDRAW) return;
    4165 #endif
    4166 
    4167   LISTVIEW_DumpListview (infoPtr, __LINE__);
    4168 
    4169   GetClientRect(hwnd, &rect);
    4170   cdmode = LISTVIEW_SendCustomDrawNotify(hwnd,CDDS_PREPAINT,hdc,rect);
    4171 
    4172   if (cdmode == CDRF_SKIPDEFAULT) return;
    4173 
    4174   /* select font */
    4175   hOldFont = SelectObject(hdc, infoPtr->hFont);
    4176 
    4177   /* select the dotted pen (for drawing the focus box) */
    4178   hPen = CreatePen(PS_ALTERNATE, 1, 0);
    4179   hOldPen = SelectObject(hdc, hPen);
    4180 
    4181   /* select transparent brush (for drawing the focus box) */
    4182   SelectObject(hdc, GetStockObject(NULL_BRUSH));
    4183 
    4184   if (uView == LVS_LIST)
    4185     LISTVIEW_RefreshList(hwnd, hdc, cdmode);
    4186   else if (uView == LVS_REPORT)
    4187     LISTVIEW_RefreshReport(hwnd, hdc, cdmode);
    4188   else if (uView == LVS_SMALLICON)
    4189     LISTVIEW_RefreshIcon(hwnd, hdc, TRUE, cdmode);
    4190   else if (uView == LVS_ICON)
    4191     LISTVIEW_RefreshIcon(hwnd, hdc, FALSE, cdmode);
    4192 
    4193   /* unselect objects */
    4194   SelectObject(hdc, hOldFont);
    4195   SelectObject(hdc, hOldPen);
    4196  
    4197   /* delete pen */
    4198   DeleteObject(hPen);
    4199  
    4200   if (cdmode & CDRF_NOTIFYPOSTPAINT)
    4201       LISTVIEW_SendCustomDrawNotify(hwnd, CDDS_POSTPAINT, hdc, rect);
     3890        if (uView == LVS_REPORT)
     3891            LISTVIEW_RefreshReport(infoPtr, &i, hdc, cdmode);
     3892        else /* LVS_LIST, LVS_ICON or LVS_SMALLICON */
     3893            LISTVIEW_RefreshList(infoPtr, &i, hdc, cdmode);
     3894
     3895        /* if we have a focus rect, draw it */
     3896        if (infoPtr->bFocus)
     3897            DrawFocusRect(hdc, &infoPtr->rcFocus);
     3898    }
     3899    iterator_destroy(&i);
     3900   
     3901enddraw:
     3902    if (cdmode & CDRF_NOTIFYPOSTPAINT)
     3903        notify_postpaint(infoPtr, &nmlvcd);
     3904
     3905    infoPtr->clrTextBk = oldClrTextBk;
     3906    infoPtr->clrText = oldClrText;
     3907
     3908    SelectObject(hdc, hOldFont);
     3909    SetBkMode(hdc, oldBkMode);
     3910    SetBkColor(hdc, infoPtr->clrTextBkDefault);
     3911    SetTextColor(hdc, oldTextColor);
     3912    infoPtr->bIsDrawing = FALSE;
    42023913}
    42033914
     
    42063917 * DESCRIPTION:
    42073918 * Calculates the approximate width and height of a given number of items.
    4208  * 
    4209  * PARAMETER(S):
    4210  * [I] HWND : window handle
    4211  * [I] INT : number of items
    4212  * [I] INT : width
    4213  * [I] INT : height
     3919 *
     3920 * PARAMETER(S):
     3921 * [I] infoPtr : valid pointer to the listview structure
     3922 * [I] nItemCount : number of items
     3923 * [I] wWidth : width
     3924 * [I] wHeight : height
    42143925 *
    42153926 * RETURN:
    42163927 * Returns a DWORD. The width in the low word and the height in high word.
    42173928 */
    4218 static LRESULT LISTVIEW_ApproximateViewRect(HWND hwnd, INT nItemCount,
     3929static DWORD LISTVIEW_ApproximateViewRect(LISTVIEW_INFO *infoPtr, INT nItemCount,
    42193930                                            WORD wWidth, WORD wHeight)
    42203931{
    4221   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    4222   UINT uView = GetWindowLongW(hwnd, GWL_STYLE) & LVS_TYPEMASK;
     3932  UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
    42233933  INT nItemCountPerColumn = 1;
    42243934  INT nColumnCount = 0;
     
    42263936
    42273937  if (nItemCount == -1)
    4228     nItemCount = GETITEMCOUNT(infoPtr);
     3938    nItemCount = infoPtr->nItemCount;
    42293939
    42303940  if (uView == LVS_LIST)
     
    42463956        if (nItemCountPerColumn == 0)
    42473957          nItemCountPerColumn = 1;
    4248        
     3958
    42493959        if (nItemCount % nItemCountPerColumn != 0)
    42503960          nColumnCount = nItemCount / nItemCountPerColumn;
     
    42613971  }
    42623972  else if (uView == LVS_REPORT)
    4263     FIXME("uView == LVS_REPORT: not implemented\n"); 
     3973    FIXME("uView == LVS_REPORT: not implemented\n");
    42643974  else if (uView == LVS_SMALLICON)
    4265     FIXME("uView == LVS_SMALLICON: not implemented\n"); 
     3975    FIXME("uView == LVS_SMALLICON: not implemented\n");
    42663976  else if (uView == LVS_ICON)
    4267     FIXME("uView == LVS_ICON: not implemented\n"); 
    4268  
     3977    FIXME("uView == LVS_ICON: not implemented\n");
     3978
    42693979  return dwViewRect;
    42703980}
    42713981
    4272 /***
    4273  * DESCRIPTION:
    4274  * Arranges listview items in icon display mode.
    4275  *
    4276  * PARAMETER(S):
    4277  * [I] HWND : window handle
    4278  * [I] INT : alignment code
     3982/* << LISTVIEW_CreateDragImage >> */
     3983
     3984
     3985/***
     3986 * DESCRIPTION:
     3987 * Removes all listview items and subitems.
     3988 *
     3989 * PARAMETER(S):
     3990 * [I] infoPtr : valid pointer to the listview structure
    42793991 *
    42803992 * RETURN:
     
    42823994 *   FAILURE : FALSE
    42833995 */
    4284 static LRESULT LISTVIEW_Arrange(HWND hwnd, INT nAlignCode)
    4285 {
    4286   UINT uView = GetWindowLongW(hwnd, GWL_STYLE) & LVS_TYPEMASK;
    4287   BOOL bResult = FALSE;
    4288 
    4289   if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
    4290   {
    4291     switch (nAlignCode)
    4292     {
    4293     case LVA_ALIGNLEFT:
    4294       FIXME("nAlignCode=LVA_ALIGNLEFT: not implemented\n");
    4295       break;
    4296     case LVA_ALIGNTOP:
    4297       FIXME("nAlignCode=LVA_ALIGNTOP: not implemented\n");
    4298       break;
    4299     case LVA_DEFAULT:
    4300       FIXME("nAlignCode=LVA_DEFAULT: not implemented\n");
    4301       break;
    4302     case LVA_SNAPTOGRID:
    4303       FIXME("nAlignCode=LVA_SNAPTOGRID: not implemented\n");
    4304       break;
    4305     }
    4306   }
    4307 
    4308   return bResult;
    4309 }
    4310 
    4311 /* << LISTVIEW_CreateDragImage >> */
    4312 
    4313 
    4314 /***
    4315  * DESCRIPTION:
    4316  * Removes all listview items and subitems.
    4317  *
    4318  * PARAMETER(S):
    4319  * [I] HWND : window handle
     3996static BOOL LISTVIEW_DeleteAllItems(LISTVIEW_INFO *infoPtr)
     3997{
     3998    NMLISTVIEW nmlv;
     3999    HDPA hdpaSubItems = NULL;
     4000    BOOL bSuppress;
     4001    ITEMHDR *hdrItem;
     4002    INT i, j;
     4003
     4004    TRACE("()\n");
     4005
     4006    /* we do it directly, to avoid notifications */
     4007    ranges_clear(infoPtr->selectionRanges);
     4008    infoPtr->nSelectionMark = -1;
     4009    infoPtr->nFocusedItem = -1;
     4010    SetRectEmpty(&infoPtr->rcFocus);
     4011    /* But we are supposed to leave nHotItem as is! */
     4012
     4013
     4014    /* send LVN_DELETEALLITEMS notification */
     4015    ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
     4016    nmlv.iItem = -1;
     4017    bSuppress = notify_listview(infoPtr, LVN_DELETEALLITEMS, &nmlv);
     4018
     4019    for (i = infoPtr->nItemCount - 1; i >= 0; i--)
     4020    {
     4021        /* send LVN_DELETEITEM notification, if not supressed */
     4022        if (!bSuppress) notify_deleteitem(infoPtr, i);
     4023        if (!(infoPtr->dwStyle & LVS_OWNERDATA))
     4024        {
     4025            hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
     4026            for (j = 0; j < hdpaSubItems->nItemCount; j++)
     4027            {
     4028                hdrItem = (ITEMHDR *)DPA_GetPtr(hdpaSubItems, j);
     4029                if (is_textW(hdrItem->pszText)) COMCTL32_Free(hdrItem->pszText);
     4030                COMCTL32_Free(hdrItem);
     4031            }
     4032            DPA_Destroy(hdpaSubItems);
     4033            DPA_DeletePtr(infoPtr->hdpaItems, i);
     4034        }
     4035        DPA_DeletePtr(infoPtr->hdpaPosX, i);
     4036        DPA_DeletePtr(infoPtr->hdpaPosY, i);
     4037        infoPtr->nItemCount --;
     4038    }
     4039   
     4040    LISTVIEW_UpdateScroll(infoPtr);
     4041
     4042    LISTVIEW_InvalidateList(infoPtr);
     4043   
     4044    return TRUE;
     4045}
     4046
     4047/***
     4048 * DESCRIPTION:
     4049 * Scrolls, and updates the columns, when a column is changing width.
     4050 *
     4051 * PARAMETER(S):
     4052 * [I] infoPtr : valid pointer to the listview structure
     4053 * [I] nColumn : column to scroll
     4054 * [I] dx : amount of scroll, in pixels
     4055 *
     4056 * RETURN:
     4057 *   None.
     4058 */
     4059static void LISTVIEW_ScrollColumns(LISTVIEW_INFO *infoPtr, INT nColumn, INT dx)
     4060{
     4061    COLUMN_INFO *lpColumnInfo;
     4062    RECT rcOld, rcCol;
     4063    INT nCol;
     4064   
     4065    lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, min(nColumn, infoPtr->hdpaColumns->nItemCount - 1));
     4066    rcCol = lpColumnInfo->rcHeader;
     4067    if (nColumn >= infoPtr->hdpaColumns->nItemCount)
     4068        rcCol.left = rcCol.right;
     4069   
     4070    /* ajust the other columns */
     4071    for (nCol = nColumn; nCol < infoPtr->hdpaColumns->nItemCount; nCol++)
     4072    {
     4073        lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, nCol);
     4074        lpColumnInfo->rcHeader.left += dx;
     4075        lpColumnInfo->rcHeader.right += dx;
     4076    }
     4077
     4078    /* do not update screen if not in report mode */
     4079    if (!is_redrawing(infoPtr) || (infoPtr->dwStyle & LVS_TYPEMASK) != LVS_REPORT) return;
     4080   
     4081    /* if we have a focus, must first erase the focus rect */
     4082    if (infoPtr->bFocus) LISTVIEW_ShowFocusRect(infoPtr, FALSE);
     4083   
     4084    /* Need to reset the item width when inserting a new column */
     4085    infoPtr->nItemWidth += dx;
     4086
     4087    LISTVIEW_UpdateScroll(infoPtr);
     4088
     4089    /* scroll to cover the deleted column, and invalidate for redraw */
     4090    rcOld = infoPtr->rcList;
     4091    rcOld.left = rcCol.left;
     4092    ScrollWindowEx(infoPtr->hwndSelf, dx, 0, &rcOld, &rcOld, 0, 0, SW_ERASE | SW_INVALIDATE);
     4093   
     4094    /* we can restore focus now */
     4095    if (infoPtr->bFocus) LISTVIEW_ShowFocusRect(infoPtr, TRUE);
     4096}
     4097
     4098/***
     4099 * DESCRIPTION:
     4100 * Removes a column from the listview control.
     4101 *
     4102 * PARAMETER(S):
     4103 * [I] infoPtr : valid pointer to the listview structure
     4104 * [I] nColumn : column index
    43204105 *
    43214106 * RETURN:
     
    43234108 *   FAILURE : FALSE
    43244109 */
    4325 static LRESULT LISTVIEW_DeleteAllItems(HWND hwnd)
    4326 {
    4327   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    4328   LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    4329   UINT uView = lStyle & LVS_TYPEMASK;
    4330   LISTVIEW_ITEM *lpItem;
    4331   LISTVIEW_SUBITEM *lpSubItem;
    4332   NMLISTVIEW nmlv;
    4333   BOOL bSuppress;
    4334   BOOL bResult = FALSE;
    4335   HDPA hdpaSubItems;
    4336 
    4337   TRACE("(hwnd=%x,)\n", hwnd);
    4338 
    4339   LISTVIEW_RemoveAllSelections(hwnd);
    4340   infoPtr->nSelectionMark=-1;
    4341   infoPtr->nFocusedItem=-1;
    4342   /* But we are supposed to leave nHotItem as is! */
    4343 
    4344   if (lStyle & LVS_OWNERDATA)
    4345   {
    4346     infoPtr->hdpaItems->nItemCount = 0;
    4347     InvalidateRect(hwnd, NULL, TRUE);
     4110static BOOL LISTVIEW_DeleteColumn(LISTVIEW_INFO *infoPtr, INT nColumn)
     4111{
     4112    RECT rcCol;
     4113   
     4114    TRACE("nColumn=%d\n", nColumn);
     4115
     4116    if (nColumn < 0 || infoPtr->hdpaColumns->nItemCount == 0
     4117           || nColumn >= infoPtr->hdpaColumns->nItemCount) return FALSE;
     4118
     4119    /* While the MSDN specifically says that column zero should not be deleted,
     4120       it does in fact work on WinNT, and at least one app depends on it. On
     4121       WinNT, deleting column zero deletes the last column of items but the
     4122       first header. Since no app will ever depend on that bizarre behavior,
     4123       we just delete the last column including the header.
     4124     */
     4125    if (nColumn == 0)
     4126        nColumn = infoPtr->hdpaColumns->nItemCount - 1;
     4127
     4128    LISTVIEW_GetHeaderRect(infoPtr, nColumn, &rcCol);
     4129   
     4130    if (!Header_DeleteItem(infoPtr->hwndHeader, nColumn))
     4131        return FALSE;
     4132
     4133    COMCTL32_Free(DPA_GetPtr(infoPtr->hdpaColumns, nColumn));
     4134    DPA_DeletePtr(infoPtr->hdpaColumns, nColumn);
     4135 
     4136    if (!(infoPtr->dwStyle & LVS_OWNERDATA))
     4137    {
     4138        SUBITEM_INFO *lpSubItem, *lpDelItem;
     4139        HDPA hdpaSubItems;
     4140        INT nItem, nSubItem, i;
     4141       
     4142        if (nColumn == 0)
     4143            return LISTVIEW_DeleteAllItems(infoPtr);
     4144           
     4145        for (nItem = 0; nItem < infoPtr->nItemCount; nItem++)
     4146        {
     4147            hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
     4148            nSubItem = 0;
     4149            lpDelItem = 0;
     4150            for (i = 1; i < hdpaSubItems->nItemCount; i++)
     4151            {
     4152                lpSubItem = (SUBITEM_INFO *)DPA_GetPtr(hdpaSubItems, i);
     4153                if (lpSubItem->iSubItem == nColumn)
     4154                {
     4155                    nSubItem = i;
     4156                    lpDelItem = lpSubItem;
     4157                }
     4158                else if (lpSubItem->iSubItem > nColumn)
     4159                {
     4160                    lpSubItem->iSubItem--;
     4161                }
     4162            }
     4163
     4164            /* if we found our subitem, zapp it */     
     4165            if (nSubItem > 0)
     4166            {
     4167                /* free string */
     4168                if (is_textW(lpDelItem->hdr.pszText))
     4169                    COMCTL32_Free(lpDelItem->hdr.pszText);
     4170
     4171                /* free item */
     4172                COMCTL32_Free(lpDelItem);
     4173
     4174                /* free dpa memory */
     4175                DPA_DeletePtr(hdpaSubItems, nSubItem);
     4176            }
     4177        }
     4178    }
     4179
     4180    /* update the other column info */
     4181    LISTVIEW_ScrollColumns(infoPtr, nColumn, -(rcCol.right - rcCol.left));
     4182
    43484183    return TRUE;
    4349   }
    4350 
    4351   if (GETITEMCOUNT(infoPtr) > 0)
    4352   {
    4353     INT i, j;
    4354    
    4355     /* send LVN_DELETEALLITEMS notification */
    4356     /* verify if subsequent LVN_DELETEITEM notifications should be
    4357        suppressed */
    4358     ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
    4359     nmlv.iItem = -1;
    4360     bSuppress = listview_notify(hwnd, LVN_DELETEALLITEMS, &nmlv);
    4361 
    4362     for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
    4363     {
    4364       hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
    4365       if (hdpaSubItems != NULL)
    4366       {
    4367         for (j = 1; j < hdpaSubItems->nItemCount; j++)
    4368         {
    4369           lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, j);
    4370           if (lpSubItem != NULL)
    4371           {
    4372             /* free subitem string */
    4373             if (is_textW(lpSubItem->pszText))
    4374               COMCTL32_Free(lpSubItem->pszText);
    4375        
    4376             /* free subitem */
    4377             COMCTL32_Free(lpSubItem);
    4378           }   
    4379         }
    4380 
    4381         lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
    4382         if (lpItem != NULL)
    4383         {
    4384           if (!bSuppress)
    4385           {
    4386             /* send LVN_DELETEITEM notification */
    4387             nmlv.iItem = i;
    4388             nmlv.lParam = lpItem->lParam;
    4389             listview_notify(hwnd, LVN_DELETEITEM, &nmlv);
    4390           }
    4391 
    4392           /* free item string */
    4393           if (is_textW(lpItem->pszText))
    4394             COMCTL32_Free(lpItem->pszText);
    4395      
    4396           /* free item */
    4397           COMCTL32_Free(lpItem);
    4398         }
    4399        
    4400         DPA_Destroy(hdpaSubItems);
    4401       }
    4402     }
    4403 
    4404     /* reinitialize listview memory */
    4405     bResult = DPA_DeleteAllPtrs(infoPtr->hdpaItems);
    4406    
    4407     /* align items (set position of each item) */
    4408     if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
    4409     {
    4410       if (lStyle & LVS_ALIGNLEFT)
    4411       {
    4412         LISTVIEW_AlignLeft(hwnd);
    4413       }
    4414       else
    4415       {
    4416         LISTVIEW_AlignTop(hwnd);
    4417       }
    4418     }
    4419    
    4420     LISTVIEW_UpdateScroll(hwnd);
    4421 
    4422     /* invalidate client area (optimization needed) */
    4423     InvalidateRect(hwnd, NULL, TRUE);
    4424   }
    4425  
    4426   return bResult;
    4427 }
    4428 
    4429 /***
    4430  * DESCRIPTION:
    4431  * Removes a column from the listview control.
    4432  *
    4433  * PARAMETER(S):
    4434  * [I] HWND : window handle
    4435  * [I] INT : column index
     4184}
     4185
     4186/***
     4187 * DESCRIPTION:
     4188 * Invalidates the listview after an item's insertion or deletion.
     4189 *
     4190 * PARAMETER(S):
     4191 * [I] infoPtr : valid pointer to the listview structure
     4192 * [I] nItem : item index
     4193 * [I] dir : -1 if deleting, 1 if inserting
     4194 *
     4195 * RETURN:
     4196 *   None
     4197 */
     4198static void LISTVIEW_ScrollOnInsert(LISTVIEW_INFO *infoPtr, INT nItem, INT dir)
     4199{
     4200    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     4201    INT nPerCol, nItemCol, nItemRow;
     4202    RECT rcScroll;
     4203    POINT Origin;
     4204
     4205    /* if we don't refresh, what's the point of scrolling? */
     4206    if (!is_redrawing(infoPtr)) return;
     4207   
     4208    assert (abs(dir) == 1);
     4209
     4210    /* arrange icons if autoarrange is on */
     4211    if (is_autoarrange(infoPtr))
     4212    {
     4213        BOOL arrange = TRUE;
     4214        if (dir < 0 && nItem >= infoPtr->nItemCount) arrange = FALSE;
     4215        if (dir > 0 && nItem == infoPtr->nItemCount - 1) arrange = FALSE;
     4216        if (arrange) LISTVIEW_Arrange(infoPtr, LVA_DEFAULT);
     4217    }
     4218
     4219    /* scrollbars need updating */
     4220    LISTVIEW_UpdateScroll(infoPtr);
     4221
     4222    /* figure out the item's position */
     4223    if (uView == LVS_REPORT)
     4224        nPerCol = infoPtr->nItemCount + 1;
     4225    else if (uView == LVS_LIST)
     4226        nPerCol = LISTVIEW_GetCountPerColumn(infoPtr);
     4227    else /* LVS_ICON, or LVS_SMALLICON */
     4228        return;
     4229   
     4230    nItemCol = nItem / nPerCol;
     4231    nItemRow = nItem % nPerCol;
     4232    LISTVIEW_GetOrigin(infoPtr, &Origin);
     4233
     4234    /* move the items below up a slot */
     4235    rcScroll.left = nItemCol * infoPtr->nItemWidth;
     4236    rcScroll.top = nItemRow * infoPtr->nItemHeight;
     4237    rcScroll.right = rcScroll.left + infoPtr->nItemWidth;
     4238    rcScroll.bottom = nPerCol * infoPtr->nItemHeight;
     4239    OffsetRect(&rcScroll, Origin.x, Origin.y);
     4240    TRACE("rcScroll=%s, dx=%d\n", debugrect(&rcScroll), dir * infoPtr->nItemHeight);
     4241    if (IntersectRect(&rcScroll, &rcScroll, &infoPtr->rcList))
     4242    {
     4243        TRACE("Scrolling rcScroll=%s, rcList=%s\n", debugrect(&rcScroll), debugrect(&infoPtr->rcList));
     4244        ScrollWindowEx(infoPtr->hwndSelf, 0, dir * infoPtr->nItemHeight,
     4245                       &rcScroll, &rcScroll, 0, 0, SW_ERASE | SW_INVALIDATE);
     4246    }
     4247
     4248    /* report has only that column, so we're done */
     4249    if (uView == LVS_REPORT) return;
     4250
     4251    /* now for LISTs, we have to deal with the columns to the right */
     4252    rcScroll.left = (nItemCol + 1) * infoPtr->nItemWidth;
     4253    rcScroll.top = 0;
     4254    rcScroll.right = (infoPtr->nItemCount / nPerCol + 1) * infoPtr->nItemWidth;
     4255    rcScroll.bottom = nPerCol * infoPtr->nItemHeight;
     4256    OffsetRect(&rcScroll, Origin.x, Origin.y);
     4257    if (IntersectRect(&rcScroll, &rcScroll, &infoPtr->rcList))
     4258        ScrollWindowEx(infoPtr->hwndSelf, 0, dir * infoPtr->nItemHeight,
     4259                       &rcScroll, &rcScroll, 0, 0, SW_ERASE | SW_INVALIDATE);
     4260}
     4261
     4262/***
     4263 * DESCRIPTION:
     4264 * Removes an item from the listview control.
     4265 *
     4266 * PARAMETER(S):
     4267 * [I] infoPtr : valid pointer to the listview structure
     4268 * [I] nItem : item index
    44364269 *
    44374270 * RETURN:
     
    44394272 *   FAILURE : FALSE
    44404273 */
    4441 static LRESULT LISTVIEW_DeleteColumn(HWND hwnd, INT nColumn)
    4442 {
    4443   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    4444   UINT uView = GetWindowLongW(hwnd, GWL_STYLE) & LVS_TYPEMASK;
    4445   UINT uOwnerData = GetWindowLongW(hwnd, GWL_STYLE) & LVS_OWNERDATA;
    4446   BOOL bResult = FALSE;
    4447 
    4448   if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) != FALSE)
    4449   {
    4450     if (!uOwnerData)
    4451       bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
    4452 
    4453     /* Need to reset the item width when deleting a column */
    4454     infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
    4455 
    4456     /* reset scroll parameters */
    4457     if (uView == LVS_REPORT)
    4458     {
    4459       /* update scrollbar(s) */
    4460       LISTVIEW_UpdateScroll(hwnd);
    4461 
    4462       /* refresh client area */
    4463       InvalidateRect(hwnd, NULL, FALSE);
    4464     }
    4465   }
    4466 
    4467   return bResult;
    4468 }
    4469 
    4470 /***
    4471  * DESCRIPTION:
    4472  * Removes an item from the listview control.
    4473  *
    4474  * PARAMETER(S):
    4475  * [I] HWND : window handle
    4476  * [I] INT : item index 
     4274static BOOL LISTVIEW_DeleteItem(LISTVIEW_INFO *infoPtr, INT nItem)
     4275{
     4276    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     4277    LVITEMW item;
     4278
     4279    TRACE("(nItem=%d)\n", nItem);
     4280
     4281    if (nItem < 0 || nItem >= infoPtr->nItemCount) return FALSE;
     4282   
     4283    /* remove selection, and focus */
     4284    item.state = 0;
     4285    item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
     4286    LISTVIEW_SetItemState(infoPtr, nItem, &item);
     4287           
     4288    /* send LVN_DELETEITEM notification. */
     4289    notify_deleteitem(infoPtr, nItem);
     4290
     4291    /* we need to do this here, because we'll be deleting stuff */ 
     4292    if (uView == LVS_SMALLICON || uView == LVS_ICON)
     4293        LISTVIEW_InvalidateItem(infoPtr, nItem);
     4294   
     4295    if (!(infoPtr->dwStyle & LVS_OWNERDATA))
     4296    {
     4297        HDPA hdpaSubItems;
     4298        ITEMHDR *hdrItem;
     4299        INT i;
     4300
     4301        hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem); 
     4302        for (i = 0; i < hdpaSubItems->nItemCount; i++)
     4303        {
     4304            hdrItem = (ITEMHDR *)DPA_GetPtr(hdpaSubItems, i);
     4305            if (is_textW(hdrItem->pszText)) COMCTL32_Free(hdrItem->pszText);
     4306            COMCTL32_Free(hdrItem);
     4307        }
     4308        DPA_Destroy(hdpaSubItems);
     4309    }
     4310
     4311    if (uView == LVS_SMALLICON || uView == LVS_ICON)
     4312    {
     4313        DPA_DeletePtr(infoPtr->hdpaPosX, nItem);
     4314        DPA_DeletePtr(infoPtr->hdpaPosY, nItem);
     4315    }
     4316
     4317    infoPtr->nItemCount--;
     4318    LISTVIEW_ShiftIndices(infoPtr, nItem, -1);
     4319
     4320    /* now is the invalidation fun */
     4321    LISTVIEW_ScrollOnInsert(infoPtr, nItem, -1);
     4322    return TRUE;
     4323}
     4324
     4325
     4326/***
     4327 * DESCRIPTION:
     4328 * Callback implementation for editlabel control
     4329 *
     4330 * PARAMETER(S):
     4331 * [I] infoPtr : valid pointer to the listview structure
     4332 * [I] pszText : modified text
     4333 * [I] isW : TRUE if psxText is Unicode, FALSE if it's ANSI
    44774334 *
    44784335 * RETURN:
     
    44804337 *   FAILURE : FALSE
    44814338 */
    4482 static LRESULT LISTVIEW_DeleteItem(HWND hwnd, INT nItem)
    4483 {
    4484   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    4485   LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    4486   UINT uView = lStyle & LVS_TYPEMASK;
    4487   LONG lCtrlId = GetWindowLongW(hwnd, GWL_ID);
    4488   NMLISTVIEW nmlv;
    4489   BOOL bResult = FALSE;
    4490   HDPA hdpaSubItems;
    4491   LISTVIEW_ITEM *lpItem;
    4492   LISTVIEW_SUBITEM *lpSubItem;
    4493   INT i;
    4494   LVITEMW item;
    4495 
    4496   TRACE("(hwnd=%x, nItem=%d)\n", hwnd, nItem);
    4497  
    4498  
    4499   /* First, send LVN_DELETEITEM notification. */
    4500   memset(&nmlv, 0, sizeof (NMLISTVIEW));
    4501   nmlv.hdr.hwndFrom = hwnd;
    4502   nmlv.hdr.idFrom = lCtrlId;
    4503   nmlv.hdr.code = LVN_DELETEITEM;
    4504   nmlv.iItem = nItem;
    4505   SendMessageW(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId,
    4506                (LPARAM)&nmlv);
    4507 
    4508 
    4509   /* remove it from the selection range */
    4510   ZeroMemory(&item,sizeof(item));
    4511   item.stateMask = LVIS_SELECTED;
    4512   LISTVIEW_SetItemState(hwnd,nItem,&item);
    4513 
    4514   if (lStyle & LVS_OWNERDATA)
    4515   {
    4516     infoPtr->hdpaItems->nItemCount --;
    4517     InvalidateRect(hwnd, NULL, TRUE);
    4518     return TRUE;
    4519   }
    4520 
    4521   if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
    4522   {
    4523     /* initialize memory */
    4524     ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
    4525 
    4526     hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem);
    4527     if (hdpaSubItems != NULL)
    4528     {
    4529       for (i = 1; i < hdpaSubItems->nItemCount; i++)
    4530       {
    4531         lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
    4532         if (lpSubItem != NULL)
    4533         {
    4534           /* free item string */
    4535           if (is_textW(lpSubItem->pszText))
    4536             COMCTL32_Free(lpSubItem->pszText);
    4537        
    4538           /* free item */
    4539           COMCTL32_Free(lpSubItem);
    4540         }   
    4541       }
    4542  
    4543       lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
    4544       if (lpItem != NULL)
    4545       {
    4546         /* free item string */
    4547         if (is_textW(lpItem->pszText))
    4548           COMCTL32_Free(lpItem->pszText);
    4549      
    4550         /* free item */
    4551         COMCTL32_Free(lpItem);
    4552       }
    4553    
    4554       bResult = DPA_Destroy(hdpaSubItems);
    4555     }
    4556 
    4557     LISTVIEW_ShiftIndices(hwnd,nItem,-1);
    4558 
    4559     /* align items (set position of each item) */
    4560     if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
    4561     {
    4562       if (lStyle & LVS_ALIGNLEFT)
    4563         LISTVIEW_AlignLeft(hwnd);
    4564       else
    4565         LISTVIEW_AlignTop(hwnd);
    4566     }
    4567 
    4568     LISTVIEW_UpdateScroll(hwnd);
    4569 
    4570     /* refresh client area */
    4571     InvalidateRect(hwnd, NULL, TRUE);
    4572   }
    4573  
    4574   return bResult;
    4575 }
    4576 
    4577 
    4578 /***
    4579  * DESCRIPTION:
    4580  * Return edit control handle of current edit label
    4581  *
    4582  * PARAMETER(S):
    4583  * [I] HWND : window handle
    4584  *
    4585  * RETURN:
    4586  *   SUCCESS : HWND
    4587  *   FAILURE : 0
    4588  */
    4589 static LRESULT LISTVIEW_GetEditControl(HWND hwnd)
    4590 {
    4591   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    4592   return infoPtr->hwndEdit;
    4593 }
    4594 
    4595 
    4596 /***
    4597  * DESCRIPTION:
    4598  * Callback implementation for editlabel control
    4599  *
    4600  * PARAMETER(S):
    4601  * [I] HWND : window handle
    4602  * [I] LPSTR : modified text
    4603  * [I] DWORD : item index
    4604  * [I] isW : TRUE if psxText is Unicode, FALSE if it's ANSI
     4339static BOOL LISTVIEW_EndEditLabelT(LISTVIEW_INFO *infoPtr, LPWSTR pszText, BOOL isW)
     4340{
     4341    NMLVDISPINFOW dispInfo;
     4342
     4343    TRACE("(pszText=%s, isW=%d)\n", debugtext_t(pszText, isW), isW);
     4344
     4345    ZeroMemory(&dispInfo, sizeof(dispInfo));
     4346    dispInfo.item.mask = LVIF_PARAM | LVIF_STATE;
     4347    dispInfo.item.iItem = infoPtr->nEditLabelItem;
     4348    dispInfo.item.iSubItem = 0;
     4349    dispInfo.item.stateMask = ~0;
     4350    if (!LISTVIEW_GetItemW(infoPtr, &dispInfo.item)) return FALSE;
     4351    /* add the text from the edit in */
     4352    dispInfo.item.mask |= LVIF_TEXT;
     4353    dispInfo.item.pszText = pszText;
     4354    dispInfo.item.cchTextMax = textlenT(pszText, isW);
     4355
     4356    /* Do we need to update the Item Text */
     4357    if (!notify_dispinfoT(infoPtr, LVN_ENDLABELEDITW, &dispInfo, isW)) return FALSE;
     4358    if (!pszText) return TRUE;
     4359
     4360    ZeroMemory(&dispInfo, sizeof(dispInfo));
     4361    dispInfo.item.mask = LVIF_TEXT;
     4362    dispInfo.item.iItem = infoPtr->nEditLabelItem;
     4363    dispInfo.item.iSubItem = 0;
     4364    dispInfo.item.pszText = pszText;
     4365    dispInfo.item.cchTextMax = textlenT(pszText, isW);
     4366    return LISTVIEW_SetItemT(infoPtr, &dispInfo.item, isW);
     4367}
     4368
     4369/***
     4370 * DESCRIPTION:
     4371 * Begin in place editing of specified list view item
     4372 *
     4373 * PARAMETER(S):
     4374 * [I] infoPtr : valid pointer to the listview structure
     4375 * [I] nItem : item index
     4376 * [I] isW : TRUE if it's a Unicode req, FALSE if ASCII
    46054377 *
    46064378 * RETURN:
     
    46084380 *   FAILURE : FALSE
    46094381 */
    4610 static BOOL LISTVIEW_EndEditLabelT(HWND hwnd, LPWSTR pszText, DWORD nItem, BOOL isW)
    4611 {
    4612   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    4613   LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    4614   NMLVDISPINFOW dispInfo;
    4615   LISTVIEW_ITEM *lpItem;
    4616   HDPA hdpaSubItems;
    4617   LISTVIEW_ITEM lvItemRef;
    4618   LVITEMW item;
    4619   BOOL bResult = TRUE;
    4620 
    4621   TRACE("(hwnd=%x, pszText=%s, nItem=%ld, isW=%d)\n", hwnd, debugstr_t(pszText, isW), nItem, isW);
    4622  
    4623   if (!(lStyle & LVS_OWNERDATA))
    4624   {
    4625     if (!(hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
    4626           return FALSE;
    4627 
    4628     if (!(lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
    4629           return FALSE;
    4630   }
    4631   else
    4632   {
    4633     ZeroMemory(&lvItemRef,sizeof(LISTVIEW_ITEM));
    4634     ZeroMemory(&item,sizeof(item));
    4635     item.iItem = nItem;
    4636     item.iSubItem = 0;
    4637     item.mask = LVIF_PARAM | LVIF_STATE;
    4638     ListView_GetItemW(hwnd, &item);
    4639     lvItemRef.state = item.state;
    4640     lvItemRef.iImage = item.iImage;
    4641     lvItemRef.lParam = item.lParam;
    4642     lpItem = &lvItemRef;
    4643   }
    4644 
    4645   ZeroMemory(&dispInfo, sizeof(dispInfo));
    4646   dispInfo.item.mask = 0;
    4647   dispInfo.item.iItem = nItem;
    4648   dispInfo.item.state = lpItem->state;
    4649   dispInfo.item.stateMask = 0;
    4650   dispInfo.item.pszText = pszText;
    4651   dispInfo.item.cchTextMax = textlenT(pszText, isW);
    4652   dispInfo.item.iImage = lpItem->iImage;
    4653   dispInfo.item.lParam = lpItem->lParam;
    4654   infoPtr->hwndEdit = 0;
    4655 
    4656   /* Do we need to update the Item Text */
    4657   if(dispinfo_notifyT(hwnd, LVN_ENDLABELEDITW, &dispInfo, isW))
    4658     if (lpItem->pszText != LPSTR_TEXTCALLBACKW && !(lStyle & LVS_OWNERDATA))
    4659       bResult = textsetptrT(&lpItem->pszText, pszText, isW);
    4660  
    4661   return bResult;
    4662 }
    4663 
    4664 /***
    4665  * DESCRIPTION:
    4666  * Callback implementation for editlabel control
    4667  *
    4668  * PARAMETER(S):
    4669  * [I] HWND : window handle
    4670  * [I] LPSTR : modified text
    4671  * [I] DWORD : item index
     4382static HWND LISTVIEW_EditLabelT(LISTVIEW_INFO *infoPtr, INT nItem, BOOL isW)
     4383{
     4384    WCHAR szDispText[DISP_TEXT_SIZE] = { 0 };
     4385    NMLVDISPINFOW dispInfo;
     4386    RECT rect;
     4387
     4388    TRACE("(nItem=%d, isW=%d)\n", nItem, isW);
     4389
     4390    if (~infoPtr->dwStyle & LVS_EDITLABELS) return 0;
     4391    if (nItem < 0 || nItem >= infoPtr->nItemCount) return 0;
     4392
     4393    infoPtr->nEditLabelItem = nItem;
     4394
     4395    /* Is the EditBox still there, if so remove it */
     4396    if(infoPtr->hwndEdit != 0)
     4397    {
     4398        SetFocus(infoPtr->hwndSelf);
     4399        infoPtr->hwndEdit = 0;
     4400    }
     4401
     4402    LISTVIEW_SetSelection(infoPtr, nItem);
     4403    LISTVIEW_SetItemFocus(infoPtr, nItem);
     4404    LISTVIEW_InvalidateItem(infoPtr, nItem);
     4405
     4406    rect.left = LVIR_LABEL;
     4407    if (!LISTVIEW_GetItemRect(infoPtr, nItem, &rect)) return 0;
     4408   
     4409    ZeroMemory(&dispInfo, sizeof(dispInfo));
     4410    dispInfo.item.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT;
     4411    dispInfo.item.iItem = nItem;
     4412    dispInfo.item.iSubItem = 0;
     4413    dispInfo.item.stateMask = ~0;
     4414    dispInfo.item.pszText = szDispText;
     4415    dispInfo.item.cchTextMax = DISP_TEXT_SIZE;
     4416    if (!LISTVIEW_GetItemT(infoPtr, &dispInfo.item, isW)) return 0;
     4417
     4418    infoPtr->hwndEdit = CreateEditLabelT(infoPtr, dispInfo.item.pszText, WS_VISIBLE,
     4419                    rect.left-2, rect.top-1, 0, rect.bottom - rect.top+2, isW);
     4420    if (!infoPtr->hwndEdit) return 0;
     4421   
     4422    if (notify_dispinfoT(infoPtr, LVN_BEGINLABELEDITW, &dispInfo, isW))
     4423    {
     4424        SendMessageW(infoPtr->hwndEdit, WM_CLOSE, 0, 0);
     4425        infoPtr->hwndEdit = 0;
     4426        return 0;
     4427    }
     4428
     4429    ShowWindow(infoPtr->hwndEdit, SW_NORMAL);
     4430    SetFocus(infoPtr->hwndEdit);
     4431    SendMessageW(infoPtr->hwndEdit, EM_SETSEL, 0, -1);
     4432    return infoPtr->hwndEdit;
     4433}
     4434
     4435
     4436/***
     4437 * DESCRIPTION:
     4438 * Ensures the specified item is visible, scrolling into view if necessary.
     4439 *
     4440 * PARAMETER(S):
     4441 * [I] infoPtr : valid pointer to the listview structure
     4442 * [I] nItem : item index
     4443 * [I] bPartial : partially or entirely visible
    46724444 *
    46734445 * RETURN:
     
    46754447 *   FAILURE : FALSE
    46764448 */
    4677 static BOOL LISTVIEW_EndEditLabelW(HWND hwnd, LPWSTR pszText, DWORD nItem)
    4678 {
    4679     return LISTVIEW_EndEditLabelT(hwnd, pszText, nItem, TRUE);
    4680 }
    4681 
    4682 /***
    4683  * DESCRIPTION:
    4684  * Callback implementation for editlabel control
    4685  *
    4686  * PARAMETER(S):
    4687  * [I] HWND : window handle
    4688  * [I] LPSTR : modified text
    4689  * [I] DWORD : item index
    4690  *
    4691  * RETURN:
    4692  *   SUCCESS : TRUE
    4693  *   FAILURE : FALSE
    4694  */
    4695 static BOOL LISTVIEW_EndEditLabelA(HWND hwnd, LPSTR pszText, DWORD nItem)
    4696 {
    4697     return LISTVIEW_EndEditLabelT(hwnd, (LPWSTR)pszText, nItem, FALSE);
    4698 }
    4699 
    4700 /***
    4701  * DESCRIPTION:
    4702  * Begin in place editing of specified list view item
    4703  *
    4704  * PARAMETER(S):
    4705  * [I] HWND : window handle
    4706  * [I] INT : item index
    4707  * [I] isW : TRUE if it's a Unicode req, FALSE if ASCII
    4708  *
    4709  * RETURN:
    4710  *   SUCCESS : TRUE
    4711  *   FAILURE : FALSE
    4712  */
    4713 static HWND LISTVIEW_EditLabelT(HWND hwnd, INT nItem, BOOL isW)
    4714 {
    4715   NMLVDISPINFOW dispInfo;
    4716   RECT rect;
    4717   LISTVIEW_ITEM *lpItem;
    4718   HWND hedit;
    4719   HINSTANCE hinst = GetWindowLongW(hwnd, GWL_HINSTANCE);
    4720   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    4721   HDPA hdpaSubItems;
    4722   WCHAR szDispText[DISP_TEXT_SIZE];
    4723   LVITEMW lvItem;
    4724   LISTVIEW_ITEM lvItemRef;
    4725   LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    4726  
    4727   if (~GetWindowLongW(hwnd, GWL_STYLE) & LVS_EDITLABELS)
    4728       return FALSE;
    4729 
    4730   /* Is the EditBox still there, if so remove it */
    4731   if(infoPtr->hwndEdit != 0)
    4732       SetFocus(hwnd);
    4733 
    4734   LISTVIEW_SetSelection(hwnd, nItem);
    4735   LISTVIEW_SetItemFocus(hwnd, nItem);
    4736 
    4737   if (!(lStyle & LVS_OWNERDATA))
    4738   {
    4739     if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
    4740           return 0;
    4741 
    4742     if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
    4743           return 0;
    4744   }
    4745   else
    4746   {
    4747     LVITEMW item;
    4748     ZeroMemory(&lvItemRef,sizeof(LISTVIEW_ITEM));
    4749     ZeroMemory(&item, sizeof(item));
    4750     item.iItem = nItem;
    4751     item.iSubItem = 0;
    4752     item.mask = LVIF_PARAM | LVIF_STATE;
    4753     ListView_GetItemW(hwnd, &item);
    4754     lvItemRef.iImage = item.iImage;
    4755     lvItemRef.state = item.state;
    4756     lvItemRef.lParam = item.lParam;
    4757     lpItem = &lvItemRef;
    4758   }
    4759 
    4760   /* get information needed for drawing the item */
    4761   ZeroMemory(&lvItem, sizeof(lvItem));
    4762   lvItem.mask = LVIF_TEXT;
    4763   lvItem.iItem = nItem;
    4764   lvItem.iSubItem = 0;
    4765   lvItem.cchTextMax = DISP_TEXT_SIZE;
    4766   lvItem.pszText = szDispText;
    4767   *lvItem.pszText = '\0';
    4768   LISTVIEW_GetItemT(hwnd, &lvItem, FALSE, isW);
    4769 
    4770   ZeroMemory(&dispInfo, sizeof(dispInfo));
    4771   dispInfo.item.mask = 0;
    4772   dispInfo.item.iItem = nItem;
    4773   dispInfo.item.state = lpItem->state;
    4774   dispInfo.item.stateMask = 0;
    4775   dispInfo.item.pszText = lvItem.pszText;
    4776   dispInfo.item.cchTextMax = lstrlenW(lvItem.pszText);
    4777   dispInfo.item.iImage = lpItem->iImage;
    4778   dispInfo.item.lParam = lpItem->lParam;
    4779 
    4780   if (dispinfo_notifyT(hwnd, LVN_BEGINLABELEDITW, &dispInfo, isW))
    4781           return 0;
    4782 
    4783   rect.left = LVIR_LABEL;
    4784   if (!LISTVIEW_GetItemRect(hwnd, nItem, &rect))
    4785           return 0;
    4786  
    4787   if (!(hedit = CreateEditLabelT(szDispText , WS_VISIBLE,
    4788                  rect.left-2, rect.top-1, 0, rect.bottom - rect.top+2, hwnd, hinst,
    4789                  isW ? LISTVIEW_EndEditLabelW : (EditlblCallbackW)LISTVIEW_EndEditLabelA,
    4790                  nItem, isW)))
    4791          return 0;
    4792 
    4793   infoPtr->hwndEdit = hedit;
    4794   SetFocus(hedit);
    4795   SendMessageW(hedit, EM_SETSEL, 0, -1);
    4796 
    4797   return hedit;
    4798 }
    4799 
    4800 
    4801 /***
    4802  * DESCRIPTION:
    4803  * Ensures the specified item is visible, scrolling into view if necessary.
    4804  *
    4805  * PARAMETER(S):
    4806  * [I] HWND : window handle
    4807  * [I] INT : item index
    4808  * [I] BOOL : partially or entirely visible
    4809  *
    4810  * RETURN:
    4811  *   SUCCESS : TRUE
    4812  *   FAILURE : FALSE
    4813  */
    4814 #ifdef __WIN32OS2__
    4815 static VOID LISTVIEW_ScrollWindow(HWND hwnd,INT xScroll,INT yScroll);
    4816 
    4817 static BOOL LISTVIEW_EnsureVisible(HWND hwnd,INT nItem,BOOL bPartialOk)
    4818 {
    4819   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
    4820   DWORD dwStyle = GetWindowLongA(hwnd, GWL_STYLE);
    4821   UINT uView = dwStyle & LVS_TYPEMASK;
    4822   INT nScrollPosHeight = 0;
    4823   INT nScrollPosWidth = 0;
    4824   RECT rcItem;
    4825   POINT oldlefttop = infoPtr->lefttop;
    4826 
    4827   rcItem.left = LVIR_BOUNDS;
    4828   if (LISTVIEW_GetItemRect(hwnd, nItem, &rcItem))
    4829   {
    4830     if (bPartialOk && IntersectRect(NULL,&rcItem,&infoPtr->rcList))
    4831       return TRUE;
    4832 
    4833     if (rcItem.left < infoPtr->rcList.left)
    4834     {
    4835       if (dwStyle & WS_HSCROLL)
    4836       {
    4837         /* scroll left */
     4449static BOOL LISTVIEW_EnsureVisible(LISTVIEW_INFO *infoPtr, INT nItem, BOOL bPartial)
     4450{
     4451    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     4452    INT nScrollPosHeight = 0;
     4453    INT nScrollPosWidth = 0;
     4454    INT nHorzAdjust = 0;
     4455    INT nVertAdjust = 0;
     4456    INT nHorzDiff = 0;
     4457    INT nVertDiff = 0;
     4458    RECT rcItem, rcTemp;
     4459
     4460    rcItem.left = LVIR_BOUNDS;
     4461    if (!LISTVIEW_GetItemRect(infoPtr, nItem, &rcItem)) return FALSE;
     4462
     4463    if (bPartial && IntersectRect(&rcTemp, &infoPtr->rcList, &rcItem)) return TRUE;
     4464   
     4465    if (rcItem.left < infoPtr->rcList.left || rcItem.right > infoPtr->rcList.right)
     4466    {
     4467        /* scroll left/right, but in LVS_REPORT mode */
    48384468        if (uView == LVS_LIST)
    4839         {
    4840           nScrollPosWidth = infoPtr->scrollStep.x;
    4841           rcItem.left += infoPtr->rcList.left;
    4842         } else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
    4843         {
    4844           nScrollPosWidth = infoPtr->scrollStep.x;
    4845           rcItem.left += infoPtr->rcList.left;
    4846         }
    4847 
    4848         /* When in LVS_REPORT view, the scroll position should
    4849            not be updated. */
    4850         if (nScrollPosWidth)
    4851         {
    4852           if (rcItem.left % nScrollPosWidth == 0)
    4853             infoPtr->lefttop.x += rcItem.left / nScrollPosWidth;
    4854           else
    4855             infoPtr->lefttop.x += rcItem.left / nScrollPosWidth - 1;
    4856 
    4857           if (infoPtr->lefttop.x != oldlefttop.x)
    4858           {
    4859             SCROLLINFO scrollInfo;
    4860 
    4861             ZeroMemory(&scrollInfo,sizeof(SCROLLINFO));
    4862             scrollInfo.cbSize = sizeof(SCROLLINFO);
    4863             scrollInfo.fMask  = SIF_POS;
    4864             scrollInfo.nPos = infoPtr->lefttop.x;
    4865             SetScrollInfo(hwnd,SB_HORZ,&scrollInfo,TRUE);
    4866           }
    4867         }
    4868       }
    4869     } else if (rcItem.right > infoPtr->rcList.right)
    4870     {
    4871       if (dwStyle & WS_HSCROLL)
    4872       {
    4873         /* scroll right */
    4874         if (uView == LVS_LIST)
    4875         {
    4876           rcItem.right -= infoPtr->rcList.right;
    4877           nScrollPosWidth = infoPtr->scrollStep.x;
    4878         } else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
    4879         {
    4880           rcItem.right -= infoPtr->rcList.right;
    4881           nScrollPosWidth = infoPtr->scrollStep.x;
    4882         }
    4883 
    4884         /* When in LVS_REPORT view, the scroll position should
    4885            not be updated. */
    4886         if (nScrollPosWidth)
    4887         {
    4888           SCROLLINFO scrollInfo;
    4889 
    4890           if (rcItem.right % nScrollPosWidth == 0)
    4891             infoPtr->lefttop.x += rcItem.right / nScrollPosWidth;
    4892           else
    4893             infoPtr->lefttop.x += rcItem.right / nScrollPosWidth + 1;
    4894 
    4895           if (infoPtr->lefttop.x != oldlefttop.x)
    4896           {
    4897             SCROLLINFO scrollInfo;
    4898 
    4899             ZeroMemory(&scrollInfo,sizeof(SCROLLINFO));
    4900             scrollInfo.cbSize = sizeof(SCROLLINFO);
    4901             scrollInfo.fMask  = SIF_POS;
    4902             scrollInfo.nPos   = infoPtr->lefttop.x;
    4903             SetScrollInfo(hwnd,SB_HORZ,&scrollInfo,TRUE);
    4904           }
    4905         }
    4906       }
    4907     }
    4908 
    4909     if (rcItem.top < infoPtr->rcList.top)
    4910     {
    4911       /* scroll up */
    4912       if (dwStyle & WS_VSCROLL)
    4913       {
     4469            nScrollPosWidth = infoPtr->nItemWidth;
     4470        else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
     4471            nScrollPosWidth = 1;
     4472
     4473        if (rcItem.left < infoPtr->rcList.left)
     4474        {
     4475            nHorzAdjust = -1;
     4476            if (uView != LVS_REPORT) nHorzDiff = rcItem.left - infoPtr->rcList.left;
     4477        }
     4478        else
     4479        {
     4480            nHorzAdjust = 1;
     4481            if (uView != LVS_REPORT) nHorzDiff = rcItem.right - infoPtr->rcList.right;
     4482        }
     4483    }
     4484
     4485    if (rcItem.top < infoPtr->rcList.top || rcItem.bottom > infoPtr->rcList.bottom)
     4486    {
     4487        /* scroll up/down, but not in LVS_LIST mode */
    49144488        if (uView == LVS_REPORT)
    4915         {
    4916           rcItem.top -= infoPtr->rcList.top;
    4917           nScrollPosHeight = infoPtr->scrollStep.y;
    4918         }
     4489            nScrollPosHeight = infoPtr->nItemHeight;
    49194490        else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
    4920         {
    4921           nScrollPosHeight = infoPtr->scrollStep.y;
    4922           rcItem.top += infoPtr->rcList.top;
    4923         }
    4924 
    4925         if (rcItem.top % nScrollPosHeight == 0)
    4926           infoPtr->lefttop.y += rcItem.top / nScrollPosHeight;
    4927         else
    4928           infoPtr->lefttop.y += rcItem.top / nScrollPosHeight - 1;
    4929 
    4930         if (infoPtr->lefttop.y != oldlefttop.y)
    4931         {
    4932           SCROLLINFO scrollInfo;
    4933 
    4934           ZeroMemory(&scrollInfo,sizeof(SCROLLINFO));
    4935           scrollInfo.cbSize = sizeof(SCROLLINFO);
    4936           scrollInfo.fMask  = SIF_POS;
    4937           scrollInfo.nPos = infoPtr->lefttop.y;
    4938           SetScrollInfo(hwnd,SB_VERT,&scrollInfo,TRUE);
    4939         }
    4940       }
    4941     } else if (rcItem.bottom > infoPtr->rcList.bottom)
    4942     {
    4943       /* scroll down */
    4944       if (dwStyle & WS_VSCROLL)
    4945       {
    4946         if (uView == LVS_REPORT)
    4947         {
    4948           rcItem.bottom -= infoPtr->rcList.bottom;
    4949           nScrollPosHeight = infoPtr->scrollStep.y;
    4950         } else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
    4951         {
    4952           nScrollPosHeight = infoPtr->scrollStep.x;
    4953           rcItem.bottom -= infoPtr->rcList.bottom;
    4954         }
    4955 
    4956         if (rcItem.bottom % nScrollPosHeight == 0)
    4957           infoPtr->lefttop.y += rcItem.bottom / nScrollPosHeight;
    4958         else
    4959           infoPtr->lefttop.y += rcItem.bottom / nScrollPosHeight + 1;
    4960         if (infoPtr->lefttop.y != oldlefttop.y)
    4961         {
    4962           SCROLLINFO scrollInfo;
    4963 
    4964           ZeroMemory(&scrollInfo,sizeof(SCROLLINFO));
    4965           scrollInfo.cbSize = sizeof(SCROLLINFO);
    4966           scrollInfo.fMask  = SIF_POS | SIF_RANGE;
    4967           scrollInfo.nPos = infoPtr->lefttop.y;
    4968           //@@PF M$ always show entries when EnsureVisible is issued
    4969           //so we better change range also
    4970           scrollInfo.nMax   = GETITEMCOUNT(infoPtr)-1;
    4971           SetScrollInfo(hwnd,SB_VERT,&scrollInfo,TRUE);
    4972         }
    4973       }
    4974     }
    4975   }
    4976 
    4977   if ((oldlefttop.x != infoPtr->lefttop.x) || (oldlefttop.y != infoPtr->lefttop.y))
    4978     LISTVIEW_ScrollWindow(hwnd,(oldlefttop.x-infoPtr->lefttop.x)*infoPtr->scrollStep.x,(oldlefttop.y-infoPtr->lefttop.y)*infoPtr->scrollStep.y);
    4979 
    4980   return TRUE;
    4981 }
    4982 #else
    4983 static BOOL LISTVIEW_EnsureVisible(HWND hwnd, INT nItem, BOOL bPartial)
    4984 {
    4985   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
    4986   UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
    4987   INT nScrollPosHeight = 0;
    4988   INT nScrollPosWidth = 0;
    4989   SCROLLINFO scrollInfo;
    4990   RECT rcItem;
    4991   BOOL bRedraw = FALSE;
    4992 
    4993   ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
    4994   scrollInfo.cbSize = sizeof(SCROLLINFO);
    4995   scrollInfo.fMask = SIF_POS;
    4996 
    4997   /* ALWAYS bPartial == FALSE, FOR NOW! */
    4998 
    4999   rcItem.left = LVIR_BOUNDS;
    5000   if (LISTVIEW_GetItemRect(hwnd, nItem, &rcItem) != FALSE)
    5001   {
    5002     if (rcItem.left < infoPtr->rcList.left)
    5003     {
    5004       if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
    5005       {
    5006         /* scroll left */
    5007         bRedraw = TRUE;
    5008         if (uView == LVS_LIST)
    5009         {
    5010           nScrollPosWidth = infoPtr->nItemWidth;
    5011           rcItem.left += infoPtr->rcList.left;
    5012         }
    5013         else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
    5014         {
    5015           nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
    5016           rcItem.left += infoPtr->rcList.left;
    5017         }
    5018 
    5019     /* When in LVS_REPORT view, the scroll position should
    5020        not be updated. */
    5021     if (nScrollPosWidth != 0)
    5022     {
    5023       if (rcItem.left % nScrollPosWidth == 0)
    5024       {
    5025         scrollInfo.nPos += rcItem.left / nScrollPosWidth;
    5026       }
    5027       else
    5028       {
    5029         scrollInfo.nPos += rcItem.left / nScrollPosWidth - 1;
    5030       }
    5031 
    5032       SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
    5033     }
    5034       }
    5035     }
    5036     else if (rcItem.right > infoPtr->rcList.right)
    5037     {
    5038       if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
    5039       {
    5040         /* scroll right */
    5041     bRedraw = TRUE;
    5042         if (uView == LVS_LIST)
    5043         {
    5044           rcItem.right -= infoPtr->rcList.right;
    5045           nScrollPosWidth = infoPtr->nItemWidth;
    5046         }
    5047         else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
    5048         {
    5049           rcItem.right -= infoPtr->rcList.right;
    5050           nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
    5051         }
    5052 
    5053     /* When in LVS_REPORT view, the scroll position should
    5054        not be updated. */
    5055     if (nScrollPosWidth != 0)
    5056     {
    5057       if (rcItem.right % nScrollPosWidth == 0)
    5058       {
    5059         scrollInfo.nPos += rcItem.right / nScrollPosWidth;
    5060       }
    5061       else
    5062       {
    5063         scrollInfo.nPos += rcItem.right / nScrollPosWidth + 1;
    5064       }
    5065 
    5066       SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
    5067     }
    5068       }
    5069     }
    5070 
    5071     if (rcItem.top < infoPtr->rcList.top)
    5072     {
    5073       /* scroll up */
    5074       bRedraw = TRUE;
    5075       if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
    5076       {
    5077         if (uView == LVS_REPORT)
    5078         {
    5079           rcItem.top -= infoPtr->rcList.top;
    5080           nScrollPosHeight = infoPtr->nItemHeight;
    5081         }
    5082         else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
    5083         {
    5084           nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
    5085           rcItem.top += infoPtr->rcList.top;
    5086         }
    5087 
    5088         if (rcItem.top % nScrollPosHeight == 0)
    5089         {
    5090           scrollInfo.nPos += rcItem.top / nScrollPosHeight;
    5091         }
    5092         else
    5093         {
    5094           scrollInfo.nPos += rcItem.top / nScrollPosHeight - 1;
    5095         }
    5096 
    5097         SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
    5098       }
    5099     }
    5100     else if (rcItem.bottom > infoPtr->rcList.bottom)
    5101     {
    5102       /* scroll down */
    5103       bRedraw = TRUE;
    5104       if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
    5105       {
    5106         if (uView == LVS_REPORT)
    5107         {
    5108           rcItem.bottom -= infoPtr->rcList.bottom;
    5109           nScrollPosHeight = infoPtr->nItemHeight;
    5110         }
    5111         else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
    5112         {
    5113           nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
    5114           rcItem.bottom -= infoPtr->rcList.bottom;
    5115         }
    5116 
    5117         if (rcItem.bottom % nScrollPosHeight == 0)
    5118         {
    5119           scrollInfo.nPos += rcItem.bottom / nScrollPosHeight;
    5120         }
    5121         else
    5122         {
    5123           scrollInfo.nPos += rcItem.bottom / nScrollPosHeight + 1;
    5124         }
    5125 
    5126         SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
    5127       }
    5128     }
    5129   }
    5130 
    5131   if(bRedraw)
    5132     InvalidateRect(hwnd,NULL,TRUE);
    5133   return TRUE;
    5134 }
    5135 #endif
    5136 
    5137 /***
    5138  * DESCRIPTION:
    5139  * Retrieves the nearest item, given a position and a direction.
    5140  *
    5141  * PARAMETER(S):
    5142  * [I] HWND : window handle
    5143  * [I] POINT : start position
    5144  * [I] UINT : direction
    5145  *
    5146  * RETURN:
    5147  * Item index if successdful, -1 otherwise.
    5148  */
    5149 static INT LISTVIEW_GetNearestItem(HWND hwnd, POINT pt, UINT vkDirection)
    5150 {
    5151   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    5152   LV_INTHIT lvIntHit;
    5153   INT nItem = -1;
    5154   RECT rcView;
    5155 
    5156   TRACE("point %ld,%ld, direction %s\n", pt.x, pt.y,
    5157         (vkDirection == VK_DOWN) ? "VK_DOWN" :
    5158         ((vkDirection == VK_UP) ? "VK_UP" :
    5159         ((vkDirection == VK_LEFT) ? "VK_LEFT" : "VK_RIGHT")));
    5160 
    5161   if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
    5162   {
    5163     ZeroMemory(&lvIntHit, sizeof(lvIntHit));
    5164     LISTVIEW_GetOrigin(hwnd, &lvIntHit.ht.pt);
    5165     lvIntHit.ht.pt.x += pt.x;
    5166     lvIntHit.ht.pt.y += pt.y;
    5167    
    5168     if (vkDirection == VK_DOWN)
    5169       lvIntHit.ht.pt.y += infoPtr->nItemHeight;
    5170     else if (vkDirection == VK_UP)
    5171       lvIntHit.ht.pt.y -= infoPtr->nItemHeight;
    5172     else if (vkDirection == VK_LEFT)
    5173       lvIntHit.ht.pt.x -= infoPtr->nItemWidth;
    5174     else if (vkDirection == VK_RIGHT)
    5175       lvIntHit.ht.pt.x += infoPtr->nItemWidth;
    5176 
    5177     if (PtInRect(&rcView, lvIntHit.ht.pt) == FALSE)
    5178       return -1;
    5179     else
    5180     {
    5181       nItem = LISTVIEW_SuperHitTestItem(hwnd, &lvIntHit, TRUE);
    5182       return nItem == -1 ? lvIntHit.iDistItem : nItem;
    5183     }
    5184   }
    5185 
    5186   return nItem;
    5187 
     4491            nScrollPosHeight = 1;
     4492
     4493        if (rcItem.top < infoPtr->rcList.top)
     4494        {
     4495            nVertAdjust = -1;
     4496            if (uView != LVS_LIST) nVertDiff = rcItem.top - infoPtr->rcList.top;
     4497        }
     4498        else
     4499        {
     4500            nVertAdjust = 1;
     4501            if (uView != LVS_LIST) nVertDiff = rcItem.bottom - infoPtr->rcList.bottom;
     4502        }
     4503    }
     4504
     4505    if (!nScrollPosWidth && !nScrollPosHeight) return TRUE;
     4506
     4507    if (nScrollPosWidth)
     4508    {
     4509        INT diff = nHorzDiff / nScrollPosWidth;
     4510        if (nHorzDiff % nScrollPosWidth) diff += nHorzAdjust;
     4511        LISTVIEW_HScroll(infoPtr, SB_INTERNAL, diff, 0);
     4512    }
     4513
     4514    if (nScrollPosHeight)
     4515    {
     4516        INT diff = nVertDiff / nScrollPosHeight;
     4517        if (nVertDiff % nScrollPosHeight) diff += nVertAdjust;
     4518        LISTVIEW_VScroll(infoPtr, SB_INTERNAL, diff, 0);
     4519    }
     4520
     4521    return TRUE;
     4522}
    51884523
    51894524/***
    51904525 * DESCRIPTION:
    51914526 * Searches for an item with specific characteristics.
    5192  * 
     4527 *
    51934528 * PARAMETER(S):
    51944529 * [I] hwnd : window handle
    51954530 * [I] nStart : base item index
    51964531 * [I] lpFindInfo : item information to look for
    5197  * 
     4532 *
    51984533 * RETURN:
    51994534 *   SUCCESS : index of item
    52004535 *   FAILURE : -1
    52014536 */
    5202 static LRESULT LISTVIEW_FindItemW(HWND hwnd, INT nStart,
    5203                                   LPLVFINDINFOW lpFindInfo)
    5204 {
    5205   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    5206   POINT ptItem;
    5207   WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
    5208   LVITEMW lvItem;
    5209   BOOL bWrap = FALSE;
    5210   INT nItem = nStart;
    5211   INT nLast = GETITEMCOUNT(infoPtr);
    5212 
    5213   if ((nItem >= -1) && (lpFindInfo != NULL))
    5214   {
    5215     ZeroMemory(&lvItem, sizeof(lvItem));
    5216 
     4537static INT LISTVIEW_FindItemW(LISTVIEW_INFO *infoPtr, INT nStart,
     4538                              const LVFINDINFOW *lpFindInfo)
     4539{
     4540    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     4541    WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
     4542    BOOL bWrap = FALSE, bNearest = FALSE;
     4543    INT nItem = nStart + 1, nLast = infoPtr->nItemCount, nNearestItem = -1;
     4544    ULONG xdist, ydist, dist, mindist = 0x7fffffff;
     4545    POINT Position, Destination;
     4546    LVITEMW lvItem;
     4547
     4548    if (!lpFindInfo || nItem < 0) return -1;
     4549   
     4550    lvItem.mask = 0;
     4551    if (lpFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL))
     4552    {
     4553        lvItem.mask |= LVIF_TEXT;
     4554        lvItem.pszText = szDispText;
     4555        lvItem.cchTextMax = DISP_TEXT_SIZE;
     4556    }
     4557
     4558    if (lpFindInfo->flags & LVFI_WRAP)
     4559        bWrap = TRUE;
     4560
     4561    if ((lpFindInfo->flags & LVFI_NEARESTXY) &&
     4562        (uView == LVS_ICON || uView ==LVS_SMALLICON))
     4563    {
     4564        POINT Origin;
     4565        RECT rcArea;
     4566       
     4567        LISTVIEW_GetOrigin(infoPtr, &Origin);
     4568        Destination.x = lpFindInfo->pt.x - Origin.x;
     4569        Destination.y = lpFindInfo->pt.y - Origin.y;
     4570        switch(lpFindInfo->vkDirection)
     4571        {
     4572        case VK_DOWN:  Destination.y += infoPtr->nItemHeight; break;
     4573        case VK_UP:    Destination.y -= infoPtr->nItemHeight; break;
     4574        case VK_RIGHT: Destination.x += infoPtr->nItemWidth; break;
     4575        case VK_LEFT:  Destination.x -= infoPtr->nItemWidth; break;
     4576        case VK_HOME:  Destination.x = Destination.y = 0; break;
     4577        case VK_NEXT:  Destination.y += infoPtr->rcList.bottom - infoPtr->rcList.top; break;
     4578        case VK_PRIOR: Destination.y -= infoPtr->rcList.bottom - infoPtr->rcList.top; break;
     4579        case VK_END:
     4580            LISTVIEW_GetAreaRect(infoPtr, &rcArea);
     4581            Destination.x = rcArea.right;
     4582            Destination.y = rcArea.bottom;
     4583            break;
     4584        default: ERR("Unknown vkDirection=%d\n", lpFindInfo->vkDirection);
     4585        }
     4586        bNearest = TRUE;
     4587    }
     4588
     4589    /* if LVFI_PARAM is specified, all other flags are ignored */
    52174590    if (lpFindInfo->flags & LVFI_PARAM)
    52184591    {
    5219       lvItem.mask |= LVIF_PARAM;
    5220     }
    5221    
    5222     if (lpFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL))
    5223     {
    5224       lvItem.mask |= LVIF_TEXT;
    5225       lvItem.pszText = szDispText;
    5226       lvItem.cchTextMax = DISP_TEXT_SIZE;
    5227     }
    5228 
    5229     if (lpFindInfo->flags & LVFI_WRAP)
    5230       bWrap = TRUE;
    5231 
    5232     if (lpFindInfo->flags & LVFI_NEARESTXY)
    5233     {
    5234       ptItem.x = lpFindInfo->pt.x;
    5235       ptItem.y = lpFindInfo->pt.y;
    5236     }
    5237 
    5238     while (1)
    5239     {
    5240       while (nItem < nLast)
    5241       {
    5242         if (lpFindInfo->flags & LVFI_NEARESTXY)
    5243         {
    5244           nItem = LISTVIEW_GetNearestItem(hwnd, ptItem,
    5245                                           lpFindInfo->vkDirection);
    5246           if (nItem != -1)
    5247           {
    5248             /* get position of the new item index */
    5249             if (ListView_GetItemPosition(hwnd, nItem, &ptItem) == FALSE)
    5250               return -1;
    5251           }
    5252           else
    5253             return -1;
    5254         }
    5255         else
    5256         {
    5257           nItem++;
    5258         }
    5259        
     4592        lvItem.mask |= LVIF_PARAM;
     4593        bNearest = FALSE;
     4594        lvItem.mask &= ~LVIF_TEXT;
     4595    }
     4596
     4597again:
     4598    for (; nItem < nLast; nItem++)
     4599    {
    52604600        lvItem.iItem = nItem;
    52614601        lvItem.iSubItem = 0;
    5262         if (LISTVIEW_GetItemW(hwnd, &lvItem, TRUE))
     4602        if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) continue;
     4603
     4604        if (lvItem.mask & LVIF_PARAM)
    52634605        {
    5264           if (lvItem.mask & LVIF_TEXT)
    5265           {
     4606            if (lpFindInfo->lParam == lvItem.lParam)
     4607                return nItem;
     4608            else
     4609                continue;
     4610        }
     4611       
     4612        if (lvItem.mask & LVIF_TEXT)
     4613        {
    52664614            if (lpFindInfo->flags & LVFI_PARTIAL)
    52674615            {
    5268               if (strstrW(lvItem.pszText, lpFindInfo->psz) == NULL)
    5269                 continue;
     4616                if (strstrW(lvItem.pszText, lpFindInfo->psz) == NULL) continue;
    52704617            }
    52714618            else
    52724619            {
    5273               if (lstrcmpW(lvItem.pszText, lpFindInfo->psz) != 0)
    5274                 continue;
     4620                if (lstrcmpW(lvItem.pszText, lpFindInfo->psz) != 0) continue;
    52754621            }
    5276           }
    5277          
    5278           if (lvItem.mask & LVIF_PARAM)
    5279           {
    5280             if (lpFindInfo->lParam != lvItem.lParam)
    5281               continue;
    5282           }
    5283          
    5284           return nItem;
    5285         }
    5286       }
    5287 
    5288       if (bWrap)
    5289       {
    5290         nItem = -1;
    5291         nLast = nStart + 1;
     4622        }
     4623
     4624        if (!bNearest) return nItem;
     4625       
     4626        /* This is very inefficient. To do a good job here,
     4627         * we need a sorted array of (x,y) item positions */
     4628        LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position);
     4629
     4630        /* compute the distance^2 to the destination */
     4631        xdist = Destination.x - Position.x;
     4632        ydist = Destination.y - Position.y;
     4633        dist = xdist * xdist + ydist * ydist;
     4634
     4635        /* remember the distance, and item if it's closer */
     4636        if (dist < mindist)
     4637        {
     4638            mindist = dist;
     4639            nNearestItem = nItem;
     4640        }
     4641    }
     4642
     4643    if (bWrap)
     4644    {
     4645        nItem = 0;
     4646        nLast = min(nStart + 1, infoPtr->nItemCount);
    52924647        bWrap = FALSE;
    5293       }
    5294       else
    5295       {
    5296         return -1;
    5297       }       
    5298     }
    5299   }
    5300 
    5301  return -1;
     4648        goto again;
     4649    }
     4650
     4651    return nNearestItem;
    53024652}
    53034653
     
    53054655 * DESCRIPTION:
    53064656 * Searches for an item with specific characteristics.
    5307  * 
     4657 *
    53084658 * PARAMETER(S):
    53094659 * [I] hwnd : window handle
    53104660 * [I] nStart : base item index
    53114661 * [I] lpFindInfo : item information to look for
    5312  * 
     4662 *
    53134663 * RETURN:
    53144664 *   SUCCESS : index of item
    53154665 *   FAILURE : -1
    53164666 */
    5317 static LRESULT LISTVIEW_FindItemA(HWND hwnd, INT nStart,
    5318                                   LPLVFINDINFOA lpFindInfo)
    5319 {
    5320   BOOL hasText = lpFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL);
    5321   LVFINDINFOW fiw;
    5322   LRESULT res;
    5323  
    5324   memcpy(&fiw, lpFindInfo, sizeof(fiw));
    5325   if (hasText) fiw.psz = textdupTtoW((LPCWSTR)lpFindInfo->psz, FALSE);
    5326   res = LISTVIEW_FindItemW(hwnd, nStart, &fiw);
    5327   if (hasText) textfreeT((LPWSTR)fiw.psz, FALSE);
    5328   return res;
    5329 }
    5330 
    5331 /***
    5332  * DESCRIPTION:
    5333  * Retrieves the background color of the listview control.
    5334  *
    5335  * PARAMETER(S):
    5336  * [I] HWND : window handle
    5337  *
    5338  * RETURN:
    5339  * COLORREF associated with the background.
    5340  */
    5341 static LRESULT LISTVIEW_GetBkColor(HWND hwnd)
    5342 {
    5343   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    5344 
    5345   return infoPtr->clrBk;
     4667static INT LISTVIEW_FindItemA(LISTVIEW_INFO *infoPtr, INT nStart,
     4668                              const LVFINDINFOA *lpFindInfo)
     4669{
     4670    BOOL hasText = lpFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL);
     4671    LVFINDINFOW fiw;
     4672    INT res;
     4673
     4674    memcpy(&fiw, lpFindInfo, sizeof(fiw));
     4675    if (hasText) fiw.psz = textdupTtoW((LPCWSTR)lpFindInfo->psz, FALSE);
     4676    res = LISTVIEW_FindItemW(infoPtr, nStart, &fiw);
     4677    if (hasText) textfreeT((LPWSTR)fiw.psz, FALSE);
     4678    return res;
    53464679}
    53474680
     
    53494682 * DESCRIPTION:
    53504683 * Retrieves the background image of the listview control.
    5351  * 
    5352  * PARAMETER(S):
    5353  * [I] HWND : window handle
    5354  * [O] LPLVMKBIMAGE : background image attributes
     4684 *
     4685 * PARAMETER(S):
     4686 * [I] infoPtr : valid pointer to the listview structure
     4687 * [O] lpBkImage : background image attributes
    53554688 *
    53564689 * RETURN:
     
    53584691 *   FAILURE : FALSE
    53594692 */
    5360 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage)   */
     4693/* static BOOL LISTVIEW_GetBkImage(LISTVIEW_INFO *infoPtr, LPLVBKIMAGE lpBkImage)   */
    53614694/* {   */
    53624695/*   FIXME (listview, "empty stub!\n"); */
     
    53664699/***
    53674700 * DESCRIPTION:
    5368  * Retrieves the callback mask.
    5369  *
    5370  * PARAMETER(S):
    5371  * [I] HWND : window handle
    5372  *
    5373  * RETURN:
    5374  *  Value of mask
    5375  */
    5376 static UINT LISTVIEW_GetCallbackMask(HWND hwnd)
    5377 {
    5378   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    5379 
    5380   return infoPtr->uCallbackMask;
    5381 }
    5382 
    5383 /***
    5384  * DESCRIPTION:
    53854701 * Retrieves column attributes.
    5386  * 
    5387  * PARAMETER(S):
    5388  * [I] HWND : window handle
    5389  * [I] INT :  column index
    5390  * [IO] LPLVCOLUMNW : column information
     4702 *
     4703 * PARAMETER(S):
     4704 * [I] infoPtr : valid pointer to the listview structure
     4705 * [I] nColumn :  column index
     4706 * [IO] lpColumn : column information
    53914707 * [I] isW : if TRUE, then lpColumn is a LPLVCOLUMNW
    53924708 *           otherwise it is in fact a LPLVCOLUMNA
     
    53964712 *   FAILURE : FALSE
    53974713 */
    5398 static LRESULT LISTVIEW_GetColumnT(HWND hwnd, INT nItem, LPLVCOLUMNW lpColumn, BOOL isW)
    5399 {
    5400   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    5401   HDITEMW hdi;
    5402   BOOL bResult = FALSE;
    5403  
    5404   if (lpColumn != NULL)
    5405   {
    5406 
    5407     TRACE("(hwnd=%x, col=%d, lpColumn=%s, isW=%d)\n",
    5408         hwnd, nItem, debuglvcolumn_t(lpColumn, isW), isW);
     4714static BOOL LISTVIEW_GetColumnT(LISTVIEW_INFO *infoPtr, INT nColumn, LPLVCOLUMNW lpColumn, BOOL isW)
     4715{
     4716    COLUMN_INFO *lpColumnInfo;
     4717    HDITEMW hdi;
     4718
     4719    if (!lpColumn || nColumn < 0 || nColumn >= infoPtr->hdpaColumns->nItemCount) return FALSE;
     4720    lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, nColumn);
    54094721
    54104722    /* initialize memory */
    54114723    ZeroMemory(&hdi, sizeof(hdi));
    5412    
     4724
     4725    if (lpColumn->mask & LVCF_TEXT)
     4726    {
     4727        hdi.mask |= HDI_TEXT;
     4728        hdi.pszText = lpColumn->pszText;
     4729        hdi.cchTextMax = lpColumn->cchTextMax;
     4730    }
     4731
     4732    if (lpColumn->mask & LVCF_IMAGE)
     4733        hdi.mask |= HDI_IMAGE;
     4734
     4735    if (lpColumn->mask & LVCF_ORDER)
     4736        hdi.mask |= HDI_ORDER;
     4737
     4738    if (!SendMessageW(infoPtr->hwndHeader, isW ? HDM_GETITEMW : HDM_GETITEMA, nColumn, (LPARAM)&hdi)) return FALSE;
     4739
    54134740    if (lpColumn->mask & LVCF_FMT)
    5414       hdi.mask |= HDI_FORMAT;
     4741        lpColumn->fmt = lpColumnInfo->fmt;
    54154742
    54164743    if (lpColumn->mask & LVCF_WIDTH)
    5417       hdi.mask |= HDI_WIDTH;
    5418 
    5419     if (lpColumn->mask & LVCF_TEXT)
    5420     {
    5421       hdi.mask |= HDI_TEXT;
    5422       hdi.cchTextMax = lpColumn->cchTextMax;
    5423       hdi.pszText    = lpColumn->pszText;
    5424     }
     4744        lpColumn->cx = lpColumnInfo->rcHeader.right - lpColumnInfo->rcHeader.left;
    54254745
    54264746    if (lpColumn->mask & LVCF_IMAGE)
    5427       hdi.mask |= HDI_IMAGE;
     4747        lpColumn->iImage = hdi.iImage;
    54284748
    54294749    if (lpColumn->mask & LVCF_ORDER)
    5430       hdi.mask |= HDI_ORDER;
    5431 
    5432     if (isW)
    5433       bResult = Header_GetItemW(infoPtr->hwndHeader, nItem, &hdi);
    5434     else
    5435       bResult = Header_GetItemA(infoPtr->hwndHeader, nItem, &hdi);
    5436 
    5437     if (bResult != FALSE)
    5438     {
    5439       if (lpColumn->mask & LVCF_FMT)
    5440       {
    5441         lpColumn->fmt = 0;
    5442 
    5443         if (hdi.fmt & HDF_LEFT)
    5444           lpColumn->fmt |= LVCFMT_LEFT;
    5445         else if (hdi.fmt & HDF_RIGHT)
    5446           lpColumn->fmt |= LVCFMT_RIGHT;
    5447         else if (hdi.fmt & HDF_CENTER)
    5448           lpColumn->fmt |= LVCFMT_CENTER;
    5449 
    5450         if (hdi.fmt & HDF_IMAGE)
    5451           lpColumn->fmt |= LVCFMT_COL_HAS_IMAGES;
    5452 
    5453         if (hdi.fmt & HDF_BITMAP_ON_RIGHT)
    5454           lpColumn->fmt |= LVCFMT_BITMAP_ON_RIGHT;
    5455       }
    5456 
    5457       if (lpColumn->mask & LVCF_WIDTH)
    5458         lpColumn->cx = hdi.cxy;
    5459      
    5460       if (lpColumn->mask & LVCF_IMAGE)
    5461         lpColumn->iImage = hdi.iImage;
    5462 
    5463       if (lpColumn->mask & LVCF_ORDER)
    5464         lpColumn->iOrder = hdi.iOrder;
    5465     }
    5466   }
    5467 
    5468   return bResult;
    5469 }
    5470 
    5471 
    5472 static LRESULT LISTVIEW_GetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
    5473 {
    5474 /*  LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0); */
     4750        lpColumn->iOrder = hdi.iOrder;
     4751
     4752    return TRUE;
     4753}
     4754
     4755
     4756static BOOL LISTVIEW_GetColumnOrderArray(LISTVIEW_INFO *infoPtr, INT iCount, LPINT lpiArray)
     4757{
    54754758    INT i;
    54764759
     
    54784761        return FALSE;
    54794762
    5480     /* little hack */
     4763    /* FIXME: little hack */
    54814764    for (i = 0; i < iCount; i++)
    54824765        lpiArray[i] = i;
     
    54884771 * DESCRIPTION:
    54894772 * Retrieves the column width.
    5490  * 
    5491  * PARAMETER(S):
    5492  * [I] HWND : window handle
     4773 *
     4774 * PARAMETER(S):
     4775 * [I] infoPtr : valid pointer to the listview structure
    54934776 * [I] int : column index
    54944777 *
    54954778 * RETURN:
    54964779 *   SUCCESS : column width
    5497  *   FAILURE : zero
    5498  */
    5499 static LRESULT LISTVIEW_GetColumnWidth(HWND hwnd, INT nColumn)
    5500 {
    5501   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    5502   UINT uView = GetWindowLongW(hwnd, GWL_STYLE) & LVS_TYPEMASK;
    5503   INT nColumnWidth = 0;
    5504   HDITEMW hdi;
    5505 
    5506   if (uView == LVS_LIST)
    5507   {
    5508     nColumnWidth = infoPtr->nItemWidth;
    5509   }
    5510   else if (uView == LVS_REPORT)
    5511   {
    5512     /* get column width from header */
    5513     ZeroMemory(&hdi, sizeof(hdi));
    5514     hdi.mask = HDI_WIDTH;
    5515     if (Header_GetItemW(infoPtr->hwndHeader, nColumn, &hdi) != FALSE)
    5516       nColumnWidth = hdi.cxy;
    5517   }
    5518 
    5519   return nColumnWidth;
    5520 }
    5521 
    5522 /***
    5523  * DESCRIPTION:
    5524  * In list or report display mode, retrieves the number of items that can fit
    5525  * vertically in the visible area. In icon or small icon display mode,
     4780 *   FAILURE : zero
     4781 */
     4782static INT LISTVIEW_GetColumnWidth(LISTVIEW_INFO *infoPtr, INT nColumn)
     4783{
     4784    INT nColumnWidth = 0;
     4785    RECT rcHeader;
     4786
     4787    TRACE("nColumn=%d\n", nColumn);
     4788
     4789    /* we have a 'column' in LIST and REPORT mode only */
     4790    switch(infoPtr->dwStyle & LVS_TYPEMASK)
     4791    {
     4792    case LVS_LIST:
     4793        nColumnWidth = infoPtr->nItemWidth;
     4794        break;
     4795    case LVS_REPORT:
     4796        if (nColumn < 0 || nColumn >= infoPtr->hdpaColumns->nItemCount) return 0;
     4797        LISTVIEW_GetHeaderRect(infoPtr, nColumn, &rcHeader);
     4798        nColumnWidth = rcHeader.right - rcHeader.left;
     4799        break;
     4800    }
     4801
     4802    TRACE("nColumnWidth=%d\n", nColumnWidth);
     4803    return nColumnWidth;
     4804}
     4805
     4806/***
     4807 * DESCRIPTION:
     4808 * In list or report display mode, retrieves the number of items that can fit
     4809 * vertically in the visible area. In icon or small icon display mode,
    55264810 * retrieves the total number of visible items.
    5527  * 
    5528  * PARAMETER(S):
    5529  * [I] HWND : window handle
     4811 *
     4812 * PARAMETER(S):
     4813 * [I] infoPtr : valid pointer to the listview structure
    55304814 *
    55314815 * RETURN:
    55324816 * Number of fully visible items.
    55334817 */
    5534 static LRESULT LISTVIEW_GetCountPerPage(HWND hwnd)
    5535 {
    5536   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    5537   UINT uView = GetWindowLongW(hwnd, GWL_STYLE) & LVS_TYPEMASK;
    5538   INT nItemCount = 0;
    5539 
    5540   if (uView == LVS_LIST)
    5541   {
    5542     if (infoPtr->rcList.right > infoPtr->nItemWidth)
    5543     {
    5544       nItemCount = LISTVIEW_GetCountPerRow(hwnd) *
    5545                    LISTVIEW_GetCountPerColumn(hwnd);
    5546     }
    5547   }
    5548   else if (uView == LVS_REPORT)
    5549   {
    5550     nItemCount = LISTVIEW_GetCountPerColumn(hwnd);
    5551   }
    5552   else
    5553   {
    5554     nItemCount = GETITEMCOUNT(infoPtr);
    5555   }
    5556 
    5557   return nItemCount;
    5558 }
    5559 
    5560 /* LISTVIEW_GetEditControl */
    5561 
    5562 /***
    5563  * DESCRIPTION:
    5564  * Retrieves the extended listview style.
    5565  *
    5566  * PARAMETERS:
    5567  * [I] HWND  : window handle
    5568  *
    5569  * RETURN:
    5570  *   SUCCESS : previous style
    5571  *   FAILURE : 0
    5572  */
    5573 static LRESULT LISTVIEW_GetExtendedListViewStyle(HWND hwnd)
    5574 {
    5575     LISTVIEW_INFO *infoPtr;
    5576 
    5577     /* make sure we can get the listview info */
    5578     if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0)))
    5579         return (0);
    5580 
    5581     return (infoPtr->dwExStyle);
    5582 }
    5583 
    5584 /***
    5585  * DESCRIPTION:
    5586  * Retrieves the handle to the header control.
    5587  *
    5588  * PARAMETER(S):
    5589  * [I] HWND : window handle
    5590  *
    5591  * RETURN:
    5592  * Header handle.
    5593  */
    5594 static LRESULT LISTVIEW_GetHeader(HWND hwnd)
    5595 {
    5596   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    5597 
    5598   return infoPtr->hwndHeader;
    5599 }
    5600 
    5601 /* LISTVIEW_GetHotCursor */
    5602 
    5603 /***
    5604  * DESCRIPTION:
    5605  * Returns the time that the mouse cursor must hover over an item
    5606  * before it is selected.
    5607  *
    5608  * PARAMETER(S):
    5609  * [I] HWND : window handle
    5610  *
    5611  * RETURN:
    5612  *   Returns the previously set hover time or (DWORD)-1 to indicate that the
    5613  *   hover time is set to the default hover time.
    5614  */
    5615 static LRESULT LISTVIEW_GetHoverTime(HWND hwnd)
    5616 {
    5617   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    5618 
    5619   return infoPtr->dwHoverTime;
     4818static INT LISTVIEW_GetCountPerPage(LISTVIEW_INFO *infoPtr)
     4819{
     4820    switch (infoPtr->dwStyle & LVS_TYPEMASK)
     4821    {
     4822    case LVS_ICON:
     4823    case LVS_SMALLICON:
     4824        return infoPtr->nItemCount;
     4825    case LVS_REPORT:
     4826        return LISTVIEW_GetCountPerColumn(infoPtr);
     4827    case LVS_LIST:
     4828        return LISTVIEW_GetCountPerRow(infoPtr) * LISTVIEW_GetCountPerColumn(infoPtr);
     4829    }
     4830    assert(FALSE);
     4831    return 0;
    56204832}
    56214833
     
    56234835 * DESCRIPTION:
    56244836 * Retrieves an image list handle.
    5625  * 
    5626  * PARAMETER(S):
    5627  * [I] HWND : window handle
    5628  * [I] INT : image list identifier
    5629  * 
     4837 *
     4838 * PARAMETER(S):
     4839 * [I] infoPtr : valid pointer to the listview structure
     4840 * [I] nImageList : image list identifier
     4841 *
    56304842 * RETURN:
    56314843 *   SUCCESS : image list handle
    56324844 *   FAILURE : NULL
    56334845 */
    5634 static LRESULT LISTVIEW_GetImageList(HWND hwnd, INT nImageList)
    5635 {
    5636   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    5637   HIMAGELIST himl = NULL;
    5638 
    5639   switch (nImageList)
    5640   {
    5641   case LVSIL_NORMAL:
    5642     himl = infoPtr->himlNormal;
    5643     break;
    5644   case LVSIL_SMALL:
    5645     himl = infoPtr->himlSmall;
    5646     break;
    5647   case LVSIL_STATE:
    5648     himl = infoPtr->himlState;
    5649     break;
    5650   }
    5651 
    5652   return (LRESULT)himl;
     4846static HIMAGELIST LISTVIEW_GetImageList(LISTVIEW_INFO *infoPtr, INT nImageList)
     4847{
     4848    switch (nImageList)
     4849    {
     4850    case LVSIL_NORMAL: return infoPtr->himlNormal;
     4851    case LVSIL_SMALL: return infoPtr->himlSmall;
     4852    case LVSIL_STATE: return infoPtr->himlState;
     4853    }
     4854    return NULL;
    56534855}
    56544856
     
    56584860 * DESCRIPTION:
    56594861 * Retrieves item attributes.
    5660  * 
     4862 *
    56614863 * PARAMETER(S):
    56624864 * [I] hwnd : window handle
    56634865 * [IO] lpLVItem : item info
    5664  * [I] internal : if true then we will use tricks that avoid copies
    5665  *               but are not compatible with the regular interface
    5666  * [I] isW : if TRUE, then lpLVItem is a LPLVITEMW,
     4866 * [I] isW : if TRUE, then lpLVItem is a LPLVITEMW,
    56674867 *           if FALSE, the lpLVItem is a LPLVITEMA.
    5668  *
    5669  * RETURN:
    5670  *   SUCCESS : TRUE
    5671  *   FAILURE : FALSE
    5672  */
    5673 static LRESULT LISTVIEW_GetItemT(HWND hwnd, LPLVITEMW lpLVItem, BOOL internal, BOOL isW)
    5674 {
    5675   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    5676   LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    5677   NMLVDISPINFOW dispInfo;
    5678   LISTVIEW_SUBITEM *lpSubItem;
    5679   LISTVIEW_ITEM *lpItem;
    5680   HDPA hdpaSubItems;
    5681   void* null = NULL;
    5682   INT* piImage = (INT*)&null;
    5683   LPWSTR* ppszText= (LPWSTR*)&null;
    5684   LPARAM* plParam = (LPARAM*)&null;
    5685 
    5686   if (internal && !isW)
    5687   {
    5688     ERR("We can't have internal non-Unicode GetItem!\n");
    5689     return FALSE;
    5690   }
    5691  
    5692   /* In the following:
    5693    * lpLVItem describes the information requested by the user
    5694    * lpItem/lpSubItem is what we have
    5695    * dispInfo is a structure we use to request the missing
    5696    *     information from the application
    5697    */
    5698 
    5699   TRACE("(hwnd=%x, lpLVItem=%s, internal=%d, isW=%d)\n",
    5700         hwnd, debuglvitem_t(lpLVItem, isW), internal, isW);
    5701 
    5702   if ((lpLVItem == NULL) || (lpLVItem->iItem < 0) ||
    5703       (lpLVItem->iItem >= GETITEMCOUNT(infoPtr)))
    5704     return FALSE;
    5705 
    5706   ZeroMemory(&dispInfo, sizeof(dispInfo));
    5707 
    5708   if (lStyle & LVS_OWNERDATA)
    5709   {
    5710     if (lpLVItem->mask & ~LVIF_STATE)
    5711     {
    5712       memcpy(&dispInfo.item, lpLVItem, sizeof(LVITEMW));
    5713       dispinfo_notifyT(hwnd, LVN_GETDISPINFOW, &dispInfo, isW);
    5714       memcpy(lpLVItem, &dispInfo.item, sizeof(LVITEMW));
    5715       TRACE("   getdispinfo(1):lpLVItem=%s\n", debuglvitem_t(lpLVItem, isW));
    5716     }
    5717 
    5718     if ((lpLVItem->mask & LVIF_STATE)&&(lpLVItem->iSubItem == 0))
    5719     {
    5720       lpLVItem->state = 0;
    5721       if (infoPtr->nFocusedItem == lpLVItem->iItem)
    5722         lpLVItem->state |= LVIS_FOCUSED;
    5723       if (LISTVIEW_IsSelected(hwnd,lpLVItem->iItem))
    5724         lpLVItem->state |= LVIS_SELECTED;
    5725     }
    5726 
    5727     return TRUE;
    5728   }
    5729 
    5730   hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
    5731   if (hdpaSubItems == NULL) return FALSE;
    5732 
    5733   if ( (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)) == NULL)
    5734     return FALSE;
    5735 
    5736   ZeroMemory(&dispInfo.item, sizeof(LVITEMW));
    5737   if (lpLVItem->iSubItem == 0)
    5738   {
    5739     piImage=&lpItem->iImage;
    5740     ppszText=&lpItem->pszText;
    5741     plParam=&lpItem->lParam;
    5742     if ((lpLVItem->mask & LVIF_STATE) && infoPtr->uCallbackMask)
    5743     {       
    5744       dispInfo.item.mask |= LVIF_STATE;
    5745       dispInfo.item.stateMask = infoPtr->uCallbackMask;
    5746     }
    5747   }
    5748   else
    5749   {
    5750     lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem);
    5751     if (lpSubItem != NULL)
    5752     {
    5753       piImage=&lpSubItem->iImage;
    5754       ppszText=&lpSubItem->pszText;
    5755     }
    5756   }
    5757 
    5758   if ((lpLVItem->mask & LVIF_IMAGE) && (*piImage==I_IMAGECALLBACK))
    5759   {
    5760     dispInfo.item.mask |= LVIF_IMAGE;
    5761   }
    5762 
    5763   if ((lpLVItem->mask & LVIF_TEXT) && !is_textW(*ppszText))
    5764   {
    5765     dispInfo.item.mask |= LVIF_TEXT;
    5766     dispInfo.item.pszText = lpLVItem->pszText;
    5767     dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
    5768     if (dispInfo.item.pszText && lpLVItem->cchTextMax > 0)
    5769       *dispInfo.item.pszText = '\0';
    5770     if (dispInfo.item.pszText && (*ppszText == NULL))
    5771       *dispInfo.item.pszText = '\0';
    5772   }
    5773 
    5774   if (dispInfo.item.mask != 0)
    5775   {
    5776     /* We don't have all the requested info, query the application */
    5777     dispInfo.item.iItem = lpLVItem->iItem;
    5778     dispInfo.item.iSubItem = lpLVItem->iSubItem;
    5779     dispInfo.item.lParam = lpItem->lParam;
    5780     dispinfo_notifyT(hwnd, LVN_GETDISPINFOW, &dispInfo, isW);
    5781     TRACE("   getdispinfo(2):lpLVItem=%s\n", debuglvitem_t(&dispInfo.item, isW));
    5782   }
    5783 
    5784   if (dispInfo.item.mask & LVIF_IMAGE)
    5785   {
    5786     lpLVItem->iImage = dispInfo.item.iImage;
    5787     if ((dispInfo.item.mask & LVIF_DI_SETITEM) && (*piImage==I_IMAGECALLBACK))
    5788       *piImage = dispInfo.item.iImage;
    5789   }
    5790   else if (lpLVItem->mask & LVIF_IMAGE)
    5791   {
    5792     lpLVItem->iImage = *piImage;
    5793   }
    5794 
    5795   if (dispInfo.item.mask & LVIF_PARAM)
    5796   {
    5797     lpLVItem->lParam = dispInfo.item.lParam;
    5798     if (dispInfo.item.mask & LVIF_DI_SETITEM)
    5799       *plParam = dispInfo.item.lParam;
    5800   }
    5801   else if (lpLVItem->mask & LVIF_PARAM)
    5802     lpLVItem->lParam = lpItem->lParam;
    5803 
    5804 #ifdef __WIN32OS2__
    5805       if (ppszText && (UINT)*ppszText != -1) {
    5806         dprintf(("LISTVIEW_GetItemA lpLVItem->mask (%x), dispInfo.item.mask (%x);", lpLVItem->mask, dispInfo.item.mask));
    5807       }
    5808 #endif
    5809 
    5810   if (dispInfo.item.mask & LVIF_TEXT)
    5811   {
    5812     if ((dispInfo.item.mask & LVIF_DI_SETITEM) && *ppszText)
    5813       textsetptrT(ppszText, dispInfo.item.pszText, isW);
    5814    
    5815     /* If lpLVItem->pszText==dispInfo.item.pszText a copy is unnecessary, but */
    5816     /* some apps give a new pointer in ListView_Notify so we can't be sure.  */
    5817     if (lpLVItem->pszText != dispInfo.item.pszText)
    5818         textcpynT(lpLVItem->pszText, isW, dispInfo.item.pszText, isW, lpLVItem->cchTextMax);
    5819    
    5820   }
    5821   else if (lpLVItem->mask & LVIF_TEXT)
    5822   {
    5823     if (internal) lpLVItem->pszText = *ppszText;
    5824     else textcpynT(lpLVItem->pszText, isW, *ppszText, TRUE, lpLVItem->cchTextMax);
    5825   }
    5826 
    5827   if (lpLVItem->iSubItem == 0)
    5828   {
    5829     if (dispInfo.item.mask & LVIF_STATE)
    5830     {
    5831       lpLVItem->state = lpItem->state;
    5832       lpLVItem->state &= ~dispInfo.item.stateMask;
    5833       lpLVItem->state |= (dispInfo.item.state & dispInfo.item.stateMask);
    5834 
    5835       lpLVItem->state &= ~LVIS_SELECTED;
    5836       if ((dispInfo.item.stateMask & LVIS_SELECTED) &&
    5837           LISTVIEW_IsSelected(hwnd,dispInfo.item.iItem))
    5838         lpLVItem->state |= LVIS_SELECTED;
    5839     }
    5840     else if (lpLVItem->mask & LVIF_STATE)
    5841     {
    5842       lpLVItem->state = lpItem->state & lpLVItem->stateMask;
    5843 
    5844       lpLVItem->state &= ~LVIS_SELECTED;
    5845       if ((lpLVItem->stateMask & LVIS_SELECTED) &&
    5846           LISTVIEW_IsSelected(hwnd,lpLVItem->iItem))
    5847          lpLVItem->state |= LVIS_SELECTED;
    5848     }
    5849 
    5850     if (lpLVItem->mask & LVIF_PARAM)
    5851       lpLVItem->lParam = lpItem->lParam;
    5852 
    5853     if (lpLVItem->mask & LVIF_INDENT)
    5854       lpLVItem->iIndent = lpItem->iIndent;
    5855   }
    5856 
    5857   return TRUE;
    5858 }
    5859 
    5860 /* LISTVIEW_GetHotCursor */
    5861 
    5862 /***
    5863  * DESCRIPTION:
    5864  * Retrieves the index of the hot item.
    5865  *
    5866  * PARAMETERS:
    5867  * [I] HWND  : window handle
    5868  *
    5869  * RETURN:
    5870  *   SUCCESS : hot item index
    5871  *   FAILURE : -1 (no hot item)
    5872  */
    5873 static LRESULT LISTVIEW_GetHotItem(HWND hwnd)
    5874 {
    5875   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    5876 
    5877   return infoPtr->nHotItem;
    5878 }
    5879 
    5880 /* LISTVIEW_GetHoverTime */
    5881 
    5882 /***
    5883  * DESCRIPTION:
    5884  * Retrieves the number of items in the listview control.
    5885  *
    5886  * PARAMETER(S):
    5887  * [I] HWND : window handle
    5888  *
    5889  * RETURN:
    5890  * Number of items.
    5891  */
    5892 static LRESULT LISTVIEW_GetItemCount(HWND hwnd)
    5893 {
    5894   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    5895 
    5896   return GETITEMCOUNT(infoPtr);
    5897 }
    5898 
    5899 /***
    5900  * DESCRIPTION:
    5901  * Retrieves the rectangle enclosing the item icon and text.
    5902  *
    5903  * PARAMETER(S):
    5904  * [I] HWND : window handle
    5905  * [I] INT : item index
    5906  * [O] LPRECT : coordinate information
     4868 *
     4869 * NOTE:
     4870 *   This is the internal 'GetItem' interface -- it tries to
     4871 *   be smart, and avoids text copies, if possible, by modifing
     4872 *   lpLVItem->pszText to point to the text string. Please note
     4873 *   that this is not always possible (e.g. OWNERDATA), so on
     4874 *   entry you *must* supply valid values for pszText, and cchTextMax.
     4875 *   The only difference to the documented interface is that upon
     4876 *   return, you should use *only* the lpLVItem->pszText, rather than
     4877 *   the buffer pointer you provided on input. Most code already does
     4878 *   that, so it's not a problem.
     4879 *   For the two cases when the text must be copied (that is,
     4880 *   for LVM_GETITEM, and LVMGETITEMTEXT), use LISTVIEW_GetItemExtT.
    59074881 *
    59084882 * RETURN:
     
    59104884 *   FAILURE : FALSE
    59114885 */
    5912 static BOOL LISTVIEW_GetItemBoundBox(HWND hwnd, INT nItem, LPRECT lpRect)
    5913 {
    5914   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    5915   LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    5916   UINT uView = lStyle & LVS_TYPEMASK;
    5917   BOOL bResult = FALSE;
    5918   HDPA hdpaSubItems;
    5919   LISTVIEW_ITEM *lpItem;
    5920   INT nCountPerColumn;
    5921   INT nRow;
    5922 
    5923   TRACE("(hwnd=%x,nItem=%d,lpRect=%p)\n", hwnd, nItem, lpRect);
     4886static BOOL LISTVIEW_GetItemT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
     4887{
     4888    ITEMHDR callbackHdr = { LPSTR_TEXTCALLBACKW, I_IMAGECALLBACK };
     4889    NMLVDISPINFOW dispInfo;
     4890    ITEM_INFO *lpItem;
     4891    ITEMHDR* pItemHdr;
     4892    HDPA hdpaSubItems;
     4893
     4894    TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW);
     4895
     4896    if (!lpLVItem || lpLVItem->iItem < 0 || lpLVItem->iItem >= infoPtr->nItemCount)
     4897        return FALSE;
     4898
     4899    if (lpLVItem->mask == 0) return TRUE;
     4900
     4901    /* a quick optimization if all we're asked is the focus state
     4902     * these queries are worth optimising since they are common,
     4903     * and can be answered in constant time, without the heavy accesses */
     4904    if ( (lpLVItem->mask == LVIF_STATE) && (lpLVItem->stateMask == LVIS_FOCUSED) &&
     4905         !(infoPtr->uCallbackMask & LVIS_FOCUSED) )
     4906    {
     4907        lpLVItem->state = 0;
     4908        if (infoPtr->nFocusedItem == lpLVItem->iItem)
     4909            lpLVItem->state |= LVIS_FOCUSED;
     4910        return TRUE;
     4911    }
     4912
     4913    ZeroMemory(&dispInfo, sizeof(dispInfo));
     4914
     4915    /* if the app stores all the data, handle it separately */
     4916    if (infoPtr->dwStyle & LVS_OWNERDATA)
     4917    {
     4918        dispInfo.item.state = 0;
     4919
     4920        /* apprently, we should not callback for lParam in LVS_OWNERDATA */
     4921        if ((lpLVItem->mask & ~(LVIF_STATE | LVIF_PARAM)) || infoPtr->uCallbackMask)
     4922        {
     4923            /* NOTE: copy only fields which we _know_ are initialized, some apps
     4924             *       depend on the uninitialized fields being 0 */
     4925            dispInfo.item.mask = lpLVItem->mask & ~LVIF_PARAM;
     4926            dispInfo.item.iItem = lpLVItem->iItem;
     4927            dispInfo.item.iSubItem = lpLVItem->iSubItem;
     4928            if (lpLVItem->mask & LVIF_TEXT)
     4929            {
     4930                dispInfo.item.pszText = lpLVItem->pszText;
     4931                dispInfo.item.cchTextMax = lpLVItem->cchTextMax;               
     4932            }
     4933            if (lpLVItem->mask & LVIF_STATE)
     4934                dispInfo.item.stateMask = lpLVItem->stateMask & infoPtr->uCallbackMask;
     4935            notify_dispinfoT(infoPtr, LVN_GETDISPINFOW, &dispInfo, isW);
     4936            dispInfo.item.stateMask = lpLVItem->stateMask;
     4937            if (lpLVItem->mask & (LVIF_GROUPID|LVIF_COLUMNS))
     4938            {
     4939                /* full size structure expected - _WIN32IE >= 0x560 */
     4940                *lpLVItem = dispInfo.item;
     4941            }
     4942            else if (lpLVItem->mask & LVIF_INDENT)
     4943            {
     4944                /* indent member expected - _WIN32IE >= 0x300 */
     4945                memcpy(lpLVItem, &dispInfo.item, offsetof( LVITEMW, iGroupId ));
     4946            }
     4947            else
     4948            {
     4949                /* minimal structure expected */
     4950                memcpy(lpLVItem, &dispInfo.item, offsetof( LVITEMW, iIndent ));
     4951            }
     4952            TRACE("   getdispinfo(1):lpLVItem=%s\n", debuglvitem_t(lpLVItem, isW));
     4953        }
     4954       
     4955        /* make sure lParam is zeroed out */
     4956        if (lpLVItem->mask & LVIF_PARAM) lpLVItem->lParam = 0;
     4957       
     4958        /* we store only a little state, so if we're not asked, we're done */
     4959        if (!(lpLVItem->mask & LVIF_STATE) || lpLVItem->iSubItem) return TRUE;
     4960
     4961        /* if focus is handled by us, report it */
     4962        if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED )
     4963        {
     4964            lpLVItem->state &= ~LVIS_FOCUSED;
     4965            if (infoPtr->nFocusedItem == lpLVItem->iItem)
     4966                lpLVItem->state |= LVIS_FOCUSED;
     4967        }
     4968
     4969        /* and do the same for selection, if we handle it */
     4970        if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED )
     4971        {
     4972            lpLVItem->state &= ~LVIS_SELECTED;
     4973            if (ranges_contain(infoPtr->selectionRanges, lpLVItem->iItem))
     4974                lpLVItem->state |= LVIS_SELECTED;
     4975        }
     4976       
     4977        return TRUE;
     4978    }
     4979
     4980    /* find the item and subitem structures before we proceed */
     4981    hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
     4982    lpItem = (ITEM_INFO *)DPA_GetPtr(hdpaSubItems, 0);
     4983    assert (lpItem);
     4984
     4985    if (lpLVItem->iSubItem)
     4986    {
     4987        SUBITEM_INFO *lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem);
     4988        pItemHdr = lpSubItem ? &lpSubItem->hdr : &callbackHdr;
     4989    }
     4990    else
     4991        pItemHdr = &lpItem->hdr;
     4992
     4993    /* Do we need to query the state from the app? */
     4994    if ((lpLVItem->mask & LVIF_STATE) && infoPtr->uCallbackMask && lpLVItem->iSubItem == 0)
     4995    {
     4996        dispInfo.item.mask |= LVIF_STATE;
     4997        dispInfo.item.stateMask = infoPtr->uCallbackMask;
     4998    }
    59244999 
    5925   if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
    5926       (lpRect != NULL))
    5927   {
    5928     if (uView == LVS_LIST)
    5929     {
    5930       bResult = TRUE;
    5931       nItem = nItem - ListView_GetTopIndex(hwnd);
    5932       nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
    5933       if (nItem < 0)
    5934       {
    5935         nRow = nItem % nCountPerColumn;
    5936         if (nRow == 0)
    5937         {
    5938           lpRect->left = nItem / nCountPerColumn * infoPtr->nItemWidth;
    5939           lpRect->top = 0;
     5000    /* Do we need to enquire about the image? */
     5001    if ((lpLVItem->mask & LVIF_IMAGE) && pItemHdr->iImage == I_IMAGECALLBACK)
     5002        dispInfo.item.mask |= LVIF_IMAGE;
     5003
     5004    /* Apps depend on calling back for text if it is NULL or LPSTR_TEXTCALLBACKW */
     5005    if ((lpLVItem->mask & LVIF_TEXT) && !is_textW(pItemHdr->pszText))
     5006    {
     5007        dispInfo.item.mask |= LVIF_TEXT;
     5008        dispInfo.item.pszText = lpLVItem->pszText;
     5009        dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
     5010        if (dispInfo.item.pszText && dispInfo.item.cchTextMax > 0)
     5011            *dispInfo.item.pszText = '\0';
     5012    }
     5013
     5014    /* If we don't have all the requested info, query the application */
     5015    if (dispInfo.item.mask != 0)
     5016    {
     5017        dispInfo.item.iItem = lpLVItem->iItem;
     5018        dispInfo.item.iSubItem = lpLVItem->iSubItem;
     5019        dispInfo.item.lParam = lpItem->lParam;
     5020        notify_dispinfoT(infoPtr, LVN_GETDISPINFOW, &dispInfo, isW);
     5021        TRACE("   getdispinfo(2):item=%s\n", debuglvitem_t(&dispInfo.item, isW));
     5022    }
     5023
     5024    /* we should not store values for subitems */
     5025    if (lpLVItem->iSubItem) dispInfo.item.mask &= ~LVIF_DI_SETITEM;
     5026
     5027    /* Now, handle the iImage field */
     5028    if (dispInfo.item.mask & LVIF_IMAGE)
     5029    {
     5030        lpLVItem->iImage = dispInfo.item.iImage;
     5031        if ((dispInfo.item.mask & LVIF_DI_SETITEM) && pItemHdr->iImage == I_IMAGECALLBACK)
     5032            pItemHdr->iImage = dispInfo.item.iImage;
     5033    }
     5034    else if (lpLVItem->mask & LVIF_IMAGE)
     5035        lpLVItem->iImage = pItemHdr->iImage;
     5036
     5037    /* The pszText field */
     5038    if (dispInfo.item.mask & LVIF_TEXT)
     5039    {
     5040        if ((dispInfo.item.mask & LVIF_DI_SETITEM) && pItemHdr->pszText)
     5041            textsetptrT(&pItemHdr->pszText, dispInfo.item.pszText, isW);
     5042
     5043        lpLVItem->pszText = dispInfo.item.pszText;
     5044    }
     5045    else if (lpLVItem->mask & LVIF_TEXT)
     5046    {
     5047        if (isW) lpLVItem->pszText = pItemHdr->pszText;
     5048        else textcpynT(lpLVItem->pszText, isW, pItemHdr->pszText, TRUE, lpLVItem->cchTextMax);
     5049    }
     5050
     5051    /* if this is a subitem, we're done */
     5052    if (lpLVItem->iSubItem) return TRUE;
     5053 
     5054    /* Next is the lParam field */
     5055    if (dispInfo.item.mask & LVIF_PARAM)
     5056    {
     5057        lpLVItem->lParam = dispInfo.item.lParam;
     5058        if ((dispInfo.item.mask & LVIF_DI_SETITEM))
     5059            lpItem->lParam = dispInfo.item.lParam;
     5060    }
     5061    else if (lpLVItem->mask & LVIF_PARAM)
     5062        lpLVItem->lParam = lpItem->lParam;
     5063
     5064    /* ... the state field (this one is different due to uCallbackmask) */
     5065    if (lpLVItem->mask & LVIF_STATE)
     5066    {
     5067        lpLVItem->state = lpItem->state;
     5068        if (dispInfo.item.mask & LVIF_STATE)
     5069        {
     5070            lpLVItem->state &= ~dispInfo.item.stateMask;
     5071            lpLVItem->state |= (dispInfo.item.state & dispInfo.item.stateMask);
     5072        }
     5073        if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED )
     5074        {
     5075            lpLVItem->state &= ~LVIS_FOCUSED;
     5076            if (infoPtr->nFocusedItem == lpLVItem->iItem)
     5077                lpLVItem->state |= LVIS_FOCUSED;
    59405078        }
    5941         else
    5942         {
    5943           lpRect->left = (nItem / nCountPerColumn -1) * infoPtr->nItemWidth;
    5944           lpRect->top = (nRow + nCountPerColumn) * infoPtr->nItemHeight;
    5945         }
    5946       }
    5947       else
    5948       {
    5949         lpRect->left = nItem / nCountPerColumn * infoPtr->nItemWidth;
    5950         lpRect->top = nItem % nCountPerColumn * infoPtr->nItemHeight;
    5951       }
    5952     }
    5953     else if (uView == LVS_REPORT)
    5954     {
    5955       bResult = TRUE;
    5956       lpRect->left = REPORT_MARGINX;
    5957       lpRect->top = ((nItem - ListView_GetTopIndex(hwnd)) *
    5958                          infoPtr->nItemHeight) + infoPtr->rcList.top;
    5959 
    5960       if (!(lStyle & LVS_NOSCROLL))
    5961       {
    5962         SCROLLINFO scrollInfo;
    5963         /* Adjust position by scrollbar offset */
    5964         ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
    5965         scrollInfo.cbSize = sizeof(SCROLLINFO);
    5966         scrollInfo.fMask = SIF_POS;
    5967         GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
    5968         lpRect->left -= scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
    5969       }
    5970     }
    5971     else /* either LVS_ICON or LVS_SMALLICON */
    5972     {
    5973       if ((hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
    5974       {
    5975         if ((lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
    5976         {
    5977           bResult = TRUE;
    5978           lpRect->left = lpItem->ptPosition.x;
    5979           lpRect->top = lpItem->ptPosition.y;
    5980         }
    5981       }
    5982     }
    5983   }
    5984   lpRect->right = lpRect->left + infoPtr->nItemWidth;
    5985   lpRect->bottom = lpRect->top + infoPtr->nItemHeight;
    5986   TRACE("result %s: (%d,%d)-(%d,%d)\n", bResult ? "TRUE" : "FALSE",
    5987         lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);
    5988   return bResult;
    5989 }
     5079        if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED )
     5080        {
     5081            lpLVItem->state &= ~LVIS_SELECTED;
     5082            if (ranges_contain(infoPtr->selectionRanges, lpLVItem->iItem))
     5083                lpLVItem->state |= LVIS_SELECTED;
     5084        }           
     5085    }
     5086
     5087    /* and last, but not least, the indent field */
     5088    if (lpLVItem->mask & LVIF_INDENT)
     5089        lpLVItem->iIndent = lpItem->iIndent;
     5090
     5091    return TRUE;
     5092}
     5093
     5094/***
     5095 * DESCRIPTION:
     5096 * Retrieves item attributes.
     5097 *
     5098 * PARAMETER(S):
     5099 * [I] hwnd : window handle
     5100 * [IO] lpLVItem : item info
     5101 * [I] isW : if TRUE, then lpLVItem is a LPLVITEMW,
     5102 *           if FALSE, the lpLVItem is a LPLVITEMA.
     5103 *
     5104 * NOTE:
     5105 *   This is the external 'GetItem' interface -- it properly copies
     5106 *   the text in the provided buffer.
     5107 *
     5108 * RETURN:
     5109 *   SUCCESS : TRUE
     5110 *   FAILURE : FALSE
     5111 */
     5112static BOOL LISTVIEW_GetItemExtT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
     5113{
     5114    LPWSTR pszText;
     5115    BOOL bResult;
     5116
     5117    if (!lpLVItem || lpLVItem->iItem < 0 || lpLVItem->iItem >= infoPtr->nItemCount)
     5118        return FALSE;
     5119
     5120    pszText = lpLVItem->pszText;
     5121    bResult = LISTVIEW_GetItemT(infoPtr, lpLVItem, isW);
     5122    if (bResult && lpLVItem->pszText != pszText)
     5123        textcpynT(pszText, isW, lpLVItem->pszText, isW, lpLVItem->cchTextMax);
     5124    lpLVItem->pszText = pszText;
     5125
     5126    return bResult;
     5127}
     5128
    59905129
    59915130/***
     
    59965135 *
    59975136 * PARAMETER(S):
    5998  * [I] HWND : window handle
    5999  * [I] INT : item index
    6000  * [O] LPPOINT : coordinate information
     5137 * [I] infoPtr : valid pointer to the listview structure
     5138 * [I] nItem : item index
     5139 * [O] lpptPosition : coordinate information
    60015140 *
    60025141 * RETURN:
     
    60045143 *   FAILURE : FALSE
    60055144 */
    6006 static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem, LPPOINT lpptPosition)
    6007 {
    6008   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
    6009   UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
    6010   BOOL bResult = FALSE;
    6011   RECT rcBounding;
    6012 
    6013   TRACE("(hwnd=%x, nItem=%d, lpptPosition=%p)\n", hwnd, nItem, lpptPosition);
    6014 
    6015   if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
    6016       (lpptPosition != NULL))
    6017   {
    6018     bResult = LISTVIEW_GetItemBoundBox(hwnd, nItem, &rcBounding);
    6019     lpptPosition->x = rcBounding.left;
    6020     lpptPosition->y = rcBounding.top;
    6021     if (uView == LVS_ICON)
    6022     {
    6023        lpptPosition->y += ICON_TOP_PADDING;
    6024        lpptPosition->x += (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
    6025     }
    6026     TRACE("result %s (%ld,%ld)\n", bResult ? "TRUE" : "FALSE",
    6027           lpptPosition->x, lpptPosition->y);
    6028    }
    6029    return bResult;
    6030 }
    6031 
    6032 /***
    6033  * Update the bounding rectangle around the text under a large icon.
    6034  * This depends on whether it has the focus or not.
    6035  * On entry the rectangle's top, left and right should be set.
    6036  * On return the bottom will also be set and the width may have been
    6037  * modified.
    6038  *
    6039  * This appears to be weird, even in the Microsoft implementation.
    6040  */
    6041 
    6042 static void ListView_UpdateLargeItemLabelRect (
    6043         HWND hwnd,                    /* The window of the listview */
    6044         const LISTVIEW_INFO *infoPtr, /* The listview itself */
    6045         int nItem, /* The item for which we are calculating this */
    6046         RECT *rect) /* The rectangle to be updated */
    6047 {
    6048     HDC hdc = GetDC (hwnd);
    6049     HFONT hOldFont = SelectObject (hdc, infoPtr->hFont);
    6050 
    6051     if (infoPtr->bFocus && infoPtr->nFocusedItem == nItem)
    6052     {
    6053         /* We (aim to) display the full text.  In Windows 95 it appears to
    6054          * calculate the size assuming the specified font and then it draws
    6055          * the text in that region with the specified font except scaled to
    6056          * 10 point (or the height of the system font or ...).  Thus if the
    6057          * window has 24 point Helvetica the highlit rectangle will be
    6058          * taller than the text and if it is 7 point Helvetica then the text
    6059          * will be clipped.
    6060          * For now we will simply say that it is the correct size to display
    6061          * the text in the specified font.
    6062          */
    6063         LVITEMW lvItem;
    6064         lvItem.mask = LVIF_TEXT;
    6065         lvItem.iItem = nItem;
    6066         lvItem.iSubItem = 0;
    6067         /* We will specify INTERNAL and so will receive back a const
    6068          * pointer to the text, rather than specifying a buffer to which
    6069          * to copy it.
    6070          */
    6071         LISTVIEW_GetItemW (hwnd, &lvItem, TRUE);
    6072         DrawTextW (hdc, lvItem.pszText, -1, rect, DT_CALCRECT |
    6073                         DT_NOCLIP | DT_EDITCONTROL | DT_TOP | DT_CENTER |
    6074                         DT_WORDBREAK | DT_NOPREFIX);
    6075         /* Maintain this DT_* list in line with LISTVIEW_DrawLargeItem */
    6076     }
    6077     else
    6078     {
    6079         /* As far as I can see the text region seems to be trying to be
    6080          * "tall enough for two lines of text".  Once again (comctl32.dll ver
    6081          * 5.81?) it measures this on the basis of the selected font and then
    6082          * draws it with the same font except in 10 point size.  This can lead
    6083          * to more or less than the two rows appearing.
    6084          * Question; are we  supposed to be including DT_EXTERNALLEADING?
    6085          * Question; should the width be shrunk to the space required to
    6086          * display the two lines?
    6087          */
    6088         rect->bottom = rect->top + 2 * infoPtr->ntmHeight;
    6089     }
    6090 
    6091     SelectObject (hdc, hOldFont);
    6092     ReleaseDC (hwnd, hdc);
    6093 }
     5145static BOOL LISTVIEW_GetItemPosition(LISTVIEW_INFO *infoPtr, INT nItem, LPPOINT lpptPosition)
     5146{
     5147    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     5148    POINT Origin;
     5149
     5150    TRACE("(nItem=%d, lpptPosition=%p)\n", nItem, lpptPosition);
     5151
     5152    if (!lpptPosition || nItem < 0 || nItem >= infoPtr->nItemCount) return FALSE;
     5153
     5154    LISTVIEW_GetOrigin(infoPtr, &Origin);
     5155    LISTVIEW_GetItemOrigin(infoPtr, nItem, lpptPosition);
     5156
     5157    if (uView == LVS_ICON)
     5158    {
     5159        lpptPosition->x += (infoPtr->nItemWidth - infoPtr->iconSize.cx) / 2;
     5160        lpptPosition->y += ICON_TOP_PADDING;
     5161    }
     5162    lpptPosition->x += Origin.x;
     5163    lpptPosition->y += Origin.y;
     5164   
     5165    TRACE ("  lpptPosition=%s\n", debugpoint(lpptPosition));
     5166    return TRUE;
     5167}
     5168
    60945169
    60955170/***
    60965171 * DESCRIPTION:
    60975172 * Retrieves the bounding rectangle for a listview control item.
    6098  * 
    6099  * PARAMETER(S):
    6100  * [I] HWND : window handle
    6101  * [I] INT : item index
    6102  * [IO] LPRECT : bounding rectangle coordinates
     5173 *
     5174 * PARAMETER(S):
     5175 * [I] infoPtr : valid pointer to the listview structure
     5176 * [I] nItem : item index
     5177 * [IO] lprc : bounding rectangle coordinates
    61035178 *     lprc->left specifies the portion of the item for which the bounding
    61045179 *     rectangle will be retrieved.
     
    61065181 *     LVIR_BOUNDS Returns the bounding rectangle of the entire item,
    61075182 *        including the icon and label.
     5183 *         *
     5184 *         * For LVS_ICON
     5185 *         * Experiment shows that native control returns:
     5186 *         *  width = min (48, length of text line)
     5187 *         *    .left = position.x - (width - iconsize.cx)/2
     5188 *         *    .right = .left + width
     5189 *         *  height = #lines of text * ntmHeight + icon height + 8
     5190 *         *    .top = position.y - 2
     5191 *         *    .bottom = .top + height
     5192 *         *  separation between items .y = itemSpacing.cy - height
     5193 *         *                           .x = itemSpacing.cx - width
    61085194 *     LVIR_ICON Returns the bounding rectangle of the icon or small icon.
     5195 *         *
     5196 *         * For LVS_ICON
     5197 *         * Experiment shows that native control returns:
     5198 *         *  width = iconSize.cx + 16
     5199 *         *    .left = position.x - (width - iconsize.cx)/2
     5200 *         *    .right = .left + width
     5201 *         *  height = iconSize.cy + 4
     5202 *         *    .top = position.y - 2
     5203 *         *    .bottom = .top + height
     5204 *         *  separation between items .y = itemSpacing.cy - height
     5205 *         *                           .x = itemSpacing.cx - width
    61095206 *     LVIR_LABEL Returns the bounding rectangle of the item text.
     5207 *         *
     5208 *         * For LVS_ICON
     5209 *         * Experiment shows that native control returns:
     5210 *         *  width = text length
     5211 *         *    .left = position.x - width/2
     5212 *         *    .right = .left + width
     5213 *         *  height = ntmH * linecount + 2
     5214 *         *    .top = position.y + iconSize.cy + 6
     5215 *         *    .bottom = .top + height
     5216 *         *  separation between items .y = itemSpacing.cy - height
     5217 *         *                           .x = itemSpacing.cx - width
    61105218 *     LVIR_SELECTBOUNDS Returns the union of the LVIR_ICON and LVIR_LABEL
    61115219 *      rectangles, but excludes columns in report view.
    6112  * 
     5220 *
    61135221 * RETURN:
    61145222 *   SUCCESS : TRUE
     
    61185226 *   Note that the bounding rectangle of the label in the LVS_ICON view depends
    61195227 *   upon whether the window has the focus currently and on whether the item
    6120  *   is the one with the focus.  Ensure that the control's record of which 
     5228 *   is the one with the focus.  Ensure that the control's record of which
    61215229 *   item has the focus agrees with the items' records.
    61225230 */
    6123 static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc)
    6124 {
    6125   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    6126   UINT uView = GetWindowLongW(hwnd, GWL_STYLE) & LVS_TYPEMASK;
    6127   BOOL bResult = FALSE;
    6128   POINT ptOrigin;
    6129   POINT ptItem;
    6130   INT nLeftPos;
    6131   INT nLabelWidth;
    6132   INT nIndent;
    6133   LVITEMW lvItem;
    6134   RECT rcInternal;
    6135 
    6136   TRACE("(hwnd=%x, nItem=%d, lprc=%p)\n", hwnd, nItem, lprc);
    6137 
    6138   if (uView & LVS_REPORT)
    6139   {
    6140     ZeroMemory(&lvItem, sizeof(lvItem));
    6141     lvItem.mask = LVIF_INDENT;
     5231static BOOL LISTVIEW_GetItemRect(LISTVIEW_INFO *infoPtr, INT nItem, LPRECT lprc)
     5232{
     5233    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     5234    WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
     5235    BOOL doLabel = TRUE, oversizedBox = FALSE;
     5236    POINT Position, Origin;
     5237    LVITEMW lvItem;
     5238    RECT label_rect;
     5239
     5240    TRACE("(hwnd=%p, nItem=%d, lprc=%p)\n", infoPtr->hwndSelf, nItem, lprc);
     5241
     5242    if (!lprc || nItem < 0 || nItem >= infoPtr->nItemCount) return FALSE;
     5243
     5244    LISTVIEW_GetOrigin(infoPtr, &Origin);
     5245    LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position);
     5246
     5247    /* Be smart and try to figure out the minimum we have to do */
     5248    if (lprc->left == LVIR_ICON) doLabel = FALSE;
     5249    if (uView == LVS_REPORT && lprc->left == LVIR_BOUNDS) doLabel = FALSE;
     5250    if (uView == LVS_ICON && lprc->left != LVIR_ICON &&
     5251        infoPtr->bFocus && LISTVIEW_GetItemState(infoPtr, nItem, LVIS_FOCUSED))
     5252        oversizedBox = TRUE;
     5253
     5254    /* get what we need from the item before hand, so we make
     5255     * only one request. This can speed up things, if data
     5256     * is stored on the app side */
     5257    lvItem.mask = 0;
     5258    if (uView == LVS_REPORT) lvItem.mask |= LVIF_INDENT;
     5259    if (doLabel) lvItem.mask |= LVIF_TEXT;
    61425260    lvItem.iItem = nItem;
    61435261    lvItem.iSubItem = 0;
    6144     LISTVIEW_GetItemW(hwnd, &lvItem, TRUE);
    6145 
    6146     /* do indent */
    6147     if (lvItem.iIndent>0 && infoPtr->iconSize.cx > 0)
    6148       nIndent = infoPtr->iconSize.cx * lvItem.iIndent;
    6149     else
    6150       nIndent = 0;
    6151   }
    6152   else
    6153     nIndent = 0;
    6154  
    6155   if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL))
    6156   {
    6157       switch(lprc->left) 
    6158       { 
    6159       case LVIR_ICON:
    6160         if (!ListView_GetItemPosition(hwnd, nItem, &ptItem)) break;
    6161         if (uView == LVS_ICON)
    6162         {
    6163           if (infoPtr->himlNormal != NULL)
    6164           {
    6165             if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
    6166             {
    6167               bResult = TRUE;
    6168               lprc->left = ptItem.x + ptOrigin.x;
    6169               lprc->top = ptItem.y + ptOrigin.y;
    6170               lprc->right = lprc->left + infoPtr->iconSize.cx;
    6171               lprc->bottom = (lprc->top + infoPtr->iconSize.cy +
    6172                               ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
    6173             }
    6174           }
    6175         }
    6176         else if (uView == LVS_SMALLICON)
    6177         {
    6178           if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
    6179           {
    6180             bResult = TRUE;
    6181             lprc->left = ptItem.x + ptOrigin.x;
    6182             lprc->top = ptItem.y + ptOrigin.y;
    6183             lprc->bottom = lprc->top + infoPtr->nItemHeight;
    6184 
    6185             if (infoPtr->himlState != NULL)
    6186               lprc->left += infoPtr->iconSize.cx;
    6187              
    6188             if (infoPtr->himlSmall != NULL)
    6189               lprc->right = lprc->left + infoPtr->iconSize.cx;
    6190             else
    6191               lprc->right = lprc->left;
    6192           }
    6193         }
    6194         else
    6195         {
    6196           bResult = TRUE;
    6197           lprc->left = ptItem.x;
    6198           if (uView & LVS_REPORT)
    6199             lprc->left += nIndent;
    6200           lprc->top = ptItem.y;
    6201           lprc->bottom = lprc->top + infoPtr->nItemHeight;
    6202 
    6203           if (infoPtr->himlState != NULL)
    6204             lprc->left += infoPtr->iconSize.cx;
    6205            
    6206           if (infoPtr->himlSmall != NULL)
    6207             lprc->right = lprc->left + infoPtr->iconSize.cx;
    6208           else
    6209             lprc->right = lprc->left;
    6210         }
     5262    lvItem.pszText = szDispText;
     5263    lvItem.cchTextMax = DISP_TEXT_SIZE;
     5264    if (lvItem.mask && !LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE;
     5265    /* we got the state already up, simulate it here, to avoid a reget */
     5266    if (uView == LVS_ICON && (lprc->left != LVIR_ICON))
     5267    {
     5268        lvItem.mask |= LVIF_STATE;
     5269        lvItem.stateMask = LVIS_FOCUSED;
     5270        lvItem.state = (oversizedBox ? LVIS_FOCUSED : 0);
     5271    }
     5272
     5273    if (uView == LVS_REPORT && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) && lprc->left == LVIR_SELECTBOUNDS)
     5274        lprc->left = LVIR_BOUNDS;
     5275    switch(lprc->left)
     5276    {
     5277    case LVIR_ICON:
     5278        LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, NULL, lprc, NULL);
    62115279        break;
    62125280
    6213       case LVIR_LABEL:
    6214         if (!ListView_GetItemPosition(hwnd, nItem, &ptItem)) break;
    6215         if (uView == LVS_ICON)
    6216         {
    6217           if (infoPtr->himlNormal != NULL)
    6218           {
    6219             if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
    6220             {
    6221               bResult = TRUE;
    6222               lprc->left = ptItem.x + ptOrigin.x;
    6223               lprc->top = (ptItem.y + ptOrigin.y + infoPtr->iconSize.cy +
    6224                            ICON_BOTTOM_PADDING);
    6225               nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
    6226               if (infoPtr->iconSpacing.cx - nLabelWidth > 1)
    6227               {
    6228                 lprc->left += (infoPtr->iconSpacing.cx - nLabelWidth) / 2;
    6229                 lprc->right = lprc->left + nLabelWidth;
    6230               }
    6231               else
    6232               {
    6233                 lprc->left += 1;
    6234                 lprc->right = lprc->left + infoPtr->iconSpacing.cx - 1;
    6235                 ListView_UpdateLargeItemLabelRect (hwnd, infoPtr, nItem, lprc);
    6236               }
    6237             }             
    6238           }
    6239         }
    6240         else if (uView == LVS_SMALLICON)
    6241         {
    6242           if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
    6243           {
    6244             bResult = TRUE;
    6245             nLeftPos = lprc->left = ptItem.x + ptOrigin.x;
    6246             lprc->top = ptItem.y + ptOrigin.y;
    6247             lprc->bottom = lprc->top + infoPtr->nItemHeight;
    6248            
    6249             if (infoPtr->himlState != NULL)
    6250               lprc->left += infoPtr->iconSize.cx;
    6251            
    6252             if (infoPtr->himlSmall != NULL)
    6253               lprc->left += infoPtr->iconSize.cx;
    6254            
    6255             nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
    6256             nLabelWidth += TRAILING_PADDING;
    6257             if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
    6258               lprc->right = lprc->left + nLabelWidth;
    6259             else
    6260               lprc->right = nLeftPos + infoPtr->nItemWidth;
    6261           }
    6262         }
    6263         else
    6264         {
    6265           bResult = TRUE;
    6266           if (uView == LVS_REPORT)
    6267             nLeftPos = lprc->left = ptItem.x + nIndent;
    6268           else
    6269             nLeftPos = lprc->left = ptItem.x;
    6270           lprc->top = ptItem.y;
    6271           lprc->bottom = lprc->top + infoPtr->nItemHeight;
    6272 
    6273           if (infoPtr->himlState != NULL)
    6274             lprc->left += infoPtr->iconSize.cx;
    6275 
    6276           if (infoPtr->himlSmall != NULL)
    6277             lprc->left += infoPtr->iconSize.cx;
    6278 
    6279           if (uView != LVS_REPORT)
    6280           {
    6281             nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
    6282             nLabelWidth += TRAILING_PADDING;
    6283             if (infoPtr->himlSmall)
    6284               nLabelWidth += IMAGE_PADDING;
    6285           }
    6286           else
    6287             nLabelWidth = LISTVIEW_GetColumnWidth(hwnd, 0)-lprc->left;
    6288           if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
    6289             lprc->right = lprc->left + nLabelWidth;
    6290           else
    6291             lprc->right = nLeftPos + infoPtr->nItemWidth;
    6292         }
     5281    case LVIR_LABEL:
     5282        LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, NULL, NULL, lprc);
    62935283        break;
    62945284
    6295       case LVIR_BOUNDS:
    6296         if (!LISTVIEW_GetItemBoundBox(hwnd, nItem, &rcInternal)) break;
    6297         ptItem.x = rcInternal.left;
    6298         ptItem.y = rcInternal.top;
    6299         if (uView == LVS_ICON)
    6300         {
    6301           if (infoPtr->himlNormal != NULL)
    6302           {
    6303             if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
    6304             {
    6305               RECT label_rect;
    6306               INT text_left, text_right, icon_left, text_pos_x;
    6307               /* for style LVS_ICON bounds
    6308                *            left = min(icon.left, text.left)
    6309                *            right = max(icon.right, text.right)
    6310                *            top = boundbox.top + NOTHITABLE
    6311                *            bottom = text.bottom + 1
    6312                */
    6313               bResult = TRUE;
    6314               icon_left = text_left = ptItem.x;
    6315  
    6316               /* Correct ptItem to icon upper-left */
    6317               icon_left += (infoPtr->nItemWidth - infoPtr->iconSize.cx)/2;
    6318               ptItem.y += ICON_TOP_PADDING;
    6319  
    6320               /* Compute the label left and right */
    6321                nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
    6322                text_pos_x = infoPtr->iconSpacing.cx - 2*CAPTION_BORDER - nLabelWidth;
    6323                if (text_pos_x > 1)
    6324                {
    6325                  text_left += text_pos_x / 2;
    6326                  text_right = text_left + nLabelWidth + 2*CAPTION_BORDER;
    6327                }
    6328                else
    6329                {
    6330                  text_left += 1;
    6331                  text_right = text_left + infoPtr->iconSpacing.cx - 1;
    6332                }
    6333  
    6334               /* Compute rectangle w/o the text height */
    6335                lprc->left = min(icon_left, text_left) + ptOrigin.x;
    6336                lprc->right = max(icon_left + infoPtr->iconSize.cx,
    6337                                 text_right) + ptOrigin.x;
    6338                lprc->top = ptItem.y + ptOrigin.y - ICON_TOP_PADDING_HITABLE;
    6339                lprc->bottom = lprc->top + ICON_TOP_PADDING_HITABLE
    6340                              + infoPtr->iconSize.cy + 1
    6341                               + ICON_BOTTOM_PADDING;
    6342  
    6343                CopyRect (&label_rect, lprc);
    6344                label_rect.top = lprc->bottom;
    6345                ListView_UpdateLargeItemLabelRect (hwnd, infoPtr, nItem, &label_rect);
    6346                UnionRect (lprc, lprc, &label_rect);
    6347             }
    6348           }
    6349         }
    6350         else if (uView == LVS_SMALLICON)
    6351         {
    6352           if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
    6353           {
    6354             bResult = TRUE;
    6355             lprc->left = ptItem.x + ptOrigin.x;
    6356             lprc->right = lprc->left;
    6357             lprc->top = ptItem.y + ptOrigin.y;
    6358             lprc->bottom = lprc->top + infoPtr->nItemHeight;
    6359             if (infoPtr->himlState != NULL)
    6360               lprc->right += infoPtr->iconSize.cx;
    6361             if (infoPtr->himlSmall != NULL)
    6362               lprc->right += infoPtr->iconSize.cx;
    6363 
    6364             nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
    6365             nLabelWidth += TRAILING_PADDING;
    6366             if (infoPtr->himlSmall)
    6367               nLabelWidth += IMAGE_PADDING;
    6368             if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
    6369               lprc->right += nLabelWidth;
    6370             else
    6371               lprc->right = lprc->left + infoPtr->nItemWidth;
    6372           }
    6373         }
    6374         else
    6375         {
    6376           bResult = TRUE;
    6377           lprc->left = ptItem.x;
    6378           if (!(infoPtr->dwExStyle&LVS_EX_FULLROWSELECT) && uView&LVS_REPORT)
    6379             lprc->left += nIndent;
    6380           lprc->right = lprc->left;
    6381           lprc->top = ptItem.y;
    6382           lprc->bottom = lprc->top + infoPtr->nItemHeight;
    6383 
    6384           if ((infoPtr->dwExStyle & LVS_EX_FULLROWSELECT) || (uView == LVS_REPORT))
    6385           {
    6386             RECT br;
    6387             int nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
    6388             Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
    6389 #ifdef __WIN32OS2__
    6390       if(GetWindowLongA(hwnd, GWL_STYLE) & LVS_OWNERDRAWFIXED)
    6391             lprc->right = max(lprc->left, br.right);
    6392       else
    6393             lprc->right = max(lprc->left, br.right - REPORT_MARGINX);
    6394 #else
    6395             lprc->right = max(lprc->left, br.right - REPORT_MARGINX);
    6396 #endif
    6397           }
    6398           else
    6399           {
    6400              if (infoPtr->himlState != NULL)
    6401               lprc->right += infoPtr->iconSize.cx;
    6402 
    6403             if (infoPtr->himlSmall != NULL)
    6404               lprc->right += infoPtr->iconSize.cx;
    6405 
    6406             nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
    6407             nLabelWidth += TRAILING_PADDING;
    6408             if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
    6409               lprc->right += nLabelWidth;
    6410             else
    6411               lprc->right = lprc->left + infoPtr->nItemWidth;
    6412           }
    6413         }
     5285    case LVIR_BOUNDS:
     5286        LISTVIEW_GetItemMetrics(infoPtr, &lvItem, lprc, NULL, NULL, NULL);
    64145287        break;
    6415        
    6416       case LVIR_SELECTBOUNDS:
    6417         if (!ListView_GetItemPosition(hwnd, nItem, &ptItem)) break;
    6418         if (uView == LVS_ICON)
    6419         {
    6420           if (infoPtr->himlNormal != NULL)
    6421           {
    6422             if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
    6423             {
    6424               bResult = TRUE;
    6425               lprc->left = ptItem.x + ptOrigin.x;
    6426               lprc->top = ptItem.y + ptOrigin.y;
    6427               lprc->right = lprc->left + infoPtr->iconSpacing.cx;
    6428               lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
    6429             }
    6430           }
    6431         }
    6432         else if (uView == LVS_SMALLICON)
    6433         {
    6434           if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
    6435           {
    6436             bResult = TRUE;
    6437             nLeftPos= lprc->left = ptItem.x + ptOrigin.x; 
    6438             lprc->top = ptItem.y + ptOrigin.y;
    6439             lprc->bottom = lprc->top + infoPtr->nItemHeight;
    6440            
    6441             if (infoPtr->himlState != NULL)
    6442               lprc->left += infoPtr->iconSize.cx;
    6443            
    6444             lprc->right = lprc->left;
    6445            
    6446             if (infoPtr->himlSmall != NULL)
    6447               lprc->right += infoPtr->iconSize.cx;
    6448            
    6449             nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
    6450             nLabelWidth += TRAILING_PADDING;
    6451             if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
    6452               lprc->right += nLabelWidth;
    6453             else
    6454               lprc->right = nLeftPos + infoPtr->nItemWidth;
    6455           }
    6456         }
    6457         else
    6458         {
    6459           bResult = TRUE;
    6460           if (!(infoPtr->dwExStyle&LVS_EX_FULLROWSELECT) && (uView&LVS_REPORT))
    6461             nLeftPos = lprc->left = ptItem.x + nIndent;
    6462           else
    6463             nLeftPos = lprc->left = ptItem.x;
    6464           lprc->top = ptItem.y;
    6465           lprc->bottom = lprc->top + infoPtr->nItemHeight;
    6466 
    6467           if (infoPtr->himlState != NULL)
    6468             lprc->left += infoPtr->iconSize.cx;
    6469          
    6470           lprc->right = lprc->left;
    6471        
    6472           if (infoPtr->dwExStyle & LVS_EX_FULLROWSELECT)
    6473           {
    6474             RECT br;
    6475             int nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
    6476             Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
    6477 
    6478             lprc->right = max(lprc->left, br.right - REPORT_MARGINX);
    6479           }
    6480           else
    6481           {
    6482             if (infoPtr->himlSmall != NULL)
    6483               lprc->right += infoPtr->iconSize.cx;
    6484 
    6485             nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
    6486             nLabelWidth += TRAILING_PADDING;
    6487             if (infoPtr->himlSmall)
    6488               nLabelWidth += IMAGE_PADDING;
    6489             if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
    6490               lprc->right += nLabelWidth;
    6491             else
    6492               lprc->right = nLeftPos + infoPtr->nItemWidth;
    6493           }
    6494         }
     5288
     5289    case LVIR_SELECTBOUNDS:
     5290        LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, NULL, lprc, &label_rect);
     5291        UnionRect(lprc, lprc, &label_rect);
    64955292        break;
    6496       }
    6497   }
    6498 #ifdef __WIN32OS2__
    6499           if(GetWindowLongA(hwnd, GWL_STYLE) & LVS_OWNERDRAWFIXED && lprc->left == REPORT_MARGINX) {
    6500               lprc->left = 0;
    6501           }
    6502 #endif
    6503   TRACE("result %s (%d,%d)-(%d,%d)\n", bResult ? "TRUE" : "FALSE",
    6504         lprc->left, lprc->top, lprc->right, lprc->bottom);
    6505 
    6506   return bResult;
    6507 }
     5293
     5294    default:
     5295        WARN("Unknown value: %ld\n", lprc->left);
     5296        return FALSE;
     5297    }
     5298
     5299    OffsetRect(lprc, Position.x + Origin.x, Position.y + Origin.y);
     5300
     5301    TRACE(" rect=%s\n", debugrect(lprc));
     5302
     5303    return TRUE;
     5304}
     5305
     5306/***
     5307 * DESCRIPTION:
     5308 * Retrieves the spacing between listview control items.
     5309 *
     5310 * PARAMETER(S):
     5311 * [I] infoPtr : valid pointer to the listview structure
     5312 * [IO] lprc : rectangle to receive the output
     5313 *             on input, lprc->top = nSubItem
     5314 *                       lprc->left = LVIR_ICON | LVIR_BOUNDS | LVIR_LABEL
     5315 *
     5316 * NOTE: for subItem = 0, we should return the bounds of the _entire_ item,
     5317 *       not only those of the first column.
     5318 *       Fortunately, LISTVIEW_GetItemMetrics does the right thing.
     5319 *
     5320 * RETURN:
     5321 *     TRUE: success
     5322 *     FALSE: failure
     5323 */
     5324static BOOL LISTVIEW_GetSubItemRect(LISTVIEW_INFO *infoPtr, INT nItem, LPRECT lprc)
     5325{
     5326    POINT Position;
     5327    LVITEMW lvItem;
     5328   
     5329    if (!lprc || (infoPtr->dwStyle & LVS_TYPEMASK) != LVS_REPORT) return FALSE;
     5330   
     5331    TRACE("(nItem=%d, nSubItem=%ld)\n", nItem, lprc->top);
     5332    /* On WinNT, a subitem of '0' calls LISTVIEW_GetItemRect */
     5333    if (lprc->top == 0)
     5334        return LISTVIEW_GetItemRect(infoPtr, nItem, lprc);
     5335
     5336    if (!LISTVIEW_GetItemPosition(infoPtr, nItem, &Position)) return FALSE;
     5337
     5338    lvItem.mask = lprc->top == 0 ? LVIF_INDENT : 0;
     5339    lvItem.iItem = nItem;
     5340    lvItem.iSubItem = lprc->top;
     5341   
     5342    if (lvItem.mask && !LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE;
     5343    switch(lprc->left)
     5344    {
     5345    case LVIR_ICON:
     5346        LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, NULL, lprc, NULL);
     5347        break;
     5348
     5349    case LVIR_LABEL:
     5350    case LVIR_BOUNDS:
     5351        LISTVIEW_GetItemMetrics(infoPtr, &lvItem, lprc, NULL, NULL, NULL);
     5352        break;
     5353
     5354    default:
     5355        ERR("Unknown bounds=%ld\n", lprc->left);
     5356        return FALSE;
     5357    }
     5358
     5359    OffsetRect(lprc, Position.x, Position.y);
     5360    return TRUE;
     5361}
     5362
    65085363
    65095364/***
    65105365 * DESCRIPTION:
    65115366 * Retrieves the width of a label.
    6512  * 
    6513  * PARAMETER(S):
    6514  * [I] HWND : window handle
    6515  * 
     5367 *
     5368 * PARAMETER(S):
     5369 * [I] infoPtr : valid pointer to the listview structure
     5370 *
    65165371 * RETURN:
    65175372 *   SUCCESS : string width (in pixels)
    65185373 *   FAILURE : zero
    65195374 */
    6520 static INT LISTVIEW_GetLabelWidth(HWND hwnd, INT nItem)
    6521 {
    6522   WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
    6523   INT nLabelWidth = 0;
    6524   LVITEMW lvItem;
    6525 
    6526   TRACE("(hwnd=%x, nItem=%d)\n", hwnd, nItem);
    6527 
    6528   ZeroMemory(&lvItem, sizeof(lvItem));
    6529   lvItem.mask = LVIF_TEXT;
    6530   lvItem.iItem = nItem;
    6531   lvItem.cchTextMax = DISP_TEXT_SIZE;
    6532   lvItem.pszText = szDispText;
    6533   if (LISTVIEW_GetItemW(hwnd, &lvItem, TRUE))
    6534     nLabelWidth = ListView_GetStringWidthW(hwnd, lvItem.pszText);
    6535    
    6536   return nLabelWidth;
     5375static INT LISTVIEW_GetLabelWidth(LISTVIEW_INFO *infoPtr, INT nItem)
     5376{
     5377    WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
     5378    LVITEMW lvItem;
     5379
     5380    TRACE("(nItem=%d)\n", nItem);
     5381
     5382    lvItem.mask = LVIF_TEXT;
     5383    lvItem.iItem = nItem;
     5384    lvItem.iSubItem = 0;
     5385    lvItem.pszText = szDispText;
     5386    lvItem.cchTextMax = DISP_TEXT_SIZE;
     5387    if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return 0;
     5388 
     5389    return LISTVIEW_GetStringWidthT(infoPtr, lvItem.pszText, TRUE);
    65375390}
    65385391
     
    65405393 * DESCRIPTION:
    65415394 * Retrieves the spacing between listview control items.
    6542  * 
    6543  * PARAMETER(S):
    6544  * [I] HWND : window handle
    6545  * [I] BOOL : flag for small or large icon
     5395 *
     5396 * PARAMETER(S):
     5397 * [I] infoPtr : valid pointer to the listview structure
     5398 * [I] bSmall : flag for small or large icon
    65465399 *
    65475400 * RETURN:
    65485401 * Horizontal + vertical spacing
    65495402 */
    6550 static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall)
    6551 {
    6552   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
     5403static LONG LISTVIEW_GetItemSpacing(LISTVIEW_INFO *infoPtr, BOOL bSmall)
     5404{
    65535405  LONG lResult;
    65545406
    6555   if (bSmall == FALSE)
     5407  if (!bSmall)
    65565408  {
    65575409    lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
     
    65595411  else
    65605412  {
    6561     LONG style = GetWindowLongW(hwnd, GWL_STYLE);
    6562     if ((style & LVS_TYPEMASK) == LVS_ICON)
     5413    if ((infoPtr->dwStyle & LVS_TYPEMASK) == LVS_ICON)
    65635414      lResult = MAKELONG(DEFAULT_COLUMN_WIDTH, GetSystemMetrics(SM_CXSMICON)+HEIGHT_PADDING);
    65645415    else
     
    65715422 * DESCRIPTION:
    65725423 * Retrieves the state of a listview control item.
    6573  * 
    6574  * PARAMETER(S):
    6575  * [I] HWND : window handle
    6576  * [I] INT : item index
    6577  * [I] UINT : state mask
    6578  * 
     5424 *
     5425 * PARAMETER(S):
     5426 * [I] infoPtr : valid pointer to the listview structure
     5427 * [I] nItem : item index
     5428 * [I] uMask : state mask
     5429 *
    65795430 * RETURN:
    65805431 * State specified by the mask.
    65815432 */
    6582 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask)
    6583 {
    6584   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    6585   LVITEMW lvItem;
    6586   UINT uState = 0;
    6587 
    6588   if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
    6589   {
    6590     ZeroMemory(&lvItem, sizeof(lvItem));
     5433static UINT LISTVIEW_GetItemState(LISTVIEW_INFO *infoPtr, INT nItem, UINT uMask)
     5434{
     5435    LVITEMW lvItem;
     5436
     5437    if (nItem < 0 || nItem >= infoPtr->nItemCount) return 0;
     5438
    65915439    lvItem.iItem = nItem;
     5440    lvItem.iSubItem = 0;
     5441    lvItem.mask = LVIF_STATE;
    65925442    lvItem.stateMask = uMask;
    6593     lvItem.mask = LVIF_STATE;
    6594     if (LISTVIEW_GetItemW(hwnd, &lvItem, TRUE))
    6595       uState = lvItem.state;
    6596   }
    6597 
    6598   return uState;
    6599 }
    6600 
    6601 /***
    6602  * DESCRIPTION:
    6603  * Retrieves the text of a listview control item or subitem.
    6604  *
     5443    if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return 0;
     5444
     5445    return lvItem.state & uMask;
     5446}
     5447
     5448/***
     5449 * DESCRIPTION:
     5450 * Retrieves the text of a listview control item or subitem.
     5451 *
    66055452 * PARAMETER(S):
    66065453 * [I] hwnd : window handle
     
    66085455 * [IO] lpLVItem : item information
    66095456 * [I] isW :  TRUE if lpLVItem is Unicode
    6610  * 
     5457 *
    66115458 * RETURN:
    66125459 *   SUCCESS : string length
    66135460 *   FAILURE : 0
    66145461 */
    6615 static LRESULT LISTVIEW_GetItemTextT(HWND hwnd, INT nItem, LPLVITEMW lpLVItem, BOOL isW)
    6616 {
    6617   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    6618   INT nLength = 0;
    6619  
    6620   if (lpLVItem != NULL)
    6621   {
    6622     if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
    6623     {
    6624       lpLVItem->mask = LVIF_TEXT;
    6625       lpLVItem->iItem = nItem;
    6626       if (LISTVIEW_GetItemT(hwnd, lpLVItem, FALSE, isW))
    6627         nLength = textlenT(lpLVItem->pszText, isW);
    6628     }
    6629   }
    6630 
    6631   return nLength;
     5462static INT LISTVIEW_GetItemTextT(LISTVIEW_INFO *infoPtr, INT nItem, LPLVITEMW lpLVItem, BOOL isW)
     5463{
     5464    if (!lpLVItem || nItem < 0 || nItem >= infoPtr->nItemCount) return 0;
     5465
     5466    lpLVItem->mask = LVIF_TEXT;
     5467    lpLVItem->iItem = nItem;
     5468    if (!LISTVIEW_GetItemExtT(infoPtr, lpLVItem, isW)) return 0;
     5469
     5470    return textlenT(lpLVItem->pszText, isW);
    66325471}
    66335472
     
    66355474 * DESCRIPTION:
    66365475 * Searches for an item based on properties + relationships.
    6637  * 
    6638  * PARAMETER(S):
    6639  * [I] HWND : window handle
    6640  * [I] INT : item index
    6641  * [I] INT : relationship flag
    6642  * 
     5476 *
     5477 * PARAMETER(S):
     5478 * [I] infoPtr : valid pointer to the listview structure
     5479 * [I] nItem : item index
     5480 * [I] uFlags : relationship flag
     5481 *
    66435482 * RETURN:
    66445483 *   SUCCESS : item index
    66455484 *   FAILURE : -1
    66465485 */
    6647 static LRESULT LISTVIEW_GetNextItem(HWND hwnd, INT nItem, UINT uFlags)
    6648 {
    6649   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    6650   UINT uView = GetWindowLongW(hwnd, GWL_STYLE) & LVS_TYPEMASK;
    6651   UINT uMask = 0;
    6652   LVFINDINFOW lvFindInfo;
    6653   INT nCountPerColumn;
    6654   INT i;
    6655  
    6656   if ((nItem >= -1) && (nItem < GETITEMCOUNT(infoPtr)))
    6657   {
     5486static INT LISTVIEW_GetNextItem(LISTVIEW_INFO *infoPtr, INT nItem, UINT uFlags)
     5487{
     5488    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     5489    UINT uMask = 0;
     5490    LVFINDINFOW lvFindInfo;
     5491    INT nCountPerColumn;
     5492    INT nCountPerRow;
     5493    INT i;
     5494
     5495    TRACE("nItem=%d, uFlags=%x, nItemCount=%d\n", nItem, uFlags, infoPtr->nItemCount);
     5496    if (nItem < -1 || nItem >= infoPtr->nItemCount) return -1;
     5497
    66585498    ZeroMemory(&lvFindInfo, sizeof(lvFindInfo));
    66595499
    66605500    if (uFlags & LVNI_CUT)
    66615501      uMask |= LVIS_CUT;
    6662    
     5502
    66635503    if (uFlags & LVNI_DROPHILITED)
    66645504      uMask |= LVIS_DROPHILITED;
    6665          
     5505
    66665506    if (uFlags & LVNI_FOCUSED)
    66675507      uMask |= LVIS_FOCUSED;
     
    66705510      uMask |= LVIS_SELECTED;
    66715511
     5512    /* if we're asked for the focused item, that's only one,
     5513     * so it's worth optimizing */
     5514    if (uFlags & LVNI_FOCUSED)
     5515    {
     5516        if (!(LISTVIEW_GetItemState(infoPtr, infoPtr->nFocusedItem, uMask) & uMask) == uMask) return -1;
     5517        return (infoPtr->nFocusedItem == nItem) ? -1 : infoPtr->nFocusedItem;
     5518    }
     5519   
    66725520    if (uFlags & LVNI_ABOVE)
    66735521    {
     
    66775525        {
    66785526          nItem--;
    6679           if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
     5527          if ((ListView_GetItemState(infoPtr->hwndSelf, nItem, uMask) & uMask) == uMask)
    66805528            return nItem;
    66815529        }
     
    66835531      else
    66845532      {
     5533        /* Special case for autoarrange - move 'til the top of a list */
     5534        if (is_autoarrange(infoPtr))
     5535        {
     5536          nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr);
     5537          while (nItem - nCountPerRow >= 0)
     5538          {
     5539            nItem -= nCountPerRow;
     5540            if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
     5541              return nItem;
     5542          }
     5543          return -1;
     5544        }
    66855545        lvFindInfo.flags = LVFI_NEARESTXY;
    66865546        lvFindInfo.vkDirection = VK_UP;
    6687         ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
    6688         while ((nItem = ListView_FindItemW(hwnd, nItem, &lvFindInfo)) != -1)
     5547        ListView_GetItemPosition(infoPtr->hwndSelf, nItem, &lvFindInfo.pt);
     5548        while ((nItem = ListView_FindItemW(infoPtr->hwndSelf, nItem, &lvFindInfo)) != -1)
    66895549        {
    6690           if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
     5550          if ((ListView_GetItemState(infoPtr->hwndSelf, nItem, uMask) & uMask) == uMask)
    66915551            return nItem;
    66925552        }
     
    66975557      if ((uView == LVS_LIST) || (uView == LVS_REPORT))
    66985558      {
    6699         while (nItem < GETITEMCOUNT(infoPtr))
     5559        while (nItem < infoPtr->nItemCount)
    67005560        {
    67015561          nItem++;
    6702           if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
     5562          if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
    67035563            return nItem;
    67045564        }
     
    67065566      else
    67075567      {
     5568        /* Special case for autoarrange - move 'til the bottom of a list */
     5569        if (is_autoarrange(infoPtr))
     5570        {
     5571          nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr);
     5572          while (nItem + nCountPerRow < infoPtr->nItemCount )
     5573          {
     5574            nItem += nCountPerRow;
     5575            if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
     5576              return nItem;
     5577          }
     5578          return -1;
     5579        }
    67085580        lvFindInfo.flags = LVFI_NEARESTXY;
    67095581        lvFindInfo.vkDirection = VK_DOWN;
    6710         ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
    6711         while ((nItem = ListView_FindItemW(hwnd, nItem, &lvFindInfo)) != -1)
     5582        ListView_GetItemPosition(infoPtr->hwndSelf, nItem, &lvFindInfo.pt);
     5583        while ((nItem = ListView_FindItemW(infoPtr->hwndSelf, nItem, &lvFindInfo)) != -1)
    67125584        {
    6713           if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
     5585          if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
    67145586            return nItem;
    67155587        }
     
    67205592      if (uView == LVS_LIST)
    67215593      {
    6722         nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
     5594        nCountPerColumn = LISTVIEW_GetCountPerColumn(infoPtr);
    67235595        while (nItem - nCountPerColumn >= 0)
    67245596        {
    67255597          nItem -= nCountPerColumn;
    6726           if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
     5598          if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
    67275599            return nItem;
    67285600        }
     
    67305602      else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
    67315603      {
     5604        /* Special case for autoarrange - move 'ti the beginning of a row */
     5605        if (is_autoarrange(infoPtr))
     5606        {
     5607          nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr);
     5608          while (nItem % nCountPerRow > 0)
     5609          {
     5610            nItem --;
     5611            if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
     5612              return nItem;
     5613          }
     5614          return -1;
     5615        }
    67325616        lvFindInfo.flags = LVFI_NEARESTXY;
    67335617        lvFindInfo.vkDirection = VK_LEFT;
    6734         ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
    6735         while ((nItem = ListView_FindItemW(hwnd, nItem, &lvFindInfo)) != -1)
     5618        ListView_GetItemPosition(infoPtr->hwndSelf, nItem, &lvFindInfo.pt);
     5619        while ((nItem = ListView_FindItemW(infoPtr->hwndSelf, nItem, &lvFindInfo)) != -1)
    67365620        {
    6737           if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
     5621          if ((ListView_GetItemState(infoPtr->hwndSelf, nItem, uMask) & uMask) == uMask)
    67385622            return nItem;
    67395623        }
     
    67445628      if (uView == LVS_LIST)
    67455629      {
    6746         nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
    6747         while (nItem + nCountPerColumn < GETITEMCOUNT(infoPtr))
     5630        nCountPerColumn = LISTVIEW_GetCountPerColumn(infoPtr);
     5631        while (nItem + nCountPerColumn < infoPtr->nItemCount)
    67485632        {
    67495633          nItem += nCountPerColumn;
    6750           if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
     5634          if ((ListView_GetItemState(infoPtr->hwndSelf, nItem, uMask) & uMask) == uMask)
    67515635            return nItem;
    67525636        }
     
    67545638      else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
    67555639      {
     5640        /* Special case for autoarrange - move 'til the end of a row */
     5641        if (is_autoarrange(infoPtr))
     5642        {
     5643          nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr);
     5644          while (nItem % nCountPerRow < nCountPerRow - 1 )
     5645          {
     5646            nItem ++;
     5647            if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
     5648              return nItem;
     5649          }
     5650          return -1;
     5651        }
    67565652        lvFindInfo.flags = LVFI_NEARESTXY;
    67575653        lvFindInfo.vkDirection = VK_RIGHT;
    6758         ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
    6759         while ((nItem = ListView_FindItemW(hwnd, nItem, &lvFindInfo)) != -1)
     5654        ListView_GetItemPosition(infoPtr->hwndSelf, nItem, &lvFindInfo.pt);
     5655        while ((nItem = ListView_FindItemW(infoPtr->hwndSelf, nItem, &lvFindInfo)) != -1)
    67605656        {
    6761           if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
     5657          if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask)
    67625658            return nItem;
    67635659        }
     
    67695665
    67705666      /* search by index */
    6771       for (i = nItem; i < GETITEMCOUNT(infoPtr); i++)
     5667      for (i = nItem; i < infoPtr->nItemCount; i++)
    67725668      {
    6773         if ((ListView_GetItemState(hwnd, i, uMask) & uMask) == uMask)
     5669        if ((LISTVIEW_GetItemState(infoPtr, i, uMask) & uMask) == uMask)
    67745670          return i;
    67755671      }
    67765672    }
    6777   }
    6778 
    6779   return -1;
     5673
     5674    return -1;
    67805675}
    67815676
     
    67855680 * DESCRIPTION:
    67865681 * Retrieves the origin coordinates when in icon or small icon display mode.
    6787  *
    6788  * PARAMETER(S):
    6789  * [I] HWND : window handle
    6790  * [O] LPPOINT : coordinate information
    6791  *
    6792  * RETURN:
    6793  *   SUCCESS : TRUE
    6794  *   FAILURE : FALSE
    6795  */
    6796 static LRESULT LISTVIEW_GetOrigin(HWND hwnd, LPPOINT lpptOrigin)
    6797 {
    6798   LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    6799   UINT uView = lStyle & LVS_TYPEMASK;
    6800   BOOL bResult = FALSE;
    6801  
    6802   TRACE("(hwnd=%x, lpptOrigin=%p)\n", hwnd, lpptOrigin);
    6803 
    6804   if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
    6805   {
     5682 *
     5683 * PARAMETER(S):
     5684 * [I] infoPtr : valid pointer to the listview structure
     5685 * [O] lpptOrigin : coordinate information
     5686 *
     5687 * RETURN:
     5688 *   None.
     5689 */
     5690static void LISTVIEW_GetOrigin(LISTVIEW_INFO *infoPtr, LPPOINT lpptOrigin)
     5691{
     5692    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     5693    INT nHorzPos = 0, nVertPos = 0;
    68065694    SCROLLINFO scrollInfo;
    6807     ZeroMemory(lpptOrigin, sizeof(POINT));
    6808     ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
    6809     scrollInfo.cbSize = sizeof(SCROLLINFO);
    6810 
    6811     if (lStyle & WS_HSCROLL)
    6812     {
    6813       scrollInfo.fMask = SIF_POS;
    6814       if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
    6815         lpptOrigin->x = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
    6816     }
    6817 
    6818     if (lStyle & WS_VSCROLL)
    6819     {
    6820       scrollInfo.fMask = SIF_POS;
    6821       if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
    6822         lpptOrigin->y = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
    6823     }
    6824      
    6825     bResult = TRUE;
    6826   }
    6827  
    6828   return bResult;
    6829 }
    6830 
    6831 /***
    6832  * DESCRIPTION:
    6833  * Retrieves the number of items that are marked as selected.
    6834  *
    6835  * PARAMETER(S):
    6836  * [I] HWND : window handle
    6837  *
    6838  * RETURN:
    6839  * Number of items selected.
    6840  */
    6841 static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd)
    6842 {
    6843 /* REDO THIS */
    6844   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    6845   INT nSelectedCount = 0;
    6846   INT i;
    6847 
    6848   for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
    6849   {
    6850     if (ListView_GetItemState(hwnd, i, LVIS_SELECTED) & LVIS_SELECTED)
    6851       nSelectedCount++;
    6852   }
    6853  
    6854   return nSelectedCount;
    6855 }
    6856 
    6857 /***
    6858  * DESCRIPTION:
    6859  * Retrieves item index that marks the start of a multiple selection.
    6860  *
    6861  * PARAMETER(S):
    6862  * [I] HWND : window handle
    6863  *
    6864  * RETURN:
    6865  * Index number or -1 if there is no selection mark.
    6866  */
    6867 static LRESULT LISTVIEW_GetSelectionMark(HWND hwnd)
    6868 {
    6869   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    6870 
    6871   return infoPtr->nSelectionMark;
    6872 }
    6873 
     5695
     5696    scrollInfo.cbSize = sizeof(SCROLLINFO);   
     5697    scrollInfo.fMask = SIF_POS;
     5698   
     5699    if ((infoPtr->dwStyle & WS_HSCROLL) && GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo))
     5700        nHorzPos = scrollInfo.nPos;
     5701    if ((infoPtr->dwStyle & WS_VSCROLL) && GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo))
     5702        nVertPos = scrollInfo.nPos;
     5703
     5704    TRACE("nHorzPos=%d, nVertPos=%d\n", nHorzPos, nVertPos);
     5705
     5706    lpptOrigin->x = infoPtr->rcList.left;
     5707    lpptOrigin->y = infoPtr->rcList.top;
     5708    if (uView == LVS_LIST)
     5709        nHorzPos *= infoPtr->nItemWidth;
     5710    else if (uView == LVS_REPORT)
     5711        nVertPos *= infoPtr->nItemHeight;
     5712   
     5713    lpptOrigin->x -= nHorzPos;
     5714    lpptOrigin->y -= nVertPos;
     5715
     5716    TRACE(" origin=%s\n", debugpoint(lpptOrigin));
     5717}
    68745718
    68755719/***
    68765720 * DESCRIPTION:
    68775721 * Retrieves the width of a string.
    6878  * 
     5722 *
    68795723 * PARAMETER(S):
    68805724 * [I] hwnd : window handle
    68815725 * [I] lpszText : text string to process
    68825726 * [I] isW : TRUE if lpszText is Unicode, FALSE otherwise
    6883  * 
     5727 *
    68845728 * RETURN:
    68855729 *   SUCCESS : string width (in pixels)
    68865730 *   FAILURE : zero
    68875731 */
    6888 static LRESULT LISTVIEW_GetStringWidthT(HWND hwnd, LPCWSTR lpszText, BOOL isW)
    6889 {
    6890   if (is_textT(lpszText, isW))
    6891   {
    6892     LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    6893     HFONT hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
    6894     HDC hdc = GetDC(hwnd);
    6895     HFONT hOldFont = SelectObject(hdc, hFont);
    6896     DWORD dwStyle = GetWindowLongA(hwnd, GWL_STYLE);
     5732static INT LISTVIEW_GetStringWidthT(LISTVIEW_INFO *infoPtr, LPCWSTR lpszText, BOOL isW)
     5733{
    68975734    SIZE stringSize;
    6898     ZeroMemory(&stringSize, sizeof(SIZE));
    6899     if (isW)
    6900       GetTextExtentPointW(hdc, lpszText, lstrlenW(lpszText), &stringSize);
    6901     else
    6902       GetTextExtentPointA(hdc, (LPCSTR)lpszText, lstrlenA((LPCSTR)lpszText), &stringSize);
    6903     SelectObject(hdc, hOldFont);
    6904     ReleaseDC(hwnd, hdc);
    6905 #ifdef __WIN32OS2__
    6906     if(dwStyle & LVS_OWNERDRAWFIXED) {
    6907         /* Get item width */
    6908 
    6909         MEASUREITEMSTRUCT mis;
    6910         UINT              id = GetWindowLongA(hwnd,GWL_ID);
    6911         mis.CtlType    = ODT_LISTVIEW;
    6912         mis.CtlID      = id;
    6913         mis.itemID     = 0;
    6914         mis.itemData   = 0;     //TODO:!!!!
    6915         mis.itemHeight = 0;
    6916         mis.itemWidth  = 0;
    6917         if (isW) 
    6918          SendMessageW(GetParent(hwnd), WM_MEASUREITEM, id, (LPARAM)&mis );
    6919         else
    6920          SendMessageA(GetParent(hwnd), WM_MEASUREITEM, id, (LPARAM)&mis );
    6921         stringSize.cx  = (mis.itemWidth) ? mis.itemWidth : infoPtr->nItemWidth;
    6922     }
    6923 #endif
     5735   
     5736    stringSize.cx = 0;   
     5737    if (is_textT(lpszText, isW))
     5738    {
     5739        HFONT hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
     5740        HDC hdc = GetDC(infoPtr->hwndSelf);
     5741        HFONT hOldFont = SelectObject(hdc, hFont);
     5742
     5743        if (isW)
     5744            GetTextExtentPointW(hdc, lpszText, lstrlenW(lpszText), &stringSize);
     5745        else
     5746            GetTextExtentPointA(hdc, (LPCSTR)lpszText, lstrlenA((LPCSTR)lpszText), &stringSize);
     5747        SelectObject(hdc, hOldFont);
     5748        ReleaseDC(infoPtr->hwndSelf, hdc);
     5749    }
    69245750    return stringSize.cx;
    6925   }
    6926   return 0;
    6927 }
    6928 
    6929 /***
    6930  * DESCRIPTION:
    6931  * Retrieves the text backgound color.
     5751}
     5752
     5753/***
     5754 * DESCRIPTION:
     5755 * Determines which listview item is located at the specified position.
     5756 *
     5757 * PARAMETER(S):
     5758 * [I] infoPtr : valid pointer to the listview structure
     5759 * [IO] lpht : hit test information
     5760 * [I] subitem : fill out iSubItem.
     5761 * [I] select : return the index only if the hit selects the item
     5762 *
     5763 * NOTE:
     5764 * (mm 20001022): We must not allow iSubItem to be touched, for
     5765 * an app might pass only a structure with space up to iItem!
     5766 * (MS Office 97 does that for instance in the file open dialog)
    69325767 *
    6933  * PARAMETER(S):
    6934  * [I] HWND : window handle
    6935  *
    6936  * RETURN:
    6937  * COLORREF associated with the the background.
    6938  */
    6939 static LRESULT LISTVIEW_GetTextBkColor(HWND hwnd)
    6940 {
    6941   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongW(hwnd, 0);
    6942 
    6943   return infoPtr->clrTextBk;
    6944 }
    6945 
    6946 /***
    6947  * DESCRIPTION:
    6948  * Retrieves the text color.
    6949  *
    6950  * PARAMETER(S):
    6951  * [I] HWND : window handle
    6952  *
    6953  * RETURN:
    6954  * COLORREF associated with the text.
    6955  */
    6956 static LRESULT LISTVIEW_GetTextColor(HWND hwnd)
    6957 {
    6958   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongW(hwnd, 0);
    6959 
    6960   return infoPtr->clrText;
    6961 }
    6962 
    6963 /***
    6964  * DESCRIPTION:
    6965  * Determines item if a hit or closest if not
    6966  *
    6967  * PARAMETER(S):
    6968  * [I] HWND : window handle
    6969  * [IO] LPLV_INTHIT : hit test information
    6970  * [I] subitem : fill out iSubItem.
    6971  *
    6972  * RETURN:
    6973  *   SUCCESS : item index of hit
    6974  *   FAILURE : -1
    6975  */
    6976 static INT LISTVIEW_SuperHitTestItem(HWND hwnd, LPLV_INTHIT lpInt, BOOL subitem)
    6977 {
    6978   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    6979   LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    6980   UINT uView = lStyle & LVS_TYPEMASK;
    6981   INT i,topindex,bottomindex;
    6982   RECT rcItem;
    6983   DWORD xterm, yterm, dist;
    6984 
    6985   TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpInt->ht.pt.x, lpInt->ht.pt.y);
    6986 
    6987   topindex = ListView_GetTopIndex(hwnd);
    6988   if (uView == LVS_REPORT)
    6989   {
    6990     bottomindex = topindex + LISTVIEW_GetCountPerColumn(hwnd) + 1; 
    6991     bottomindex = min(bottomindex,GETITEMCOUNT(infoPtr));
    6992   }
    6993   else
    6994   {
    6995     bottomindex = GETITEMCOUNT(infoPtr);
    6996   }
    6997 
    6998   lpInt->distance = 0x7fffffff;
    6999   lpInt->iDistItem = -1;
    7000 
    7001   for (i = topindex; i < bottomindex; i++)
    7002   {
    7003     rcItem.left = LVIR_BOUNDS;
    7004     if (LISTVIEW_GetItemRect(hwnd, i, &rcItem))
    7005     {
    7006       if (PtInRect(&rcItem, lpInt->ht.pt))
    7007       {
    7008         rcItem.left = LVIR_ICON;
    7009         if (LISTVIEW_GetItemRect(hwnd, i, &rcItem))
    7010         {
    7011           if (PtInRect(&rcItem, lpInt->ht.pt))
    7012           {
    7013             lpInt->ht.flags = LVHT_ONITEMICON;
    7014             lpInt->ht.iItem = i;
    7015             if (subitem) lpInt->ht.iSubItem = 0;
    7016             return i;
    7017           }
    7018         }
    7019      
    7020         rcItem.left = LVIR_LABEL;
    7021         if (LISTVIEW_GetItemRect(hwnd, i, &rcItem))
    7022         {
    7023           if (PtInRect(&rcItem, lpInt->ht.pt))
    7024           {
    7025             lpInt->ht.flags = LVHT_ONITEMLABEL;
    7026             lpInt->ht.iItem = i;
    7027             if (subitem) lpInt->ht.iSubItem = 0;
    7028             return i;
    7029           }
    7030         }
    7031        
    7032         lpInt->ht.flags = LVHT_ONITEMSTATEICON;
    7033         lpInt->ht.iItem = i;
    7034         if (subitem) lpInt->ht.iSubItem = 0;
    7035         return i;
    7036       }
    7037       else
    7038       {
    7039         /*
    7040          * Now compute distance from point to center of boundary
    7041          * box. Since we are only interested in the relative
    7042          * distance, we can skip the nasty square root operation
    7043          */
    7044         xterm = rcItem.left + (rcItem.right - rcItem.left)/2 - lpInt->ht.pt.x;
    7045         yterm = rcItem.top + (rcItem.bottom - rcItem.top)/2 - lpInt->ht.pt.y;
    7046         dist = xterm * xterm + yterm * yterm;
    7047         if (dist < lpInt->distance)
    7048         {
    7049           lpInt->distance = dist;
    7050           lpInt->iDistItem = i;
    7051         }
    7052       }
    7053     }
    7054   }
    7055      
    7056   lpInt->ht.flags = LVHT_NOWHERE;
    7057   TRACE("no hit, closest item %d, distance %ld\n", lpInt->iDistItem, lpInt->distance);
    7058 
    7059   return -1;
    7060 }
    7061 
    7062  /***
    7063   * DESCRIPTION:
    7064   * Determines which section of the item was selected (if any).
    7065   *
    7066   * PARAMETER(S):
    7067   * [I] HWND : window handle
    7068   * [IO] LPLVHITTESTINFO : hit test information
    7069   * [I] subitem : fill out iSubItem.
    7070   *
    7071   * RETURN:
    7072   *   SUCCESS : item index
    7073   *   FAILURE : -1
    7074   */
    7075 static INT LISTVIEW_HitTestItem(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo, BOOL subitem)
    7076 {
    7077   INT ret;
    7078   LV_INTHIT lv_inthit;
    7079 
    7080   TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpHitTestInfo->pt.x,
    7081         lpHitTestInfo->pt.y);
    7082 
    7083   memcpy(&lv_inthit, lpHitTestInfo, sizeof(LVHITTESTINFO));
    7084   ret = LISTVIEW_SuperHitTestItem(hwnd, &lv_inthit, subitem);
    7085   memcpy(lpHitTestInfo, &lv_inthit, sizeof(LVHITTESTINFO));
    7086   return ret;
    7087 }
    7088 
    7089 /***
    7090  * DESCRIPTION:
    7091  * Determines which listview item is located at the specified position.
    7092  *
    7093  * PARAMETER(S):
    7094  * [I] HWND : window handle
    7095  * [IO} LPLVHITTESTINFO : hit test information
    7096  *
    70975768 * RETURN:
    70985769 *   SUCCESS : item index
    70995770 *   FAILURE : -1
    71005771 */
    7101 static LRESULT LISTVIEW_HitTest(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
    7102 {
    7103   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    7104   INT nItem = -1;
    7105 
    7106   lpHitTestInfo->flags = 0;
    7107 
    7108   if (infoPtr->rcList.left > lpHitTestInfo->pt.x)
    7109     lpHitTestInfo->flags = LVHT_TOLEFT;
    7110   else if (infoPtr->rcList.right < lpHitTestInfo->pt.x)
    7111     lpHitTestInfo->flags = LVHT_TORIGHT;
    7112   if (infoPtr->rcList.top > lpHitTestInfo->pt.y)
    7113     lpHitTestInfo->flags |= LVHT_ABOVE;
    7114   else if (infoPtr->rcList.bottom < lpHitTestInfo->pt.y)
    7115     lpHitTestInfo->flags |= LVHT_BELOW;
    7116 
    7117   if (lpHitTestInfo->flags == 0)
    7118   {
    7119     /* NOTE (mm 20001022): We must not allow iSubItem to be touched, for
    7120      * an app might pass only a structure with space up to iItem!
    7121      * (MS Office 97 does that for instance in the file open dialog)
    7122      */
    7123     nItem = LISTVIEW_HitTestItem(hwnd, lpHitTestInfo, FALSE);
    7124   }
    7125  
    7126   return nItem;
    7127 }
    7128 
    7129 /***
    7130  * DESCRIPTION:
    7131  * Inserts a new column.
    7132  *
    7133  * PARAMETER(S):
    7134  * [I] HWND : window handle
    7135  * [I] INT : column index
    7136  * [I] LPLVCOLUMNW : column information
    7137  *
    7138  * RETURN:
    7139  *   SUCCESS : new column index
    7140  *   FAILURE : -1
    7141  */
    7142 static LRESULT LISTVIEW_InsertColumnT(HWND hwnd, INT nColumn,
    7143                                       LPLVCOLUMNW lpColumn, BOOL isW)
    7144 {
    7145   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    7146   INT nNewColumn = -1;
    7147   HDITEMW hdi;
    7148 
    7149   TRACE("(hwnd=%x, nColumn=%d, lpColumn=%p)\n",hwnd, nColumn, lpColumn);
    7150 
    7151   if (lpColumn != NULL)
    7152   {
    7153     /* initialize memory */
    7154     ZeroMemory(&hdi, sizeof(hdi));
    7155 
    7156     if (lpColumn->mask & LVCF_FMT)
    7157     {
    7158       /* format member is valid */
    7159       hdi.mask |= HDI_FORMAT;
    7160 
    7161       /* set text alignment (leftmost column must be left-aligned) */
    7162       if (nColumn == 0)
    7163       {
    7164         hdi.fmt |= HDF_LEFT;
    7165       }
    7166       else
    7167       {
    7168         if (lpColumn->fmt & LVCFMT_LEFT)
     5772static INT LISTVIEW_HitTest(LISTVIEW_INFO *infoPtr, LPLVHITTESTINFO lpht, BOOL subitem, BOOL select)
     5773{
     5774    WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
     5775    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     5776    RECT rcBox, rcBounds, rcState, rcIcon, rcLabel, rcSearch;
     5777    POINT Origin, Position, opt;
     5778    LVITEMW lvItem;
     5779    ITERATOR i;
     5780   
     5781    TRACE("(pt=%s, subitem=%d, select=%d)\n", debugpoint(&lpht->pt), subitem, select);
     5782   
     5783    lpht->flags = 0;
     5784    lpht->iItem = -1;
     5785    if (subitem) lpht->iSubItem = 0;
     5786
     5787    if (infoPtr->rcList.left > lpht->pt.x)
     5788        lpht->flags |= LVHT_TOLEFT;
     5789    else if (infoPtr->rcList.right < lpht->pt.x)
     5790        lpht->flags |= LVHT_TORIGHT;
     5791   
     5792    if (infoPtr->rcList.top > lpht->pt.y)
     5793        lpht->flags |= LVHT_ABOVE;
     5794    else if (infoPtr->rcList.bottom < lpht->pt.y)
     5795        lpht->flags |= LVHT_BELOW;
     5796
     5797    TRACE("lpht->flags=0x%x\n", lpht->flags);
     5798    if (lpht->flags) return -1;
     5799
     5800    lpht->flags |= LVHT_NOWHERE;
     5801
     5802    LISTVIEW_GetOrigin(infoPtr, &Origin);
     5803   
     5804    /* first deal with the large items */
     5805    rcSearch.left = lpht->pt.x;
     5806    rcSearch.top = lpht->pt.y;
     5807    rcSearch.right = rcSearch.left + 1;
     5808    rcSearch.bottom = rcSearch.top + 1;
     5809   
     5810    iterator_frameditems(&i, infoPtr, &rcSearch);
     5811    iterator_next(&i); /* go to first item in the sequence */
     5812    lpht->iItem = i.nItem;
     5813    iterator_destroy(&i);
     5814   
     5815    TRACE("lpht->iItem=%d\n", lpht->iItem);
     5816    if (lpht->iItem == -1) return -1;
     5817
     5818    lvItem.mask = LVIF_STATE | LVIF_TEXT;
     5819    if (uView == LVS_REPORT) lvItem.mask |= LVIF_INDENT;
     5820    lvItem.stateMask = LVIS_STATEIMAGEMASK;
     5821    if (uView == LVS_ICON) lvItem.stateMask |= LVIS_FOCUSED;
     5822    lvItem.iItem = lpht->iItem;
     5823    lvItem.iSubItem = 0;
     5824    lvItem.pszText = szDispText;
     5825    lvItem.cchTextMax = DISP_TEXT_SIZE;
     5826    if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return -1;
     5827    if (!infoPtr->bFocus) lvItem.state &= ~LVIS_FOCUSED;
     5828   
     5829    LISTVIEW_GetItemMetrics(infoPtr, &lvItem, &rcBox, &rcState, &rcIcon, &rcLabel);
     5830    LISTVIEW_GetItemOrigin(infoPtr, lpht->iItem, &Position);
     5831    opt.x = lpht->pt.x - Position.x - Origin.x;
     5832    opt.y = lpht->pt.y - Position.y - Origin.y;
     5833   
     5834    if (uView == LVS_REPORT && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT))
     5835        rcBounds = rcBox;
     5836    else
     5837        UnionRect(&rcBounds, &rcIcon, &rcLabel);
     5838    TRACE("rcBounds=%s\n", debugrect(&rcBounds));
     5839    if (!PtInRect(&rcBounds, opt)) return -1;
     5840
     5841    if (PtInRect(&rcIcon, opt))
     5842        lpht->flags |= LVHT_ONITEMICON;
     5843    else if (PtInRect(&rcLabel, opt))
     5844        lpht->flags |= LVHT_ONITEMLABEL;
     5845    else if (infoPtr->himlState && ((lvItem.state & LVIS_STATEIMAGEMASK) >> 12) && PtInRect(&rcState, opt))
     5846        lpht->flags |= LVHT_ONITEMSTATEICON;
     5847    if (lpht->flags & LVHT_ONITEM)
     5848        lpht->flags &= ~LVHT_NOWHERE;
     5849   
     5850    TRACE("lpht->flags=0x%x\n", lpht->flags);
     5851    if (uView == LVS_REPORT && lpht->iItem != -1 && subitem)
     5852    {
     5853        INT j;
     5854
     5855        rcBounds.right = rcBounds.left;
     5856        for (j = 0; j < infoPtr->hdpaColumns->nItemCount; j++)
    71695857        {
    7170           hdi.fmt |= HDF_LEFT;
    7171         }
    7172         else if (lpColumn->fmt & LVCFMT_RIGHT)
    7173         {
    7174           hdi.fmt |= HDF_RIGHT;
    7175         }
    7176         else if (lpColumn->fmt & LVCFMT_CENTER)
    7177         {
    7178           hdi.fmt |= HDF_CENTER;
    7179         }
    7180       }
    7181  
    7182       if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
    7183       {
    7184         hdi.fmt |= HDF_BITMAP_ON_RIGHT;
    7185         /* ??? */
    7186       }
    7187 
    7188       if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
    7189       {
    7190         /* ??? */
    7191       }
    7192      
    7193       if (lpColumn->fmt & LVCFMT_IMAGE)
    7194       {
    7195         hdi.fmt |= HDF_IMAGE;
    7196         hdi.iImage = I_IMAGECALLBACK;
    7197       }
    7198     }
    7199 
    7200     if (lpColumn->mask & LVCF_WIDTH)
    7201     {
    7202       hdi.mask |= HDI_WIDTH;
    7203       if(lpColumn->cx == LVSCW_AUTOSIZE_USEHEADER)
    7204       {
    7205         /* make it fill the remainder of the controls width */
    7206         HDITEMW hdit;
    7207         RECT rcHeader;
    7208         INT item_index;
    7209        
    7210         ZeroMemory(&hdit, sizeof(hdit));
    7211  
    7212         /* get the width of every item except the current one */
    7213         hdit.mask = HDI_WIDTH;
    7214         hdi.cxy = 0;
    7215        
    7216         for(item_index = 0; item_index < (nColumn - 1); item_index++) {
    7217           Header_GetItemW(infoPtr->hwndHeader, item_index, (LPARAM)(&hdit));
    7218           hdi.cxy+=hdit.cxy;
    7219         }
    7220 
    7221         /* retrieve the layout of the header */
    7222         GetClientRect(hwnd, &rcHeader);
    7223 /*        GetWindowRect(infoPtr->hwndHeader, &rcHeader);*/
    7224         TRACE("start cxy=%d left=%d right=%d\n", hdi.cxy, rcHeader.left, rcHeader.right);
    7225 
    7226         hdi.cxy = (rcHeader.right - rcHeader.left) - hdi.cxy;
    7227       }
    7228       else
    7229         hdi.cxy = lpColumn->cx;
    7230     }
    7231  
    7232     if (lpColumn->mask & LVCF_TEXT)
    7233     {
    7234       hdi.mask |= HDI_TEXT | HDI_FORMAT;
    7235       hdi.pszText = lpColumn->pszText;
    7236       hdi.cchTextMax = textlenT(lpColumn->pszText, isW);
    7237       hdi.fmt |= HDF_STRING;
    7238     }
    7239  
    7240     if (lpColumn->mask & LVCF_IMAGE)
    7241     {
    7242       hdi.mask |= HDI_IMAGE;
    7243       hdi.iImage = lpColumn->iImage;
    7244     }
    7245 
    7246     if (lpColumn->mask & LVCF_ORDER)
    7247     {
    7248       hdi.mask |= HDI_ORDER;
    7249       hdi.iOrder = lpColumn->iOrder;
    7250     }
    7251 
    7252     /* insert item in header control */
    7253     nNewColumn = SendMessageW(infoPtr->hwndHeader, HDM_INSERTITEMT(isW),
    7254                              (WPARAM)nColumn, (LPARAM)&hdi);
    7255    
    7256     /* Need to reset the item width when inserting a new column */
    7257     infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
    7258 
    7259     LISTVIEW_UpdateScroll(hwnd);
    7260     InvalidateRect(hwnd, NULL, FALSE);
    7261   }
    7262 
    7263   return nNewColumn;
    7264 }
     5858            rcBounds.left = rcBounds.right;
     5859            rcBounds.right += LISTVIEW_GetColumnWidth(infoPtr, j);
     5860            if (PtInRect(&rcBounds, opt))
     5861            {
     5862                lpht->iSubItem = j;
     5863                break;
     5864            }
     5865        }
     5866    }
     5867
     5868    if (!select || lpht->iItem == -1) return lpht->iItem;
     5869
     5870    if (uView == LVS_REPORT && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT)) return lpht->iItem;
     5871   
     5872    if (uView == LVS_REPORT) UnionRect(&rcBounds, &rcIcon, &rcLabel);
     5873    return PtInRect(&rcBounds, opt) ? lpht->iItem : -1;
     5874}
     5875
    72655876
    72665877/* LISTVIEW_InsertCompare:  callback routine for comparing pszText members of the LV_ITEMS
     
    72735884    (remarks on LVITEM: LVM_INSERTITEM will insert the new item in the proper sort postion...
    72745885        if:
    7275           LVS_SORTXXX must be specified, 
    7276           LVS_OWNERDRAW is not set, 
     5886          LVS_SORTXXX must be specified,
     5887          LVS_OWNERDRAW is not set,
    72775888          <item>.pszText is not LPSTR_TEXTCALLBACK.
    72785889
    7279     (LVS_SORT* flags): "For the LVS_SORTASCENDING... styles, item indices 
    7280     are sorted based on item text..." 
     5890    (LVS_SORT* flags): "For the LVS_SORTASCENDING... styles, item indices
     5891    are sorted based on item text..."
    72815892*/
    72825893static INT WINAPI LISTVIEW_InsertCompare(  LPVOID first, LPVOID second,  LPARAM lParam)
    72835894{
    7284   LONG lStyle = GetWindowLongW((HWND) lParam, GWL_STYLE);
    7285   LISTVIEW_ITEM* lv_first = (LISTVIEW_ITEM*) DPA_GetPtr( (HDPA)first, 0 );
    7286   LISTVIEW_ITEM* lv_second = (LISTVIEW_ITEM*) DPA_GetPtr( (HDPA)second, 0 );
    7287   INT  cmpv = lstrcmpW( lv_first->pszText, lv_second->pszText );
    7288   /* if we're sorting descending, negate the return value */
    7289   return (lStyle & LVS_SORTDESCENDING) ? -cmpv : cmpv;
     5895    ITEM_INFO* lv_first = (ITEM_INFO*) DPA_GetPtr( (HDPA)first, 0 );
     5896    ITEM_INFO* lv_second = (ITEM_INFO*) DPA_GetPtr( (HDPA)second, 0 );
     5897    INT cmpv = textcmpWT(lv_first->hdr.pszText, lv_second->hdr.pszText, TRUE);
     5898
     5899    /* if we're sorting descending, negate the return value */
     5900    return (((LISTVIEW_INFO *)lParam)->dwStyle & LVS_SORTDESCENDING) ? -cmpv : cmpv;
    72905901}
    72915902
     
    72935904 * nESCRIPTION:
    72945905 * Inserts a new item in the listview control.
    7295  * 
    7296  * PARAMETER(S):
    7297  * [I] HWND : window handle
    7298  * [I] LPLVITEMW : item information
     5906 *
     5907 * PARAMETER(S):
     5908 * [I] infoPtr : valid pointer to the listview structure
     5909 * [I] lpLVItem : item information
    72995910 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
    73005911 *
     
    73035914 *   FAILURE : -1
    73045915 */
    7305 static LRESULT LISTVIEW_InsertItemT(HWND hwnd, LPLVITEMW lpLVItem, BOOL isW)
    7306 {
    7307   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    7308   LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    7309   UINT uView = lStyle & LVS_TYPEMASK;
    7310   INT nItem = -1;
    7311   HDPA hdpaSubItems;
    7312   INT nItemWidth = 0;
    7313   LISTVIEW_ITEM *lpItem = NULL;
    7314 
    7315   TRACE("(hwnd=%x, lpLVItem=%s, isW=%d)\n",
    7316         hwnd, debuglvitem_t(lpLVItem, isW), isW);
    7317 
    7318   if (lStyle & LVS_OWNERDATA)
    7319   {
    7320     nItem = infoPtr->hdpaItems->nItemCount;
    7321     infoPtr->hdpaItems->nItemCount ++;
     5916static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL isW)
     5917{
     5918    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     5919    INT nItem;
     5920    HDPA hdpaSubItems;
     5921    NMLISTVIEW nmlv;
     5922    ITEM_INFO *lpItem;
     5923    BOOL is_sorted, has_changed;
     5924    LVITEMW item;
     5925
     5926    TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW);
     5927
     5928    if (infoPtr->dwStyle & LVS_OWNERDATA) return infoPtr->nItemCount++;
     5929
     5930    /* make sure it's an item, and not a subitem; cannot insert a subitem */
     5931    if (!lpLVItem || lpLVItem->iItem < 0 || lpLVItem->iSubItem) return -1;
     5932
     5933    if (!is_assignable_item(lpLVItem, infoPtr->dwStyle)) return -1;
     5934
     5935    if ( !(lpItem = (ITEM_INFO *)COMCTL32_Alloc(sizeof(ITEM_INFO))) )
     5936        return -1;
     5937   
     5938    /* insert item in listview control data structure */
     5939    if ( !(hdpaSubItems = DPA_Create(8)) ) goto fail;
     5940    if ( !DPA_SetPtr(hdpaSubItems, 0, lpItem) ) assert (FALSE);
     5941
     5942    is_sorted = (infoPtr->dwStyle & (LVS_SORTASCENDING | LVS_SORTDESCENDING)) &&
     5943                !(infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && (LPSTR_TEXTCALLBACKW != lpLVItem->pszText);
     5944
     5945    nItem = is_sorted ? infoPtr->nItemCount : min(lpLVItem->iItem, infoPtr->nItemCount);
     5946    TRACE(" inserting at %d, sorted=%d, count=%d, iItem=%d\n", nItem, is_sorted, infoPtr->nItemCount, lpLVItem->iItem);
     5947    nItem = DPA_InsertPtr( infoPtr->hdpaItems, nItem, hdpaSubItems );
     5948    if (nItem == -1) goto fail;
     5949    infoPtr->nItemCount++;
     5950
     5951    /* set the item attributes */
     5952    if (lpLVItem->mask & (LVIF_GROUPID|LVIF_COLUMNS))
     5953    {
     5954       /* full size structure expected - _WIN32IE >= 0x560 */
     5955       item = *lpLVItem;
     5956    }
     5957    else if (lpLVItem->mask & LVIF_INDENT)
     5958    {
     5959       /* indent member expected - _WIN32IE >= 0x300 */
     5960       memcpy(&item, lpLVItem, offsetof( LVITEMW, iGroupId ));
     5961    }
     5962    else
     5963    {
     5964       /* minimal structure expected */
     5965       memcpy(&item, lpLVItem, offsetof( LVITEMW, iIndent ));
     5966    }
     5967    item.iItem = nItem;
     5968    item.state &= ~LVIS_STATEIMAGEMASK;
     5969    if (!set_main_item(infoPtr, &item, TRUE, isW, &has_changed)) goto undo;
     5970
     5971    /* if we're sorted, sort the list, and update the index */
     5972    if (is_sorted)
     5973    {
     5974        DPA_Sort( infoPtr->hdpaItems, LISTVIEW_InsertCompare, (LPARAM)infoPtr );
     5975        nItem = DPA_GetPtrIndex( infoPtr->hdpaItems, hdpaSubItems );
     5976        assert(nItem != -1);
     5977    }
     5978
     5979    /* make room for the position, if we are in the right mode */
     5980    if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
     5981    {
     5982        if (DPA_InsertPtr(infoPtr->hdpaPosX, nItem, 0) == -1)
     5983            goto undo;
     5984        if (DPA_InsertPtr(infoPtr->hdpaPosY, nItem, 0) == -1)
     5985        {
     5986            DPA_DeletePtr(infoPtr->hdpaPosX, nItem);
     5987            goto undo;
     5988        }
     5989    }
     5990   
     5991    /* Add the subitem list to the items array. Do this last in case we go to
     5992     * fail during the above.
     5993     */
     5994    LISTVIEW_ShiftIndices(infoPtr, nItem, 1);
     5995   
     5996    /* send LVN_INSERTITEM notification */
     5997    ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
     5998    nmlv.iItem = nItem;
     5999    nmlv.lParam = lpItem->lParam;
     6000    notify_listview(infoPtr, LVN_INSERTITEM, &nmlv);
     6001
     6002    /* align items (set position of each item) */
     6003    if ((uView == LVS_SMALLICON || uView == LVS_ICON))
     6004    {
     6005        POINT pt;
     6006
     6007        if (infoPtr->dwStyle & LVS_ALIGNLEFT)
     6008            LISTVIEW_NextIconPosLeft(infoPtr, &pt);
     6009        else
     6010            LISTVIEW_NextIconPosTop(infoPtr, &pt);
     6011
     6012        LISTVIEW_MoveIconTo(infoPtr, nItem, &pt, TRUE);
     6013    }
     6014
     6015    /* now is the invalidation fun */
     6016    LISTVIEW_ScrollOnInsert(infoPtr, nItem, 1);
    73226017    return nItem;
    7323   }
    7324 
    7325   if (lpLVItem != NULL)
    7326   {
    7327     /* make sure it's not a subitem; cannot insert a subitem */
    7328     if (lpLVItem->iSubItem == 0)
    7329     {
    7330       if ( (lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM))) )
    7331       {
    7332         ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
    7333         if (LISTVIEW_InitItemT(hwnd, lpItem, lpLVItem, isW))
    7334         {
    7335           /* insert item in listview control data structure */
    7336           if ( (hdpaSubItems = DPA_Create(8)) )
    7337           {
    7338             if ( (nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem)) != -1)
    7339             {
    7340               if ( ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
    7341                       && !(lStyle & LVS_OWNERDRAWFIXED)
    7342                       && (LPSTR_TEXTCALLBACKW != lpLVItem->pszText) )
    7343               {
    7344                 /* Insert the item in the proper sort order based on the pszText
    7345                   member. See comments for LISTVIEW_InsertCompare() for greater detail */
    7346                   nItem = DPA_InsertPtr( infoPtr->hdpaItems,
    7347                           GETITEMCOUNT( infoPtr ) + 1, hdpaSubItems );
    7348                   DPA_Sort( infoPtr->hdpaItems, LISTVIEW_InsertCompare, hwnd );
    7349                   nItem = DPA_GetPtrIndex( infoPtr->hdpaItems, hdpaSubItems );
    7350               }
    7351               else
    7352               {
    7353                 nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpLVItem->iItem,
    7354                                     hdpaSubItems);
    7355               }
    7356               if (nItem != -1)
    7357               {
    7358                 NMLISTVIEW nmlv;
    7359 
    7360                 LISTVIEW_ShiftIndices(hwnd,nItem,1);
    7361 
    7362                 /* manage item focus */
    7363                 if (lpLVItem->mask & LVIF_STATE)
    7364                 {
    7365                   lpItem->state &= ~(LVIS_FOCUSED|LVIS_SELECTED);
    7366                   if (lpLVItem->stateMask & LVIS_SELECTED)
    7367                     LISTVIEW_SetSelection(hwnd, nItem);
    7368                   else if (lpLVItem->stateMask & LVIS_FOCUSED)
    7369                     LISTVIEW_SetItemFocus(hwnd, nItem);
    7370                 }
    7371                
    7372                 /* send LVN_INSERTITEM notification */
    7373                 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
    7374                 nmlv.iItem = nItem;
    7375                 nmlv.lParam = lpItem->lParam;
    7376                 listview_notify(hwnd, LVN_INSERTITEM, &nmlv);
    7377                
    7378                 if ((uView == LVS_SMALLICON) || (uView == LVS_LIST))
    7379                 {
    7380                   nItemWidth = LISTVIEW_CalculateWidth(hwnd, lpLVItem->iItem);
    7381                   if (nItemWidth > infoPtr->nItemWidth)
    7382                     infoPtr->nItemWidth = nItemWidth;
    7383                 }
    7384 
    7385                 /* align items (set position of each item) */
    7386                 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
    7387                 {
    7388                   if (lStyle & LVS_ALIGNLEFT)
    7389                     LISTVIEW_AlignLeft(hwnd);
    7390                   else
    7391                     LISTVIEW_AlignTop(hwnd);
    7392                 }
    7393                
    7394                 LISTVIEW_UpdateScroll(hwnd);
    7395                 /* refresh client area */
    7396                 InvalidateRect(hwnd, NULL, FALSE);
    7397               }
    7398             }
    7399           }
    7400         }
    7401       }
    7402     }
    7403   }
    7404 
    7405   /* free memory if unsuccessful */
    7406   if ((nItem == -1) && (lpItem != NULL))
    7407     COMCTL32_Free(lpItem);
    7408  
    7409   return nItem;
     6018
     6019undo:
     6020    DPA_DeletePtr(infoPtr->hdpaItems, nItem);
     6021    infoPtr->nItemCount--;
     6022fail:
     6023    DPA_DeletePtr(hdpaSubItems, 0);
     6024    DPA_Destroy (hdpaSubItems);
     6025    COMCTL32_Free (lpItem);
     6026    return -1;
    74106027}
    74116028
     
    74136030 * DESCRIPTION:
    74146031 * Redraws a range of items.
    7415  * 
    7416  * PARAMETER(S):
    7417  * [I] HWND : window handle
    7418  * [I] INT : first item
    7419  * [I] INT : last item
     6032 *
     6033 * PARAMETER(S):
     6034 * [I] infoPtr : valid pointer to the listview structure
     6035 * [I] nFirst : first item
     6036 * [I] nLast : last item
    74206037 *
    74216038 * RETURN:
     
    74236040 *   FAILURE : FALSE
    74246041 */
    7425 static LRESULT LISTVIEW_RedrawItems(HWND hwnd, INT nFirst, INT nLast)
    7426 {
    7427   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    7428   BOOL bResult = FALSE;
    7429   RECT rcItem;
    7430   INT i;
    7431 
    7432   if (nFirst <= nLast)
    7433   {
    7434     if ((nFirst >= 0) && (nFirst < GETITEMCOUNT(infoPtr)))
    7435     {
    7436       if ((nLast >= 0) && (nLast < GETITEMCOUNT(infoPtr)))
    7437       {
    7438         for (i = nFirst; i <= nLast; i++)
    7439         {
    7440           rcItem.left = LVIR_BOUNDS;
    7441           LISTVIEW_GetItemRect(hwnd, i, &rcItem);
    7442           InvalidateRect(hwnd, &rcItem, TRUE);
    7443         }
    7444       }
    7445     }
    7446   }
    7447 
    7448   return bResult;
    7449 }
    7450 
    7451 /* LISTVIEW_Scroll */
    7452 
    7453 /***
    7454  * DESCRIPTION:
    7455  * Sets the background color.
    7456  *
    7457  * PARAMETER(S):
    7458  * [I] HWND : window handle
    7459  * [I] COLORREF : background color
     6042static BOOL LISTVIEW_RedrawItems(LISTVIEW_INFO *infoPtr, INT nFirst, INT nLast)
     6043{
     6044    INT i;
     6045 
     6046    if (nLast < nFirst || min(nFirst, nLast) < 0 ||
     6047        max(nFirst, nLast) >= infoPtr->nItemCount)
     6048        return FALSE;
     6049   
     6050    for (i = nFirst; i <= nLast; i++)
     6051        LISTVIEW_InvalidateItem(infoPtr, i);
     6052
     6053    return TRUE;
     6054}
     6055
     6056/***
     6057 * DESCRIPTION:
     6058 * Scroll the content of a listview.
     6059 *
     6060 * PARAMETER(S):
     6061 * [I] infoPtr : valid pointer to the listview structure
     6062 * [I] dx : horizontal scroll amount in pixels
     6063 * [I] dy : vertical scroll amount in pixels
    74606064 *
    74616065 * RETURN:
    74626066 *   SUCCESS : TRUE
    74636067 *   FAILURE : FALSE
    7464  */
    7465 static LRESULT LISTVIEW_SetBkColor(HWND hwnd, COLORREF clrBk)
    7466 {
    7467   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    7468 
    7469   if(infoPtr->clrBk!=clrBk){
    7470     infoPtr->clrBk = clrBk;
    7471     InvalidateRect(hwnd, NULL, TRUE);
    7472   }
     6068 *
     6069 * COMMENTS:
     6070 *  If the control is in report mode (LVS_REPORT) the control can
     6071 *  be scrolled only in line increments. "dy" will be rounded to the
     6072 *  nearest number of pixels that are a whole line. Ex: if line height
     6073 *  is 16 and an 8 is passed, the list will be scrolled by 16. If a 7
     6074 *  is passed the the scroll will be 0.  (per MSDN 7/2002)
     6075 *
     6076 *  For:  (per experimentaion with native control and CSpy ListView)
     6077 *     LVS_ICON       dy=1 = 1 pixel  (vertical only)
     6078 *                    dx ignored
     6079 *     LVS_SMALLICON  dy=1 = 1 pixel  (vertical only)
     6080 *                    dx ignored
     6081 *     LVS_LIST       dx=1 = 1 column (horizontal only)
     6082 *                           but will only scroll 1 column per message
     6083 *                           no matter what the value.
     6084 *                    dy must be 0 or FALSE returned.
     6085 *     LVS_REPORT     dx=1 = 1 pixel
     6086 *                    dy=  see above
     6087 *
     6088 */
     6089static BOOL LISTVIEW_Scroll(LISTVIEW_INFO *infoPtr, INT dx, INT dy)
     6090{
     6091    switch(infoPtr->dwStyle & LVS_TYPEMASK) {
     6092    case LVS_REPORT:
     6093        dy += (dy < 0 ? -1 : 1) * infoPtr->nItemHeight/2;
     6094        dy /= infoPtr->nItemHeight;
     6095        break;
     6096    case LVS_LIST:
     6097        if (dy != 0) return FALSE;
     6098        break;
     6099    default: /* icon */
     6100        dx = 0;
     6101        break;
     6102    }   
     6103
     6104    if (dx != 0) LISTVIEW_HScroll(infoPtr, SB_INTERNAL, dx, 0);
     6105    if (dy != 0) LISTVIEW_VScroll(infoPtr, SB_INTERNAL, dy, 0);
    74736106 
    7474   return TRUE;
    7475 }
    7476 
    7477 /* LISTVIEW_SetBkImage */
    7478 
    7479 /***
    7480  * DESCRIPTION:
    7481  * Sets the callback mask. This mask will be used when the parent
    7482  * window stores state information (some or all).
    7483  *
    7484  * PARAMETER(S):
    7485  * [I] HWND : window handle
    7486  * [I] UINT : state mask
     6107    return TRUE;
     6108}
     6109
     6110/***
     6111 * DESCRIPTION:
     6112 * Sets the background color.
     6113 *
     6114 * PARAMETER(S):
     6115 * [I] infoPtr : valid pointer to the listview structure
     6116 * [I] clrBk : background color
    74876117 *
    74886118 * RETURN:
     
    74906120 *   FAILURE : FALSE
    74916121 */
    7492 static BOOL LISTVIEW_SetCallbackMask(HWND hwnd, UINT uMask)
    7493 {
    7494   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    7495 
    7496   infoPtr->uCallbackMask = uMask;
    7497 
    7498   return TRUE;
     6122static BOOL LISTVIEW_SetBkColor(LISTVIEW_INFO *infoPtr, COLORREF clrBk)
     6123{
     6124    TRACE("(clrBk=%lx)\n", clrBk);
     6125
     6126    if(infoPtr->clrBk != clrBk) {
     6127        if (infoPtr->clrBk != CLR_NONE) DeleteObject(infoPtr->hBkBrush);
     6128        infoPtr->clrBk = clrBk;
     6129        if (clrBk == CLR_NONE)
     6130            infoPtr->hBkBrush = (HBRUSH)GetClassLongW(infoPtr->hwndSelf, GCL_HBRBACKGROUND);
     6131        else
     6132            infoPtr->hBkBrush = CreateSolidBrush(clrBk);
     6133        LISTVIEW_InvalidateList(infoPtr);
     6134    }
     6135
     6136   return TRUE;
     6137}
     6138
     6139/* LISTVIEW_SetBkImage */
     6140
     6141/*** Helper for {Insert,Set}ColumnT *only* */
     6142static void column_fill_hditem(LISTVIEW_INFO *infoPtr, HDITEMW *lphdi, INT nColumn, const LVCOLUMNW *lpColumn, BOOL isW)
     6143{
     6144    if (lpColumn->mask & LVCF_FMT)
     6145    {
     6146        /* format member is valid */
     6147        lphdi->mask |= HDI_FORMAT;
     6148
     6149        /* set text alignment (leftmost column must be left-aligned) */
     6150        if (nColumn == 0 || lpColumn->fmt & LVCFMT_LEFT)
     6151            lphdi->fmt |= HDF_LEFT;
     6152        else if (lpColumn->fmt & LVCFMT_RIGHT)
     6153            lphdi->fmt |= HDF_RIGHT;
     6154        else if (lpColumn->fmt & LVCFMT_CENTER)
     6155            lphdi->fmt |= HDF_CENTER;
     6156
     6157        if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
     6158            lphdi->fmt |= HDF_BITMAP_ON_RIGHT;
     6159
     6160        if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
     6161        {
     6162            lphdi->fmt |= HDF_IMAGE;
     6163            lphdi->iImage = I_IMAGECALLBACK;
     6164        }
     6165    }
     6166
     6167    if (lpColumn->mask & LVCF_WIDTH)
     6168    {
     6169        lphdi->mask |= HDI_WIDTH;
     6170        if(lpColumn->cx == LVSCW_AUTOSIZE_USEHEADER)
     6171        {
     6172            /* make it fill the remainder of the controls width */
     6173            RECT rcHeader;
     6174            INT item_index;
     6175
     6176            for(item_index = 0; item_index < (nColumn - 1); item_index++)
     6177            {
     6178                LISTVIEW_GetHeaderRect(infoPtr, item_index, &rcHeader);
     6179                lphdi->cxy += rcHeader.right - rcHeader.left;
     6180            }
     6181
     6182            /* retrieve the layout of the header */
     6183            GetClientRect(infoPtr->hwndSelf, &rcHeader);
     6184            TRACE("start cxy=%d rcHeader=%s\n", lphdi->cxy, debugrect(&rcHeader));
     6185
     6186            lphdi->cxy = (rcHeader.right - rcHeader.left) - lphdi->cxy;
     6187        }
     6188        else
     6189            lphdi->cxy = lpColumn->cx;
     6190    }
     6191
     6192    if (lpColumn->mask & LVCF_TEXT)
     6193    {
     6194        lphdi->mask |= HDI_TEXT | HDI_FORMAT;
     6195        lphdi->fmt |= HDF_STRING;
     6196        lphdi->pszText = lpColumn->pszText;
     6197        lphdi->cchTextMax = textlenT(lpColumn->pszText, isW);
     6198    }
     6199
     6200    if (lpColumn->mask & LVCF_IMAGE)
     6201    {
     6202        lphdi->mask |= HDI_IMAGE;
     6203        lphdi->iImage = lpColumn->iImage;
     6204    }
     6205
     6206    if (lpColumn->mask & LVCF_ORDER)
     6207    {
     6208        lphdi->mask |= HDI_ORDER;
     6209        lphdi->iOrder = lpColumn->iOrder;
     6210    }
     6211}
     6212
     6213
     6214/***
     6215 * DESCRIPTION:
     6216 * Inserts a new column.
     6217 *
     6218 * PARAMETER(S):
     6219 * [I] infoPtr : valid pointer to the listview structure
     6220 * [I] nColumn : column index
     6221 * [I] lpColumn : column information
     6222 * [I] isW : TRUE if lpColumn is Unicode, FALSE otherwise
     6223 *
     6224 * RETURN:
     6225 *   SUCCESS : new column index
     6226 *   FAILURE : -1
     6227 */
     6228static INT LISTVIEW_InsertColumnT(LISTVIEW_INFO *infoPtr, INT nColumn,
     6229                                  const LVCOLUMNW *lpColumn, BOOL isW)
     6230{
     6231    COLUMN_INFO *lpColumnInfo;
     6232    INT nNewColumn;
     6233    HDITEMW hdi;
     6234
     6235    TRACE("(nColumn=%d, lpColumn=%s, isW=%d)\n", nColumn, debuglvcolumn_t(lpColumn, isW), isW);
     6236
     6237    if (!lpColumn || nColumn < 0) return -1;
     6238    nColumn = min(nColumn, infoPtr->hdpaColumns->nItemCount);
     6239   
     6240    ZeroMemory(&hdi, sizeof(HDITEMW));
     6241    column_fill_hditem(infoPtr, &hdi, nColumn, lpColumn, isW);
     6242
     6243    /* insert item in header control */
     6244    nNewColumn = SendMessageW(infoPtr->hwndHeader,
     6245                              isW ? HDM_INSERTITEMW : HDM_INSERTITEMA,
     6246                              (WPARAM)nColumn, (LPARAM)&hdi);
     6247    if (nNewColumn == -1) return -1;
     6248    if (nNewColumn != nColumn) ERR("nColumn=%d, nNewColumn=%d\n", nColumn, nNewColumn);
     6249   
     6250    /* create our own column info */
     6251    if (!(lpColumnInfo = COMCTL32_Alloc(sizeof(COLUMN_INFO)))) goto fail;
     6252    if (DPA_InsertPtr(infoPtr->hdpaColumns, nNewColumn, lpColumnInfo) == -1) goto fail;
     6253
     6254    if (lpColumn->mask & LVCF_FMT) lpColumnInfo->fmt = lpColumn->fmt;
     6255    if (!Header_GetItemRect(infoPtr->hwndHeader, nNewColumn, &lpColumnInfo->rcHeader)) goto fail;
     6256
     6257    /* now we have to actually adjust the data */
     6258    if (!(infoPtr->dwStyle & LVS_OWNERDATA) && infoPtr->nItemCount > 0)
     6259    {
     6260        SUBITEM_INFO *lpSubItem, *lpMainItem, **lpNewItems = 0;
     6261        HDPA hdpaSubItems;
     6262        INT nItem, i;
     6263       
     6264        /* preallocate memory, so we can fail gracefully */
     6265        if (nNewColumn == 0)
     6266        {
     6267            lpNewItems = COMCTL32_Alloc(sizeof(SUBITEM_INFO *) * infoPtr->nItemCount);
     6268            if (!lpNewItems) goto fail;
     6269            for (i = 0; i < infoPtr->nItemCount; i++)
     6270                if (!(lpNewItems[i] = COMCTL32_Alloc(sizeof(SUBITEM_INFO)))) break;
     6271            if (i != infoPtr->nItemCount)
     6272            {
     6273                for(; i >=0; i--) COMCTL32_Free(lpNewItems[i]);
     6274                COMCTL32_Free(lpNewItems);
     6275                goto fail;
     6276            }
     6277        }
     6278       
     6279        for (nItem = 0; nItem < infoPtr->nItemCount; nItem++)
     6280        {
     6281            hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
     6282            for (i = 1; i < hdpaSubItems->nItemCount; i++)
     6283            {
     6284                lpSubItem = (SUBITEM_INFO *)DPA_GetPtr(hdpaSubItems, i);
     6285                if (lpSubItem->iSubItem >= nNewColumn)
     6286                    lpSubItem->iSubItem++;
     6287            }
     6288
     6289            /* for inserting column 0, we have to special-case the main item */
     6290            if (nNewColumn == 0)
     6291            {
     6292                lpMainItem = (SUBITEM_INFO *)DPA_GetPtr(hdpaSubItems, 0);
     6293                lpSubItem = lpNewItems[nItem];
     6294                lpSubItem->hdr = lpMainItem->hdr;
     6295                lpSubItem->iSubItem = 1;
     6296                ZeroMemory(&lpMainItem->hdr, sizeof(lpMainItem->hdr));
     6297                lpMainItem->iSubItem = 0;
     6298                DPA_InsertPtr(hdpaSubItems, 1, lpSubItem);
     6299            }
     6300        }
     6301
     6302        COMCTL32_Free(lpNewItems);
     6303    }
     6304
     6305    /* make space for the new column */
     6306    LISTVIEW_ScrollColumns(infoPtr, nNewColumn + 1, lpColumnInfo->rcHeader.right - lpColumnInfo->rcHeader.left);
     6307   
     6308    return nNewColumn;
     6309
     6310fail:
     6311    if (nNewColumn != -1) SendMessageW(infoPtr->hwndHeader, HDM_DELETEITEM, nNewColumn, 0);
     6312    if (lpColumnInfo)
     6313    {
     6314        DPA_DeletePtr(infoPtr->hdpaColumns, nNewColumn);
     6315        COMCTL32_Free(lpColumnInfo);
     6316    }
     6317    return -1;
    74996318}
    75006319
     
    75026321 * DESCRIPTION:
    75036322 * Sets the attributes of a header item.
    7504  *
    7505  * PARAMETER(S):
    7506  * [I] HWND : window handle
    7507  * [I] INT : column index
    7508  * [I] LPLVCOLUMNW : column attributes
    7509  * [I] isW: if TRUE, the lpColumn is a LPLVCOLUMNW,
    7510  *          otherwise it is in fact a LPLVCOLUMNA
     6323 *
     6324 * PARAMETER(S):
     6325 * [I] infoPtr : valid pointer to the listview structure
     6326 * [I] nColumn : column index
     6327 * [I] lpColumn : column attributes
     6328 * [I] isW: if TRUE, the lpColumn is a LPLVCOLUMNW, else it is a LPLVCOLUMNA
    75116329 *
    75126330 * RETURN:
     
    75146332 *   FAILURE : FALSE
    75156333 */
    7516 static LRESULT LISTVIEW_SetColumnT(HWND hwnd, INT nColumn,
    7517                                    LPLVCOLUMNW lpColumn, BOOL isW)
    7518 {
    7519   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    7520   BOOL bResult = FALSE;
    7521   HDITEMW hdi, hdiget;
    7522 
    7523   if ((lpColumn != NULL) && (nColumn >= 0) &&
    7524       (nColumn < Header_GetItemCount(infoPtr->hwndHeader)))
    7525   {
    7526     /* initialize memory */
    7527     ZeroMemory(&hdi, sizeof(hdi));
    7528 
    7529     if (lpColumn->mask & LVCF_FMT)
    7530     {
    7531       /* format member is valid */
    7532       hdi.mask |= HDI_FORMAT;
    7533 
    7534       /* get current format first */
    7535       hdiget.mask = HDI_FORMAT;
    7536       if (Header_GetItemW(infoPtr->hwndHeader, nColumn, &hdiget))
    7537               /* preserve HDF_STRING if present */
    7538               hdi.fmt = hdiget.fmt & HDF_STRING;
    7539 
    7540       /* set text alignment (leftmost column must be left-aligned) */
    7541       if (nColumn == 0)
    7542       {
    7543         hdi.fmt |= HDF_LEFT;
    7544       }
    7545       else
    7546       {
    7547         if (lpColumn->fmt & LVCFMT_LEFT)
    7548           hdi.fmt |= HDF_LEFT;
    7549         else if (lpColumn->fmt & LVCFMT_RIGHT)
    7550           hdi.fmt |= HDF_RIGHT;
    7551         else if (lpColumn->fmt & LVCFMT_CENTER)
    7552           hdi.fmt |= HDF_CENTER;
    7553       }
    7554      
    7555       if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
    7556         hdi.fmt |= HDF_BITMAP_ON_RIGHT;
    7557 
    7558       if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
    7559         hdi.fmt |= HDF_IMAGE;
    7560      
    7561       if (lpColumn->fmt & LVCFMT_IMAGE)
    7562       {
    7563         hdi.fmt |= HDF_IMAGE;
    7564         hdi.iImage = I_IMAGECALLBACK;
    7565       }
    7566     }
    7567 
    7568     if (lpColumn->mask & LVCF_WIDTH)
    7569     {
    7570       hdi.mask |= HDI_WIDTH;
    7571       hdi.cxy = lpColumn->cx;
    7572     }
    7573    
    7574     if (lpColumn->mask & LVCF_TEXT)
    7575     {
    7576       hdi.mask |= HDI_TEXT | HDI_FORMAT;
    7577       hdi.pszText = lpColumn->pszText;
    7578       hdi.cchTextMax = textlenT(lpColumn->pszText, isW);
    7579       hdi.fmt |= HDF_STRING;
    7580     }
    7581  
    7582     if (lpColumn->mask & LVCF_IMAGE)
    7583     {
    7584       hdi.mask |= HDI_IMAGE;
    7585       hdi.iImage = lpColumn->iImage;
    7586     }
    7587 
    7588     if (lpColumn->mask & LVCF_ORDER)
    7589     {
    7590       hdi.mask |= HDI_ORDER;
    7591       hdi.iOrder = lpColumn->iOrder;
    7592     }
     6334static BOOL LISTVIEW_SetColumnT(LISTVIEW_INFO *infoPtr, INT nColumn,
     6335                                const LVCOLUMNW *lpColumn, BOOL isW)
     6336{
     6337    HDITEMW hdi, hdiget;
     6338    BOOL bResult;
     6339
     6340    TRACE("(nColumn=%d, lpColumn=%s, isW=%d)\n", nColumn, debuglvcolumn_t(lpColumn, isW), isW);
     6341   
     6342    if (!lpColumn || nColumn < 0 || nColumn >= infoPtr->hdpaColumns->nItemCount) return FALSE;
     6343
     6344    ZeroMemory(&hdi, sizeof(HDITEMW));
     6345    if (lpColumn->mask & LVCF_FMT)
     6346    {
     6347        hdi.mask |= HDI_FORMAT;
     6348        hdiget.mask = HDI_FORMAT;
     6349        if (Header_GetItemW(infoPtr->hwndHeader, nColumn, &hdiget))
     6350            hdi.fmt = hdiget.fmt & HDF_STRING;
     6351    }
     6352    column_fill_hditem(infoPtr, &hdi, nColumn, lpColumn, isW);
    75936353
    75946354    /* set header item attributes */
    7595     if (isW)
    7596       bResult = Header_SetItemW(infoPtr->hwndHeader, nColumn, &hdi);
    7597     else
    7598       bResult = Header_SetItemA(infoPtr->hwndHeader, nColumn, &hdi);
    7599   }
    7600  
    7601   return bResult;
     6355    bResult = SendMessageW(infoPtr->hwndHeader, isW ? HDM_SETITEMW : HDM_SETITEMA, (WPARAM)nColumn, (LPARAM)&hdi);
     6356    if (!bResult) return FALSE;
     6357
     6358    if (lpColumn->mask & LVCF_FMT)
     6359    {
     6360        COLUMN_INFO *lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, nColumn);
     6361        int oldFmt = lpColumnInfo->fmt;
     6362       
     6363        lpColumnInfo->fmt = lpColumn->fmt;
     6364        if ((oldFmt ^ lpColumn->fmt) & (LVCFMT_JUSTIFYMASK | LVCFMT_IMAGE))
     6365        {
     6366            UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     6367            if (uView == LVS_REPORT) LISTVIEW_InvalidateColumn(infoPtr, nColumn);
     6368        }
     6369    }
     6370
     6371    return TRUE;
    76026372}
    76036373
     
    76076377 *
    76086378 * PARAMETERS:
    7609  * [I] HWND : window handle
    7610  * [I] INT : number of elements in column order array
    7611  * [I] INT : pointer to column order array
     6379 * [I] infoPtr : valid pointer to the listview structure
     6380 * [I] iCount : number of elements in column order array
     6381 * [I] lpiArray : pointer to column order array
    76126382 *
    76136383 * RETURN:
     
    76156385 *   FAILURE : FALSE
    76166386 */
    7617 static LRESULT LISTVIEW_SetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
    7618 {
    7619   /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0); */
    7620 
     6387static BOOL LISTVIEW_SetColumnOrderArray(LISTVIEW_INFO *infoPtr, INT iCount, const INT *lpiArray)
     6388{
    76216389  FIXME("iCount %d lpiArray %p\n", iCount, lpiArray);
    76226390
     
    76336401 *
    76346402 * PARAMETERS:
    7635  * [I] HWND : window handle
    7636  * [I] INT : column index
    7637  * [I] INT : column width
     6403 * [I] infoPtr : valid pointer to the listview structure
     6404 * [I] nColumn : column index
     6405 * [I] cx : column width
    76386406 *
    76396407 * RETURN:
     
    76416409 *   FAILURE : FALSE
    76426410 */
    7643 static LRESULT LISTVIEW_SetColumnWidth(HWND hwnd, INT iCol, INT cx)
    7644 {
    7645     LISTVIEW_INFO *infoPtr;
     6411static BOOL LISTVIEW_SetColumnWidth(LISTVIEW_INFO *infoPtr, INT nColumn, INT cx)
     6412{
     6413    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     6414    WCHAR szDispText[DISP_TEXT_SIZE] = { 0 };
     6415    INT max_cx = 0;
    76466416    HDITEMW hdi;
    7647     LRESULT lret;
    7648     LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    7649     UINT uView = lStyle & LVS_TYPEMASK;
    7650     HDC hdc;
    7651     HFONT header_font;
    7652     HFONT old_font;
    7653     SIZE size;
    7654     WCHAR text_buffer[DISP_TEXT_SIZE];
    7655     INT header_item_count;
    7656     INT item_index;
    7657     INT nLabelWidth;
    7658     RECT rcHeader;
    7659     LVITEMW lvItem;
    7660     WCHAR szDispText[DISP_TEXT_SIZE];
    7661 
    7662     /* make sure we can get the listview info */
    7663     if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0)))
    7664       return (FALSE);
    7665 
    7666     if (!infoPtr->hwndHeader) /* make sure we have a header */
    7667       return (FALSE);
     6417
     6418    TRACE("(nColumn=%d, cx=%d\n", nColumn, cx);
    76686419
    76696420    /* set column width only if in report or list mode */
    7670     if ((uView != LVS_REPORT) && (uView != LVS_LIST))
    7671       return (FALSE);           
    7672 
    7673     TRACE("(hwnd=%x, iCol=%d, cx=%d\n", hwnd, iCol, cx);
    7674    
     6421    if (uView != LVS_REPORT && uView != LVS_LIST) return FALSE;
     6422
    76756423    /* take care of invalid cx values */
    7676     if((uView == LVS_REPORT) && (cx < -2))
    7677       cx = LVSCW_AUTOSIZE;
    7678     else if (uView == LVS_LIST && (cx < 1))
    7679       return FALSE;
    7680  
     6424    if(uView == LVS_REPORT && cx < -2) cx = LVSCW_AUTOSIZE;
     6425    else if (uView == LVS_LIST && cx < 1) return FALSE;
     6426
    76816427    /* resize all columns if in LVS_LIST mode */
    7682     if(uView == LVS_LIST) {
    7683       infoPtr->nItemWidth = cx;
    7684       InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
    7685       return TRUE;
     6428    if(uView == LVS_LIST)
     6429    {
     6430        infoPtr->nItemWidth = cx;
     6431        LISTVIEW_InvalidateList(infoPtr);
     6432        return TRUE;
     6433    }
     6434
     6435    if (nColumn < 0 || nColumn >= infoPtr->hdpaColumns->nItemCount) return FALSE;
     6436
     6437    if (cx == LVSCW_AUTOSIZE || (cx == LVSCW_AUTOSIZE_USEHEADER && nColumn < infoPtr->hdpaColumns->nItemCount -1))
     6438    {
     6439        INT nLabelWidth;
     6440        LVITEMW lvItem;
     6441
     6442        lvItem.mask = LVIF_TEXT;       
     6443        lvItem.iItem = 0;
     6444        lvItem.iSubItem = nColumn;
     6445        lvItem.pszText = szDispText;
     6446        lvItem.cchTextMax = DISP_TEXT_SIZE;
     6447        for (; lvItem.iItem < infoPtr->nItemCount; lvItem.iItem++)
     6448        {
     6449            if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) continue;
     6450            nLabelWidth = LISTVIEW_GetStringWidthT(infoPtr, lvItem.pszText, TRUE);
     6451            if (max_cx < nLabelWidth) max_cx = nLabelWidth;
     6452        }
     6453        if (infoPtr->himlSmall && (nColumn == 0 || (LISTVIEW_GetColumnInfo(infoPtr, nColumn)->fmt & LVCFMT_IMAGE)))
     6454            max_cx += infoPtr->iconSize.cx;
     6455        max_cx += TRAILING_LABEL_PADDING;
    76866456    }
    76876457
    76886458    /* autosize based on listview items width */
    76896459    if(cx == LVSCW_AUTOSIZE)
    7690     {
    7691       /* set the width of the column to the width of the widest item */
    7692       if (iCol == 0 || uView == LVS_LIST)
    7693       {
    7694         cx = 0;
    7695         for(item_index = 0; item_index < GETITEMCOUNT(infoPtr); item_index++)
    7696         {
    7697           nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, item_index);
    7698           cx = (nLabelWidth>cx)?nLabelWidth:cx;
    7699         }
    7700         if (infoPtr->himlSmall)
    7701           cx += infoPtr->iconSize.cx + IMAGE_PADDING;
    7702       }
    7703       else
    7704       {
    7705         ZeroMemory(&lvItem, sizeof(lvItem));
    7706         lvItem.iSubItem = iCol;
    7707         lvItem.mask = LVIF_TEXT;
    7708         lvItem.cchTextMax = DISP_TEXT_SIZE;
    7709         lvItem.pszText = szDispText;
    7710         *lvItem.pszText = '\0';
    7711         cx = 0;
    7712         for(item_index = 0; item_index < GETITEMCOUNT(infoPtr); item_index++)
    7713         {
    7714           lvItem.iItem = item_index;
    7715           LISTVIEW_GetItemT(hwnd, &lvItem, FALSE, TRUE);
    7716           nLabelWidth = LISTVIEW_GetStringWidthT(hwnd, lvItem.pszText, TRUE);
    7717           cx = (nLabelWidth>cx)?nLabelWidth:cx;
    7718         }
    7719       }
    7720       cx += TRAILING_PADDING;
    7721     } /* autosize based on listview header width */
     6460        cx = max_cx;
    77226461    else if(cx == LVSCW_AUTOSIZE_USEHEADER)
    77236462    {
    7724       header_item_count = Header_GetItemCount(infoPtr->hwndHeader);
    7725  
    7726       /* if iCol is the last column make it fill the remainder of the controls width */
    7727       if(iCol == (header_item_count - 1)) {
    7728         /* get the width of every item except the current one */
    7729         hdi.mask = HDI_WIDTH;
    7730         cx = 0;
    7731        
    7732         for(item_index = 0; item_index < (header_item_count - 1); item_index++) {
    7733           Header_GetItemW(infoPtr->hwndHeader, item_index, (LPARAM)(&hdi));
    7734           cx+=hdi.cxy;
    7735         }
    7736  
    7737         /* retrieve the layout of the header */
    7738         GetWindowRect(infoPtr->hwndHeader, &rcHeader);
    7739 
    7740         cx = (rcHeader.right - rcHeader.left) - cx;
    7741       }                                 
    7742       else
    7743       {
    7744         /* Despite what the MS docs say, if this is not the last
    7745            column, then MS resizes the column to the width of the
    7746            largest text string in the column, including headers
    7747            and items. This is different from LVSCW_AUTOSIZE in that
    7748            LVSCW_AUTOSIZE ignores the header string length.
    7749            */
    7750            
    7751         /* retrieve header font */
    7752         header_font = SendMessageW(infoPtr->hwndHeader, WM_GETFONT, 0L, 0L);
    7753  
    7754         /* retrieve header text */
    7755         hdi.mask = HDI_TEXT;
    7756         hdi.cchTextMax = sizeof(text_buffer)/sizeof(text_buffer[0]);
    7757         hdi.pszText = text_buffer;             
    7758    
    7759         Header_GetItemW(infoPtr->hwndHeader, iCol, (LPARAM)(&hdi));
    7760  
    7761         /* determine the width of the text in the header */
    7762         hdc = GetDC(hwnd);
    7763         old_font = SelectObject(hdc, header_font); /* select the font into hdc */
    7764 
    7765         GetTextExtentPoint32W(hdc, text_buffer, lstrlenW(text_buffer), &size);
    7766  
    7767         SelectObject(hdc, old_font); /* restore the old font */   
    7768         ReleaseDC(hwnd, hdc);
    7769  
    7770         ZeroMemory(&lvItem, sizeof(lvItem));
    7771         lvItem.iSubItem = iCol;
    7772         lvItem.mask = LVIF_TEXT;
    7773         lvItem.cchTextMax = DISP_TEXT_SIZE;
    7774         lvItem.pszText = szDispText;
    7775         *lvItem.pszText = '\0';
    7776         cx = size.cx;
    7777         for(item_index = 0; item_index < GETITEMCOUNT(infoPtr); item_index++)
    7778         {
    7779           lvItem.iItem = item_index;
    7780           LISTVIEW_GetItemT(hwnd, &lvItem, FALSE, TRUE);
    7781           nLabelWidth = LISTVIEW_GetStringWidthT(hwnd, lvItem.pszText, TRUE);
    7782           nLabelWidth += TRAILING_PADDING;
    7783           /* While it is possible for subitems to have icons, even MS messes
    7784              up the positioning, so I suspect no applications actually use
    7785              them. */
    7786           if (item_index == 0 && infoPtr->himlSmall)
    7787             nLabelWidth += infoPtr->iconSize.cx + IMAGE_PADDING;
    7788           cx = (nLabelWidth>cx)?nLabelWidth:cx;
    7789         }
    7790       }
    7791   }
    7792 
    7793   /* call header to update the column change */
    7794   hdi.mask = HDI_WIDTH;                         
    7795 
    7796   hdi.cxy = cx;
    7797   lret = Header_SetItemW(infoPtr->hwndHeader, (WPARAM)iCol, (LPARAM)&hdi);
    7798  
    7799   InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
    7800  
    7801   return lret;
     6463        /* if iCol is the last column make it fill the remainder of the controls width */
     6464        if(nColumn == infoPtr->hdpaColumns->nItemCount - 1)
     6465        {
     6466            RECT rcHeader;
     6467            POINT Origin;
     6468
     6469            LISTVIEW_GetOrigin(infoPtr, &Origin);
     6470            LISTVIEW_GetHeaderRect(infoPtr, nColumn, &rcHeader);
     6471
     6472            cx = infoPtr->rcList.right - Origin.x - rcHeader.left;
     6473        }
     6474        else
     6475        {
     6476            /* Despite what the MS docs say, if this is not the last
     6477               column, then MS resizes the column to the width of the
     6478               largest text string in the column, including headers
     6479               and items. This is different from LVSCW_AUTOSIZE in that
     6480               LVSCW_AUTOSIZE ignores the header string length. */
     6481            cx = 0;
     6482
     6483            /* retrieve header text */
     6484            hdi.mask = HDI_TEXT;
     6485            hdi.cchTextMax = DISP_TEXT_SIZE;
     6486            hdi.pszText = szDispText;
     6487            if (Header_GetItemW(infoPtr->hwndHeader, nColumn, (LPARAM)&hdi))
     6488            {
     6489                HDC hdc = GetDC(infoPtr->hwndSelf);
     6490                HFONT old_font = SelectObject(hdc, (HFONT)SendMessageW(infoPtr->hwndHeader, WM_GETFONT, 0, 0));
     6491                SIZE size;
     6492
     6493                if (GetTextExtentPoint32W(hdc, hdi.pszText, lstrlenW(hdi.pszText), &size))
     6494                    cx = size.cx + TRAILING_HEADER_PADDING;
     6495                /* FIXME: Take into account the header image, if one is present */
     6496                SelectObject(hdc, old_font);
     6497                ReleaseDC(infoPtr->hwndSelf, hdc);
     6498            }
     6499            cx = max (cx, max_cx);
     6500        }
     6501    }
     6502
     6503    if (cx < 0) return FALSE;
     6504
     6505    /* call header to update the column change */
     6506    hdi.mask = HDI_WIDTH;
     6507    hdi.cxy = cx;
     6508    TRACE("hdi.cxy=%d\n", hdi.cxy);
     6509    return Header_SetItemW(infoPtr->hwndHeader, nColumn, (LPARAM)&hdi);
    78026510}
    78036511
     
    78076515 *
    78086516 * PARAMETERS:
    7809  * [I] HWND  : window handle
    7810  * [I] DWORD : mask
    7811  * [I] DWORD : style
     6517 * [I] infoPtr : valid pointer to the listview structure
     6518 * [I] dwMask : mask
     6519 * [I] dwStyle : style
    78126520 *
    78136521 * RETURN:
     
    78156523 *   FAILURE : 0
    78166524 */
    7817 static LRESULT LISTVIEW_SetExtendedListViewStyle(HWND hwnd, DWORD dwMask, DWORD dwStyle)
    7818 {
    7819   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    7820   DWORD dwOldStyle = infoPtr->dwExStyle;
    7821 
    7822   /* set new style */
    7823   if (dwMask)
    7824     infoPtr->dwExStyle = (dwOldStyle & ~dwMask) | (dwStyle & dwMask);
    7825   else
    7826     infoPtr->dwExStyle = dwStyle;
    7827 
    7828   return dwOldStyle;
    7829 }
    7830 
    7831 /* LISTVIEW_SetHotCursor */
     6525static DWORD LISTVIEW_SetExtendedListViewStyle(LISTVIEW_INFO *infoPtr, DWORD dwMask, DWORD dwStyle)
     6526{
     6527    DWORD dwOldStyle = infoPtr->dwLvExStyle;
     6528
     6529    /* set new style */
     6530    if (dwMask)
     6531        infoPtr->dwLvExStyle = (dwOldStyle & ~dwMask) | (dwStyle & dwMask);
     6532    else
     6533        infoPtr->dwLvExStyle = dwStyle;
     6534
     6535    return dwOldStyle;
     6536}
     6537
     6538/***
     6539 * DESCRIPTION:
     6540 * Sets the new hot cursor used during hot tracking and hover selection.
     6541 *
     6542 * PARAMETER(S):
     6543 * [I] infoPtr : valid pointer to the listview structure
     6544 * [I} hCurosr : the new hot cursor handle
     6545 *
     6546 * RETURN:
     6547 * Returns the previous hot cursor
     6548 */
     6549static HCURSOR LISTVIEW_SetHotCursor(LISTVIEW_INFO *infoPtr, HCURSOR hCursor)
     6550{
     6551    HCURSOR oldCursor = infoPtr->hHotCursor;
     6552   
     6553    infoPtr->hHotCursor = hCursor;
     6554
     6555    return oldCursor;
     6556}
     6557
    78326558
    78336559/***
     
    78366562 *
    78376563 * PARAMETERS:
    7838  * [I] HWND  : window handle
    7839  * [I] INT  : index
     6564 * [I] infoPtr : valid pointer to the listview structure
     6565 * [I] iIndex : index
    78406566 *
    78416567 * RETURN:
     
    78436569 *   FAILURE : -1 (no hot item)
    78446570 */
    7845 static LRESULT LISTVIEW_SetHotItem(HWND hwnd, INT iIndex)
    7846 {
    7847   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    7848   INT iOldIndex = infoPtr->nHotItem;
    7849 
    7850   /* set new style */
    7851   infoPtr->nHotItem = iIndex;
    7852 
    7853   return iOldIndex;
    7854 }
     6571static INT LISTVIEW_SetHotItem(LISTVIEW_INFO *infoPtr, INT iIndex)
     6572{
     6573    INT iOldIndex = infoPtr->nHotItem;
     6574   
     6575    infoPtr->nHotItem = iIndex;
     6576   
     6577    return iOldIndex;
     6578}
     6579
    78556580
    78566581/***
     
    78596584 *
    78606585 * PARAMETER(S):
    7861  * [I] HWND : window handle
    7862  * [I] DWORD : dwHoverTime, if -1 the hover time is set to the default
     6586 * [I] infoPtr : valid pointer to the listview structure
     6587 * [I] dwHoverTime : hover time, if -1 the hover time is set to the default
    78636588 *
    78646589 * RETURN:
    78656590 * Returns the previous hover time
    78666591 */
    7867 static LRESULT LISTVIEW_SetHoverTime(HWND hwnd, DWORD dwHoverTime)
    7868 {
    7869   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    7870   DWORD oldHoverTime = infoPtr->dwHoverTime;
    7871 
    7872   infoPtr->dwHoverTime = dwHoverTime;
    7873 
    7874   return oldHoverTime;
     6592static DWORD LISTVIEW_SetHoverTime(LISTVIEW_INFO *infoPtr, DWORD dwHoverTime)
     6593{
     6594    DWORD oldHoverTime = infoPtr->dwHoverTime;
     6595   
     6596    infoPtr->dwHoverTime = dwHoverTime;
     6597   
     6598    return oldHoverTime;
    78756599}
    78766600
     
    78806604 *
    78816605 * PARAMETER(S):
    7882  * [I] HWND : window handle
    7883  * [I] DWORD : MAKELONG(cx, cy)
     6606 * [I] infoPtr : valid pointer to the listview structure
     6607 * [I] cx : horizontal spacing (-1 = system spacing, 0 = autosize)
     6608 * [I] cy : vertical spacing (-1 = system spacing, 0 = autosize)
    78846609 *
    78856610 * RETURN:
    78866611 *   MAKELONG(oldcx, oldcy)
    78876612 */
    7888 #ifdef __WIN32OS2__
    7889 static LRESULT LISTVIEW_SetIconSpacing(HWND hwnd,WPARAM wParam,LPARAM lParam)
    7890 {
    7891   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
    7892   UINT dwStyle = GetWindowLongA(hwnd, GWL_STYLE);
    7893   UINT uView = dwStyle & LVS_TYPEMASK;
    7894   DWORD oldIS = MAKELONG(infoPtr->iconSpacing.cx,infoPtr->iconSpacing.cy);
    7895   INT cx = LOWORD(lParam),cy = HIWORD(lParam);
    7896 
    7897   if (cx == -1) cx = GetSystemMetrics(SM_CXICONSPACING);
    7898   if (cy == -1) cy = GetSystemMetrics(SM_CYICONSPACING);
    7899   if ((cx != infoPtr->iconSpacing.cx) || (cy != infoPtr->iconSpacing.cy))
    7900   {
     6613static DWORD LISTVIEW_SetIconSpacing(LISTVIEW_INFO *infoPtr, INT cx, INT cy)
     6614{
     6615    DWORD oldspacing = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
     6616    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     6617
     6618    TRACE("requested=(%d,%d)\n", cx, cy);
     6619   
     6620    /* this is supported only for LVS_ICON style */
     6621    if (uView != LVS_ICON) return oldspacing;
     6622 
     6623    /* set to defaults, if instructed to */
     6624    if (cx == -1) cx = GetSystemMetrics(SM_CXICONSPACING);
     6625    if (cy == -1) cy = GetSystemMetrics(SM_CYICONSPACING);
     6626
     6627    /* if 0 then compute width
     6628     * FIXME: Should scan each item and determine max width of
     6629     *        icon or label, then make that the width */
     6630    if (cx == 0)
     6631        cx = infoPtr->iconSpacing.cx;
     6632
     6633    /* if 0 then compute height */
     6634    if (cy == 0)
     6635        cy = infoPtr->iconSize.cy + 2 * infoPtr->ntmHeight +
     6636             ICON_BOTTOM_PADDING + ICON_TOP_PADDING + LABEL_VERT_PADDING;
     6637   
     6638
    79016639    infoPtr->iconSpacing.cx = cx;
    79026640    infoPtr->iconSpacing.cy = cy;
    7903     if (((uView == LVS_ICON) || (uView == LVS_SMALLICON)) && (dwStyle & LVS_AUTOARRANGE))
    7904     {
    7905       LISTVIEW_Arrange(hwnd,LVA_DEFAULT);
    7906     }
    7907   }
    7908   return oldIS;
    7909 }
    7910 #else
    7911 static LRESULT LISTVIEW_SetIconSpacing(HWND hwnd, DWORD spacing)
    7912 {
    7913   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
    7914   INT cy = HIWORD(spacing);
    7915   INT cx = LOWORD(spacing);
    7916   DWORD oldspacing;
    7917   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
    7918   UINT uView = lStyle & LVS_TYPEMASK;
    7919 
    7920   oldspacing = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
    7921   if (cx == -1) /* set to default */
    7922     cx = GetSystemMetrics(SM_CXICONSPACING);
    7923   if (cy == -1) /* set to default */
    7924     cy = GetSystemMetrics(SM_CYICONSPACING);
    7925 
    7926   if (cx)
    7927     infoPtr->iconSpacing.cx = cx;
    7928   else
    7929   {  /* if 0 then compute width */
    7930     if (uView == LVS_ICON)
    7931        FIXME("width computation not yet done\n");
    7932        /*
    7933         * Should scan each item and determine max width of
    7934         * icon or label, then make that the width
    7935         */
    7936      else /* FIXME: unknown computation for non LVS_ICON - this is a guess */
    7937        infoPtr->iconSpacing.cx = LISTVIEW_GetItemWidth(hwnd);
    7938   }
    7939   if (cy)
    7940       infoPtr->iconSpacing.cy = cy;
    7941   else
    7942   {  /* if 0 then compute height */
    7943     if (uView == LVS_ICON)
    7944        infoPtr->iconSpacing.cy = infoPtr->iconSize.cy + infoPtr->ntmHeight
    7945                                   + ICON_BOTTOM_PADDING + ICON_TOP_PADDING + LABEL_VERT_OFFSET;
    7946         /* FIXME.  I don't think so; I think it is based on twice the ntmHeight */
    7947     else /* FIXME: unknown computation for non LVS_ICON - this is a guess */
    7948        infoPtr->iconSpacing.cy = LISTVIEW_GetItemHeight(hwnd);
    7949   }
    7950 
    7951   TRACE("old=(%d,%d), new=(%ld,%ld)\n", LOWORD(oldspacing), HIWORD(oldspacing),
    7952         infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
    7953 
    7954   /* these depend on the iconSpacing */
    7955   infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
    7956   infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
    7957 
    7958   return oldspacing;
    7959 }
    7960 #endif
     6641
     6642    TRACE("old=(%d,%d), new=(%d,%d), iconSize=(%ld,%ld), ntmH=%d\n",
     6643          LOWORD(oldspacing), HIWORD(oldspacing), cx, cy,
     6644          infoPtr->iconSize.cx, infoPtr->iconSize.cy,
     6645          infoPtr->ntmHeight);
     6646
     6647    /* these depend on the iconSpacing */
     6648    LISTVIEW_UpdateItemSize(infoPtr);
     6649
     6650    return oldspacing;
     6651}
     6652
     6653inline void set_icon_size(SIZE *size, HIMAGELIST himl, BOOL small)
     6654{
     6655    INT cx, cy;
     6656   
     6657    if (himl && ImageList_GetIconSize(himl, &cx, &cy))
     6658    {
     6659        size->cx = cx;
     6660        size->cy = cy;
     6661    }
     6662    else
     6663    {
     6664        size->cx = GetSystemMetrics(small ? SM_CXSMICON : SM_CXICON);
     6665        size->cy = GetSystemMetrics(small ? SM_CYSMICON : SM_CYICON);
     6666    }
     6667}
    79616668
    79626669/***
    79636670 * DESCRIPTION:
    79646671 * Sets image lists.
    7965  * 
    7966  * PARAMETER(S):
    7967  * [I] HWND : window handle
    7968  * [I] INT : image list type 
    7969  * [I] HIMAGELIST : image list handle
     6672 *
     6673 * PARAMETER(S):
     6674 * [I] infoPtr : valid pointer to the listview structure
     6675 * [I] nType : image list type
     6676 * [I] himl : image list handle
    79706677 *
    79716678 * RETURN:
     
    79736680 *   FAILURE : NULL
    79746681 */
    7975 static HIMAGELIST LISTVIEW_SetImageList(HWND hwnd, INT nType, HIMAGELIST himl)
    7976 {
    7977   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    7978   HIMAGELIST himlOld = 0;
    7979   INT oldHeight;
    7980 
    7981   switch (nType)
    7982   {
    7983   case LVSIL_NORMAL:
    7984     himlOld = infoPtr->himlNormal;
    7985     infoPtr->himlNormal = himl;
     6682static HIMAGELIST LISTVIEW_SetImageList(LISTVIEW_INFO *infoPtr, INT nType, HIMAGELIST himl)
     6683{
     6684    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     6685    INT oldHeight = infoPtr->nItemHeight;
     6686    HIMAGELIST himlOld = 0;
     6687
     6688    TRACE("(nType=%d, himl=%p\n", nType, himl);
     6689
     6690    switch (nType)
     6691    {
     6692    case LVSIL_NORMAL:
     6693        himlOld = infoPtr->himlNormal;
     6694        infoPtr->himlNormal = himl;
     6695        if (uView == LVS_ICON) set_icon_size(&infoPtr->iconSize, himl, FALSE);
     6696        LISTVIEW_SetIconSpacing(infoPtr, 0, 0);
    79866697    break;
    79876698
    7988   case LVSIL_SMALL:
    7989     himlOld = infoPtr->himlSmall;
    7990     infoPtr->himlSmall = himl;
     6699    case LVSIL_SMALL:
     6700        himlOld = infoPtr->himlSmall;
     6701        infoPtr->himlSmall = himl;
     6702         if (uView != LVS_ICON) set_icon_size(&infoPtr->iconSize, himl, TRUE);
    79916703    break;
    79926704
    7993   case LVSIL_STATE:
    7994     himlOld = infoPtr->himlState;
    7995     infoPtr->himlState = himl;
    7996     ImageList_SetBkColor(infoPtr->himlState, CLR_NONE);
     6705    case LVSIL_STATE:
     6706        himlOld = infoPtr->himlState;
     6707        infoPtr->himlState = himl;
     6708        set_icon_size(&infoPtr->iconStateSize, himl, TRUE);
     6709        ImageList_SetBkColor(infoPtr->himlState, CLR_NONE);
    79976710    break;
    7998   }
    7999 
    8000   oldHeight = infoPtr->nItemHeight;
    8001   infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
    8002   if (infoPtr->nItemHeight != oldHeight)
    8003     LISTVIEW_UpdateScroll(hwnd);
    8004 
    8005   return himlOld;
     6711
     6712    default:
     6713        ERR("Unknown icon type=%d\n", nType);
     6714        return NULL;
     6715    }
     6716
     6717    infoPtr->nItemHeight = LISTVIEW_CalculateItemHeight(infoPtr);
     6718    if (infoPtr->nItemHeight != oldHeight)
     6719        LISTVIEW_UpdateScroll(infoPtr);
     6720
     6721    return himlOld;
    80066722}
    80076723
     
    80096725 * DESCRIPTION:
    80106726 * Preallocates memory (does *not* set the actual count of items !)
    8011  * 
    8012  * PARAMETER(S):
    8013  * [I] HWND : window handle
    8014  * [I] INT  : item count (projected number of items to allocate)
    8015  * [I] DWORD : update flags
     6727 *
     6728 * PARAMETER(S):
     6729 * [I] infoPtr : valid pointer to the listview structure
     6730 * [I] nItems : item count (projected number of items to allocate)
     6731 * [I] dwFlags : update flags
    80166732 *
    80176733 * RETURN:
     
    80196735 *   FAILURE : FALSE
    80206736 */
    8021 static BOOL LISTVIEW_SetItemCount(HWND hwnd, INT nItems, DWORD dwFlags)
    8022 {
    8023   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongW(hwnd, 0);
    8024 
    8025   TRACE("(hwnd=%x, nItems=%d, dwFlags=%lx)\n", hwnd, nItems, dwFlags);
    8026 
    8027   if (GetWindowLongW(hwnd, GWL_STYLE) & LVS_OWNERDATA)
    8028   {
    8029       int precount,topvisible;
    8030 
    8031       TRACE("LVS_OWNERDATA is set!\n");
    8032       if (dwFlags & (LVSICF_NOINVALIDATEALL | LVSICF_NOSCROLL))
    8033         FIXME("flags %s %s not implemented\n",
    8034               (dwFlags & LVSICF_NOINVALIDATEALL) ? "LVSICF_NOINVALIDATEALL"
    8035               : "",
    8036               (dwFlags & LVSICF_NOSCROLL) ? "LVSICF_NOSCROLL" : "");
    8037 
    8038       /*
    8039        * Internally remove all the selections.
    8040        */
    8041       do
    8042       {
    8043         LISTVIEW_SELECTION *selection;
    8044         selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,0);
    8045         if (selection)
    8046             LISTVIEW_RemoveSelectionRange(hwnd,selection->lower,
    8047                                           selection->upper);
    8048       }
    8049       while (infoPtr->hdpaSelectionRanges->nItemCount>0);
    8050  
    8051       precount = infoPtr->hdpaItems->nItemCount;
    8052       topvisible = ListView_GetTopIndex(hwnd) +
    8053                    LISTVIEW_GetCountPerColumn(hwnd) + 1;
    8054 
    8055       infoPtr->hdpaItems->nItemCount = nItems;
    8056 
    8057       infoPtr->nItemWidth = max(LISTVIEW_GetItemWidth(hwnd),
    8058                                 DEFAULT_COLUMN_WIDTH);
    8059 
    8060       LISTVIEW_UpdateSize(hwnd);
    8061       LISTVIEW_UpdateScroll(hwnd);
    8062 
    8063       if (min(precount,infoPtr->hdpaItems->nItemCount)<topvisible)
    8064         InvalidateRect(hwnd, NULL, TRUE);
    8065   }
    8066   else
    8067   {
    8068     /* According to MSDN for non-LVS_OWNERDATA this is just
    8069      * a performance issue. The control allocates its internal
    8070      * data structures for the number of items specified. It
    8071      * cuts down on the number of memory allocations. Therefore
    8072      * we will just issue a WARN here
    8073      */
    8074      WARN("for non-ownerdata performance option not implemented.\n");
    8075   }
    8076 
    8077   return TRUE;
     6737static BOOL LISTVIEW_SetItemCount(LISTVIEW_INFO *infoPtr, INT nItems, DWORD dwFlags)
     6738{
     6739    TRACE("(nItems=%d, dwFlags=%lx)\n", nItems, dwFlags);
     6740
     6741    if (infoPtr->dwStyle & LVS_OWNERDATA)
     6742    {
     6743        UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     6744        INT nOldCount = infoPtr->nItemCount;
     6745
     6746        if (nItems < nOldCount)
     6747        {
     6748            RANGE range = { nItems, nOldCount };
     6749            ranges_del(infoPtr->selectionRanges, range);
     6750            if (infoPtr->nFocusedItem >= nItems)
     6751            {
     6752                infoPtr->nFocusedItem = -1;
     6753                SetRectEmpty(&infoPtr->rcFocus);
     6754            }
     6755        }
     6756
     6757        infoPtr->nItemCount = nItems;
     6758        LISTVIEW_UpdateScroll(infoPtr);
     6759
     6760        /* the flags are valid only in ownerdata report and list modes */
     6761        if (uView == LVS_ICON || uView == LVS_SMALLICON) dwFlags = 0;
     6762
     6763        if (!(dwFlags & LVSICF_NOSCROLL) && infoPtr->nFocusedItem != -1)
     6764            LISTVIEW_EnsureVisible(infoPtr, infoPtr->nFocusedItem, FALSE);
     6765
     6766        if (!(dwFlags & LVSICF_NOINVALIDATEALL))
     6767            LISTVIEW_InvalidateList(infoPtr);
     6768        else
     6769        {
     6770            INT nFrom, nTo;
     6771            POINT Origin;
     6772            RECT rcErase;
     6773           
     6774            LISTVIEW_GetOrigin(infoPtr, &Origin);
     6775            nFrom = min(nOldCount, nItems);
     6776            nTo = max(nOldCount, nItems);
     6777   
     6778            if (uView == LVS_REPORT)
     6779            {
     6780                rcErase.left = 0;
     6781                rcErase.top = nFrom * infoPtr->nItemHeight;
     6782                rcErase.right = infoPtr->nItemWidth;
     6783                rcErase.bottom = nTo * infoPtr->nItemHeight;
     6784                OffsetRect(&rcErase, Origin.x, Origin.y);
     6785                if (IntersectRect(&rcErase, &rcErase, &infoPtr->rcList))
     6786                    LISTVIEW_InvalidateRect(infoPtr, &rcErase);
     6787            }
     6788            else /* LVS_LIST */
     6789            {
     6790                INT nPerCol = LISTVIEW_GetCountPerColumn(infoPtr);
     6791
     6792                rcErase.left = (nFrom / nPerCol) * infoPtr->nItemWidth;
     6793                rcErase.top = (nFrom % nPerCol) * infoPtr->nItemHeight;
     6794                rcErase.right = rcErase.left + infoPtr->nItemWidth;
     6795                rcErase.bottom = nPerCol * infoPtr->nItemHeight;
     6796                OffsetRect(&rcErase, Origin.x, Origin.y);
     6797                if (IntersectRect(&rcErase, &rcErase, &infoPtr->rcList))
     6798                    LISTVIEW_InvalidateRect(infoPtr, &rcErase);
     6799
     6800                rcErase.left = (nFrom / nPerCol + 1) * infoPtr->nItemWidth;
     6801                rcErase.top = 0;
     6802                rcErase.right = (nTo / nPerCol + 1) * infoPtr->nItemWidth;
     6803                rcErase.bottom = nPerCol * infoPtr->nItemHeight;
     6804                OffsetRect(&rcErase, Origin.x, Origin.y);
     6805                if (IntersectRect(&rcErase, &rcErase, &infoPtr->rcList))
     6806                    LISTVIEW_InvalidateRect(infoPtr, &rcErase);
     6807            }
     6808        }
     6809    }
     6810    else
     6811    {
     6812        /* According to MSDN for non-LVS_OWNERDATA this is just
     6813         * a performance issue. The control allocates its internal
     6814         * data structures for the number of items specified. It
     6815         * cuts down on the number of memory allocations. Therefore
     6816         * we will just issue a WARN here
     6817         */
     6818        WARN("for non-ownerdata performance option not implemented.\n");
     6819    }
     6820
     6821    return TRUE;
    80786822}
    80796823
     
    80816825 * DESCRIPTION:
    80826826 * Sets the position of an item.
    8083  *
    8084  * PARAMETER(S):
    8085  * [I] HWND : window handle
    8086  * [I] INT : item index
    8087  * [I] LONG : x coordinate
    8088  * [I] LONG : y coordinate
     6827 *
     6828 * PARAMETER(S):
     6829 * [I] infoPtr : valid pointer to the listview structure
     6830 * [I] nItem : item index
     6831 * [I] pt : coordinate
    80896832 *
    80906833 * RETURN:
     
    80926835 *   FAILURE : FALSE
    80936836 */
    8094 static BOOL LISTVIEW_SetItemPosition(HWND hwnd, INT nItem,
    8095                                      LONG nPosX, LONG nPosY)
    8096 {
    8097   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongW(hwnd, 0);
    8098   UINT lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    8099   UINT uView = lStyle & LVS_TYPEMASK;
    8100   LISTVIEW_ITEM *lpItem;
    8101   HDPA hdpaSubItems;
    8102   BOOL bResult = FALSE;
    8103 
    8104   TRACE("(hwnd=%x, nItem=%d, X=%ld, Y=%ld)\n", hwnd, nItem, nPosX, nPosY);
    8105  
    8106   if (lStyle & LVS_OWNERDATA)
    8107     return FALSE;
    8108 
    8109   if ((nItem >= 0) || (nItem < GETITEMCOUNT(infoPtr)))
    8110   {
    8111     if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
    8112     {
    8113       if ( (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)) )
    8114       {
    8115         if ( (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)) )
    8116         {
    8117           POINT orig;
    8118           bResult = TRUE;
    8119           orig = lpItem->ptPosition;
    8120           if ((nPosX == -1) && (nPosY == -1))
    8121           {
    8122             /* This point value seems to be an undocumented feature. The
    8123              * best guess is that it means either at the origin, or at
    8124              * the true beginning of the list. I will assume the origin.
    8125              */
    8126             POINT pt1;
    8127             if (!LISTVIEW_GetOrigin(hwnd, &pt1))
    8128             {
    8129               pt1.x = 0;
    8130               pt1.y = 0;
    8131             }
    8132             nPosX = pt1.x;
    8133             nPosY = pt1.y;
    8134             if (uView == LVS_ICON)
    8135             {
    8136               nPosX += (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
    8137               nPosY += ICON_TOP_PADDING;
    8138             }
    8139             TRACE("requested special (-1,-1), set to origin (%ld,%ld)\n",
    8140                   nPosX, nPosY);
    8141           }
    8142 
    8143           lpItem->ptPosition.x = nPosX;
    8144           lpItem->ptPosition.y = nPosY;
    8145           if (uView == LVS_ICON)
    8146           {
    8147             lpItem->ptPosition.y -= ICON_TOP_PADDING;
    8148               lpItem->ptPosition.x -= (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
    8149               if ((lpItem->ptPosition.y < 0) || (lpItem->ptPosition.x < 0))
    8150               {
    8151                   FIXME("failed orig (%ld,%ld), intent (%ld,%ld), is (%ld, %ld), setting neg to 0\n",
    8152                         orig.x, orig.y, nPosX, nPosY, lpItem->ptPosition.x, lpItem->ptPosition.y);
    8153  
    8154                   /*
    8155                   if (lpItem->ptPosition.x < 0) lpItem->ptPosition.x = 0;
    8156                   if (lpItem->ptPosition.y < 0) lpItem->ptPosition.y = 0;
    8157                   */
    8158               }
    8159               else
    8160               {
    8161                   TRACE("orig (%ld,%ld), intent (%ld,%ld), is (%ld,%ld)\n",
    8162                         orig.x, orig.y, nPosX, nPosY, lpItem->ptPosition.x, lpItem->ptPosition.y);
    8163               }
    8164           }
    8165         }
    8166       }
    8167     }
    8168   }
    8169 
    8170   return bResult;
     6837static BOOL LISTVIEW_SetItemPosition(LISTVIEW_INFO *infoPtr, INT nItem, POINT pt)
     6838{
     6839    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     6840    POINT Origin;
     6841
     6842    TRACE("(nItem=%d, &pt=%s\n", nItem, debugpoint(&pt));
     6843
     6844    if (nItem < 0 || nItem >= infoPtr->nItemCount ||
     6845        !(uView == LVS_ICON || uView == LVS_SMALLICON)) return FALSE;
     6846
     6847    LISTVIEW_GetOrigin(infoPtr, &Origin);
     6848
     6849    /* This point value seems to be an undocumented feature.
     6850     * The best guess is that it means either at the origin,
     6851     * or at true beginning of the list. I will assume the origin. */
     6852    if ((pt.x == -1) && (pt.y == -1))
     6853        pt = Origin;
     6854   
     6855    if (uView == LVS_ICON)
     6856    {
     6857        pt.x -= (infoPtr->nItemWidth - infoPtr->iconSize.cx) / 2;
     6858        pt.y -= ICON_TOP_PADDING;
     6859    }
     6860    pt.x -= Origin.x;
     6861    pt.y -= Origin.y;
     6862
     6863    infoPtr->bAutoarrange = FALSE;
     6864
     6865    return LISTVIEW_MoveIconTo(infoPtr, nItem, &pt, FALSE);
    81716866}
    81726867
     
    81746869 * DESCRIPTION:
    81756870 * Sets the state of one or many items.
    8176  * 
    8177  * PARAMETER(S):
    8178  * [I] HWND : window handle
    8179  * [I]INT : item index
    8180  * [I] LPLVITEM : item or subitem info
     6871 *
     6872 * PARAMETER(S):
     6873 * [I] infoPtr : valid pointer to the listview structure
     6874 * [I] nItem : item index
     6875 * [I] lpLVItem : item or subitem info
    81816876 *
    81826877 * RETURN:
     
    81846879 *   FAILURE : FALSE
    81856880 */
    8186 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMW lpLVItem)
    8187 {
    8188   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    8189   BOOL bResult = TRUE;
    8190   LVITEMW lvItem;
    8191 
    8192   TRACE("(hwnd=%x, nItem=%d, lpLVItem=%s)\n",
    8193         hwnd, nItem, debuglvitem_t(lpLVItem, TRUE));
    8194 
    8195   ZeroMemory(&lvItem, sizeof(lvItem));
    8196   lvItem.mask = LVIF_STATE;
    8197   lvItem.state = lpLVItem->state;
    8198   lvItem.stateMask = lpLVItem->stateMask ;
    8199   lvItem.iItem = nItem;
    8200 
    8201   if (nItem == -1)
    8202   {
    8203     /* apply to all items */
    8204     for (lvItem.iItem = 0; lvItem.iItem < GETITEMCOUNT(infoPtr); lvItem.iItem++)
    8205       if (!ListView_SetItemW(hwnd, &lvItem)) bResult = FALSE;
    8206   }
    8207   else
    8208     bResult = ListView_SetItemW(hwnd, &lvItem);
    8209 
    8210   return bResult;
     6881static BOOL LISTVIEW_SetItemState(LISTVIEW_INFO *infoPtr, INT nItem, const LVITEMW *lpLVItem)
     6882{
     6883    BOOL bResult = TRUE;
     6884    LVITEMW lvItem;
     6885
     6886    lvItem.iItem = nItem;
     6887    lvItem.iSubItem = 0;
     6888    lvItem.mask = LVIF_STATE;
     6889    lvItem.state = lpLVItem->state;
     6890    lvItem.stateMask = lpLVItem->stateMask;
     6891    TRACE("lvItem=%s\n", debuglvitem_t(&lvItem, TRUE));
     6892
     6893    if (nItem == -1)
     6894    {
     6895        /* apply to all items */
     6896        for (lvItem.iItem = 0; lvItem.iItem < infoPtr->nItemCount; lvItem.iItem++)
     6897            if (!LISTVIEW_SetItemT(infoPtr, &lvItem, TRUE)) bResult = FALSE;
     6898    }
     6899    else
     6900        bResult = LISTVIEW_SetItemT(infoPtr, &lvItem, TRUE);
     6901
     6902    return bResult;
    82116903}
    82126904
     
    82146906 * DESCRIPTION:
    82156907 * Sets the text of an item or subitem.
    8216  * 
     6908 *
    82176909 * PARAMETER(S):
    82186910 * [I] hwnd : window handle
     
    82256917 *   FAILURE : FALSE
    82266918 */
    8227 static BOOL LISTVIEW_SetItemTextT(HWND hwnd, INT nItem, LPLVITEMW lpLVItem, BOOL isW)
    8228 {
    8229   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    8230   BOOL bResult = FALSE;
    8231   LVITEMW lvItem;
    8232 
    8233   TRACE("(hwnd=%x, nItem=%d, lpLVItem=%s, isW=%d)\n",
    8234         hwnd, nItem, debuglvitem_t(lpLVItem, isW), isW);
    8235  
    8236   if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
    8237   {
    8238     ZeroMemory(&lvItem, sizeof(LVITEMW));
     6919static BOOL LISTVIEW_SetItemTextT(LISTVIEW_INFO *infoPtr, INT nItem, const LVITEMW *lpLVItem, BOOL isW)
     6920{
     6921    LVITEMW lvItem;
     6922
     6923    if (nItem < 0 && nItem >= infoPtr->nItemCount) return FALSE;
     6924   
     6925    lvItem.iItem = nItem;
     6926    lvItem.iSubItem = lpLVItem->iSubItem;
    82396927    lvItem.mask = LVIF_TEXT;
    82406928    lvItem.pszText = lpLVItem->pszText;
    8241     lvItem.iItem = nItem;
    8242     lvItem.iSubItem = lpLVItem->iSubItem;
    8243     if(isW) bResult = ListView_SetItemW(hwnd, &lvItem);
    8244     else    bResult = ListView_SetItemA(hwnd, &lvItem);
    8245   }
    8246  
    8247   return bResult;
     6929    lvItem.cchTextMax = lpLVItem->cchTextMax;
     6930   
     6931    TRACE("(nItem=%d, lpLVItem=%s, isW=%d)\n", nItem, debuglvitem_t(&lvItem, isW), isW);
     6932
     6933    return LISTVIEW_SetItemT(infoPtr, &lvItem, isW);
    82486934}
    82496935
     
    82536939 *
    82546940 * PARAMETER(S):
    8255  * [I] HWND : window handle
    8256  * [I] INT : index
     6941 * [I] infoPtr : valid pointer to the listview structure
     6942 * [I] nIndex : index
    82576943 *
    82586944 * RETURN:
    82596945 * Index number or -1 if there is no selection mark.
    82606946 */
    8261 static LRESULT LISTVIEW_SetSelectionMark(HWND hwnd, INT nIndex)
    8262 {
    8263   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
     6947static INT LISTVIEW_SetSelectionMark(LISTVIEW_INFO *infoPtr, INT nIndex)
     6948{
    82646949  INT nOldIndex = infoPtr->nSelectionMark;
    82656950
    8266   TRACE("(hwnd=%x, nIndex=%d)\n", hwnd, nIndex);
     6951  TRACE("(nIndex=%d)\n", nIndex);
    82676952
    82686953  infoPtr->nSelectionMark = nIndex;
     
    82746959 * DESCRIPTION:
    82756960 * Sets the text background color.
    8276  * 
    8277  * PARAMETER(S):
    8278  * [I] HWND : window handle
    8279  * [I] COLORREF : text background color
     6961 *
     6962 * PARAMETER(S):
     6963 * [I] infoPtr : valid pointer to the listview structure
     6964 * [I] clrTextBk : text background color
    82806965 *
    82816966 * RETURN:
     
    82836968 *   FAILURE : FALSE
    82846969 */
    8285 static LRESULT LISTVIEW_SetTextBkColor(HWND hwnd, COLORREF clrTextBk)
    8286 {
    8287   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    8288 
    8289   TRACE("(hwnd=%x, clrTextBk=%lx)\n", hwnd, clrTextBk);
    8290  
    8291   infoPtr->clrTextBk = clrTextBk;
    8292   InvalidateRect(hwnd, NULL, TRUE);
    8293 
     6970static BOOL LISTVIEW_SetTextBkColor(LISTVIEW_INFO *infoPtr, COLORREF clrTextBk)
     6971{
     6972    TRACE("(clrTextBk=%lx)\n", clrTextBk);
     6973
     6974    if (infoPtr->clrTextBk != clrTextBk)
     6975    {
     6976        infoPtr->clrTextBk = clrTextBk;
     6977        LISTVIEW_InvalidateList(infoPtr);
     6978    }
     6979   
    82946980  return TRUE;
    82956981}
     
    82986984 * DESCRIPTION:
    82996985 * Sets the text foreground color.
    8300  * 
    8301  * PARAMETER(S):
    8302  * [I] HWND : window handle
    8303  * [I] COLORREF : text color
     6986 *
     6987 * PARAMETER(S):
     6988 * [I] infoPtr : valid pointer to the listview structure
     6989 * [I] clrText : text color
    83046990 *
    83056991 * RETURN:
     
    83076993 *   FAILURE : FALSE
    83086994 */
    8309 static LRESULT LISTVIEW_SetTextColor (HWND hwnd, COLORREF clrText)
    8310 {
    8311   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    8312 
    8313   TRACE("(hwnd=%x, clrText=%lx)\n", hwnd, clrText);
    8314 
    8315   infoPtr->clrText = clrText;
    8316   InvalidateRect(hwnd, NULL, TRUE);
    8317 
    8318   return TRUE;
    8319 }
    8320 
    8321 /* LISTVIEW_SetToolTips */
     6995static BOOL LISTVIEW_SetTextColor (LISTVIEW_INFO *infoPtr, COLORREF clrText)
     6996{
     6997    TRACE("(clrText=%lx)\n", clrText);
     6998
     6999    if (infoPtr->clrText != clrText)
     7000    {
     7001        infoPtr->clrText = clrText;
     7002        LISTVIEW_InvalidateList(infoPtr);
     7003    }
     7004
     7005    return TRUE;
     7006}
     7007
     7008/***
     7009 * DESCRIPTION:
     7010 * Determines which listview item is located at the specified position.
     7011 *
     7012 * PARAMETER(S):
     7013 * [I] infoPtr        : valid pointer to the listview structure
     7014 * [I] hwndNewToolTip : handle to new ToolTip
     7015 *
     7016 * RETURN:
     7017 *   old tool tip
     7018 */
     7019static HWND LISTVIEW_SetToolTips( LISTVIEW_INFO *infoPtr, HWND hwndNewToolTip)
     7020{
     7021  HWND hwndOldToolTip = infoPtr->hwndToolTip;
     7022  infoPtr->hwndToolTip = hwndNewToolTip;
     7023  return hwndOldToolTip;
     7024}
     7025
    83227026/* LISTVIEW_SetUnicodeFormat */
    83237027/* LISTVIEW_SetWorkAreas */
     
    83267030 * DESCRIPTION:
    83277031 * Callback internally used by LISTVIEW_SortItems()
    8328  * 
    8329  * PARAMETER(S):
    8330  * [I] LPVOID : first LISTVIEW_ITEM to compare
    8331  * [I] LPVOID : second LISTVIEW_ITEM to compare
    8332  * [I] LPARAM : HWND of control
     7032 *
     7033 * PARAMETER(S):
     7034 * [I] first : pointer to first ITEM_INFO to compare
     7035 * [I] second : pointer to second ITEM_INFO to compare
     7036 * [I] lParam : HWND of control
    83337037 *
    83347038 * RETURN:
     
    83407044{
    83417045  LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW((HWND)lParam, 0);
    8342   LISTVIEW_ITEM* lv_first = (LISTVIEW_ITEM*) DPA_GetPtr( (HDPA)first, 0 );
    8343   LISTVIEW_ITEM* lv_second = (LISTVIEW_ITEM*) DPA_GetPtr( (HDPA)second, 0 );
     7046  ITEM_INFO* lv_first = (ITEM_INFO*) DPA_GetPtr( (HDPA)first, 0 );
     7047  ITEM_INFO* lv_second = (ITEM_INFO*) DPA_GetPtr( (HDPA)second, 0 );
    83447048
    83457049  /* Forward the call to the client defined callback */
     
    83507054 * DESCRIPTION:
    83517055 * Sorts the listview items.
    8352  * 
    8353  * PARAMETER(S):
    8354  * [I] HWND : window handle
    8355  * [I] WPARAM : application-defined value
    8356  * [I] LPARAM : pointer to comparision callback
     7056 *
     7057 * PARAMETER(S):
     7058 * [I] infoPtr : valid pointer to the listview structure
     7059 * [I] pfnCompare : application-defined value
     7060 * [I] lParamSort : pointer to comparision callback
    83577061 *
    83587062 * RETURN:
     
    83607064 *   FAILURE : FALSE
    83617065 */
    8362 static LRESULT LISTVIEW_SortItems(HWND hwnd, PFNLVCOMPARE pfnCompare, LPARAM lParamSort)
    8363 {
    8364     LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    8365     UINT lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    8366     HDPA hdpaSubItems=NULL;
    8367     LISTVIEW_ITEM *pLVItem=NULL;
     7066static BOOL LISTVIEW_SortItems(LISTVIEW_INFO *infoPtr, PFNLVCOMPARE pfnCompare, LPARAM lParamSort)
     7067{
     7068    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     7069    HDPA hdpaSubItems;
     7070    ITEM_INFO *lpItem;
    83687071    LPVOID selectionMarkItem;
    8369     int nCount, i;
    8370 
    8371     TRACE("(hwnd=%x, pfnCompare=%p, lParamSort=%lx)\n", hwnd, pfnCompare, lParamSort);
    8372    
    8373     if (lStyle & LVS_OWNERDATA) return FALSE;
    8374 
    8375     if (!infoPtr || !infoPtr->hdpaItems) return FALSE;
    8376    
    8377     nCount = GETITEMCOUNT(infoPtr);
     7072    LVITEMW item;
     7073    int i;
     7074
     7075    TRACE("(pfnCompare=%p, lParamSort=%lx)\n", pfnCompare, lParamSort);
     7076
     7077    if (infoPtr->dwStyle & LVS_OWNERDATA) return FALSE;
     7078
     7079    if (!infoPtr->hdpaItems) return FALSE;
     7080
    83787081    /* if there are 0 or 1 items, there is no need to sort */
    8379     if (nCount < 2)
    8380         return TRUE;
    8381 
     7082    if (infoPtr->nItemCount < 2) return TRUE;
     7083
     7084    if (infoPtr->nFocusedItem >= 0)
     7085    {
     7086        hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, infoPtr->nFocusedItem);
     7087        lpItem = (ITEM_INFO *)DPA_GetPtr(hdpaSubItems, 0);
     7088        if (lpItem) lpItem->state |= LVIS_FOCUSED;
     7089    }
     7090    /* FIXME: go thorugh selected items and mark them so in lpItem->state */
     7091    /*        clear the lpItem->state for non-selected ones */
     7092    /*        remove the selection ranges */
     7093   
    83827094    infoPtr->pfnCompare = pfnCompare;
    83837095    infoPtr->lParamSort = lParamSort;
    8384     DPA_Sort(infoPtr->hdpaItems, LISTVIEW_CallBackCompare, hwnd);
    8385 
    8386     /* Adjust selections and indices so that they are the way they should 
    8387      * be after the sort (otherwise, the list items move around, but 
    8388      * whatever is at the item's previous original position will be 
     7096    DPA_Sort(infoPtr->hdpaItems, LISTVIEW_CallBackCompare, (LPARAM)infoPtr->hwndSelf);
     7097
     7098    /* Adjust selections and indices so that they are the way they should
     7099     * be after the sort (otherwise, the list items move around, but
     7100     * whatever is at the item's previous original position will be
    83897101     * selected instead)
    83907102     */
    83917103    selectionMarkItem=(infoPtr->nSelectionMark>=0)?DPA_GetPtr(infoPtr->hdpaItems, infoPtr->nSelectionMark):NULL;
    8392     for (i=0; i < nCount; i++)
    8393     {
    8394        hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
    8395        pLVItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
    8396 
    8397        if (pLVItem->state & LVIS_SELECTED)
    8398           LISTVIEW_AddSelectionRange(hwnd, i, i);
    8399        else
    8400           LISTVIEW_RemoveSelectionRange(hwnd, i, i);
    8401        if (pLVItem->state & LVIS_FOCUSED)
    8402           infoPtr->nFocusedItem=i;
     7104    for (i=0; i < infoPtr->nItemCount; i++)
     7105    {
     7106        hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
     7107        lpItem = (ITEM_INFO *)DPA_GetPtr(hdpaSubItems, 0);
     7108
     7109        if (lpItem->state & LVIS_SELECTED)
     7110        {
     7111            item.state = LVIS_SELECTED;
     7112            item.stateMask = LVIS_SELECTED;
     7113            LISTVIEW_SetItemState(infoPtr, i, &item);
     7114        }
     7115        if (lpItem->state & LVIS_FOCUSED)
     7116        {
     7117            infoPtr->nFocusedItem = i;
     7118            lpItem->state &= ~LVIS_FOCUSED;
     7119        }
    84037120    }
    84047121    if (selectionMarkItem != NULL)
    8405        infoPtr->nSelectionMark = DPA_GetPtrIndex(infoPtr->hdpaItems, selectionMarkItem);
     7122        infoPtr->nSelectionMark = DPA_GetPtrIndex(infoPtr->hdpaItems, selectionMarkItem);
    84067123    /* I believe nHotItem should be left alone, see LISTVIEW_ShiftIndices */
    84077124
    8408     /* align the items */
    8409     LISTVIEW_AlignTop(hwnd);
    8410 
    84117125    /* refresh the display */
    8412     InvalidateRect(hwnd, NULL, TRUE);
     7126    if (uView != LVS_ICON && uView != LVS_SMALLICON)
     7127        LISTVIEW_InvalidateList(infoPtr);
    84137128
    84147129    return TRUE;
    84157130}
    84167131
    8417 /* LISTVIEW_SubItemHitTest */
    8418 
    84197132/***
    84207133 * DESCRIPTION:
    84217134 * Updates an items or rearranges the listview control.
    8422  * 
    8423  * PARAMETER(S):
    8424  * [I] HWND : window handle
    8425  * [I] INT : item index
     7135 *
     7136 * PARAMETER(S):
     7137 * [I] infoPtr : valid pointer to the listview structure
     7138 * [I] nItem : item index
    84267139 *
    84277140 * RETURN:
     
    84297142 *   FAILURE : FALSE
    84307143 */
    8431 static LRESULT LISTVIEW_Update(HWND hwnd, INT nItem)
    8432 {
    8433   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    8434   LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    8435   BOOL bResult = FALSE;
    8436   RECT rc;
    8437 
    8438   TRACE("(hwnd=%x, nItem=%d)\n", hwnd, nItem);
    8439  
    8440   if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
    8441   {
    8442     bResult = TRUE;
     7144static BOOL LISTVIEW_Update(LISTVIEW_INFO *infoPtr, INT nItem)
     7145{
     7146    TRACE("(nItem=%d)\n", nItem);
     7147
     7148    if (nItem < 0 || nItem >= infoPtr->nItemCount) return FALSE;
    84437149
    84447150    /* rearrange with default alignment style */
    8445     if ((lStyle & LVS_AUTOARRANGE) && (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
    8446         ((lStyle & LVS_TYPEMASK)  == LVS_SMALLICON)))
    8447     {
    8448       ListView_Arrange(hwnd, 0);
    8449     }
     7151    if (is_autoarrange(infoPtr))
     7152        LISTVIEW_Arrange(infoPtr, LVA_DEFAULT);
    84507153    else
    8451     {
    8452       /* get item bounding rectangle */
    8453       ListView_GetItemRect(hwnd, nItem, &rc, LVIR_BOUNDS);
    8454       InvalidateRect(hwnd, &rc, TRUE);
    8455     }
    8456   }
    8457 
    8458   return bResult;
    8459 }
    8460 
     7154        LISTVIEW_InvalidateItem(infoPtr, nItem);
     7155
     7156    return TRUE;
     7157}
     7158
     7159       
    84617160/***
    84627161 * DESCRIPTION:
    84637162 * Creates the listview control.
    8464  *
    8465  * PARAMETER(S):
    8466  * [I] HWND : window handle
    8467  *
    8468  * RETURN:
    8469  * Zero
    8470  */
    8471 static LRESULT LISTVIEW_Create(HWND hwnd, LPCREATESTRUCTW lpcs)
    8472 {
    8473   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
     7163 *
     7164 * PARAMETER(S):
     7165 * [I] hwnd : window handle
     7166 * [I] lpcs : the create parameters
     7167 *
     7168 * RETURN:
     7169 *   Success: 0
     7170 *   Failure: -1
     7171 */
     7172static LRESULT LISTVIEW_Create(HWND hwnd, const CREATESTRUCTW *lpcs)
     7173{
     7174  LISTVIEW_INFO *infoPtr;
    84747175  UINT uView = lpcs->style & LVS_TYPEMASK;
    84757176  LOGFONTW logFont;
    84767177
    8477   TRACE("(hwnd=%x, lpcs=%p)\n", hwnd, lpcs);
     7178  TRACE("(lpcs=%p)\n", lpcs);
    84787179
    84797180  /* initialize info pointer */
    8480   ZeroMemory(infoPtr, sizeof(LISTVIEW_INFO));
    8481 
     7181  infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc(sizeof(LISTVIEW_INFO));
     7182  if (!infoPtr) return -1;
     7183
     7184  SetWindowLongW(hwnd, 0, (LONG)infoPtr);
     7185
     7186  infoPtr->hwndSelf = hwnd;
     7187  infoPtr->dwStyle = lpcs->style;
    84827188  /* determine the type of structures to use */
    8483   infoPtr->notifyFormat = SendMessageW(GetParent(hwnd), WM_NOTIFYFORMAT,
    8484                                        (WPARAM)hwnd, (LPARAM)NF_QUERY);
    8485  
     7189  infoPtr->notifyFormat = SendMessageW(GetParent(infoPtr->hwndSelf), WM_NOTIFYFORMAT,
     7190                                       (WPARAM)infoPtr->hwndSelf, (LPARAM)NF_QUERY);
     7191
    84867192  /* initialize color information  */
    8487   infoPtr->clrBk = GetSysColor(COLOR_WINDOW);
    8488   infoPtr->clrText = GetSysColor(COLOR_WINDOWTEXT);
     7193  infoPtr->clrBk = CLR_NONE;
     7194  infoPtr->clrText = comctl32_color.clrWindowText;
    84897195  infoPtr->clrTextBk = CLR_DEFAULT;
     7196  LISTVIEW_SetBkColor(infoPtr, comctl32_color.clrWindow);
    84907197
    84917198  /* set default values */
    8492   infoPtr->hwndSelf = hwnd;
    8493   infoPtr->uCallbackMask = 0;
    8494 #ifdef __WIN32OS2__
    8495   infoPtr->nFocusedItem = -2;
    8496 #else
    84977199  infoPtr->nFocusedItem = -1;
    8498 #endif
    84997200  infoPtr->nSelectionMark = -1;
    85007201  infoPtr->nHotItem = -1;
     7202  infoPtr->bRedraw = TRUE;
     7203  infoPtr->bFirstPaint = TRUE;
     7204  infoPtr->bNoItemMetrics = TRUE;
     7205  infoPtr->bDoChangeNotify = TRUE;
    85017206  infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING);
    85027207  infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING);
    8503   ZeroMemory(&infoPtr->rcList, sizeof(RECT));
    8504   infoPtr->hwndEdit = 0;
    8505   infoPtr->pedititem = NULL;
    85067208  infoPtr->nEditLabelItem = -1;
     7209  infoPtr->dwHoverTime = -1; /* default system hover time */
    85077210
    85087211  /* get default font (icon title) */
     
    85107213  infoPtr->hDefaultFont = CreateFontIndirectW(&logFont);
    85117214  infoPtr->hFont = infoPtr->hDefaultFont;
    8512   LISTVIEW_SaveTextMetrics(hwnd);
     7215  LISTVIEW_SaveTextMetrics(infoPtr);
     7216
     7217  /* create header */
     7218  infoPtr->hwndHeader = CreateWindowW(WC_HEADERW, NULL,
     7219    WS_CHILD | HDS_HORZ | (DWORD)((LVS_NOSORTHEADER & lpcs->style)?0:HDS_BUTTONS),
     7220    0, 0, 0, 0, hwnd, NULL,
     7221    lpcs->hInstance, NULL);
     7222  if (!infoPtr->hwndHeader) goto fail;
     7223
     7224  /* set header unicode format */
     7225  SendMessageW(infoPtr->hwndHeader, HDM_SETUNICODEFORMAT, (WPARAM)TRUE, (LPARAM)NULL);
     7226
     7227  /* set header font */
     7228  SendMessageW(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont, (LPARAM)TRUE);
     7229
     7230  /* allocate memory for the data structure */
     7231  if (!(infoPtr->selectionRanges = ranges_create(10))) goto fail;
     7232  if (!(infoPtr->hdpaItems = DPA_Create(10))) goto fail;
     7233  if (!(infoPtr->hdpaPosX  = DPA_Create(10))) goto fail;
     7234  if (!(infoPtr->hdpaPosY  = DPA_Create(10))) goto fail;
     7235  if (!(infoPtr->hdpaColumns = DPA_Create(10))) goto fail;
     7236
     7237  /* initialize the icon sizes */
     7238  set_icon_size(&infoPtr->iconSize, infoPtr->himlNormal, uView != LVS_ICON);
     7239  set_icon_size(&infoPtr->iconStateSize, infoPtr->himlState, TRUE);
     7240
     7241  /* init item size to avoid division by 0 */
     7242  LISTVIEW_UpdateItemSize (infoPtr);
    85137243 
    8514   /* create header */
    8515   infoPtr->hwndHeader = CreateWindowW(WC_HEADERW, (LPCWSTR)NULL,
    8516     WS_CHILD | HDS_HORZ | (DWORD)((LVS_NOSORTHEADER & lpcs->style)?0:HDS_BUTTONS),
    8517     0, 0, 0, 0, hwnd, (HMENU)0,
    8518     lpcs->hInstance, NULL);
    8519 
    8520   /* set header unicode format */
    8521   SendMessageW(infoPtr->hwndHeader, HDM_SETUNICODEFORMAT,(WPARAM)TRUE,(LPARAM)NULL);
    8522 
    8523   /* set header font */
    8524   SendMessageW(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont,
    8525                (LPARAM)TRUE);
    8526  
    8527   if (uView == LVS_ICON)
    8528   {
    8529     infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
    8530     infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
    8531   }
    8532   else if (uView == LVS_REPORT)
     7244  if (uView == LVS_REPORT)
    85337245  {
    85347246    if (!(LVS_NOCOLUMNHEADER & lpcs->style))
     
    85397251    {
    85407252      /* set HDS_HIDDEN flag to hide the header bar */
    8541       SetWindowLongW(infoPtr->hwndHeader, GWL_STYLE, 
     7253      SetWindowLongW(infoPtr->hwndHeader, GWL_STYLE,
    85427254                    GetWindowLongW(infoPtr->hwndHeader, GWL_STYLE) | HDS_HIDDEN);
    85437255    }
    8544      
    8545 
    8546     infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
    8547     infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
    85487256  }
    8549   else
    8550   {
    8551     infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
    8552     infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
    8553   }
    8554 
    8555   /* display unsupported listview window styles */
    8556   LISTVIEW_UnsupportedStyles(lpcs->style);
    8557 
    8558   /* allocate memory for the data structure */
    8559   infoPtr->hdpaItems = DPA_Create(10);
    8560 
    8561   /* allocate memory for the selection ranges */
    8562   infoPtr->hdpaSelectionRanges = DPA_Create(10);
    8563 
    8564   /* initialize size of items */
    8565   infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
    8566   infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
    8567 
    8568   /* initialize the hover time to -1(indicating the default system hover time) */
    8569   infoPtr->dwHoverTime = -1; 
    8570 
    8571 #ifdef __WIN32OS2__
    8572   //create tooltip
    8573   infoPtr->hwndToolTip = createToolTip(hwnd,TTF_TRACK | TTF_ABSOLUTE | TTF_TRANSPARENT,TRUE);
    8574   SendMessageA(infoPtr->hwndToolTip,WM_SETFONT,infoPtr->hFont,0);
    8575 
    8576   infoPtr->hHotCursor = LoadCursorA(0,IDC_ARROWA);
    8577 #endif
    85787257
    85797258  return 0;
     7259
     7260fail:
     7261    DestroyWindow(infoPtr->hwndHeader);
     7262    ranges_destroy(infoPtr->selectionRanges);
     7263    DPA_Destroy(infoPtr->hdpaItems);
     7264    DPA_Destroy(infoPtr->hdpaPosX);
     7265    DPA_Destroy(infoPtr->hdpaPosY);
     7266    DPA_Destroy(infoPtr->hdpaColumns);
     7267    COMCTL32_Free(infoPtr);
     7268    return -1;
    85807269}
    85817270
     
    85837272 * DESCRIPTION:
    85847273 * Erases the background of the listview control.
    8585  *
    8586  * PARAMETER(S):
    8587  * [I] HWND : window handle
    8588  * [I] WPARAM : device context handle
    8589  * [I] LPARAM : not used
    8590  *
     7274 *
     7275 * PARAMETER(S):
     7276 * [I] infoPtr : valid pointer to the listview structure
     7277 * [I] hdc : device context handle
     7278 *
    85917279 * RETURN:
    85927280 *   SUCCESS : TRUE
    85937281 *   FAILURE : FALSE
    85947282 */
    8595 static LRESULT LISTVIEW_EraseBackground(HWND hwnd, WPARAM wParam,
    8596                                         LPARAM lParam)
    8597 {
    8598   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    8599   BOOL bResult;
    8600 
    8601   TRACE("(hwnd=%x, wParam=%x, lParam=%lx)\n", hwnd, wParam, lParam);
    8602  
    8603   if (infoPtr->clrBk == CLR_NONE)
    8604   {
    8605     bResult = SendMessageW(GetParent(hwnd), WM_ERASEBKGND, wParam, lParam);
    8606   }
    8607   else
    8608   {
     7283static inline BOOL LISTVIEW_EraseBkgnd(LISTVIEW_INFO *infoPtr, HDC hdc)
     7284{
    86097285    RECT rc;
    8610     HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
    8611     GetClientRect(hwnd, &rc);
    8612     FillRect((HDC)wParam, &rc, hBrush);
    8613     DeleteObject(hBrush);
    8614     bResult = TRUE;
    8615   }
    8616   return bResult;
    8617 }
    8618 
    8619 
    8620 static void LISTVIEW_FillBackground(HWND hwnd, HDC hdc, LPRECT rc)
    8621 {
    8622   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    8623 
    8624   TRACE("(hwnd=%x, hdc=%x, rc=%p)\n", hwnd, hdc, rc);
    8625 
    8626   if (infoPtr->clrBk != CLR_NONE)
    8627   {
    8628     HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
    8629     FillRect(hdc, rc, hBrush);
    8630     DeleteObject(hBrush);
    8631   }
    8632 }
    8633 
    8634 /***
    8635  * DESCRIPTION:
    8636  * Retrieves the listview control font.
    8637  *
    8638  * PARAMETER(S):
    8639  * [I] HWND : window handle
    8640  *
    8641  * RETURN:
    8642  * Font handle.
    8643  */
    8644 static LRESULT LISTVIEW_GetFont(HWND hwnd)
    8645 {
    8646   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    8647 
    8648   TRACE("(hwnd=%x)\n", hwnd);
    8649 
    8650   return infoPtr->hFont;
     7286
     7287    TRACE("(hdc=%p)\n", hdc);
     7288
     7289    if (!GetClipBox(hdc, &rc)) return FALSE;
     7290
     7291    return LISTVIEW_FillBkgnd(infoPtr, hdc, &rc);
     7292}
     7293       
     7294
     7295/***
     7296 * DESCRIPTION:
     7297 * Helper function for LISTVIEW_[HV]Scroll *only*.
     7298 * Performs vertical/horizontal scrolling by a give amount.
     7299 *
     7300 * PARAMETER(S):
     7301 * [I] infoPtr : valid pointer to the listview structure
     7302 * [I] dx : amount of horizontal scroll
     7303 * [I] dy : amount of vertical scroll
     7304 */
     7305static void scroll_list(LISTVIEW_INFO *infoPtr, INT dx, INT dy)
     7306{
     7307    /* now we can scroll the list */
     7308    ScrollWindowEx(infoPtr->hwndSelf, dx, dy, &infoPtr->rcList,
     7309                   &infoPtr->rcList, 0, 0, SW_ERASE | SW_INVALIDATE);
     7310    /* if we have focus, adjust rect */
     7311    OffsetRect(&infoPtr->rcFocus, dx, dy);
     7312    UpdateWindow(infoPtr->hwndSelf);
    86517313}
    86527314
     
    86547316 * DESCRIPTION:
    86557317 * Performs vertical scrolling.
    8656  *
    8657  * PARAMETER(S):
    8658  * [I] HWND : window handle
    8659  * [I] INT : scroll code
    8660  * [I] SHORT : current scroll position if scroll code is SB_THUMBPOSITION
    8661  *             or SB_THUMBTRACK.
    8662  * [I] HWND : scrollbar control window handle
     7318 *
     7319 * PARAMETER(S):
     7320 * [I] infoPtr : valid pointer to the listview structure
     7321 * [I] nScrollCode : scroll code
     7322 * [I] nScrollDiff : units to scroll in SB_INTERNAL mode, 0 otherwise
     7323 * [I] hScrollWnd  : scrollbar control window handle
    86637324 *
    86647325 * RETURN:
    86657326 * Zero
    8666  */
    8667 static LRESULT LISTVIEW_VScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
    8668                                 HWND hScrollWnd)
    8669 {
    8670   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    8671   SCROLLINFO scrollInfo;
    8672 
    8673   TRACE("(hwnd=%x, nScrollCode=%d, nCurrentPos=%d, hScrollWnd=%x)\n",
    8674         hwnd, nScrollCode, nCurrentPos, hScrollWnd);
    8675 
    8676   SendMessageW(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
    8677 
    8678   ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
    8679   scrollInfo.cbSize = sizeof(SCROLLINFO);
    8680   scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
    8681 
    8682   if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
    8683   {
    8684     INT nOldScrollPos = scrollInfo.nPos;
     7327 *
     7328 * NOTES:
     7329 *   SB_LINEUP/SB_LINEDOWN:
     7330 *        for LVS_ICON, LVS_SMALLICON is 37 by experiment
     7331 *        for LVS_REPORT is 1 line
     7332 *        for LVS_LIST cannot occur
     7333 *
     7334 */
     7335static LRESULT LISTVIEW_VScroll(LISTVIEW_INFO *infoPtr, INT nScrollCode,
     7336                                INT nScrollDiff, HWND hScrollWnd)
     7337{
     7338    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     7339    INT nOldScrollPos, nNewScrollPos;
     7340    SCROLLINFO scrollInfo;
     7341    BOOL is_an_icon;
     7342
     7343    TRACE("(nScrollCode=%d(%s), nScrollDiff=%d)\n", nScrollCode,
     7344        debugscrollcode(nScrollCode), nScrollDiff);
     7345
     7346    if (infoPtr->hwndEdit) SendMessageW(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
     7347
     7348    scrollInfo.cbSize = sizeof(SCROLLINFO);
     7349    scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS;
     7350
     7351    is_an_icon = ((uView == LVS_ICON) || (uView == LVS_SMALLICON));
     7352
     7353    if (!GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo)) return 1;
     7354
     7355    nOldScrollPos = scrollInfo.nPos;
    86857356    switch (nScrollCode)
    86867357    {
     7358    case SB_INTERNAL:
     7359        break;
     7360
    86877361    case SB_LINEUP:
    8688       if (scrollInfo.nPos > scrollInfo.nMin)
    8689         scrollInfo.nPos--;
    8690     break;
    8691    
     7362        nScrollDiff = (is_an_icon) ? -LISTVIEW_SCROLL_ICON_LINE_SIZE : -1;
     7363        break;
     7364
    86927365    case SB_LINEDOWN:
    8693       if (scrollInfo.nPos < scrollInfo.nMax)
    8694         scrollInfo.nPos++;
    8695       break;
    8696      
     7366        nScrollDiff = (is_an_icon) ? LISTVIEW_SCROLL_ICON_LINE_SIZE : 1;
     7367        break;
     7368
    86977369    case SB_PAGEUP:
    8698       if (scrollInfo.nPos > scrollInfo.nMin)
    8699       {
    8700         if (scrollInfo.nPos >= scrollInfo.nPage)
    8701           scrollInfo.nPos -= scrollInfo.nPage;
    8702         else
    8703           scrollInfo.nPos = scrollInfo.nMin;
    8704       }
    8705       break;
    8706      
     7370        nScrollDiff = -scrollInfo.nPage;
     7371        break;
     7372
    87077373    case SB_PAGEDOWN:
    8708       if (scrollInfo.nPos < scrollInfo.nMax)
    8709       {
    8710         if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
    8711           scrollInfo.nPos += scrollInfo.nPage;
    8712         else
    8713           scrollInfo.nPos = scrollInfo.nMax;
    8714       }
    8715       break;
     7374        nScrollDiff = scrollInfo.nPage;
     7375        break;
    87167376
    87177377    case SB_THUMBPOSITION:
    87187378    case SB_THUMBTRACK:
    8719         scrollInfo.nPos = nCurrentPos;
    8720         if (scrollInfo.nPos > scrollInfo.nMax)
    8721             scrollInfo.nPos=scrollInfo.nMax;
    8722 
    8723         if (scrollInfo.nPos < scrollInfo.nMin)
    8724             scrollInfo.nPos=scrollInfo.nMin;
    8725 
    8726       break;
    8727     }
    8728 
    8729     if (nOldScrollPos != scrollInfo.nPos)
    8730     {
    8731       scrollInfo.fMask = SIF_POS;
    8732       SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
    8733       if (IsWindowVisible(infoPtr->hwndHeader))
    8734       {
    8735         RECT rListview, rcHeader, rDest;
    8736         GetClientRect(hwnd, &rListview);
    8737         GetWindowRect(infoPtr->hwndHeader, &rcHeader);
    8738         MapWindowPoints((HWND) NULL, hwnd, (LPPOINT) &rcHeader, 2);
    8739         SubtractRect(&rDest, &rListview, &rcHeader);
    8740         InvalidateRect(hwnd, &rDest, TRUE);
    8741       }
    8742       else
    8743         InvalidateRect(hwnd, NULL, TRUE);
    8744     }
    8745 #ifdef __WIN32OS2__
    8746     //@PF: Correct scrollbar range
    8747     if (scrollInfo.nMax != GETITEMCOUNT(infoPtr))
    8748     {
    8749         SetScrollRange(hwnd,SB_VERT,0,GETITEMCOUNT(infoPtr)-1,TRUE);
    8750     }
    8751 #endif
    8752   }
    8753    
    8754   return 0;
     7379        nScrollDiff = scrollInfo.nTrackPos - scrollInfo.nPos;
     7380        break;
     7381
     7382    default:
     7383        nScrollDiff = 0;
     7384    }
     7385
     7386    /* quit right away if pos isn't changing */
     7387    if (nScrollDiff == 0) return 0;
     7388   
     7389    /* calculate new position, and handle overflows */
     7390    nNewScrollPos = scrollInfo.nPos + nScrollDiff;
     7391    if (nScrollDiff > 0) {
     7392        if (nNewScrollPos < nOldScrollPos ||
     7393            nNewScrollPos > scrollInfo.nMax)
     7394            nNewScrollPos = scrollInfo.nMax;
     7395    } else {
     7396        if (nNewScrollPos > nOldScrollPos ||
     7397            nNewScrollPos < scrollInfo.nMin)
     7398            nNewScrollPos = scrollInfo.nMin;
     7399    }
     7400
     7401    /* set the new position, and reread in case it changed */
     7402    scrollInfo.fMask = SIF_POS;
     7403    scrollInfo.nPos = nNewScrollPos;
     7404    nNewScrollPos = SetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo, TRUE);
     7405   
     7406    /* carry on only if it really changed */
     7407    if (nNewScrollPos == nOldScrollPos) return 0;
     7408   
     7409    /* now adjust to client coordinates */
     7410    nScrollDiff = nOldScrollPos - nNewScrollPos;
     7411    if (uView == LVS_REPORT) nScrollDiff *= infoPtr->nItemHeight;
     7412   
     7413    /* and scroll the window */
     7414    scroll_list(infoPtr, 0, nScrollDiff);
     7415
     7416    return 0;
    87557417}
    87567418
     
    87587420 * DESCRIPTION:
    87597421 * Performs horizontal scrolling.
    8760  *
    8761  * PARAMETER(S):
    8762  * [I] HWND : window handle
    8763  * [I] INT : scroll code
    8764  * [I] SHORT : current scroll position if scroll code is SB_THUMBPOSITION
    8765  *             or SB_THUMBTRACK.
    8766  * [I] HWND : scrollbar control window handle
     7422 *
     7423 * PARAMETER(S):
     7424 * [I] infoPtr : valid pointer to the listview structure
     7425 * [I] nScrollCode : scroll code
     7426 * [I] nScrollDiff : units to scroll in SB_INTERNAL mode, 0 otherwise
     7427 * [I] hScrollWnd  : scrollbar control window handle
    87677428 *
    87687429 * RETURN:
    87697430 * Zero
    8770  */
    8771 static LRESULT LISTVIEW_HScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
    8772                                 HWND hScrollWnd)
    8773 {
    8774   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    8775   SCROLLINFO scrollInfo;
    8776 
    8777   TRACE("(hwnd=%x, nScrollCode=%d, nCurrentPos=%d, hScrollWnd=%x)\n",
    8778         hwnd, nScrollCode, nCurrentPos, hScrollWnd);
    8779  
    8780   SendMessageW(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
    8781 
    8782   ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
    8783   scrollInfo.cbSize = sizeof(SCROLLINFO);
    8784   scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
    8785  
    8786   if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
    8787   {
    8788     INT nOldScrollPos = scrollInfo.nPos;
     7431 *
     7432 * NOTES:
     7433 *   SB_LINELEFT/SB_LINERIGHT:
     7434 *        for LVS_ICON, LVS_SMALLICON  1 pixel
     7435 *        for LVS_REPORT is 1 pixel
     7436 *        for LVS_LIST  is 1 column --> which is a 1 because the
     7437 *                                      scroll is based on columns not pixels
     7438 *
     7439 */
     7440static LRESULT LISTVIEW_HScroll(LISTVIEW_INFO *infoPtr, INT nScrollCode,
     7441                                INT nScrollDiff, HWND hScrollWnd)
     7442{
     7443    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     7444    INT nOldScrollPos, nNewScrollPos;
     7445    SCROLLINFO scrollInfo;
     7446
     7447    TRACE("(nScrollCode=%d(%s), nScrollDiff=%d)\n", nScrollCode,
     7448        debugscrollcode(nScrollCode), nScrollDiff);
     7449
     7450    if (infoPtr->hwndEdit) SendMessageW(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
     7451
     7452    scrollInfo.cbSize = sizeof(SCROLLINFO);
     7453    scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS;
     7454
     7455    if (!GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo)) return 1;
     7456
     7457    nOldScrollPos = scrollInfo.nPos;
    87897458
    87907459    switch (nScrollCode)
    87917460    {
     7461    case SB_INTERNAL:
     7462        break;
     7463
    87927464    case SB_LINELEFT:
    8793       if (scrollInfo.nPos > scrollInfo.nMin)
    8794         scrollInfo.nPos--;
    8795       break;
    8796    
     7465        nScrollDiff = -1;
     7466        break;
     7467
    87977468    case SB_LINERIGHT:
    8798       if (scrollInfo.nPos < scrollInfo.nMax)
    8799         scrollInfo.nPos++;
    8800       break;
    8801      
     7469        nScrollDiff = 1;
     7470        break;
     7471
    88027472    case SB_PAGELEFT:
    8803       if (scrollInfo.nPos > scrollInfo.nMin)
    8804       {
    8805         if (scrollInfo.nPos >= scrollInfo.nPage)
    8806           scrollInfo.nPos -= scrollInfo.nPage;
    8807         else
    8808           scrollInfo.nPos = scrollInfo.nMin;
    8809       }
    8810       break;
    8811      
     7473        nScrollDiff = -scrollInfo.nPage;
     7474        break;
     7475
    88127476    case SB_PAGERIGHT:
    8813       if (scrollInfo.nPos < scrollInfo.nMax)
    8814       {
    8815         if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
    8816           scrollInfo.nPos += scrollInfo.nPage;
    8817         else
    8818           scrollInfo.nPos = scrollInfo.nMax;
    8819       }
    8820       break;
     7477        nScrollDiff = scrollInfo.nPage;
     7478        break;
    88217479
    88227480    case SB_THUMBPOSITION:
    88237481    case SB_THUMBTRACK:
    8824         scrollInfo.nPos = nCurrentPos;
    8825 
    8826         if (scrollInfo.nPos > scrollInfo.nMax)
    8827             scrollInfo.nPos=scrollInfo.nMax;
    8828 
    8829         if (scrollInfo.nPos < scrollInfo.nMin)
    8830             scrollInfo.nPos=scrollInfo.nMin;
    8831       break;
    8832     }
    8833 
    8834     if (nOldScrollPos != scrollInfo.nPos)
    8835     {
    8836       UINT uView = GetWindowLongW(hwnd, GWL_STYLE) & LVS_TYPEMASK;
    8837       scrollInfo.fMask = SIF_POS;
    8838       SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
    8839       if(uView == LVS_REPORT)
    8840       {
    8841           scrollInfo.fMask = SIF_POS;
    8842           GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
    8843           LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
    8844       }
    8845       InvalidateRect(hwnd, NULL, TRUE);
    8846     }
    8847   }
    8848    
     7482        nScrollDiff = scrollInfo.nTrackPos - scrollInfo.nPos;
     7483        break;
     7484
     7485    default:
     7486        nScrollDiff = 0;
     7487    }
     7488
     7489    /* quit right away if pos isn't changing */
     7490    if (nScrollDiff == 0) return 0;
     7491   
     7492    /* calculate new position, and handle overflows */
     7493    nNewScrollPos = scrollInfo.nPos + nScrollDiff;
     7494    if (nScrollDiff > 0) {
     7495        if (nNewScrollPos < nOldScrollPos ||
     7496            nNewScrollPos > scrollInfo.nMax)
     7497            nNewScrollPos = scrollInfo.nMax;
     7498    } else {
     7499        if (nNewScrollPos > nOldScrollPos ||
     7500            nNewScrollPos < scrollInfo.nMin)
     7501            nNewScrollPos = scrollInfo.nMin;
     7502    }
     7503
     7504    /* set the new position, and reread in case it changed */
     7505    scrollInfo.fMask = SIF_POS;
     7506    scrollInfo.nPos = nNewScrollPos;
     7507    nNewScrollPos = SetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo, TRUE);
     7508   
     7509    /* carry on only if it really changed */
     7510    if (nNewScrollPos == nOldScrollPos) return 0;
     7511   
     7512    if(uView == LVS_REPORT)
     7513        LISTVIEW_UpdateHeaderSize(infoPtr, nNewScrollPos);
     7514     
     7515    /* now adjust to client coordinates */
     7516    nScrollDiff = nOldScrollPos - nNewScrollPos;
     7517    if (uView == LVS_LIST) nScrollDiff *= infoPtr->nItemWidth;
     7518   
     7519    /* and scroll the window */
     7520    scroll_list(infoPtr, nScrollDiff, 0);
     7521
    88497522  return 0;
    88507523}
    88517524
    8852 static LRESULT LISTVIEW_MouseWheel(HWND hwnd, INT wheelDelta)
    8853 {
    8854     UINT uView = GetWindowLongW(hwnd, GWL_STYLE) & LVS_TYPEMASK;
     7525static LRESULT LISTVIEW_MouseWheel(LISTVIEW_INFO *infoPtr, INT wheelDelta)
     7526{
     7527    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
    88557528    INT gcWheelDelta = 0;
    88567529    UINT pulScrollLines = 3;
    88577530    SCROLLINFO scrollInfo;
    88587531
    8859     TRACE("(hwnd=%x, wheelDelta=%d)\n", hwnd, wheelDelta);
     7532    TRACE("(wheelDelta=%d)\n", wheelDelta);
    88607533
    88617534    SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
    88627535    gcWheelDelta -= wheelDelta;
    88637536
    8864     ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
    88657537    scrollInfo.cbSize = sizeof(SCROLLINFO);
    8866     scrollInfo.fMask = SIF_POS | SIF_RANGE;
     7538    scrollInfo.fMask = SIF_POS;
    88677539
    88687540    switch(uView)
     
    88747546        *  should be fixed in the future.
    88757547        */
    8876         if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
    8877             LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + (gcWheelDelta < 0) ? 37 : -37, 0);
     7548        LISTVIEW_VScroll(infoPtr, SB_INTERNAL, (gcWheelDelta < 0) ?
     7549                -LISTVIEW_SCROLL_ICON_LINE_SIZE : LISTVIEW_SCROLL_ICON_LINE_SIZE, 0);
    88787550        break;
    88797551
     
    88817553        if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
    88827554        {
    8883             if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
    8884             {
    8885                 int cLineScroll = min(LISTVIEW_GetCountPerColumn(hwnd), pulScrollLines);
    8886                 cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
    8887                 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + cLineScroll, 0);
    8888             }
     7555            int cLineScroll = min(LISTVIEW_GetCountPerColumn(infoPtr), pulScrollLines);
     7556            cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
     7557            LISTVIEW_VScroll(infoPtr, SB_INTERNAL, cLineScroll, 0);
    88897558        }
    88907559        break;
    88917560
    88927561    case LVS_LIST:
    8893         LISTVIEW_HScroll(hwnd, (gcWheelDelta < 0) ? SB_LINELEFT : SB_LINERIGHT, 0, 0);
     7562        LISTVIEW_HScroll(infoPtr, (gcWheelDelta < 0) ? SB_LINELEFT : SB_LINERIGHT, 0, 0);
    88947563        break;
    88957564    }
     
    88997568/***
    89007569 * DESCRIPTION:
    8901  * ??? 
    8902  * 
    8903  * PARAMETER(S):
    8904  * [I] HWND : window handle
    8905  * [I] INT : virtual key
    8906  * [I] LONG : key data
     7570 * ???
     7571 *
     7572 * PARAMETER(S):
     7573 * [I] infoPtr : valid pointer to the listview structure
     7574 * [I] nVirtualKey : virtual key
     7575 * [I] lKeyData : key data
    89077576 *
    89087577 * RETURN:
    89097578 * Zero
    89107579 */
    8911 static LRESULT LISTVIEW_KeyDown(HWND hwnd, INT nVirtualKey, LONG lKeyData)
    8912 {
    8913   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    8914   UINT uView =  GetWindowLongW(hwnd, GWL_STYLE) & LVS_TYPEMASK;
     7580static LRESULT LISTVIEW_KeyDown(LISTVIEW_INFO *infoPtr, INT nVirtualKey, LONG lKeyData)
     7581{
     7582  UINT uView =  infoPtr->dwStyle & LVS_TYPEMASK;
    89157583  INT nItem = -1;
    8916   INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
    8917   NMLVKEYDOWN nmKeyDown;
    8918   HWND hwndParent = GetParent(hwnd);
    8919 
    8920   TRACE("(hwnd=%x, nVirtualKey=%d, lKeyData=%ld)\n", hwnd, nVirtualKey, lKeyData);
     7584  NMLVKEYDOWN nmKeyDown;
     7585
     7586  TRACE("(nVirtualKey=%d, lKeyData=%ld)\n", nVirtualKey, lKeyData);
    89217587
    89227588  /* send LVN_KEYDOWN notification */
    8923   nmKeyDown.wVKey = nVirtualKey; 
     7589  nmKeyDown.wVKey = nVirtualKey;
    89247590  nmKeyDown.flags = 0;
    8925 #ifdef __WIN32OS2__
    8926   if(notify(hwnd, LVN_KEYDOWN, &nmKeyDown.hdr) == TRUE)
    8927     return 0;    //application processed this key press
    8928 #else
    8929   notify(hwnd, LVN_KEYDOWN, &nmKeyDown.hdr);
    8930 #endif
    8931  
     7591  notify_hdr(infoPtr, LVN_KEYDOWN, &nmKeyDown.hdr);
     7592
    89327593  switch (nVirtualKey)
    89337594  {
    89347595  case VK_RETURN:
    8935     if ((GETITEMCOUNT(infoPtr) > 0) && (infoPtr->nFocusedItem != -1))
    8936     {
    8937       hdr_notify(hwnd, NM_RETURN);        /* NM_RETURN notification */
    8938       hdr_notify(hwnd, LVN_ITEMACTIVATE); /* LVN_ITEMACTIVATE notification */
     7596    if ((infoPtr->nItemCount > 0) && (infoPtr->nFocusedItem != -1))
     7597    {
     7598      notify(infoPtr, NM_RETURN);
     7599      notify(infoPtr, LVN_ITEMACTIVATE);
    89397600    }
    89407601    break;
    89417602
    89427603  case VK_HOME:
    8943     if (GETITEMCOUNT(infoPtr) > 0)
     7604    if (infoPtr->nItemCount > 0)
    89447605      nItem = 0;
    89457606    break;
    89467607
    89477608  case VK_END:
    8948     if (GETITEMCOUNT(infoPtr) > 0)
    8949       nItem = GETITEMCOUNT(infoPtr) - 1;
     7609    if (infoPtr->nItemCount > 0)
     7610      nItem = infoPtr->nItemCount - 1;
    89507611    break;
    89517612
    89527613  case VK_LEFT:
    8953     nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TOLEFT);
     7614    nItem = ListView_GetNextItem(infoPtr->hwndSelf, infoPtr->nFocusedItem, LVNI_TOLEFT);
    89547615    break;
    89557616
    89567617  case VK_UP:
    8957     nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_ABOVE);
     7618    nItem = ListView_GetNextItem(infoPtr->hwndSelf, infoPtr->nFocusedItem, LVNI_ABOVE);
    89587619    break;
    8959    
     7620
    89607621  case VK_RIGHT:
    8961     nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TORIGHT);
     7622    nItem = ListView_GetNextItem(infoPtr->hwndSelf, infoPtr->nFocusedItem, LVNI_TORIGHT);
    89627623    break;
    89637624
    89647625  case VK_DOWN:
    8965     nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_BELOW);
     7626    nItem = ListView_GetNextItem(infoPtr->hwndSelf, infoPtr->nFocusedItem, LVNI_BELOW);
    89667627    break;
    89677628
    89687629  case VK_PRIOR:
    89697630    if (uView == LVS_REPORT)
    8970       nItem = infoPtr->nFocusedItem - LISTVIEW_GetCountPerColumn(hwnd);
     7631      nItem = infoPtr->nFocusedItem - LISTVIEW_GetCountPerColumn(infoPtr);
    89717632    else
    8972       nItem = infoPtr->nFocusedItem - LISTVIEW_GetCountPerColumn(hwnd)
    8973                                     * LISTVIEW_GetCountPerRow(hwnd);
     7633      nItem = infoPtr->nFocusedItem - LISTVIEW_GetCountPerColumn(infoPtr)
     7634                                    * LISTVIEW_GetCountPerRow(infoPtr);
    89747635    if(nItem < 0) nItem = 0;
    89757636    break;
     
    89777638  case VK_NEXT:
    89787639    if (uView == LVS_REPORT)
    8979       nItem = infoPtr->nFocusedItem + LISTVIEW_GetCountPerColumn(hwnd);
     7640      nItem = infoPtr->nFocusedItem + LISTVIEW_GetCountPerColumn(infoPtr);
    89807641    else
    8981       nItem = infoPtr->nFocusedItem + LISTVIEW_GetCountPerColumn(hwnd)
    8982                                     * LISTVIEW_GetCountPerRow(hwnd);
    8983     if(nItem >= GETITEMCOUNT(infoPtr)) nItem = GETITEMCOUNT(infoPtr) - 1;
     7642      nItem = infoPtr->nFocusedItem + LISTVIEW_GetCountPerColumn(infoPtr)
     7643                                    * LISTVIEW_GetCountPerRow(infoPtr);
     7644    if(nItem >= infoPtr->nItemCount) nItem = infoPtr->nItemCount - 1;
    89847645    break;
    89857646  }
    89867647
    89877648  if ((nItem != -1) && (nItem != infoPtr->nFocusedItem))
    8988   {
    8989     if (LISTVIEW_KeySelection(hwnd, nItem))
    8990       UpdateWindow(hwnd); /* update client area */
    8991   }
     7649      LISTVIEW_KeySelection(infoPtr, nItem);
    89927650
    89937651  return 0;
     
    89977655 * DESCRIPTION:
    89987656 * Kills the focus.
    8999  * 
    9000  * PARAMETER(S):
    9001  * [I] HWND : window handle
     7657 *
     7658 * PARAMETER(S):
     7659 * [I] infoPtr : valid pointer to the listview structure
    90027660 *
    90037661 * RETURN:
    90047662 * Zero
    90057663 */
    9006 static LRESULT LISTVIEW_KillFocus(HWND hwnd)
    9007 {
    9008   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongW(hwnd, 0);
    9009   UINT uView =  GetWindowLongW(hwnd, GWL_STYLE) & LVS_TYPEMASK;
    9010   INT i,nTop,nBottom;
    9011  
    9012   TRACE("(hwnd=%x)\n", hwnd);
    9013 
    9014   /* send NM_KILLFOCUS notification */
    9015   hdr_notify(hwnd, NM_KILLFOCUS);
    9016 
    9017   /* set window focus flag */
    9018   infoPtr->bFocus = FALSE;
    9019 
    9020   /* NEED drawing optimization ; redraw the selected items */
    9021   if (uView & LVS_REPORT)
    9022   {
    9023     nTop = LISTVIEW_GetTopIndex(hwnd);
    9024     nBottom = nTop +
    9025               LISTVIEW_GetCountPerColumn(hwnd) + 1;
    9026   }
    9027   else
    9028   {
    9029     nTop = 0;
    9030     nBottom = GETITEMCOUNT(infoPtr);
    9031   }
    9032   for (i = nTop; i<nBottom; i++)
    9033   {
    9034     if (LISTVIEW_IsSelected(hwnd,i))
    9035     {
    9036       RECT rcItem;
    9037       rcItem.left = LVIR_BOUNDS;
    9038       LISTVIEW_GetItemRect(hwnd, i, &rcItem);
    9039       InvalidateRect(hwnd, &rcItem, FALSE);
    9040     }
    9041   }
    9042 
    9043   return 0;
     7664static LRESULT LISTVIEW_KillFocus(LISTVIEW_INFO *infoPtr)
     7665{
     7666    TRACE("()\n");
     7667
     7668    /* if we did not have the focus, there's nothing to do */
     7669    if (!infoPtr->bFocus) return 0;
     7670   
     7671    /* send NM_KILLFOCUS notification */
     7672    notify(infoPtr, NM_KILLFOCUS);
     7673
     7674    /* if we have a focus rectagle, get rid of it */
     7675    LISTVIEW_ShowFocusRect(infoPtr, FALSE);
     7676   
     7677    /* set window focus flag */
     7678    infoPtr->bFocus = FALSE;
     7679
     7680    /* invalidate the selected items before reseting focus flag */
     7681    LISTVIEW_InvalidateSelectedItems(infoPtr);
     7682   
     7683    return 0;
    90447684}
    90457685
     
    90477687 * DESCRIPTION:
    90487688 * Processes double click messages (left mouse button).
    9049  *
    9050  * PARAMETER(S):
    9051  * [I] HWND : window handle
    9052  * [I] WORD : key flag
    9053  * [I] WORD : x coordinate
    9054  * [I] WORD : y coordinate
     7689 *
     7690 * PARAMETER(S):
     7691 * [I] infoPtr : valid pointer to the listview structure
     7692 * [I] wKey : key flag
     7693 * [I] pts : mouse coordinate
    90557694 *
    90567695 * RETURN:
    90577696 * Zero
    90587697 */
    9059 static LRESULT LISTVIEW_LButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
    9060                                       WORD wPosY)
    9061 {
    9062   LVHITTESTINFO htInfo;
    9063   NMLISTVIEW nmlv;
    9064 
    9065   TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
    9066 
    9067   htInfo.pt.x = wPosX;
    9068   htInfo.pt.y = wPosY;
    9069 
    9070   /* send NM_DBLCLK notification */
    9071   ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
    9072   if (LISTVIEW_HitTestItem(hwnd, &htInfo, TRUE) != -1)
    9073   {
    9074     nmlv.iItem = htInfo.iItem;
    9075     nmlv.iSubItem = htInfo.iSubItem;
    9076   }
    9077   else
    9078   {
    9079     nmlv.iItem = -1;
    9080     nmlv.iSubItem = 0;
    9081   } 
    9082   nmlv.ptAction.x = wPosX;
    9083   nmlv.ptAction.y = wPosY;
    9084   listview_notify(hwnd, NM_DBLCLK, &nmlv);
    9085 
    9086 
    9087   /* To send the LVN_ITEMACTIVATE, it must be on an Item */
    9088   if(nmlv.iItem != -1)
    9089     hdr_notify(hwnd, LVN_ITEMACTIVATE);
    9090 
    9091   return 0;
     7698static LRESULT LISTVIEW_LButtonDblClk(LISTVIEW_INFO *infoPtr, WORD wKey, POINTS pts)
     7699{
     7700    LVHITTESTINFO htInfo;
     7701
     7702    TRACE("(key=%hu, X=%hu, Y=%hu)\n", wKey, pts.x, pts.y);
     7703
     7704    /* send NM_RELEASEDCAPTURE notification */
     7705    notify(infoPtr, NM_RELEASEDCAPTURE);
     7706
     7707    htInfo.pt.x = pts.x;
     7708    htInfo.pt.y = pts.y;
     7709
     7710    /* send NM_DBLCLK notification */
     7711    LISTVIEW_HitTest(infoPtr, &htInfo, TRUE, FALSE);
     7712    notify_click(infoPtr, NM_DBLCLK, &htInfo);
     7713
     7714    /* To send the LVN_ITEMACTIVATE, it must be on an Item */
     7715    if(htInfo.iItem != -1) notify(infoPtr, LVN_ITEMACTIVATE);
     7716
     7717    return 0;
    90927718}
    90937719
     
    90957721 * DESCRIPTION:
    90967722 * Processes mouse down messages (left mouse button).
    9097  *
    9098  * PARAMETER(S):
    9099  * [I] HWND : window handle
    9100  * [I] WORD : key flag
    9101  * [I] WORD : x coordinate
    9102  * [I] WORD : y coordinate
     7723 *
     7724 * PARAMETER(S):
     7725 * [I] infoPtr : valid pointer to the listview structure
     7726 * [I] wKey : key flag
     7727 * [I] pts : mouse coordinate
    91037728 *
    91047729 * RETURN:
    91057730 * Zero
    91067731 */
    9107 static LRESULT LISTVIEW_LButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
    9108                                     WORD wPosY)
    9109 {
    9110   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    9111   LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    9112   INT nCtrlId = GetWindowLongW(hwnd, GWL_ID);
     7732static LRESULT LISTVIEW_LButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, POINTS pts)
     7733{
     7734  LVHITTESTINFO lvHitTestInfo;
    91137735  static BOOL bGroupSelect = TRUE;
    9114   POINT ptPosition;
     7736  POINT pt = { pts.x, pts.y };
    91157737  INT nItem;
    91167738
    9117   TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
     7739  TRACE("(key=%hu, X=%hu, Y=%hu)\n", wKey, pts.x, pts.y);
    91187740
    91197741  /* send NM_RELEASEDCAPTURE notification */
    9120   hdr_notify(hwnd, NM_RELEASEDCAPTURE);
    9121  
    9122   if (infoPtr->bFocus == FALSE)
    9123     SetFocus(hwnd);
     7742  notify(infoPtr, NM_RELEASEDCAPTURE);
     7743
     7744  if (!infoPtr->bFocus) SetFocus(infoPtr->hwndSelf);
    91247745
    91257746  /* set left button down flag */
    91267747  infoPtr->bLButtonDown = TRUE;
    9127  
    9128   ptPosition.x = wPosX;
    9129   ptPosition.y = wPosY;
    9130   nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
    9131   if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
     7748
     7749  lvHitTestInfo.pt.x = pts.x;
     7750  lvHitTestInfo.pt.y = pts.y;
     7751
     7752  nItem = LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE);
     7753  TRACE("at %s, nItem=%d\n", debugpoint(&pt), nItem);
     7754  infoPtr->nEditLabelItem = -1;
     7755  if ((nItem >= 0) && (nItem < infoPtr->nItemCount))
    91327756  {
    9133     if (lStyle & LVS_SINGLESEL)
    9134     {
    9135       if ((ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
    9136           && infoPtr->nEditLabelItem == -1)
    9137           infoPtr->nEditLabelItem = nItem;
     7757    if (infoPtr->dwStyle & LVS_SINGLESEL)
     7758    {
     7759      if (LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED))
     7760        infoPtr->nEditLabelItem = nItem;
    91387761      else
    9139         LISTVIEW_SetSelection(hwnd, nItem);
     7762        LISTVIEW_SetSelection(infoPtr, nItem);
    91407763    }
    91417764    else
     
    91447767      {
    91457768        if (bGroupSelect)
    9146           LISTVIEW_AddGroupSelection(hwnd, nItem);
     7769        {
     7770          LISTVIEW_AddGroupSelection(infoPtr, nItem);
     7771          LISTVIEW_SetItemFocus(infoPtr, nItem);
     7772          infoPtr->nSelectionMark = nItem;
     7773        }
    91477774        else
    9148           LISTVIEW_AddSelection(hwnd, nItem);
     7775        {
     7776          LVITEMW item;
     7777
     7778          item.state = LVIS_SELECTED | LVIS_FOCUSED;
     7779          item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
     7780
     7781          LISTVIEW_SetItemState(infoPtr,nItem,&item);
     7782          infoPtr->nSelectionMark = nItem;
     7783        }
    91497784      }
    91507785      else if (wKey & MK_CONTROL)
    91517786      {
    9152         bGroupSelect = LISTVIEW_ToggleSelection(hwnd, nItem);
     7787        LVITEMW item;
     7788
     7789        bGroupSelect = (LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED) == 0);
     7790       
     7791        item.state = (bGroupSelect ? LVIS_SELECTED : 0) | LVIS_FOCUSED;
     7792        item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
     7793        LISTVIEW_SetItemState(infoPtr, nItem, &item);
     7794        infoPtr->nSelectionMark = nItem;
    91537795      }
    91547796      else  if (wKey & MK_SHIFT)
    91557797      {
    9156         LISTVIEW_SetGroupSelection(hwnd, nItem);
     7798        LISTVIEW_SetGroupSelection(infoPtr, nItem);
    91577799      }
    91587800      else
    91597801      {
    9160         BOOL was_selected =
    9161             (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED);
     7802        if (LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED))
     7803          infoPtr->nEditLabelItem = nItem;
    91627804
    91637805        /* set selection (clears other pre-existing selections) */
    9164         LISTVIEW_SetSelection(hwnd, nItem);
    9165 
    9166         if (was_selected && infoPtr->nEditLabelItem == -1)
    9167           infoPtr->nEditLabelItem = nItem;
     7806        LISTVIEW_SetSelection(infoPtr, nItem);
    91687807      }
    91697808    }
     
    91727811  {
    91737812    /* remove all selections */
    9174     LISTVIEW_RemoveAllSelections(hwnd);
     7813    LISTVIEW_DeselectAll(infoPtr);
    91757814  }
    91767815
    9177 #ifdef __WIN32OS2__
    9178   //SvL: Send WM_COMMAND as well. (also done by NT's comctl32)
    9179   SendMessageA(GetParent(hwnd), WM_COMMAND, (1<<16) | nCtrlId, hwnd);
    9180 #endif
    9181 
    9182   /* redraw if we could have possibly selected something */
    9183   if(!GETITEMCOUNT(infoPtr)) InvalidateRect(hwnd, NULL, TRUE);
    9184 
    91857816  return 0;
    91867817}
     
    91897820 * DESCRIPTION:
    91907821 * Processes mouse up messages (left mouse button).
    9191  *
    9192  * PARAMETER(S):
    9193  * [I] HWND : window handle
    9194  * [I] WORD : key flag
    9195  * [I] WORD : x coordinate
    9196  * [I] WORD : y coordinate
     7822 *
     7823 * PARAMETER(S):
     7824 * [I] infoPtr : valid pointer to the listview structure
     7825 * [I] wKey : key flag
     7826 * [I] pts : mouse coordinate
    91977827 *
    91987828 * RETURN:
    91997829 * Zero
    92007830 */
    9201 static LRESULT LISTVIEW_LButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
    9202                                   WORD wPosY)
    9203 {
    9204   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    9205 
    9206   TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
    9207 
    9208   if (infoPtr->bLButtonDown != FALSE)
    9209   {
     7831static LRESULT LISTVIEW_LButtonUp(LISTVIEW_INFO *infoPtr, WORD wKey, POINTS pts)
     7832{
    92107833    LVHITTESTINFO lvHitTestInfo;
    9211     NMLISTVIEW nmlv;
    9212 
    9213     lvHitTestInfo.pt.x = wPosX;
    9214     lvHitTestInfo.pt.y = wPosY;
    9215 
    9216   /* send NM_CLICK notification */
    9217     ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
    9218     if (LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo, TRUE) != -1)
    9219     {
    9220         nmlv.iItem = lvHitTestInfo.iItem;
    9221         nmlv.iSubItem = lvHitTestInfo.iSubItem;
    9222     }
    9223     else
    9224     {
    9225         nmlv.iItem = -1;
    9226         nmlv.iSubItem = 0;
    9227     }
    9228     nmlv.ptAction.x = wPosX;
    9229     nmlv.ptAction.y = wPosY;
    9230     listview_notify(hwnd, NM_CLICK, &nmlv);
     7834   
     7835    TRACE("(key=%hu, X=%hu, Y=%hu)\n", wKey, pts.x, pts.y);
     7836
     7837    if (!infoPtr->bLButtonDown) return 0;
     7838
     7839    lvHitTestInfo.pt.x = pts.x;
     7840    lvHitTestInfo.pt.y = pts.y;
     7841
     7842    /* send NM_CLICK notification */
     7843    LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, FALSE);
     7844    notify_click(infoPtr, NM_CLICK, &lvHitTestInfo);
    92317845
    92327846    /* set left button flag */
    92337847    infoPtr->bLButtonDown = FALSE;
    92347848
    9235     if(infoPtr->nEditLabelItem != -1)
    9236     {
    9237       if(lvHitTestInfo.iItem == infoPtr->nEditLabelItem && lvHitTestInfo.flags & LVHT_ONITEMLABEL)
    9238         LISTVIEW_EditLabelT(hwnd, lvHitTestInfo.iItem, TRUE);
    9239       infoPtr->nEditLabelItem = -1;
    9240     }
    9241   }
    9242 #ifdef __WIN32OS2__
    9243   if(infoPtr->bDragInProcess) {
    9244       infoPtr->bDragInProcess = FALSE;
    9245   }
    9246 #endif 
    9247 
    9248   return 0;
    9249 }
    9250 
    9251 /***
    9252  * DESCRIPTION:
    9253  * Creates the listview control (called before WM_CREATE).
    9254  *
    9255  * PARAMETER(S):
    9256  * [I] HWND : window handle
    9257  * [I] WPARAM : unhandled
    9258  * [I] LPARAM : widow creation info
    9259  *
     7849    /* if we clicked on a selected item, edit the label */
     7850    if(lvHitTestInfo.iItem == infoPtr->nEditLabelItem && (lvHitTestInfo.flags & LVHT_ONITEMLABEL))
     7851        LISTVIEW_EditLabelT(infoPtr, lvHitTestInfo.iItem, TRUE);
     7852
     7853    return 0;
     7854}
     7855
     7856/***
     7857 * DESCRIPTION:
     7858 * Destroys the listview control (called after WM_DESTROY).
     7859 *
     7860 * PARAMETER(S):
     7861 * [I] infoPtr : valid pointer to the listview structure
     7862 *
    92607863 * RETURN:
    92617864 * Zero
    92627865 */
    9263 static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
    9264 {
    9265   LISTVIEW_INFO *infoPtr;
    9266 
    9267   TRACE("(hwnd=%x, wParam=%x, lParam=%lx)\n", hwnd, wParam, lParam);
    9268 
    9269   /* allocate memory for info structure */
    9270 #ifdef __WIN32OS2__
    9271   infoPtr = (LISTVIEW_INFO*)initControl(hwnd,sizeof(LISTVIEW_INFO));
    9272 #else
    9273   infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc(sizeof(LISTVIEW_INFO));
    9274 #endif
    9275   if (infoPtr == NULL)
    9276   {
    9277     ERR("could not allocate info memory!\n");
    9278     return 0;
    9279   }
    9280 
    9281   SetWindowLongW(hwnd, 0, (LONG)infoPtr);
    9282   if ((LISTVIEW_INFO *)GetWindowLongW(hwnd, 0) != infoPtr)
    9283   {
    9284     ERR("pointer assignment error!\n");
    9285     return 0;
    9286   }
    9287 
    9288   return DefWindowProcW(hwnd, WM_NCCREATE, wParam, lParam);
    9289 }
    9290 
    9291 /***
    9292  * DESCRIPTION:
    9293  * Destroys the listview control (called after WM_DESTROY).
    9294  *
    9295  * PARAMETER(S):
    9296  * [I] HWND : window handle
    9297  *
    9298  * RETURN:
    9299  * Zero
    9300  */
    9301 static LRESULT LISTVIEW_NCDestroy(HWND hwnd)
    9302 {
    9303   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    9304 
    9305   TRACE("(hwnd=%x)\n", hwnd);
    9306 
    9307 #ifdef __WIN32OS2__
    9308   //destroy tooltip
    9309   destroyToolTip(infoPtr->hwndToolTip);
    9310 #endif
     7866static LRESULT LISTVIEW_NCDestroy(LISTVIEW_INFO *infoPtr)
     7867{
     7868  TRACE("()\n");
    93117869
    93127870  /* delete all items */
    9313   LISTVIEW_DeleteAllItems(hwnd);
     7871  LISTVIEW_DeleteAllItems(infoPtr);
    93147872
    93157873  /* destroy data structure */
    93167874  DPA_Destroy(infoPtr->hdpaItems);
    9317   DPA_Destroy(infoPtr->hdpaSelectionRanges);
    9318 
    9319   /* destroy font */
    9320   infoPtr->hFont = (HFONT)0;
    9321   if (infoPtr->hDefaultFont)
     7875  DPA_Destroy(infoPtr->hdpaPosX);
     7876  DPA_Destroy(infoPtr->hdpaPosY);
     7877  DPA_Destroy(infoPtr->hdpaColumns);
     7878  ranges_destroy(infoPtr->selectionRanges);
     7879
     7880  /* destroy image lists */
     7881  if (!(infoPtr->dwStyle & LVS_SHAREIMAGELISTS))
    93227882  {
    9323     DeleteObject(infoPtr->hDefaultFont);
     7883      if (infoPtr->himlNormal)
     7884          ImageList_Destroy(infoPtr->himlNormal);
     7885      if (infoPtr->himlSmall)
     7886          ImageList_Destroy(infoPtr->himlSmall);
     7887      if (infoPtr->himlState)
     7888          ImageList_Destroy(infoPtr->himlState);
    93247889  }
     7890
     7891  /* destroy font, bkgnd brush */
     7892  infoPtr->hFont = 0;
     7893  if (infoPtr->hDefaultFont) DeleteObject(infoPtr->hDefaultFont);
     7894  if (infoPtr->clrBk != CLR_NONE) DeleteObject(infoPtr->hBkBrush);
     7895
     7896  SetWindowLongW(infoPtr->hwndSelf, 0, 0);
    93257897
    93267898  /* free listview info pointer*/
    93277899  COMCTL32_Free(infoPtr);
    93287900
    9329   SetWindowLongW(hwnd, 0, 0);
    93307901  return 0;
    93317902}
     
    93337904/***
    93347905 * DESCRIPTION:
    9335  * Handles notifications from children.
    9336  * 
    9337  * PARAMETER(S):
    9338  * [I] HWND : window handle
    9339  * [I] INT : control identifier
    9340  * [I] LPNMHDR : notification information
    9341  * 
     7906 * Handles notifications from header.
     7907 *
     7908 * PARAMETER(S):
     7909 * [I] infoPtr : valid pointer to the listview structure
     7910 * [I] nCtrlId : control identifier
     7911 * [I] lpnmh : notification information
     7912 *
    93427913 * RETURN:
    93437914 * Zero
    93447915 */
    9345 static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh)
    9346 {
    9347   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
     7916static LRESULT LISTVIEW_HeaderNotification(LISTVIEW_INFO *infoPtr, const NMHEADERW *lpnmh)
     7917{
     7918    UINT uView =  infoPtr->dwStyle & LVS_TYPEMASK;
     7919   
     7920    TRACE("(lpnmh=%p)\n", lpnmh);
     7921
     7922    if (!lpnmh || lpnmh->iItem < 0 || lpnmh->iItem >= infoPtr->hdpaColumns->nItemCount) return 0;
     7923   
     7924    switch (lpnmh->hdr.code)
     7925    {   
     7926        case HDN_TRACKW:
     7927        case HDN_TRACKA:
     7928        case HDN_ITEMCHANGEDW:
     7929        case HDN_ITEMCHANGEDA:
     7930        {
     7931            COLUMN_INFO *lpColumnInfo;
     7932            INT dx, cxy;
     7933
     7934            if (!lpnmh->pitem || !(lpnmh->pitem->mask & HDI_WIDTH))
     7935            {
     7936                HDITEMW hdi;
     7937   
     7938                hdi.mask = HDI_WIDTH;
     7939                if (!Header_GetItemW(infoPtr->hwndHeader, lpnmh->iItem, (LPARAM)&hdi)) return 0;
     7940                cxy = hdi.cxy;
     7941            }
     7942            else
     7943                cxy = lpnmh->pitem->cxy;
     7944           
     7945            /* determine how much we change since the last know position */
     7946            lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, lpnmh->iItem);
     7947            dx = cxy - (lpColumnInfo->rcHeader.right - lpColumnInfo->rcHeader.left);
     7948            if (dx != 0)
     7949            {
     7950                RECT rcCol = lpColumnInfo->rcHeader;
     7951
     7952                lpColumnInfo->rcHeader.right += dx;
     7953                LISTVIEW_ScrollColumns(infoPtr, lpnmh->iItem + 1, dx);
     7954                if (uView == LVS_REPORT && is_redrawing(infoPtr))
     7955                {
     7956                    /* this trick works for left aligned columns only */
     7957                    if ((lpColumnInfo->fmt & LVCFMT_JUSTIFYMASK) == LVCFMT_LEFT)
     7958                    {
     7959                        rcCol.right = min (rcCol.right, lpColumnInfo->rcHeader.right);
     7960                        rcCol.left = max (rcCol.left, rcCol.right - 3 * infoPtr->ntmAveCharWidth);
     7961                    }
     7962                    rcCol.top = infoPtr->rcList.top;
     7963                    rcCol.bottom = infoPtr->rcList.bottom;
     7964                    LISTVIEW_InvalidateRect(infoPtr, &rcCol);
     7965                }
     7966            }
     7967        }
     7968        break;
     7969
     7970        case HDN_ITEMCLICKW:
     7971        case HDN_ITEMCLICKA:
     7972        {
     7973            /* Handle sorting by Header Column */
     7974            NMLISTVIEW nmlv;
     7975
     7976            ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
     7977            nmlv.iItem = -1;
     7978            nmlv.iSubItem = lpnmh->iItem;
     7979            notify_listview(infoPtr, LVN_COLUMNCLICK, &nmlv);
     7980        }
     7981        break;
     7982    }
     7983
     7984    return 0;
     7985}
     7986
     7987/***
     7988 * DESCRIPTION:
     7989 * Determines the type of structure to use.
     7990 *
     7991 * PARAMETER(S):
     7992 * [I] infoPtr : valid pointer to the listview structureof the sender
     7993 * [I] hwndFrom : listview window handle
     7994 * [I] nCommand : command specifying the nature of the WM_NOTIFYFORMAT
     7995 *
     7996 * RETURN:
     7997 * Zero
     7998 */
     7999static LRESULT LISTVIEW_NotifyFormat(LISTVIEW_INFO *infoPtr, HWND hwndFrom, INT nCommand)
     8000{
     8001    TRACE("(hwndFrom=%p, nCommand=%d)\n", hwndFrom, nCommand);
     8002
     8003    if (nCommand != NF_REQUERY) return 0;
     8004   
     8005    infoPtr->notifyFormat = SendMessageW(hwndFrom, WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY);
     8006   
     8007    return 0;
     8008}
     8009
     8010/***
     8011 * DESCRIPTION:
     8012 * Paints/Repaints the listview control.
     8013 *
     8014 * PARAMETER(S):
     8015 * [I] infoPtr : valid pointer to the listview structure
     8016 * [I] hdc : device context handle
     8017 *
     8018 * RETURN:
     8019 * Zero
     8020 */
     8021static LRESULT LISTVIEW_Paint(LISTVIEW_INFO *infoPtr, HDC hdc)
     8022{
     8023    TRACE("(hdc=%p)\n", hdc);
     8024
     8025    infoPtr->bFirstPaint = FALSE;
     8026    if (infoPtr->bNoItemMetrics && infoPtr->nItemCount)
     8027    {
     8028        UINT uView =  infoPtr->dwStyle & LVS_TYPEMASK;
     8029       
     8030        infoPtr->bNoItemMetrics = FALSE;
     8031        LISTVIEW_UpdateItemSize(infoPtr);
     8032        if (uView == LVS_ICON || uView == LVS_SMALLICON)
     8033            LISTVIEW_Arrange(infoPtr, LVA_DEFAULT);
     8034        LISTVIEW_UpdateScroll(infoPtr);
     8035    }
     8036    if (hdc)
     8037        LISTVIEW_Refresh(infoPtr, hdc);
     8038    else
     8039    {
     8040        PAINTSTRUCT ps;
     8041
     8042        hdc = BeginPaint(infoPtr->hwndSelf, &ps);
     8043        if (!hdc) return 1;
     8044        if (ps.fErase) LISTVIEW_FillBkgnd(infoPtr, hdc, &ps.rcPaint);
     8045        LISTVIEW_Refresh(infoPtr, hdc);
     8046        EndPaint(infoPtr->hwndSelf, &ps);
     8047    }
     8048
     8049    return 0;
     8050}
     8051
     8052/***
     8053 * DESCRIPTION:
     8054 * Processes double click messages (right mouse button).
     8055 *
     8056 * PARAMETER(S):
     8057 * [I] infoPtr : valid pointer to the listview structure
     8058 * [I] wKey : key flag
     8059 * [I] pts : mouse coordinate
     8060 *
     8061 * RETURN:
     8062 * Zero
     8063 */
     8064static LRESULT LISTVIEW_RButtonDblClk(LISTVIEW_INFO *infoPtr, WORD wKey, POINTS pts)
     8065{
     8066    LVHITTESTINFO lvHitTestInfo;
     8067   
     8068    TRACE("(key=%hu,X=%hu,Y=%hu)\n", wKey, pts.x, pts.y);
     8069
     8070    /* send NM_RELEASEDCAPTURE notification */
     8071    notify(infoPtr, NM_RELEASEDCAPTURE);
     8072
     8073    /* send NM_RDBLCLK notification */
     8074    lvHitTestInfo.pt.x = pts.x;
     8075    lvHitTestInfo.pt.y = pts.y;
     8076    LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, FALSE);
     8077    notify_click(infoPtr, NM_RDBLCLK, &lvHitTestInfo);
     8078
     8079    return 0;
     8080}
     8081
     8082/***
     8083 * DESCRIPTION:
     8084 * Processes mouse down messages (right mouse button).
     8085 *
     8086 * PARAMETER(S):
     8087 * [I] infoPtr : valid pointer to the listview structure
     8088 * [I] wKey : key flag
     8089 * [I] pts : mouse coordinate
     8090 *
     8091 * RETURN:
     8092 * Zero
     8093 */
     8094static LRESULT LISTVIEW_RButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, POINTS pts)
     8095{
     8096    LVHITTESTINFO lvHitTestInfo;
     8097    INT nItem;
     8098
     8099    TRACE("(key=%hu,X=%hu,Y=%hu)\n", wKey, pts.x, pts.y);
     8100
     8101    /* send NM_RELEASEDCAPTURE notification */
     8102    notify(infoPtr, NM_RELEASEDCAPTURE);
     8103
     8104    /* make sure the listview control window has the focus */
     8105    if (!infoPtr->bFocus) SetFocus(infoPtr->hwndSelf);
     8106
     8107    /* set right button down flag */
     8108    infoPtr->bRButtonDown = TRUE;
     8109
     8110    /* determine the index of the selected item */
     8111    lvHitTestInfo.pt.x = pts.x;
     8112    lvHitTestInfo.pt.y = pts.y;
     8113    nItem = LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE);
    93488114 
    9349   TRACE("(hwnd=%x, nCtrlId=%d, lpnmh=%p)\n", hwnd, nCtrlId, lpnmh);
    9350  
    9351   if (lpnmh->hwndFrom == infoPtr->hwndHeader)
    9352   {
    9353     /* handle notification from header control */
    9354     if (lpnmh->code == HDN_ENDTRACKW)
    9355     {
    9356       infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
    9357       InvalidateRect(hwnd, NULL, TRUE);
    9358     }
    9359 #ifdef __WIN32OS2__
     8115    if ((nItem >= 0) && (nItem < infoPtr->nItemCount))
     8116    {
     8117        LISTVIEW_SetItemFocus(infoPtr, nItem);
     8118        if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)) &&
     8119            !LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED))
     8120            LISTVIEW_SetSelection(infoPtr, nItem);
     8121    }
    93608122    else
    9361     if ((lpnmh->code == HDN_ITEMCHANGEDA) || (lpnmh->code == HDN_ITEMCHANGEDW))
    9362     {
    9363       INT width;
    9364 
    9365       width = LISTVIEW_GetItemWidth(hwnd);
    9366       if (width != infoPtr->nItemWidth)
    9367       {
    9368         HDC hdc;
    9369 
    9370         infoPtr->nItemWidth = width;
    9371         LISTVIEW_UpdateScroll(hwnd);
    9372         hdc = GetDC(hwnd);
    9373         LISTVIEW_Refresh(hwnd, hdc);
    9374         ReleaseDC(hwnd, hdc);
    9375       }
    9376     }
    9377 #endif
    9378     else if(lpnmh->code ==  HDN_ITEMCLICKW || lpnmh->code ==  HDN_ITEMCLICKA)
    9379     {
    9380         /* Handle sorting by Header Column */
    9381         NMLISTVIEW nmlv;
    9382 
    9383         ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
    9384         nmlv.iItem = -1;
    9385         nmlv.iSubItem = ((LPNMHEADERW)lpnmh)->iItem;
    9386         listview_notify(hwnd, LVN_COLUMNCLICK, &nmlv);
    9387     }
    9388     else if(lpnmh->code == NM_RELEASEDCAPTURE)
    9389     {
    9390       /* Idealy this should be done in HDN_ENDTRACKA
    9391        * but since SetItemBounds in Header.c is called after
    9392        * the notification is sent, it is neccessary to handle the
    9393        * update of the scroll bar here (Header.c works fine as it is,
    9394        * no need to disturb it)
    9395        */
    9396       infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
    9397       LISTVIEW_UpdateScroll(hwnd);
    9398       InvalidateRect(hwnd, NULL, TRUE);
    9399     }
    9400 
    9401   }
    9402 
    9403   return 0;
    9404 }
    9405 
    9406 /***
    9407  * DESCRIPTION:
    9408  * Determines the type of structure to use.
    9409  *
    9410  * PARAMETER(S):
    9411  * [I] HWND : window handle of the sender
    9412  * [I] HWND : listview window handle
    9413  * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
     8123    {
     8124        LISTVIEW_DeselectAll(infoPtr);
     8125    }
     8126
     8127    return 0;
     8128}
     8129
     8130/***
     8131 * DESCRIPTION:
     8132 * Processes mouse up messages (right mouse button).
     8133 *
     8134 * PARAMETER(S):
     8135 * [I] infoPtr : valid pointer to the listview structure
     8136 * [I] wKey : key flag
     8137 * [I] pts : mouse coordinate
    94148138 *
    94158139 * RETURN:
    94168140 * Zero
    94178141 */
    9418 static LRESULT LISTVIEW_NotifyFormat(HWND hwndFrom, HWND hwnd, INT nCommand)
    9419 {
    9420   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    9421 
    9422   TRACE("(hwndFrom=%x, hwnd=%x, nCommand=%d)\n", hwndFrom, hwnd, nCommand);
    9423  
    9424   if (nCommand == NF_REQUERY)
    9425     infoPtr->notifyFormat = SendMessageW(hwndFrom, WM_NOTIFYFORMAT,
    9426                                          (WPARAM)hwnd, (LPARAM)NF_QUERY);
    9427   return 0;
    9428 }
    9429 
    9430 /***
    9431  * DESCRIPTION:
    9432  * Paints/Repaints the listview control.
    9433  *
    9434  * PARAMETER(S):
    9435  * [I] HWND : window handle
    9436  * [I] HDC : device context handle
    9437  *
    9438  * RETURN:
    9439  * Zero
    9440  */
    9441 static LRESULT LISTVIEW_Paint(HWND hwnd, HDC hdc)
    9442 {
    9443   PAINTSTRUCT ps;
    9444 
    9445   TRACE("(hwnd=%x, hdc=%x)\n", hwnd, hdc);
    9446 
    9447   if (hdc == 0)
    9448   {
    9449     hdc = BeginPaint(hwnd, &ps);
    9450     LISTVIEW_Refresh(hwnd, hdc);
    9451     EndPaint(hwnd, &ps);
    9452   }
    9453   else
    9454   {
    9455     LISTVIEW_Refresh(hwnd, hdc);
    9456   }
    9457 
    9458   return 0;
    9459 }
    9460 
    9461 /***
    9462  * DESCRIPTION:
    9463  * Processes double click messages (right mouse button).
    9464  *
    9465  * PARAMETER(S):
    9466  * [I] HWND : window handle
    9467  * [I] WORD : key flag
    9468  * [I] WORD : x coordinate
    9469  * [I] WORD : y coordinate
    9470  *
    9471  * RETURN:
    9472  * Zero
    9473  */
    9474 static LRESULT LISTVIEW_RButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
    9475                                       WORD wPosY)
    9476 {
    9477   TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
    9478 
    9479   /* send NM_RELEASEDCAPTURE notification */
    9480   hdr_notify(hwnd, NM_RELEASEDCAPTURE);
    9481 
    9482   /* send NM_RDBLCLK notification */
    9483   hdr_notify(hwnd, NM_RDBLCLK);
    9484 
    9485   return 0;
    9486 }
    9487 
    9488 /***
    9489  * DESCRIPTION:
    9490  * Processes mouse down messages (right mouse button).
    9491  *
    9492  * PARAMETER(S):
    9493  * [I] HWND : window handle
    9494  * [I] WORD : key flag
    9495  * [I] WORD : x coordinate
    9496  * [I] WORD : y coordinate
    9497  *
    9498  * RETURN:
    9499  * Zero
    9500  */
    9501 static LRESULT LISTVIEW_RButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
    9502                                     WORD wPosY)
    9503 {
    9504   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    9505   POINT ptPosition;
    9506   INT nItem;
    9507   NMLISTVIEW nmlv;
    9508   LVHITTESTINFO lvHitTestInfo;
    9509 
    9510   TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
    9511 
    9512   /* send NM_RELEASEDCAPTURE notification */
    9513   hdr_notify(hwnd, NM_RELEASEDCAPTURE);
     8142static LRESULT LISTVIEW_RButtonUp(LISTVIEW_INFO *infoPtr, WORD wKey, POINTS pts)
     8143{
     8144    LVHITTESTINFO lvHitTestInfo;
     8145    POINT pt;
     8146
     8147    TRACE("(key=%hu,X=%hu,Y=%hu)\n", wKey, pts.x, pts.y);
     8148
     8149    if (!infoPtr->bRButtonDown) return 0;
    95148150 
    9515   /* make sure the listview control window has the focus */
    9516   if (infoPtr->bFocus == FALSE)
    9517     SetFocus(hwnd);
    9518 
    9519   /* set right button down flag */
    9520   infoPtr->bRButtonDown = TRUE;
    9521 
    9522   /* determine the index of the selected item */
    9523   ptPosition.x = wPosX;
    9524   ptPosition.y = wPosY;
    9525   nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
    9526   if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
    9527   {
    9528     LISTVIEW_SetItemFocus(hwnd,nItem);
    9529     if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)) &&
    9530         !LISTVIEW_IsSelected(hwnd,nItem))
    9531       LISTVIEW_SetSelection(hwnd, nItem);
    9532   }
    9533   else
    9534   {
    9535     LISTVIEW_RemoveAllSelections(hwnd);
    9536   }
    9537 
    9538   lvHitTestInfo.pt.x = wPosX;
    9539   lvHitTestInfo.pt.y = wPosY;
    9540 
    9541   /* Send NM_RClICK notification */
    9542   ZeroMemory(&nmlv, sizeof(nmlv));
    9543   if (LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo, TRUE) != -1)
    9544   {
    9545     nmlv.iItem = lvHitTestInfo.iItem;
    9546     nmlv.iSubItem = lvHitTestInfo.iSubItem;
    9547   }
    9548   else
    9549   {
    9550     nmlv.iItem = -1;
    9551     nmlv.iSubItem = 0;
    9552   }
    9553   nmlv.ptAction.x = wPosX;
    9554   nmlv.ptAction.y = wPosY;
    9555   listview_notify(hwnd, NM_RCLICK, &nmlv);
    9556  
    9557   return 0;
    9558 }
    9559 
    9560 /***
    9561  * DESCRIPTION:
    9562  * Processes mouse up messages (right mouse button).
    9563  *
    9564  * PARAMETER(S):
    9565  * [I] HWND : window handle
    9566  * [I] WORD : key flag
    9567  * [I] WORD : x coordinate
    9568  * [I] WORD : y coordinate
    9569  *
    9570  * RETURN:
    9571  * Zero
    9572  */
    9573 static LRESULT LISTVIEW_RButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
    9574                                   WORD wPosY)
    9575 {
    9576   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    9577 
    9578   TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
    9579 
    9580   if (infoPtr->bRButtonDown)
    9581   {
    9582     POINT pt;
    9583 
    9584     pt.x = wPosX;
    9585     pt.y = wPosY;
    9586 
    95878151    /* set button flag */
    95888152    infoPtr->bRButtonDown = FALSE;
    9589    
     8153
     8154    /* Send NM_RClICK notification */
     8155    lvHitTestInfo.pt.x = pts.x;
     8156    lvHitTestInfo.pt.y = pts.y;
     8157    LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, FALSE);
     8158    notify_click(infoPtr, NM_RCLICK, &lvHitTestInfo);
     8159
    95908160    /* Change to screen coordinate for WM_CONTEXTMENU */
    9591     ClientToScreen(hwnd, &pt);
    9592    
     8161    pt = lvHitTestInfo.pt;
     8162    ClientToScreen(infoPtr->hwndSelf, &pt);
     8163
    95938164    /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
    9594     SendMessageW( hwnd, WM_CONTEXTMENU, (WPARAM) hwnd, MAKELPARAM(pt.x, pt.y));
    9595   }
    9596 
    9597 #ifdef __WIN32OS2__
    9598   if(infoPtr->bDragInProcess) {
    9599       infoPtr->bDragInProcess = FALSE;
    9600   }
    9601 #endif 
    9602  
    9603   return 0;
    9604 }
    9605 
    9606 /***
    9607  * DESCRIPTION:
    9608  * Sets the focus. 
    9609  *
    9610  * PARAMETER(S):
    9611  * [I] HWND : window handle
    9612  * [I] HWND : window handle of previously focused window
     8165    SendMessageW(infoPtr->hwndSelf, WM_CONTEXTMENU,
     8166                 (WPARAM)infoPtr->hwndSelf, MAKELPARAM(pt.x, pt.y));
     8167
     8168    return 0;
     8169}
     8170
     8171
     8172/***
     8173 * DESCRIPTION:
     8174 * Sets the cursor.
     8175 *
     8176 * PARAMETER(S):
     8177 * [I] infoPtr : valid pointer to the listview structure
     8178 * [I] hwnd : window handle of window containing the cursor
     8179 * [I] nHittest : hit-test code
     8180 * [I] wMouseMsg : ideintifier of the mouse message
     8181 *
     8182 * RETURN:
     8183 * TRUE if cursor is set
     8184 * FALSE otherwise
     8185 */
     8186static BOOL LISTVIEW_SetCursor(LISTVIEW_INFO *infoPtr, HWND hwnd, UINT nHittest, UINT wMouseMsg)
     8187{
     8188    LVHITTESTINFO lvHitTestInfo;
     8189
     8190    if(!(infoPtr->dwLvExStyle & LVS_EX_TRACKSELECT)) return FALSE;
     8191
     8192    if(!infoPtr->hHotCursor)  return FALSE;
     8193
     8194    GetCursorPos(&lvHitTestInfo.pt);
     8195    if (LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, FALSE, FALSE) < 0) return FALSE;
     8196
     8197    SetCursor(infoPtr->hHotCursor);
     8198
     8199    return TRUE;
     8200}
     8201
     8202/***
     8203 * DESCRIPTION:
     8204 * Sets the focus.
     8205 *
     8206 * PARAMETER(S):
     8207 * [I] infoPtr : valid pointer to the listview structure
     8208 * [I] hwndLoseFocus : handle of previously focused window
    96138209 *
    96148210 * RETURN:
    96158211 * Zero
    96168212 */
    9617 static LRESULT LISTVIEW_SetFocus(HWND hwnd, HWND hwndLoseFocus)
    9618 {
    9619   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    9620 
    9621   TRACE("(hwnd=%x, hwndLoseFocus=%x)\n", hwnd, hwndLoseFocus);
    9622 
    9623   /* send NM_SETFOCUS notification */
    9624   hdr_notify(hwnd, NM_SETFOCUS);
    9625 
    9626   /* set window focus flag */
    9627   infoPtr->bFocus = TRUE;
    9628 
    9629   UpdateWindow(hwnd);
    9630 
    9631   return 0;
    9632 }
    9633 
    9634 /***
    9635  * DESCRIPTION:
    9636  * Sets the font. 
    9637  *
    9638  * PARAMETER(S):
    9639  * [I] HWND : window handle
    9640  * [I] HFONT : font handle
    9641  * [I] WORD : redraw flag
     8213static LRESULT LISTVIEW_SetFocus(LISTVIEW_INFO *infoPtr, HWND hwndLoseFocus)
     8214{
     8215    TRACE("(hwndLoseFocus=%p)\n", hwndLoseFocus);
     8216
     8217    /* if we have the focus already, there's nothing to do */
     8218    if (infoPtr->bFocus) return 0;
     8219   
     8220    /* send NM_SETFOCUS notification */
     8221    notify(infoPtr, NM_SETFOCUS);
     8222
     8223    /* set window focus flag */
     8224    infoPtr->bFocus = TRUE;
     8225
     8226    /* put the focus rect back on */
     8227    LISTVIEW_ShowFocusRect(infoPtr, TRUE);
     8228
     8229    /* redraw all visible selected items */
     8230    LISTVIEW_InvalidateSelectedItems(infoPtr);
     8231
     8232    return 0;
     8233}
     8234
     8235/***
     8236 * DESCRIPTION:
     8237 * Sets the font.
     8238 *
     8239 * PARAMETER(S):
     8240 * [I] infoPtr : valid pointer to the listview structure
     8241 * [I] fRedraw : font handle
     8242 * [I] fRedraw : redraw flag
    96428243 *
    96438244 * RETURN:
    96448245 * Zero
    96458246 */
    9646 static LRESULT LISTVIEW_SetFont(HWND hwnd, HFONT hFont, WORD fRedraw)
    9647 {
    9648   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    9649   UINT uView = GetWindowLongW(hwnd, GWL_STYLE) & LVS_TYPEMASK;
    9650 
    9651   TRACE("(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd, hFont, fRedraw);
    9652 
    9653   infoPtr->hFont = hFont ? hFont : infoPtr->hDefaultFont;
    9654   LISTVIEW_SaveTextMetrics(hwnd);
    9655 
    9656   if (uView == LVS_REPORT)
    9657   {
    9658     /* set header font */
    9659     SendMessageW(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont,
    9660                    MAKELPARAM(fRedraw, 0));
    9661   }
    9662 
    9663 #ifdef __WIN32OS2__
    9664   //set tooltip font
    9665   SendMessageA(infoPtr->hwndToolTip,WM_SETFONT,(WPARAM)hFont,fRedraw);
    9666 #endif
    9667 
    9668   /* invalidate listview control client area */
    9669   InvalidateRect(hwnd, NULL, TRUE);
    9670  
    9671   if (fRedraw != FALSE)
    9672     UpdateWindow(hwnd);
    9673 
    9674   return 0;
    9675 }
    9676 
    9677 /***
    9678  * DESCRIPTION:
    9679  * Message handling for WM_SETREDRAW. 
     8247static LRESULT LISTVIEW_SetFont(LISTVIEW_INFO *infoPtr, HFONT hFont, WORD fRedraw)
     8248{
     8249    HFONT oldFont = infoPtr->hFont;
     8250
     8251    TRACE("(hfont=%p,redraw=%hu)\n", hFont, fRedraw);
     8252
     8253    infoPtr->hFont = hFont ? hFont : infoPtr->hDefaultFont;
     8254    if (infoPtr->hFont == oldFont) return 0;
     8255   
     8256    LISTVIEW_SaveTextMetrics(infoPtr);
     8257
     8258    if ((infoPtr->dwStyle & LVS_TYPEMASK) == LVS_REPORT)
     8259        SendMessageW(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(fRedraw, 0));
     8260
     8261    if (fRedraw) LISTVIEW_InvalidateList(infoPtr);
     8262
     8263    return 0;
     8264}
     8265
     8266/***
     8267 * DESCRIPTION:
     8268 * Message handling for WM_SETREDRAW.
    96808269 * For the Listview, it invalidates the entire window (the doc specifies otherwise)
    9681  * 
    9682  * PARAMETER(S):
    9683  * [I] HWND   : window handle
     8270 *
     8271 * PARAMETER(S):
     8272 * [I] infoPtr : valid pointer to the listview structure
    96848273 * [I] bRedraw: state of redraw flag
    96858274 *
     
    96878276 * DefWinProc return value
    96888277 */
    9689 static LRESULT LISTVIEW_SetRedraw(HWND hwnd, BOOL bRedraw)
    9690 {
    9691 #ifdef __WIN32OS2__
    9692   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
    9693   LRESULT lResult;
    9694   if (bRedraw)
    9695   {
    9696     if (!(infoPtr->internalFlags & IF_NOREDRAW)) return 0;
    9697     infoPtr->internalFlags &= ~IF_NOREDRAW;
    9698     lResult = DefWindowProcA(hwnd, WM_SETREDRAW, bRedraw, 0);
    9699 
    9700     LISTVIEW_UpdateScroll(hwnd);
    9701     RedrawWindow(hwnd,NULL,0,RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN | RDW_ERASENOW);
    9702   } else
    9703   {
    9704     infoPtr->internalFlags |= IF_NOREDRAW;
    9705     lResult = DefWindowProcA(hwnd, WM_SETREDRAW, bRedraw, 0);
    9706   }
    9707 #else
    9708     LRESULT lResult;
    9709     lResult = DefWindowProcA(hwnd, WM_SETREDRAW, bRedraw, 0);
    9710     if(bRedraw)
    9711     {
    9712         RedrawWindow(hwnd, NULL, 0,
    9713             RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN | RDW_ERASENOW);
    9714     }
    9715 #endif
    9716     return lResult;
     8278static LRESULT LISTVIEW_SetRedraw(LISTVIEW_INFO *infoPtr, BOOL bRedraw)
     8279{
     8280    TRACE("infoPtr->bRedraw=%d, bRedraw=%d\n", infoPtr->bRedraw, bRedraw);
     8281
     8282    /* we can not use straight equality here because _any_ non-zero value is TRUE */
     8283    if ((infoPtr->bRedraw && bRedraw) || (!infoPtr->bRedraw && !bRedraw)) return 0;
     8284
     8285    infoPtr->bRedraw = bRedraw;
     8286
     8287    if(!bRedraw) return 0;
     8288   
     8289    if (is_autoarrange(infoPtr))
     8290        LISTVIEW_Arrange(infoPtr, LVA_DEFAULT);
     8291    LISTVIEW_UpdateScroll(infoPtr);
     8292
     8293    /* despite what the WM_SETREDRAW docs says, apps expect us
     8294     * to invalidate the listview here... stupid! */
     8295    LISTVIEW_InvalidateList(infoPtr);
     8296
     8297    return 0;
    97178298}
    97188299
     
    97218302 * Resizes the listview control. This function processes WM_SIZE
    97228303 * messages.  At this time, the width and height are not used.
    9723  * 
    9724  * PARAMETER(S):
    9725  * [I] HWND : window handle
    9726  * [I] WORD : new width
    9727  * [I] WORD : new height
     8304 *
     8305 * PARAMETER(S):
     8306 * [I] infoPtr : valid pointer to the listview structure
     8307 * [I] Width : new width
     8308 * [I] Height : new height
    97288309 *
    97298310 * RETURN:
    97308311 * Zero
    97318312 */
    9732 static LRESULT LISTVIEW_Size(HWND hwnd, int Width, int Height)
    9733 {
    9734   LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    9735   UINT uView = lStyle & LVS_TYPEMASK;
    9736 #ifdef __WIN32OS2__
    9737   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
    9738 #endif
    9739   TRACE("(hwnd=%x, width=%d, height=%d)\n", hwnd, Width, Height);
    9740 
    9741   if (LISTVIEW_UpdateSize(hwnd))
    9742   {
    9743     if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
    9744     {
    9745         if (lStyle & LVS_ALIGNLEFT)
    9746             LISTVIEW_AlignLeft(hwnd);
    9747         else
    9748             LISTVIEW_AlignTop(hwnd);
    9749     }
    9750 
    9751     LISTVIEW_UpdateScroll(hwnd);
    9752 
    9753 #ifdef __WIN32OS2__
    9754   //width/height may have changed
    9755   infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
    9756   infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
    9757 #endif
     8313static LRESULT LISTVIEW_Size(LISTVIEW_INFO *infoPtr, int Width, int Height)
     8314{
     8315    RECT rcOld = infoPtr->rcList;
     8316
     8317    TRACE("(width=%d, height=%d)\n", Width, Height);
     8318
     8319    LISTVIEW_UpdateSize(infoPtr);
     8320    if (EqualRect(&rcOld, &infoPtr->rcList)) return 0;
    97588321 
    9759     /* invalidate client area + erase background */
    9760     InvalidateRect(hwnd, NULL, TRUE);
    9761   }
     8322    /* do not bother with display related stuff if we're not redrawing */
     8323    if (!is_redrawing(infoPtr)) return 0;
     8324   
     8325    if (is_autoarrange(infoPtr))
     8326        LISTVIEW_Arrange(infoPtr, LVA_DEFAULT);
     8327
     8328    LISTVIEW_UpdateScroll(infoPtr);
     8329
     8330    /* refresh all only for lists whose height changed significantly */
     8331    if ((infoPtr->dwStyle & LVS_TYPEMASK) == LVS_LIST &&
     8332        (rcOld.bottom - rcOld.top) / infoPtr->nItemHeight !=
     8333        (infoPtr->rcList.bottom - infoPtr->rcList.top) / infoPtr->nItemHeight)
     8334        LISTVIEW_InvalidateList(infoPtr);
    97628335
    97638336  return 0;
     
    97678340 * DESCRIPTION:
    97688341 * Sets the size information.
    9769  *
    9770  * PARAMETER(S):
    9771  * [I] HWND : window handle
    9772  *
    9773  * RETURN:
    9774  * Zero if no size change
    9775  * 1 of size changed
    9776  */
    9777 static BOOL LISTVIEW_UpdateSize(HWND hwnd)
    9778 {
    9779   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    9780   LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
    9781   UINT uView = lStyle & LVS_TYPEMASK;
    9782   RECT rcList;
    9783   RECT rcOld;
     8342 *
     8343 * PARAMETER(S):
     8344 * [I] infoPtr : valid pointer to the listview structure
     8345 *
     8346 * RETURN:
     8347 *  None
     8348 */
     8349static void LISTVIEW_UpdateSize(LISTVIEW_INFO *infoPtr)
     8350{
     8351    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     8352
     8353    TRACE("uView=%d, rcList(old)=%s\n", uView, debugrect(&infoPtr->rcList));
     8354   
     8355    GetClientRect(infoPtr->hwndSelf, &infoPtr->rcList);
     8356
     8357    if (uView == LVS_LIST)
     8358    {
     8359        /* Apparently the "LIST" style is supposed to have the same
     8360         * number of items in a column even if there is no scroll bar.
     8361         * Since if a scroll bar already exists then the bottom is already
     8362         * reduced, only reduce if the scroll bar does not currently exist.
     8363         * The "2" is there to mimic the native control. I think it may be
     8364         * related to either padding or edges.  (GLA 7/2002)
     8365         */
     8366        if (!(infoPtr->dwStyle & WS_HSCROLL))
     8367            infoPtr->rcList.bottom -= GetSystemMetrics(SM_CYHSCROLL);
     8368        infoPtr->rcList.bottom = max (infoPtr->rcList.bottom - 2, 0);
     8369    }
     8370    else if (uView == LVS_REPORT && !(infoPtr->dwStyle & LVS_NOCOLUMNHEADER))
     8371    {
     8372        HDLAYOUT hl;
     8373        WINDOWPOS wp;
     8374
     8375        hl.prc = &infoPtr->rcList;
     8376        hl.pwpos = &wp;
     8377        Header_Layout(infoPtr->hwndHeader, &hl);
     8378
     8379        SetWindowPos(wp.hwnd, wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
     8380
     8381        infoPtr->rcList.top = max(wp.cy, 0);
     8382    }
     8383
     8384    TRACE("  rcList=%s\n", debugrect(&infoPtr->rcList));
     8385}
     8386
     8387/***
     8388 * DESCRIPTION:
     8389 * Processes WM_STYLECHANGED messages.
     8390 *
     8391 * PARAMETER(S):
     8392 * [I] infoPtr : valid pointer to the listview structure
     8393 * [I] wStyleType : window style type (normal or extended)
     8394 * [I] lpss : window style information
     8395 *
     8396 * RETURN:
     8397 * Zero
     8398 */
     8399static INT LISTVIEW_StyleChanged(LISTVIEW_INFO *infoPtr, WPARAM wStyleType,
     8400                                 const STYLESTRUCT *lpss)
     8401{
     8402    UINT uNewView = lpss->styleNew & LVS_TYPEMASK;
     8403    UINT uOldView = lpss->styleOld & LVS_TYPEMASK;
     8404
     8405    TRACE("(styletype=%x, styleOld=0x%08lx, styleNew=0x%08lx)\n",
     8406          wStyleType, lpss->styleOld, lpss->styleNew);
     8407
     8408    if (wStyleType != GWL_STYLE) return 0;
    97848409 
    9785   TRACE("(hwnd=%x)\n", hwnd);
    9786  
    9787   GetClientRect(hwnd, &rcList);
    9788   CopyRect(&rcOld,&(infoPtr->rcList));
    9789   infoPtr->rcList.left = 0;
    9790   infoPtr->rcList.right = max(rcList.right - rcList.left, 1);
    9791   infoPtr->rcList.top = 0;
    9792   infoPtr->rcList.bottom = max(rcList.bottom - rcList.top, 1);
    9793      
    9794   if (uView == LVS_LIST)
    9795   {
    9796     if (lStyle & WS_HSCROLL)
    9797     {
    9798       INT nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
    9799       if (infoPtr->rcList.bottom > nHScrollHeight)
    9800         infoPtr->rcList.bottom -= nHScrollHeight;
    9801     }
    9802   }
    9803   else if (uView == LVS_REPORT)
    9804   {
    9805     HDLAYOUT hl;
    9806     WINDOWPOS wp;
    9807 
    9808     hl.prc = &rcList;
    9809     hl.pwpos = &wp;
    9810     Header_Layout(infoPtr->hwndHeader, &hl);
    9811 
    9812     SetWindowPos(wp.hwnd, wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
    9813 
    9814     if (!(LVS_NOCOLUMNHEADER & lStyle))
    9815       infoPtr->rcList.top = max(wp.cy, 0);
    9816   }
    9817   return (!EqualRect(&rcOld,&(infoPtr->rcList)));
    9818 }
    9819 
    9820 /***
    9821  * DESCRIPTION:
    9822  * Processes WM_STYLECHANGED messages.
    9823  *
    9824  * PARAMETER(S):
    9825  * [I] HWND : window handle
    9826  * [I] WPARAM : window style type (normal or extended)
    9827  * [I] LPSTYLESTRUCT : window style information
    9828  *
    9829  * RETURN:
    9830  * Zero
    9831  */
    9832 static INT LISTVIEW_StyleChanged(HWND hwnd, WPARAM wStyleType,
    9833                                  LPSTYLESTRUCT lpss)
    9834 {
    9835   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    9836   UINT uNewView = lpss->styleNew & LVS_TYPEMASK;
    9837   UINT uOldView = lpss->styleOld & LVS_TYPEMASK;
    9838   RECT rcList = infoPtr->rcList;
    9839 
    9840   TRACE("(hwnd=%x, styletype=%x, stylestruct=%p)\n",
    9841         hwnd, wStyleType, lpss);
    9842 
    9843   if (wStyleType == GWL_STYLE)
    9844   {
    9845     if (uOldView == LVS_REPORT)
    9846       ShowWindow(infoPtr->hwndHeader, SW_HIDE);
    9847  
     8410    /* FIXME: if LVS_NOSORTHEADER changed, update header */
     8411    /*        what if LVS_OWNERDATA changed? */
     8412    /*        or LVS_SINGLESEL */
     8413    /*        or LVS_SORT{AS,DES}CENDING */
     8414
     8415    infoPtr->dwStyle = lpss->styleNew;
     8416
    98488417    if (((lpss->styleOld & WS_HSCROLL) != 0)&&
    98498418        ((lpss->styleNew & WS_HSCROLL) == 0))
    9850        ShowScrollBar(hwnd, SB_HORZ, FALSE);
    9851  
     8419       ShowScrollBar(infoPtr->hwndSelf, SB_HORZ, FALSE);
     8420
    98528421    if (((lpss->styleOld & WS_VSCROLL) != 0)&&
    98538422        ((lpss->styleNew & WS_VSCROLL) == 0))
    9854        ShowScrollBar(hwnd, SB_VERT, FALSE);
    9855  
    9856     if (uNewView == LVS_ICON)
    9857     {
    9858       infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
    9859       infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
    9860       infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
    9861       infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
    9862       if (lpss->styleNew & LVS_ALIGNLEFT)
    9863         LISTVIEW_AlignLeft(hwnd);
    9864       else
    9865         LISTVIEW_AlignTop(hwnd);
    9866     }
    9867     else if (uNewView == LVS_REPORT)
    9868     {
    9869       HDLAYOUT hl;
    9870       WINDOWPOS wp;
    9871 
    9872       hl.prc = &rcList;
    9873       hl.pwpos = &wp;
    9874       Header_Layout(infoPtr->hwndHeader, &hl);
    9875       SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, wp.cy,
    9876                    wp.flags);
    9877       if (!(LVS_NOCOLUMNHEADER & lpss->styleNew))
    9878         ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
    9879      
    9880       infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
    9881       infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
    9882       infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
    9883       infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
    9884     }
    9885     else if (uNewView == LVS_LIST)
    9886     {
    9887       infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
    9888       infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
    9889       infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
    9890       infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
    9891     }
    9892     else
    9893     {
    9894       infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
    9895       infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
    9896       infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
    9897       infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
    9898       if (lpss->styleNew & LVS_ALIGNLEFT)
    9899         LISTVIEW_AlignLeft(hwnd);
    9900       else
    9901         LISTVIEW_AlignTop(hwnd);
    9902     }
     8423       ShowScrollBar(infoPtr->hwndSelf, SB_VERT, FALSE);
     8424
     8425    if (uNewView != uOldView)
     8426    {
     8427        SIZE oldIconSize = infoPtr->iconSize;
     8428        HIMAGELIST himl;
     8429   
     8430        SendMessageW(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
     8431        ShowWindow(infoPtr->hwndHeader, SW_HIDE);
     8432
     8433        ShowScrollBar(infoPtr->hwndSelf, SB_BOTH, FALSE);
     8434        SetRectEmpty(&infoPtr->rcFocus);
     8435
     8436        himl = (uNewView == LVS_ICON ? infoPtr->himlNormal : infoPtr->himlSmall);
     8437        set_icon_size(&infoPtr->iconSize, himl, uNewView != LVS_ICON);
     8438   
     8439        if (uNewView == LVS_ICON)
     8440        {
     8441            if ((infoPtr->iconSize.cx != oldIconSize.cx) || (infoPtr->iconSize.cy != oldIconSize.cy))
     8442            {
     8443                TRACE("icon old size=(%ld,%ld), new size=(%ld,%ld)\n",
     8444                      oldIconSize.cx, oldIconSize.cy, infoPtr->iconSize.cx, infoPtr->iconSize.cy);
     8445                LISTVIEW_SetIconSpacing(infoPtr, 0, 0);
     8446            }
     8447        }
     8448        else if (uNewView == LVS_REPORT)
     8449        {
     8450            HDLAYOUT hl;
     8451            WINDOWPOS wp;
     8452
     8453            hl.prc = &infoPtr->rcList;
     8454            hl.pwpos = &wp;
     8455            Header_Layout(infoPtr->hwndHeader, &hl);
     8456            SetWindowPos(infoPtr->hwndHeader, infoPtr->hwndSelf, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
     8457        }
     8458
     8459        LISTVIEW_UpdateItemSize(infoPtr);
     8460    }
     8461
     8462    if (uNewView == LVS_REPORT)
     8463        ShowWindow(infoPtr->hwndHeader, (lpss->styleNew & LVS_NOCOLUMNHEADER) ? SW_HIDE : SW_SHOWNORMAL);
     8464     
     8465    if ( (uNewView == LVS_ICON || uNewView == LVS_SMALLICON) &&
     8466         (uNewView != uOldView || ((lpss->styleNew ^ lpss->styleOld) & LVS_ALIGNMASK)) )
     8467         LISTVIEW_Arrange(infoPtr, LVA_DEFAULT);
    99038468
    99048469    /* update the size of the client area */
    9905     LISTVIEW_UpdateSize(hwnd);
     8470    LISTVIEW_UpdateSize(infoPtr);
    99068471
    99078472    /* add scrollbars if needed */
    9908     LISTVIEW_UpdateScroll(hwnd);
    9909    
     8473    LISTVIEW_UpdateScroll(infoPtr);
     8474
    99108475    /* invalidate client area + erase background */
    9911     InvalidateRect(hwnd, NULL, TRUE);
    9912 
    9913     /* print the list of unsupported window styles */
    9914     LISTVIEW_UnsupportedStyles(lpss->styleNew);
     8476    LISTVIEW_InvalidateList(infoPtr);
     8477
     8478    return 0;
     8479}
     8480
     8481/***
     8482 * DESCRIPTION:
     8483 * Window procedure of the listview control.
     8484 *
     8485 */
     8486static LRESULT WINAPI
     8487LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     8488{
     8489  LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
     8490
     8491  TRACE("(uMsg=%x wParam=%x lParam=%lx)\n", uMsg, wParam, lParam);
     8492
     8493  if (!infoPtr && (uMsg != WM_CREATE))
     8494    return DefWindowProcW(hwnd, uMsg, wParam, lParam);
     8495
     8496  if (infoPtr)
     8497  {
     8498    infoPtr->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
    99158499  }
    9916 
    9917   /* If they change the view and we have an active edit control
    9918      we will need to kill the control since the redraw will
    9919      misplace the edit control.
    9920    */
    9921   if (infoPtr->hwndEdit &&
    9922         ((uNewView & (LVS_ICON|LVS_LIST|LVS_SMALLICON)) !=
    9923         ((LVS_ICON|LVS_LIST|LVS_SMALLICON) & uOldView)))
    9924   {
    9925      SendMessageW(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
    9926   }
    9927 
    9928   return 0;
    9929 }
    9930 
    9931 #ifdef __WIN32OS2__
    9932 static LRESULT LISTVIEW_CreateDragImage(HWND hwnd,WPARAM wParam,LPARAM lParam)
    9933 {
    9934   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
    9935   UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
    9936   INT iItem = (INT)wParam;
    9937   LPPOINT lpptUpLeft = (LPPOINT)lParam;
    9938   HWND hwtop;
    9939   HDC htopdc,hdc;
    9940   HFONT hOldFont;
    9941   RECT rect, SuggestedFocus;
    9942   HBITMAP hbmp,hOldbmp;
    9943   HIMAGELIST dragImage = NULL;
    9944 
    9945   LISTVIEW_GetOrigin(hwnd,lpptUpLeft);
    9946 
    9947   if ((iItem < 0) || (iItem > infoPtr->hdpaItems->nItemCount)) return 0;
    9948 
    9949   //get size
    9950   rect.left = LVIR_BOUNDS;
    9951   LISTVIEW_GetItemRect(hwnd,iItem,&rect);
    9952 
    9953   rect.right -= rect.left;
    9954   rect.bottom -= rect.top;
    9955   rect.left = 0;
    9956   rect.top = 0;
    9957 
    9958   hwtop = GetDesktopWindow();
    9959   htopdc = GetDC(hwtop);
    9960   hdc = CreateCompatibleDC(htopdc);
    9961 
    9962   hOldFont = SelectObject(hdc,infoPtr->hFont);
    9963   hbmp = CreateCompatibleBitmap(htopdc,rect.right,rect.bottom);
    9964   hOldbmp = SelectObject(hdc,hbmp);
    9965 
    9966   if (uView == LVS_ICON)
    9967   {
    9968     LISTVIEW_DrawLargeItem(hwnd,hdc,iItem,rect, &SuggestedFocus);
    9969   } else
    9970   { //TODO: FullSelect = FALSE????
    9971     LISTVIEW_DrawItem(hwnd,hdc,iItem,rect, FALSE, &SuggestedFocus);
    9972   }
    9973 
    9974   SelectObject(hdc,hOldFont);
    9975   SelectObject(hdc,hOldbmp);
    9976 
    9977   dragImage = ImageList_Create(rect.right,rect.bottom,ILC_COLOR,10,10);
    9978   ImageList_Add(dragImage,hbmp,0);
    9979 
    9980   DeleteDC(hdc);
    9981   DeleteObject(hbmp);
    9982   ReleaseDC(hwtop,htopdc);
    9983 
    9984   return (LRESULT)dragImage;
    9985 }
    9986 /***
    9987  * DESCRIPTION:
    9988  * Retrieves the background image of the listview control.
    9989  *
    9990  * PARAMETER(S):
    9991  * [I] HWND : window handle
    9992  * [O] LPLVMKBIMAGE : background image attributes
    9993  *
    9994  * RETURN:
    9995  *   SUCCESS : TRUE
    9996  *   FAILURE : FALSE`
    9997  */
    9998 static LRESULT LISTVIEW_GetBkImage(HWND hwnd,WPARAM wParam,LPARAM lParam,BOOL unicode)
    9999 {
    10000   LPLVBKIMAGEW plvbki = (LPLVBKIMAGEW)lParam;
    10001 
    10002   if (!plvbki) return FALSE;
    10003 
    10004   //todo: use COM OLE interface
    10005   dprintf(("LISTVIEW_GetBkImage %x %x %x %d not implemented!!", hwnd, wParam, lParam, unicode));
    10006 
    10007   return FALSE;
    10008 }
    10009 
    10010 static LRESULT LISTVIEW_SetBkImage(HWND hwnd,WPARAM wParam,LPARAM lParam,BOOL unicode)
    10011 {
    10012   LPLVBKIMAGEW plvbki = (LPLVBKIMAGEW)lParam;
    10013 
    10014   if (!plvbki) return FALSE;
    10015 
    10016   //todo: use OLE COM interface
    10017   dprintf(("LISTVIEW_SetBkImage %x %x %x %d not implemented!!", hwnd, wParam, lParam, unicode));
    10018 
    10019   return TRUE;
    10020 }
    10021 
    10022 static LRESULT LISTVIEW_GetHotCursor(HWND hwnd,WPARAM wParam,LPARAM lParam)
    10023 {
    10024   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
    10025 
    10026   return (LRESULT)infoPtr->hHotCursor;
    10027 }
    10028 
    10029 static LRESULT LISTVIEW_SetHotCursor(HWND hwnd,WPARAM wParam,LPARAM lParam)
    10030 {
    10031   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
    10032   HCURSOR hOldCursor = infoPtr->hHotCursor;
    10033 
    10034   infoPtr->hHotCursor = (HCURSOR)lParam;
    10035 
    10036   return hOldCursor;
    10037 }
    10038 
    10039 static LRESULT LISTVIEW_GetISearchString(HWND hwnd,WPARAM wParam,LPARAM lParam,BOOL unicode)
    10040 {
    10041   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
    10042   LPWSTR lpsz = (LPWSTR)lParam;
    10043 
    10044   if (infoPtr->uISearchLen == 0) return 0;
    10045 
    10046   if (unicode)
    10047     lstrcpyW(lpsz,infoPtr->pszISearch);
    10048   else
    10049     lstrcpyWtoA((LPSTR)lpsz,infoPtr->pszISearch);
    10050 
    10051   return infoPtr->uISearchLen;
    10052 }
    10053 
    10054 static LRESULT LISTVIEW_GetNumberOfWorkAreas(HWND hwnd,WPARAM wParam,LPARAM lParam)
    10055 {
    10056   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
    10057   LPINT lpuWorkAreas = (LPINT)lParam;
    10058 
    10059   if (!lpuWorkAreas) return FALSE;
    10060 
    10061   *lpuWorkAreas = infoPtr->nWorkAreas;
    10062 
    10063   return TRUE;
    10064 }
    10065 
    10066 //TODO: mustn't these be freed when the control is destroyed?
    10067 static LRESULT LISTVIEW_GetWorkAreas(HWND hwnd,WPARAM wParam,LPARAM lParam)
    10068 {
    10069   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
    10070   INT nWorkAreas = (INT)wParam, x;
    10071   LPRECT lprc = (LPRECT)lParam;
    10072 
    10073   if ((nWorkAreas <= 0) || (nWorkAreas > infoPtr->nWorkAreas) || !lprc) return FALSE;
    10074 
    10075   for (x = 0;x < nWorkAreas;x++)
    10076     lprc[x] = infoPtr->rcWorkAreas[x];
    10077 
    10078   return TRUE;
    10079 }
    10080 
    10081 static LRESULT LISTVIEW_SetWorkAreas(HWND hwnd,WPARAM wParam,LPARAM lParam)
    10082 {
    10083   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
    10084   INT nWorkAreas = (INT)wParam, x;
    10085   LPRECT lprc = (LPRECT)lParam;
    10086 
    10087   if ((nWorkAreas < 0) || (nWorkAreas > LV_MAX_WORKAREAS)) return FALSE;
    10088 
    10089   COMCTL32_Free(infoPtr->rcWorkAreas);
    10090   if ((nWorkAreas == 0) || !lprc)
    10091   {
    10092     infoPtr->nWorkAreas = 0;
    10093     infoPtr->rcWorkAreas = NULL;
    10094   } else
    10095   {
    10096     infoPtr->nWorkAreas = nWorkAreas;
    10097     infoPtr->rcWorkAreas = (LPRECT)COMCTL32_Alloc(nWorkAreas*sizeof(RECT));
    10098     for (x = 0;x < nWorkAreas;x++)
    10099      infoPtr->rcWorkAreas[x] = lprc[x];
    10100   }
    10101 
    10102   return TRUE;
    10103 }
    10104 
    10105 static BOOL LISTVIEW_GetSubItemPosition(HWND hwnd, LISTVIEW_INFO *infoPtr,INT nItem,INT nSubItem,LPPOINT lpptPosition)
    10106 {
    10107   RECT rect;
    10108 
    10109   if (Header_GetItemRect(infoPtr->hwndHeader,(WPARAM)nSubItem,(LPARAM)&rect))
    10110   {
    10111     lpptPosition->x = rect.left+REPORT_MARGINX;
    10112     lpptPosition->y = ((nItem-LISTVIEW_GetTopIndex(hwnd))*infoPtr->nItemHeight)+infoPtr->rcList.top;
    10113 
    10114     return TRUE;
    10115   }
    10116 
    10117   return FALSE;
    10118 }
    10119 
    10120 INT LISTVIEW_GetLabelWidthSub(HWND hwnd,INT nItem,INT nSubItem)
    10121 {
    10122   INT nLabelWidth = 0;
    10123   LVINTERNALITEMW lvItem;
    10124 
    10125   ZeroMemory(&lvItem, sizeof(LVITEMW));
    10126   lvItem.header.mask = LVIF_TEXT;
    10127   lvItem.header.iItem = nItem;
    10128   lvItem.header.iSubItem = nSubItem;
    10129   lvItem.header.cchTextMax = DISP_TEXT_SIZE;
    10130   lvItem.header.pszText = NULL;
    10131   lvItem.mustFree = FALSE;
    10132   if (LISTVIEW_GetItemT(hwnd,(LPLVITEMW)&lvItem,TRUE,TRUE))
    10133     nLabelWidth = ListView_GetStringWidthW(hwnd,lvItem.header.pszText);
    10134   if (lvItem.mustFree) COMCTL32_Free(lvItem.header.pszText);
    10135 
    10136   return nLabelWidth;
    10137 }
    10138 
    10139 static LRESULT LISTVIEW_GetSubItemRect(HWND hwnd,INT nItem,LPRECT lprc)
    10140 {
    10141   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
    10142   UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
    10143   INT nSubItem,code,nLabelWidth;
    10144   POINT ptItem;
    10145 
    10146   if (!lprc || (uView != LVS_REPORT) || (nItem < 0) || (nItem >= GETITEMCOUNT(infoPtr))) return FALSE;
    10147 
    10148   nSubItem = lprc->top;
    10149   if ((nSubItem < 0) || (nSubItem >= Header_GetItemCount(infoPtr->hwndHeader))) return FALSE;
    10150   if (!LISTVIEW_GetSubItemPosition(hwnd, infoPtr,nItem,nSubItem,&ptItem)) return FALSE;
    10151 
    10152   code = lprc->left;
    10153 
    10154   switch (code)
    10155   {
    10156     case LVIR_BOUNDS:
    10157       lprc->left = ptItem.x;
    10158       lprc->right = lprc->left;
    10159       lprc->top = ptItem.y;
    10160       lprc->bottom = lprc->top+infoPtr->nItemHeight;
    10161 
    10162       if ((infoPtr->dwExStyle & LVS_EX_SUBITEMIMAGES) && infoPtr->himlSmall)
    10163       {
    10164         lprc->right += infoPtr->iconSize.cx;
    10165       }
    10166 
    10167       nLabelWidth = LISTVIEW_GetLabelWidthSub(hwnd,nItem,nSubItem);
    10168       lprc->right += nLabelWidth;
    10169       break;
    10170 
    10171     case LVIR_ICON:
    10172       if (infoPtr->dwExStyle & LVS_EX_SUBITEMIMAGES)
    10173       {
    10174         lprc->left = ptItem.x;
    10175         lprc->top = ptItem.y;
    10176         lprc->bottom = lprc->top+infoPtr->nItemHeight;
    10177 
    10178         if (infoPtr->himlSmall)
    10179         {
    10180           lprc->right = lprc->left+infoPtr->iconSize.cx;
    10181         } else
    10182         {
    10183           lprc->right = lprc->left;
    10184         }
    10185         break;
    10186       } else return FALSE;
    10187 
    10188     case LVIR_LABEL:
    10189       lprc->left = ptItem.x;
    10190       lprc->right = lprc->left;
    10191       lprc->top = ptItem.y;
    10192       lprc->bottom = lprc->top+infoPtr->nItemHeight;
    10193 
    10194       nLabelWidth = LISTVIEW_GetLabelWidthSub(hwnd,nItem,nSubItem);
    10195       lprc->right += nLabelWidth;
    10196       break;
    10197 
    10198     default:
    10199       return FALSE;
    10200   }
    10201 
    10202   return TRUE;
    10203 }
    10204 
    10205 static LRESULT LISTVIEW_GetToolTips(HWND hwnd,WPARAM wParam,LPARAM lParam)
    10206 {
    10207   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
    10208 
    10209   return infoPtr->hwndToolTip;
    10210 }
    10211 
    10212 static LRESULT LISTVIEW_SetToolTips(HWND hwnd,WPARAM wParam,LPARAM lParam)
    10213 {
    10214   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
    10215   HWND oldToolTip = infoPtr->hwndToolTip;
    10216 
    10217   infoPtr->hwndToolTip = (HWND)lParam;
    10218 
    10219   return oldToolTip;
    10220 }
    10221 
    10222 static VOID LISTVIEW_ScrollWindow(HWND hwnd,INT xScroll,INT yScroll)
    10223 {
    10224   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
    10225   UINT dwStyle = GetWindowLongA(hwnd, GWL_STYLE);
    10226   UINT uView = dwStyle & LVS_TYPEMASK;
    10227 
    10228   if (infoPtr->internalFlags & IF_NOREDRAW) return;
    10229 
    10230   if ((uView == LVS_REPORT) && !(dwStyle & LVS_NOCOLUMNHEADER))
    10231   {
    10232     RECT rect = infoPtr->rcList;
    10233 
    10234     //clip header
    10235     if (yScroll < 0)
    10236     { //up
    10237       rect.top -= yScroll;
    10238       if (rect.top < rect.bottom)
    10239       {
    10240         INT h;
    10241 
    10242         ScrollWindowEx(hwnd,xScroll,yScroll,&rect,NULL,0,NULL,SW_INVALIDATE);
    10243         h = rect.bottom-rect.top;
    10244         rect.top = infoPtr->rcList.top+h;
    10245         rect.bottom = infoPtr->rcList.bottom-h;
    10246         if (rect.bottom > rect.top) InvalidateRect(hwnd,&rect,TRUE);
    10247       } else
    10248       {
    10249         InvalidateRect(hwnd,&infoPtr->rcList,TRUE);
    10250       }
    10251     } else
    10252     { //down
    10253       ScrollWindowEx(hwnd,xScroll,yScroll,&rect,NULL,0,NULL,SW_INVALIDATE);
    10254     }
    10255 
    10256 //    if (xScroll != 0) LISTVIEW_UpdateHeaderSize(hwnd,infoPtr->lefttop.x,xScroll);
    10257     if (xScroll != 0) LISTVIEW_UpdateHeaderSize(hwnd,infoPtr->lefttop.x);
    10258   } else ScrollWindowEx(hwnd,xScroll,yScroll,NULL,NULL,0,NULL,SW_INVALIDATE);
    10259 }
    10260 
    10261 static LRESULT LISTVIEW_Scroll(HWND hwnd,WPARAM wParam,LPARAM lParam)
    10262 {
    10263   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
    10264   UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
    10265   INT dx = (INT)wParam,dy = (INT)lParam,maxX,maxY;
    10266   POINT oldlefttop = infoPtr->lefttop;
    10267 
    10268   //x units: (icon, report -> pixels; list -> columns)
    10269   if (uView != LVS_LIST)
    10270   {
    10271     dx /= infoPtr->scrollStep.x;
    10272   }
    10273 
    10274   //y units: (icon, list -> pixels; report -> lines)
    10275   if (uView == LVS_LIST)
    10276   {
    10277     //no vertical scrolling (so far)
    10278     dy = 0;
    10279   } else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
    10280   {
    10281     dy /= infoPtr->scrollStep.y;
    10282   }
    10283 
    10284   infoPtr->lefttop.x += dx;
    10285   infoPtr->lefttop.y += dy;
    10286   maxX = infoPtr->maxScroll.x-infoPtr->scrollPage.x;
    10287   maxY = infoPtr->maxScroll.y-infoPtr->scrollPage.y;
    10288 
    10289   if (infoPtr->lefttop.x > maxX)
    10290     infoPtr->lefttop.x = maxX;
    10291 
    10292   if (infoPtr->lefttop.x < 0)
    10293     infoPtr->lefttop.x = 0;
    10294 
    10295   if (infoPtr->lefttop.y > maxY)
    10296     infoPtr->lefttop.y = maxY;
    10297 
    10298   if (infoPtr->lefttop.y < 0)
    10299     infoPtr->lefttop.y = 0;
    10300 
    10301   if ((oldlefttop.x != infoPtr->lefttop.x) || (oldlefttop.y != infoPtr->lefttop.y))
    10302   {
    10303     SCROLLINFO scrollInfo;
    10304     RECT rect;
    10305     INT xScroll = (oldlefttop.x-infoPtr->lefttop.x)*infoPtr->scrollStep.x;
    10306     INT yScroll = (oldlefttop.y-infoPtr->lefttop.y)*infoPtr->scrollStep.y;
    10307 
    10308     if (xScroll != 0)
    10309     {
    10310       ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
    10311       scrollInfo.cbSize = sizeof(SCROLLINFO);
    10312       scrollInfo.nPos   = infoPtr->lefttop.x;
    10313       scrollInfo.fMask  = SIF_POS;
    10314       SetScrollInfo(hwnd,SB_HORZ,&scrollInfo,TRUE);
    10315     }
    10316 
    10317     if (yScroll != 0)
    10318     {
    10319       ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
    10320       scrollInfo.cbSize = sizeof(SCROLLINFO);
    10321       scrollInfo.nPos   = infoPtr->lefttop.y;
    10322       scrollInfo.fMask  = SIF_POS;
    10323       SetScrollInfo(hwnd,SB_VERT,&scrollInfo,TRUE);
    10324     }
    10325 
    10326     LISTVIEW_ScrollWindow(hwnd,xScroll,yScroll);
    10327 
    10328     return TRUE;
    10329   }
    10330 
    10331   return FALSE;
    10332 }
    10333 
    10334 static LRESULT LISTVIEW_Timer(HWND hwnd,WPARAM wParam,LPARAM lParam)
    10335 {
    10336   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
    10337 
    10338   return DefWindowProcA(hwnd,WM_TIMER,wParam,lParam);
    10339 }
    10340 
    10341 static BOOL LISTVIEW_InternalHitTestItem(HWND hwnd,LISTVIEW_INFO *infoPtr, UINT uView, INT nItem,LPLVHITTESTINFO lpHitTestInfo,BOOL checkSubItems)
    10342 {
    10343   RECT rcItem;
    10344   INT  x;
    10345 
    10346   if (checkSubItems && (uView == LVS_REPORT))
    10347   {
    10348     INT nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
    10349     INT xDiff = -infoPtr->lefttop.x*infoPtr->scrollStep.x;
    10350 
    10351     rcItem.top = infoPtr->rcList.top+(nItem-LISTVIEW_GetTopIndex(hwnd))*infoPtr->nItemHeight;
    10352     rcItem.bottom = rcItem.top+infoPtr->nItemHeight;
    10353     for (x = 0;x < nColumnCount;x++)
    10354     {
    10355       RECT rcColumn;
    10356 
    10357       Header_GetItemRect(infoPtr->hwndHeader,(WPARAM)x,(LPARAM)&rcColumn);
    10358       rcItem.left = xDiff+REPORT_MARGINX+rcColumn.left;
    10359       rcItem.right = xDiff+rcColumn.right-REPORT_MARGINX;
    10360       if (PtInRect(&rcItem,lpHitTestInfo->pt))
    10361       {
    10362         rcItem.top = x;
    10363         rcItem.left = LVIR_BOUNDS;
    10364         if (LISTVIEW_GetSubItemRect(hwnd,nItem,&rcItem) && PtInRect(&rcItem,lpHitTestInfo->pt))
    10365         {
    10366           rcItem.top = x;
    10367           rcItem.left = LVIR_ICON;
    10368           if (LISTVIEW_GetSubItemRect(hwnd,nItem,&rcItem) && PtInRect(&rcItem,lpHitTestInfo->pt))
    10369           {
    10370             lpHitTestInfo->flags = LVHT_ONITEMICON;
    10371             lpHitTestInfo->iItem = nItem;
    10372             lpHitTestInfo->iSubItem = x;
    10373             return TRUE;
    10374           }
    10375 
    10376           lpHitTestInfo->flags = LVHT_ONITEMLABEL;
    10377           lpHitTestInfo->iItem = nItem;
    10378           lpHitTestInfo->iSubItem = x;
    10379 
    10380           return TRUE;
    10381         }
    10382       }
    10383     }
    10384     return FALSE;
    10385   }
    10386 
    10387   rcItem.left = LVIR_BOUNDS;
    10388   if (LISTVIEW_GetItemRect(hwnd,nItem,&rcItem))
    10389   {
    10390     if (PtInRect(&rcItem,lpHitTestInfo->pt))
    10391     {
    10392       rcItem.left = LVIR_ICON;
    10393       if (LISTVIEW_GetItemRect(hwnd,nItem,&rcItem) && PtInRect(&rcItem,lpHitTestInfo->pt))
    10394       {
    10395         lpHitTestInfo->flags = LVHT_ONITEMICON;
    10396         lpHitTestInfo->iItem = nItem;
    10397         lpHitTestInfo->iSubItem = 0;
    10398         return TRUE;
    10399       }
    10400 
    10401       rcItem.left = LVIR_LABEL;
    10402       if (LISTVIEW_GetItemRect(hwnd,nItem,&rcItem) && PtInRect(&rcItem,lpHitTestInfo->pt))
    10403       {
    10404         lpHitTestInfo->flags = LVHT_ONITEMLABEL;
    10405         lpHitTestInfo->iItem = nItem;
    10406         lpHitTestInfo->iSubItem = 0;
    10407         return TRUE;
    10408       }
    10409 
    10410       lpHitTestInfo->flags = LVHT_ONITEMSTATEICON;
    10411       lpHitTestInfo->iItem = nItem;
    10412       lpHitTestInfo->iSubItem = 0;
    10413       return TRUE;
    10414     }
    10415   }
    10416 
    10417   return FALSE;
    10418 }
    10419 
    10420 static LRESULT LISTVIEW_SubItemHitTest(HWND hwnd,LPLVHITTESTINFO lpHitTestInfo)
    10421 {
    10422   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
    10423   UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
    10424   INT nItem = -1;
    10425   INT nSubItem = -1;
    10426 
    10427   lpHitTestInfo->flags = 0;
    10428   if (uView != LVS_REPORT) return -1;
    10429 
    10430   if (infoPtr->rcList.left > lpHitTestInfo->pt.x)
    10431   {
    10432     lpHitTestInfo->flags = LVHT_TOLEFT;
    10433   } else if (infoPtr->rcList.right < lpHitTestInfo->pt.x)
    10434   {
    10435     lpHitTestInfo->flags = LVHT_TORIGHT;
    10436   }
    10437   if (infoPtr->rcList.top > lpHitTestInfo->pt.y)
    10438   {
    10439     lpHitTestInfo->flags |= LVHT_ABOVE;
    10440   } else if (infoPtr->rcList.bottom < lpHitTestInfo->pt.y)
    10441   {
    10442     lpHitTestInfo->flags |= LVHT_BELOW;
    10443   }
    10444 
    10445   if (lpHitTestInfo->flags == 0)
    10446   {
    10447     INT nTop = LISTVIEW_GetTopIndex(hwnd),nItem;
    10448 
    10449     nItem = nTop+((lpHitTestInfo->pt.y-infoPtr->rcList.top)/infoPtr->nItemHeight);
    10450     if (nItem >= GETITEMCOUNT(infoPtr)) return -1;
    10451 
    10452     if (LISTVIEW_InternalHitTestItem(hwnd,infoPtr,uView, nItem,lpHitTestInfo,TRUE))
    10453       return lpHitTestInfo->iSubItem;
    10454   }
    10455 
    10456   return nSubItem;
    10457 }
    10458 
    10459 #ifdef DEBUG
    10460 void dprintfMsg(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    10461 {
    10462  char *msg = NULL;
    104638500
    104648501  switch (uMsg)
    104658502  {
    104668503  case LVM_APPROXIMATEVIEWRECT:
    10467       msg = "LVM_APPROXIMATEVIEWRECT";
    10468       break;
     8504    return LISTVIEW_ApproximateViewRect(infoPtr, (INT)wParam,
     8505                                        LOWORD(lParam), HIWORD(lParam));
    104698506  case LVM_ARRANGE:
    10470       msg = "LVM_ARRANGE";
    10471       break;
    10472   case LVM_CREATEDRAGIMAGE:
    10473       msg = "LVM_CREATEDRAGIMAGE";
    10474       break;
     8507    return LISTVIEW_Arrange(infoPtr, (INT)wParam);
     8508
     8509/* case LVM_CANCELEDITLABEL: */
     8510
     8511/* case LVM_CREATEDRAGIMAGE: */
     8512
    104758513  case LVM_DELETEALLITEMS:
    10476       msg = "LVM_DELETEALLITEMS";
    10477       break;
     8514    return LISTVIEW_DeleteAllItems(infoPtr);
     8515
    104788516  case LVM_DELETECOLUMN:
    10479       msg = "LVM_DELETECOLUMN";
    10480       break;
     8517    return LISTVIEW_DeleteColumn(infoPtr, (INT)wParam);
     8518
    104818519  case LVM_DELETEITEM:
    10482       msg = "LVM_DELETEITEM";
    10483       break;
     8520    return LISTVIEW_DeleteItem(infoPtr, (INT)wParam);
     8521
    104848522  case LVM_EDITLABELW:
    10485       msg = "LVM_EDITLABELW";
    10486       break;
     8523    return (LRESULT)LISTVIEW_EditLabelT(infoPtr, (INT)wParam, TRUE);
     8524
    104878525  case LVM_EDITLABELA:
    10488       msg = "LVM_EDITLABELA";
    10489       break;
     8526    return (LRESULT)LISTVIEW_EditLabelT(infoPtr, (INT)wParam, FALSE);
     8527
     8528  /* case LVM_ENABLEGROUPVIEW: */
     8529
    104908530  case LVM_ENSUREVISIBLE:
    10491       msg = "LVM_ENSUREVISIBLE";
    10492       break;
     8531    return LISTVIEW_EnsureVisible(infoPtr, (INT)wParam, (BOOL)lParam);
     8532
     8533  case LVM_FINDITEMW:
     8534    return LISTVIEW_FindItemW(infoPtr, (INT)wParam, (LPLVFINDINFOW)lParam);
     8535
    104938536  case LVM_FINDITEMA:
    10494       msg = "LVM_FINDITEMA";
    10495       break;
     8537    return LISTVIEW_FindItemA(infoPtr, (INT)wParam, (LPLVFINDINFOA)lParam);
     8538
    104968539  case LVM_GETBKCOLOR:
    10497       msg = "LVM_GETBKCOLOR";
    10498       break;
    10499   case LVM_GETBKIMAGEA:
    10500       msg = "LVM_GETBKIMAGEA";
    10501       break;
    10502   case LVM_GETBKIMAGEW:
    10503       msg = "LVM_GETBKIMAGEW";
    10504       break;
     8540    return infoPtr->clrBk;
     8541
     8542  /* case LVM_GETBKIMAGE: */
     8543
    105058544  case LVM_GETCALLBACKMASK:
    10506       msg = "LVM_GETCALLBACKMASK";
    10507       break;
     8545    return infoPtr->uCallbackMask;
     8546
    105088547  case LVM_GETCOLUMNA:
    10509       msg = "LVM_GETCOLUMNA";
    10510       break;
     8548    return LISTVIEW_GetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, FALSE);
     8549
    105118550  case LVM_GETCOLUMNW:
    10512       msg = "LVM_GETCOLUMNW";
    10513       break;
     8551    return LISTVIEW_GetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, TRUE);
     8552
    105148553  case LVM_GETCOLUMNORDERARRAY:
    10515       msg = "LVM_GETCOLUMNORDERARRAY";
    10516       break;
     8554    return LISTVIEW_GetColumnOrderArray(infoPtr, (INT)wParam, (LPINT)lParam);
     8555
    105178556  case LVM_GETCOLUMNWIDTH:
    10518       msg = "LVM_GETCOLUMNWIDTH";
    10519       break;
     8557    return LISTVIEW_GetColumnWidth(infoPtr, (INT)wParam);
     8558
    105208559  case LVM_GETCOUNTPERPAGE:
    10521       msg = "LVM_GETCOUNTPERPAGE";
    10522       break;
     8560    return LISTVIEW_GetCountPerPage(infoPtr);
     8561
    105238562  case LVM_GETEDITCONTROL:
    10524       msg = "LVM_GETEDITCONTROL";
    10525       break;
     8563    return (LRESULT)infoPtr->hwndEdit;
     8564
    105268565  case LVM_GETEXTENDEDLISTVIEWSTYLE:
    10527       msg = "LVM_GETEXTENDEDLISTVIEWSTYLE";
    10528       break;
     8566    return infoPtr->dwLvExStyle;
     8567
     8568  /* case LVM_GETGROUPINFO: */
     8569
     8570  /* case LVM_GETGROUPMETRICS: */
     8571
    105298572  case LVM_GETHEADER:
    10530       msg = "LVM_GETHEADER";
    10531       break;
     8573    return (LRESULT)infoPtr->hwndHeader;
     8574
    105328575  case LVM_GETHOTCURSOR:
    10533       msg = "LVM_GETHOTCURSOR";
    10534       break;
     8576    return (LRESULT)infoPtr->hHotCursor;
     8577
    105358578  case LVM_GETHOTITEM:
    10536       msg = "LVM_GETHOTITEM";
    10537       break;
     8579    return infoPtr->nHotItem;
     8580
    105388581  case LVM_GETHOVERTIME:
    10539       msg = "LVM_GETHOVERTIME";
    10540       break;
     8582    return infoPtr->dwHoverTime;
     8583
    105418584  case LVM_GETIMAGELIST:
    10542       msg = "LVM_GETIMAGELIST";
    10543       break;
     8585    return (LRESULT)LISTVIEW_GetImageList(infoPtr, (INT)wParam);
     8586
     8587  /* case LVM_GETINSERTMARK: */
     8588
     8589  /* case LVM_GETINSERTMARKCOLOR: */
     8590
     8591  /* case LVM_GETINSERTMARKRECT: */
     8592
    105448593  case LVM_GETISEARCHSTRINGA:
    10545       msg = "LVM_GETISEARCHSTRINGA";
    10546       break;
    105478594  case LVM_GETISEARCHSTRINGW:
    10548       msg = "LVM_GETISEARCHSTRINGW";
    10549       break;
     8595    FIXME("LVM_GETISEARCHSTRING: unimplemented\n");
     8596    return FALSE;
     8597
    105508598  case LVM_GETITEMA:
    10551       msg = "LVM_GETITEMA";
    10552       break;
     8599    return LISTVIEW_GetItemExtT(infoPtr, (LPLVITEMW)lParam, FALSE);
     8600
    105538601  case LVM_GETITEMW:
    10554       msg = "LVM_GETITEMW";
    10555       break;
     8602    return LISTVIEW_GetItemExtT(infoPtr, (LPLVITEMW)lParam, TRUE);
     8603
    105568604  case LVM_GETITEMCOUNT:
    10557       msg = "LVM_GETITEMCOUNT";
    10558       break;
     8605    return infoPtr->nItemCount;
     8606
    105598607  case LVM_GETITEMPOSITION:
    10560       msg = "LVM_GETITEMPOSITION";
    10561       break;
     8608    return LISTVIEW_GetItemPosition(infoPtr, (INT)wParam, (LPPOINT)lParam);
     8609
    105628610  case LVM_GETITEMRECT:
    10563       msg = "LVM_GETITEMRECT";
    10564       break;
     8611    return LISTVIEW_GetItemRect(infoPtr, (INT)wParam, (LPRECT)lParam);
     8612
    105658613  case LVM_GETITEMSPACING:
    10566       msg = "LVM_GETITEMSPACING";
    10567       break;
     8614    return LISTVIEW_GetItemSpacing(infoPtr, (BOOL)wParam);
     8615
    105688616  case LVM_GETITEMSTATE:
    10569       msg = "LVM_GETITEMSTATE";
    10570       break;
     8617    return LISTVIEW_GetItemState(infoPtr, (INT)wParam, (UINT)lParam);
     8618
    105718619  case LVM_GETITEMTEXTA:
    10572       msg = "LVM_GETITEMTEXTA";
    10573       break;
     8620    return LISTVIEW_GetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam, FALSE);
     8621
    105748622  case LVM_GETITEMTEXTW:
    10575       msg = "LVM_GETITEMTEXTW";
    10576       break;
     8623    return LISTVIEW_GetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam, TRUE);
     8624
    105778625  case LVM_GETNEXTITEM:
    10578       msg = "LVM_GETNEXTITEM";
    10579       break;
     8626    return LISTVIEW_GetNextItem(infoPtr, (INT)wParam, LOWORD(lParam));
     8627
    105808628  case LVM_GETNUMBEROFWORKAREAS:
    10581       msg = "LVM_GETNUMBEROFWORKAREAS";
    10582       break;
     8629    FIXME("LVM_GETNUMBEROFWORKAREAS: unimplemented\n");
     8630    return 1;
     8631
    105838632  case LVM_GETORIGIN:
    10584       msg = "LVM_GETORIGIN";
    10585       break;
     8633    if (!lParam) return FALSE;
     8634    LISTVIEW_GetOrigin(infoPtr, (LPPOINT)lParam);
     8635    return TRUE;
     8636
     8637  /* case LVM_GETOUTLINECOLOR: */
     8638
     8639  /* case LVM_GETSELECTEDCOLUMN: */
     8640
    105868641  case LVM_GETSELECTEDCOUNT:
    10587       msg = "LVM_GETSELECTEDCOUNT";
    10588       break;
     8642    return LISTVIEW_GetSelectedCount(infoPtr);
     8643
    105898644  case LVM_GETSELECTIONMARK:
    10590       msg = "LVM_GETSELECTIONMARK";
    10591       break;
     8645    return infoPtr->nSelectionMark;
     8646
    105928647  case LVM_GETSTRINGWIDTHA:
    10593       msg = "LVM_GETSTRINGWIDTHA";
    10594       break;
     8648    return LISTVIEW_GetStringWidthT(infoPtr, (LPCWSTR)lParam, FALSE);
     8649
    105958650  case LVM_GETSTRINGWIDTHW:
    10596       msg = "LVM_GETSTRINGWIDTHW";
    10597       break;
     8651    return LISTVIEW_GetStringWidthT(infoPtr, (LPCWSTR)lParam, TRUE);
     8652
    105988653  case LVM_GETSUBITEMRECT:
    10599       msg = "LVM_GETSUBITEMRECT";
    10600       break;
     8654    return LISTVIEW_GetSubItemRect(infoPtr, (UINT)wParam, (LPRECT)lParam);
     8655
    106018656  case LVM_GETTEXTBKCOLOR:
    10602       msg = "LVM_GETTEXTBKCOLOR";
    10603       break;
     8657    return infoPtr->clrTextBk;
     8658
    106048659  case LVM_GETTEXTCOLOR:
    10605       msg = "LVM_GETTEXTCOLOR";
    10606       break;
     8660    return infoPtr->clrText;
     8661
     8662  /* case LVM_GETTILEINFO: */
     8663
     8664  /* case LVM_GETTILEVIEWINFO: */
     8665
    106078666  case LVM_GETTOOLTIPS:
    10608       msg = "LVM_GETTOOLTIPS";
    10609       break;
     8667    return (LRESULT)infoPtr->hwndToolTip;
     8668
    106108669  case LVM_GETTOPINDEX:
    10611       msg = "LVM_GETTOPINDEX";
    10612       break;
    10613   case LVM_GETVIEWRECT:
    10614       msg = "LVM_GETVIEWRECT";
    10615       break;
    10616   case LVM_GETWORKAREAS:
    10617       msg = "LVM_GETWORKAREAS";
    10618       break;
    10619   case LVM_HITTEST:
    10620       msg = "LVM_HITTEST";
    10621       break;
    10622   case LVM_INSERTCOLUMNA:
    10623       msg = "LVM_INSERTCOLUMNA";
    10624       break;
    10625   case LVM_INSERTCOLUMNW:
    10626       msg = "LVM_INSERTCOLUMNW";
    10627       break;
    10628   case LVM_INSERTITEMA:
    10629       msg = "LVM_INSERTITEMA";
    10630       break;
    10631   case LVM_INSERTITEMW:
    10632       msg = "LVM_INSERTITEMW";
    10633       break;
    10634   case LVM_REDRAWITEMS:
    10635       msg = "LVM_REDRAWITEMS";
    10636       break;
    10637   case LVM_SCROLL:
    10638       msg = "LVM_SCROLL";
    10639       break;
    10640   case LVM_SETBKCOLOR:
    10641       msg = "LVM_SETBKCOLOR";
    10642       break;
    10643   case LVM_SETBKIMAGEA:
    10644       msg = "LVM_SETBKIMAGEA";
    10645       break;
    10646   case LVM_SETBKIMAGEW:
    10647       msg = "LVM_SETBKIMAGEW";
    10648       break;
    10649   case LVM_SETCALLBACKMASK:
    10650       msg = "LVM_SETCALLBACKMASK";
    10651       break;
    10652   case LVM_SETCOLUMNA:
    10653       msg = "LVM_SETCOLUMNA";
    10654       break;
    10655   case LVM_SETCOLUMNW:
    10656       msg = "LVM_SETCOLUMNW";
    10657       break;
    10658   case LVM_SETCOLUMNORDERARRAY:
    10659       msg = "LVM_SETCOLUMNORDERARRAY";
    10660       break;
    10661   case LVM_SETCOLUMNWIDTH:
    10662       msg = "LVM_SETCOLUMNWIDTH";
    10663       break;
    10664   case LVM_SETEXTENDEDLISTVIEWSTYLE:
    10665       msg = "LVM_SETEXTENDEDLISTVIEWSTYLE";
    10666       break;
    10667   case LVM_SETHOTCURSOR:
    10668       msg = "LVM_SETHOTCURSOR";
    10669       break;
    10670   case LVM_SETHOTITEM:
    10671       msg = "LVM_SETHOTITEM";
    10672       break;
    10673   case LVM_SETHOVERTIME:
    10674       msg = "LVM_SETHOVERTIME";
    10675       break;
    10676   case LVM_SETICONSPACING:
    10677       msg = "LVM_SETICONSPACING";
    10678       break;
    10679   case LVM_SETIMAGELIST:
    10680       msg = "LVM_SETIMAGELIST";
    10681       break;
    10682   case LVM_SETITEMA:
    10683       msg = "LVM_SETITEMA";
    10684       break;
    10685   case LVM_SETITEMW:
    10686       msg = "LVM_SETITEMW";
    10687       break;
    10688   case LVM_SETITEMCOUNT:
    10689       msg = "LVM_SETITEMCOUNT";
    10690       break;
    10691   case LVM_SETITEMPOSITION:
    10692       msg = "LVM_SETITEMPOSITION";
    10693       break;
    10694   case LVM_SETITEMPOSITION32:
    10695       msg = "LVM_SETITEMPOSITION32";
    10696       break;
    10697   case LVM_SETITEMSTATE:
    10698       msg = "LVM_SETITEMSTATE";
    10699       break;
    10700   case LVM_SETITEMTEXTA:
    10701       msg = "LVM_SETITEMTEXTA";
    10702       break;
    10703   case LVM_SETITEMTEXTW:
    10704       msg = "LVM_SETITEMTEXTW";
    10705       break;
    10706   case LVM_SETSELECTIONMARK:
    10707       msg = "LVM_SETSELECTIONMARK";
    10708       break;
    10709   case LVM_SETTEXTBKCOLOR:
    10710       msg = "LVM_SETTEXTBKCOLOR";
    10711       break;
    10712   case LVM_SETTEXTCOLOR:
    10713       msg = "LVM_SETTEXTCOLOR";
    10714       break;
    10715   case LVM_SETTOOLTIPS:
    10716       msg = "LVM_SETTOOLTIPS";
    10717       break;
    10718   case LVM_SETWORKAREAS:
    10719       msg = "LVM_SETWORKAREAS";
    10720       break;
    10721   case LVM_SORTITEMS:
    10722       msg = "LVM_SORTITEMS";
    10723       break;
    10724   case LVM_SUBITEMHITTEST:
    10725       msg = "LVM_SUBITEMHITTEST";
    10726       break;
    10727   case LVM_UPDATE:
    10728       msg = "LVM_UPDATE";
    10729       break;
    10730   default:
    10731       return;
    10732   }
    10733   dprintf(("SysListView %x %s %x %x", hwnd, msg, wParam, lParam));
    10734 }
    10735 #endif
    10736 #endif //__WIN32OS2__
    10737 
    10738 /***
    10739  * DESCRIPTION:
    10740  * Window procedure of the listview control.
    10741  *
    10742  */
    10743 static LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
    10744                                    LPARAM lParam)
    10745 {
    10746 #if defined(DEBUG) && defined(__WIN32OS2__)
    10747   dprintfMsg(hwnd, uMsg, wParam, lParam);
    10748 #else
    10749   TRACE("hwnd=%x uMsg=%x wParam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam);
    10750 #endif
    10751   if (!GetWindowLongW(hwnd, 0) && (uMsg != WM_NCCREATE))
    10752     return DefWindowProcW( hwnd, uMsg, wParam, lParam );
    10753   switch (uMsg)
    10754   {
    10755   case LVM_APPROXIMATEVIEWRECT:
    10756     return LISTVIEW_ApproximateViewRect(hwnd, (INT)wParam,
    10757                                         LOWORD(lParam), HIWORD(lParam));
    10758   case LVM_ARRANGE:
    10759     return LISTVIEW_Arrange(hwnd, (INT)wParam);
    10760 
    10761 #ifdef __WIN32OS2__
    10762   case LVM_CREATEDRAGIMAGE:
    10763     return LISTVIEW_CreateDragImage(hwnd,wParam,lParam);
    10764 
    10765 #endif
    10766 
    10767 /* case LVM_CREATEDRAGIMAGE: */
    10768 
    10769   case LVM_DELETEALLITEMS:
    10770     return LISTVIEW_DeleteAllItems(hwnd);
    10771 
    10772   case LVM_DELETECOLUMN:
    10773     return LISTVIEW_DeleteColumn(hwnd, (INT)wParam);
    10774 
    10775   case LVM_DELETEITEM:
    10776     return LISTVIEW_DeleteItem(hwnd, (INT)wParam);
    10777 
    10778   case LVM_EDITLABELW:
    10779     return LISTVIEW_EditLabelT(hwnd, (INT)wParam, TRUE);
    10780    
    10781   case LVM_EDITLABELA:
    10782     return LISTVIEW_EditLabelT(hwnd, (INT)wParam, FALSE);
    10783 
    10784   case LVM_ENSUREVISIBLE:
    10785     return LISTVIEW_EnsureVisible(hwnd, (INT)wParam, (BOOL)lParam);
    10786 
    10787   case LVM_FINDITEMW:
    10788     return LISTVIEW_FindItemW(hwnd, (INT)wParam, (LPLVFINDINFOW)lParam);
    10789 
    10790   case LVM_FINDITEMA:
    10791     return LISTVIEW_FindItemA(hwnd, (INT)wParam, (LPLVFINDINFOA)lParam);
    10792 
    10793   case LVM_GETBKCOLOR:
    10794     return LISTVIEW_GetBkColor(hwnd);
    10795 
    10796 #ifdef __WIN32OS2__
    10797   case LVM_GETBKIMAGEA:
    10798     return LISTVIEW_GetBkImage(hwnd,wParam,lParam,FALSE);
    10799 
    10800   case LVM_GETBKIMAGEW:
    10801     return LISTVIEW_GetBkImage(hwnd,wParam,lParam,TRUE);
    10802 #endif
    10803 /*      case LVM_GETBKIMAGE: */
    10804 
    10805   case LVM_GETCALLBACKMASK:
    10806     return LISTVIEW_GetCallbackMask(hwnd);
    10807 
    10808   case LVM_GETCOLUMNA:
    10809     return LISTVIEW_GetColumnT(hwnd, (INT)wParam, (LPLVCOLUMNW)lParam, FALSE);
    10810 
    10811   case LVM_GETCOLUMNW:
    10812     return LISTVIEW_GetColumnT(hwnd, (INT)wParam, (LPLVCOLUMNW)lParam, TRUE);
    10813 
    10814   case LVM_GETCOLUMNORDERARRAY:
    10815     return LISTVIEW_GetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
    10816 
    10817   case LVM_GETCOLUMNWIDTH:
    10818     return LISTVIEW_GetColumnWidth(hwnd, (INT)wParam);
    10819 
    10820   case LVM_GETCOUNTPERPAGE:
    10821     return LISTVIEW_GetCountPerPage(hwnd);
    10822 
    10823   case LVM_GETEDITCONTROL:
    10824     return LISTVIEW_GetEditControl(hwnd);
    10825 
    10826   case LVM_GETEXTENDEDLISTVIEWSTYLE:
    10827     return LISTVIEW_GetExtendedListViewStyle(hwnd);
    10828 
    10829   case LVM_GETHEADER:
    10830     return LISTVIEW_GetHeader(hwnd);
    10831 
    10832 #ifdef __WIN32OS2__
    10833   case LVM_GETHOTCURSOR:
    10834     return LISTVIEW_GetHotCursor(hwnd,wParam,lParam);
    10835 #endif
    10836 
    10837   case LVM_GETHOTITEM:
    10838     return LISTVIEW_GetHotItem(hwnd);
    10839 
    10840   case LVM_GETHOVERTIME:
    10841     return LISTVIEW_GetHoverTime(hwnd);
    10842 
    10843   case LVM_GETIMAGELIST:
    10844     return LISTVIEW_GetImageList(hwnd, (INT)wParam);
    10845 
    10846 #ifdef __WIN32OS2__
    10847   case LVM_GETISEARCHSTRINGA:
    10848     return LISTVIEW_GetISearchString(hwnd,wParam,lParam,FALSE);
    10849 
    10850   case LVM_GETISEARCHSTRINGW:
    10851     return LISTVIEW_GetISearchString(hwnd,wParam,lParam,TRUE);
    10852 #endif
    10853 
    10854   case LVM_GETITEMA:
    10855     return LISTVIEW_GetItemT(hwnd, (LPLVITEMW)lParam, FALSE, FALSE);
    10856 
    10857   case LVM_GETITEMW:
    10858     return LISTVIEW_GetItemT(hwnd, (LPLVITEMW)lParam, FALSE, TRUE);
    10859 
    10860   case LVM_GETITEMCOUNT:
    10861     return LISTVIEW_GetItemCount(hwnd);
    10862 
    10863   case LVM_GETITEMPOSITION:
    10864     return LISTVIEW_GetItemPosition(hwnd, (INT)wParam, (LPPOINT)lParam);
    10865 
    10866   case LVM_GETITEMRECT:
    10867     return LISTVIEW_GetItemRect(hwnd, (INT)wParam, (LPRECT)lParam);
    10868 
    10869   case LVM_GETITEMSPACING:
    10870     return LISTVIEW_GetItemSpacing(hwnd, (BOOL)wParam);
    10871 
    10872   case LVM_GETITEMSTATE:
    10873     return LISTVIEW_GetItemState(hwnd, (INT)wParam, (UINT)lParam);
    10874    
    10875   case LVM_GETITEMTEXTA:
    10876     return LISTVIEW_GetItemTextT(hwnd, (INT)wParam, (LPLVITEMW)lParam, FALSE);
    10877 
    10878   case LVM_GETITEMTEXTW:
    10879     return LISTVIEW_GetItemTextT(hwnd, (INT)wParam, (LPLVITEMW)lParam, TRUE);
    10880 
    10881   case LVM_GETNEXTITEM:
    10882     return LISTVIEW_GetNextItem(hwnd, (INT)wParam, LOWORD(lParam));
    10883 
    10884 #ifdef __WIN32OS2__
    10885   case LVM_GETNUMBEROFWORKAREAS:
    10886     return LISTVIEW_GetNumberOfWorkAreas(hwnd,wParam,lParam);
    10887 #endif
    10888 
    10889   case LVM_GETORIGIN:
    10890     return LISTVIEW_GetOrigin(hwnd, (LPPOINT)lParam);
    10891 
    10892   case LVM_GETSELECTEDCOUNT:
    10893     return LISTVIEW_GetSelectedCount(hwnd);
    10894 
    10895   case LVM_GETSELECTIONMARK:
    10896     return LISTVIEW_GetSelectionMark(hwnd);
    10897 
    10898   case LVM_GETSTRINGWIDTHA:
    10899     return LISTVIEW_GetStringWidthT(hwnd, (LPCWSTR)lParam, FALSE);
    10900 
    10901   case LVM_GETSTRINGWIDTHW:
    10902     return LISTVIEW_GetStringWidthT(hwnd, (LPCWSTR)lParam, TRUE);
    10903 
    10904 #ifdef __WIN32OS2__
    10905   case LVM_GETSUBITEMRECT:
    10906       return LISTVIEW_GetSubItemRect(hwnd,(INT)wParam,(LPRECT)lParam);
    10907 #endif
    10908    
    10909   case LVM_GETTEXTBKCOLOR:
    10910     return LISTVIEW_GetTextBkColor(hwnd);
    10911 
    10912   case LVM_GETTEXTCOLOR:
    10913     return LISTVIEW_GetTextColor(hwnd);
    10914 
    10915 #ifdef __WIN32OS2__
    10916   case LVM_GETTOOLTIPS:
    10917     return LISTVIEW_GetToolTips(hwnd,wParam,lParam);
    10918 #endif
    10919 
    10920   case LVM_GETTOPINDEX:
    10921     return LISTVIEW_GetTopIndex(hwnd);
     8670    return LISTVIEW_GetTopIndex(infoPtr);
    109228671
    109238672  /*case LVM_GETUNICODEFORMAT:
     
    109258674    return FALSE;*/
    109268675
     8676  /* case LVM_GETVIEW: */
     8677
    109278678  case LVM_GETVIEWRECT:
    10928     return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam);
    10929 
    10930 #ifdef __WIN32OS2__
     8679    return LISTVIEW_GetViewRect(infoPtr, (LPRECT)lParam);
     8680
    109318681  case LVM_GETWORKAREAS:
    10932       return LISTVIEW_GetWorkAreas(hwnd,wParam,lParam);
    10933 #endif
     8682    FIXME("LVM_GETWORKAREAS: unimplemented\n");
     8683    return FALSE;
     8684
     8685  /* case LVM_HASGROUP: */
    109348686
    109358687  case LVM_HITTEST:
    10936     return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam);
     8688    return LISTVIEW_HitTest(infoPtr, (LPLVHITTESTINFO)lParam, FALSE, FALSE);
    109378689
    109388690  case LVM_INSERTCOLUMNA:
    10939     return LISTVIEW_InsertColumnT(hwnd, (INT)wParam, (LPLVCOLUMNW)lParam, FALSE);
     8691    return LISTVIEW_InsertColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, FALSE);
    109408692
    109418693  case LVM_INSERTCOLUMNW:
    10942     return LISTVIEW_InsertColumnT(hwnd, (INT)wParam, (LPLVCOLUMNW)lParam, TRUE);
     8694    return LISTVIEW_InsertColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, TRUE);
     8695
     8696  /* case LVM_INSERTGROUP: */
     8697
     8698  /* case LVM_INSERTGROUPSORTED: */
    109438699
    109448700  case LVM_INSERTITEMA:
    10945     return LISTVIEW_InsertItemT(hwnd, (LPLVITEMW)lParam, FALSE);
     8701    return LISTVIEW_InsertItemT(infoPtr, (LPLVITEMW)lParam, FALSE);
    109468702
    109478703  case LVM_INSERTITEMW:
    10948     return LISTVIEW_InsertItemT(hwnd, (LPLVITEMW)lParam, TRUE);
     8704    return LISTVIEW_InsertItemT(infoPtr, (LPLVITEMW)lParam, TRUE);
     8705
     8706  /* case LVM_INSERTMARKHITTEST: */
     8707
     8708  /* case LVM_ISGROUPVIEWENABLED: */
     8709
     8710  /* case LVM_MAPIDTOINDEX: */
     8711
     8712  /* case LVM_MAPINDEXTOID: */
     8713
     8714  /* case LVM_MOVEGROUP: */
     8715
     8716  /* case LVM_MOVEITEMTOGROUP: */
    109498717
    109508718  case LVM_REDRAWITEMS:
    10951     return LISTVIEW_RedrawItems(hwnd, (INT)wParam, (INT)lParam);
    10952 
    10953 #ifdef __WIN32OS2__
     8719    return LISTVIEW_RedrawItems(infoPtr, (INT)wParam, (INT)lParam);
     8720
     8721  /* case LVM_REMOVEALLGROUPS: */
     8722
     8723  /* case LVM_REMOVEGROUP: */
     8724
    109548725  case LVM_SCROLL:
    10955     return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam);
    10956 #endif
    10957 
    10958 /*   case LVM_SCROLL:  */
    10959 /*     return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); */
     8726    return LISTVIEW_Scroll(infoPtr, (INT)wParam, (INT)lParam);
    109608727
    109618728  case LVM_SETBKCOLOR:
    10962     return LISTVIEW_SetBkColor(hwnd, (COLORREF)lParam);
    10963 
    10964 /*      case LVM_SETBKIMAGE: */
    10965 
    10966 #ifdef __WIN32OS2__
    10967   case LVM_SETBKIMAGEA:
    10968     return LISTVIEW_SetBkImage(hwnd,wParam,lParam,FALSE);
    10969 
    10970   case LVM_SETBKIMAGEW:
    10971     return LISTVIEW_SetBkImage(hwnd,wParam,lParam,TRUE);
    10972 #endif
     8729    return LISTVIEW_SetBkColor(infoPtr, (COLORREF)lParam);
     8730
     8731  /* case LVM_SETBKIMAGE: */
    109738732
    109748733  case LVM_SETCALLBACKMASK:
    10975     return LISTVIEW_SetCallbackMask(hwnd, (UINT)wParam);
     8734    infoPtr->uCallbackMask = (UINT)wParam;
     8735    return TRUE;
    109768736
    109778737  case LVM_SETCOLUMNA:
    10978     return LISTVIEW_SetColumnT(hwnd, (INT)wParam, (LPLVCOLUMNW)lParam, FALSE);
     8738    return LISTVIEW_SetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, FALSE);
    109798739
    109808740  case LVM_SETCOLUMNW:
    10981     return LISTVIEW_SetColumnT(hwnd, (INT)wParam, (LPLVCOLUMNW)lParam, TRUE);
     8741    return LISTVIEW_SetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, TRUE);
    109828742
    109838743  case LVM_SETCOLUMNORDERARRAY:
    10984     return LISTVIEW_SetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
     8744    return LISTVIEW_SetColumnOrderArray(infoPtr, (INT)wParam, (LPINT)lParam);
    109858745
    109868746  case LVM_SETCOLUMNWIDTH:
    10987     return LISTVIEW_SetColumnWidth(hwnd, (INT)wParam, SLOWORD(lParam));
     8747    return LISTVIEW_SetColumnWidth(infoPtr, (INT)wParam, SLOWORD(lParam));
    109888748
    109898749  case LVM_SETEXTENDEDLISTVIEWSTYLE:
    10990     return LISTVIEW_SetExtendedListViewStyle(hwnd, (DWORD)wParam, (DWORD)lParam);
    10991 
    10992 #ifdef __WIN32OS2__
     8750    return LISTVIEW_SetExtendedListViewStyle(infoPtr, (DWORD)wParam, (DWORD)lParam);
     8751
     8752  /* case LVM_SETGROUPINFO: */
     8753
     8754  /* case LVM_SETGROUPMETRICS: */
     8755
    109938756  case LVM_SETHOTCURSOR:
    10994     return LISTVIEW_SetHotCursor(hwnd,wParam,lParam);
    10995 #endif
    10996 
    10997 /*      case LVM_SETHOTCURSOR: */
     8757    return (LRESULT)LISTVIEW_SetHotCursor(infoPtr, (HCURSOR)lParam);
    109988758
    109998759  case LVM_SETHOTITEM:
    11000     return LISTVIEW_SetHotItem(hwnd, (INT)wParam);
     8760    return LISTVIEW_SetHotItem(infoPtr, (INT)wParam);
    110018761
    110028762  case LVM_SETHOVERTIME:
    11003     return LISTVIEW_SetHoverTime(hwnd, (DWORD)wParam);
    11004 #ifdef __WIN32OS2__
     8763    return LISTVIEW_SetHoverTime(infoPtr, (DWORD)wParam);
     8764
    110058765  case LVM_SETICONSPACING:
    11006     return LISTVIEW_SetIconSpacing(hwnd,wParam,lParam);
    11007 #else
    11008   case LVM_SETICONSPACING:
    11009     return LISTVIEW_SetIconSpacing(hwnd, (DWORD)lParam);
    11010 #endif 
     8766    return LISTVIEW_SetIconSpacing(infoPtr, SLOWORD(lParam), SHIWORD(lParam));
     8767
    110118768  case LVM_SETIMAGELIST:
    11012     return (LRESULT)LISTVIEW_SetImageList(hwnd, (INT)wParam, (HIMAGELIST)lParam);
     8769    return (LRESULT)LISTVIEW_SetImageList(infoPtr, (INT)wParam, (HIMAGELIST)lParam);
     8770
     8771  /* case LVM_SETINFOTIP: */
     8772
     8773  /* case LVM_SETINSERTMARK: */
     8774
     8775  /* case LVM_SETINSERTMARKCOLOR: */
    110138776
    110148777  case LVM_SETITEMA:
    11015     return LISTVIEW_SetItemT(hwnd, (LPLVITEMW)lParam, FALSE);
     8778    return LISTVIEW_SetItemT(infoPtr, (LPLVITEMW)lParam, FALSE);
    110168779
    110178780  case LVM_SETITEMW:
    11018     return LISTVIEW_SetItemT(hwnd, (LPLVITEMW)lParam, TRUE);
    11019 
    11020   case LVM_SETITEMCOUNT: 
    11021     return LISTVIEW_SetItemCount(hwnd, (INT)wParam, (DWORD)lParam);
    11022    
     8781    return LISTVIEW_SetItemT(infoPtr, (LPLVITEMW)lParam, TRUE);
     8782
     8783  case LVM_SETITEMCOUNT:
     8784    return LISTVIEW_SetItemCount(infoPtr, (INT)wParam, (DWORD)lParam);
     8785
    110238786  case LVM_SETITEMPOSITION:
    11024     return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, (INT)LOWORD(lParam),
    11025                                     (INT)HIWORD(lParam));
     8787    {
     8788        POINT pt = { SLOWORD(lParam), SHIWORD(lParam) };
     8789        return LISTVIEW_SetItemPosition(infoPtr, (INT)wParam, pt);
     8790    }
    110268791
    110278792  case LVM_SETITEMPOSITION32:
    11028     return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, ((POINT*)lParam)->x,
    11029                                     ((POINT*)lParam)->y);
     8793    if (lParam == 0) return FALSE;
     8794    return LISTVIEW_SetItemPosition(infoPtr, (INT)wParam, *((POINT*)lParam));
    110308795
    110318796  case LVM_SETITEMSTATE:
    11032     return LISTVIEW_SetItemState(hwnd, (INT)wParam, (LPLVITEMW)lParam);
     8797    return LISTVIEW_SetItemState(infoPtr, (INT)wParam, (LPLVITEMW)lParam);
    110338798
    110348799  case LVM_SETITEMTEXTA:
    11035     return LISTVIEW_SetItemTextT(hwnd, (INT)wParam, (LPLVITEMW)lParam, FALSE);
     8800    return LISTVIEW_SetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam, FALSE);
    110368801
    110378802  case LVM_SETITEMTEXTW:
    11038     return LISTVIEW_SetItemTextT(hwnd, (INT)wParam, (LPLVITEMW)lParam, TRUE);
     8803    return LISTVIEW_SetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam, TRUE);
     8804
     8805  /* case LVM_SETOUTLINECOLOR: */
     8806
     8807  /* case LVM_SETSELECTEDCOLUMN: */
    110398808
    110408809  case LVM_SETSELECTIONMARK:
    11041     return LISTVIEW_SetSelectionMark(hwnd, (INT)lParam);
     8810    return LISTVIEW_SetSelectionMark(infoPtr, (INT)lParam);
    110428811
    110438812  case LVM_SETTEXTBKCOLOR:
    11044     return LISTVIEW_SetTextBkColor(hwnd, (COLORREF)lParam);
     8813    return LISTVIEW_SetTextBkColor(infoPtr, (COLORREF)lParam);
    110458814
    110468815  case LVM_SETTEXTCOLOR:
    11047     return LISTVIEW_SetTextColor(hwnd, (COLORREF)lParam);
    11048 
    11049 #ifdef __WIN32OS2__
     8816    return LISTVIEW_SetTextColor(infoPtr, (COLORREF)lParam);
     8817
     8818  /* case LVM_SETTILEINFO: */
     8819
     8820  /* case LVM_SETTILEVIEWINFO: */
     8821
     8822  /* case LVM_SETTILEWIDTH: */
     8823
    110508824  case LVM_SETTOOLTIPS:
    11051     return LISTVIEW_SetToolTips(hwnd,wParam,lParam);
    11052 
    11053   case LVM_SETWORKAREAS:
    11054     return LISTVIEW_SetWorkAreas(hwnd,wParam,lParam);
    11055 #endif
    11056 
    11057 /*      case LVM_SETTOOLTIPS: */
    11058 /*      case LVM_SETUNICODEFORMAT: */
    11059 /*      case LVM_SETWORKAREAS: */
     8825    return (LRESULT)LISTVIEW_SetToolTips(infoPtr, (HWND)lParam);
     8826
     8827  /* case LVM_SETUNICODEFORMAT: */
     8828
     8829  /* case LVM_SETVIEW: */
     8830
     8831  /* case LVM_SETWORKAREAS: */
     8832
     8833  /* case LVM_SORTGROUPS: */
    110608834
    110618835  case LVM_SORTITEMS:
    11062     return LISTVIEW_SortItems(hwnd, (PFNLVCOMPARE)lParam, (LPARAM)wParam);
    11063 
    11064 #ifdef __WIN32OS2__
     8836    return LISTVIEW_SortItems(infoPtr, (PFNLVCOMPARE)lParam, (LPARAM)wParam);
     8837
     8838  /* LVM_SORTITEMSEX: */
     8839
    110658840  case LVM_SUBITEMHITTEST:
    11066     return LISTVIEW_SubItemHitTest(hwnd,(LPLVHITTESTINFO)lParam);
    11067 #endif
    11068 
    11069 /*      case LVM_SUBITEMHITTEST: */
    11070 
    11071   case LVM_UPDATE:
    11072     return LISTVIEW_Update(hwnd, (INT)wParam);
     8841    return LISTVIEW_HitTest(infoPtr, (LPLVHITTESTINFO)lParam, TRUE, FALSE);
     8842
     8843  case LVM_UPDATE:
     8844    return LISTVIEW_Update(infoPtr, (INT)wParam);
    110738845
    110748846  case WM_CHAR:
    11075     return LISTVIEW_ProcessLetterKeys( hwnd, wParam, lParam );
     8847    return LISTVIEW_ProcessLetterKeys( infoPtr, wParam, lParam );
    110768848
    110778849  case WM_COMMAND:
    11078     return LISTVIEW_Command(hwnd, wParam, lParam);
     8850    return LISTVIEW_Command(infoPtr, wParam, lParam);
    110798851
    110808852  case WM_CREATE:
    110818853    return LISTVIEW_Create(hwnd, (LPCREATESTRUCTW)lParam);
    11082    
     8854
    110838855  case WM_ERASEBKGND:
    11084     return LISTVIEW_EraseBackground(hwnd, wParam, lParam);
     8856    return LISTVIEW_EraseBkgnd(infoPtr, (HDC)wParam);
    110858857
    110868858  case WM_GETDLGCODE:
     
    110888860
    110898861  case WM_GETFONT:
    11090     return LISTVIEW_GetFont(hwnd);
     8862    return (LRESULT)infoPtr->hFont;
    110918863
    110928864  case WM_HSCROLL:
    11093     return LISTVIEW_HScroll(hwnd, (INT)LOWORD(wParam),
    11094                             (INT)HIWORD(wParam), (HWND)lParam);
     8865    return LISTVIEW_HScroll(infoPtr, (INT)LOWORD(wParam), 0, (HWND)lParam);
    110958866
    110968867  case WM_KEYDOWN:
    11097     return LISTVIEW_KeyDown(hwnd, (INT)wParam, (LONG)lParam);
     8868    return LISTVIEW_KeyDown(infoPtr, (INT)wParam, (LONG)lParam);
    110988869
    110998870  case WM_KILLFOCUS:
    11100     return LISTVIEW_KillFocus(hwnd);
     8871    return LISTVIEW_KillFocus(infoPtr);
    111018872
    111028873  case WM_LBUTTONDBLCLK:
    11103     return LISTVIEW_LButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
    11104                                 HIWORD(lParam));
    11105    
     8874    return LISTVIEW_LButtonDblClk(infoPtr, (WORD)wParam, MAKEPOINTS(lParam));
     8875
    111068876  case WM_LBUTTONDOWN:
    11107     return LISTVIEW_LButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
    11108                                 HIWORD(lParam));
     8877    return LISTVIEW_LButtonDown(infoPtr, (WORD)wParam, MAKEPOINTS(lParam));
     8878
    111098879  case WM_LBUTTONUP:
    11110     return LISTVIEW_LButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
    11111                               HIWORD(lParam));
     8880    return LISTVIEW_LButtonUp(infoPtr, (WORD)wParam, MAKEPOINTS(lParam));
     8881
    111128882  case WM_MOUSEMOVE:
    11113     return LISTVIEW_MouseMove (hwnd, wParam, lParam);
     8883    return LISTVIEW_MouseMove (infoPtr, (WORD)wParam, MAKEPOINTS(lParam));
    111148884
    111158885  case WM_MOUSEHOVER:
    11116     return LISTVIEW_MouseHover(hwnd, wParam, lParam);
    11117 
    11118   case WM_NCCREATE:
    11119     return LISTVIEW_NCCreate(hwnd, wParam, lParam);
     8886    return LISTVIEW_MouseHover(infoPtr, (WORD)wParam, MAKEPOINTS(lParam));
    111208887
    111218888  case WM_NCDESTROY:
    11122     return LISTVIEW_NCDestroy(hwnd);
     8889    return LISTVIEW_NCDestroy(infoPtr);
    111238890
    111248891  case WM_NOTIFY:
    11125     return LISTVIEW_Notify(hwnd, (INT)wParam, (LPNMHDR)lParam);
     8892    if (lParam && ((LPNMHDR)lParam)->hwndFrom == infoPtr->hwndHeader)
     8893        return LISTVIEW_HeaderNotification(infoPtr, (LPNMHEADERW)lParam);
     8894    else return 0;
    111268895
    111278896  case WM_NOTIFYFORMAT:
    11128     return LISTVIEW_NotifyFormat(hwnd, (HWND)wParam, (INT)lParam);
    11129 
    11130   case WM_PAINT: 
    11131     return LISTVIEW_Paint(hwnd, (HDC)wParam);
     8897    return LISTVIEW_NotifyFormat(infoPtr, (HWND)wParam, (INT)lParam);
     8898
     8899  case WM_PAINT:
     8900    return LISTVIEW_Paint(infoPtr, (HDC)wParam);
    111328901
    111338902  case WM_RBUTTONDBLCLK:
    11134     return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
    11135                                   HIWORD(lParam));
     8903    return LISTVIEW_RButtonDblClk(infoPtr, (WORD)wParam, MAKEPOINTS(lParam));
    111368904
    111378905  case WM_RBUTTONDOWN:
    11138     return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
    11139                                 HIWORD(lParam));
     8906    return LISTVIEW_RButtonDown(infoPtr, (WORD)wParam, MAKEPOINTS(lParam));
    111408907
    111418908  case WM_RBUTTONUP:
    11142     return LISTVIEW_RButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
    11143                               HIWORD(lParam));
     8909    return LISTVIEW_RButtonUp(infoPtr, (WORD)wParam, MAKEPOINTS(lParam));
     8910
     8911  case WM_SETCURSOR:
     8912    if(LISTVIEW_SetCursor(infoPtr, (HWND)wParam, LOWORD(lParam), HIWORD(lParam)))
     8913      return TRUE;
     8914    goto fwd_msg;
    111448915
    111458916  case WM_SETFOCUS:
    11146     return LISTVIEW_SetFocus(hwnd, (HWND)wParam);
     8917    return LISTVIEW_SetFocus(infoPtr, (HWND)wParam);
    111478918
    111488919  case WM_SETFONT:
    11149     return LISTVIEW_SetFont(hwnd, (HFONT)wParam, (WORD)lParam);
    11150 
    11151   case WM_SETREDRAW: 
    11152     return LISTVIEW_SetRedraw(hwnd, (BOOL)wParam);
     8920    return LISTVIEW_SetFont(infoPtr, (HFONT)wParam, (WORD)lParam);
     8921
     8922  case WM_SETREDRAW:
     8923    return LISTVIEW_SetRedraw(infoPtr, (BOOL)wParam);
    111538924
    111548925  case WM_SIZE:
    11155     return LISTVIEW_Size(hwnd, (int)SLOWORD(lParam), (int)SHIWORD(lParam));
     8926    return LISTVIEW_Size(infoPtr, (int)SLOWORD(lParam), (int)SHIWORD(lParam));
    111568927
    111578928  case WM_STYLECHANGED:
    11158     return LISTVIEW_StyleChanged(hwnd, wParam, (LPSTYLESTRUCT)lParam);
    11159 
    11160 #ifdef __WIN32OS2__
    11161   case WM_TIMER:
    11162     return LISTVIEW_Timer(hwnd,wParam,lParam);
    11163 #endif
     8929    return LISTVIEW_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam);
     8930
     8931  case WM_SYSCOLORCHANGE:
     8932    COMCTL32_RefreshSysColors();
     8933    return 0;
    111648934
    111658935/*      case WM_TIMER: */
    111668936
    111678937  case WM_VSCROLL:
    11168     return LISTVIEW_VScroll(hwnd, (INT)LOWORD(wParam),
    11169                             (INT)HIWORD(wParam), (HWND)lParam);
     8938    return LISTVIEW_VScroll(infoPtr, (INT)LOWORD(wParam), 0, (HWND)lParam);
    111708939
    111718940  case WM_MOUSEWHEEL:
    111728941      if (wParam & (MK_SHIFT | MK_CONTROL))
    11173           return DefWindowProcW( hwnd, uMsg, wParam, lParam );
    11174       return LISTVIEW_MouseWheel(hwnd, (short int)HIWORD(wParam));/*    case WM_WINDOWPOSCHANGED: */
     8942          return DefWindowProcW(hwnd, uMsg, wParam, lParam);
     8943      return LISTVIEW_MouseWheel(infoPtr, (short int)HIWORD(wParam));
     8944
     8945  case WM_WINDOWPOSCHANGED:
     8946      if (!(((WINDOWPOS *)lParam)->flags & SWP_NOSIZE))
     8947      {
     8948          SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE |
     8949                       SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE);
     8950          LISTVIEW_UpdateSize(infoPtr);
     8951          LISTVIEW_UpdateScroll(infoPtr);
     8952      }
     8953      return DefWindowProcW(hwnd, uMsg, wParam, lParam);
    111758954
    111768955/*      case WM_WININICHANGE: */
    111778956
    111788957  default:
    11179     if (uMsg >= WM_USER)
    11180     {
    11181       ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam,
    11182           lParam);
    11183     }
    11184 #ifdef __WIN32OS2__
    11185     return defComCtl32ProcA (hwnd, uMsg, wParam, lParam);
    11186 #else
    11187     return DefWindowProcA(hwnd, uMsg, wParam, lParam);
    11188 #endif
     8958    if ((uMsg >= WM_USER) && (uMsg < WM_APP))
     8959      ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam, lParam);
     8960
     8961  fwd_msg:
     8962    /* call default window procedure */
     8963    return DefWindowProcW(hwnd, uMsg, wParam, lParam);
    111898964  }
    111908965
     
    111958970 * DESCRIPTION:
    111968971 * Registers the window class.
    11197  * 
     8972 *
    111988973 * PARAMETER(S):
    111998974 * None
     
    112028977 * None
    112038978 */
    11204 VOID LISTVIEW_Register(void)
    11205 {
    11206   WNDCLASSW wndClass;
     8979void LISTVIEW_Register(void)
     8980{
     8981    WNDCLASSW wndClass;
    112078982
    112088983    ZeroMemory(&wndClass, sizeof(WNDCLASSW));
     
    112208995 * DESCRIPTION:
    112218996 * Unregisters the window class.
    11222  * 
     8997 *
    112238998 * PARAMETER(S):
    112248999 * None
     
    112279002 * None
    112289003 */
    11229 VOID LISTVIEW_Unregister(void)
    11230 {
    11231     UnregisterClassW(WC_LISTVIEWW, (HINSTANCE)NULL);
     9004void LISTVIEW_Unregister(void)
     9005{
     9006    UnregisterClassW(WC_LISTVIEWW, NULL);
    112329007}
    112339008
     
    112359010 * DESCRIPTION:
    112369011 * Handle any WM_COMMAND messages
    11237  *
    11238  * PARAMETER(S):
    11239  *
    11240  * RETURN:
    11241  */
    11242 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam)
     9012 *
     9013 * PARAMETER(S):
     9014 * [I] infoPtr : valid pointer to the listview structure
     9015 * [I] wParam : the first message parameter
     9016 * [I] lParam : the second message parameter
     9017 *
     9018 * RETURN:
     9019 *   Zero.
     9020 */
     9021static LRESULT LISTVIEW_Command(LISTVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
    112439022{
    112449023    switch (HIWORD(wParam))
     
    112469025        case EN_UPDATE:
    112479026        {
    11248             /* 
    11249              * Adjust the edit window size 
     9027            /*
     9028             * Adjust the edit window size
    112509029             */
    112519030            WCHAR buffer[1024];
    11252             LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
    11253             HDC           hdc      = GetDC(infoPtr->hwndEdit);
     9031            HDC           hdc = GetDC(infoPtr->hwndEdit);
    112549032            HFONT         hFont, hOldFont = 0;
    112559033            RECT          rect;
     
    112579035            int           len;
    112589036
     9037            if (!infoPtr->hwndEdit || !hdc) return 0;
    112599038            len = GetWindowTextW(infoPtr->hwndEdit, buffer, sizeof(buffer)/sizeof(buffer[0]));
    112609039            GetWindowRect(infoPtr->hwndEdit, &rect);
    112619040
    112629041            /* Select font to get the right dimension of the string */
    11263             hFont = SendMessageW(infoPtr->hwndEdit, WM_GETFONT, 0, 0);
     9042            hFont = (HFONT)SendMessageW(infoPtr->hwndEdit, WM_GETFONT, 0, 0);
    112649043            if(hFont != 0)
    112659044            {
     
    112759054                sz.cx += (textMetric.tmMaxCharWidth * 2);
    112769055
    11277                 SetWindowPos ( 
     9056                SetWindowPos (
    112789057                    infoPtr->hwndEdit,
    11279                     HWND_TOP, 
    11280                     0, 
     9058                    HWND_TOP,
     9059                    0,
    112819060                    0,
    112829061                    sz.cx,
     
    112879066                SelectObject(hdc, hOldFont);
    112889067
    11289             ReleaseDC(hwnd, hdc);
     9068            ReleaseDC(infoPtr->hwndSelf, hdc);
    112909069
    112919070            break;
     
    112939072
    112949073        default:
    11295           return SendMessageW (GetParent (hwnd), WM_COMMAND, wParam, lParam);
     9074          return SendMessageW (GetParent (infoPtr->hwndSelf), WM_COMMAND, wParam, lParam);
    112969075    }
    112979076
     
    113059084 *
    113069085 * PARAMETER(S):
    11307  *
    11308  * RETURN:
    11309  */
    11310 static LRESULT EditLblWndProcT(HWND hwnd, UINT uMsg,
    11311         WPARAM wParam, LPARAM lParam, BOOL isW)
     9086 * [I] hwnd : the edit window handle
     9087 * [I] uMsg : the message that is to be processed
     9088 * [I] wParam : first message parameter
     9089 * [I] lParam : second message parameter
     9090 * [I] isW : TRUE if input is Unicode
     9091 *
     9092 * RETURN:
     9093 *   Zero.
     9094 */
     9095static LRESULT EditLblWndProcT(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL isW)
    113129096{
    113139097    LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(GetParent(hwnd), 0);
    11314     EDITLABEL_ITEM *einfo = infoPtr->pedititem;
    11315     static BOOL bIgnoreKillFocus = FALSE;
    113169098    BOOL cancel = FALSE;
    113179099
    11318     TRACE("(hwnd=%x, uMsg=%x, wParam=%x, lParam=%lx, isW=%d)\n",
     9100    TRACE("(hwnd=%p, uMsg=%x, wParam=%x, lParam=%lx, isW=%d)\n",
    113199101          hwnd, uMsg, wParam, lParam, isW);
    11320    
     9102
    113219103    switch (uMsg)
    113229104    {
    113239105        case WM_GETDLGCODE:
    113249106          return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
    11325                        
     9107
    113269108        case WM_KILLFOCUS:
    11327             if(bIgnoreKillFocus) return TRUE;
    113289109            break;
    113299110
    113309111        case WM_DESTROY:
    113319112        {
    11332             WNDPROC editProc = einfo->EditWndProc;
     9113            WNDPROC editProc = infoPtr->EditWndProc;
     9114            infoPtr->EditWndProc = 0;
    113339115            SetWindowLongW(hwnd, GWL_WNDPROC, (LONG)editProc);
    11334             COMCTL32_Free(einfo);
    11335             infoPtr->pedititem = NULL;
    113369116            return CallWindowProcT(editProc, hwnd, uMsg, wParam, lParam, isW);
    113379117        }
     
    113479127
    113489128        default:
    11349             return CallWindowProcT(einfo->EditWndProc, hwnd, uMsg, wParam, lParam, isW);
    11350     }
    11351 
    11352     if (einfo->EditLblCb)
     9129            return CallWindowProcT(infoPtr->EditWndProc, hwnd, uMsg, wParam, lParam, isW);
     9130    }
     9131
     9132    /* kill the edit */
     9133    if (infoPtr->hwndEdit)
    113539134    {
    113549135        LPWSTR buffer = NULL;
    11355        
     9136
     9137        infoPtr->hwndEdit = 0;
    113569138        if (!cancel)
    113579139        {
     
    113679149            }
    113689150        }
    11369         /* Processing LVN_ENDLABELEDIT message could kill the focus       */
    11370         /* eg. Using a messagebox                                         */
    11371         bIgnoreKillFocus = TRUE;
    11372         einfo->EditLblCb(GetParent(hwnd), buffer, einfo->param);
     9151        LISTVIEW_EndEditLabelT(infoPtr, buffer, isW);
    113739152
    113749153        if (buffer) COMCTL32_Free(buffer);
    113759154
    11376         einfo->EditLblCb = NULL;
    11377         bIgnoreKillFocus = FALSE;
    113789155    }
    113799156
    113809157    SendMessageW(hwnd, WM_CLOSE, 0, 0);
    11381     return TRUE;
    11382 }
    11383 
    11384 /***
    11385  * DESCRIPTION:
    11386  * Subclassed edit control windproc function
    11387  *
    11388  * PARAMETER(S):
     9158    return 0;
     9159}
     9160
     9161/***
     9162 * DESCRIPTION:
     9163 * Subclassed edit control Unicode windproc function
     9164 *
     9165 * PARAMETER(S):
     9166 * [I] hwnd : the edit window handle
     9167 * [I] uMsg : the message that is to be processed
     9168 * [I] wParam : first message parameter
     9169 * [I] lParam : second message parameter
    113899170 *
    113909171 * RETURN:
     
    113979178/***
    113989179 * DESCRIPTION:
    11399  * Subclassed edit control windproc function
    11400  *
    11401  * PARAMETER(S):
     9180 * Subclassed edit control ANSI windproc function
     9181 *
     9182 * PARAMETER(S):
     9183 * [I] hwnd : the edit window handle
     9184 * [I] uMsg : the message that is to be processed
     9185 * [I] wParam : first message parameter
     9186 * [I] lParam : second message parameter
    114029187 *
    114039188 * RETURN:
     
    114139198 *
    114149199 * PARAMETER(S):
    11415  *
    11416  * RETURN:
    11417  */
    11418 HWND CreateEditLabelT(LPCWSTR text, DWORD style, INT x, INT y,
    11419         INT width, INT height, HWND parent, HINSTANCE hinst,
    11420         EditlblCallbackW EditLblCb, DWORD param, BOOL isW)
    11421 {
    11422     LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(parent, 0);
     9200 * [I] infoPtr : valid pointer to the listview structure
     9201 * [I] text : initial text for the edit
     9202 * [I] style : the window style
     9203 * [I] isW : TRUE if input is Unicode
     9204 *
     9205 * RETURN:
     9206 */
     9207static HWND CreateEditLabelT(LISTVIEW_INFO *infoPtr, LPCWSTR text, DWORD style,
     9208        INT x, INT y, INT width, INT height, BOOL isW)
     9209{
    114239210    WCHAR editName[5] = { 'E', 'd', 'i', 't', '\0' };
    114249211    HWND hedit;
     
    114279214    HDC hOldFont=0;
    114289215    TEXTMETRICW textMetric;
    11429 
    11430     TRACE("(text=%s, ..., isW=%d)\n", debugstr_t(text, isW), isW);
    11431    
    11432     if (NULL == (infoPtr->pedititem = COMCTL32_Alloc(sizeof(EDITLABEL_ITEM))))
    11433         return 0;
     9216    HINSTANCE hinst = (HINSTANCE)GetWindowLongW(infoPtr->hwndSelf, GWL_HINSTANCE);
     9217
     9218    TRACE("(text=%s, ..., isW=%d)\n", debugtext_t(text, isW), isW);
    114349219
    114359220    style |= WS_CHILDWINDOW|WS_CLIPSIBLINGS|ES_LEFT|WS_BORDER;
    11436     hdc = GetDC(parent);
     9221    hdc = GetDC(infoPtr->hwndSelf);
    114379222
    114389223    /* Select the font to get appropriate metric dimensions */
     
    114509235        SelectObject(hdc, hOldFont);
    114519236
    11452     ReleaseDC(parent, hdc);
    11453     if (isW) 
    11454         hedit = CreateWindowW(editName, text, style, x, y, sz.cx, height, parent, 0, hinst, 0);
     9237    ReleaseDC(infoPtr->hwndSelf, hdc);
     9238    if (isW)
     9239        hedit = CreateWindowW(editName, text, style, x, y, sz.cx, height, infoPtr->hwndSelf, 0, hinst, 0);
    114559240    else
    11456         hedit = CreateWindowA("Edit", (LPCSTR)text, style, x, y, sz.cx, height, parent, 0, hinst, 0);
    11457 
    11458     if (!hedit)
    11459     {
    11460         COMCTL32_Free(infoPtr->pedititem);
    11461         return 0;
    11462     }
    11463 
    11464     infoPtr->pedititem->param = param;
    11465     infoPtr->pedititem->EditLblCb = EditLblCb;
    11466     infoPtr->pedititem->EditWndProc = (WNDPROC)
     9241        hedit = CreateWindowA("Edit", (LPCSTR)text, style, x, y, sz.cx, height, infoPtr->hwndSelf, 0, hinst, 0);
     9242
     9243    if (!hedit) return 0;
     9244
     9245    infoPtr->EditWndProc = (WNDPROC)
    114679246        (isW ? SetWindowLongW(hedit, GWL_WNDPROC, (LONG)EditLblWndProcW) :
    114689247               SetWindowLongA(hedit, GWL_WNDPROC, (LONG)EditLblWndProcA) );
    114699248
    11470     SendMessageW(hedit, WM_SETFONT, infoPtr->hFont, FALSE);
     9249    SendMessageW(hedit, WM_SETFONT, (WPARAM)infoPtr->hFont, FALSE);
    114719250
    114729251    return hedit;
    114739252}
    11474 
Note: See TracChangeset for help on using the changeset viewer.