Changeset 10097 for trunk/src/comctl32/listview.c
- Timestamp:
- May 15, 2003, 4:25:14 PM (22 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/comctl32/listview.c
r9370 r10097 23 23 * 24 24 * 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 * 27 33 * 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 * 32 97 * 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 50 139 * 51 140 * Known differences in message stream from native control (not known if … … 53 142 * LVM_INSERTITEM issues LVM_SETITEMSTATE and LVM_SETITEM in certain cases. 54 143 * 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 and57 * does *not* invoke DefWindowProc58 144 * WM_CREATE does not issue WM_QUERYUISTATE and associated registry 59 145 * processing for "USEDOUBLECLICKTIME". 60 146 */ 61 147 148 #include "config.h" 149 #include "wine/port.h" 150 151 #include <assert.h> 62 152 #include <ctype.h> 63 153 #include <string.h> … … 67 157 #include "winbase.h" 68 158 #include "winnt.h" 69 #include "heap.h"70 159 #include "commctrl.h" 160 #include "comctl32.h" 161 71 162 #include "wine/debug.h" 163 #include "wine/unicode.h" 72 164 73 165 WINE_DEFAULT_DEBUG_CHANNEL(listview); 74 166 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 170 typedef struct tagCOLUMN_INFO 171 { 172 RECT rcHeader; /* tracks the header's rectangle */ 173 int fmt; /* same as LVCOLUMN.fmt */ 174 } COLUMN_INFO; 175 176 typedef struct tagITEMHDR 110 177 { 111 178 LPWSTR pszText; 112 179 INT iImage; 180 } ITEMHDR, *LPITEMHDR; 181 182 typedef struct tagSUBITEM_INFO 183 { 184 ITEMHDR hdr; 113 185 INT iSubItem; 114 } LISTVIEW_SUBITEM; 115 116 typedef struct tagLISTVIEW_ITEM 117 { 186 } SUBITEM_INFO; 187 188 typedef struct tagITEM_INFO 189 { 190 ITEMHDR hdr; 118 191 UINT state; 119 LPWSTR pszText;120 INT iImage;121 192 LPARAM lParam; 122 193 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 196 typedef struct tagRANGE 197 { 198 INT lower; 199 INT upper; 200 } RANGE; 201 202 typedef struct tagRANGES 203 { 204 HDPA hdpa; 205 } *RANGES; 206 207 typedef struct tagITERATOR 208 { 209 INT nItem; 210 INT nSpecial; 211 RANGE range; 212 RANGES ranges; 213 INT index; 214 } ITERATOR; 132 215 133 216 typedef struct tagLISTVIEW_INFO 134 217 { 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 units145 POINT maxScroll; //in scroll units146 POINT scrollPage; //in scroll units147 POINT scrollStep; //in pixels148 DWORD internalFlags;149 BOOL bDragInProcess;150 #endif151 218 HWND hwndSelf; 219 HBRUSH hBkBrush; 152 220 COLORREF clrBk; 153 221 COLORREF clrText; 154 222 COLORREF clrTextBk; 223 COLORREF clrTextBkDefault; 155 224 HIMAGELIST himlNormal; 156 225 HIMAGELIST himlSmall; … … 158 227 BOOL bLButtonDown; 159 228 BOOL bRButtonDown; 160 INT nFocusedItem; 161 HDPA hdpaSelectionRanges; 229 BOOL bNoItemMetrics; /* flags if item metrics are not yet computed */ 162 230 INT nItemHeight; 163 231 INT nItemWidth; 232 RANGES selectionRanges; 164 233 INT nSelectionMark; 165 234 INT nHotItem; 166 235 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 */ 169 242 SIZE iconSize; 170 243 SIZE iconSpacing; 244 SIZE iconStateSize; 171 245 UINT uCallbackMask; 172 246 HWND hwndHeader; 247 HCURSOR hHotCursor; 173 248 HFONT hDefaultFont; 174 249 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 */ 177 255 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 */ 180 267 PFNLVCOMPARE pfnCompare; 181 268 LPARAM lParamSort; 182 269 HWND hwndEdit; 270 WNDPROC EditWndProc; 183 271 INT nEditLabelItem; 184 EDITLABEL_ITEM *pedititem;185 272 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; 192 280 } LISTVIEW_INFO; 193 281 194 282 /* 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 197 292 198 293 /* maximum size of a label */ … … 214 309 * ICON_TOP_PADDING - sum of the two above. 215 310 * 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 217 316 */ 218 317 #define ICON_TOP_PADDING_NOTHITABLE 2 219 318 #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) 223 325 224 326 /* default label width for items in list and small icon display modes */ … … 226 328 227 329 /* default column width for items in list display mode */ 228 #define DEFAULT_COLUMN_WIDTH 96229 230 /* Increment size of the horizontal scroll bar*/231 #define LISTVIEW_SCROLL_ DIV_SIZE 10330 #define DEFAULT_COLUMN_WIDTH 128 331 332 /* Size of "line" scroll for V & H scrolls */ 333 #define LISTVIEW_SCROLL_ICON_LINE_SIZE 37 232 334 233 335 /* Padding betwen image and label */ … … 235 337 236 338 /* Padding behind the label */ 237 #define TRAILING_PADDING 5 339 #define TRAILING_LABEL_PADDING 12 340 #define TRAILING_HEADER_PADDING 11 238 341 239 342 /* Border for the icon caption */ 240 343 #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 */ 309 351 #define KEY_DELAY 450 310 352 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 */ 370 static BOOL LISTVIEW_GetItemT(LISTVIEW_INFO *, LPLVITEMW, BOOL); 371 static void LISTVIEW_GetItemBox(LISTVIEW_INFO *, INT, LPRECT); 372 static void LISTVIEW_GetItemOrigin(LISTVIEW_INFO *, INT, LPPOINT); 373 static BOOL LISTVIEW_GetItemPosition(LISTVIEW_INFO *, INT, LPPOINT); 374 static BOOL LISTVIEW_GetItemRect(LISTVIEW_INFO *, INT, LPRECT); 375 static INT LISTVIEW_GetLabelWidth(LISTVIEW_INFO *, INT); 376 static void LISTVIEW_GetOrigin(LISTVIEW_INFO *, LPPOINT); 377 static BOOL LISTVIEW_GetViewRect(LISTVIEW_INFO *, LPRECT); 378 static void LISTVIEW_SetGroupSelection(LISTVIEW_INFO *, INT); 379 static BOOL LISTVIEW_SetItemT(LISTVIEW_INFO *, const LVITEMW *, BOOL); 380 static void LISTVIEW_UpdateScroll(LISTVIEW_INFO *); 381 static void LISTVIEW_SetSelection(LISTVIEW_INFO *, INT); 382 static void LISTVIEW_UpdateSize(LISTVIEW_INFO *); 383 static HWND LISTVIEW_EditLabelT(LISTVIEW_INFO *, INT, BOOL); 384 static LRESULT LISTVIEW_Command(LISTVIEW_INFO *, WPARAM, LPARAM); 385 static BOOL LISTVIEW_SortItems(LISTVIEW_INFO *, PFNLVCOMPARE, LPARAM); 386 static INT LISTVIEW_GetStringWidthT(LISTVIEW_INFO *, LPCWSTR, BOOL); 387 static BOOL LISTVIEW_KeySelection(LISTVIEW_INFO *, INT); 388 static UINT LISTVIEW_GetItemState(LISTVIEW_INFO *, INT, UINT); 389 static BOOL LISTVIEW_SetItemState(LISTVIEW_INFO *, INT, const LVITEMW *); 390 static LRESULT LISTVIEW_VScroll(LISTVIEW_INFO *, INT, INT, HWND); 391 static LRESULT LISTVIEW_HScroll(LISTVIEW_INFO *, INT, INT, HWND); 392 static INT LISTVIEW_GetTopIndex(LISTVIEW_INFO *); 393 static BOOL LISTVIEW_EnsureVisible(LISTVIEW_INFO *, INT, BOOL); 394 static 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 */ 312 405 313 406 static inline BOOL is_textW(LPCWSTR text) 314 407 { 315 return text != NULL && text != LPSTR_TEXTCALLBACKW;408 return text != NULL && text != LPSTR_TEXTCALLBACKW; 316 409 } 317 410 318 411 static inline BOOL is_textT(LPCWSTR text, BOOL isW) 319 412 { 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); 322 415 } 323 416 324 417 static inline int textlenT(LPCWSTR text, BOOL isW) 325 418 { 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); 328 421 } 329 422 330 423 static inline void textcpynT(LPWSTR dest, BOOL isDestW, LPCWSTR src, BOOL isSrcW, INT max) 331 424 { 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); 348 431 } 349 432 350 433 static inline LPWSTR textdupTtoW(LPCWSTR text, BOOL isW) 351 434 { 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; 363 445 } 364 446 365 447 static inline void textfreeT(LPWSTR wstr, BOOL isW) 366 448 { 367 if (!isW && wstr) HeapFree(GetProcessHeap(), 0, wstr);449 if (!isW && is_textT(wstr, isW)) HeapFree(GetProcessHeap(), 0, wstr); 368 450 } 369 451 … … 372 454 * src is a pointer to a string (Unicode if isW, ANSI if !isW) 373 455 */ 374 static inline BOOL textsetptrT(LPWSTR *dest, LPWSTR src, BOOL isW) 375 { 376 LPWSTR pszText = textdupTtoW(src, isW); 456 static BOOL textsetptrT(LPWSTR *dest, LPWSTR src, BOOL isW) 457 { 377 458 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 } 381 472 return bResult; 382 473 } 383 474 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 */ 478 static 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 495 static 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 521 static 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 527 static 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 534 static 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 541 static 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 551 static 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 561 static 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 572 static 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; 597 end: 598 buf = text + strlen(text); 599 undo: 600 if (buf - text > 2) { buf[-2] = '}'; buf[-1] = 0; } 601 return text; 602 } 603 604 static 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 617 static 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; 646 end: 647 buf = text + strlen(text); 648 undo: 649 if (buf - text > 2) { buf[-2] = '}'; buf[-1] = 0; } 650 return text; 651 } 652 653 static 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; 686 end: 687 buf = text + strlen(text); 688 undo: 689 if (buf - text > 2) { buf[-2] = '}'; buf[-1] = 0; } 690 return text; 691 } 692 693 static 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 */ 705 static 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 724 static 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 741 static inline LRESULT notify(LISTVIEW_INFO *infoPtr, INT code) 742 { 743 NMHDR nmh; 744 return notify_hdr(infoPtr, code, &nmh); 745 } 746 747 static inline void notify_itemactivate(LISTVIEW_INFO *infoPtr) 748 { 749 notify(infoPtr, LVN_ITEMACTIVATE); 750 } 751 752 static 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 758 static 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 775 static 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 } 422 788 423 789 static int get_ansi_notification(INT unicodeNotificationCode) 424 790 { 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; 430 803 } 431 804 432 805 /* 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 436 811 notificationCode : *Unicode* notification code 437 812 pdi : dispinfo structure (can be unicode or ansi) 438 813 isW : TRUE if dispinfo is Unicode 439 814 */ 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); 815 static 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 868 static 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 885 static 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 899 static 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); 474 929 } 475 930 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 937 static 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 944 static RANGES ranges_create(int count); 945 static void ranges_destroy(RANGES ranges); 946 static BOOL ranges_add(RANGES ranges, RANGE range); 947 static BOOL ranges_del(RANGES ranges, RANGE range); 948 static void ranges_dump(RANGES ranges); 949 950 static inline BOOL ranges_additem(RANGES ranges, INT nItem) 951 { 952 RANGE range = { nItem, nItem + 1 }; 953 954 return ranges_add(ranges, range); 955 } 956 957 static 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 */ 1025 static 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++; 1039 testitem: 1040 if (i->nItem == i->nSpecial) i->nItem++; 1041 if (i->nItem < i->range.upper) return TRUE; 1042 1043 pickarange: 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; 1054 end: 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 */ 1065 static 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 1081 testitem: 1082 i->nItem--; 1083 if (i->nItem == i->nSpecial) i->nItem--; 1084 if (i->nItem >= i->range.lower) return TRUE; 1085 1086 pickarange: 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; 1097 end: 1098 return (i->nItem = i->nSpecial) != -1; 1099 } 1100 1101 static 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 */ 1115 static inline void iterator_destroy(ITERATOR* i) 1116 { 1117 ranges_destroy(i->ranges); 1118 } 1119 1120 /*** 1121 * Create an empty iterator. 1122 */ 1123 static 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 */ 1133 static 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 */ 1145 static 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 */ 1155 static 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 } 484 1206 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 */ 1240 static 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 1291 static 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 1298 static 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 1308 static 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 1317 static inline void LISTVIEW_GetHeaderRect(LISTVIEW_INFO *infoPtr, INT nSubItem, RECT *lprc) 1318 { 1319 *lprc = LISTVIEW_GetColumnInfo(infoPtr, nSubItem)->rcHeader; 1320 } 1321 1322 static 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 1329 static inline BOOL is_redrawing(LISTVIEW_INFO *infoPtr) 1330 { 1331 return infoPtr->bRedraw && !infoPtr->bFirstPaint; 1332 } 1333 1334 static 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 1341 static 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 1350 static 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 1366 static inline void LISTVIEW_InvalidateList(LISTVIEW_INFO *infoPtr) 1367 { 1368 LISTVIEW_InvalidateRect(infoPtr, NULL); 1369 } 1370 1371 static 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 */ 1392 static 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 */ 1410 static 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); 644 1415 } 645 1416 … … 648 1419 * LISTVIEW_ProcessLetterKeys 649 1420 * 650 * Processes keyboard messages generated by pressing the letter keys 1421 * Processes keyboard messages generated by pressing the letter keys 651 1422 * 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 653 1424 * 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 655 1426 * 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 657 1428 * 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 661 1432 * 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 664 1435 * go to that string if there is a match. 665 1436 * 1437 * PARAMETERS 1438 * [I] hwnd : handle to the window 1439 * [I] charCode : the character code, the actual character 1440 * [I] keyData : key data 1441 * 666 1442 * RETURNS 667 1443 * … … 670 1446 * BUGS 671 1447 * 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 676 1452 * Windows there. 677 1453 * - We don't sound a beep when the search fails. … … 681 1457 * TREEVIEW_ProcessLetterKeys 682 1458 */ 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; 1459 static INT LISTVIEW_ProcessLetterKeys(LISTVIEW_INFO *infoPtr, WPARAM charCode, LPARAM keyData) 1460 { 690 1461 INT nItem; 691 INT nSize;692 1462 INT endidx,idx; 693 1463 LVITEMW item; 694 1464 WCHAR buffer[MAX_PATH]; 695 DWORD timestamp,elapsed;1465 DWORD lastKeyPressTimestamp = infoPtr->lastKeyPressTimestamp; 696 1466 697 1467 /* 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; 704 1469 705 1470 /* only allow the valid WM_CHARs through */ … … 716 1481 return 0; 717 1482 718 nSize=GETITEMCOUNT(infoPtr);719 1483 /* 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; 730 1485 731 1486 /* 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) 735 1490 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; 740 1493 } else { 741 1494 infoPtr->charCode=charCode; … … 757 1510 idx++; 758 1511 } else { 759 endidx= nSize;1512 endidx=infoPtr->nItemCount; 760 1513 idx=0; 761 1514 } 762 1515 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) 769 1518 break; 770 1519 idx=0; … … 772 1521 773 1522 /* get item */ 774 ZeroMemory(&item, sizeof(item));775 1523 item.mask = LVIF_TEXT; 776 1524 item.iItem = idx; 777 1525 item.iSubItem = 0; 778 1526 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; 781 1529 782 1530 /* check for a match */ … … 792 1540 } while (idx != endidx); 793 1541 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); 801 1544 802 1545 return 0; … … 804 1547 805 1548 /************************************************************************* 806 * LISTVIEW_UpdateHeaderSize [Internal] 1549 * LISTVIEW_UpdateHeaderSize [Internal] 807 1550 * 808 1551 * Function to resize the header control 809 1552 * 810 1553 * PARAMS 811 * hwnd [I]handle to a window812 * nNewScrollPos [I] Scroll Pos to Set1554 * [I] hwnd : handle to a window 1555 * [I] nNewScrollPos : scroll pos to set 813 1556 * 814 1557 * 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 */ 1560 static void LISTVIEW_UpdateHeaderSize(LISTVIEW_INFO *infoPtr, INT nNewScrollPos) 1561 { 822 1562 RECT winRect; 823 1563 POINT point[2]; 1564 1565 TRACE("nNewScrollPos=%d\n", nNewScrollPos); 824 1566 825 1567 GetWindowRect(infoPtr->hwndHeader, &winRect); … … 829 1571 point[1].y = winRect.bottom; 830 1572 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 839 1577 SetWindowPos(infoPtr->hwndHeader,0, 840 1578 point[0].x,point[0].y,point[1].x,point[1].y, … … 844 1582 /*** 845 1583 * DESCRIPTION: 846 * Update the scrollbars. This functions should be called whenever 1584 * Update the scrollbars. This functions should be called whenever 847 1585 * 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 */ 1593 static 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 */ 1684 static 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 } 1736 done: 1737 ReleaseDC(infoPtr->hwndSelf, hdc); 1738 } 1739 1740 /*** 1741 * Invalidates all visible selected items. 1742 */ 1743 static 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. 848 1765 * 849 1766 * 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 */ 1774 static 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 */ 1839 static 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 2002 calc_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 */ 2051 static 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 851 2090 * 852 2091 * RETURN: 853 2092 * None 854 2093 */ 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 2094 static 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 1087 2116 * 1088 2117 * RETURN: 1089 2118 * None 1090 2119 */ 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 2120 static 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 */ 2149 static 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 1249 2179 * 1250 2180 * RETURN: … … 1252 2182 * FAILURE : FALSE 1253 2183 */ 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); 2184 static 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; 1261 2192 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 1281 2227 * 1282 2228 * RETURN: … … 1284 2230 * FAILURE : FALSE 1285 2231 */ 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; 2232 static 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 */ 2283 static 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; 1310 2298 } 1311 2299 … … 1313 2301 * DESCRIPTION: 1314 2302 * Retrieves the subitem pointer associated with the subitem index. 1315 * 1316 * PARAMETER(S): 1317 * [I] HDPA: DPA handle for a specific item1318 * [I] INT: index of subitem2303 * 2304 * PARAMETER(S): 2305 * [I] hdpaSubItems : DPA handle for a specific item 2306 * [I] nSubItem : index of subitem 1319 2307 * 1320 2308 * RETURN: … … 1322 2310 * FAILURE : NULL 1323 2311 */ 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 handle1351 * [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 else1393 {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 } 2312 static 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 */ 2339 static 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 */ 2384 static 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; 1405 2393 else 1406 2394 { 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 */ 2417 static inline void LISTVIEW_UpdateItemSize(LISTVIEW_INFO *infoPtr) 2418 { 2419 infoPtr->nItemWidth = LISTVIEW_CalculateItemWidth(infoPtr); 2420 infoPtr->nItemHeight = LISTVIEW_CalculateItemHeight(infoPtr); 2421 } 2422 1510 2423 1511 2424 /*** … … 1515 2428 * 1516 2429 * 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 */ 2433 static 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 */ 2465 static 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__) 1558 2483 #else 1559 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK; 2484 #define ranges_check(ranges, desc) do { } while(0) 1560 2485 #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 2487 static 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 2509 static 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 2519 static 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 2529 static 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 2537 static 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 2553 fail: 2554 TRACE ("clone failed\n"); 2555 ranges_destroy(clone); 2556 return NULL; 2557 } 2558 2559 static 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 2569 static 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 2577 static 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 2586 static 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 2599 static 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 2618 static 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 } 1571 2654 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"); 1828 2694 return TRUE; 1829 else 2695 2696 fail: 2697 ranges_check(ranges, "failed add"); 2698 return FALSE; 2699 } 2700 2701 static 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 2768 fail: 2769 ranges_check(ranges, "failed del"); 1830 2770 return FALSE; 1831 2771 } … … 1836 2776 * 1837 2777 * 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 1839 2780 * 1840 2781 * RETURNS: … … 1842 2783 * FAILURE : TRUE 1843 2784 */ 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; 2785 static 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 2807 static 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 2818 static 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 */ 2833 static 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 */ 2865 static 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* */ 2880 static 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); 1871 2889 } 1872 2890 1873 2891 /** 1874 2892 * DESCRIPTION: 1875 * Removes a range selections.1876 * 2893 * Updates the various indices after an item has been inserted or deleted. 2894 * 1877 2895 * PARAMETER(S): 1878 * [I] HWND : window handle1879 * [I] INT : loweritem index1880 * [I] INT : upper item index2896 * [I] infoPtr : valid pointer to the listview structure 2897 * [I] nItem : item index 2898 * [I] direction : Direction of shift, +1 or -1. 1881 2899 * 1882 2900 * RETURN: 1883 2901 * None 1884 2902 */ 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 } 2903 static 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 1969 2929 1970 2930 /** 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 */ 2941 static 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 */ 2975 static 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 } 2026 3003 else 2027 3004 { 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 2045 3039 * 2046 3040 * RETURN: 2047 3041 * None 2048 3042 */ 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; 3043 static 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; 2307 3056 } 2308 3057 … … 2310 3059 * DESCRIPTION: 2311 3060 * Set selection(s) with keyboard. 2312 * 2313 * PARAMETER(S): 2314 * [I] HWND : window handle2315 * [I] INT : item index3061 * 3062 * PARAMETER(S): 3063 * [I] infoPtr : valid pointer to the listview structure 3064 * [I] nItem : item index 2316 3065 * 2317 3066 * RETURN: … … 2319 3068 * FAILURE : FALSE (nothing has changed) 2320 3069 */ 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); 3070 static BOOL LISTVIEW_KeySelection(LISTVIEW_INFO *infoPtr, INT nItem) 3071 { 3072 /* FIXME: pass in the state */ 2325 3073 WORD wShift = HIWORD(GetKeyState(VK_SHIFT)); 2326 3074 WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL)); 2327 3075 BOOL bResult = FALSE; 2328 3076 2329 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))3077 if ((nItem >= 0) && (nItem < infoPtr->nItemCount)) 2330 3078 { 2331 if ( lStyle & LVS_SINGLESEL)3079 if (infoPtr->dwStyle & LVS_SINGLESEL) 2332 3080 { 2333 3081 bResult = TRUE; 2334 LISTVIEW_SetSelection(hwnd, nItem); 2335 ListView_EnsureVisible(hwnd, nItem, FALSE); 3082 LISTVIEW_SetSelection(infoPtr, nItem); 2336 3083 } 2337 3084 else … … 2340 3087 { 2341 3088 bResult = TRUE; 2342 LISTVIEW_SetGroupSelection( hwnd, nItem);3089 LISTVIEW_SetGroupSelection(infoPtr, nItem); 2343 3090 } 2344 3091 else if (wCtrl) 2345 3092 { 2346 bResult = LISTVIEW_SetItemFocus( hwnd, nItem);3093 bResult = LISTVIEW_SetItemFocus(infoPtr, nItem); 2347 3094 } 2348 3095 else 2349 3096 { 2350 3097 bResult = TRUE; 2351 LISTVIEW_SetSelection(hwnd, nItem); 2352 ListView_EnsureVisible(hwnd, nItem, FALSE); 3098 LISTVIEW_SetSelection(infoPtr, nItem); 2353 3099 } 2354 3100 } 3101 LISTVIEW_EnsureVisible(infoPtr, nItem, FALSE); 2355 3102 } 2356 3103 3104 UpdateWindow(infoPtr->hwndSelf); /* update client area */ 2357 3105 return bResult; 2358 3106 } 3107 2359 3108 2360 3109 /*** … … 2364 3113 * 2365 3114 * PARAMETER(S): 2366 * [I] HWND : window handle2367 * [I] wParam: key indicator2368 * [I] lParam: mouse position3115 * [I] infoPtr : valid pointer to the listview structure 3116 * [I] fwKeys : key indicator 3117 * [I] pts : mouse position 2369 3118 * 2370 3119 * RETURN: … … 2374 3123 * LVS_EX_TRACKSELECT: An item is automatically selected when the cursor remains 2375 3124 * 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 */ 3127 static 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; 2392 3134 } 2393 3135 … … 2397 3139 * 2398 3140 * PARAMETER(S): 2399 * [I] HWND : window handle2400 * [I] wParam : key indicators2401 * [I] lParam : cursorposition3141 * [I] infoPtr : valid pointer to the listview structure 3142 * [I] fwKeys : key indicator 3143 * [I] pts : mouse position 2402 3144 * 2403 3145 * RETURN: 2404 3146 * 0 if the message is processed, non-zero if there was an error 2405 3147 */ 2406 static LRESULT LISTVIEW_MouseMove(HWND hwnd, WPARAM wParam, LPARAM lParam) 2407 { 2408 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0); 3148 static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, POINTS pts) 3149 { 2409 3150 TRACKMOUSEEVENT trackinfo; 2410 3151 2411 3152 /* see if we are supposed to be tracking mouse hovering */ 2412 if(infoPtr->dw ExStyle & LVS_EX_TRACKSELECT) {3153 if(infoPtr->dwLvExStyle & LVS_EX_TRACKSELECT) { 2413 3154 /* fill in the trackinfo struct */ 2414 3155 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT); 2415 3156 trackinfo.dwFlags = TME_QUERY; 2416 trackinfo.hwndTrack = hwnd;3157 trackinfo.hwndTrack = infoPtr->hwndSelf; 2417 3158 trackinfo.dwHoverTime = infoPtr->dwHoverTime; 2418 3159 … … 2427 3168 } 2428 3169 } 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 2438 3171 return 0; 2439 3172 } 2440 3173 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 */ 3178 static 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 2671 3196 * [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 2788 3198 * 2789 3199 * RETURN: … … 2791 3201 * FAILURE : FALSE 2792 3202 */ 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 3203 static 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 2840 3336 * 2841 3337 * RETURN: … … 2843 3339 * FAILURE : FALSE 2844 3340 */ 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 3341 static 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 2867 3408 * 2868 3409 * RETURN: … … 2870 3411 * FAILURE : FALSE 2871 3412 */ 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 } 3413 static 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 */ 3469 static 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 */ 3514 static 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 */ 3539 static 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 3648 postpaint: 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 */ 3665 static 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 */ 3735 static 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 */ 3806 static 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 */ 3835 static 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); 2888 3847 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); 3287 3888 else 3288 3889 { 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 3901 enddraw: 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; 4202 3913 } 4203 3914 … … 4206 3917 * DESCRIPTION: 4207 3918 * Calculates the approximate width and height of a given number of items. 4208 * 4209 * PARAMETER(S): 4210 * [I] HWND : window handle4211 * [I] INT: number of items4212 * [I] INT: width4213 * [I] INT: height3919 * 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 4214 3925 * 4215 3926 * RETURN: 4216 3927 * Returns a DWORD. The width in the low word and the height in high word. 4217 3928 */ 4218 static LRESULT LISTVIEW_ApproximateViewRect(HWND hwnd, INT nItemCount,3929 static DWORD LISTVIEW_ApproximateViewRect(LISTVIEW_INFO *infoPtr, INT nItemCount, 4219 3930 WORD wWidth, WORD wHeight) 4220 3931 { 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; 4223 3933 INT nItemCountPerColumn = 1; 4224 3934 INT nColumnCount = 0; … … 4226 3936 4227 3937 if (nItemCount == -1) 4228 nItemCount = GETITEMCOUNT(infoPtr);3938 nItemCount = infoPtr->nItemCount; 4229 3939 4230 3940 if (uView == LVS_LIST) … … 4246 3956 if (nItemCountPerColumn == 0) 4247 3957 nItemCountPerColumn = 1; 4248 3958 4249 3959 if (nItemCount % nItemCountPerColumn != 0) 4250 3960 nColumnCount = nItemCount / nItemCountPerColumn; … … 4261 3971 } 4262 3972 else if (uView == LVS_REPORT) 4263 FIXME("uView == LVS_REPORT: not implemented\n"); 3973 FIXME("uView == LVS_REPORT: not implemented\n"); 4264 3974 else if (uView == LVS_SMALLICON) 4265 FIXME("uView == LVS_SMALLICON: not implemented\n"); 3975 FIXME("uView == LVS_SMALLICON: not implemented\n"); 4266 3976 else if (uView == LVS_ICON) 4267 FIXME("uView == LVS_ICON: not implemented\n"); 4268 3977 FIXME("uView == LVS_ICON: not implemented\n"); 3978 4269 3979 return dwViewRect; 4270 3980 } 4271 3981 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 4279 3991 * 4280 3992 * RETURN: … … 4282 3994 * FAILURE : FALSE 4283 3995 */ 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 3996 static 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 */ 4059 static 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 4320 4105 * 4321 4106 * RETURN: … … 4323 4108 * FAILURE : FALSE 4324 4109 */ 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); 4110 static 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 4348 4183 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 */ 4198 static 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 4436 4269 * 4437 4270 * RETURN: … … 4439 4272 * FAILURE : FALSE 4440 4273 */ 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 4274 static 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 4477 4334 * 4478 4335 * RETURN: … … 4480 4337 * FAILURE : FALSE 4481 4338 */ 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 4339 static 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 4605 4377 * 4606 4378 * RETURN: … … 4608 4380 * FAILURE : FALSE 4609 4381 */ 4610 static BOOL LISTVIEW_EndEditLabelT(HWND hwnd, LPWSTR pszText, DWORDnItem, 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 else4632 {4633 ZeroMemory(&lvItemRef,sizeof(LISTVIEW_ITEM)); 4634 ZeroMemory(&item,sizeof(item));4635 i tem.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 control4667 * 4668 * PARAMETER(S): 4669 * [I] HWND : window handle4670 * [I] LPSTR : modified text4671 * [I] DWORD : item index4382 static 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 4672 4444 * 4673 4445 * RETURN: … … 4675 4447 * FAILURE : FALSE 4676 4448 */ 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 */ 4449 static 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 */ 4838 4468 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 */ 4914 4488 if (uView == LVS_REPORT) 4915 { 4916 rcItem.top -= infoPtr->rcList.top; 4917 nScrollPosHeight = infoPtr->scrollStep.y; 4918 } 4489 nScrollPosHeight = infoPtr->nItemHeight; 4919 4490 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 } 5188 4523 5189 4524 /*** 5190 4525 * DESCRIPTION: 5191 4526 * Searches for an item with specific characteristics. 5192 * 4527 * 5193 4528 * PARAMETER(S): 5194 4529 * [I] hwnd : window handle 5195 4530 * [I] nStart : base item index 5196 4531 * [I] lpFindInfo : item information to look for 5197 * 4532 * 5198 4533 * RETURN: 5199 4534 * SUCCESS : index of item 5200 4535 * FAILURE : -1 5201 4536 */ 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 4537 static 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 */ 5217 4590 if (lpFindInfo->flags & LVFI_PARAM) 5218 4591 { 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 4597 again: 4598 for (; nItem < nLast; nItem++) 4599 { 5260 4600 lvItem.iItem = nItem; 5261 4601 lvItem.iSubItem = 0; 5262 if (LISTVIEW_GetItemW(hwnd, &lvItem, TRUE)) 4602 if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) continue; 4603 4604 if (lvItem.mask & LVIF_PARAM) 5263 4605 { 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 { 5266 4614 if (lpFindInfo->flags & LVFI_PARTIAL) 5267 4615 { 5268 if (strstrW(lvItem.pszText, lpFindInfo->psz) == NULL) 5269 continue; 4616 if (strstrW(lvItem.pszText, lpFindInfo->psz) == NULL) continue; 5270 4617 } 5271 4618 else 5272 4619 { 5273 if (lstrcmpW(lvItem.pszText, lpFindInfo->psz) != 0) 5274 continue; 4620 if (lstrcmpW(lvItem.pszText, lpFindInfo->psz) != 0) continue; 5275 4621 } 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); 5292 4647 bWrap = FALSE; 5293 } 5294 else 5295 { 5296 return -1; 5297 } 5298 } 5299 } 5300 5301 return -1; 4648 goto again; 4649 } 4650 4651 return nNearestItem; 5302 4652 } 5303 4653 … … 5305 4655 * DESCRIPTION: 5306 4656 * Searches for an item with specific characteristics. 5307 * 4657 * 5308 4658 * PARAMETER(S): 5309 4659 * [I] hwnd : window handle 5310 4660 * [I] nStart : base item index 5311 4661 * [I] lpFindInfo : item information to look for 5312 * 4662 * 5313 4663 * RETURN: 5314 4664 * SUCCESS : index of item 5315 4665 * FAILURE : -1 5316 4666 */ 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; 4667 static 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; 5346 4679 } 5347 4680 … … 5349 4682 * DESCRIPTION: 5350 4683 * Retrieves the background image of the listview control. 5351 * 5352 * PARAMETER(S): 5353 * [I] HWND : window handle5354 * [O] LPLVMKBIMAGE: background image attributes4684 * 4685 * PARAMETER(S): 4686 * [I] infoPtr : valid pointer to the listview structure 4687 * [O] lpBkImage : background image attributes 5355 4688 * 5356 4689 * RETURN: … … 5358 4691 * FAILURE : FALSE 5359 4692 */ 5360 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */4693 /* static BOOL LISTVIEW_GetBkImage(LISTVIEW_INFO *infoPtr, LPLVBKIMAGE lpBkImage) */ 5361 4694 /* { */ 5362 4695 /* FIXME (listview, "empty stub!\n"); */ … … 5366 4699 /*** 5367 4700 * DESCRIPTION: 5368 * Retrieves the callback mask.5369 *5370 * PARAMETER(S):5371 * [I] HWND : window handle5372 *5373 * RETURN:5374 * Value of mask5375 */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:5385 4701 * Retrieves column attributes. 5386 * 5387 * PARAMETER(S): 5388 * [I] HWND : window handle5389 * [I] INT: column index5390 * [IO] LPLVCOLUMNW: column information4702 * 4703 * PARAMETER(S): 4704 * [I] infoPtr : valid pointer to the listview structure 4705 * [I] nColumn : column index 4706 * [IO] lpColumn : column information 5391 4707 * [I] isW : if TRUE, then lpColumn is a LPLVCOLUMNW 5392 4708 * otherwise it is in fact a LPLVCOLUMNA … … 5396 4712 * FAILURE : FALSE 5397 4713 */ 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); 4714 static 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); 5409 4721 5410 4722 /* initialize memory */ 5411 4723 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 5413 4740 if (lpColumn->mask & LVCF_FMT) 5414 hdi.mask |= HDI_FORMAT;4741 lpColumn->fmt = lpColumnInfo->fmt; 5415 4742 5416 4743 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; 5425 4745 5426 4746 if (lpColumn->mask & LVCF_IMAGE) 5427 hdi.mask |= HDI_IMAGE;4747 lpColumn->iImage = hdi.iImage; 5428 4748 5429 4749 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 4756 static BOOL LISTVIEW_GetColumnOrderArray(LISTVIEW_INFO *infoPtr, INT iCount, LPINT lpiArray) 4757 { 5475 4758 INT i; 5476 4759 … … 5478 4761 return FALSE; 5479 4762 5480 /* little hack */4763 /* FIXME: little hack */ 5481 4764 for (i = 0; i < iCount; i++) 5482 4765 lpiArray[i] = i; … … 5488 4771 * DESCRIPTION: 5489 4772 * Retrieves the column width. 5490 * 5491 * PARAMETER(S): 5492 * [I] HWND : window handle4773 * 4774 * PARAMETER(S): 4775 * [I] infoPtr : valid pointer to the listview structure 5493 4776 * [I] int : column index 5494 4777 * 5495 4778 * RETURN: 5496 4779 * 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 */ 4782 static 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, 5526 4810 * retrieves the total number of visible items. 5527 * 5528 * PARAMETER(S): 5529 * [I] HWND : window handle4811 * 4812 * PARAMETER(S): 4813 * [I] infoPtr : valid pointer to the listview structure 5530 4814 * 5531 4815 * RETURN: 5532 4816 * Number of fully visible items. 5533 4817 */ 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; 4818 static 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; 5620 4832 } 5621 4833 … … 5623 4835 * DESCRIPTION: 5624 4836 * Retrieves an image list handle. 5625 * 5626 * PARAMETER(S): 5627 * [I] HWND : window handle5628 * [I] INT : image list identifier5629 * 4837 * 4838 * PARAMETER(S): 4839 * [I] infoPtr : valid pointer to the listview structure 4840 * [I] nImageList : image list identifier 4841 * 5630 4842 * RETURN: 5631 4843 * SUCCESS : image list handle 5632 4844 * FAILURE : NULL 5633 4845 */ 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; 4846 static 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; 5653 4855 } 5654 4856 … … 5658 4860 * DESCRIPTION: 5659 4861 * Retrieves item attributes. 5660 * 4862 * 5661 4863 * PARAMETER(S): 5662 4864 * [I] hwnd : window handle 5663 4865 * [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, 5667 4867 * 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. 5907 4881 * 5908 4882 * RETURN: … … 5910 4884 * FAILURE : FALSE 5911 4885 */ 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); 4886 static 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 } 5924 4999 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; 5940 5078 } 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 */ 5112 static 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 5990 5129 5991 5130 /*** … … 5996 5135 * 5997 5136 * PARAMETER(S): 5998 * [I] HWND : window handle5999 * [I] INT: item index6000 * [O] LPPOINT: coordinate information5137 * [I] infoPtr : valid pointer to the listview structure 5138 * [I] nItem : item index 5139 * [O] lpptPosition : coordinate information 6001 5140 * 6002 5141 * RETURN: … … 6004 5143 * FAILURE : FALSE 6005 5144 */ 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 } 5145 static 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 6094 5169 6095 5170 /*** 6096 5171 * DESCRIPTION: 6097 5172 * Retrieves the bounding rectangle for a listview control item. 6098 * 6099 * PARAMETER(S): 6100 * [I] HWND : window handle6101 * [I] INT: item index6102 * [IO] LPRECT: bounding rectangle coordinates5173 * 5174 * PARAMETER(S): 5175 * [I] infoPtr : valid pointer to the listview structure 5176 * [I] nItem : item index 5177 * [IO] lprc : bounding rectangle coordinates 6103 5178 * lprc->left specifies the portion of the item for which the bounding 6104 5179 * rectangle will be retrieved. … … 6106 5181 * LVIR_BOUNDS Returns the bounding rectangle of the entire item, 6107 5182 * 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 6108 5194 * 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 6109 5206 * 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 6110 5218 * LVIR_SELECTBOUNDS Returns the union of the LVIR_ICON and LVIR_LABEL 6111 5219 * rectangles, but excludes columns in report view. 6112 * 5220 * 6113 5221 * RETURN: 6114 5222 * SUCCESS : TRUE … … 6118 5226 * Note that the bounding rectangle of the label in the LVS_ICON view depends 6119 5227 * 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 6121 5229 * item has the focus agrees with the items' records. 6122 5230 */ 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; 5231 static 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; 6142 5260 lvItem.iItem = nItem; 6143 5261 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); 6211 5279 break; 6212 5280 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); 6293 5283 break; 6294 5284 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); 6414 5287 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); 6495 5292 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 */ 5324 static 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 6508 5363 6509 5364 /*** 6510 5365 * DESCRIPTION: 6511 5366 * Retrieves the width of a label. 6512 * 6513 * PARAMETER(S): 6514 * [I] HWND : window handle6515 * 5367 * 5368 * PARAMETER(S): 5369 * [I] infoPtr : valid pointer to the listview structure 5370 * 6516 5371 * RETURN: 6517 5372 * SUCCESS : string width (in pixels) 6518 5373 * FAILURE : zero 6519 5374 */ 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; 5375 static 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); 6537 5390 } 6538 5391 … … 6540 5393 * DESCRIPTION: 6541 5394 * Retrieves the spacing between listview control items. 6542 * 6543 * PARAMETER(S): 6544 * [I] HWND : window handle6545 * [I] BOOL : flag for small or large icon5395 * 5396 * PARAMETER(S): 5397 * [I] infoPtr : valid pointer to the listview structure 5398 * [I] bSmall : flag for small or large icon 6546 5399 * 6547 5400 * RETURN: 6548 5401 * Horizontal + vertical spacing 6549 5402 */ 6550 static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall) 6551 { 6552 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0); 5403 static LONG LISTVIEW_GetItemSpacing(LISTVIEW_INFO *infoPtr, BOOL bSmall) 5404 { 6553 5405 LONG lResult; 6554 5406 6555 if ( bSmall == FALSE)5407 if (!bSmall) 6556 5408 { 6557 5409 lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy); … … 6559 5411 else 6560 5412 { 6561 LONG style = GetWindowLongW(hwnd, GWL_STYLE); 6562 if ((style & LVS_TYPEMASK) == LVS_ICON) 5413 if ((infoPtr->dwStyle & LVS_TYPEMASK) == LVS_ICON) 6563 5414 lResult = MAKELONG(DEFAULT_COLUMN_WIDTH, GetSystemMetrics(SM_CXSMICON)+HEIGHT_PADDING); 6564 5415 else … … 6571 5422 * DESCRIPTION: 6572 5423 * Retrieves the state of a listview control item. 6573 * 6574 * PARAMETER(S): 6575 * [I] HWND : window handle6576 * [I] INT: item index6577 * [I] UINT: state mask6578 * 5424 * 5425 * PARAMETER(S): 5426 * [I] infoPtr : valid pointer to the listview structure 5427 * [I] nItem : item index 5428 * [I] uMask : state mask 5429 * 6579 5430 * RETURN: 6580 5431 * State specified by the mask. 6581 5432 */ 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)); 5433 static 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 6591 5439 lvItem.iItem = nItem; 5440 lvItem.iSubItem = 0; 5441 lvItem.mask = LVIF_STATE; 6592 5442 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 * 6605 5452 * PARAMETER(S): 6606 5453 * [I] hwnd : window handle … … 6608 5455 * [IO] lpLVItem : item information 6609 5456 * [I] isW : TRUE if lpLVItem is Unicode 6610 * 5457 * 6611 5458 * RETURN: 6612 5459 * SUCCESS : string length 6613 5460 * FAILURE : 0 6614 5461 */ 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; 5462 static 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); 6632 5471 } 6633 5472 … … 6635 5474 * DESCRIPTION: 6636 5475 * Searches for an item based on properties + relationships. 6637 * 6638 * PARAMETER(S): 6639 * [I] HWND : window handle6640 * [I] INT: item index6641 * [I] INT: relationship flag6642 * 5476 * 5477 * PARAMETER(S): 5478 * [I] infoPtr : valid pointer to the listview structure 5479 * [I] nItem : item index 5480 * [I] uFlags : relationship flag 5481 * 6643 5482 * RETURN: 6644 5483 * SUCCESS : item index 6645 5484 * FAILURE : -1 6646 5485 */ 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 { 5486 static 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 6658 5498 ZeroMemory(&lvFindInfo, sizeof(lvFindInfo)); 6659 5499 6660 5500 if (uFlags & LVNI_CUT) 6661 5501 uMask |= LVIS_CUT; 6662 5502 6663 5503 if (uFlags & LVNI_DROPHILITED) 6664 5504 uMask |= LVIS_DROPHILITED; 6665 5505 6666 5506 if (uFlags & LVNI_FOCUSED) 6667 5507 uMask |= LVIS_FOCUSED; … … 6670 5510 uMask |= LVIS_SELECTED; 6671 5511 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 6672 5520 if (uFlags & LVNI_ABOVE) 6673 5521 { … … 6677 5525 { 6678 5526 nItem--; 6679 if ((ListView_GetItemState( hwnd, nItem, uMask) & uMask) == uMask)5527 if ((ListView_GetItemState(infoPtr->hwndSelf, nItem, uMask) & uMask) == uMask) 6680 5528 return nItem; 6681 5529 } … … 6683 5531 else 6684 5532 { 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 } 6685 5545 lvFindInfo.flags = LVFI_NEARESTXY; 6686 5546 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) 6689 5549 { 6690 if ((ListView_GetItemState( hwnd, nItem, uMask) & uMask) == uMask)5550 if ((ListView_GetItemState(infoPtr->hwndSelf, nItem, uMask) & uMask) == uMask) 6691 5551 return nItem; 6692 5552 } … … 6697 5557 if ((uView == LVS_LIST) || (uView == LVS_REPORT)) 6698 5558 { 6699 while (nItem < GETITEMCOUNT(infoPtr))5559 while (nItem < infoPtr->nItemCount) 6700 5560 { 6701 5561 nItem++; 6702 if ((L istView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)5562 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask) 6703 5563 return nItem; 6704 5564 } … … 6706 5566 else 6707 5567 { 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 } 6708 5580 lvFindInfo.flags = LVFI_NEARESTXY; 6709 5581 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) 6712 5584 { 6713 if ((L istView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)5585 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask) 6714 5586 return nItem; 6715 5587 } … … 6720 5592 if (uView == LVS_LIST) 6721 5593 { 6722 nCountPerColumn = LISTVIEW_GetCountPerColumn( hwnd);5594 nCountPerColumn = LISTVIEW_GetCountPerColumn(infoPtr); 6723 5595 while (nItem - nCountPerColumn >= 0) 6724 5596 { 6725 5597 nItem -= nCountPerColumn; 6726 if ((L istView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)5598 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask) 6727 5599 return nItem; 6728 5600 } … … 6730 5602 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON)) 6731 5603 { 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 } 6732 5616 lvFindInfo.flags = LVFI_NEARESTXY; 6733 5617 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) 6736 5620 { 6737 if ((ListView_GetItemState( hwnd, nItem, uMask) & uMask) == uMask)5621 if ((ListView_GetItemState(infoPtr->hwndSelf, nItem, uMask) & uMask) == uMask) 6738 5622 return nItem; 6739 5623 } … … 6744 5628 if (uView == LVS_LIST) 6745 5629 { 6746 nCountPerColumn = LISTVIEW_GetCountPerColumn( hwnd);6747 while (nItem + nCountPerColumn < GETITEMCOUNT(infoPtr))5630 nCountPerColumn = LISTVIEW_GetCountPerColumn(infoPtr); 5631 while (nItem + nCountPerColumn < infoPtr->nItemCount) 6748 5632 { 6749 5633 nItem += nCountPerColumn; 6750 if ((ListView_GetItemState( hwnd, nItem, uMask) & uMask) == uMask)5634 if ((ListView_GetItemState(infoPtr->hwndSelf, nItem, uMask) & uMask) == uMask) 6751 5635 return nItem; 6752 5636 } … … 6754 5638 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON)) 6755 5639 { 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 } 6756 5652 lvFindInfo.flags = LVFI_NEARESTXY; 6757 5653 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) 6760 5656 { 6761 if ((L istView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)5657 if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask) 6762 5658 return nItem; 6763 5659 } … … 6769 5665 6770 5666 /* search by index */ 6771 for (i = nItem; i < GETITEMCOUNT(infoPtr); i++)5667 for (i = nItem; i < infoPtr->nItemCount; i++) 6772 5668 { 6773 if ((L istView_GetItemState(hwnd, i, uMask) & uMask) == uMask)5669 if ((LISTVIEW_GetItemState(infoPtr, i, uMask) & uMask) == uMask) 6774 5670 return i; 6775 5671 } 6776 5672 } 6777 } 6778 6779 return -1; 5673 5674 return -1; 6780 5675 } 6781 5676 … … 6785 5680 * DESCRIPTION: 6786 5681 * 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 */ 5690 static void LISTVIEW_GetOrigin(LISTVIEW_INFO *infoPtr, LPPOINT lpptOrigin) 5691 { 5692 UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; 5693 INT nHorzPos = 0, nVertPos = 0; 6806 5694 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 } 6874 5718 6875 5719 /*** 6876 5720 * DESCRIPTION: 6877 5721 * Retrieves the width of a string. 6878 * 5722 * 6879 5723 * PARAMETER(S): 6880 5724 * [I] hwnd : window handle 6881 5725 * [I] lpszText : text string to process 6882 5726 * [I] isW : TRUE if lpszText is Unicode, FALSE otherwise 6883 * 5727 * 6884 5728 * RETURN: 6885 5729 * SUCCESS : string width (in pixels) 6886 5730 * FAILURE : zero 6887 5731 */ 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); 5732 static INT LISTVIEW_GetStringWidthT(LISTVIEW_INFO *infoPtr, LPCWSTR lpszText, BOOL isW) 5733 { 6897 5734 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 } 6924 5750 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) 6932 5767 * 6933 * PARAMETER(S):6934 * [I] HWND : window handle6935 *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 handle6952 *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 not6966 *6967 * PARAMETER(S):6968 * [I] HWND : window handle6969 * [IO] LPLV_INTHIT : hit test information6970 * [I] subitem : fill out iSubItem.6971 *6972 * RETURN:6973 * SUCCESS : item index of hit6974 * FAILURE : -16975 */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 else6994 {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 else7038 {7039 /*7040 * Now compute distance from point to center of boundary7041 * box. Since we are only interested in the relative7042 * distance, we can skip the nasty square root operation7043 */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 handle7068 * [IO] LPLVHITTESTINFO : hit test information7069 * [I] subitem : fill out iSubItem.7070 *7071 * RETURN:7072 * SUCCESS : item index7073 * FAILURE : -17074 */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 handle7095 * [IO} LPLVHITTESTINFO : hit test information7096 *7097 5768 * RETURN: 7098 5769 * SUCCESS : item index 7099 5770 * FAILURE : -1 7100 5771 */ 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) 5772 static 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++) 7169 5857 { 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 7265 5876 7266 5877 /* LISTVIEW_InsertCompare: callback routine for comparing pszText members of the LV_ITEMS … … 7273 5884 (remarks on LVITEM: LVM_INSERTITEM will insert the new item in the proper sort postion... 7274 5885 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, 7277 5888 <item>.pszText is not LPSTR_TEXTCALLBACK. 7278 5889 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..." 7281 5892 */ 7282 5893 static INT WINAPI LISTVIEW_InsertCompare( LPVOID first, LPVOID second, LPARAM lParam) 7283 5894 { 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; 7290 5901 } 7291 5902 … … 7293 5904 * nESCRIPTION: 7294 5905 * Inserts a new item in the listview control. 7295 * 7296 * PARAMETER(S): 7297 * [I] HWND : window handle7298 * [I] LPLVITEMW: item information5906 * 5907 * PARAMETER(S): 5908 * [I] infoPtr : valid pointer to the listview structure 5909 * [I] lpLVItem : item information 7299 5910 * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI 7300 5911 * … … 7303 5914 * FAILURE : -1 7304 5915 */ 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 ++; 5916 static 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); 7322 6017 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 6019 undo: 6020 DPA_DeletePtr(infoPtr->hdpaItems, nItem); 6021 infoPtr->nItemCount--; 6022 fail: 6023 DPA_DeletePtr(hdpaSubItems, 0); 6024 DPA_Destroy (hdpaSubItems); 6025 COMCTL32_Free (lpItem); 6026 return -1; 7410 6027 } 7411 6028 … … 7413 6030 * DESCRIPTION: 7414 6031 * Redraws a range of items. 7415 * 7416 * PARAMETER(S): 7417 * [I] HWND : window handle7418 * [I] INT: first item7419 * [I] INT: last item6032 * 6033 * PARAMETER(S): 6034 * [I] infoPtr : valid pointer to the listview structure 6035 * [I] nFirst : first item 6036 * [I] nLast : last item 7420 6037 * 7421 6038 * RETURN: … … 7423 6040 * FAILURE : FALSE 7424 6041 */ 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 6042 static 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 7460 6064 * 7461 6065 * RETURN: 7462 6066 * SUCCESS : TRUE 7463 6067 * 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 */ 6089 static 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); 7473 6106 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 7487 6117 * 7488 6118 * RETURN: … … 7490 6120 * FAILURE : FALSE 7491 6121 */ 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; 6122 static 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* */ 6142 static 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 */ 6228 static 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 6310 fail: 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; 7499 6318 } 7500 6319 … … 7502 6321 * DESCRIPTION: 7503 6322 * 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 7511 6329 * 7512 6330 * RETURN: … … 7514 6332 * FAILURE : FALSE 7515 6333 */ 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 } 6334 static 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); 7593 6353 7594 6354 /* 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; 7602 6372 } 7603 6373 … … 7607 6377 * 7608 6378 * PARAMETERS: 7609 * [I] HWND : window handle7610 * [I] INT: number of elements in column order array7611 * [I] INT: pointer to column order array6379 * [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 7612 6382 * 7613 6383 * RETURN: … … 7615 6385 * FAILURE : FALSE 7616 6386 */ 7617 static LRESULT LISTVIEW_SetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray) 7618 { 7619 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0); */ 7620 6387 static BOOL LISTVIEW_SetColumnOrderArray(LISTVIEW_INFO *infoPtr, INT iCount, const INT *lpiArray) 6388 { 7621 6389 FIXME("iCount %d lpiArray %p\n", iCount, lpiArray); 7622 6390 … … 7633 6401 * 7634 6402 * PARAMETERS: 7635 * [I] HWND : window handle7636 * [I] INT: column index7637 * [I] INT: column width6403 * [I] infoPtr : valid pointer to the listview structure 6404 * [I] nColumn : column index 6405 * [I] cx : column width 7638 6406 * 7639 6407 * RETURN: … … 7641 6409 * FAILURE : FALSE 7642 6410 */ 7643 static LRESULT LISTVIEW_SetColumnWidth(HWND hwnd, INT iCol, INT cx) 7644 { 7645 LISTVIEW_INFO *infoPtr; 6411 static 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; 7646 6416 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); 7668 6419 7669 6420 /* 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 7675 6423 /* 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 7681 6427 /* 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; 7686 6456 } 7687 6457 7688 6458 /* autosize based on listview items width */ 7689 6459 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; 7722 6461 else if(cx == LVSCW_AUTOSIZE_USEHEADER) 7723 6462 { 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); 7802 6510 } 7803 6511 … … 7807 6515 * 7808 6516 * PARAMETERS: 7809 * [I] HWND : window handle7810 * [I] DWORD: mask7811 * [I] DWORD: style6517 * [I] infoPtr : valid pointer to the listview structure 6518 * [I] dwMask : mask 6519 * [I] dwStyle : style 7812 6520 * 7813 6521 * RETURN: … … 7815 6523 * FAILURE : 0 7816 6524 */ 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 */ 6525 static 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 */ 6549 static 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 7832 6558 7833 6559 /*** … … 7836 6562 * 7837 6563 * PARAMETERS: 7838 * [I] HWND : window handle7839 * [I] INT: index6564 * [I] infoPtr : valid pointer to the listview structure 6565 * [I] iIndex : index 7840 6566 * 7841 6567 * RETURN: … … 7843 6569 * FAILURE : -1 (no hot item) 7844 6570 */ 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 } 6571 static 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 7855 6580 7856 6581 /*** … … 7859 6584 * 7860 6585 * PARAMETER(S): 7861 * [I] HWND : window handle7862 * [I] DWORD : dwHoverTime, if -1 the hover time is set to the default6586 * [I] infoPtr : valid pointer to the listview structure 6587 * [I] dwHoverTime : hover time, if -1 the hover time is set to the default 7863 6588 * 7864 6589 * RETURN: 7865 6590 * Returns the previous hover time 7866 6591 */ 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; 6592 static DWORD LISTVIEW_SetHoverTime(LISTVIEW_INFO *infoPtr, DWORD dwHoverTime) 6593 { 6594 DWORD oldHoverTime = infoPtr->dwHoverTime; 6595 6596 infoPtr->dwHoverTime = dwHoverTime; 6597 6598 return oldHoverTime; 7875 6599 } 7876 6600 … … 7880 6604 * 7881 6605 * 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) 7884 6609 * 7885 6610 * RETURN: 7886 6611 * MAKELONG(oldcx, oldcy) 7887 6612 */ 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 { 6613 static 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 7901 6639 infoPtr->iconSpacing.cx = cx; 7902 6640 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 6653 inline 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 } 7961 6668 7962 6669 /*** 7963 6670 * DESCRIPTION: 7964 6671 * Sets image lists. 7965 * 7966 * PARAMETER(S): 7967 * [I] HWND : window handle7968 * [I] INT : image list type7969 * [I] HIMAGELIST: image list handle6672 * 6673 * PARAMETER(S): 6674 * [I] infoPtr : valid pointer to the listview structure 6675 * [I] nType : image list type 6676 * [I] himl : image list handle 7970 6677 * 7971 6678 * RETURN: … … 7973 6680 * FAILURE : NULL 7974 6681 */ 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; 6682 static 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); 7986 6697 break; 7987 6698 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); 7991 6703 break; 7992 6704 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); 7997 6710 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; 8006 6722 } 8007 6723 … … 8009 6725 * DESCRIPTION: 8010 6726 * Preallocates memory (does *not* set the actual count of items !) 8011 * 8012 * PARAMETER(S): 8013 * [I] HWND : window handle8014 * [I] INT: item count (projected number of items to allocate)8015 * [I] DWORD: update flags6727 * 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 8016 6732 * 8017 6733 * RETURN: … … 8019 6735 * FAILURE : FALSE 8020 6736 */ 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; 6737 static 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; 8078 6822 } 8079 6823 … … 8081 6825 * DESCRIPTION: 8082 6826 * 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 8089 6832 * 8090 6833 * RETURN: … … 8092 6835 * FAILURE : FALSE 8093 6836 */ 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; 6837 static 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); 8171 6866 } 8172 6867 … … 8174 6869 * DESCRIPTION: 8175 6870 * Sets the state of one or many items. 8176 * 8177 * PARAMETER(S): 8178 * [I] HWND : window handle8179 * [I] INT: item index8180 * [I] LPLVITEM: item or subitem info6871 * 6872 * PARAMETER(S): 6873 * [I] infoPtr : valid pointer to the listview structure 6874 * [I] nItem : item index 6875 * [I] lpLVItem : item or subitem info 8181 6876 * 8182 6877 * RETURN: … … 8184 6879 * FAILURE : FALSE 8185 6880 */ 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; 6881 static 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; 8211 6903 } 8212 6904 … … 8214 6906 * DESCRIPTION: 8215 6907 * Sets the text of an item or subitem. 8216 * 6908 * 8217 6909 * PARAMETER(S): 8218 6910 * [I] hwnd : window handle … … 8225 6917 * FAILURE : FALSE 8226 6918 */ 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)); 6919 static 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; 8239 6927 lvItem.mask = LVIF_TEXT; 8240 6928 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); 8248 6934 } 8249 6935 … … 8253 6939 * 8254 6940 * PARAMETER(S): 8255 * [I] HWND : window handle8256 * [I] INT: index6941 * [I] infoPtr : valid pointer to the listview structure 6942 * [I] nIndex : index 8257 6943 * 8258 6944 * RETURN: 8259 6945 * Index number or -1 if there is no selection mark. 8260 6946 */ 8261 static LRESULT LISTVIEW_SetSelectionMark(HWND hwnd, INT nIndex) 8262 { 8263 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0); 6947 static INT LISTVIEW_SetSelectionMark(LISTVIEW_INFO *infoPtr, INT nIndex) 6948 { 8264 6949 INT nOldIndex = infoPtr->nSelectionMark; 8265 6950 8266 TRACE("( hwnd=%x, nIndex=%d)\n", hwnd, nIndex);6951 TRACE("(nIndex=%d)\n", nIndex); 8267 6952 8268 6953 infoPtr->nSelectionMark = nIndex; … … 8274 6959 * DESCRIPTION: 8275 6960 * Sets the text background color. 8276 * 8277 * PARAMETER(S): 8278 * [I] HWND : window handle8279 * [I] COLORREF: text background color6961 * 6962 * PARAMETER(S): 6963 * [I] infoPtr : valid pointer to the listview structure 6964 * [I] clrTextBk : text background color 8280 6965 * 8281 6966 * RETURN: … … 8283 6968 * FAILURE : FALSE 8284 6969 */ 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 6970 static 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 8294 6980 return TRUE; 8295 6981 } … … 8298 6984 * DESCRIPTION: 8299 6985 * Sets the text foreground color. 8300 * 8301 * PARAMETER(S): 8302 * [I] HWND : window handle8303 * [I] COLORREF : text color6986 * 6987 * PARAMETER(S): 6988 * [I] infoPtr : valid pointer to the listview structure 6989 * [I] clrText : text color 8304 6990 * 8305 6991 * RETURN: … … 8307 6993 * FAILURE : FALSE 8308 6994 */ 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 */ 6995 static 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 */ 7019 static HWND LISTVIEW_SetToolTips( LISTVIEW_INFO *infoPtr, HWND hwndNewToolTip) 7020 { 7021 HWND hwndOldToolTip = infoPtr->hwndToolTip; 7022 infoPtr->hwndToolTip = hwndNewToolTip; 7023 return hwndOldToolTip; 7024 } 7025 8322 7026 /* LISTVIEW_SetUnicodeFormat */ 8323 7027 /* LISTVIEW_SetWorkAreas */ … … 8326 7030 * DESCRIPTION: 8327 7031 * Callback internally used by LISTVIEW_SortItems() 8328 * 8329 * PARAMETER(S): 8330 * [I] LPVOID : first LISTVIEW_ITEMto compare8331 * [I] LPVOID : second LISTVIEW_ITEMto compare8332 * [I] LPARAM: HWND of control7032 * 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 8333 7037 * 8334 7038 * RETURN: … … 8340 7044 { 8341 7045 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 ); 8344 7048 8345 7049 /* Forward the call to the client defined callback */ … … 8350 7054 * DESCRIPTION: 8351 7055 * Sorts the listview items. 8352 * 8353 * PARAMETER(S): 8354 * [I] HWND : window handle8355 * [I] WPARAM: application-defined value8356 * [I] LPARAM: pointer to comparision callback7056 * 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 8357 7061 * 8358 7062 * RETURN: … … 8360 7064 * FAILURE : FALSE 8361 7065 */ 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; 7066 static 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; 8368 7071 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 8378 7081 /* 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 8382 7094 infoPtr->pfnCompare = pfnCompare; 8383 7095 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 8389 7101 * selected instead) 8390 7102 */ 8391 7103 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 } 8403 7120 } 8404 7121 if (selectionMarkItem != NULL) 8405 7122 infoPtr->nSelectionMark = DPA_GetPtrIndex(infoPtr->hdpaItems, selectionMarkItem); 8406 7123 /* I believe nHotItem should be left alone, see LISTVIEW_ShiftIndices */ 8407 7124 8408 /* align the items */8409 LISTVIEW_AlignTop(hwnd);8410 8411 7125 /* refresh the display */ 8412 InvalidateRect(hwnd, NULL, TRUE); 7126 if (uView != LVS_ICON && uView != LVS_SMALLICON) 7127 LISTVIEW_InvalidateList(infoPtr); 8413 7128 8414 7129 return TRUE; 8415 7130 } 8416 7131 8417 /* LISTVIEW_SubItemHitTest */8418 8419 7132 /*** 8420 7133 * DESCRIPTION: 8421 7134 * Updates an items or rearranges the listview control. 8422 * 8423 * PARAMETER(S): 8424 * [I] HWND : window handle8425 * [I] INT: item index7135 * 7136 * PARAMETER(S): 7137 * [I] infoPtr : valid pointer to the listview structure 7138 * [I] nItem : item index 8426 7139 * 8427 7140 * RETURN: … … 8429 7142 * FAILURE : FALSE 8430 7143 */ 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; 7144 static 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; 8443 7149 8444 7150 /* 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); 8450 7153 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 8461 7160 /*** 8462 7161 * DESCRIPTION: 8463 7162 * 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 */ 7172 static LRESULT LISTVIEW_Create(HWND hwnd, const CREATESTRUCTW *lpcs) 7173 { 7174 LISTVIEW_INFO *infoPtr; 8474 7175 UINT uView = lpcs->style & LVS_TYPEMASK; 8475 7176 LOGFONTW logFont; 8476 7177 8477 TRACE("( hwnd=%x, lpcs=%p)\n", hwnd, lpcs);7178 TRACE("(lpcs=%p)\n", lpcs); 8478 7179 8479 7180 /* 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; 8482 7188 /* 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 8486 7192 /* 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; 8489 7195 infoPtr->clrTextBk = CLR_DEFAULT; 7196 LISTVIEW_SetBkColor(infoPtr, comctl32_color.clrWindow); 8490 7197 8491 7198 /* set default values */ 8492 infoPtr->hwndSelf = hwnd;8493 infoPtr->uCallbackMask = 0;8494 #ifdef __WIN32OS2__8495 infoPtr->nFocusedItem = -2;8496 #else8497 7199 infoPtr->nFocusedItem = -1; 8498 #endif8499 7200 infoPtr->nSelectionMark = -1; 8500 7201 infoPtr->nHotItem = -1; 7202 infoPtr->bRedraw = TRUE; 7203 infoPtr->bFirstPaint = TRUE; 7204 infoPtr->bNoItemMetrics = TRUE; 7205 infoPtr->bDoChangeNotify = TRUE; 8501 7206 infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING); 8502 7207 infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING); 8503 ZeroMemory(&infoPtr->rcList, sizeof(RECT));8504 infoPtr->hwndEdit = 0;8505 infoPtr->pedititem = NULL;8506 7208 infoPtr->nEditLabelItem = -1; 7209 infoPtr->dwHoverTime = -1; /* default system hover time */ 8507 7210 8508 7211 /* get default font (icon title) */ … … 8510 7213 infoPtr->hDefaultFont = CreateFontIndirectW(&logFont); 8511 7214 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); 8513 7243 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) 8533 7245 { 8534 7246 if (!(LVS_NOCOLUMNHEADER & lpcs->style)) … … 8539 7251 { 8540 7252 /* set HDS_HIDDEN flag to hide the header bar */ 8541 SetWindowLongW(infoPtr->hwndHeader, GWL_STYLE, 7253 SetWindowLongW(infoPtr->hwndHeader, GWL_STYLE, 8542 7254 GetWindowLongW(infoPtr->hwndHeader, GWL_STYLE) | HDS_HIDDEN); 8543 7255 } 8544 8545 8546 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);8547 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);8548 7256 } 8549 else8550 {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 tooltip8573 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 #endif8578 7257 8579 7258 return 0; 7259 7260 fail: 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; 8580 7269 } 8581 7270 … … 8583 7272 * DESCRIPTION: 8584 7273 * 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 * 8591 7279 * RETURN: 8592 7280 * SUCCESS : TRUE 8593 7281 * FAILURE : FALSE 8594 7282 */ 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 { 7283 static inline BOOL LISTVIEW_EraseBkgnd(LISTVIEW_INFO *infoPtr, HDC hdc) 7284 { 8609 7285 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 */ 7305 static 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); 8651 7313 } 8652 7314 … … 8654 7316 * DESCRIPTION: 8655 7317 * 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 8663 7324 * 8664 7325 * RETURN: 8665 7326 * 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 */ 7335 static 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; 8685 7356 switch (nScrollCode) 8686 7357 { 7358 case SB_INTERNAL: 7359 break; 7360 8687 7361 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 8692 7365 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 8697 7369 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 8707 7373 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; 8716 7376 8717 7377 case SB_THUMBPOSITION: 8718 7378 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; 8755 7417 } 8756 7418 … … 8758 7420 * DESCRIPTION: 8759 7421 * 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 8767 7428 * 8768 7429 * RETURN: 8769 7430 * 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 */ 7440 static 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; 8789 7458 8790 7459 switch (nScrollCode) 8791 7460 { 7461 case SB_INTERNAL: 7462 break; 7463 8792 7464 case SB_LINELEFT: 8793 if (scrollInfo.nPos > scrollInfo.nMin) 8794 scrollInfo.nPos--; 8795 break; 8796 7465 nScrollDiff = -1; 7466 break; 7467 8797 7468 case SB_LINERIGHT: 8798 if (scrollInfo.nPos < scrollInfo.nMax) 8799 scrollInfo.nPos++; 8800 break; 8801 7469 nScrollDiff = 1; 7470 break; 7471 8802 7472 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 8812 7476 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; 8821 7479 8822 7480 case SB_THUMBPOSITION: 8823 7481 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 8849 7522 return 0; 8850 7523 } 8851 7524 8852 static LRESULT LISTVIEW_MouseWheel( HWND hwnd, INT wheelDelta)8853 { 8854 UINT uView = GetWindowLongW(hwnd, GWL_STYLE)& LVS_TYPEMASK;7525 static LRESULT LISTVIEW_MouseWheel(LISTVIEW_INFO *infoPtr, INT wheelDelta) 7526 { 7527 UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; 8855 7528 INT gcWheelDelta = 0; 8856 7529 UINT pulScrollLines = 3; 8857 7530 SCROLLINFO scrollInfo; 8858 7531 8859 TRACE("( hwnd=%x, wheelDelta=%d)\n", hwnd, wheelDelta);7532 TRACE("(wheelDelta=%d)\n", wheelDelta); 8860 7533 8861 7534 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0); 8862 7535 gcWheelDelta -= wheelDelta; 8863 7536 8864 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));8865 7537 scrollInfo.cbSize = sizeof(SCROLLINFO); 8866 scrollInfo.fMask = SIF_POS | SIF_RANGE;7538 scrollInfo.fMask = SIF_POS; 8867 7539 8868 7540 switch(uView) … … 8874 7546 * should be fixed in the future. 8875 7547 */ 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); 8878 7550 break; 8879 7551 … … 8881 7553 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines) 8882 7554 { 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); 8889 7558 } 8890 7559 break; 8891 7560 8892 7561 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); 8894 7563 break; 8895 7564 } … … 8899 7568 /*** 8900 7569 * DESCRIPTION: 8901 * ??? 8902 * 8903 * PARAMETER(S): 8904 * [I] HWND : window handle8905 * [I] INT : virtual key8906 * [I] LONG: key data7570 * ??? 7571 * 7572 * PARAMETER(S): 7573 * [I] infoPtr : valid pointer to the listview structure 7574 * [I] nVirtualKey : virtual key 7575 * [I] lKeyData : key data 8907 7576 * 8908 7577 * RETURN: 8909 7578 * Zero 8910 7579 */ 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; 7580 static LRESULT LISTVIEW_KeyDown(LISTVIEW_INFO *infoPtr, INT nVirtualKey, LONG lKeyData) 7581 { 7582 UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; 8915 7583 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); 8921 7587 8922 7588 /* send LVN_KEYDOWN notification */ 8923 nmKeyDown.wVKey = nVirtualKey; 7589 nmKeyDown.wVKey = nVirtualKey; 8924 7590 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 8932 7593 switch (nVirtualKey) 8933 7594 { 8934 7595 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); 8939 7600 } 8940 7601 break; 8941 7602 8942 7603 case VK_HOME: 8943 if ( GETITEMCOUNT(infoPtr)> 0)7604 if (infoPtr->nItemCount > 0) 8944 7605 nItem = 0; 8945 7606 break; 8946 7607 8947 7608 case VK_END: 8948 if ( GETITEMCOUNT(infoPtr)> 0)8949 nItem = GETITEMCOUNT(infoPtr)- 1;7609 if (infoPtr->nItemCount > 0) 7610 nItem = infoPtr->nItemCount - 1; 8950 7611 break; 8951 7612 8952 7613 case VK_LEFT: 8953 nItem = ListView_GetNextItem( hwnd, infoPtr->nFocusedItem, LVNI_TOLEFT);7614 nItem = ListView_GetNextItem(infoPtr->hwndSelf, infoPtr->nFocusedItem, LVNI_TOLEFT); 8954 7615 break; 8955 7616 8956 7617 case VK_UP: 8957 nItem = ListView_GetNextItem( hwnd, infoPtr->nFocusedItem, LVNI_ABOVE);7618 nItem = ListView_GetNextItem(infoPtr->hwndSelf, infoPtr->nFocusedItem, LVNI_ABOVE); 8958 7619 break; 8959 7620 8960 7621 case VK_RIGHT: 8961 nItem = ListView_GetNextItem( hwnd, infoPtr->nFocusedItem, LVNI_TORIGHT);7622 nItem = ListView_GetNextItem(infoPtr->hwndSelf, infoPtr->nFocusedItem, LVNI_TORIGHT); 8962 7623 break; 8963 7624 8964 7625 case VK_DOWN: 8965 nItem = ListView_GetNextItem( hwnd, infoPtr->nFocusedItem, LVNI_BELOW);7626 nItem = ListView_GetNextItem(infoPtr->hwndSelf, infoPtr->nFocusedItem, LVNI_BELOW); 8966 7627 break; 8967 7628 8968 7629 case VK_PRIOR: 8969 7630 if (uView == LVS_REPORT) 8970 nItem = infoPtr->nFocusedItem - LISTVIEW_GetCountPerColumn( hwnd);7631 nItem = infoPtr->nFocusedItem - LISTVIEW_GetCountPerColumn(infoPtr); 8971 7632 else 8972 nItem = infoPtr->nFocusedItem - LISTVIEW_GetCountPerColumn( hwnd)8973 * LISTVIEW_GetCountPerRow( hwnd);7633 nItem = infoPtr->nFocusedItem - LISTVIEW_GetCountPerColumn(infoPtr) 7634 * LISTVIEW_GetCountPerRow(infoPtr); 8974 7635 if(nItem < 0) nItem = 0; 8975 7636 break; … … 8977 7638 case VK_NEXT: 8978 7639 if (uView == LVS_REPORT) 8979 nItem = infoPtr->nFocusedItem + LISTVIEW_GetCountPerColumn( hwnd);7640 nItem = infoPtr->nFocusedItem + LISTVIEW_GetCountPerColumn(infoPtr); 8980 7641 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; 8984 7645 break; 8985 7646 } 8986 7647 8987 7648 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); 8992 7650 8993 7651 return 0; … … 8997 7655 * DESCRIPTION: 8998 7656 * Kills the focus. 8999 * 9000 * PARAMETER(S): 9001 * [I] HWND : window handle7657 * 7658 * PARAMETER(S): 7659 * [I] infoPtr : valid pointer to the listview structure 9002 7660 * 9003 7661 * RETURN: 9004 7662 * Zero 9005 7663 */ 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; 7664 static 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; 9044 7684 } 9045 7685 … … 9047 7687 * DESCRIPTION: 9048 7688 * 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 9055 7694 * 9056 7695 * RETURN: 9057 7696 * Zero 9058 7697 */ 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; 7698 static 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; 9092 7718 } 9093 7719 … … 9095 7721 * DESCRIPTION: 9096 7722 * 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 9103 7728 * 9104 7729 * RETURN: 9105 7730 * Zero 9106 7731 */ 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); 7732 static LRESULT LISTVIEW_LButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, POINTS pts) 7733 { 7734 LVHITTESTINFO lvHitTestInfo; 9113 7735 static BOOL bGroupSelect = TRUE; 9114 POINT pt Position;7736 POINT pt = { pts.x, pts.y }; 9115 7737 INT nItem; 9116 7738 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); 9118 7740 9119 7741 /* 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); 9124 7745 9125 7746 /* set left button down flag */ 9126 7747 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)) 9132 7756 { 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; 9138 7761 else 9139 LISTVIEW_SetSelection( hwnd, nItem);7762 LISTVIEW_SetSelection(infoPtr, nItem); 9140 7763 } 9141 7764 else … … 9144 7767 { 9145 7768 if (bGroupSelect) 9146 LISTVIEW_AddGroupSelection(hwnd, nItem); 7769 { 7770 LISTVIEW_AddGroupSelection(infoPtr, nItem); 7771 LISTVIEW_SetItemFocus(infoPtr, nItem); 7772 infoPtr->nSelectionMark = nItem; 7773 } 9147 7774 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 } 9149 7784 } 9150 7785 else if (wKey & MK_CONTROL) 9151 7786 { 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; 9153 7795 } 9154 7796 else if (wKey & MK_SHIFT) 9155 7797 { 9156 LISTVIEW_SetGroupSelection( hwnd, nItem);7798 LISTVIEW_SetGroupSelection(infoPtr, nItem); 9157 7799 } 9158 7800 else 9159 7801 { 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; 9162 7804 9163 7805 /* 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); 9168 7807 } 9169 7808 } … … 9172 7811 { 9173 7812 /* remove all selections */ 9174 LISTVIEW_ RemoveAllSelections(hwnd);7813 LISTVIEW_DeselectAll(infoPtr); 9175 7814 } 9176 7815 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 #endif9181 9182 /* redraw if we could have possibly selected something */9183 if(!GETITEMCOUNT(infoPtr)) InvalidateRect(hwnd, NULL, TRUE);9184 9185 7816 return 0; 9186 7817 } … … 9189 7820 * DESCRIPTION: 9190 7821 * 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 9197 7827 * 9198 7828 * RETURN: 9199 7829 * Zero 9200 7830 */ 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 { 7831 static LRESULT LISTVIEW_LButtonUp(LISTVIEW_INFO *infoPtr, WORD wKey, POINTS pts) 7832 { 9210 7833 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); 9231 7845 9232 7846 /* set left button flag */ 9233 7847 infoPtr->bLButtonDown = FALSE; 9234 7848 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 * 9260 7863 * RETURN: 9261 7864 * Zero 9262 7865 */ 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 7866 static LRESULT LISTVIEW_NCDestroy(LISTVIEW_INFO *infoPtr) 7867 { 7868 TRACE("()\n"); 9311 7869 9312 7870 /* delete all items */ 9313 LISTVIEW_DeleteAllItems( hwnd);7871 LISTVIEW_DeleteAllItems(infoPtr); 9314 7872 9315 7873 /* destroy data structure */ 9316 7874 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)) 9322 7882 { 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); 9324 7889 } 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); 9325 7897 9326 7898 /* free listview info pointer*/ 9327 7899 COMCTL32_Free(infoPtr); 9328 7900 9329 SetWindowLongW(hwnd, 0, 0);9330 7901 return 0; 9331 7902 } … … 9333 7904 /*** 9334 7905 * DESCRIPTION: 9335 * Handles notifications from children.9336 * 9337 * PARAMETER(S): 9338 * [I] HWND : window handle9339 * [I] INT: control identifier9340 * [I] LPNMHDR: notification information9341 * 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 * 9342 7913 * RETURN: 9343 7914 * Zero 9344 7915 */ 9345 static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh) 9346 { 9347 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0); 7916 static 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 */ 7999 static 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 */ 8021 static 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 */ 8064 static 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 */ 8094 static 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); 9348 8114 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 } 9360 8122 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 9414 8138 * 9415 8139 * RETURN: 9416 8140 * Zero 9417 8141 */ 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); 8142 static 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; 9514 8150 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 else9534 {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 else9549 {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 handle9566 * [I] WORD : key flag9567 * [I] WORD : x coordinate9568 * [I] WORD : y coordinate9569 *9570 * RETURN:9571 * Zero9572 */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 9587 8151 /* set button flag */ 9588 8152 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 9590 8160 /* Change to screen coordinate for WM_CONTEXTMENU */ 9591 ClientToScreen(hwnd, &pt); 9592 8161 pt = lvHitTestInfo.pt; 8162 ClientToScreen(infoPtr->hwndSelf, &pt); 8163 9593 8164 /* 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 */ 8186 static 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 9613 8209 * 9614 8210 * RETURN: 9615 8211 * Zero 9616 8212 */ 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 8213 static 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 9642 8243 * 9643 8244 * RETURN: 9644 8245 * Zero 9645 8246 */ 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. 8247 static 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. 9680 8269 * For the Listview, it invalidates the entire window (the doc specifies otherwise) 9681 * 9682 * PARAMETER(S): 9683 * [I] HWND : window handle8270 * 8271 * PARAMETER(S): 8272 * [I] infoPtr : valid pointer to the listview structure 9684 8273 * [I] bRedraw: state of redraw flag 9685 8274 * … … 9687 8276 * DefWinProc return value 9688 8277 */ 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; 8278 static 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; 9717 8298 } 9718 8299 … … 9721 8302 * Resizes the listview control. This function processes WM_SIZE 9722 8303 * messages. At this time, the width and height are not used. 9723 * 9724 * PARAMETER(S): 9725 * [I] HWND : window handle9726 * [I] W ORD: new width9727 * [I] WORD: new height8304 * 8305 * PARAMETER(S): 8306 * [I] infoPtr : valid pointer to the listview structure 8307 * [I] Width : new width 8308 * [I] Height : new height 9728 8309 * 9729 8310 * RETURN: 9730 8311 * Zero 9731 8312 */ 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 8313 static 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; 9758 8321 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); 9762 8335 9763 8336 return 0; … … 9767 8340 * DESCRIPTION: 9768 8341 * 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 */ 8349 static 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 = ℘ 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 */ 8399 static 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; 9784 8409 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 = ℘ 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 9848 8417 if (((lpss->styleOld & WS_HSCROLL) != 0)&& 9849 8418 ((lpss->styleNew & WS_HSCROLL) == 0)) 9850 ShowScrollBar( hwnd, SB_HORZ, FALSE);9851 8419 ShowScrollBar(infoPtr->hwndSelf, SB_HORZ, FALSE); 8420 9852 8421 if (((lpss->styleOld & WS_VSCROLL) != 0)&& 9853 8422 ((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 = ℘ 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 = ℘ 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); 9903 8468 9904 8469 /* update the size of the client area */ 9905 LISTVIEW_UpdateSize( hwnd);8470 LISTVIEW_UpdateSize(infoPtr); 9906 8471 9907 8472 /* add scrollbars if needed */ 9908 LISTVIEW_UpdateScroll( hwnd);9909 8473 LISTVIEW_UpdateScroll(infoPtr); 8474 9910 8475 /* 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 */ 8486 static LRESULT WINAPI 8487 LISTVIEW_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); 9915 8499 } 9916 9917 /* If they change the view and we have an active edit control9918 we will need to kill the control since the redraw will9919 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 size9950 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 } else9970 { //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 handle9992 * [O] LPLVMKBIMAGE : background image attributes9993 *9994 * RETURN:9995 * SUCCESS : TRUE9996 * 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 interface10005 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 interface10017 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 else10049 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 } else10095 {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 } else10182 {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 header10235 if (yScroll < 0)10236 { //up10237 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 } else10248 {10249 InvalidateRect(hwnd,&infoPtr->rcList,TRUE);10250 }10251 } else10252 { //down10253 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 DEBUG10460 void dprintfMsg(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)10461 {10462 char *msg = NULL;10463 8500 10464 8501 switch (uMsg) 10465 8502 { 10466 8503 case LVM_APPROXIMATEVIEWRECT: 10467 msg = "LVM_APPROXIMATEVIEWRECT";10468 break;8504 return LISTVIEW_ApproximateViewRect(infoPtr, (INT)wParam, 8505 LOWORD(lParam), HIWORD(lParam)); 10469 8506 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 10475 8513 case LVM_DELETEALLITEMS: 10476 msg = "LVM_DELETEALLITEMS";10477 break; 8514 return LISTVIEW_DeleteAllItems(infoPtr); 8515 10478 8516 case LVM_DELETECOLUMN: 10479 msg = "LVM_DELETECOLUMN";10480 break; 8517 return LISTVIEW_DeleteColumn(infoPtr, (INT)wParam); 8518 10481 8519 case LVM_DELETEITEM: 10482 msg = "LVM_DELETEITEM";10483 break; 8520 return LISTVIEW_DeleteItem(infoPtr, (INT)wParam); 8521 10484 8522 case LVM_EDITLABELW: 10485 msg = "LVM_EDITLABELW";10486 break; 8523 return (LRESULT)LISTVIEW_EditLabelT(infoPtr, (INT)wParam, TRUE); 8524 10487 8525 case LVM_EDITLABELA: 10488 msg = "LVM_EDITLABELA"; 10489 break; 8526 return (LRESULT)LISTVIEW_EditLabelT(infoPtr, (INT)wParam, FALSE); 8527 8528 /* case LVM_ENABLEGROUPVIEW: */ 8529 10490 8530 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 10493 8536 case LVM_FINDITEMA: 10494 msg = "LVM_FINDITEMA";10495 break; 8537 return LISTVIEW_FindItemA(infoPtr, (INT)wParam, (LPLVFINDINFOA)lParam); 8538 10496 8539 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 10505 8544 case LVM_GETCALLBACKMASK: 10506 msg = "LVM_GETCALLBACKMASK";10507 break; 8545 return infoPtr->uCallbackMask; 8546 10508 8547 case LVM_GETCOLUMNA: 10509 msg = "LVM_GETCOLUMNA";10510 break; 8548 return LISTVIEW_GetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, FALSE); 8549 10511 8550 case LVM_GETCOLUMNW: 10512 msg = "LVM_GETCOLUMNW";10513 break; 8551 return LISTVIEW_GetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, TRUE); 8552 10514 8553 case LVM_GETCOLUMNORDERARRAY: 10515 msg = "LVM_GETCOLUMNORDERARRAY";10516 break; 8554 return LISTVIEW_GetColumnOrderArray(infoPtr, (INT)wParam, (LPINT)lParam); 8555 10517 8556 case LVM_GETCOLUMNWIDTH: 10518 msg = "LVM_GETCOLUMNWIDTH";10519 break; 8557 return LISTVIEW_GetColumnWidth(infoPtr, (INT)wParam); 8558 10520 8559 case LVM_GETCOUNTPERPAGE: 10521 msg = "LVM_GETCOUNTPERPAGE";10522 break; 8560 return LISTVIEW_GetCountPerPage(infoPtr); 8561 10523 8562 case LVM_GETEDITCONTROL: 10524 msg = "LVM_GETEDITCONTROL";10525 break; 8563 return (LRESULT)infoPtr->hwndEdit; 8564 10526 8565 case LVM_GETEXTENDEDLISTVIEWSTYLE: 10527 msg = "LVM_GETEXTENDEDLISTVIEWSTYLE"; 10528 break; 8566 return infoPtr->dwLvExStyle; 8567 8568 /* case LVM_GETGROUPINFO: */ 8569 8570 /* case LVM_GETGROUPMETRICS: */ 8571 10529 8572 case LVM_GETHEADER: 10530 msg = "LVM_GETHEADER";10531 break; 8573 return (LRESULT)infoPtr->hwndHeader; 8574 10532 8575 case LVM_GETHOTCURSOR: 10533 msg = "LVM_GETHOTCURSOR";10534 break; 8576 return (LRESULT)infoPtr->hHotCursor; 8577 10535 8578 case LVM_GETHOTITEM: 10536 msg = "LVM_GETHOTITEM";10537 break; 8579 return infoPtr->nHotItem; 8580 10538 8581 case LVM_GETHOVERTIME: 10539 msg = "LVM_GETHOVERTIME";10540 break; 8582 return infoPtr->dwHoverTime; 8583 10541 8584 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 10544 8593 case LVM_GETISEARCHSTRINGA: 10545 msg = "LVM_GETISEARCHSTRINGA";10546 break;10547 8594 case LVM_GETISEARCHSTRINGW: 10548 msg = "LVM_GETISEARCHSTRINGW"; 10549 break; 8595 FIXME("LVM_GETISEARCHSTRING: unimplemented\n"); 8596 return FALSE; 8597 10550 8598 case LVM_GETITEMA: 10551 msg = "LVM_GETITEMA";10552 break; 8599 return LISTVIEW_GetItemExtT(infoPtr, (LPLVITEMW)lParam, FALSE); 8600 10553 8601 case LVM_GETITEMW: 10554 msg = "LVM_GETITEMW";10555 break; 8602 return LISTVIEW_GetItemExtT(infoPtr, (LPLVITEMW)lParam, TRUE); 8603 10556 8604 case LVM_GETITEMCOUNT: 10557 msg = "LVM_GETITEMCOUNT";10558 break; 8605 return infoPtr->nItemCount; 8606 10559 8607 case LVM_GETITEMPOSITION: 10560 msg = "LVM_GETITEMPOSITION";10561 break; 8608 return LISTVIEW_GetItemPosition(infoPtr, (INT)wParam, (LPPOINT)lParam); 8609 10562 8610 case LVM_GETITEMRECT: 10563 msg = "LVM_GETITEMRECT";10564 break; 8611 return LISTVIEW_GetItemRect(infoPtr, (INT)wParam, (LPRECT)lParam); 8612 10565 8613 case LVM_GETITEMSPACING: 10566 msg = "LVM_GETITEMSPACING";10567 break; 8614 return LISTVIEW_GetItemSpacing(infoPtr, (BOOL)wParam); 8615 10568 8616 case LVM_GETITEMSTATE: 10569 msg = "LVM_GETITEMSTATE";10570 break; 8617 return LISTVIEW_GetItemState(infoPtr, (INT)wParam, (UINT)lParam); 8618 10571 8619 case LVM_GETITEMTEXTA: 10572 msg = "LVM_GETITEMTEXTA";10573 break; 8620 return LISTVIEW_GetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam, FALSE); 8621 10574 8622 case LVM_GETITEMTEXTW: 10575 msg = "LVM_GETITEMTEXTW";10576 break; 8623 return LISTVIEW_GetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam, TRUE); 8624 10577 8625 case LVM_GETNEXTITEM: 10578 msg = "LVM_GETNEXTITEM";10579 break; 8626 return LISTVIEW_GetNextItem(infoPtr, (INT)wParam, LOWORD(lParam)); 8627 10580 8628 case LVM_GETNUMBEROFWORKAREAS: 10581 msg = "LVM_GETNUMBEROFWORKAREAS"; 10582 break; 8629 FIXME("LVM_GETNUMBEROFWORKAREAS: unimplemented\n"); 8630 return 1; 8631 10583 8632 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 10586 8641 case LVM_GETSELECTEDCOUNT: 10587 msg = "LVM_GETSELECTEDCOUNT";10588 break; 8642 return LISTVIEW_GetSelectedCount(infoPtr); 8643 10589 8644 case LVM_GETSELECTIONMARK: 10590 msg = "LVM_GETSELECTIONMARK";10591 break; 8645 return infoPtr->nSelectionMark; 8646 10592 8647 case LVM_GETSTRINGWIDTHA: 10593 msg = "LVM_GETSTRINGWIDTHA";10594 break; 8648 return LISTVIEW_GetStringWidthT(infoPtr, (LPCWSTR)lParam, FALSE); 8649 10595 8650 case LVM_GETSTRINGWIDTHW: 10596 msg = "LVM_GETSTRINGWIDTHW";10597 break; 8651 return LISTVIEW_GetStringWidthT(infoPtr, (LPCWSTR)lParam, TRUE); 8652 10598 8653 case LVM_GETSUBITEMRECT: 10599 msg = "LVM_GETSUBITEMRECT";10600 break; 8654 return LISTVIEW_GetSubItemRect(infoPtr, (UINT)wParam, (LPRECT)lParam); 8655 10601 8656 case LVM_GETTEXTBKCOLOR: 10602 msg = "LVM_GETTEXTBKCOLOR";10603 break; 8657 return infoPtr->clrTextBk; 8658 10604 8659 case LVM_GETTEXTCOLOR: 10605 msg = "LVM_GETTEXTCOLOR"; 10606 break; 8660 return infoPtr->clrText; 8661 8662 /* case LVM_GETTILEINFO: */ 8663 8664 /* case LVM_GETTILEVIEWINFO: */ 8665 10607 8666 case LVM_GETTOOLTIPS: 10608 msg = "LVM_GETTOOLTIPS";10609 break; 8667 return (LRESULT)infoPtr->hwndToolTip; 8668 10610 8669 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); 10922 8671 10923 8672 /*case LVM_GETUNICODEFORMAT: … … 10925 8674 return FALSE;*/ 10926 8675 8676 /* case LVM_GETVIEW: */ 8677 10927 8678 case LVM_GETVIEWRECT: 10928 return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam); 10929 10930 #ifdef __WIN32OS2__ 8679 return LISTVIEW_GetViewRect(infoPtr, (LPRECT)lParam); 8680 10931 8681 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: */ 10934 8686 10935 8687 case LVM_HITTEST: 10936 return LISTVIEW_HitTest( hwnd, (LPLVHITTESTINFO)lParam);8688 return LISTVIEW_HitTest(infoPtr, (LPLVHITTESTINFO)lParam, FALSE, FALSE); 10937 8689 10938 8690 case LVM_INSERTCOLUMNA: 10939 return LISTVIEW_InsertColumnT( hwnd, (INT)wParam, (LPLVCOLUMNW)lParam, FALSE);8691 return LISTVIEW_InsertColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, FALSE); 10940 8692 10941 8693 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: */ 10943 8699 10944 8700 case LVM_INSERTITEMA: 10945 return LISTVIEW_InsertItemT( hwnd, (LPLVITEMW)lParam, FALSE);8701 return LISTVIEW_InsertItemT(infoPtr, (LPLVITEMW)lParam, FALSE); 10946 8702 10947 8703 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: */ 10949 8717 10950 8718 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 10954 8725 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); 10960 8727 10961 8728 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: */ 10973 8732 10974 8733 case LVM_SETCALLBACKMASK: 10975 return LISTVIEW_SetCallbackMask(hwnd, (UINT)wParam); 8734 infoPtr->uCallbackMask = (UINT)wParam; 8735 return TRUE; 10976 8736 10977 8737 case LVM_SETCOLUMNA: 10978 return LISTVIEW_SetColumnT( hwnd, (INT)wParam, (LPLVCOLUMNW)lParam, FALSE);8738 return LISTVIEW_SetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, FALSE); 10979 8739 10980 8740 case LVM_SETCOLUMNW: 10981 return LISTVIEW_SetColumnT( hwnd, (INT)wParam, (LPLVCOLUMNW)lParam, TRUE);8741 return LISTVIEW_SetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, TRUE); 10982 8742 10983 8743 case LVM_SETCOLUMNORDERARRAY: 10984 return LISTVIEW_SetColumnOrderArray( hwnd, (INT)wParam, (LPINT)lParam);8744 return LISTVIEW_SetColumnOrderArray(infoPtr, (INT)wParam, (LPINT)lParam); 10985 8745 10986 8746 case LVM_SETCOLUMNWIDTH: 10987 return LISTVIEW_SetColumnWidth( hwnd, (INT)wParam, SLOWORD(lParam));8747 return LISTVIEW_SetColumnWidth(infoPtr, (INT)wParam, SLOWORD(lParam)); 10988 8748 10989 8749 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 10993 8756 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); 10998 8758 10999 8759 case LVM_SETHOTITEM: 11000 return LISTVIEW_SetHotItem( hwnd, (INT)wParam);8760 return LISTVIEW_SetHotItem(infoPtr, (INT)wParam); 11001 8761 11002 8762 case LVM_SETHOVERTIME: 11003 return LISTVIEW_SetHoverTime( hwnd, (DWORD)wParam);11004 #ifdef __WIN32OS2__ 8763 return LISTVIEW_SetHoverTime(infoPtr, (DWORD)wParam); 8764 11005 8765 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 11011 8768 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: */ 11013 8776 11014 8777 case LVM_SETITEMA: 11015 return LISTVIEW_SetItemT( hwnd, (LPLVITEMW)lParam, FALSE);8778 return LISTVIEW_SetItemT(infoPtr, (LPLVITEMW)lParam, FALSE); 11016 8779 11017 8780 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 11023 8786 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 } 11026 8791 11027 8792 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)); 11030 8795 11031 8796 case LVM_SETITEMSTATE: 11032 return LISTVIEW_SetItemState( hwnd, (INT)wParam, (LPLVITEMW)lParam);8797 return LISTVIEW_SetItemState(infoPtr, (INT)wParam, (LPLVITEMW)lParam); 11033 8798 11034 8799 case LVM_SETITEMTEXTA: 11035 return LISTVIEW_SetItemTextT( hwnd, (INT)wParam, (LPLVITEMW)lParam, FALSE);8800 return LISTVIEW_SetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam, FALSE); 11036 8801 11037 8802 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: */ 11039 8808 11040 8809 case LVM_SETSELECTIONMARK: 11041 return LISTVIEW_SetSelectionMark( hwnd, (INT)lParam);8810 return LISTVIEW_SetSelectionMark(infoPtr, (INT)lParam); 11042 8811 11043 8812 case LVM_SETTEXTBKCOLOR: 11044 return LISTVIEW_SetTextBkColor( hwnd, (COLORREF)lParam);8813 return LISTVIEW_SetTextBkColor(infoPtr, (COLORREF)lParam); 11045 8814 11046 8815 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 11050 8824 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: */ 11060 8834 11061 8835 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 11065 8840 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); 11073 8845 11074 8846 case WM_CHAR: 11075 return LISTVIEW_ProcessLetterKeys( hwnd, wParam, lParam );8847 return LISTVIEW_ProcessLetterKeys( infoPtr, wParam, lParam ); 11076 8848 11077 8849 case WM_COMMAND: 11078 return LISTVIEW_Command( hwnd, wParam, lParam);8850 return LISTVIEW_Command(infoPtr, wParam, lParam); 11079 8851 11080 8852 case WM_CREATE: 11081 8853 return LISTVIEW_Create(hwnd, (LPCREATESTRUCTW)lParam); 11082 8854 11083 8855 case WM_ERASEBKGND: 11084 return LISTVIEW_EraseB ackground(hwnd, wParam, lParam);8856 return LISTVIEW_EraseBkgnd(infoPtr, (HDC)wParam); 11085 8857 11086 8858 case WM_GETDLGCODE: … … 11088 8860 11089 8861 case WM_GETFONT: 11090 return LISTVIEW_GetFont(hwnd);8862 return (LRESULT)infoPtr->hFont; 11091 8863 11092 8864 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); 11095 8866 11096 8867 case WM_KEYDOWN: 11097 return LISTVIEW_KeyDown( hwnd, (INT)wParam, (LONG)lParam);8868 return LISTVIEW_KeyDown(infoPtr, (INT)wParam, (LONG)lParam); 11098 8869 11099 8870 case WM_KILLFOCUS: 11100 return LISTVIEW_KillFocus( hwnd);8871 return LISTVIEW_KillFocus(infoPtr); 11101 8872 11102 8873 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 11106 8876 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 11109 8879 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 11112 8882 case WM_MOUSEMOVE: 11113 return LISTVIEW_MouseMove ( hwnd, wParam, lParam);8883 return LISTVIEW_MouseMove (infoPtr, (WORD)wParam, MAKEPOINTS(lParam)); 11114 8884 11115 8885 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)); 11120 8887 11121 8888 case WM_NCDESTROY: 11122 return LISTVIEW_NCDestroy( hwnd);8889 return LISTVIEW_NCDestroy(infoPtr); 11123 8890 11124 8891 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; 11126 8895 11127 8896 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); 11132 8901 11133 8902 case WM_RBUTTONDBLCLK: 11134 return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam), 11135 HIWORD(lParam)); 8903 return LISTVIEW_RButtonDblClk(infoPtr, (WORD)wParam, MAKEPOINTS(lParam)); 11136 8904 11137 8905 case WM_RBUTTONDOWN: 11138 return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam), 11139 HIWORD(lParam)); 8906 return LISTVIEW_RButtonDown(infoPtr, (WORD)wParam, MAKEPOINTS(lParam)); 11140 8907 11141 8908 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; 11144 8915 11145 8916 case WM_SETFOCUS: 11146 return LISTVIEW_SetFocus( hwnd, (HWND)wParam);8917 return LISTVIEW_SetFocus(infoPtr, (HWND)wParam); 11147 8918 11148 8919 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); 11153 8924 11154 8925 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)); 11156 8927 11157 8928 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; 11164 8934 11165 8935 /* case WM_TIMER: */ 11166 8936 11167 8937 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); 11170 8939 11171 8940 case WM_MOUSEWHEEL: 11172 8941 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); 11175 8954 11176 8955 /* case WM_WININICHANGE: */ 11177 8956 11178 8957 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); 11189 8964 } 11190 8965 … … 11195 8970 * DESCRIPTION: 11196 8971 * Registers the window class. 11197 * 8972 * 11198 8973 * PARAMETER(S): 11199 8974 * None … … 11202 8977 * None 11203 8978 */ 11204 VOIDLISTVIEW_Register(void)11205 { 11206 WNDCLASSW wndClass;8979 void LISTVIEW_Register(void) 8980 { 8981 WNDCLASSW wndClass; 11207 8982 11208 8983 ZeroMemory(&wndClass, sizeof(WNDCLASSW)); … … 11220 8995 * DESCRIPTION: 11221 8996 * Unregisters the window class. 11222 * 8997 * 11223 8998 * PARAMETER(S): 11224 8999 * None … … 11227 9002 * None 11228 9003 */ 11229 VOIDLISTVIEW_Unregister(void)11230 { 11231 UnregisterClassW(WC_LISTVIEWW, (HINSTANCE)NULL);9004 void LISTVIEW_Unregister(void) 9005 { 9006 UnregisterClassW(WC_LISTVIEWW, NULL); 11232 9007 } 11233 9008 … … 11235 9010 * DESCRIPTION: 11236 9011 * 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 */ 9021 static LRESULT LISTVIEW_Command(LISTVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 11243 9022 { 11244 9023 switch (HIWORD(wParam)) … … 11246 9025 case EN_UPDATE: 11247 9026 { 11248 /* 11249 * Adjust the edit window size 9027 /* 9028 * Adjust the edit window size 11250 9029 */ 11251 9030 WCHAR buffer[1024]; 11252 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0); 11253 HDC hdc = GetDC(infoPtr->hwndEdit); 9031 HDC hdc = GetDC(infoPtr->hwndEdit); 11254 9032 HFONT hFont, hOldFont = 0; 11255 9033 RECT rect; … … 11257 9035 int len; 11258 9036 9037 if (!infoPtr->hwndEdit || !hdc) return 0; 11259 9038 len = GetWindowTextW(infoPtr->hwndEdit, buffer, sizeof(buffer)/sizeof(buffer[0])); 11260 9039 GetWindowRect(infoPtr->hwndEdit, &rect); 11261 9040 11262 9041 /* 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); 11264 9043 if(hFont != 0) 11265 9044 { … … 11275 9054 sz.cx += (textMetric.tmMaxCharWidth * 2); 11276 9055 11277 SetWindowPos ( 9056 SetWindowPos ( 11278 9057 infoPtr->hwndEdit, 11279 HWND_TOP, 11280 0, 9058 HWND_TOP, 9059 0, 11281 9060 0, 11282 9061 sz.cx, … … 11287 9066 SelectObject(hdc, hOldFont); 11288 9067 11289 ReleaseDC( hwnd, hdc);9068 ReleaseDC(infoPtr->hwndSelf, hdc); 11290 9069 11291 9070 break; … … 11293 9072 11294 9073 default: 11295 return SendMessageW (GetParent ( hwnd), WM_COMMAND, wParam, lParam);9074 return SendMessageW (GetParent (infoPtr->hwndSelf), WM_COMMAND, wParam, lParam); 11296 9075 } 11297 9076 … … 11305 9084 * 11306 9085 * 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 */ 9095 static LRESULT EditLblWndProcT(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL isW) 11312 9096 { 11313 9097 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(GetParent(hwnd), 0); 11314 EDITLABEL_ITEM *einfo = infoPtr->pedititem;11315 static BOOL bIgnoreKillFocus = FALSE;11316 9098 BOOL cancel = FALSE; 11317 9099 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", 11319 9101 hwnd, uMsg, wParam, lParam, isW); 11320 9102 11321 9103 switch (uMsg) 11322 9104 { 11323 9105 case WM_GETDLGCODE: 11324 9106 return DLGC_WANTARROWS | DLGC_WANTALLKEYS; 11325 9107 11326 9108 case WM_KILLFOCUS: 11327 if(bIgnoreKillFocus) return TRUE;11328 9109 break; 11329 9110 11330 9111 case WM_DESTROY: 11331 9112 { 11332 WNDPROC editProc = einfo->EditWndProc; 9113 WNDPROC editProc = infoPtr->EditWndProc; 9114 infoPtr->EditWndProc = 0; 11333 9115 SetWindowLongW(hwnd, GWL_WNDPROC, (LONG)editProc); 11334 COMCTL32_Free(einfo);11335 infoPtr->pedititem = NULL;11336 9116 return CallWindowProcT(editProc, hwnd, uMsg, wParam, lParam, isW); 11337 9117 } … … 11347 9127 11348 9128 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) 11353 9134 { 11354 9135 LPWSTR buffer = NULL; 11355 9136 9137 infoPtr->hwndEdit = 0; 11356 9138 if (!cancel) 11357 9139 { … … 11367 9149 } 11368 9150 } 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); 11373 9152 11374 9153 if (buffer) COMCTL32_Free(buffer); 11375 9154 11376 einfo->EditLblCb = NULL;11377 bIgnoreKillFocus = FALSE;11378 9155 } 11379 9156 11380 9157 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 11389 9170 * 11390 9171 * RETURN: … … 11397 9178 /*** 11398 9179 * 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 11402 9187 * 11403 9188 * RETURN: … … 11413 9198 * 11414 9199 * 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 */ 9207 static HWND CreateEditLabelT(LISTVIEW_INFO *infoPtr, LPCWSTR text, DWORD style, 9208 INT x, INT y, INT width, INT height, BOOL isW) 9209 { 11423 9210 WCHAR editName[5] = { 'E', 'd', 'i', 't', '\0' }; 11424 9211 HWND hedit; … … 11427 9214 HDC hOldFont=0; 11428 9215 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); 11434 9219 11435 9220 style |= WS_CHILDWINDOW|WS_CLIPSIBLINGS|ES_LEFT|WS_BORDER; 11436 hdc = GetDC( parent);9221 hdc = GetDC(infoPtr->hwndSelf); 11437 9222 11438 9223 /* Select the font to get appropriate metric dimensions */ … … 11450 9235 SelectObject(hdc, hOldFont); 11451 9236 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); 11455 9240 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) 11467 9246 (isW ? SetWindowLongW(hedit, GWL_WNDPROC, (LONG)EditLblWndProcW) : 11468 9247 SetWindowLongA(hedit, GWL_WNDPROC, (LONG)EditLblWndProcA) ); 11469 9248 11470 SendMessageW(hedit, WM_SETFONT, infoPtr->hFont, FALSE);9249 SendMessageW(hedit, WM_SETFONT, (WPARAM)infoPtr->hFont, FALSE); 11471 9250 11472 9251 return hedit; 11473 9252 } 11474
Note:
See TracChangeset
for help on using the changeset viewer.