Changeset 3585 for trunk/src/comctl32/treeview.cpp
- Timestamp:
- May 22, 2000, 7:25:13 PM (25 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/comctl32/treeview.cpp
r3520 r3585 1 /* $Id: treeview.cpp,v 1.1 3 2000-05-10 19:50:33 cbratschi Exp $ */1 /* $Id: treeview.cpp,v 1.14 2000-05-22 17:25:13 cbratschi Exp $ */ 2 2 /* Treeview control 3 3 * … … 8 8 * Copyright 1999-2000 Christoph Bratschi (cbratschi@datacomm.ch) 9 9 * 10 * Note that TREEVIEW_INFO * and HTREEITEM are the same thing. 10 11 * 11 * FIXMEs (for personal use)12 Expand: -ctlmacro expands twice ->toggle.13 -DblClick: ctlmacro.exe's NM_DBLCLK seems to go wrong (returns FALSE).14 -treehelper: stack corruption makes big window.15 12 * 16 13 * Status: complete (many things untested) … … 30 27 - expand not finished 31 28 - WM_ENABLE: draw disabled control 29 - AMD cpuid: text not drawn (> treeview.cpp,v 1.13 2000/05/10 19:50:33) 30 t1: GDI32: SetBkColor to FFFFFF 31 t1: GDI32: GetTextMetricsA returned 1 32 t1: GDI32: SetTextAlign 33 --> 34 t1: GDI32: RestoreDC 35 t1: SendInternalMessageA WM_NOTIFY for 68000003 65 1312e4 36 t1: USER32: GetDlgCtrlID 37 38 missing lines at -->: 39 t1: GDI32: GetTextExtentPoint32A 10001a1 Processor Speed Test 20 returned 1 (93,14) 40 t1: GDI32: ExtTextOutA 10001a1 Processor Speed Test 41 t1: GDI32: GetTextAlign 42 t1: GDI32: GetTextExtentPoint32A 10001a1 454 Mhz 7 returned 1 (37,14) 43 t1: GDI32: ExtTextOutA 10001a1 454 Mhz 44 t1: GDI32: GetTextAlign 45 46 don't know why it fails 32 47 */ 33 48 49 #include <assert.h> 34 50 #include <stdlib.h> 35 51 #include <string.h> 36 52 #include <math.h> 53 #include <limits.h> 37 54 #include "winbase.h" 38 55 #include "wingdi.h" … … 45 62 /* ffs should be in <string.h>. */ 46 63 47 //#define OS2LINEHACK //CB: too slow, but looks good 48 49 /* Defines, since they do not need to return previous state, and nr 50 * has no side effects in this file. 64 //#define NDEBUG 65 #define NDEBUG_TEXT 66 67 #define TEXT_CALLBACK_SIZE 260 68 69 #define TREEVIEW_LEFT_MARGIN 8 70 71 #define MINIMUM_INDENT 19 72 73 #define CALLBACK_MASK_ALL (TVIF_TEXT|TVIF_CHILDREN|TVIF_IMAGE|TVIF_SELECTEDIMAGE) 74 75 #define STATEIMAGEINDEX(x) (((x) >> 12) & 0x0f) 76 #define OVERLAYIMAGEINDEX(x) (((x) >> 8) & 0x0f) 77 78 typedef VOID (*TREEVIEW_ItemEnumFunc)(TREEVIEW_INFO *, TREEVIEW_ITEM *,LPVOID); 79 80 static BOOL TREEVIEW_UnqueueRefresh(TREEVIEW_INFO *,BOOL calc,BOOL refresh); 81 static void TREEVIEW_QueueRefresh(TREEVIEW_INFO *); 82 static void TREEVIEW_Refresh(TREEVIEW_INFO *infoPtr); 83 static void TREEVIEW_RefreshItem(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item,DWORD changed); 84 85 static VOID TREEVIEW_HideInfoTip(TREEVIEW_INFO *infoPtr); 86 static LRESULT TREEVIEW_DoSelectItem(TREEVIEW_INFO *, INT, HTREEITEM, INT); 87 static LRESULT TREEVIEW_EnsureVisible(TREEVIEW_INFO *, HTREEITEM); 88 static LRESULT TREEVIEW_RButtonUp(TREEVIEW_INFO *, LPPOINT); 89 static LRESULT TREEVIEW_EndEditLabelNow(TREEVIEW_INFO *infoPtr, BOOL bCancel); 90 static VOID TREEVIEW_UpdateScrollBars(TREEVIEW_INFO *infoPtr, BOOL); 91 static VOID TREEVIEW_CheckInfoTip(TREEVIEW_INFO *infoPtr); 92 static VOID TREEVIEW_ISearch(TREEVIEW_INFO *infoPtr,CHAR ch); 93 94 /* Random Utilities *****************************************************/ 95 96 #ifdef NDEBUG 97 static inline void 98 TREEVIEW_VerifyTree(TREEVIEW_INFO *infoPtr) 99 { 100 (void)infoPtr; 101 } 102 103 #else 104 /* The definition is at the end of the file. */ 105 static void TREEVIEW_VerifyTree(TREEVIEW_INFO *infoPtr); 106 #ifndef NDEBUG_TEXT 107 static void TREEVIEW_WriteVerify(CHAR *text) 108 { 109 dprintf((text)); 110 } 111 #else 112 static inline void TREEVIEW_WriteVerify(CHAR * text) {} 113 #endif 114 #endif 115 116 /* Returns the treeview private data if hwnd is a treeview. 117 * Otherwise returns an undefined value. */ 118 #define TREEVIEW_GetInfoPtr(hwnd) ((TREEVIEW_INFO *)getInfoPtr(hwnd)) 119 120 /* Don't call this. Nothing wants an item index. */ 121 static inline int 122 TREEVIEW_GetItemIndex(TREEVIEW_INFO *infoPtr, HTREEITEM handle) 123 { 124 assert(infoPtr != NULL); 125 126 return DPA_GetPtrIndex(infoPtr->items,handle); 127 } 128 129 /*************************************************************************** 130 * This method checks that handle is an item for this tree. 51 131 */ 52 #define tv_test_bit(nr,bf) (((LPBYTE)bf)[nr>>3]&(1<<(nr&7))) 53 #define tv_set_bit(nr,bf) ((LPBYTE)bf)[nr>>3]|=(1<<(nr&7)) 54 #define tv_clear_bit(nr,bf) ((LPBYTE)bf)[nr>>3]&=~(1<<(nr&7)) 55 56 #define TREEVIEW_GetInfoPtr(hwnd) ((TREEVIEW_INFO *)getInfoPtr(hwnd)) 57 58 static BOOL TREEVIEW_SendTreeviewNotify (HWND hwnd, UINT code, UINT action, HTREEITEM oldItem, HTREEITEM newItem); 59 static BOOL TREEVIEW_SendTreeviewDnDNotify (HWND hwnd, UINT code, HTREEITEM dragItem, POINT pt); 60 static INT TREEVIEW_CallbackChildren(HWND hwnd,TREEVIEW_ITEM *wineItem); 61 static INT TREEVIEW_CallbackImage(HWND hwnd,TREEVIEW_ITEM *wineItem); 62 static INT TREEVIEW_CallbackSelectedImage(HWND hwnd,TREEVIEW_ITEM *wineItem); 63 static WCHAR* TREEVIEW_CallbackText(HWND hwnd,TREEVIEW_ITEM *wineItem,BOOL *mustFree); 64 static BOOL TREEVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc, RECT rc); 65 static BOOL TREEVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc, TREEVIEW_ITEM *tvItem, UINT uItemDrawState); 66 static LRESULT TREEVIEW_RButtonUp (HWND hwnd, LPPOINT pPt); 67 static LRESULT TREEVIEW_SelectItem (HWND hwnd, WPARAM wParam, LPARAM lParam); 68 static LRESULT TREEVIEW_DoSelectItem(HWND hwnd,INT action,HTREEITEM newSelect,INT cause); 69 static void TREEVIEW_Refresh(HWND hwnd); 70 static void TREEVIEW_RefreshItem(HWND hwnd,TREEVIEW_ITEM *item,BOOL wholeLine); 71 static void TREEVIEW_Draw(HWND hwnd,HDC hdc,RECT *updateRect); 72 static BOOL TREEVIEW_UnqueueRefresh(HWND hwnd,BOOL calc,BOOL refresh); 73 static void TREEVIEW_QueueRefresh(HWND hwnd); 74 static void TREEVIEW_CalcItem(HWND hwnd,HDC hdc,DWORD dwStyle,TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item); 75 static BOOL TREEVIEW_CalcItems(HWND hwnd,HDC hdc,TREEVIEW_INFO *infoPtr); 76 static LRESULT TREEVIEW_EnsureVisible(HWND hwnd,HTREEITEM hItem); 77 static VOID TREEVIEW_ISearch(HWND hwnd,CHAR ch); 78 static VOID TREEVIEW_CheckInfoTip(HWND hwnd); 79 static VOID TREEVIEW_HideInfoTip(HWND hwnd,TREEVIEW_INFO *infoPtr); 80 81 static LRESULT CALLBACK TREEVIEW_Edit_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 82 83 LRESULT WINAPI TREEVIEW_EndEditLabelNow (HWND hwnd, BOOL bCancel); 84 85 HWND TREEVIEW_EditLabel(HWND hwnd, HTREEITEM hItem,BOOL unicode); 86 87 /* helper functions. Work with the assumption that validity of operands 88 is checked beforehand, and that tree state is valid. */ 89 90 /* FIXME: MS documentation says `GetNextVisibleItem' returns NULL 91 if not succesfull'. Probably only applies to derefencing infoPtr 92 (ie we are offered a valid treeview structure) 93 and not whether there is a next `visible' child. 94 FIXME: check other failures. 132 static BOOL 133 TREEVIEW_ValidItem(TREEVIEW_INFO *infoPtr,HTREEITEM handle) 134 { 135 if (TREEVIEW_GetItemIndex(infoPtr, handle) == -1) 136 { 137 //TRACE("invalid item %p\n", handle); 138 return FALSE; 139 } 140 else 141 return TRUE; 142 } 143 144 static HFONT 145 TREEVIEW_CreateBoldFont(HFONT hOrigFont) 146 { 147 LOGFONTA font; 148 149 GetObjectA(hOrigFont, sizeof(font), &font); 150 font.lfWeight = FW_BOLD; 151 152 return CreateFontIndirectA(&font); 153 } 154 155 static inline HFONT 156 TREEVIEW_FontForItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) 157 { 158 return (item->state & TVIS_BOLD) ? infoPtr->hBoldFont : infoPtr->hFont; 159 } 160 161 /* for trace/debugging purposes only */ 162 static const WCHAR * 163 TREEVIEW_ItemName(TREEVIEW_ITEM *item) 164 { 165 if (item == NULL) return (WCHAR*)L"<null item>"; 166 if (item->pszText == LPSTR_TEXTCALLBACKW) return (WCHAR*)L"<callback>"; 167 if (item->pszText == NULL) return (WCHAR*)L"<null>"; 168 /* It would be nice to check item->callbackMask & TVIF_TEXT here, 169 * and indicate that this is a callback string, but there is nowhere 170 * to put that indication. (Or we could be clever, and put it before 171 * pszText, but that is just too hacky.) */ 172 return item->pszText; 173 } 174 175 /* An item is not a child of itself. */ 176 static BOOL 177 TREEVIEW_IsChildOf(TREEVIEW_ITEM *parent, TREEVIEW_ITEM *child) 178 { 179 do 180 { 181 child = child->parent; 182 if (child == parent) return TRUE; 183 } while (child != NULL); 184 185 return FALSE; 186 } 187 188 /* Tree Traversal *******************************************************/ 189 190 /*************************************************************************** 191 * This method returns the last expanded sibling or child child item 192 * of a tree node 95 193 */ 194 static TREEVIEW_ITEM * 195 TREEVIEW_GetLastListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem) 196 { 197 /* 198 * Get this item's last sibling 199 */ 200 while (wineItem->nextSibling) 201 wineItem = wineItem->nextSibling; 202 203 /* 204 * If the last sibling has expanded children, restart. 205 */ 206 if ((wineItem->state & TVIS_EXPANDED) && wineItem->firstChild != NULL) 207 { 208 return TREEVIEW_GetLastListItem(infoPtr, wineItem->firstChild); 209 } 210 211 return wineItem; 212 } 96 213 97 214 /*************************************************************************** 98 * This method returns the TREEVIEW_ITEM object given the handle 99 */ 100 static TREEVIEW_ITEM* TREEVIEW_ValidItem( 101 TREEVIEW_INFO *infoPtr, 102 HTREEITEM handle) 103 { 104 if ((!handle) || (handle>infoPtr->uMaxHandle)) 105 return NULL; 106 107 if (tv_test_bit ((INT)handle, infoPtr->freeList)) 108 return NULL; 109 110 return &infoPtr->items[(INT)handle]; 111 } 112 113 /*************************************************************************** 114 * This function uses cChildren field to decide whether item has children 115 * or not. 116 * Note: return value doesn't reflect physical presence of children. 117 */ 118 static INT TREEVIEW_HasChildren( 119 HWND hwnd, 120 TREEVIEW_ITEM *wineItem) 121 { 122 INT cChildren = 0; 123 124 if ( wineItem->mask & TVIF_CHILDREN ) 125 { 126 if (wineItem->cChildren == I_CHILDRENCALLBACK) 127 cChildren = TREEVIEW_CallbackChildren(hwnd,wineItem); 128 else 129 cChildren = wineItem->cChildren; 130 } 131 else if ( wineItem->firstChild ) 132 cChildren = 1; 133 134 return cChildren; 135 } 136 137 /*************************************************************************** 138 * This method returns the last expanded child item of a tree node 139 */ 140 static TREEVIEW_ITEM *TREEVIEW_GetLastListItem( 141 HWND hwnd, 142 TREEVIEW_INFO *infoPtr, 143 TREEVIEW_ITEM *tvItem) 144 { 145 TREEVIEW_ITEM *wineItem = tvItem; 146 147 /* 148 * Get this item last sibling 149 */ 150 while (wineItem->sibling) 151 wineItem=& infoPtr->items [(INT)wineItem->sibling]; 152 153 /* 154 * If the last sibling has expanded children, restart. 155 */ 156 if ((wineItem->state & TVIS_EXPANDED) && 157 TREEVIEW_HasChildren(hwnd, wineItem)) 158 { 159 return TREEVIEW_GetLastListItem( 160 hwnd, 161 infoPtr, 162 &(infoPtr->items[(INT)wineItem->firstChild])); 163 } 164 165 return wineItem; 166 } 167 168 /*************************************************************************** 169 * This method returns the previous physical item in the list not 215 * This method returns the previous non-hidden item in the list not 170 216 * considering the tree hierarchy. 171 217 */ 172 static TREEVIEW_ITEM *TREEVIEW_GetPrevListItem( 173 HWND hwnd, 174 TREEVIEW_INFO *infoPtr, 175 TREEVIEW_ITEM *tvItem) 176 { 177 if (tvItem->upsibling) 178 { 179 /* 180 * This item has a upsibling, get the last item. Since, GetLastListItem 181 * first looks at siblings, we must feed it with the first child. 182 */ 183 TREEVIEW_ITEM *upItem = &infoPtr->items[(INT)tvItem->upsibling]; 184 185 if ( (upItem->state & TVIS_EXPANDED) && 186 TREEVIEW_HasChildren(hwnd, upItem) ) 187 { 188 return TREEVIEW_GetLastListItem( 189 hwnd, 190 infoPtr, 191 &infoPtr->items[(INT)upItem->firstChild]); 218 static TREEVIEW_ITEM * 219 TREEVIEW_GetPrevListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *tvItem) 220 { 221 if (tvItem->prevSibling) 222 { 223 /* 224 * This item has a prevSibling, get the last item. Since 225 * GetLastListItem first looks at siblings, we must feed it with the 226 * first child. 227 */ 228 TREEVIEW_ITEM *upItem = tvItem->prevSibling; 229 230 if ((upItem->state & TVIS_EXPANDED) && upItem->firstChild != NULL) 231 return TREEVIEW_GetLastListItem(infoPtr, upItem->firstChild); 232 else 233 return upItem; 192 234 } 193 235 else 194 return upItem; 195 } 196 else 197 { 198 /* 199 * this item does not have a upsibling, get the parent 200 */ 201 if (tvItem->parent) 202 return &infoPtr->items[(INT)tvItem->parent]; 203 } 204 205 return NULL; 236 { 237 /* 238 * this item does not have a prevSibling, get the parent 239 */ 240 return (tvItem->parent != infoPtr->root) ? tvItem->parent : NULL; 241 } 206 242 } 207 243 … … 211 247 * considering the tree hierarchy. 212 248 */ 213 static TREEVIEW_ITEM *TREEVIEW_GetNextListItem( 214 HWND hwnd, 215 TREEVIEW_INFO *infoPtr, 216 TREEVIEW_ITEM *tvItem) 217 { 218 TREEVIEW_ITEM *wineItem = NULL; 219 220 /* 221 * If this item has children and is expanded, return the first child 222 */ 223 if ( (tvItem->state & TVIS_EXPANDED) && 224 TREEVIEW_HasChildren(hwnd, tvItem) ) 225 { 226 return (& infoPtr->items[(INT)tvItem->firstChild]); 227 } 228 229 230 /* 231 * try to get the sibling 232 */ 233 if (tvItem->sibling) 234 return (& infoPtr->items[(INT)tvItem->sibling]); 235 236 /* 237 * Otherwise, get the parent's sibling. 238 */ 239 wineItem=tvItem; 240 while (wineItem->parent) { 241 wineItem=& infoPtr->items [(INT)wineItem->parent]; 242 if (wineItem->sibling) 243 return (& infoPtr->items [(INT)wineItem->sibling]); 244 } 245 246 return NULL; 249 static TREEVIEW_ITEM * 250 TREEVIEW_GetNextListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *tvItem) 251 { 252 assert(infoPtr != NULL); 253 assert(tvItem != NULL); 254 255 /* 256 * If this item has children and is expanded, return the first child 257 */ 258 if ((tvItem->state & TVIS_EXPANDED) && tvItem->firstChild != NULL) 259 { 260 return tvItem->firstChild; 261 } 262 263 264 /* 265 * try to get the sibling 266 */ 267 if (tvItem->nextSibling) 268 return tvItem->nextSibling; 269 270 /* 271 * Otherwise, get the parent's sibling. 272 */ 273 while (tvItem->parent) 274 { 275 tvItem = tvItem->parent; 276 277 if (tvItem->nextSibling) 278 return tvItem->nextSibling; 279 } 280 281 return NULL; 247 282 } 248 283 … … 254 289 * forward if count is >0. 255 290 */ 256 static TREEVIEW_ITEM *TREEVIEW_GetListItem( 257 HWND hwnd, 258 TREEVIEW_INFO *infoPtr, 259 TREEVIEW_ITEM *tvItem, 260 LONG count) 261 { 262 TREEVIEW_ITEM *previousItem = NULL; 263 TREEVIEW_ITEM *wineItem = tvItem; 264 LONG iter = 0; 265 266 if (count > 0) 267 { 268 /* Find count item downward */ 269 while ((iter++ < count) && (wineItem != NULL)) 270 { 271 /* Keep a pointer to the previous in case we ask for more than we got */ 272 previousItem = wineItem; 273 wineItem = TREEVIEW_GetNextListItem(hwnd,infoPtr,wineItem); 274 } 275 276 if (wineItem == NULL) 277 wineItem = previousItem; 278 } 279 else if (count < 0) 280 { 281 /* Find count item upward */ 282 while ((iter-- > count) && (wineItem != NULL)) 283 { 284 /* Keep a pointer to the previous in case we ask for more than we got */ 285 previousItem = wineItem; 286 wineItem = TREEVIEW_GetPrevListItem(hwnd,infoPtr,wineItem); 287 } 288 289 if (wineItem == NULL) 290 wineItem = previousItem; 291 } 292 else 293 wineItem = NULL; 294 295 return wineItem; 296 } 297 291 static TREEVIEW_ITEM * 292 TREEVIEW_GetListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, 293 LONG count) 294 { 295 TREEVIEW_ITEM *(*next_item)(TREEVIEW_INFO *, TREEVIEW_ITEM *); 296 TREEVIEW_ITEM *previousItem; 297 298 assert(wineItem != NULL); 299 300 if (count > 0) 301 { 302 next_item = TREEVIEW_GetNextListItem; 303 } 304 else if (count < 0) 305 { 306 count = -count; 307 next_item = TREEVIEW_GetPrevListItem; 308 } 309 else 310 return wineItem; 311 312 do 313 { 314 previousItem = wineItem; 315 wineItem = next_item(infoPtr, wineItem); 316 317 } while (--count && wineItem != NULL); 318 319 320 return wineItem ? wineItem : previousItem; 321 } 322 323 static VOID 324 TREEVIEW_ForEachDisplayed(TREEVIEW_INFO *infoPtr,TREEVIEW_ItemEnumFunc func,LPVOID data) 325 { 326 TREEVIEW_ITEM *item; 327 328 for (item = infoPtr->root->firstChild; item != NULL; 329 item = TREEVIEW_GetNextListItem(infoPtr, item)) 330 { 331 func(infoPtr, item, data); 332 } 333 } 334 335 /* Notifications */ 336 337 static VOID 338 TREEVIEW_TVItemFromItem(UINT mask,TVITEMW *tvItem,TREEVIEW_ITEM *item) 339 { 340 tvItem->mask = mask; 341 tvItem->hItem = item; 342 tvItem->state = item->state; 343 tvItem->stateMask = 0; 344 tvItem->iImage = item->iImage; 345 tvItem->pszText = item->pszText; 346 tvItem->cchTextMax = item->cchTextMax; 347 tvItem->iImage = item->iImage; 348 tvItem->iSelectedImage = item->iSelectedImage; 349 tvItem->cChildren = item->cChildren; 350 tvItem->lParam = item->lParam; 351 } 352 353 static BOOL TREEVIEW_SendTreeviewNotify(TREEVIEW_INFO *infoPtr,UINT code,UINT action,UINT mask,HTREEITEM oldItem,HTREEITEM newItem) 354 { 355 NMTREEVIEWW nmhdr; 356 CHAR *oldText = NULL,*newText = NULL; 357 BOOL rc; 358 359 ZeroMemory(&nmhdr,sizeof(NMTREEVIEWW)); 360 361 nmhdr.action = action; 362 if (oldItem) 363 { 364 TREEVIEW_TVItemFromItem(mask, &nmhdr.itemOld, oldItem); 365 if (!isUnicodeNotify(&infoPtr->header)) 366 { 367 if (!oldItem->pszText || (oldItem->pszText == LPSTR_TEXTCALLBACKW)) nmhdr.itemOld.pszText = NULL; else 368 { 369 INT len = lstrlenW(oldItem->pszText)+1; 370 371 oldText = (CHAR*)COMCTL32_Alloc(len); 372 lstrcpyWtoA(oldText,oldItem->pszText); 373 nmhdr.itemOld.pszText = (WCHAR*)oldText; 374 nmhdr.itemOld.cchTextMax = len; 375 } 376 } 377 } 378 379 if (newItem) 380 { 381 TREEVIEW_TVItemFromItem(mask, &nmhdr.itemNew, newItem); 382 if (!isUnicodeNotify(&infoPtr->header)) 383 { 384 if (!newItem->pszText || (newItem->pszText == LPSTR_TEXTCALLBACKW)) nmhdr.itemNew.pszText = NULL; else 385 { 386 INT len = lstrlenW(newItem->pszText)+1; 387 388 newText = (CHAR*)COMCTL32_Alloc(len); 389 lstrcpyWtoA(newText,newItem->pszText); 390 nmhdr.itemNew.pszText = (WCHAR*)newText; 391 nmhdr.itemNew.cchTextMax = len; 392 } 393 } 394 } 395 396 nmhdr.ptDrag.x = 0; 397 nmhdr.ptDrag.y = 0; 398 399 rc = (BOOL)sendNotify(infoPtr->hwnd,code,&nmhdr.hdr); 400 401 if (oldText) COMCTL32_Free(oldText); 402 if (newText) COMCTL32_Free(newText); 403 404 return rc; 405 } 406 407 static BOOL 408 TREEVIEW_SendTreeviewDnDNotify (TREEVIEW_INFO *infoPtr,UINT code,HTREEITEM dragItem,POINT pt) 409 { 410 NMTREEVIEWA nmhdr; 411 412 nmhdr.action = 0; 413 nmhdr.itemNew.mask = TVIF_STATE | TVIF_PARAM | TVIF_HANDLE; 414 nmhdr.itemNew.hItem = dragItem; 415 nmhdr.itemNew.state = dragItem->state; 416 nmhdr.itemNew.lParam = dragItem->lParam; 417 418 nmhdr.ptDrag.x = pt.x; 419 nmhdr.ptDrag.y = pt.y; 420 421 return (BOOL)sendNotify(infoPtr->hwnd,code,&nmhdr.hdr); 422 } 423 424 static BOOL 425 TREEVIEW_SendCustomDrawNotify(TREEVIEW_INFO *infoPtr,DWORD dwDrawStage,HDC hdc,RECT rc) 426 { 427 NMTVCUSTOMDRAW nmcdhdr; 428 LPNMCUSTOMDRAW nmcd; 429 430 nmcd = &nmcdhdr.nmcd; 431 nmcd->dwDrawStage = dwDrawStage; 432 nmcd->hdc = hdc; 433 nmcd->rc = rc; 434 nmcd->dwItemSpec = 0; 435 nmcd->uItemState = 0; 436 nmcd->lItemlParam = 0; 437 nmcdhdr.clrText = infoPtr->clrText; 438 nmcdhdr.clrTextBk = infoPtr->clrBk; 439 nmcdhdr.iLevel = 0; 440 441 return (BOOL)sendNotify(infoPtr->hwnd,NM_CUSTOMDRAW,&nmcdhdr.nmcd.hdr); 442 } 443 444 /* FIXME: need to find out when the flags in uItemState need to be set */ 445 static BOOL 446 TREEVIEW_SendCustomDrawItemNotify(TREEVIEW_INFO *infoPtr,HDC hdc,TREEVIEW_ITEM *wineItem,UINT uItemDrawState) 447 { 448 NMTVCUSTOMDRAW nmcdhdr; 449 LPNMCUSTOMDRAW nmcd; 450 DWORD dwDrawStage,dwItemSpec; 451 UINT uItemState; 452 INT retval; 453 454 dwDrawStage = CDDS_ITEM | uItemDrawState; 455 dwItemSpec = (DWORD)wineItem; 456 uItemState = 0; 457 if (wineItem == infoPtr->selectedItem) 458 { 459 uItemState |= CDIS_SELECTED; 460 if (GetFocus() == infoPtr->hwnd) uItemState |= CDIS_FOCUS; 461 } 462 if (wineItem == infoPtr->focusItem) 463 uItemState |= CDIS_FOCUS; 464 if (wineItem == infoPtr->hotItem) 465 uItemState |= CDIS_HOT; 466 467 nmcd = &nmcdhdr.nmcd; 468 nmcd->dwDrawStage = dwDrawStage; 469 nmcd->hdc = hdc; 470 nmcd->rc = wineItem->rect; 471 nmcd->dwItemSpec = dwItemSpec; 472 nmcd->uItemState = uItemState; 473 nmcd->lItemlParam = wineItem->lParam; 474 nmcdhdr.clrText = infoPtr->clrText; 475 nmcdhdr.clrTextBk = infoPtr->clrBk; 476 nmcdhdr.iLevel = wineItem->iLevel; 477 478 retval = sendNotify(infoPtr->hwnd,NM_CUSTOMDRAW,&nmcdhdr.nmcd.hdr); 479 480 infoPtr->clrText = nmcdhdr.clrText; 481 infoPtr->clrBk = nmcdhdr.clrTextBk; 482 483 return (BOOL)retval; 484 } 485 486 static void 487 TREEVIEW_GetDispInfo(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *wineItem,NMTVDISPINFOW* info,UINT mask) 488 { 489 info->item.mask = mask; 490 info->item.hItem = wineItem; 491 info->item.state = wineItem->state; 492 info->item.stateMask = 0; 493 info->item.lParam = wineItem->lParam; 494 495 sendNotify(infoPtr->hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_GETDISPINFOW:TVN_GETDISPINFOA,&info->hdr); 496 } 497 498 static void 499 TREEVIEW_UpdateDispInfo(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *wineItem,UINT mask) 500 { 501 NMTVDISPINFOW callback; 502 503 mask &= wineItem->callbackMask; 504 505 if (mask == 0) return; 506 507 if ((mask & TVIF_TEXT) /*&& (wineItem->cchTextMax < TEXT_CALLBACK_SIZE)*/) 508 { 509 wineItem->pszText = (WCHAR*)COMCTL32_ReAlloc(wineItem->pszText,TEXT_CALLBACK_SIZE*sizeof(WCHAR)); 510 wineItem->cchTextMax = TEXT_CALLBACK_SIZE; 511 } 512 513 callback.item.pszText = wineItem->pszText; 514 callback.item.cchTextMax = wineItem->cchTextMax; 515 callback.item.iImage = wineItem->iImage; 516 callback.item.iSelectedImage = wineItem->iSelectedImage; 517 callback.item.cChildren = wineItem->cChildren; 518 519 TREEVIEW_GetDispInfo(infoPtr,wineItem,&callback,mask); 520 521 /* It may have changed due to a call to SetItem. */ 522 mask &= wineItem->callbackMask; 523 524 if (mask & TVIF_TEXT) 525 { 526 if (callback.item.pszText != wineItem->pszText) 527 { 528 INT len = MAX((isUnicodeNotify(&infoPtr->header) ? lstrlenW(callback.item.pszText):lstrlenA((CHAR*)callback.item.pszText))+1,TEXT_CALLBACK_SIZE); 529 530 wineItem->pszText = (WCHAR*)COMCTL32_ReAlloc(wineItem->pszText,len*sizeof(WCHAR)); 531 if (isUnicodeNotify(&infoPtr->header)) 532 lstrcpyW(wineItem->pszText,callback.item.pszText); 533 else 534 lstrcpyAtoW(wineItem->pszText,(CHAR*)callback.item.pszText); 535 wineItem->cchTextMax = len; 536 } else if (!isUnicodeNotify(&infoPtr->header)) 537 { 538 WCHAR *newText; 539 INT len = MAX(lstrlenA((CHAR*)callback.item.pszText)+1,TEXT_CALLBACK_SIZE); 540 541 newText = (WCHAR*)COMCTL32_Alloc(len*sizeof(WCHAR)); 542 lstrcpyAtoW(newText,(LPSTR)callback.item.pszText); 543 COMCTL32_Free(wineItem->pszText); 544 wineItem->pszText = newText; 545 wineItem->cchTextMax = len; 546 } 547 } 548 549 if (mask & TVIF_IMAGE) 550 wineItem->iImage = callback.item.iImage; 551 552 if (mask & TVIF_SELECTEDIMAGE) 553 wineItem->iSelectedImage = callback.item.iSelectedImage; 554 555 if (mask & TVIF_CHILDREN) 556 wineItem->cChildren = callback.item.cChildren; 557 558 /* These members are now permanently set. */ 559 if (callback.item.mask & TVIF_DI_SETITEM) 560 wineItem->callbackMask &= ~callback.item.mask; 561 } 562 563 static VOID TREEVIEW_SendKeyDownNotify(TREEVIEW_INFO *infoPtr,UINT code,WORD wVKey) 564 { 565 NMTVKEYDOWN nmkdhdr; 566 567 nmkdhdr.wVKey = wVKey; 568 nmkdhdr.flags = 0; 569 570 sendNotify(infoPtr->hwnd,code,&nmkdhdr.hdr); 571 } 298 572 299 573 /*************************************************************************** 300 * This method 574 * This function uses cChildren field to decide whether the item has 575 * children or not. 576 * Note: if this returns TRUE, the child items may not actually exist, 577 * they could be virtual. 578 * 579 * Just use wineItem->firstChild to check for physical children. 301 580 */ 302 static void TREEVIEW_RemoveAllChildren( 303 HWND hwnd, 304 TREEVIEW_ITEM *parentItem) 305 { 306 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 307 TREEVIEW_ITEM *killItem; 308 INT kill; 309 310 kill=(INT)parentItem->firstChild; 311 while (kill) 312 { 313 tv_set_bit ( kill, infoPtr->freeList); 314 infoPtr->uNumItems--; 315 killItem=& infoPtr->items[kill]; 316 if (killItem->pszText != LPSTR_TEXTCALLBACKW) 317 COMCTL32_Free (killItem->pszText); 318 killItem->pszText = NULL; 319 TREEVIEW_SendTreeviewNotify (hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_DELETEITEMW:TVN_DELETEITEMA, 0, (HTREEITEM)kill, 0); 320 if (killItem->firstChild) 321 TREEVIEW_RemoveAllChildren (hwnd, killItem); 322 kill=(INT)killItem->sibling; 323 } 324 325 parentItem->firstChild = 0; 326 } 327 328 329 static void 330 TREEVIEW_RemoveItem (HWND hwnd, TREEVIEW_ITEM *wineItem) 331 332 { 333 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 334 TREEVIEW_ITEM *parentItem, *upsiblingItem, *siblingItem; 335 INT iItem; 336 337 if (infoPtr->hwndEdit) SetFocus(hwnd); 338 339 iItem=(INT)wineItem->hItem; 340 tv_set_bit(iItem,infoPtr->freeList); 341 infoPtr->uNumItems--; 342 parentItem=NULL; 343 if (wineItem->pszText != LPSTR_TEXTCALLBACKW) 344 COMCTL32_Free (wineItem->pszText); 345 wineItem->pszText = NULL; 346 347 TREEVIEW_SendTreeviewNotify (hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_DELETEITEMW:TVN_DELETEITEMA, 0, (HTREEITEM)iItem, 0); 348 349 if (wineItem->firstChild) 350 TREEVIEW_RemoveAllChildren (hwnd,wineItem); 351 352 if (wineItem->parent) { 353 parentItem=& infoPtr->items [(INT)wineItem->parent]; 354 if ((INT)parentItem->firstChild==iItem) 355 parentItem->firstChild=wineItem->sibling; 356 } 357 358 if (iItem==(INT)infoPtr->TopRootItem) 359 infoPtr->TopRootItem=(HTREEITEM)wineItem->sibling; 360 if (wineItem->upsibling) { 361 upsiblingItem=& infoPtr->items [(INT)wineItem->upsibling]; 362 upsiblingItem->sibling=wineItem->sibling; 363 } 364 if (wineItem->sibling) { 365 siblingItem=& infoPtr->items [(INT)wineItem->sibling]; 366 siblingItem->upsibling=wineItem->upsibling; 367 } 368 369 if (iItem==(INT)infoPtr->selectedItem) { 370 if (!wineItem->upsibling) 371 infoPtr->selectedItem = 0; 372 else 373 TREEVIEW_DoSelectItem(hwnd, TVGN_CARET, wineItem->upsibling, TVC_UNKNOWN); 374 } 375 } 376 377 /* Note:TREEVIEW_RemoveTree doesn't remove infoPtr itself */ 378 379 static void TREEVIEW_RemoveTree (HWND hwnd) 380 { 381 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 382 TREEVIEW_ITEM *killItem; 383 int i; 384 385 TREEVIEW_EndEditLabelNow(hwnd,TRUE); 386 387 for (i=1; i<=(INT)infoPtr->uMaxHandle; i++) 388 if (!tv_test_bit (i, infoPtr->freeList)) { 389 killItem=& infoPtr->items [i]; 390 if (killItem->pszText != LPSTR_TEXTCALLBACKW) 391 COMCTL32_Free (killItem->pszText); 392 killItem->pszText = NULL; 393 394 TREEVIEW_SendTreeviewNotify(hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_DELETEITEMW:TVN_DELETEITEMA, 0, killItem->hItem, 0); 395 } 396 397 if (infoPtr->uNumPtrsAlloced) { 398 COMCTL32_Free (infoPtr->items); 399 COMCTL32_Free (infoPtr->freeList); 400 infoPtr->uNumItems=0; 401 infoPtr->uNumPtrsAlloced=0; 402 infoPtr->uMaxHandle=0; 403 infoPtr->lefttop.x = infoPtr->lefttop.y = 0; 404 } 405 } 406 407 408 static LRESULT 409 TREEVIEW_GetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam) 410 { 411 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 412 413 if ((INT)wParam == TVSIL_NORMAL) 414 return (LRESULT) infoPtr->himlNormal; 415 if ((INT)wParam == TVSIL_STATE) 416 return (LRESULT) infoPtr->himlState; 417 418 return 0; 419 } 420 421 static LRESULT 422 TREEVIEW_SetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam) 423 { 424 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 425 HIMAGELIST himlTemp; 426 427 switch ((INT)wParam) { 428 case TVSIL_NORMAL: 429 himlTemp = infoPtr->himlNormal; 430 infoPtr->himlNormal = (HIMAGELIST)lParam; 431 return (LRESULT)himlTemp; 432 433 case TVSIL_STATE: 434 himlTemp = infoPtr->himlState; 435 infoPtr->himlState = (HIMAGELIST)lParam; 436 return (LRESULT)himlTemp; 437 } 438 439 return (LRESULT)NULL; 440 } 441 442 443 444 static LRESULT 445 TREEVIEW_SetItemHeight (HWND hwnd, WPARAM wParam) 446 { 447 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 448 INT cx,cy,prevHeight = infoPtr->uItemHeight; 449 450 if (wParam == -1) 451 { 452 infoPtr->uItemHeight = -1; 453 454 return prevHeight; 455 } 456 457 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &cy); 458 459 if (wParam > cy) cy = wParam; 460 infoPtr->uItemHeight = cy; 461 462 if (!(GetWindowLongA(hwnd, GWL_STYLE) & TVS_NONEVENHEIGHT)) 463 if (infoPtr->uItemHeight & 0x1) infoPtr->uItemHeight++; 464 465 if (prevHeight != infoPtr->uItemHeight) 466 { 467 infoPtr->uInternalStatus |= TV_CALCALL; 468 TREEVIEW_QueueRefresh(hwnd); 469 } 470 471 return prevHeight; 472 } 473 474 static LRESULT 475 TREEVIEW_GetItemHeight (HWND hwnd) 476 { 477 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 478 479 return infoPtr->uItemHeight; 480 } 481 482 static LRESULT 483 TREEVIEW_GetLineColor (HWND hwnd, WPARAM wParam, LPARAM lParam) 484 { 485 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 486 487 //TRACE("\n"); 488 return (LRESULT) infoPtr->clrLine; 489 } 490 491 static LRESULT 492 TREEVIEW_SetLineColor (HWND hwnd, WPARAM wParam, LPARAM lParam) 493 { 494 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 495 COLORREF prevColor=infoPtr->clrLine; 496 497 //TRACE("\n"); 498 infoPtr->clrLine=(COLORREF) lParam; 499 return (LRESULT) prevColor; 500 } 501 502 static LRESULT 503 TREEVIEW_GetInsertMarkColor (HWND hwnd, WPARAM wParam, LPARAM lParam) 504 { 505 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 506 507 //TRACE("\n"); 508 return (LRESULT) infoPtr->clrInsertMark; 509 } 510 511 static LRESULT 512 TREEVIEW_SetInsertMarkColor (HWND hwnd, WPARAM wParam, LPARAM lParam) 513 { 514 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 515 COLORREF prevColor=infoPtr->clrInsertMark; 516 517 //TRACE("%d %ld\n",wParam,lParam); 518 infoPtr->clrInsertMark=(COLORREF) lParam; 519 return (LRESULT) prevColor; 520 } 521 522 static LRESULT 523 TREEVIEW_SetInsertMark (HWND hwnd, WPARAM wParam, LPARAM lParam) 524 { 525 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 526 527 //FIXME("%d %ld\n",wParam,lParam); 528 if (!TREEVIEW_ValidItem (infoPtr, (HTREEITEM)lParam)) return 0; 529 //FIXME("%d %ld\n",wParam,lParam); 530 531 infoPtr->insertBeforeorAfter=(BOOL) wParam; 532 infoPtr->insertMarkItem=(HTREEITEM) lParam; 533 534 TREEVIEW_Refresh(hwnd); 535 536 return 1; 537 } 538 539 static LRESULT 540 TREEVIEW_SetTextColor (HWND hwnd, WPARAM wParam, LPARAM lParam) 541 { 542 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 543 COLORREF prevColor=infoPtr->clrText; 544 545 infoPtr->clrText=(COLORREF) lParam; 546 if (infoPtr->clrText != prevColor) 547 TREEVIEW_Refresh(hwnd); 548 549 return (LRESULT) prevColor; 550 } 551 552 static LRESULT 553 TREEVIEW_GetBkColor (HWND hwnd) 554 { 555 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 556 557 return (LRESULT) infoPtr->clrBk; 558 } 559 560 static LRESULT 561 TREEVIEW_SetBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam) 562 { 563 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 564 COLORREF prevColor=infoPtr->clrBk; 565 566 infoPtr->clrBk=(COLORREF) lParam; 567 if (infoPtr->clrBk != prevColor) 568 TREEVIEW_Refresh(hwnd); 569 570 571 return (LRESULT) prevColor; 572 } 573 574 static LRESULT 575 TREEVIEW_GetTextColor (HWND hwnd) 576 { 577 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 578 579 return (LRESULT) infoPtr->clrText; 580 } 581 582 583 /* cdmode: custom draw mode as received from app. in first NMCUSTOMDRAW 584 notification */ 585 586 #define TREEVIEW_LEFT_MARGIN 8 587 588 #ifdef OS2LINEHACK 589 //CB: hack for PS_DOT bug in Open32 pen handling 590 591 BOOL drawPixel; 592 HDC drawDC; 593 594 VOID CALLBACK TREEVIEW_DDAProc(int x,int y,LPARAM lpData) 595 { 596 if (drawPixel) SetPixel(drawDC,x,y,(COLORREF)lpData); 597 drawPixel = !drawPixel; 598 } 599 600 static void TREEVIEW_Polyline(HDC hdc,const POINT *lppt,int cPoints,COLORREF color) 601 { 602 INT x; 603 604 drawPixel = TRUE; 605 drawDC = hdc; 606 for (x = 0;x < cPoints-1;x++) 607 LineDDA(lppt[x].x,lppt[x].y,lppt[x+1].x,lppt[x+1].y,TREEVIEW_DDAProc,color); 608 } 609 #endif 610 611 //pen must be selected! 612 613 static void TREEVIEW_DrawVLines(HDC hdc,TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item) 614 { 615 POINT points[2]; 616 INT center; 617 618 center = (item->rect.top+item->rect.bottom)/2; 619 //INT cChildren = TREEVIEW_HasChildren(hwnd,wineItem); 620 if ((item->iLevel == 0) && !item->upsibling && item->sibling) 621 { 622 TREEVIEW_ITEM *lastItem = &infoPtr->items[(INT)item->sibling]; 623 624 while (lastItem->sibling) lastItem = &infoPtr->items[(INT)lastItem->sibling]; 625 626 points[0].y = center; 627 points[1].x = points[0].x = 8; 628 points[1].y = (lastItem->rect.top+lastItem->rect.bottom)/2; 629 #ifdef OS2LINEHACK 630 TREEVIEW_Polyline(hdc,points,2,infoPtr->clrLine); 631 #else 632 Polyline(hdc,points,2); 633 #endif 634 } 635 636 if (item->firstChild && (item->state & TVIS_EXPANDED)) 637 { 638 TREEVIEW_ITEM *lastItem = &infoPtr->items[(INT)item->firstChild]; 639 640 while (lastItem->sibling) lastItem = &infoPtr->items[(INT)lastItem->sibling]; 641 642 points[0].y = (lastItem->upsibling != NULL) ? 643 item->rect.bottom-3: /* is linked to an icon */ 644 item->rect.bottom+1; /* is linked to a +/- box */ 645 points[1].x = points[0].x = 28+20*item->iLevel-infoPtr->lefttop.x; 646 points[1].y = (lastItem->rect.top+lastItem->rect.bottom)/2; /* is linked to a +/- box */ 647 #ifdef OS2LINEHACK 648 TREEVIEW_Polyline(hdc,points,2,infoPtr->clrLine); 649 #else 650 Polyline(hdc,points,2); 651 #endif 652 } 653 } 654 655 static VOID TREEVIEW_DrawHottrackLine(HDC hdc,TREEVIEW_ITEM *item) 656 { 657 HPEN hPen,hOldPen; 658 INT rop; 659 660 if (!item->visible) return; 661 662 rop = SetROP2(hdc,R2_XORPEN); 663 hPen = CreatePen(PS_SOLID,2,RGB(0,0,0)); 664 hOldPen = SelectObject(hdc,hPen); 665 666 MoveToEx(hdc,item->text.left,item->text.bottom-1,NULL); 667 LineTo(hdc,item->text.right,item->text.bottom-1); 668 669 DeleteObject(hPen); 670 SelectObject(hdc,hOldPen); 671 SetROP2(hdc,rop); 672 } 673 674 static void 675 TREEVIEW_DrawItem(HWND hwnd,HDC hdc,TREEVIEW_ITEM *item,DWORD dwStyle,TREEVIEW_INFO *infoPtr) 676 { 677 INT center,cditem; 678 HFONT hOldFont; 679 680 if (!item->calculated) TREEVIEW_CalcItem(hwnd,hdc,dwStyle,infoPtr,item); 681 682 if (item->state & TVIS_BOLD) 683 hOldFont = SelectObject(hdc,infoPtr->hBoldFont); 684 else 685 hOldFont = SelectObject(hdc,infoPtr->hFont); 686 687 cditem = 0; 688 689 if (infoPtr->cdmode & CDRF_NOTIFYITEMDRAW) 690 { 691 cditem = TREEVIEW_SendCustomDrawItemNotify(hwnd, hdc, item, CDDS_ITEMPREPAINT); 692 693 if (cditem & CDRF_SKIPDEFAULT) return; 694 } 695 696 //CDRF_NEWFONT: CCM_SETVERSION < 5 clips text (what we do now) 697 // > 5 ??? recalc? 698 699 /* 700 * Set drawing starting points 701 */ 702 center = (item->rect.top+item->rect.bottom)/2; /* this item vertical center */ 703 704 /* 705 * Display the tree hierarchy 706 */ 707 if (dwStyle & TVS_HASLINES) 708 { 709 /* 710 * Write links to parent node 711 * we draw the L starting from the child to the parent 712 * 713 * points[0] is attached to the current item 714 * points[1] is the L corner 715 * points[2] is attached to the parent or the up sibling 716 */ 717 if (dwStyle & TVS_LINESATROOT) 718 { 719 TREEVIEW_ITEM *upNode = NULL; 720 RECT upRect = {0,0,0,0}; 721 HPEN hOldPen, hnewPen; 722 POINT points[2]; 723 724 hnewPen = CreatePen(PS_DOT, 0, infoPtr->clrLine); 725 hOldPen = SelectObject(hdc,hnewPen); 726 727 TREEVIEW_DrawVLines(hdc,infoPtr,item); 728 729 /* 730 * determine the target location of the line at root, either be linked 731 * to the up sibling or to the parent node. 732 */ 733 if (item->upsibling) 734 upNode = TREEVIEW_ValidItem (infoPtr, item->upsibling); 735 else if (item->parent) 736 upNode = TREEVIEW_ValidItem (infoPtr, item->parent); 737 738 if (upNode) upRect = upNode->rect; 739 740 if (item->iLevel == 0) 741 { 742 points[1].x = upRect.left+8; 743 points[0].x = points[1].x + 10; 744 points[1].y = points[0].y = center; 745 } else 746 { 747 points[1].x = 8+(20*item->iLevel)-infoPtr->lefttop.x; 748 points[1].y = points[0].y = center; 749 points[0].x = points[1].x + 10; 750 } 751 752 /* 753 * Get a dotted pen 754 */ 755 #ifdef OS2LINEHACK 756 TREEVIEW_Polyline(hdc,points,2,infoPtr->clrLine); 757 #else 758 Polyline(hdc,points,2); 759 #endif 760 DeleteObject(hnewPen); 761 SelectObject(hdc, hOldPen); 762 } 763 } 764 765 /* 766 * Display the (+/-) signs 767 */ 768 if ((dwStyle & TVS_HASBUTTONS) && (dwStyle & TVS_HASLINES)) 769 { 770 if (TREEVIEW_HasChildren(hwnd,item)) 771 { 772 INT vCenter = (item->expandBox.top+item->expandBox.bottom)/2; 773 INT hCenter = (item->expandBox.right+item->expandBox.left)/2; 774 775 Rectangle(hdc,item->expandBox.left,item->expandBox.top,item->expandBox.right,item->expandBox.bottom); 776 777 MoveToEx(hdc,item->expandBox.left+2,vCenter,NULL); 778 LineTo(hdc,item->expandBox.right-2,vCenter); 779 780 if (!(item->state & TVIS_EXPANDED)) 781 { 782 MoveToEx(hdc,hCenter,item->expandBox.top+2,NULL); 783 LineTo(hdc,hCenter,item->expandBox.bottom-2); 784 } 785 } 786 } 787 788 /* 789 * Display the image associated with this item 790 */ 791 if ((item->mask & (TVIF_IMAGE | TVIF_SELECTEDIMAGE)) || (dwStyle & TVS_CHECKBOXES)) 792 { 793 INT imageIndex; 794 HIMAGELIST *himlp = NULL; 795 796 /* State images are displayed to the left of the Normal image 797 * image number is in state; zero should be `display no image'. 798 * FIXME: that last sentence looks like it needs some checking. 799 */ 800 if (infoPtr->himlState) 801 himlp =& infoPtr->himlState; 802 imageIndex = item->state >> 12; 803 804 if (himlp && imageIndex) 805 { 806 imageIndex--; /* see FIXME */ 807 ImageList_Draw(*himlp,imageIndex,hdc,item->statebitmap.left,item->statebitmap.top,ILD_NORMAL); 808 } 809 810 /* Now, draw the normal image; can be either selected or 811 * non-selected image. 812 */ 813 814 himlp = NULL; 815 if (infoPtr->himlNormal) 816 himlp = &infoPtr->himlNormal; /* get the image list */ 817 818 imageIndex = item->iImage; 819 if ((item->state & TVIS_SELECTED) && item->iSelectedImage) 820 { 821 /* The item is curently selected */ 822 if (item->iSelectedImage == I_IMAGECALLBACK) 823 imageIndex = TREEVIEW_CallbackSelectedImage(hwnd,item); 824 else 825 imageIndex = item->iSelectedImage; 826 } else 827 { 828 /* The item is not selected */ 829 if (item->iImage == I_IMAGECALLBACK) 830 imageIndex = TREEVIEW_CallbackImage(hwnd,item); 831 else 832 imageIndex = item->iImage; 833 } 834 835 if (himlp && (imageIndex != I_IMAGENONE)) 836 { 837 int ovlIdx = 0; 838 839 if(item->stateMask & TVIS_OVERLAYMASK) 840 ovlIdx = item->state & TVIS_OVERLAYMASK; 841 842 ImageList_Draw(*himlp,imageIndex,hdc,item->bitmap.left,item->bitmap.top,ILD_NORMAL | ovlIdx); 843 } 844 } 845 846 /* 847 * Display the text associated with this item 848 */ 849 /* Don't paint item's text if it's being edited */ 850 if (!infoPtr->hwndEdit || (infoPtr->editItem != item->hItem)) 851 { 852 if ((item->mask & TVIF_TEXT) && (item->pszText)) 853 { 854 UINT uTextJustify = DT_LEFT; 855 COLORREF oldTextColor = 0; 856 INT oldBkMode; 857 HBRUSH hbrBk = 0; 858 BOOL inFocus = GetFocus() == hwnd; 859 WCHAR* text; 860 BOOL mustFree = FALSE; 861 862 oldBkMode = SetBkMode(hdc, TRANSPARENT); 863 864 /* - If item is drop target or it is selected and window is in focus - 865 * use blue background (COLOR_HIGHLIGHT). 866 * - If item is selected, window is not in focus, but it has style 867 * TVS_SHOWSELALWAYS - use grey background (COLOR_BTNFACE) 868 * - Otherwise - don't fill background 869 */ 870 if ((item->state & TVIS_DROPHILITED) || 871 ((item->state & TVIS_SELECTED) && 872 (inFocus || (GetWindowLongA( hwnd, GWL_STYLE) & TVS_SHOWSELALWAYS)))) 873 { 874 if ((item->state & TVIS_DROPHILITED) || inFocus) 875 { 876 hbrBk = CreateSolidBrush(GetSysColor( COLOR_HIGHLIGHT)); 877 oldTextColor = SetTextColor(hdc, GetSysColor( COLOR_HIGHLIGHTTEXT)); 878 } else 879 { 880 hbrBk = CreateSolidBrush(GetSysColor( COLOR_BTNFACE)); 881 882 if (infoPtr->clrText == -1) 883 oldTextColor = SetTextColor(hdc, GetSysColor( COLOR_WINDOWTEXT)); 884 else 885 oldTextColor = SetTextColor(hdc, infoPtr->clrText); 886 } 887 } else 888 { 889 if (infoPtr->clrText == -1) 890 oldTextColor = SetTextColor(hdc, GetSysColor( COLOR_WINDOWTEXT)); 891 else 892 oldTextColor = SetTextColor(hdc, infoPtr->clrText); 893 } 894 895 if (item->pszText == LPSTR_TEXTCALLBACKW) 896 text = TREEVIEW_CallbackText(hwnd,item,&mustFree); 897 else 898 text = item->pszText; 899 900 if (hbrBk) 901 { 902 FillRect(hdc, &item->text, hbrBk); 903 DeleteObject(hbrBk); 904 } 905 906 item->text.left += 2; 907 908 /* Draw it */ 909 DrawTextW(hdc,text,lstrlenW(text),&item->text,uTextJustify | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX); 910 if (mustFree) COMCTL32_Free(text); 911 912 item->text.left -= 2; 913 914 /* Restore the hdc state */ 915 SetTextColor( hdc, oldTextColor); 916 917 /* Draw the box arround the selected item */ 918 if (item->state & TVIS_SELECTED) 919 { 920 HPEN hNewPen = CreatePen(PS_DOT, 0, GetSysColor(COLOR_WINDOWTEXT) ); 921 HPEN hOldPen = SelectObject( hdc, hNewPen ); 922 INT rop = SetROP2(hdc, R2_XORPEN); 923 POINT points[5]; 924 925 points[4].x = points[0].x = item->text.left; 926 points[4].y = points[0].y = item->text.top; 927 points[1].x = item->text.right-1 ; 928 points[1].y = item->text.top; 929 points[2].x = item->text.right-1; 930 points[2].y = item->text.bottom-1; 931 points[3].x = item->text.left; 932 points[3].y = item->text.bottom-1; 933 934 Polyline (hdc,points,5); 935 936 SetROP2(hdc, rop); 937 DeleteObject(hNewPen); 938 SelectObject(hdc, hOldPen); 939 } 940 941 if (oldBkMode != TRANSPARENT) 942 SetBkMode(hdc, oldBkMode); 943 } 944 } 945 946 /* Draw insertion mark if necessary */ 947 948 if (item->hItem == infoPtr->insertMarkItem) 949 { 950 HPEN hNewPen, hOldPen; 951 int offset; 952 953 hNewPen = CreatePen(PS_SOLID, 2, infoPtr->clrInsertMark); 954 hOldPen = SelectObject( hdc, hNewPen ); 955 956 if (infoPtr->insertBeforeorAfter) 957 offset = item->text.top+1; 958 else 959 offset = item->text.bottom-1; 960 961 MoveToEx(hdc,item->text.left, offset-3, NULL); 962 LineTo(hdc,item->text.left, offset+3); 963 964 MoveToEx(hdc,item->text.left,offset,NULL); 965 LineTo(hdc,item->text.right-2,offset); 966 967 MoveToEx(hdc,item->text.right-2, offset+3, NULL); 968 LineTo(hdc,item->text.right-2, offset-3); 969 970 DeleteObject(hNewPen); 971 972 SelectObject(hdc, hOldPen); 973 } 974 975 //draw hot item if necessary 976 if (item->hItem == infoPtr->hotItem) 977 TREEVIEW_DrawHottrackLine(hdc,item); 978 979 if (cditem & CDRF_NOTIFYPOSTPAINT) 980 cditem = TREEVIEW_SendCustomDrawItemNotify(hwnd, hdc, item, CDDS_ITEMPOSTPAINT); 981 982 SelectObject (hdc, hOldFont); 983 } 984 985 static LRESULT 986 TREEVIEW_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam) 987 { 988 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 989 TREEVIEW_ITEM *wineItem; 990 HTREEITEM *iItem; 991 LPRECT lpRect = (LPRECT)lParam; 992 993 /* 994 * validate parameters 995 */ 996 if ((infoPtr == NULL) || (lpRect == NULL)) 997 return FALSE; 998 999 TREEVIEW_UnqueueRefresh(hwnd,TRUE,TRUE); 1000 1001 /* 1002 * retrieve the item ptr 1003 */ 1004 iItem = (HTREEITEM *) lParam; 1005 wineItem = TREEVIEW_ValidItem (infoPtr, *iItem); 1006 if (!wineItem || !wineItem->visible) 1007 return FALSE; 1008 1009 /* 1010 * If wParam is TRUE return the text size otherwise return 1011 * the whole item size 1012 */ 1013 if (wParam) 1014 { 1015 lpRect->left = wineItem->text.left; 1016 lpRect->right = wineItem->text.right; 1017 lpRect->bottom = wineItem->text.bottom; 1018 lpRect->top = wineItem->text.top; 1019 } else 1020 { 1021 lpRect->left = wineItem->rect.left; 1022 lpRect->right = wineItem->rect.right; 1023 lpRect->bottom = wineItem->rect.bottom; 1024 lpRect->top = wineItem->rect.top; 1025 } 1026 1027 return TRUE; 1028 } 1029 1030 static LRESULT 1031 TREEVIEW_GetVisibleCount (HWND hwnd, WPARAM wParam, LPARAM lParam) 1032 1033 { 1034 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 1035 1036 return (LRESULT)infoPtr->uVisibleHeight/infoPtr->uRealItemHeight; 1037 } 1038 1039 static LRESULT TREEVIEW_SetItem(HWND hwnd,WPARAM wParam,LPARAM lParam,BOOL unicode) 1040 { 1041 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 1042 TREEVIEW_ITEM *wineItem; 1043 TVITEMEXW *tvItem; 1044 INT iItem,len; 1045 BOOL mustRefresh = FALSE; 1046 BOOL mustRepaintItem = FALSE; 1047 BOOL refreshFullLine = FALSE; 1048 1049 if (infoPtr->hwndEdit) SetFocus(hwnd); 1050 1051 tvItem = (LPTVITEMEXW)lParam; 1052 iItem = (INT)tvItem->hItem; 1053 1054 wineItem = TREEVIEW_ValidItem(infoPtr,(HTREEITEM)iItem); 1055 if (!wineItem) return FALSE; 1056 1057 if ((tvItem->mask & TVIF_CHILDREN) && (wineItem->cChildren != tvItem->cChildren)) 1058 { 1059 wineItem->cChildren = tvItem->cChildren; 1060 mustRefresh = TRUE; 1061 } 1062 1063 if ((tvItem->mask & TVIF_IMAGE) && (wineItem->iImage != tvItem->iImage)) 1064 { 1065 wineItem->iImage = tvItem->iImage; 1066 mustRepaintItem = TRUE; 1067 } 1068 1069 if ((tvItem->mask & TVIF_INTEGRAL) && (wineItem->iIntegral != tvItem->iIntegral)) 1070 { 1071 wineItem->iIntegral = tvItem->iIntegral; 1072 mustRefresh = TRUE; 1073 } 1074 1075 if (tvItem->mask & TVIF_PARAM) 1076 wineItem->lParam = tvItem->lParam; 1077 1078 if ((tvItem->mask & TVIF_SELECTEDIMAGE) && (wineItem->iSelectedImage != tvItem->iSelectedImage)) 1079 { 1080 wineItem->iSelectedImage = tvItem->iSelectedImage; 1081 mustRepaintItem = TRUE; 1082 } 1083 1084 if (tvItem->mask & TVIF_STATE) 1085 { 1086 DWORD oldState = wineItem->state,oldMask = wineItem->stateMask; 1087 1088 wineItem->state &= ~tvItem->stateMask; 1089 wineItem->state |= (tvItem->state & tvItem->stateMask); 1090 wineItem->stateMask |= tvItem->stateMask; 1091 mustRepaintItem = (oldState != wineItem->state) || (oldMask != wineItem->stateMask); 1092 } 1093 1094 if (tvItem->mask & TVIF_TEXT) 1095 { 1096 if (unicode) 1097 { 1098 if (tvItem->pszText != LPSTR_TEXTCALLBACKW) 1099 { 1100 len = lstrlenW(tvItem->pszText)+1; 1101 1102 mustRepaintItem = ((wineItem->pszText == LPSTR_TEXTCALLBACKW) || (lstrcmpW(wineItem->pszText,tvItem->pszText) != 0)); 1103 if (len > wineItem->cchTextMax) 1104 { 1105 if (wineItem->pszText != LPSTR_TEXTCALLBACKW) COMCTL32_Free(wineItem->pszText); 1106 wineItem->pszText= (WCHAR*)COMCTL32_Alloc(len*sizeof(WCHAR)); 1107 wineItem->cchTextMax = len; 1108 } 1109 lstrcpyW(wineItem->pszText,tvItem->pszText); 1110 } else 1111 { 1112 if (wineItem->pszText != LPSTR_TEXTCALLBACKW) COMCTL32_Free(wineItem->pszText); 1113 wineItem->cchTextMax = 0; 1114 wineItem->pszText = LPSTR_TEXTCALLBACKW; 1115 mustRepaintItem = TRUE; 1116 } 1117 } else 1118 { 1119 if ((LPSTR)tvItem->pszText != LPSTR_TEXTCALLBACKA) 1120 { 1121 mustRepaintItem = ((wineItem->pszText == LPSTR_TEXTCALLBACKW) || (lstrcmpAtoW((CHAR*)tvItem->pszText,wineItem->pszText) != 0)); 1122 len = lstrlenA((LPSTR)tvItem->pszText)+1; 1123 if (len > wineItem->cchTextMax) 1124 { 1125 if (wineItem->pszText != LPSTR_TEXTCALLBACKW) COMCTL32_Free(wineItem->pszText); 1126 wineItem->pszText = (WCHAR*)COMCTL32_Alloc(len*sizeof(WCHAR)); 1127 wineItem->cchTextMax = len; 1128 } 1129 lstrcpyAtoW(wineItem->pszText,(LPSTR)tvItem->pszText); 1130 } else 1131 { 1132 if (wineItem->pszText != LPSTR_TEXTCALLBACKW) COMCTL32_Free(wineItem->pszText); 1133 wineItem->cchTextMax = 0; 1134 wineItem->pszText = LPSTR_TEXTCALLBACKW; 1135 mustRepaintItem = TRUE; 1136 } 1137 } 1138 refreshFullLine = TRUE; 1139 } 1140 1141 if (wineItem->mask != (wineItem->mask | tvItem->mask)) 1142 { 1143 wineItem->mask |= tvItem->mask; 1144 mustRepaintItem = TRUE; 1145 } 1146 1147 if (mustRepaintItem || mustRefresh) 1148 { 1149 wineItem->calculated = FALSE; 1150 if (mustRefresh) 1151 TREEVIEW_QueueRefresh(hwnd); 1152 else 1153 TREEVIEW_RefreshItem(hwnd,wineItem,refreshFullLine); 1154 } 1155 1156 return TRUE; 1157 } 1158 1159 static LRESULT 1160 TREEVIEW_GetItemState (HWND hwnd, WPARAM wParam, LPARAM lParam) 1161 1162 { 1163 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 1164 TREEVIEW_ITEM *wineItem; 1165 1166 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)wParam); 1167 if (!wineItem) return 0; 1168 1169 return (wineItem->state & lParam); 1170 } 1171 1172 static void TREEVIEW_Refresh(HWND hwnd) 1173 { 1174 TREEVIEW_UnqueueRefresh(hwnd,TRUE,FALSE); 1175 1176 InvalidateRect(hwnd,NULL,TRUE); 1177 } 1178 1179 static void TREEVIEW_RefreshItem(HWND hwnd,TREEVIEW_ITEM *item,BOOL wholeLine) 1180 { 1181 if (item && item->visible) 1182 { 1183 RECT rect = item->rect; 1184 1185 if (wholeLine) 1186 { 1187 RECT client; 1188 1189 GetClientRect(hwnd,&client); 1190 rect.left = 0; 1191 rect.right = client.right; 1192 } else 1193 { 1194 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE); 1195 1196 //redraw text and image 1197 if ((((item->mask & (TVIF_IMAGE | TVIF_SELECTEDIMAGE)) == (TVIF_IMAGE | TVIF_SELECTEDIMAGE)) || (dwStyle & TVS_CHECKBOXES)) && (item->iSelectedImage != item->iImage)) 1198 { 1199 rect.left += TREEVIEW_LEFT_MARGIN; 1200 if (item->iLevel != 0) rect.left += (5*item->iLevel); 1201 rect.left += 15; 1202 } else rect = item->text; 1203 } 1204 1205 InvalidateRect(hwnd,&rect,TRUE); 1206 } 1207 } 1208 1209 //HDC parameter is optional 1210 1211 static void TREEVIEW_CalcItem(HWND hwnd,HDC hdc,DWORD dwStyle,TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item) 1212 { 1213 RECT r; 1214 INT center,xpos; 1215 BOOL ownDC = FALSE; 1216 581 static INT 582 TREEVIEW_HasChildren(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *wineItem) 583 { 584 TREEVIEW_UpdateDispInfo(infoPtr, wineItem, TVIF_CHILDREN); 585 586 return wineItem->cChildren > 0; 587 } 588 589 /* Item Position ********************************************************/ 590 591 static VOID 592 TREEVIEW_ComputeTextWidth(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item,HDC hDC,BOOL useFont) 593 { 594 HDC hdc; 595 HFONT hOldFont; 596 RECT rect; 597 598 /* DRAW's OM docker creates items like this */ 599 if (item->pszText == NULL) 600 { 601 item->textWidth = 0; 602 return; 603 } 604 605 hdc = hDC ? hDC:GetDC(infoPtr->hwnd); 606 if (!hDC || !useFont) hOldFont = SelectObject(hdc, TREEVIEW_FontForItem(infoPtr, item)); 607 608 SetRectEmpty(&rect); 609 DrawTextW (hdc,item->pszText,lstrlenW(item->pszText),&rect,DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_CALCRECT | DT_NOPREFIX); 610 item->textWidth = rect.right-rect.left; 611 item->textHeight = rect.bottom-rect.top; 612 item->rect.right = item->textOffset+item->textWidth+4; 613 614 if (!hDC || !useFont) SelectObject(hdc, hOldFont); 615 if (!hDC) ReleaseDC(infoPtr->hwnd,hdc); 616 } 617 618 static INT CALLBACK 619 TREEVIEW_ResetItemOrderVisible(LPVOID pItem, DWORD unused) 620 { 621 TREEVIEW_ITEM *item = (TREEVIEW_ITEM *)pItem; 622 (void)unused; 623 624 item->displayOrder = -1; 625 item->displayed = FALSE; 626 item->inclient = FALSE; 627 628 return 1; 629 } 630 631 static VOID TREEVIEW_CalcItem(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item,HDC hdc) 632 { 633 TREEVIEW_UpdateDispInfo(infoPtr,item,TVIF_TEXT); 634 TREEVIEW_ComputeTextWidth(infoPtr,item,hdc,FALSE); 1217 635 item->calculated = TRUE; 1218 1219 r = item->rect; /* this item rectangle */ 1220 center = (r.top+r.bottom)/2; /* this item vertical center */ 1221 xpos = r.left + TREEVIEW_LEFT_MARGIN;/* horizontal starting point */ 1222 1223 if (item->iLevel != 0)/* update position only for non root node */ 1224 xpos += 5*item->iLevel; 1225 1226 if ((dwStyle & TVS_HASBUTTONS) && (dwStyle & TVS_HASLINES)) 1227 { 1228 if (TREEVIEW_HasChildren(hwnd,item)) 1229 { 1230 /* Setup expand box coordinate to facilitate the LMBClick handling */ 1231 item->expandBox.left = xpos-4; 1232 item->expandBox.top = center-4; 1233 item->expandBox.right = xpos+5; 1234 item->expandBox.bottom = center+5; 1235 } else SetRectEmpty(&item->expandBox); 1236 } else SetRectEmpty(&item->expandBox); 1237 1238 xpos += 13; /* update position */ 1239 1240 if ((item->mask & (TVIF_IMAGE | TVIF_SELECTEDIMAGE)) || (dwStyle & TVS_CHECKBOXES)) 1241 { 1242 INT imageIndex,cx,cy; 1243 HIMAGELIST *himlp = NULL; 1244 1245 /* State images are displayed to the left of the Normal image 1246 * image number is in state; zero should be `display no image'. 1247 * FIXME: that last sentence looks like it needs some checking. 1248 */ 1249 if (infoPtr->himlState) 1250 himlp = &infoPtr->himlState; 1251 imageIndex = item->state >> 12; 1252 1253 if (himlp && imageIndex) 1254 { 1255 if (!hdc) 1256 { 1257 ownDC = TRUE; 1258 hdc = GetDC(hwnd); 1259 } 1260 1261 imageIndex--; /* see FIXME */ 1262 ImageList_GetIconSize(*himlp,&cx,&cy); 1263 item->statebitmap.left = xpos-2; 1264 item->statebitmap.right = xpos-2+cx; 1265 item->statebitmap.top = r.top+1; 1266 item->statebitmap.bottom = r.top+1+cy; 1267 xpos += cx; 1268 } else SetRectEmpty(&item->statebitmap); 1269 1270 /* Now, draw the normal image; can be either selected or 1271 * non-selected image. 1272 */ 1273 1274 himlp = NULL; 1275 if (infoPtr->himlNormal) 1276 himlp = &infoPtr->himlNormal; /* get the image list */ 1277 1278 if (himlp) 1279 { 1280 int ovlIdx = 0; 1281 1282 if(item->stateMask & TVIS_OVERLAYMASK) 1283 ovlIdx = item->state & TVIS_OVERLAYMASK; 1284 1285 if (!hdc) 1286 { 1287 ownDC = TRUE; 1288 hdc = GetDC(hwnd); 1289 } 1290 1291 ImageList_GetIconSize(*himlp,&cx,&cy); 1292 item->bitmap.left = xpos-2; 1293 item->bitmap.right = xpos-2+cx; 1294 item->bitmap.top = r.top+1; 1295 item->bitmap.bottom = r.top+1+cy; 1296 xpos += cx; 1297 } else SetRectEmpty(&item->bitmap); 1298 } else 1299 { 1300 SetRectEmpty(&item->statebitmap); 1301 SetRectEmpty(&item->bitmap); 1302 } 1303 1304 r.left = xpos; 1305 if ((item->mask & TVIF_TEXT) && item->pszText) 1306 { 1307 UINT uTextJustify = DT_LEFT; 1308 HFONT hOldFont; 1309 WCHAR* text; 1310 BOOL mustFree = FALSE; 1311 1312 r.left += 3; 1313 r.right -= 3; 1314 1315 item->text.left = r.left; 1316 item->text.right = r.right; 1317 item->text.top = r.top; 1318 item->text.bottom= r.bottom; 1319 1320 if (item->pszText == LPSTR_TEXTCALLBACKW) 1321 text = TREEVIEW_CallbackText(hwnd,item,&mustFree); 1322 else 1323 text = item->pszText; 1324 1325 if (!hdc) 1326 { 1327 ownDC = TRUE; 1328 hdc = GetDC(hwnd); 1329 } 1330 1331 if (item->state & TVIS_BOLD) 1332 hOldFont = SelectObject (hdc, infoPtr->hBoldFont); 1333 else 1334 hOldFont = SelectObject (hdc, infoPtr->hFont); 1335 1336 /* Obtain the text coordinate */ 1337 DrawTextW (hdc,text,lstrlenW(text),&item->text,uTextJustify | DT_VCENTER | DT_SINGLELINE | DT_CALCRECT | DT_NOPREFIX); 1338 if (mustFree) COMCTL32_Free(text); 1339 1340 SelectObject(hdc,hOldFont); 1341 1342 /* We need to reset it to items height */ 1343 item->text.top = r.top; 1344 item->text.bottom = r.bottom; 1345 item->text.right += 4; /* This is extra for focus rectangle */ 1346 1347 xpos = item->text.right; 1348 } else SetRectEmpty(&item->text); 1349 1350 item->rect.right = xpos; 1351 1352 if (ownDC) ReleaseDC(hwnd,hdc); 1353 } 1354 1355 //HDC parameter is optional 1356 1357 static BOOL TREEVIEW_CalcItems(HWND hwnd,HDC hdc,TREEVIEW_INFO *infoPtr) 636 } 637 638 static BOOL TREEVIEW_CalcItems(TREEVIEW_INFO *infoPtr) 1358 639 { 1359 640 TREEVIEW_ITEM *item; 1360 INT iItem, indent,x,y,height,itemHeight; 1361 TEXTMETRICA tm; 1362 RECT rect,view; 1363 BOOL ownDC = FALSE,changedLeftTop = FALSE; 1364 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE); 641 int order = 0; 642 BOOL lar = ((infoPtr->dwStyle & (TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS)) > TVS_LINESATROOT); 643 HDC hdc = 0; 1365 644 INT maxXScroll,maxYScroll; 1366 645 INT xDiff,yDiff; 1367 HFONT oldFont; 1368 1369 GetClientRect(hwnd,&rect); 1370 infoPtr->uVisibleHeight = rect.bottom-rect.top; 1371 infoPtr->uVisibleWidth = rect.right-rect.left; 1372 1373 if (infoPtr->uInternalStatus & TV_CALCALL) 1374 { 1375 TREEVIEW_HideInfoTip(hwnd,infoPtr); 1376 itemHeight = 0; 1377 ImageList_GetIconSize(infoPtr->himlNormal,&x,&itemHeight); 1378 if (infoPtr->uItemHeight != -1) itemHeight = MAX(infoPtr->uItemHeight,itemHeight); 1379 1380 if (!hdc) 1381 { 1382 ownDC = TRUE; 1383 hdc = GetDC(hwnd); 1384 } 1385 1386 oldFont = SelectObject(hdc,infoPtr->hFont); 1387 GetTextMetricsA(hdc,&tm); 1388 itemHeight = MAX(tm.tmHeight+tm.tmExternalLeading,itemHeight); 1389 SelectObject(hdc,infoPtr->hBoldFont); 1390 GetTextMetricsA(hdc,&tm); 1391 itemHeight = MAX(tm.tmHeight+tm.tmExternalLeading,itemHeight); 1392 SelectObject(hdc,oldFont); 1393 if (!(dwStyle & TVS_NONEVENHEIGHT)) 1394 if (itemHeight & 0x1) itemHeight++; //important for PS_DOT pen! 1395 infoPtr->uRealItemHeight = itemHeight; 1396 infoPtr->uVScrollStep = itemHeight+ITEM_VSPACE; 1397 } else 1398 { 1399 itemHeight = infoPtr->uRealItemHeight; 1400 } 1401 infoPtr->uTotalWidth = 0; 1402 1403 view = rect; 1404 OffsetRect(&view,infoPtr->lefttop.x,infoPtr->lefttop.y); 1405 1406 iItem = (INT)infoPtr->TopRootItem; 1407 infoPtr->firstVisible = 0; 1408 item = NULL; 1409 indent = x = y = 0; 1410 1411 while (iItem) 1412 { 1413 item = &infoPtr->items[iItem]; 1414 item->iLevel = indent; 1415 1416 height = itemHeight*item->iIntegral+ITEM_VSPACE; 1417 1418 //calculate size and fill rects 646 BOOL changedLeftTop = FALSE; 647 RECT rc; 648 649 TREEVIEW_HideInfoTip(infoPtr); 650 651 // 1) reset 652 infoPtr->treeWidth = 0; 653 infoPtr->treeHeight = 0; 654 GetClientRect(infoPtr->hwnd,&rc); 655 infoPtr->clientWidth = rc.right; 656 infoPtr->clientHeight = rc.bottom; 657 DPA_EnumCallback(infoPtr->items,TREEVIEW_ResetItemOrderVisible,(LPARAM)NULL); 658 659 // 2) get order and tree height 660 infoPtr->firstVisible = NULL; 661 for (item = infoPtr->root->firstChild;item != NULL;item = TREEVIEW_GetNextListItem(infoPtr, item)) 662 { 663 INT itemW; 664 665 item->displayOrder = order; 666 1419 667 if ((infoPtr->uInternalStatus & TV_CALCALL) || !item->calculated) 1420 668 { 1421 item->rect.top = y-view.top; 1422 item->rect.bottom = item->rect.top+height; 1423 item->rect.left = x-view.left; 1424 item->rect.right = rect.right; //dummy 1425 if (!hdc) 1426 { 1427 ownDC = TRUE; 1428 hdc = GetDC(hwnd); 1429 } 1430 TREEVIEW_CalcItem(hwnd,hdc,dwStyle,infoPtr,item); 1431 } else 1432 { 1433 INT xOffset,yOffset; 1434 1435 xOffset = (x-view.left)-item->rect.left; 1436 yOffset = (y-view.top)-item->rect.top; 1437 OffsetRect(&item->rect,xOffset,yOffset); 1438 OffsetRect(&item->text,xOffset,yOffset); 1439 OffsetRect(&item->expandBox,xOffset,yOffset); 1440 OffsetRect(&item->bitmap,xOffset,yOffset); 1441 OffsetRect(&item->statebitmap,xOffset,yOffset); 1442 } 1443 infoPtr->uTotalWidth = MAX(infoPtr->uTotalWidth,item->rect.right+infoPtr->lefttop.x); 1444 1445 if (((y >= view.top) && (y < view.bottom)) || ((y+height > view.top) && (y+height <= view.bottom))) 1446 { 1447 item->visible = TRUE; 1448 if (!infoPtr->firstVisible) 1449 infoPtr->firstVisible = item->hItem; 1450 } else item->visible = FALSE; 1451 1452 /* look up next item */ 1453 1454 if ((item->firstChild) && (item->state & TVIS_EXPANDED)) 1455 { 1456 iItem = (INT)item->firstChild; 1457 indent++; 1458 x += infoPtr->uIndent; 1459 } else 1460 { 1461 iItem = (INT)item->sibling; 1462 while ((!iItem) && (indent > 0)) 1463 { 1464 indent--; 1465 x -= infoPtr->uIndent; 1466 item = &infoPtr->items[(INT)item->parent]; 1467 iItem = (INT)item->sibling; 1468 } 1469 } 1470 y += height; 1471 } /* while */ 1472 1473 if (ownDC) ReleaseDC(hwnd,hdc); 1474 669 if (!hdc) hdc = GetDC(infoPtr->hwnd); 670 TREEVIEW_CalcItem(infoPtr,item,hdc); 671 } 672 673 //set internal metrics 674 item->linesOffset = infoPtr->uIndent * (item->iLevel + lar - 1) - infoPtr->lefttop.x; 675 item->stateOffset = item->linesOffset + infoPtr->uIndent; 676 item->imageOffset = item->stateOffset + (STATEIMAGEINDEX(item->state) ? infoPtr->stateImageWidth : 0); 677 item->textOffset = item->imageOffset + infoPtr->normalImageWidth; 678 679 //set item rect 680 item->rect.top = infoPtr->uItemHeight*item->displayOrder-infoPtr->lefttop.y; 681 item->rect.bottom = item->rect.top+infoPtr->uItemHeight*item->iIntegral; 682 item->rect.left = item->stateOffset; 683 item->rect.right = item->textOffset+item->textWidth+4; 684 item->displayed = TRUE; 685 item->inclient = (((item->rect.top >= 0) || (item->rect.bottom >= 0)) && (item->rect.top < infoPtr->clientHeight)); 686 if (!infoPtr->firstVisible && item->inclient) infoPtr->firstVisible = item; 687 688 itemW = item->textOffset+item->textWidth+4+infoPtr->lefttop.x; 689 if (itemW > infoPtr->treeWidth) 690 infoPtr->treeWidth = itemW; 691 692 infoPtr->treeHeight += item->rect.bottom-item->rect.top; 693 694 order += item->iIntegral; 695 } 696 infoPtr->maxDisplayOrder = order; 697 698 if (hdc) ReleaseDC(infoPtr->hwnd,hdc); 1475 699 infoPtr->uInternalStatus &= ~TV_CALCALL; 1476 infoPtr->uTotalHeight = y; 1477 1478 //check cx and cy 700 701 // 3) check lefttop 1479 702 yDiff = xDiff = 0; 1480 703 1481 maxYScroll = infoPtr-> uTotalHeight-infoPtr->uVisibleHeight;704 maxYScroll = infoPtr->treeHeight-infoPtr->clientHeight; 1482 705 if (maxYScroll < 0) maxYScroll = 0; 1483 706 if (infoPtr->lefttop.y > maxYScroll) 1484 707 { 1485 INT mod = maxYScroll % infoPtr->u VScrollStep;1486 1487 if (mod > 0) maxYScroll += infoPtr->u VScrollStep-mod;708 INT mod = maxYScroll % infoPtr->uItemHeight; 709 710 if (mod > 0) maxYScroll += infoPtr->uItemHeight-mod; 1488 711 yDiff = infoPtr->lefttop.y-maxYScroll; 1489 712 infoPtr->lefttop.y = maxYScroll; 1490 713 } 1491 714 1492 maxXScroll = infoPtr-> uTotalWidth-infoPtr->uVisibleWidth;715 maxXScroll = infoPtr->treeWidth-infoPtr->clientWidth; 1493 716 if (maxXScroll < 0) maxXScroll = 0; 1494 717 if (infoPtr->lefttop.x > maxXScroll) … … 1501 724 if (changedLeftTop) 1502 725 { 1503 iItem = (INT)infoPtr->TopRootItem; 1504 item = NULL; 1505 indent = 0; 1506 infoPtr->firstVisible = 0; 1507 1508 while (iItem) 1509 { 1510 item = &infoPtr->items[iItem]; 1511 OffsetRect(&item->rect,xDiff,yDiff); 1512 OffsetRect(&item->text,xDiff,yDiff); 1513 OffsetRect(&item->expandBox,xDiff,yDiff); 1514 OffsetRect(&item->bitmap,xDiff,yDiff); 1515 OffsetRect(&item->statebitmap,xDiff,yDiff); 1516 1517 y = view.top+item->rect.top; 1518 if (((y >= view.top) && (y < view.bottom)) || ((y+height > view.top) && (y+height <= view.bottom))) 1519 { 1520 item->visible = TRUE; 1521 if (!infoPtr->firstVisible) 1522 infoPtr->firstVisible = item->hItem; 1523 } else item->visible = FALSE; 1524 1525 if ((item->firstChild) && (item->state & TVIS_EXPANDED)) 1526 { 1527 iItem = (INT)item->firstChild; 1528 indent++; 1529 } else 1530 { 1531 iItem = (INT)item->sibling; 1532 while ((!iItem) && (indent > 0)) 1533 { 1534 indent--; 1535 item = &infoPtr->items[(INT)item->parent]; 1536 iItem = (INT)item->sibling; 1537 } 1538 } 1539 } /* while */ 1540 } 1541 1542 if (!(dwStyle & TVS_NOSCROLL) && (infoPtr->uVisibleHeight > 0) && (infoPtr->uVisibleWidth > 0)) 1543 { 1544 if (infoPtr->uTotalHeight > infoPtr->uVisibleHeight) 726 //update visible flag and position 727 infoPtr->firstVisible = NULL; 728 for (item = infoPtr->root->firstChild;item != NULL;item = TREEVIEW_GetNextListItem(infoPtr, item)) 729 { 730 item->rect.top += yDiff; 731 item->rect.bottom += yDiff; 732 item->rect.left += xDiff; 733 item->rect.right += xDiff; 734 item->inclient = (((item->rect.top >= 0) || (item->rect.bottom >= 0)) && (item->rect.top < infoPtr->clientHeight)); 735 if (!infoPtr->firstVisible && item->inclient) infoPtr->firstVisible = item; 736 item->linesOffset += xDiff; 737 item->stateOffset += xDiff; 738 item->imageOffset += xDiff; 739 item->textOffset += xDiff; 740 } 741 } 742 743 // 4) set scrollbars 744 if (!(infoPtr->dwStyle & TVS_NOSCROLL) && (infoPtr->clientHeight > 0) && (infoPtr->clientWidth > 0)) 745 { 746 if (infoPtr->treeHeight > infoPtr->clientHeight) 1545 747 { 1546 748 SCROLLINFO info; 1547 INT visH = ((INT)(infoPtr-> uVisibleHeight/infoPtr->uVScrollStep))*infoPtr->uVScrollStep;749 INT visH = ((INT)(infoPtr->clientHeight/infoPtr->uItemHeight))*infoPtr->uItemHeight; 1548 750 1549 751 info.cbSize = sizeof(info); 1550 752 info.nMin = 0; 1551 info.nMax = infoPtr-> uTotalHeight-1;753 info.nMax = infoPtr->treeHeight-1; 1552 754 info.nPos = infoPtr->lefttop.y; 1553 755 info.nPage = visH; 1554 756 info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE; 1555 757 infoPtr->uInternalStatus |= TV_VSCROLL; 1556 SetScrollInfo( hwnd,SB_VERT,&info,TRUE);758 SetScrollInfo(infoPtr->hwnd,SB_VERT,&info,TRUE); 1557 759 } else 1558 760 { 1559 761 if (infoPtr->uInternalStatus & TV_VSCROLL) 1560 ShowScrollBar( hwnd,SB_VERT,FALSE);762 ShowScrollBar(infoPtr->hwnd,SB_VERT,FALSE); 1561 763 infoPtr->uInternalStatus &= ~TV_VSCROLL; 1562 764 } 1563 if (!( dwStyle & TVS_NOHSCROLL) && (infoPtr->uTotalWidth > infoPtr->uVisibleWidth))765 if (!(infoPtr->dwStyle & TVS_NOHSCROLL) && (infoPtr->treeWidth > infoPtr->clientWidth)) 1564 766 { 1565 767 SCROLLINFO info; … … 1567 769 info.cbSize = sizeof(info); 1568 770 info.nMin = 0; 1569 info.nMax = infoPtr-> uTotalWidth-1;771 info.nMax = infoPtr->treeWidth-1; 1570 772 info.nPos = infoPtr->lefttop.x; 1571 info.nPage = MAX(infoPtr-> uVisibleWidth,1);773 info.nPage = MAX(infoPtr->clientWidth,1); 1572 774 info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE; 1573 775 infoPtr->uInternalStatus |= TV_HSCROLL; 1574 SetScrollInfo( hwnd,SB_HORZ,&info,TRUE);776 SetScrollInfo(infoPtr->hwnd,SB_HORZ,&info,TRUE); 1575 777 } else 1576 778 { 1577 779 if (infoPtr->uInternalStatus & TV_HSCROLL) 1578 ShowScrollBar( hwnd,SB_HORZ,FALSE);780 ShowScrollBar(infoPtr->hwnd,SB_HORZ,FALSE); 1579 781 infoPtr->uInternalStatus &= ~TV_HSCROLL; 1580 782 } … … 1582 784 { 1583 785 if (infoPtr->uInternalStatus & (TV_VSCROLL | TV_HSCROLL)) 1584 ShowScrollBar( hwnd,SB_BOTH,FALSE);786 ShowScrollBar(infoPtr->hwnd,SB_BOTH,FALSE); 1585 787 infoPtr->uInternalStatus &= ~(TV_VSCROLL | TV_HSCROLL); 1586 788 } 1587 789 790 infoPtr->dwStyle = GetWindowLongA(infoPtr->hwnd,GWL_STYLE); 791 1588 792 return changedLeftTop; 1589 793 } 1590 794 795 static VOID TREEVIEW_MoveItems(TREEVIEW_INFO *infoPtr,INT xScroll,INT yScroll) 796 { 797 TREEVIEW_ITEM *item; 798 799 infoPtr->firstVisible = NULL; 800 for (item = infoPtr->root->firstChild;item;item = TREEVIEW_GetNextListItem(infoPtr,item)) 801 { 802 item->rect.top += yScroll; 803 item->rect.bottom += yScroll; 804 item->rect.left += xScroll; 805 item->rect.right += xScroll; 806 item->inclient = (((item->rect.top >= 0) || (item->rect.bottom >= 0)) && (item->rect.top < infoPtr->clientHeight)); 807 if (!infoPtr->firstVisible && item->inclient) infoPtr->firstVisible = item; 808 809 //set internal metrics 810 item->linesOffset += xScroll; 811 item->stateOffset += xScroll; 812 item->imageOffset += xScroll; 813 item->textOffset += xScroll; 814 } 815 } 816 817 /* Item Allocation **********************************************************/ 818 819 static TREEVIEW_ITEM * 820 TREEVIEW_AllocateItem(TREEVIEW_INFO *infoPtr) 821 { 822 TREEVIEW_ITEM *newItem = (TREEVIEW_ITEM*)COMCTL32_Alloc(sizeof(TREEVIEW_ITEM)); 823 824 if (!newItem) 825 return NULL; 826 827 ZeroMemory(newItem,sizeof(TREEVIEW_ITEM)); 828 if (DPA_InsertPtr(infoPtr->items, INT_MAX, newItem) == -1) 829 { 830 COMCTL32_Free(newItem); 831 return NULL; 832 } 833 834 return newItem; 835 } 836 837 /* Exact opposite of TREEVIEW_AllocateItem. In particular, it does not 838 * free item->pszText. */ 1591 839 static void 1592 TREEVIEW_Draw(HWND hwnd,HDC hdc,RECT *updateRect) 1593 { 1594 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 1595 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE); 1596 HBRUSH hbrBk; 840 TREEVIEW_FreeItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) 841 { 842 DPA_DeletePtr(infoPtr->items, DPA_GetPtrIndex(infoPtr->items, item)); 843 COMCTL32_Free(item); 844 } 845 846 847 /* Item Insertion *******************************************************/ 848 849 /*************************************************************************** 850 * This method inserts newItem before sibling as a child of parent. 851 * sibling can be NULL, but only if parent has no children. 852 */ 853 static void 854 TREEVIEW_InsertBefore(TREEVIEW_ITEM *newItem, TREEVIEW_ITEM *sibling, 855 TREEVIEW_ITEM *parent) 856 { 857 assert(newItem != NULL); 858 assert(parent != NULL); 859 860 if (sibling != NULL) 861 { 862 assert(sibling->parent == parent); 863 864 if (sibling->prevSibling != NULL) 865 sibling->prevSibling->nextSibling = newItem; 866 867 newItem->prevSibling = sibling->prevSibling; 868 sibling->prevSibling = newItem; 869 } 870 871 newItem->nextSibling = sibling; 872 873 if (parent->firstChild == sibling) 874 { 875 newItem->nextSibling = parent->firstChild; 876 parent->firstChild = newItem; 877 } 878 879 if (parent->lastChild == NULL) 880 parent->lastChild = newItem; 881 } 882 883 /*************************************************************************** 884 * This method inserts newItem after sibling as a child of parent. 885 * sibling can be NULL, but only if parent has no children. 886 */ 887 static void 888 TREEVIEW_InsertAfter(TREEVIEW_ITEM *newItem, TREEVIEW_ITEM *sibling, 889 TREEVIEW_ITEM *parent) 890 { 891 assert(newItem != NULL); 892 assert(parent != NULL); 893 894 if (sibling != NULL) 895 { 896 assert(sibling->parent == parent); 897 898 if (sibling->nextSibling != NULL) 899 sibling->nextSibling->prevSibling = newItem; 900 901 newItem->nextSibling = sibling->nextSibling; 902 sibling->nextSibling = newItem; 903 } 904 905 newItem->prevSibling = sibling; 906 907 if (parent->lastChild == sibling) 908 { 909 newItem->prevSibling = parent->lastChild; 910 parent->lastChild = newItem; 911 } 912 913 if (parent->firstChild == NULL) 914 parent->firstChild = newItem; 915 } 916 917 static BOOL 918 TREEVIEW_DoSetItem(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *wineItem,const TVITEMEXW *tvItem,BOOL unicode,DWORD *changed = NULL) 919 { 920 UINT callbackClear = 0; 921 UINT callbackSet = 0; 922 923 if (changed) *changed = 0; 924 925 /* Do this first in case it fails. */ 926 927 if (tvItem->mask & TVIF_TEXT) 928 { 929 /* 930 * Setup the item text stuff here since it's required by the Sort method 931 * when the insertion are ordered 932 */ 933 if (unicode) 934 { 935 if (tvItem->pszText != LPSTR_TEXTCALLBACKW) 936 { 937 INT len = lstrlenW(tvItem->pszText)+1; 938 939 callbackClear |= TVIF_TEXT; 940 941 if (changed && ((wineItem->callbackMask & LVIF_TEXT) || (lstrcmpW(wineItem->pszText,tvItem->pszText) != 0))) *changed |= TVIF_TEXT; 942 if (len > wineItem->cchTextMax) 943 { 944 LPWSTR newText = (WCHAR*)COMCTL32_ReAlloc(wineItem->pszText,len*sizeof(WCHAR)); 945 if (newText == NULL) return FALSE; 946 947 wineItem->pszText = newText; 948 wineItem->cchTextMax = len; 949 } 950 lstrcpyW (wineItem->pszText,tvItem->pszText); 951 } else 952 { 953 callbackSet |= TVIF_TEXT; 954 955 wineItem->pszText = (WCHAR*)COMCTL32_ReAlloc(wineItem->pszText,TEXT_CALLBACK_SIZE*sizeof(WCHAR)); 956 wineItem->cchTextMax = TEXT_CALLBACK_SIZE; 957 if (changed) *changed |= TVIF_TEXT; 958 } 959 } else 960 { 961 if ((LPSTR)tvItem->pszText != LPSTR_TEXTCALLBACKA) 962 { 963 INT len = lstrlenA((LPSTR)tvItem->pszText)+1; 964 965 callbackClear |= TVIF_TEXT; 966 967 if (changed && ((wineItem->callbackMask & LVIF_TEXT) || (lstrcmpAtoW((CHAR*)tvItem->pszText,wineItem->pszText) != 0))) *changed |= TVIF_TEXT; 968 if (len > wineItem->cchTextMax) 969 { 970 LPWSTR newText = (WCHAR*)COMCTL32_ReAlloc(wineItem->pszText,len*sizeof(WCHAR)); 971 if (newText == NULL) return FALSE; 972 973 wineItem->pszText = newText; 974 wineItem->cchTextMax = len; 975 } 976 lstrcpyAtoW (wineItem->pszText,(LPSTR)tvItem->pszText); 977 } else 978 { 979 callbackSet |= TVIF_TEXT; 980 981 wineItem->pszText = (WCHAR*)COMCTL32_ReAlloc(wineItem->pszText,TEXT_CALLBACK_SIZE*sizeof(WCHAR)); 982 wineItem->cchTextMax = TEXT_CALLBACK_SIZE; 983 if (changed) *changed |= TVIF_TEXT; 984 } 985 } 986 } 987 988 if (tvItem->mask & TVIF_CHILDREN) 989 { 990 if (changed && (wineItem->cChildren != tvItem->cChildren)) *changed |= TVIF_CHILDREN; 991 wineItem->cChildren = tvItem->cChildren; 992 993 if (wineItem->cChildren == I_CHILDRENCALLBACK) 994 callbackSet |= TVIF_CHILDREN; 995 else 996 callbackClear |= TVIF_CHILDREN; 997 } 998 999 if (tvItem->mask & TVIF_IMAGE) 1000 { 1001 if (changed && (wineItem->iImage != tvItem->iImage)) *changed |= TVIF_IMAGE; 1002 wineItem->iImage = tvItem->iImage; 1003 1004 if (wineItem->iImage == I_IMAGECALLBACK) 1005 callbackSet |= TVIF_IMAGE; 1006 else 1007 callbackClear |= TVIF_IMAGE; 1008 } 1009 1010 if (tvItem->mask & TVIF_SELECTEDIMAGE) 1011 { 1012 if (changed && (wineItem->iSelectedImage != tvItem->iSelectedImage)) *changed |= TVIF_SELECTEDIMAGE; 1013 wineItem->iSelectedImage = tvItem->iSelectedImage; 1014 1015 if (wineItem->iImage == I_IMAGECALLBACK) 1016 callbackSet |= TVIF_SELECTEDIMAGE; 1017 else 1018 callbackClear |= TVIF_SELECTEDIMAGE; 1019 } 1020 1021 if (tvItem->mask & TVIF_PARAM) 1022 { 1023 if (changed && (wineItem->lParam != tvItem->lParam)) *changed |= TVIF_PARAM; 1024 wineItem->lParam = tvItem->lParam; 1025 } 1026 1027 /* If the application sets TVIF_INTEGRAL without 1028 * supplying a TVITEMEX structure, it's toast. */ 1029 if (tvItem->mask & TVIF_INTEGRAL) 1030 { 1031 if (changed && (wineItem->iIntegral != tvItem->iIntegral)) *changed |= TVIF_INTEGRAL; 1032 wineItem->iIntegral = tvItem->iIntegral; 1033 } 1034 1035 if (tvItem->mask & TVIF_STATE) 1036 { 1037 DWORD oldState = wineItem->state; 1038 1039 wineItem->state &= ~tvItem->stateMask; 1040 wineItem->state |= (tvItem->state & tvItem->stateMask); 1041 if (changed && (wineItem->state != oldState)) *changed |= TVIF_STATE; 1042 } 1043 1044 wineItem->callbackMask |= callbackSet; 1045 wineItem->callbackMask &= ~callbackClear; 1046 1047 return TRUE; 1048 } 1049 1050 /* Note that the new item is pre-zeroed. */ 1051 static LRESULT 1052 TREEVIEW_InsertItem(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam,BOOL unicode) 1053 { 1054 TVINSERTSTRUCTW *ptdi = (LPTVINSERTSTRUCTW)lParam; 1055 TVITEMEXW *tvItem; 1056 HTREEITEM insertAfter; 1057 INT x; 1058 TREEVIEW_ITEM *newItem, *parentItem; 1059 1060 if (!ptdi) return NULL; 1061 tvItem = &ptdi->itemex; 1062 1063 if (infoPtr->hwndEdit) SetFocus(infoPtr->hwnd); 1064 1065 if ((ptdi->hParent == TVI_ROOT) || (ptdi->hParent == 0)) 1066 { 1067 parentItem = infoPtr->root; 1068 } else 1069 { 1070 parentItem = ptdi->hParent; 1071 1072 if (!TREEVIEW_ValidItem(infoPtr,parentItem)) 1073 { 1074 //dprintf(("invalid parent %p\n",parentItem)); 1075 1076 return (LRESULT)(HTREEITEM)NULL; 1077 } 1078 } 1079 1080 insertAfter = ptdi->hInsertAfter; 1081 1082 /* Validate this now for convenience. */ 1083 if ((insertAfter != TVI_FIRST) && (insertAfter != TVI_LAST) && (insertAfter != TVI_SORT)) 1084 { 1085 if (!TREEVIEW_ValidItem(infoPtr,insertAfter)) 1086 { 1087 //dprintf(("invalid insert after %p\n",insertAfter)); 1088 insertAfter = TVI_LAST; 1089 } else if (parentItem != insertAfter->parent) 1090 { 1091 //dprintf(("invalid insert after parent %p %p %p",insertAfter,insertAfter->parent,parentItem)); 1092 //CB: Verified with AMD cpuid 2.04 (there are other strange things...) 1093 insertAfter = parentItem->lastChild; 1094 } 1095 } 1096 1097 //TRACE("parent %p position %p: %s\n", parentItem, insertAfter, 1098 // (tvItem->mask & TVIF_TEXT) 1099 // ? ((tvItem->pszText == LPSTR_TEXTCALLBACKA) ? "<callback>" 1100 // : tvItem->pszText) 1101 // : "<no label>"); 1102 1103 newItem = TREEVIEW_AllocateItem(infoPtr); 1104 if (newItem == NULL) 1105 return (LRESULT)(HTREEITEM)NULL; 1106 1107 newItem->parent = parentItem; 1108 newItem->iIntegral = 1; 1109 1110 if (!TREEVIEW_DoSetItem(infoPtr,newItem,tvItem,unicode)) 1111 return (LRESULT)(HTREEITEM)NULL; 1112 1113 /* After this point, nothing can fail. (Except for TVI_SORT.) */ 1114 1115 infoPtr->uNumItems++; 1116 1117 if (insertAfter == TVI_FIRST) 1118 { 1119 TREEVIEW_InsertBefore(newItem, parentItem->firstChild, parentItem); 1120 } else if (insertAfter == TVI_LAST) 1121 { 1122 TREEVIEW_InsertAfter(newItem, parentItem->lastChild, parentItem); 1123 } else if (insertAfter == TVI_SORT) 1124 { 1125 TREEVIEW_ITEM *aChild; 1126 TREEVIEW_ITEM *previousChild = NULL; 1127 BOOL bItemInserted = FALSE; 1128 1129 aChild = parentItem->firstChild; 1130 1131 TREEVIEW_UpdateDispInfo(infoPtr, newItem, TVIF_TEXT); 1132 1133 /* Iterate the parent children to see where we fit in */ 1134 while (aChild) 1135 { 1136 INT comp; 1137 1138 TREEVIEW_UpdateDispInfo(infoPtr,aChild,TVIF_TEXT); 1139 comp = lstrcmpW(newItem->pszText,aChild->pszText); 1140 1141 if (comp < 0) /* we are smaller than the current one */ 1142 { 1143 TREEVIEW_InsertBefore(newItem, aChild, parentItem); 1144 bItemInserted = TRUE; 1145 break; 1146 } 1147 else if (comp > 0) /* we are bigger than the current one */ 1148 { 1149 previousChild = aChild; 1150 aChild = (aChild->nextSibling == 0) /* This will help us to exit */ 1151 ? NULL /* if there is no more sibling */ 1152 : aChild->nextSibling; 1153 1154 /* Look at the next item */ 1155 continue; 1156 } 1157 else if (comp == 0) 1158 { 1159 /* 1160 * An item with this name is already existing, therefore, 1161 * we add after the one we found 1162 */ 1163 TREEVIEW_InsertAfter(newItem, aChild, parentItem); 1164 bItemInserted = TRUE; 1165 break; 1166 } 1167 } 1168 1169 /* 1170 * we reach the end of the child list and the item as not 1171 * yet been inserted, therefore, insert it after the last child. 1172 */ 1173 if ((!bItemInserted) && (aChild == NULL)) 1174 TREEVIEW_InsertAfter(newItem, previousChild, parentItem); 1175 } else 1176 { 1177 /* hInsertAfter names a specific item we want to insert after */ 1178 TREEVIEW_InsertAfter(newItem,insertAfter,parentItem); 1179 } 1180 1181 //TRACE("new item %p; parent %p, mask %x\n", newItem, 1182 // newItem->parent, tvItem->mask); 1183 1184 newItem->iLevel = newItem->parent->iLevel + 1; 1185 1186 if (newItem->parent->cChildren == 0) 1187 newItem->parent->cChildren = 1; 1188 1189 if (infoPtr->dwStyle & TVS_CHECKBOXES) 1190 { 1191 if (STATEIMAGEINDEX(newItem->state) == 0) 1192 newItem->state |= INDEXTOSTATEIMAGEMASK(1); 1193 } 1194 1195 TREEVIEW_VerifyTree(infoPtr); 1196 1197 newItem->calculated = FALSE; 1198 TREEVIEW_QueueRefresh(infoPtr); 1199 1200 return (LRESULT)newItem; 1201 } 1202 1203 /* Item Deletion ************************************************************/ 1204 static void 1205 TREEVIEW_RemoveItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem); 1206 1207 static void 1208 TREEVIEW_RemoveAllChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *parentItem) 1209 { 1210 TREEVIEW_ITEM *kill = parentItem->firstChild; 1211 1212 while (kill != NULL) 1213 { 1214 TREEVIEW_ITEM *next = kill->nextSibling; 1215 1216 TREEVIEW_RemoveItem(infoPtr, kill); 1217 1218 kill = next; 1219 } 1220 1221 assert(parentItem->cChildren <= 0); /* I_CHILDRENCALLBACK or 0 */ 1222 assert(parentItem->firstChild == NULL); 1223 assert(parentItem->lastChild == NULL); 1224 } 1225 1226 static void 1227 TREEVIEW_UnlinkItem(TREEVIEW_ITEM *item) 1228 { 1229 TREEVIEW_ITEM *parentItem = item->parent; 1230 1231 assert(item != NULL); 1232 assert(item->parent != NULL); /* i.e. it must not be the root */ 1233 1234 if (parentItem->firstChild == item) 1235 parentItem->firstChild = item->nextSibling; 1236 1237 if (parentItem->lastChild == item) 1238 parentItem->lastChild = item->prevSibling; 1239 1240 if (parentItem->firstChild == NULL && parentItem->lastChild == NULL 1241 && parentItem->cChildren > 0) 1242 parentItem->cChildren = 0; 1243 1244 if (item->prevSibling) 1245 item->prevSibling->nextSibling = item->nextSibling; 1246 1247 if (item->nextSibling) 1248 item->nextSibling->prevSibling = item->prevSibling; 1249 } 1250 1251 static void 1252 TREEVIEW_RemoveItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem) 1253 { 1254 TREEVIEW_ITEM *newFirstVisible; 1255 1256 //TRACE("%p, (%s)\n", wineItem, TREEVIEW_ItemName(wineItem)); 1257 1258 TREEVIEW_SendTreeviewNotify(infoPtr,isUnicodeNotify(&infoPtr->header) ? TVN_DELETEITEMW:TVN_DELETEITEMA,TVIF_HANDLE | TVIF_PARAM,0,wineItem,0); 1259 1260 if (wineItem->firstChild) 1261 TREEVIEW_RemoveAllChildren(infoPtr, wineItem); 1262 1263 /* Selection is handled in TREEVIEW_DeleteItem. */ 1264 1265 if (infoPtr->insertMarkItem == wineItem) 1266 infoPtr->insertMarkItem = NULL; 1267 1268 /* XXX focusItem, hotItem, dropItem */ 1269 1270 TREEVIEW_UnlinkItem(wineItem); 1271 1272 infoPtr->uNumItems--; 1273 1274 if (wineItem->pszText != LPSTR_TEXTCALLBACKW) 1275 COMCTL32_Free(wineItem->pszText); 1276 1277 TREEVIEW_FreeItem(infoPtr, wineItem); 1278 } 1279 1280 1281 /* Empty out the tree. */ 1282 static void 1283 TREEVIEW_RemoveTree(TREEVIEW_INFO *infoPtr) 1284 { 1285 TREEVIEW_RemoveAllChildren(infoPtr, infoPtr->root); 1286 1287 assert(infoPtr->uNumItems == 0); /* root isn't counted in uNumItems */ 1288 } 1289 1290 static LRESULT 1291 TREEVIEW_DeleteItem(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1292 { 1293 TREEVIEW_ITEM *oldSelection = infoPtr->selectedItem; 1294 TREEVIEW_ITEM *newSelection = NULL; 1295 1296 if (lParam == (LPARAM)TVI_ROOT) 1297 { 1298 newSelection = NULL; 1299 TREEVIEW_RemoveTree(infoPtr); 1300 } 1301 else 1302 { 1303 TREEVIEW_ITEM *wineItem = (TREEVIEW_ITEM *)lParam; 1304 1305 if (!TREEVIEW_ValidItem(infoPtr, wineItem)) 1306 return FALSE; 1307 1308 //TRACE("%p (%s)\n", wineItem, TREEVIEW_ItemName(wineItem)); 1309 1310 if (infoPtr->selectedItem != NULL 1311 && (wineItem == infoPtr->selectedItem 1312 || TREEVIEW_IsChildOf(wineItem, infoPtr->selectedItem))) 1313 { 1314 if (wineItem->nextSibling) 1315 newSelection = wineItem->nextSibling; 1316 else if (wineItem->parent != infoPtr->root) 1317 newSelection = wineItem->parent; 1318 } 1319 1320 TREEVIEW_RemoveItem(infoPtr, wineItem); 1321 } 1322 1323 /* Don't change if somebody else already has. */ 1324 if (oldSelection == infoPtr->selectedItem 1325 && TREEVIEW_ValidItem(infoPtr, newSelection)) 1326 { 1327 TREEVIEW_DoSelectItem(infoPtr, TVGN_CARET, newSelection, TVC_UNKNOWN); 1328 } 1329 1330 TREEVIEW_VerifyTree(infoPtr); 1331 1332 TREEVIEW_QueueRefresh(infoPtr); 1333 1334 return TRUE; 1335 } 1336 1337 /* Get/Set Messages *********************************************************/ 1338 1339 static LRESULT 1340 TREEVIEW_GetIndent(TREEVIEW_INFO *infoPtr) 1341 { 1342 return infoPtr->uIndent; 1343 } 1344 1345 static LRESULT 1346 TREEVIEW_SetIndent(TREEVIEW_INFO *infoPtr, WPARAM wParam) 1347 { 1348 INT newIndent; 1349 1350 newIndent = (INT)wParam; 1351 if (newIndent < MINIMUM_INDENT) 1352 newIndent = MINIMUM_INDENT; 1353 1354 if (infoPtr->uIndent != newIndent) 1355 { 1356 infoPtr->uIndent = newIndent; 1357 1358 infoPtr->uInternalStatus |= TV_CALCALL; 1359 TREEVIEW_QueueRefresh(infoPtr); 1360 } 1361 1362 return 0; 1363 } 1364 1365 static LRESULT 1366 TREEVIEW_GetToolTips(TREEVIEW_INFO *infoPtr) 1367 { 1368 return infoPtr->hwndToolTip; 1369 } 1370 1371 static LRESULT 1372 TREEVIEW_SetToolTips(TREEVIEW_INFO *infoPtr, WPARAM wParam) 1373 { 1374 HWND prevToolTip; 1375 1376 prevToolTip = infoPtr->hwndToolTip; 1377 infoPtr->hwndToolTip = (HWND)wParam; 1378 1379 return prevToolTip; 1380 } 1381 1382 static LRESULT 1383 TREEVIEW_GetScrollTime(TREEVIEW_INFO *infoPtr) 1384 { 1385 return infoPtr->uScrollTime; 1386 } 1387 1388 static LRESULT 1389 TREEVIEW_SetScrollTime(TREEVIEW_INFO *infoPtr, UINT uScrollTime) 1390 { 1391 UINT uOldScrollTime = infoPtr->uScrollTime; 1392 1393 infoPtr->uScrollTime = min(uScrollTime, 100); 1394 1395 return uOldScrollTime; 1396 } 1397 1398 1399 static LRESULT 1400 TREEVIEW_GetImageList(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1401 { 1402 switch (wParam) 1403 { 1404 case (WPARAM)TVSIL_NORMAL: 1405 return (LRESULT)infoPtr->himlNormal; 1406 1407 case (WPARAM)TVSIL_STATE: 1408 return (LRESULT)infoPtr->himlState; 1409 1410 default: 1411 return 0; 1412 } 1413 } 1414 1415 static LRESULT 1416 TREEVIEW_SetImageList(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1417 { 1418 HIMAGELIST himlNew = (HIMAGELIST)lParam; 1419 HIMAGELIST himlOld = 0; 1420 1421 switch (wParam) 1422 { 1423 case (WPARAM)TVSIL_NORMAL: 1424 himlOld = infoPtr->himlNormal; 1425 infoPtr->himlNormal = himlNew; 1426 1427 if (himlNew != NULL) 1428 ImageList_GetIconSize(himlNew, &infoPtr->normalImageWidth, 1429 &infoPtr->normalImageHeight); 1430 else 1431 { 1432 infoPtr->normalImageWidth = 0; 1433 infoPtr->normalImageHeight = 0; 1434 } 1435 1436 break; 1437 1438 case (WPARAM)TVSIL_STATE: 1439 himlOld = infoPtr->himlState; 1440 infoPtr->himlState = himlNew; 1441 1442 if (himlNew != NULL) 1443 ImageList_GetIconSize(himlNew, &infoPtr->stateImageWidth, 1444 &infoPtr->stateImageHeight); 1445 else 1446 { 1447 infoPtr->stateImageWidth = 0; 1448 infoPtr->stateImageHeight = 0; 1449 } 1450 1451 break; 1452 } 1453 1454 infoPtr->uInternalStatus |= TV_CALCALL; 1455 TREEVIEW_QueueRefresh(infoPtr); 1456 1457 return (LRESULT)himlOld; 1458 } 1459 1460 /* Compute the natural height (based on the font size) for items. */ 1461 static UINT 1462 TREEVIEW_NaturalHeight(TREEVIEW_INFO *infoPtr) 1463 { 1464 TEXTMETRICA tm; 1465 HDC hdc = GetDC(infoPtr->hwnd); 1466 HFONT hOldFont = SelectObject(hdc, infoPtr->hFont); 1467 INT height; 1468 1469 GetTextMetricsA(hdc, &tm); 1470 1471 SelectObject(hdc, hOldFont); 1472 ReleaseDC(infoPtr->hwnd, hdc); 1473 1474 /* The 16 is a hack because our fonts are tiny. */ 1475 height = MAX(16, tm.tmHeight + tm.tmExternalLeading); 1476 if (!(infoPtr->dwStyle & TVS_NONEVENHEIGHT)) 1477 if (height & 0x1) height++; //important for PS_DOT pen! 1478 1479 return height; 1480 } 1481 1482 static LRESULT 1483 TREEVIEW_SetItemHeight(TREEVIEW_INFO *infoPtr, WPARAM wParam) 1484 { 1485 INT prevHeight = infoPtr->uItemHeight; 1486 1487 if (wParam == (WPARAM)(SHORT)-1) 1488 { 1489 infoPtr->uItemHeight = TREEVIEW_NaturalHeight(infoPtr); 1490 infoPtr->bHeightSet = FALSE; 1491 } 1492 else 1493 { 1494 infoPtr->uItemHeight = wParam; 1495 infoPtr->bHeightSet = TRUE; 1496 } 1497 1498 if (!(infoPtr->dwStyle & TVS_NONEVENHEIGHT)) 1499 if (infoPtr->uItemHeight & 0x1) infoPtr->uItemHeight++; 1500 1501 if (infoPtr->uItemHeight != prevHeight) 1502 { 1503 infoPtr->uInternalStatus |= TV_CALCALL; 1504 TREEVIEW_QueueRefresh(infoPtr); 1505 } 1506 1507 return prevHeight; 1508 } 1509 1510 static LRESULT 1511 TREEVIEW_GetItemHeight(TREEVIEW_INFO *infoPtr) 1512 { 1513 return infoPtr->uItemHeight; 1514 } 1515 1516 1517 static LRESULT 1518 TREEVIEW_GetFont(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1519 { 1520 return infoPtr->hFont; 1521 } 1522 1523 static LRESULT 1524 TREEVIEW_SetFont(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1525 { 1526 infoPtr->hFont = wParam ? (HFONT)wParam : GetStockObject(SYSTEM_FONT); 1527 1528 DeleteObject(infoPtr->hBoldFont); 1529 infoPtr->hBoldFont = TREEVIEW_CreateBoldFont(infoPtr->hFont); 1530 1531 if (!infoPtr->bHeightSet) 1532 infoPtr->uItemHeight = TREEVIEW_NaturalHeight(infoPtr); 1533 1534 SendMessageA(infoPtr->hwndToolTip,WM_SETFONT,infoPtr->hFont,1); 1535 infoPtr->uInternalStatus |= TV_CALCALL; 1536 TREEVIEW_CalcItems(infoPtr); 1537 1538 if (lParam) 1539 { 1540 TREEVIEW_UnqueueRefresh(infoPtr,FALSE,FALSE); 1541 TREEVIEW_Refresh(infoPtr); 1542 } 1543 1544 return 0; 1545 } 1546 1547 1548 static LRESULT 1549 TREEVIEW_GetLineColor(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1550 { 1551 return (LRESULT)infoPtr->clrLine; 1552 } 1553 1554 static LRESULT 1555 TREEVIEW_SetLineColor(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1556 { 1557 COLORREF prevColor = infoPtr->clrLine; 1558 1559 infoPtr->clrLine = (COLORREF)lParam; 1560 1561 return (LRESULT)prevColor; 1562 } 1563 1564 1565 static LRESULT 1566 TREEVIEW_GetTextColor(TREEVIEW_INFO *infoPtr) 1567 { 1568 return (LRESULT)infoPtr->clrText; 1569 } 1570 1571 static LRESULT 1572 TREEVIEW_SetTextColor(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1573 { 1574 COLORREF prevColor = infoPtr->clrText; 1575 1576 infoPtr->clrText = (COLORREF)lParam; 1577 1578 if (infoPtr->clrText != prevColor) 1579 TREEVIEW_QueueRefresh(infoPtr); 1580 1581 return (LRESULT)prevColor; 1582 } 1583 1584 1585 static LRESULT 1586 TREEVIEW_GetBkColor(TREEVIEW_INFO *infoPtr) 1587 { 1588 return (LRESULT)infoPtr->clrBk; 1589 } 1590 1591 static LRESULT 1592 TREEVIEW_SetBkColor(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1593 { 1594 COLORREF prevColor = infoPtr->clrBk; 1595 1596 infoPtr->clrBk = (COLORREF)lParam; 1597 1598 if (infoPtr->clrBk != prevColor) 1599 TREEVIEW_QueueRefresh(infoPtr); 1600 1601 return (LRESULT)prevColor; 1602 } 1603 1604 1605 static LRESULT 1606 TREEVIEW_GetInsertMarkColor(TREEVIEW_INFO *infoPtr, WPARAM wParam, 1607 LPARAM lParam) 1608 { 1609 return (LRESULT)infoPtr->clrInsertMark; 1610 } 1611 1612 static LRESULT 1613 TREEVIEW_SetInsertMarkColor(TREEVIEW_INFO *infoPtr, WPARAM wParam, 1614 LPARAM lParam) 1615 { 1616 COLORREF prevColor = infoPtr->clrInsertMark; 1617 1618 infoPtr->clrInsertMark = (COLORREF)lParam; 1619 1620 return (LRESULT)prevColor; 1621 } 1622 1623 1624 static LRESULT 1625 TREEVIEW_SetInsertMark(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1626 { 1627 if (!TREEVIEW_ValidItem(infoPtr, (HTREEITEM)lParam)) 1628 return 0; 1629 1630 infoPtr->insertBeforeorAfter = (BOOL)wParam; 1631 infoPtr->insertMarkItem = (HTREEITEM)lParam; 1632 1633 TREEVIEW_QueueRefresh(infoPtr); 1634 1635 return 1; 1636 } 1637 1638 /************************************************************************ 1639 * Some serious braindamage here. lParam is a pointer to both the 1640 * input HTREEITEM and the output RECT. 1641 */ 1642 static LRESULT 1643 TREEVIEW_GetItemRect(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1644 { 1645 TREEVIEW_ITEM *wineItem; 1646 const HTREEITEM *pItem = (HTREEITEM *)lParam; 1647 LPRECT lpRect = (LPRECT)lParam; 1648 1649 /* 1650 * validate parameters 1651 */ 1652 if ((pItem == NULL) || (lpRect == NULL)) 1653 return FALSE; 1654 1655 TREEVIEW_UnqueueRefresh(infoPtr,TRUE,TRUE); 1656 1657 wineItem = *pItem; 1658 if (!TREEVIEW_ValidItem(infoPtr, *pItem) || !wineItem->displayed) 1659 return FALSE; 1660 1661 if (!wineItem->calculated) 1662 TREEVIEW_CalcItem(infoPtr,wineItem,(HDC)0); 1663 1664 /* 1665 * If wParam is TRUE return the text size otherwise return 1666 * the whole item size 1667 */ 1668 if (wParam) 1669 { 1670 /* Windows does not send TVN_GETDISPINFO here. */ 1671 1672 lpRect->top = wineItem->rect.top; 1673 lpRect->bottom = wineItem->rect.bottom; 1674 1675 lpRect->left = wineItem->textOffset; 1676 lpRect->right = wineItem->textOffset+wineItem->textWidth+4; 1677 } 1678 else 1679 { 1680 *lpRect = wineItem->rect; 1681 } 1682 1683 return TRUE; 1684 } 1685 1686 static inline LRESULT 1687 TREEVIEW_GetVisibleCount(TREEVIEW_INFO *infoPtr) 1688 { 1689 /* Suprise! This does not take integral height into account. */ 1690 return infoPtr->clientHeight / infoPtr->uItemHeight; 1691 } 1692 1693 static LRESULT 1694 TREEVIEW_GetItem(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam,BOOL unicode) 1695 { 1696 LPTVITEMEXW tvItem; 1697 TREEVIEW_ITEM *wineItem; 1698 1699 tvItem = (LPTVITEMEXW)lParam; 1700 1701 wineItem = tvItem->hItem; 1702 1703 if (!TREEVIEW_ValidItem(infoPtr, wineItem)) 1704 return FALSE; 1705 1706 TREEVIEW_UpdateDispInfo(infoPtr, wineItem, tvItem->mask); 1707 1708 if (tvItem->mask & TVIF_CHILDREN) 1709 tvItem->cChildren = wineItem->cChildren; 1710 1711 if (tvItem->mask & TVIF_HANDLE) 1712 tvItem->hItem = wineItem; 1713 1714 if (tvItem->mask & TVIF_IMAGE) 1715 tvItem->iImage = wineItem->iImage; 1716 1717 if (tvItem->mask & TVIF_INTEGRAL) 1718 tvItem->iIntegral = wineItem->iIntegral; 1719 1720 /* undocumented: windows ignores TVIF_PARAM and 1721 * * always sets lParam 1722 */ 1723 tvItem->lParam = wineItem->lParam; 1724 1725 if (tvItem->mask & TVIF_SELECTEDIMAGE) 1726 tvItem->iSelectedImage = wineItem->iSelectedImage; 1727 1728 if (tvItem->mask & TVIF_STATE) 1729 tvItem->state = wineItem->state & tvItem->stateMask; 1730 1731 if (tvItem->mask & TVIF_TEXT) 1732 { 1733 if (unicode) 1734 lstrcpynW(tvItem->pszText,wineItem->pszText,tvItem->cchTextMax); 1735 else 1736 lstrcpynWtoA((CHAR*)tvItem->pszText,wineItem->pszText,tvItem->cchTextMax); 1737 } 1738 1739 return TRUE; 1740 } 1741 1742 /* Beware MSDN Library Visual Studio 6.0. It says -1 on failure, 0 on success, 1743 * which is wrong. */ 1744 static LRESULT 1745 TREEVIEW_SetItem(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam,BOOL unicode) 1746 { 1747 TREEVIEW_ITEM *wineItem; 1748 TVITEMEXW *tvItem; 1749 DWORD changed = 0; 1750 1751 if (infoPtr->hwndEdit) SetFocus(infoPtr->hwnd); 1752 1753 tvItem = (LPTVITEMEXW)lParam; 1754 wineItem = tvItem->hItem; 1755 1756 if (!TREEVIEW_ValidItem(infoPtr, wineItem)) 1757 return FALSE; 1758 1759 if (!TREEVIEW_DoSetItem(infoPtr,wineItem,tvItem,unicode,&changed)) 1760 return FALSE; 1761 1762 /* If the text or TVIS_BOLD was changed, and it is displayed, recalculate. */ 1763 if (((changed & TVIF_TEXT) || ((tvItem->mask & TVIF_STATE) && (tvItem->stateMask & TVIS_BOLD))) && wineItem->displayed) 1764 { 1765 TREEVIEW_ComputeTextWidth(infoPtr,wineItem,0,FALSE); 1766 } 1767 1768 if (changed & (TVIF_INTEGRAL | TVIF_CHILDREN)) 1769 TREEVIEW_QueueRefresh(infoPtr); 1770 else 1771 TREEVIEW_RefreshItem(infoPtr,wineItem,changed); 1772 1773 return TRUE; 1774 } 1775 1776 static LRESULT 1777 TREEVIEW_GetItemState(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1778 { 1779 TREEVIEW_ITEM *wineItem = (HTREEITEM)wParam; 1780 1781 if (!wineItem || !TREEVIEW_ValidItem(infoPtr, wineItem)) 1782 return 0; 1783 1784 return (wineItem->state & lParam); 1785 } 1786 1787 static LRESULT 1788 TREEVIEW_GetNextItem(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1789 { 1790 TREEVIEW_ITEM *wineItem; 1791 TREEVIEW_ITEM *retval; 1792 WPARAM which; 1793 1794 which = (INT)wParam; 1795 wineItem = (TREEVIEW_ITEM *)lParam; 1796 retval = 0; 1797 1798 /* handle all the global data here */ 1799 switch (which) 1800 { 1801 case TVGN_CHILD: /* Special case: child of 0 is root */ 1802 if (wineItem) 1803 break; 1804 /* fall through */ 1805 case TVGN_ROOT: 1806 retval = infoPtr->root->firstChild; 1807 break; 1808 1809 case TVGN_CARET: 1810 retval = infoPtr->selectedItem; 1811 break; 1812 1813 case TVGN_FIRSTVISIBLE: 1814 TREEVIEW_UnqueueRefresh(infoPtr,TRUE,TRUE); 1815 retval = infoPtr->firstVisible; 1816 break; 1817 1818 case TVGN_DROPHILITE: 1819 retval = infoPtr->dropItem; 1820 break; 1821 } 1822 1823 if (retval) 1824 { 1825 //TRACE("flags:%x, returns %p\n", which, retval); 1826 return (LRESULT)retval; 1827 } 1828 1829 if (!TREEVIEW_ValidItem(infoPtr, wineItem)) 1830 return FALSE; 1831 1832 switch (which) 1833 { 1834 case TVGN_NEXT: 1835 retval = wineItem->nextSibling; 1836 break; 1837 1838 case TVGN_PREVIOUS: 1839 retval = wineItem->prevSibling; 1840 break; 1841 1842 case TVGN_PARENT: 1843 retval = (wineItem->parent != infoPtr->root) ? wineItem->parent : NULL; 1844 break; 1845 1846 case TVGN_CHILD: 1847 retval = wineItem->firstChild; 1848 break; 1849 1850 case TVGN_LASTVISIBLE: 1851 retval = TREEVIEW_GetLastListItem(infoPtr, wineItem); 1852 break; 1853 1854 case TVGN_NEXTVISIBLE: 1855 retval = TREEVIEW_GetNextListItem(infoPtr, wineItem); 1856 break; 1857 1858 case TVGN_PREVIOUSVISIBLE: 1859 retval = TREEVIEW_GetPrevListItem(infoPtr, wineItem); 1860 break; 1861 1862 default: 1863 //TRACE("Unknown msg %x,item %p\n", which, wineItem); 1864 break; 1865 } 1866 1867 //TRACE("flags:%x, item %p;returns %p\n", which, wineItem, retval); 1868 return (LRESULT)retval; 1869 } 1870 1871 1872 static LRESULT 1873 TREEVIEW_GetCount(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1874 { 1875 return (LRESULT)infoPtr->uNumItems; 1876 } 1877 1878 static VOID 1879 TREEVIEW_ToggleItemState(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) 1880 { 1881 if (infoPtr->dwStyle & TVS_CHECKBOXES) 1882 { 1883 static const unsigned int state_table[] = { 0, 2, 1 }; 1884 1885 unsigned int state; 1886 1887 state = STATEIMAGEINDEX(item->state); 1888 //TRACE("state:%x\n", state); 1889 item->state &= ~TVIS_STATEIMAGEMASK; 1890 1891 if (state < 3) 1892 state = state_table[state]; 1893 1894 item->state |= INDEXTOSTATEIMAGEMASK(state); 1895 1896 //TRACE("state:%x\n", state); 1897 TREEVIEW_RefreshItem(infoPtr,item,TVIF_IMAGE); 1898 } 1899 } 1900 1901 1902 /* Painting *************************************************************/ 1903 1904 /* Draw the lines and expand button for an item. Also draws one section 1905 * of the line from item's parent to item's parent's next sibling. */ 1906 static void 1907 TREEVIEW_DrawItemLines(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *item) 1908 { 1909 LONG centerx, centery; 1910 BOOL lar = ((infoPtr->dwStyle 1911 & (TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS)) 1912 > TVS_LINESATROOT); 1913 1914 if (!lar && item->iLevel == 0) 1915 return; 1916 1917 centerx = (item->linesOffset + item->stateOffset) / 2; 1918 centery = (item->rect.top + item->rect.bottom) / 2; 1919 1920 if (infoPtr->dwStyle & TVS_HASLINES) 1921 { 1922 HPEN hOldPen, hNewPen; 1923 HTREEITEM parent; 1924 1925 /* 1926 * Get a dotted grey pen 1927 */ 1928 hNewPen = CreatePen(PS_DOT, 0, infoPtr->clrLine); 1929 hOldPen = SelectObject(hdc, hNewPen); 1930 1931 MoveToEx(hdc, item->stateOffset, centery, NULL); 1932 LineTo(hdc, centerx - 1, centery); 1933 1934 if (item->prevSibling || item->parent != infoPtr->root) 1935 { 1936 MoveToEx(hdc, centerx, item->rect.top, NULL); 1937 LineTo(hdc, centerx, centery); 1938 } 1939 1940 if (item->nextSibling) 1941 { 1942 MoveToEx(hdc, centerx, centery, NULL); 1943 LineTo(hdc, centerx, item->rect.bottom + 1); 1944 } 1945 1946 /* Draw the line from our parent to its next sibling. */ 1947 parent = item->parent; 1948 while (parent != infoPtr->root) 1949 { 1950 int pcenterx = (parent->linesOffset + parent->stateOffset) / 2; 1951 1952 if (parent->nextSibling 1953 /* skip top-levels unless TVS_LINESATROOT */ 1954 && parent->stateOffset > parent->linesOffset) 1955 { 1956 MoveToEx(hdc, pcenterx, item->rect.top, NULL); 1957 LineTo(hdc, pcenterx, item->rect.bottom + 1); 1958 } 1959 1960 parent = parent->parent; 1961 } 1962 1963 SelectObject(hdc, hOldPen); 1964 DeleteObject(hNewPen); 1965 } 1966 1967 /* 1968 * Display the (+/-) signs 1969 */ 1970 1971 if (infoPtr->dwStyle & TVS_HASBUTTONS) 1972 { 1973 if (item->cChildren) 1974 { 1975 LONG height = item->rect.bottom - item->rect.top; 1976 LONG width = item->stateOffset - item->linesOffset; 1977 LONG rectsize = MIN(height, width) / 4; 1978 /* plussize = ceil(rectsize * 3/4) */ 1979 LONG plussize = (rectsize + 1) * 3 / 4; 1980 1981 HPEN hNewPen = CreatePen(PS_SOLID, 0, infoPtr->clrLine); 1982 HPEN hOldPen = SelectObject(hdc, hNewPen); 1983 1984 Rectangle(hdc, centerx - rectsize, centery - rectsize, 1985 centerx + rectsize + 1, centery + rectsize + 1); 1986 1987 SelectObject(hdc, hOldPen); 1988 DeleteObject(hNewPen); 1989 1990 MoveToEx(hdc, centerx - plussize + 1, centery, NULL); 1991 LineTo(hdc, centerx + plussize, centery); 1992 1993 if (!(item->state & TVIS_EXPANDED)) 1994 { 1995 MoveToEx(hdc, centerx, centery - plussize + 1, NULL); 1996 LineTo(hdc, centerx, centery + plussize); 1997 } 1998 } 1999 } 2000 } 2001 2002 static VOID TREEVIEW_DrawHottrackLine(HDC hdc,TREEVIEW_ITEM *item) 2003 { 2004 HPEN hPen,hOldPen; 2005 INT rop; 2006 2007 if (!item->inclient) return; 2008 2009 rop = SetROP2(hdc,R2_XORPEN); 2010 hPen = CreatePen(PS_SOLID,2,RGB(0,0,0)); 2011 hOldPen = SelectObject(hdc,hPen); 2012 2013 MoveToEx(hdc,item->textOffset,item->rect.bottom-1,NULL); 2014 LineTo(hdc,item->textOffset+item->textWidth,item->rect.bottom-1); 2015 2016 DeleteObject(hPen); 2017 SelectObject(hdc,hOldPen); 2018 SetROP2(hdc,rop); 2019 } 2020 2021 static void 2022 TREEVIEW_DrawItem(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *wineItem) 2023 { 2024 INT cditem; 2025 HFONT hOldFont; 2026 int centery; 2027 2028 if (!wineItem->calculated) TREEVIEW_CalcItem(infoPtr,wineItem,hdc); 2029 2030 hOldFont = SelectObject(hdc, TREEVIEW_FontForItem(infoPtr, wineItem)); 2031 2032 TREEVIEW_UpdateDispInfo(infoPtr, wineItem, CALLBACK_MASK_ALL); 2033 2034 /* The custom draw handler can query the text rectangle, 2035 * so get ready. */ 2036 TREEVIEW_ComputeTextWidth(infoPtr,wineItem,hdc,TRUE); 2037 2038 cditem = 0; 2039 2040 if (infoPtr->cdmode & CDRF_NOTIFYITEMDRAW) 2041 { 2042 cditem = TREEVIEW_SendCustomDrawItemNotify(infoPtr, hdc, wineItem, CDDS_ITEMPREPAINT); 2043 2044 if (cditem & CDRF_SKIPDEFAULT) 2045 { 2046 SelectObject(hdc, hOldFont); 2047 return; 2048 } 2049 } 2050 2051 if (cditem & CDRF_NEWFONT) 2052 TREEVIEW_ComputeTextWidth(infoPtr,wineItem,hdc,TRUE); 2053 2054 TREEVIEW_DrawItemLines(infoPtr, hdc, wineItem); 2055 2056 centery = (wineItem->rect.top + wineItem->rect.bottom) / 2; 2057 2058 /* 2059 * Display the images associated with this item 2060 */ 2061 { 2062 INT imageIndex; 2063 2064 /* State images are displayed to the left of the Normal image 2065 * image number is in state; zero should be `display no image'. 2066 */ 2067 imageIndex = STATEIMAGEINDEX(wineItem->state); 2068 2069 if (infoPtr->himlState && imageIndex) 2070 { 2071 ImageList_Draw(infoPtr->himlState, imageIndex - 1, hdc, 2072 wineItem->stateOffset, 2073 centery - infoPtr->stateImageHeight / 2, 2074 ILD_NORMAL); 2075 } 2076 2077 /* Now, draw the normal image; can be either selected or 2078 * non-selected image. 2079 */ 2080 2081 if ((wineItem->state & TVIS_SELECTED) && wineItem->iSelectedImage) 2082 { 2083 /* The item is curently selected */ 2084 imageIndex = wineItem->iSelectedImage; 2085 } 2086 else 2087 { 2088 /* The item is not selected */ 2089 imageIndex = wineItem->iImage; 2090 } 2091 2092 if (infoPtr->himlNormal && (imageIndex != I_IMAGENONE)) 2093 { 2094 int ovlIdx = wineItem->state & TVIS_OVERLAYMASK; 2095 2096 ImageList_Draw(infoPtr->himlNormal, imageIndex, hdc, 2097 wineItem->imageOffset, 2098 centery - infoPtr->normalImageHeight / 2, 2099 ILD_NORMAL | ovlIdx); 2100 } 2101 } 2102 2103 2104 /* 2105 * Display the text associated with this item 2106 */ 2107 2108 /* Don't paint item's text if it's being edited */ 2109 if (!infoPtr->hwndEdit) 2110 { 2111 if (wineItem->pszText && (wineItem->pszText[0] != 0)) 2112 { 2113 COLORREF oldTextColor = 0; 2114 INT oldBkMode; 2115 HBRUSH hbrBk = 0; 2116 BOOL inFocus = (GetFocus() == infoPtr->hwnd); 2117 RECT rcText; 2118 2119 oldBkMode = SetBkMode(hdc, TRANSPARENT); 2120 2121 /* - If item is drop target or it is selected and window is in focus - 2122 * use blue background (COLOR_HIGHLIGHT). 2123 * - If item is selected, window is not in focus, but it has style 2124 * TVS_SHOWSELALWAYS - use grey background (COLOR_BTNFACE) 2125 * - Otherwise - don't fill background 2126 */ 2127 if ((wineItem->state & TVIS_DROPHILITED) || 2128 ((wineItem->state & TVIS_SELECTED) && 2129 (inFocus || (infoPtr->dwStyle & TVS_SHOWSELALWAYS)))) 2130 { 2131 if ((wineItem->state & TVIS_DROPHILITED) || inFocus) 2132 { 2133 hbrBk = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT)); 2134 oldTextColor = 2135 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); 2136 } 2137 else 2138 { 2139 hbrBk = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); 2140 2141 if (infoPtr->clrText == -1) 2142 oldTextColor = 2143 SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); 2144 else 2145 oldTextColor = SetTextColor(hdc, infoPtr->clrText); 2146 } 2147 } 2148 else 2149 { 2150 if (infoPtr->clrText == -1) 2151 oldTextColor = 2152 SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); 2153 else 2154 oldTextColor = SetTextColor(hdc, infoPtr->clrText); 2155 } 2156 2157 rcText.top = wineItem->rect.top; 2158 rcText.bottom = wineItem->rect.bottom; 2159 rcText.left = wineItem->textOffset; 2160 rcText.right = rcText.left + wineItem->textWidth + 4; 2161 2162 if (hbrBk) 2163 { 2164 FillRect(hdc, &rcText, hbrBk); 2165 DeleteObject(hbrBk); 2166 } 2167 2168 /* Draw the box arround the selected item */ 2169 if ((wineItem->state & TVIS_SELECTED) && inFocus) 2170 { 2171 HPEN hNewPen = CreatePen(PS_DOT, 0, 2172 GetSysColor(COLOR_WINDOWTEXT)); 2173 HPEN hOldPen = SelectObject(hdc, hNewPen); 2174 INT rop = SetROP2(hdc, R2_XORPEN); 2175 POINT points[5]; 2176 2177 points[4].x = points[0].x = rcText.left; 2178 points[4].y = points[0].y = rcText.top; 2179 points[1].x = rcText.right - 1; 2180 points[1].y = rcText.top; 2181 points[2].x = rcText.right - 1; 2182 points[2].y = rcText.bottom - 1; 2183 points[3].x = rcText.left; 2184 points[3].y = rcText.bottom - 1; 2185 2186 Polyline(hdc, points, 5); 2187 2188 SetROP2(hdc, rop); 2189 SelectObject(hdc, hOldPen); 2190 DeleteObject(hNewPen); 2191 } 2192 2193 rcText.left += 2; 2194 rcText.right -= 2; 2195 2196 /* Draw it */ 2197 DrawTextW(hdc, 2198 wineItem->pszText, 2199 lstrlenW(wineItem->pszText), 2200 &rcText, 2201 DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX); 2202 2203 /* Restore the hdc state */ 2204 SetTextColor(hdc, oldTextColor); 2205 2206 if (oldBkMode != TRANSPARENT) 2207 SetBkMode(hdc, oldBkMode); 2208 } 2209 } 2210 2211 /* Draw insertion mark if necessary */ 2212 2213 if (wineItem == infoPtr->insertMarkItem) 2214 { 2215 HPEN hNewPen, hOldPen; 2216 int offset; 2217 int left, right; 2218 2219 hNewPen = CreatePen(PS_SOLID, 2, infoPtr->clrInsertMark); 2220 hOldPen = SelectObject(hdc, hNewPen); 2221 2222 if (infoPtr->insertBeforeorAfter) 2223 offset = wineItem->rect.bottom - 1; 2224 else 2225 offset = wineItem->rect.top + 1; 2226 2227 left = wineItem->textOffset - 2; 2228 right = wineItem->textOffset + wineItem->textWidth + 2; 2229 2230 MoveToEx(hdc, left, offset - 3, NULL); 2231 LineTo(hdc, left, offset + 4); 2232 2233 MoveToEx(hdc, left, offset, NULL); 2234 LineTo(hdc, right + 1, offset); 2235 2236 MoveToEx(hdc, right, offset + 3, NULL); 2237 LineTo(hdc, right, offset - 4); 2238 2239 SelectObject(hdc, hOldPen); 2240 DeleteObject(hNewPen); 2241 } 2242 2243 //draw hot item if necessary 2244 if (wineItem == infoPtr->hotItem) 2245 TREEVIEW_DrawHottrackLine(hdc,wineItem); 2246 2247 if (cditem & CDRF_NOTIFYPOSTPAINT) 2248 { 2249 cditem = TREEVIEW_SendCustomDrawItemNotify(infoPtr, hdc, wineItem, CDDS_ITEMPOSTPAINT); 2250 } 2251 2252 SelectObject(hdc, hOldFont); 2253 } 2254 2255 static void TREEVIEW_QueueRefresh(TREEVIEW_INFO *infoPtr) 2256 { 2257 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) 2258 KillTimer(infoPtr->hwnd,TV_REFRESH_TIMER); 2259 2260 if (infoPtr->uInternalStatus & TV_NOREDRAW) 2261 { 2262 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET; 2263 2264 return; 2265 } 2266 2267 SetTimer(infoPtr->hwnd,TV_REFRESH_TIMER,TV_REFRESH_DELAY,0); 2268 infoPtr->Timer |= TV_REFRESH_TIMER_SET; 2269 } 2270 2271 static BOOL TREEVIEW_UnqueueRefresh(TREEVIEW_INFO *infoPtr,BOOL calc,BOOL refresh) 2272 { 2273 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) 2274 { 2275 KillTimer(infoPtr->hwnd,TV_REFRESH_TIMER); 2276 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET; 2277 2278 if (calc) TREEVIEW_CalcItems(infoPtr); 2279 if (refresh) 2280 { 2281 TREEVIEW_Refresh(infoPtr); 2282 UpdateWindow(infoPtr->hwnd); 2283 } 2284 2285 return TRUE; 2286 } 2287 2288 return FALSE; 2289 } 2290 2291 static void 2292 TREEVIEW_Draw(TREEVIEW_INFO *infoPtr,HDC hdc,RECT *updateRect) 2293 { 1597 2294 RECT rect; 1598 2295 TREEVIEW_ITEM *item; 1599 INT iItem,indent; 1600 BOOL visFound = FALSE; 1601 HPEN hNewPen,hOldPen; 1602 1603 TREEVIEW_UnqueueRefresh(hwnd,TRUE,FALSE); 1604 1605 GetClientRect (hwnd, &rect); 2296 INT iItem; 2297 2298 TREEVIEW_UnqueueRefresh(infoPtr,TRUE,FALSE); 2299 2300 GetClientRect(infoPtr->hwnd,&rect); 1606 2301 if ((rect.left == rect.right) || (rect.top == rect.bottom)) return; 1607 2302 1608 infoPtr->cdmode = TREEVIEW_SendCustomDrawNotify( hwnd, CDDS_PREPAINT, hdc,rect);2303 infoPtr->cdmode = TREEVIEW_SendCustomDrawNotify(infoPtr,CDDS_PREPAINT,hdc,rect); 1609 2304 1610 2305 if (infoPtr->cdmode == CDRF_SKIPDEFAULT) return; 1611 2306 1612 / /draw items1613 1614 hNewPen = CreatePen(PS_DOT,0,infoPtr->clrLine); 1615 1616 iItem = (INT)infoPtr->TopRootItem;1617 indent = 0;1618 1619 while (iItem)1620 {1621 item = &infoPtr->items[iItem];1622 if (item->visible)2307 /* We iterate through all visible items in order */ 2308 item = infoPtr->firstVisible; 2309 2310 while ((item != NULL) && item->inclient) 2311 { 2312 RECT itemRect = item->rect; 2313 2314 if (!item->calculated) TREEVIEW_CalcItem(infoPtr,item,hdc); 2315 if (updateRect && IntersectRect(NULL,&itemRect,updateRect)) 2316 TREEVIEW_DrawItem(infoPtr,hdc,item); 2317 else 1623 2318 { 1624 if (updateRect && IntersectRect(NULL,&item->rect,updateRect)) 1625 { 1626 TREEVIEW_DrawItem(hwnd,hdc,item,dwStyle,infoPtr); 1627 visFound = TRUE; 1628 } else if (updateRect && (item->rect.top >= updateRect->bottom)) break; 1629 } else if (visFound) break; 1630 if (!visFound && (dwStyle & TVS_HASLINES) && (dwStyle & TVS_LINESATROOT)) 1631 { 1632 //draw vertical connections 1633 hOldPen = SelectObject(hdc,hNewPen); 1634 TREEVIEW_DrawVLines(hdc,infoPtr,item); 1635 SelectObject(hdc,hOldPen); 2319 if (updateRect && (item->rect.top >= updateRect->bottom)) break; 2320 itemRect.left = 0; 2321 if (updateRect && IntersectRect(NULL,&itemRect,updateRect)) 2322 TREEVIEW_DrawItemLines(infoPtr,hdc,item); 1636 2323 } 1637 if (item->firstChild && (item->state & TVIS_EXPANDED)) 1638 { 1639 iItem = (INT)item->firstChild; 1640 indent++; 1641 } else 1642 { 1643 iItem = (INT)item->sibling; 1644 while (!iItem && (indent > 0)) 1645 { 1646 item = &infoPtr->items[(INT)item->parent]; 1647 iItem = (INT)item->sibling; 1648 indent--; 1649 } 1650 } 1651 } 1652 1653 DeleteObject(hNewPen); 2324 item = TREEVIEW_GetNextListItem(infoPtr,item); 2325 } 1654 2326 1655 2327 if (infoPtr->cdmode & CDRF_NOTIFYPOSTPAINT) 1656 infoPtr->cdmode = TREEVIEW_SendCustomDrawNotify(hwnd, CDDS_POSTPAINT, hdc, rect); 1657 } 1658 1659 static LRESULT TREEVIEW_SetRedraw(HWND hwnd,WPARAM wParam,LPARAM lParam) 1660 { 1661 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 1662 1663 if (wParam) 1664 { 1665 if (!(infoPtr->uInternalStatus & TV_NOREDRAW)) return 0; 1666 infoPtr->uInternalStatus &= ~TV_NOREDRAW; 1667 TREEVIEW_CalcItems(hwnd,0,infoPtr); 1668 TREEVIEW_Refresh(hwnd); 2328 infoPtr->cdmode = TREEVIEW_SendCustomDrawNotify(infoPtr, CDDS_POSTPAINT, hdc, rect); 2329 } 2330 2331 static void TREEVIEW_Refresh(TREEVIEW_INFO *infoPtr) 2332 { 2333 TREEVIEW_UnqueueRefresh(infoPtr,TRUE,FALSE); 2334 2335 InvalidateRect(infoPtr->hwnd,NULL,TRUE); 2336 } 2337 2338 static void TREEVIEW_RefreshItem(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item,DWORD changed) 2339 { 2340 if (item && item->inclient) 2341 { 2342 RECT rect = item->rect; 2343 2344 //left 2345 if (changed & TVIF_STATE) rect.left = item->stateOffset; 2346 else if (changed & (TVIF_IMAGE | TVIF_SELECTEDIMAGE)) rect.left = item->imageOffset; 2347 else if (changed & TVIF_TEXT) rect.left = item->textOffset; 2348 2349 //right 2350 if (changed & TVIF_TEXT); 2351 else if (changed & (TVIF_IMAGE | TVIF_SELECTEDIMAGE)) rect.right = item->imageOffset-infoPtr->normalImageWidth; 2352 else if (changed & TVIF_STATE) rect.right = item->stateOffset-infoPtr->stateImageWidth; 2353 2354 InvalidateRect(infoPtr->hwnd,&rect,TRUE); 2355 } 2356 } 2357 2358 static LRESULT 2359 TREEVIEW_Paint(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 2360 { 2361 HDC hdc = (HDC)wParam; 2362 2363 if (!hdc) 2364 { 2365 PAINTSTRUCT ps; 2366 2367 hdc = BeginPaint(infoPtr->hwnd,&ps); 2368 TREEVIEW_Draw(infoPtr,hdc,&ps.rcPaint); 2369 EndPaint(infoPtr->hwnd,&ps); 1669 2370 } else 1670 { 1671 infoPtr->uInternalStatus |= TV_NOREDRAW; 1672 } 2371 TREEVIEW_Draw(infoPtr,hdc,NULL); 1673 2372 1674 2373 return 0; 1675 2374 } 1676 2375 1677 1678 static LRESULT 1679 TREEVIEW_HandleTimer (HWND hwnd, WPARAM wParam, LPARAM lParam) 1680 { 1681 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 1682 1683 switch (wParam) 1684 { 1685 case TV_REFRESH_TIMER: 1686 KillTimer (hwnd, TV_REFRESH_TIMER); 1687 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET; 1688 TREEVIEW_CalcItems(hwnd,0,infoPtr); 1689 TREEVIEW_Refresh(hwnd); 1690 return 0; 1691 1692 case TV_EDIT_TIMER: 1693 KillTimer (hwnd, TV_EDIT_TIMER); 1694 infoPtr->Timer &= ~TV_EDIT_TIMER_SET; 1695 if (infoPtr->editItem) 1696 TREEVIEW_EditLabel(hwnd,infoPtr->editItem,TRUE); 1697 return 0; 1698 1699 case TV_INFOTIP_TIMER: 1700 TREEVIEW_CheckInfoTip(hwnd); 1701 return 0; 1702 } 1703 1704 return 1; 1705 } 1706 1707 static void TREEVIEW_QueueRefresh(HWND hwnd) 1708 1709 { 1710 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 1711 1712 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) 1713 KillTimer (hwnd, TV_REFRESH_TIMER); 1714 1715 if (infoPtr->uInternalStatus & TV_NOREDRAW) 1716 { 1717 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET; 1718 1719 return; 1720 } 1721 1722 SetTimer (hwnd, TV_REFRESH_TIMER, TV_REFRESH_DELAY, 0); 1723 infoPtr->Timer |= TV_REFRESH_TIMER_SET; 1724 } 1725 1726 static BOOL TREEVIEW_UnqueueRefresh(HWND hwnd,BOOL calc,BOOL refresh) 1727 { 1728 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 1729 1730 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) 1731 { 1732 KillTimer (hwnd, TV_REFRESH_TIMER); 1733 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET; 1734 if (calc) TREEVIEW_CalcItems(hwnd,0,infoPtr); 1735 if (refresh) 1736 { 1737 TREEVIEW_Refresh(hwnd); 1738 UpdateWindow(hwnd); 1739 } 1740 1741 return TRUE; 1742 } 1743 1744 return FALSE; 1745 } 1746 1747 static LRESULT 1748 TREEVIEW_GetItem(HWND hwnd,WPARAM wParam,LPARAM lParam,BOOL unicode) 1749 { 1750 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 1751 LPTVITEMEXW tvItem; 1752 TREEVIEW_ITEM *wineItem; 1753 INT iItem; 1754 1755 tvItem = (LPTVITEMEXW)lParam; 1756 iItem = (INT)tvItem->hItem; 1757 1758 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem); 1759 if (!wineItem) return FALSE; 1760 1761 if (tvItem->mask & TVIF_CHILDREN) 1762 tvItem->cChildren = TREEVIEW_HasChildren(hwnd, wineItem); 1763 1764 if (tvItem->mask & TVIF_HANDLE) 1765 tvItem->hItem = wineItem->hItem; 1766 1767 if (tvItem->mask & TVIF_IMAGE) 1768 { 1769 if (wineItem->iImage == I_IMAGECALLBACK) 1770 tvItem->iImage = TREEVIEW_CallbackImage(hwnd,wineItem); 1771 else 1772 tvItem->iImage = wineItem->iImage; 1773 } 1774 1775 if (tvItem->mask & TVIF_INTEGRAL) 1776 tvItem->iIntegral = wineItem->iIntegral; 1777 1778 // undocumented: windows ignores TVIF_PARAM and 1779 // always sets lParam 1780 tvItem->lParam = wineItem->lParam; 1781 1782 if (tvItem->mask & TVIF_SELECTEDIMAGE) 1783 { 1784 if (wineItem->iSelectedImage == I_IMAGECALLBACK) 1785 tvItem->iSelectedImage = TREEVIEW_CallbackSelectedImage(hwnd,wineItem); 1786 else 1787 tvItem->iSelectedImage = wineItem->iSelectedImage; 1788 } 1789 1790 if (tvItem->mask & TVIF_STATE) 1791 tvItem->state = wineItem->state & tvItem->stateMask; 1792 1793 if (tvItem->mask & TVIF_TEXT) 1794 { 1795 WCHAR* text; 1796 BOOL mustFree = FALSE; 1797 1798 if (wineItem->pszText == LPSTR_TEXTCALLBACKW) 1799 text = TREEVIEW_CallbackText(hwnd,wineItem,&mustFree); 1800 else 1801 text = wineItem->pszText; 1802 1803 if (unicode) 1804 lstrcpynW(tvItem->pszText,text,tvItem->cchTextMax); 1805 else 1806 lstrcpynWtoA((LPSTR)tvItem->pszText,text,tvItem->cchTextMax); 1807 if (mustFree) COMCTL32_Free(text); 1808 } 1809 1810 return TRUE; 1811 } 1812 1813 1814 1815 /* FIXME: check implementation of TVGN_NEXT/TVGN_NEXTVISIBLE */ 1816 1817 static LRESULT 1818 TREEVIEW_GetNextItem (HWND hwnd, WPARAM wParam, LPARAM lParam) 1819 1820 { 1821 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 1822 TREEVIEW_ITEM *wineItem, *returnItem; 1823 INT iItem, retval, flag; 1824 1825 flag = (INT) wParam; 1826 iItem = (INT) lParam; 1827 retval = 0; 1828 switch (flag) 1829 { 1830 case TVGN_CHILD: /* Special case: child of 0 is root */ 1831 if (iItem) break; 1832 1833 case TVGN_ROOT: 1834 retval = (INT)infoPtr->TopRootItem; 1835 break; 1836 1837 case TVGN_CARET: 1838 retval = (INT)infoPtr->selectedItem; 1839 break; 1840 1841 case TVGN_FIRSTVISIBLE: 1842 TREEVIEW_UnqueueRefresh(hwnd,TRUE,TRUE); 1843 retval = (INT)infoPtr->firstVisible; 1844 break; 1845 1846 case TVGN_DROPHILITE: 1847 retval = (INT)infoPtr->dropItem; 1848 break; 1849 } 1850 1851 if (retval) return retval; 1852 1853 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem); 1854 returnItem = NULL; 1855 if (!wineItem) return FALSE; 1856 1857 switch (flag) 1858 { 1859 case TVGN_NEXT: 1860 retval = (INT)wineItem->sibling; 1861 break; 1862 1863 case TVGN_PREVIOUS: 1864 retval = (INT)wineItem->upsibling; 1865 break; 1866 1867 case TVGN_PARENT: 1868 retval = (INT)wineItem->parent; 1869 break; 1870 1871 case TVGN_CHILD: 1872 retval = (INT)wineItem->firstChild; 1873 break; 1874 1875 case TVGN_LASTVISIBLE: 1876 returnItem = TREEVIEW_GetLastListItem (hwnd,infoPtr,wineItem); 1877 break; 1878 1879 case TVGN_NEXTVISIBLE: 1880 returnItem = TREEVIEW_GetNextListItem (hwnd,infoPtr,wineItem); 1881 break; 1882 1883 case TVGN_PREVIOUSVISIBLE: 1884 returnItem = TREEVIEW_GetPrevListItem (hwnd,infoPtr, wineItem); 1885 break; 1886 1887 default: 1888 break; 1889 } 1890 1891 if (returnItem) return (INT)returnItem->hItem; 1892 1893 return retval; 1894 } 1895 1896 1897 static LRESULT 1898 TREEVIEW_GetCount (HWND hwnd, WPARAM wParam, LPARAM lParam) 1899 { 1900 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 1901 1902 return (LRESULT) infoPtr->uNumItems; 1903 } 1904 1905 /*************************************************************************** 1906 * This method does the chaining of the insertion of a treeview item 1907 * before an item. 1908 * If parent is NULL, we're inserting at the root of the list. 1909 */ 1910 static void TREEVIEW_InsertBefore( 1911 TREEVIEW_INFO *infoPtr, 1912 TREEVIEW_ITEM *newItem, 1913 TREEVIEW_ITEM *sibling, 1914 TREEVIEW_ITEM *parent) 1915 { 1916 HTREEITEM siblingHandle = 0; 1917 HTREEITEM upSiblingHandle = 0; 1918 TREEVIEW_ITEM *upSibling = NULL; 1919 1920 // if (newItem == NULL) 1921 // ERR(treeview, "NULL newItem, impossible condition\n"); 1922 1923 // if (parent == NULL) 1924 // ERR(treeview, "NULL parent, impossible condition\n"); 1925 1926 if (sibling != NULL) /* Insert before this sibling for this parent */ 1927 { 1928 /* Store the new item sibling up sibling and sibling tem handle */ 1929 siblingHandle = sibling->hItem; 1930 upSiblingHandle = sibling->upsibling; 1931 /* As well as a pointer to the upsibling sibling object */ 1932 if ( (INT)sibling->upsibling != 0 ) 1933 upSibling = &infoPtr->items[(INT)sibling->upsibling]; 1934 1935 /* Adjust the sibling pointer */ 1936 sibling->upsibling = newItem->hItem; 1937 1938 /* Adjust the new item pointers */ 1939 newItem->upsibling = upSiblingHandle; 1940 newItem->sibling = siblingHandle; 1941 1942 /* Adjust the up sibling pointer */ 1943 if ( upSibling != NULL ) 1944 upSibling->sibling = newItem->hItem; 1945 else 1946 if (parent) 1947 /* this item is the first child of this parent, adjust parent pointers */ 1948 parent->firstChild = newItem->hItem; 1949 else infoPtr->TopRootItem = newItem->hItem; 1950 } 1951 else /* Insert as first child of this parent */ 1952 if (parent) 1953 parent->firstChild = newItem->hItem; 1954 } 1955 1956 /*************************************************************************** 1957 * This method does the chaining of the insertion of a treeview item 1958 * If parent is NULL, we're inserting at the root of the list. 1959 * after an item. 1960 */ 1961 static void TREEVIEW_InsertAfter( 1962 TREEVIEW_INFO *infoPtr, 1963 TREEVIEW_ITEM *newItem, 1964 TREEVIEW_ITEM *upSibling, 1965 TREEVIEW_ITEM *parent) 1966 { 1967 HTREEITEM upSiblingHandle = 0; 1968 HTREEITEM siblingHandle = 0; 1969 TREEVIEW_ITEM *sibling = NULL; 1970 1971 // if (newItem == NULL) 1972 // ERR(treeview, "NULL newItem, impossible condition\n"); 1973 1974 // if (parent == NULL) 1975 // ERR(treeview, "NULL parent, impossible condition\n"); 1976 1977 if (upSibling != NULL) /* Insert after this upsibling for this parent */ 1978 { 1979 /* Store the new item up sibling and sibling item handle */ 1980 upSiblingHandle = upSibling->hItem; 1981 siblingHandle = upSibling->sibling; 1982 /* As well as a pointer to the upsibling sibling object */ 1983 if ( (INT)upSibling->sibling != 0 ) 1984 sibling = &infoPtr->items[(INT)upSibling->sibling]; 1985 1986 /* Adjust the up sibling pointer */ 1987 upSibling->sibling = newItem->hItem; 1988 1989 /* Adjust the new item pointers */ 1990 newItem->upsibling = upSiblingHandle; 1991 newItem->sibling = siblingHandle; 1992 1993 /* Adjust the sibling pointer */ 1994 if ( sibling != NULL ) 1995 sibling->upsibling = newItem->hItem; 1996 /* 1997 else 1998 newItem is the last of the level, nothing else to do 1999 */ 2000 } 2001 else /* Insert as first child of this parent */ 2002 if (parent) 2003 parent->firstChild = newItem->hItem; 2004 } 2376 /* Sorting **************************************************************/ 2005 2377 2006 2378 /*************************************************************************** 2007 2379 * Forward the DPA local callback to the treeview owner callback 2008 2380 */ 2009 static INT WINAPI TREEVIEW_CallBackCompare(LPVOID first,LPVOID second,LPARAM tvInfoPtr) 2010 { 2011 /* Forward the call to the client define callback */ 2012 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr((HWND)tvInfoPtr); 2013 2014 return (infoPtr->pCallBackSort->lpfnCompare)( 2015 ((TREEVIEW_ITEM*)first)->lParam, 2016 ((TREEVIEW_ITEM*)second)->lParam, 2017 infoPtr->pCallBackSort->lParam); 2381 static INT WINAPI 2382 TREEVIEW_CallBackCompare(LPVOID pvFirst, LPVOID pvSecond, LPARAM callback) 2383 { 2384 LPTVSORTCB pCallBackSort = (LPTVSORTCB)callback; 2385 2386 TREEVIEW_ITEM *first = (TREEVIEW_ITEM *)pvFirst; 2387 TREEVIEW_ITEM *second = (TREEVIEW_ITEM *)pvSecond; 2388 2389 /* Forward the call to the client-defined callback */ 2390 return pCallBackSort->lpfnCompare(first->lParam, 2391 second->lParam, 2392 pCallBackSort->lParam); 2018 2393 } 2019 2394 … … 2021 2396 * Treeview native sort routine: sort on item text. 2022 2397 */ 2023 static INT WINAPI TREEVIEW_SortOnName(LPVOID first,LPVOID second,LPARAM tvInfoPtr) 2024 { 2025 HWND hwnd = (HWND)tvInfoPtr; 2026 WCHAR *txt1,*txt2; 2027 TREEVIEW_ITEM *item; 2028 INT res; 2029 BOOL mustFree1 = FALSE,mustFree2 = FALSE; 2030 2031 item = (TREEVIEW_ITEM*)first; 2032 if (item->pszText == LPSTR_TEXTCALLBACKW) 2033 txt1 = TREEVIEW_CallbackText(hwnd,item,&mustFree1); 2034 else 2035 txt1 = item->pszText; 2036 2037 item = (TREEVIEW_ITEM*)second; 2038 if (item->pszText == LPSTR_TEXTCALLBACKW) 2039 txt2 = TREEVIEW_CallbackText(hwnd,item,&mustFree2); 2040 else 2041 txt2 = item->pszText; 2042 2043 res = lstrcmpiW(txt1,txt2); //CB: or lstrcmpW? 2044 if (mustFree1) COMCTL32_Free(txt1); 2045 if (mustFree2) COMCTL32_Free(txt2); 2046 2047 return res; 2398 static INT WINAPI 2399 TREEVIEW_SortOnName(LPVOID pvFirst, LPVOID pvSecond, LPARAM tvInfoPtr) 2400 { 2401 TREEVIEW_INFO *infoPtr = (TREEVIEW_INFO *)tvInfoPtr; 2402 2403 TREEVIEW_ITEM *first = (TREEVIEW_ITEM *)pvFirst; 2404 TREEVIEW_ITEM *second = (TREEVIEW_ITEM *)pvSecond; 2405 2406 TREEVIEW_UpdateDispInfo(infoPtr, first, TVIF_TEXT); 2407 TREEVIEW_UpdateDispInfo(infoPtr, second, TVIF_TEXT); 2408 2409 return lstrcmpiW(first->pszText, second->pszText); 2410 } 2411 2412 /* Returns the number of physical children belonging to item. */ 2413 static INT 2414 TREEVIEW_CountChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) 2415 { 2416 INT cChildren = 0; 2417 HTREEITEM hti; 2418 2419 for (hti = item->firstChild; hti != NULL; hti = hti->nextSibling) 2420 cChildren++; 2421 2422 return cChildren; 2423 } 2424 2425 /* Returns a DPA containing a pointer to each physical child of item in 2426 * sibling order. If item has no children, an empty DPA is returned. */ 2427 static HDPA 2428 TREEVIEW_BuildChildDPA(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) 2429 { 2430 HTREEITEM child = item->firstChild; 2431 2432 HDPA list = DPA_Create(8); 2433 if (list == 0) return NULL; 2434 2435 for (child = item->firstChild; child != NULL; child = child->nextSibling) 2436 { 2437 if (DPA_InsertPtr(list, INT_MAX, child) == -1) 2438 { 2439 DPA_Destroy(list); 2440 return NULL; 2441 } 2442 } 2443 2444 return list; 2048 2445 } 2049 2446 … … 2059 2456 */ 2060 2457 2061 static LRESULT WINAPI TREEVIEW_Sort(HWND hwnd,BOOL fRecurse,HTREEITEM parent,LPTVSORTCB pSort) 2062 { 2063 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2064 TREEVIEW_ITEM *sortMe = NULL; /* Node for which we sort the children */ 2065 INT cChildren; 2066 HTREEITEM hti; 2067 BOOL root = FALSE; 2068 2069 /* Obtain the TVSORTBC struct */ 2070 infoPtr->pCallBackSort = pSort; 2071 2072 /* undocumented feature: TVI_ROOT means `sort the whole tree' */ 2073 2074 if ((parent == TVI_ROOT) || (parent == 0)) 2075 { 2076 root = TRUE; 2077 parent = infoPtr->TopRootItem; 2078 } 2079 2080 /* Check for a valid handle to the parent item */ 2081 sortMe = TREEVIEW_ValidItem(infoPtr,parent); 2082 if (!sortMe) 2458 static LRESULT 2459 TREEVIEW_Sort(TREEVIEW_INFO *infoPtr, BOOL fRecurse, HTREEITEM parent, 2460 LPTVSORTCB pSort) 2461 { 2462 INT cChildren; 2463 PFNDPACOMPARE pfnCompare; 2464 LPARAM lpCompare; 2465 BOOL root = FALSE; 2466 2467 /* undocumented feature: TVI_ROOT means `sort the whole tree' */ 2468 if ((parent == TVI_ROOT) || (parent == 0)) 2469 { 2470 root = TRUE; 2471 parent = infoPtr->root; 2472 } 2473 2474 /* Check for a valid handle to the parent item */ 2475 if (!TREEVIEW_ValidItem(infoPtr, parent)) 2476 { 2477 //ERR("invalid item hParent=%x\n", (INT)parent); 2478 return FALSE; 2479 } 2480 2481 if (pSort) 2482 { 2483 pfnCompare = TREEVIEW_CallBackCompare; 2484 lpCompare = (LPARAM)pSort; 2485 } 2486 else 2487 { 2488 pfnCompare = TREEVIEW_SortOnName; 2489 lpCompare = (LPARAM)infoPtr; 2490 } 2491 2492 cChildren = TREEVIEW_CountChildren(infoPtr,parent); 2493 2494 /* Make sure there is something to sort */ 2495 if (cChildren > 1) 2496 { 2497 /* TREEVIEW_ITEM rechaining */ 2498 INT count = 0; 2499 HTREEITEM item = 0; 2500 HTREEITEM nextItem = 0; 2501 HTREEITEM prevItem = 0; 2502 2503 HDPA sortList = TREEVIEW_BuildChildDPA(infoPtr, parent); 2504 2505 if (sortList == NULL) 2506 return FALSE; 2507 2508 /* let DPA sort the list */ 2509 DPA_Sort(sortList, pfnCompare, lpCompare); 2510 2511 /* The order of DPA entries has been changed, so fixup the 2512 * nextSibling and prevSibling pointers. */ 2513 2514 item = (HTREEITEM)DPA_GetPtr(sortList, count++); 2515 while ((nextItem = (HTREEITEM)DPA_GetPtr(sortList, count++)) != NULL) 2516 { 2517 /* link the two current item toghether */ 2518 item->nextSibling = nextItem; 2519 nextItem->prevSibling = item; 2520 2521 if (prevItem == NULL) 2522 { 2523 /* this is the first item, update the parent */ 2524 parent->firstChild = item; 2525 item->prevSibling = NULL; 2526 } 2527 else 2528 { 2529 /* fix the back chaining */ 2530 item->prevSibling = prevItem; 2531 } 2532 2533 /* get ready for the next one */ 2534 prevItem = item; 2535 item = nextItem; 2536 } 2537 2538 /* the last item is pointed to by item and never has a sibling */ 2539 item->nextSibling = NULL; 2540 parent->lastChild = item; 2541 2542 DPA_Destroy(sortList); 2543 2544 TREEVIEW_VerifyTree(infoPtr); 2545 2546 TREEVIEW_QueueRefresh(infoPtr); 2547 2548 return TRUE; 2549 } 2083 2550 return FALSE; 2084 2085 cChildren = 0;2086 for(hti = root ? sortMe->hItem:sortMe->firstChild; hti; hti = infoPtr->items[(INT)hti].sibling)2087 cChildren++;2088 2089 /* Make sure there is something to sort */2090 if (cChildren > 1)2091 {2092 /* pointer organization */2093 HDPA sortList = DPA_Create(cChildren);2094 HTREEITEM itemHandle = root ? sortMe->hItem:sortMe->firstChild;2095 TREEVIEW_ITEM *itemPtr = &infoPtr->items[(INT)itemHandle];2096 2097 /* TREEVIEW_ITEM rechaining */2098 INT count = 0;2099 VOID *item = 0;2100 VOID *nextItem = 0;2101 VOID *prevItem = 0;2102 2103 /* Build the list of item to sort */2104 do2105 {2106 itemPtr = &infoPtr->items[(INT)itemHandle];2107 DPA_InsertPtr(2108 sortList, /* the list */2109 cChildren+1, /* force the insertion to be an append */2110 itemPtr); /* the ptr to store */2111 2112 /* Get the next sibling */2113 itemHandle = itemPtr->sibling;2114 } while (itemHandle != NULL);2115 2116 /* let DPA perform the sort activity */2117 if (pSort)2118 DPA_Sort(2119 sortList, /* what */2120 TREEVIEW_CallBackCompare, /* how */2121 hwnd); /* owner */2122 else2123 DPA_Sort (2124 sortList, /* what */2125 TREEVIEW_SortOnName, /* how */2126 hwnd); /* owner */2127 2128 /*2129 * Reorganized TREEVIEW_ITEM structures.2130 * Note that we know we have at least two elements.2131 */2132 2133 /* Get the first item and get ready to start... */2134 item = DPA_GetPtr(sortList, count++);2135 while ((nextItem = DPA_GetPtr(sortList, count++)) != NULL)2136 {2137 /* link the two current item toghether */2138 ((TREEVIEW_ITEM*)item)->sibling = ((TREEVIEW_ITEM*)nextItem)->hItem;2139 ((TREEVIEW_ITEM*)nextItem)->upsibling = ((TREEVIEW_ITEM*)item)->hItem;2140 2141 if (prevItem == NULL) /* this is the first item, update the parent */2142 {2143 if (root)2144 infoPtr->TopRootItem = ((TREEVIEW_ITEM*)item)->hItem;2145 else2146 sortMe->firstChild = ((TREEVIEW_ITEM*)item)->hItem;2147 ((TREEVIEW_ITEM*)item)->upsibling = NULL;2148 }2149 else /* fix the back chaining */2150 {2151 ((TREEVIEW_ITEM*)item)->upsibling = ((TREEVIEW_ITEM*)prevItem)->hItem;2152 }2153 2154 /* get ready for the next one */2155 prevItem = item;2156 item = nextItem;2157 }2158 2159 /* the last item is pointed to by item and never has a sibling */2160 ((TREEVIEW_ITEM*)item)->sibling = NULL;2161 2162 DPA_Destroy(sortList);2163 TREEVIEW_QueueRefresh(hwnd);2164 2165 return TRUE;2166 }2167 return FALSE;2168 2551 } 2169 2552 … … 2172 2555 * and sort the children of the TV item specified in lParam 2173 2556 */ 2174 static LRESULT WINAPI TREEVIEW_SortChildrenCB(HWND hwnd,WPARAM wParam,LPARAM lParam) 2175 { 2176 LPTVSORTCB pSort = (LPTVSORTCB) lParam; 2177 2178 return TREEVIEW_Sort (hwnd, wParam, pSort->hParent, pSort); 2557 static LRESULT 2558 TREEVIEW_SortChildrenCB(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 2559 { 2560 LPTVSORTCB pSort = (LPTVSORTCB)lParam; 2561 2562 return TREEVIEW_Sort(infoPtr, wParam, pSort->hParent, pSort); 2179 2563 } 2180 2564 … … 2183 2567 * Sort the children of the TV item specified in lParam. 2184 2568 */ 2185 static LRESULT WINAPI TREEVIEW_SortChildren(HWND hwnd,WPARAM wParam,LPARAM lParam) 2186 { 2187 return TREEVIEW_Sort (hwnd, (BOOL) wParam, (HTREEITEM) lParam, NULL); 2188 } 2189 2190 2191 int ffs(int mask) 2192 { 2193 int bit; 2194 2195 if (mask == 0) 2196 return(0); 2197 for (bit = 1; !(mask & 1); bit++) 2198 mask >>= 1; 2199 return(bit); 2200 } 2201 2202 /* the method used below isn't the most memory-friendly, but it avoids 2203 a lot of memory reallocations */ 2204 2205 /* BTW: we waste handle 0; 0 is not an allowed handle. */ 2206 2207 static LRESULT 2208 TREEVIEW_InsertItem(HWND hwnd,WPARAM wParam,LPARAM lParam,BOOL unicode) 2209 { 2210 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2211 TVINSERTSTRUCTW *ptdi; 2212 TVITEMEXW *tvItem; 2213 TREEVIEW_ITEM *wineItem, *parentItem, *prevsib, *sibItem; 2214 INT iItem,i,len; 2215 2216 if (infoPtr->hwndEdit) SetFocus(hwnd); 2217 2218 /* Item to insert */ 2219 ptdi = (LPTVINSERTSTRUCTW)lParam; 2220 2221 /* check if memory is available */ 2222 2223 if (infoPtr->uNumPtrsAlloced==0) { 2224 infoPtr->items = (TREEVIEW_ITEM*)COMCTL32_Alloc (TVITEM_ALLOC*sizeof (TREEVIEW_ITEM)); 2225 infoPtr->freeList= (INT*)COMCTL32_Alloc (((TVITEM_ALLOC>>5)) * sizeof (INT)); 2226 infoPtr->uNumPtrsAlloced=TVITEM_ALLOC; 2227 infoPtr->TopRootItem=(HTREEITEM)1; 2228 } 2229 2230 /* 2231 * Reallocate contiguous space for items 2232 */ 2233 if (infoPtr->uNumItems == (infoPtr->uNumPtrsAlloced-1) ) { 2234 TREEVIEW_ITEM *oldItems = infoPtr->items; 2235 INT *oldfreeList = infoPtr->freeList; 2236 2237 infoPtr->uNumPtrsAlloced*=2; 2238 infoPtr->items = (TREEVIEW_ITEM*)COMCTL32_Alloc (infoPtr->uNumPtrsAlloced*sizeof (TREEVIEW_ITEM)); 2239 infoPtr->freeList= (INT*)COMCTL32_Alloc (((infoPtr->uNumPtrsAlloced>>5))*sizeof (INT)); 2240 2241 memcpy (&infoPtr->items[0], &oldItems[0], 2242 infoPtr->uNumPtrsAlloced/2 * sizeof(TREEVIEW_ITEM)); 2243 memcpy (&infoPtr->freeList[0], &oldfreeList[0], 2244 (infoPtr->uNumPtrsAlloced>>6) * sizeof(INT)); 2245 2246 COMCTL32_Free (oldItems); 2247 COMCTL32_Free (oldfreeList); 2248 } 2249 2250 /* 2251 * Reset infoPtr structure with new stat according to current TV picture 2252 */ 2253 iItem=0; 2254 infoPtr->uNumItems++; 2255 if ((INT)infoPtr->uMaxHandle==(infoPtr->uNumItems-1)) { 2256 iItem=infoPtr->uNumItems; 2257 infoPtr->uMaxHandle = (HTREEITEM)((INT)infoPtr->uMaxHandle + 1); 2258 } else { /* check freelist */ 2259 for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++) { 2260 if (infoPtr->freeList[i]) { 2261 for(iItem = 0; iItem < 32; iItem++) 2262 { 2263 if(tv_test_bit(iItem, &infoPtr->freeList[i])) 2264 break; 2265 } 2266 tv_clear_bit(iItem,&infoPtr->freeList[i]); 2267 iItem+=i<<5; 2268 break; 2269 } 2270 } 2271 } 2272 2273 /* 2274 * Find the parent item of the new item 2275 */ 2276 tvItem = &ptdi->itemex; 2277 wineItem = &infoPtr->items[iItem]; 2278 2279 if ((ptdi->hParent==TVI_ROOT) || (ptdi->hParent==0)) { 2280 parentItem = NULL; 2281 wineItem->parent = 0; 2282 sibItem = &infoPtr->items [(INT)infoPtr->TopRootItem]; 2283 } 2284 else { 2285 parentItem = &infoPtr->items[(INT)ptdi->hParent]; 2286 2287 /* Do the insertion here it if it's the only item of this parent */ 2288 if (!parentItem->firstChild) 2289 parentItem->firstChild=(HTREEITEM)iItem; 2290 2291 wineItem->parent = ptdi->hParent; 2292 sibItem = &infoPtr->items [(INT)parentItem->firstChild]; 2293 } 2294 2295 2296 /* NOTE: I am moving some setup of the wineItem object that was initialy 2297 * done at the end of the function since some of the values are 2298 * required by the Callback sorting 2299 */ 2300 2301 if (tvItem->mask & TVIF_TEXT) 2302 { 2303 /* 2304 * Setup the item text stuff here since it's required by the Sort method 2305 * when the insertion are ordered 2306 */ 2307 if (unicode) 2308 { 2309 if (tvItem->pszText != LPSTR_TEXTCALLBACKW) 2569 static LRESULT 2570 TREEVIEW_SortChildren(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 2571 { 2572 return TREEVIEW_Sort(infoPtr, (BOOL)wParam, (HTREEITEM)lParam, NULL); 2573 } 2574 2575 2576 /* Expansion/Collapse ***************************************************/ 2577 2578 static BOOL 2579 TREEVIEW_SendExpanding(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, 2580 UINT action) 2581 { 2582 return !TREEVIEW_SendTreeviewNotify(infoPtr,isUnicodeNotify(&infoPtr->header) ? TVN_ITEMEXPANDINGW:TVN_ITEMEXPANDINGA, action, 2583 TVIF_HANDLE | TVIF_STATE | TVIF_PARAM 2584 | TVIF_IMAGE | TVIF_SELECTEDIMAGE, 2585 0, wineItem); 2586 } 2587 2588 static VOID 2589 TREEVIEW_SendExpanded(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, 2590 UINT action) 2591 { 2592 TREEVIEW_SendTreeviewNotify(infoPtr,isUnicodeNotify(&infoPtr->header) ? TVN_ITEMEXPANDEDW:TVN_ITEMEXPANDEDA, action, 2593 TVIF_HANDLE | TVIF_STATE | TVIF_PARAM 2594 | TVIF_IMAGE | TVIF_SELECTEDIMAGE, 2595 0, wineItem); 2596 } 2597 2598 2599 /* This corresponds to TVM_EXPAND with TVE_COLLAPSE. 2600 * bRemoveChildren corresponds to TVE_COLLAPSERESET. */ 2601 static BOOL 2602 TREEVIEW_Collapse(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, 2603 BOOL bRemoveChildren, BOOL bUser) 2604 { 2605 UINT action = TVE_COLLAPSE | (bRemoveChildren ? TVE_COLLAPSERESET : 0); 2606 BOOL bSetSelection, bSetFirstVisible; 2607 2608 //TRACE("TVE_COLLAPSE %p %s\n", wineItem, TREEVIEW_ItemName(wineItem)); 2609 2610 if (!(wineItem->state & TVIS_EXPANDED) || wineItem->firstChild == NULL) 2611 return FALSE; 2612 2613 if (bUser) 2614 TREEVIEW_SendExpanding(infoPtr, wineItem, action); 2615 2616 wineItem->state &= ~TVIS_EXPANDED; 2617 2618 if (bUser) 2619 TREEVIEW_SendExpanded(infoPtr, wineItem, action); 2620 2621 bSetSelection = (infoPtr->selectedItem != NULL 2622 && TREEVIEW_IsChildOf(wineItem, infoPtr->selectedItem)); 2623 2624 if (TREEVIEW_IsChildOf(wineItem,infoPtr->firstVisible)) 2625 { 2626 infoPtr->lefttop.y += wineItem->rect.top; 2627 } 2628 2629 if (bRemoveChildren) 2630 { 2631 //TRACE("TVE_COLLAPSERESET\n"); 2632 wineItem->state &= ~TVIS_EXPANDEDONCE; 2633 TREEVIEW_RemoveAllChildren(infoPtr, wineItem); 2634 } 2635 2636 //update window 2637 //CB: todo: optimize! 2638 TREEVIEW_UnqueueRefresh(infoPtr,FALSE,FALSE); 2639 //CB: todo: precalc expanded items here 2640 TREEVIEW_CalcItems(infoPtr); 2641 TREEVIEW_Refresh(infoPtr); 2642 2643 if (bSetSelection) 2644 { 2645 /* Don't call DoSelectItem, it sends notifications. */ 2646 if (infoPtr->selectedItem) 2647 infoPtr->selectedItem->state &= ~TVIS_SELECTED; 2648 wineItem->state |= TVIS_SELECTED; 2649 infoPtr->selectedItem = wineItem; 2650 2651 TREEVIEW_EnsureVisible(infoPtr, wineItem); 2652 } 2653 2654 return TRUE; 2655 } 2656 2657 static BOOL 2658 TREEVIEW_Expand(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, 2659 BOOL bExpandPartial, BOOL bUser) 2660 { 2661 //TRACE("TVE_EXPAND\n"); 2662 2663 if (!TREEVIEW_HasChildren(infoPtr, wineItem) 2664 || (wineItem->state & TVIS_EXPANDED)) 2665 return FALSE; 2666 2667 //TRACE(" is not expanded...\n"); 2668 2669 if (bUser || !(wineItem->state & TVIS_EXPANDEDONCE)) 2670 { 2671 //TRACE(" and has never been expanded...\n"); 2672 2673 if (bExpandPartial) 2674 { 2675 return FALSE; //CB: how does this work??? (only display one level? nonsense in MSDN docu) 2676 wineItem->state ^=TVIS_EXPANDED; 2677 wineItem->state |=TVIS_EXPANDEDONCE; 2678 } 2679 2680 wineItem->state |= TVIS_EXPANDED; 2681 //TRACE(" TVN_ITEMEXPANDING sent...\n"); 2682 2683 if (!TREEVIEW_SendExpanding(infoPtr, wineItem, TVE_EXPAND)) 2684 { 2685 //TRACE(" TVN_ITEMEXPANDING returned TRUE, exiting...\n"); 2686 return FALSE; 2687 } 2688 2689 wineItem->state |= TVIS_EXPANDEDONCE; 2690 2691 TREEVIEW_SendExpanded(infoPtr, wineItem, TVE_EXPAND); 2692 2693 //TRACE(" TVN_ITEMEXPANDED sent...\n"); 2694 } 2695 else 2696 { 2697 /* this item has already been expanded */ 2698 wineItem->state |= TVIS_EXPANDED; 2699 } 2700 2701 //if (bExpandPartial) 2702 // FIXME("TVE_EXPANDPARTIAL not implemented\n"); 2703 2704 //update window 2705 //CB: todo: optimize! 2706 TREEVIEW_UnqueueRefresh(infoPtr,TRUE,FALSE); 2707 2708 /* Scroll up so that as many children as possible are visible. 2709 * This looses when expanding causes an HScroll bar to appear, but we 2710 * don't know that yet, so the last item is obscured. */ 2711 if (wineItem->firstChild && wineItem->inclient && (infoPtr->firstVisible != wineItem) && (wineItem->lastChild->rect.bottom > infoPtr->clientHeight)) 2712 { 2713 INT childrenH = wineItem->lastChild->rect.bottom-wineItem->firstChild->rect.top; 2714 INT itemH = wineItem->rect.bottom-wineItem->rect.top; 2715 INT clientH = ((INT)(infoPtr->clientHeight/infoPtr->uItemHeight))*infoPtr->uItemHeight; 2716 2717 if (itemH+childrenH > clientH) 2310 2718 { 2311 len = lstrlenW(tvItem->pszText)+1; 2312 wineItem->pszText = (WCHAR*)COMCTL32_Alloc(len*sizeof(WCHAR)); 2313 lstrcpyW (wineItem->pszText, tvItem->pszText); 2314 wineItem->cchTextMax = len; 2719 infoPtr->lefttop.y += wineItem->rect.top; 2315 2720 } else 2316 2721 { 2317 wineItem->pszText = LPSTR_TEXTCALLBACKW; 2318 wineItem->cchTextMax = 0; 2722 INT diff = wineItem->lastChild->rect.bottom-clientH; 2723 2724 infoPtr->lefttop.y += diff; 2319 2725 } 2320 } else 2321 { 2322 if ((LPSTR)tvItem->pszText != LPSTR_TEXTCALLBACKA) 2323 { 2324 len = lstrlenA((LPSTR)tvItem->pszText)+1; 2325 wineItem->pszText = (WCHAR*)COMCTL32_Alloc(len*sizeof(WCHAR)); 2326 lstrcpyAtoW (wineItem->pszText,(LPSTR)tvItem->pszText); 2327 wineItem->cchTextMax = len; 2328 } else 2329 { 2330 wineItem->pszText = LPSTR_TEXTCALLBACKW; 2331 wineItem->cchTextMax = 0; 2332 } 2333 } 2334 } 2335 2336 if (tvItem->mask & TVIF_PARAM) 2337 wineItem->lParam=tvItem->lParam; 2338 2339 2340 wineItem->upsibling=0; /* needed in case we're the first item in a list */ 2341 wineItem->sibling=0; 2342 wineItem->firstChild=0; 2343 wineItem->hItem=(HTREEITEM)iItem; 2344 2345 if (sibItem != wineItem) 2346 { 2347 prevsib=NULL; 2348 2349 if (ptdi->hInsertAfter == TVI_FIRST) 2350 { 2351 if (wineItem->parent) { 2352 wineItem->sibling=parentItem->firstChild; 2353 parentItem->firstChild=(HTREEITEM)iItem; 2354 } else { 2355 wineItem->sibling=infoPtr->TopRootItem; 2356 infoPtr->TopRootItem=(HTREEITEM)iItem; 2357 } 2358 sibItem->upsibling=(HTREEITEM)iItem; 2359 } else if (ptdi->hInsertAfter == TVI_SORT) 2360 { 2361 TREEVIEW_ITEM *aChild; 2362 TREEVIEW_ITEM *previousChild = NULL; 2363 BOOL bItemInserted = FALSE; 2364 WCHAR* text; 2365 BOOL mustFree = FALSE; 2366 2367 if (parentItem) 2368 aChild = &infoPtr->items[(INT)parentItem->firstChild]; 2369 else 2370 aChild = &infoPtr->items[(INT)infoPtr->TopRootItem]; 2371 2372 /* lookup the text if using LPSTR_TEXTCALLBACKs */ 2373 if (wineItem->pszText == LPSTR_TEXTCALLBACKW) 2374 text = TREEVIEW_CallbackText(hwnd,wineItem,&mustFree); 2375 else 2376 text = wineItem->pszText; 2377 2378 /* Iterate the parent children to see where we fit in */ 2379 while ( aChild != NULL ) 2380 { 2381 INT comp; 2382 WCHAR* text2; 2383 BOOL mustFree2 = FALSE; 2384 2385 /* lookup the text if using LPSTR_TEXTCALLBACKs */ 2386 if (aChild->pszText == LPSTR_TEXTCALLBACKW) 2387 text2 = TREEVIEW_CallbackText(hwnd,aChild,&mustFree2); 2388 else 2389 text2 = aChild->pszText; 2390 2391 comp = lstrcmpW(text,text2); 2392 if (mustFree2) COMCTL32_Free(text2); 2393 if ( comp < 0 ) /* we are smaller than the current one */ 2394 { 2395 TREEVIEW_InsertBefore(infoPtr, wineItem, aChild, parentItem); 2396 bItemInserted = TRUE; 2397 break; 2398 } 2399 else if ( comp > 0 ) /* we are bigger than the current one */ 2400 { 2401 previousChild = aChild; 2402 aChild = (aChild->sibling == 0) /* This will help us to exit */ 2403 ? NULL /* if there is no more sibling */ 2404 : &infoPtr->items[(INT)aChild->sibling]; 2405 2406 /* Look at the next item */ 2407 continue; 2408 } 2409 else if ( comp == 0 ) 2410 { 2411 /* 2412 * An item with this name is already existing, therefore, 2413 * we add after the one we found 2414 */ 2415 TREEVIEW_InsertAfter(infoPtr, wineItem, aChild, parentItem); 2416 bItemInserted = TRUE; 2417 break; 2418 } 2419 } 2420 if (mustFree) COMCTL32_Free(text); 2421 2422 /* 2423 * we reach the end of the child list and the item as not 2424 * yet been inserted, therefore, insert it after the last child. 2425 */ 2426 if ( (! bItemInserted ) && (aChild == NULL) ) 2427 TREEVIEW_InsertAfter(infoPtr, wineItem, previousChild, parentItem); 2428 } else if (ptdi->hInsertAfter == TVI_LAST) 2429 { 2430 TVI_LAST_CASE: 2431 while (sibItem->sibling) { 2432 prevsib=sibItem; 2433 sibItem=&infoPtr->items [(INT)sibItem->sibling]; 2434 } 2435 sibItem->sibling=(HTREEITEM)iItem; 2436 wineItem->upsibling=sibItem->hItem; 2437 } else 2438 { 2439 while ((sibItem->sibling) && (sibItem->hItem!=ptdi->hInsertAfter)) 2440 { 2441 prevsib=sibItem; 2442 sibItem=&infoPtr->items [(INT)sibItem->sibling]; 2443 } 2444 if (sibItem->hItem!=ptdi->hInsertAfter) { 2445 goto TVI_LAST_CASE; 2446 } 2447 prevsib=sibItem; 2448 if (sibItem->sibling) { 2449 sibItem=&infoPtr->items [(INT)sibItem->sibling]; 2450 sibItem->upsibling=(HTREEITEM)iItem; 2451 wineItem->sibling=sibItem->hItem; 2452 } 2453 prevsib->sibling=(HTREEITEM)iItem; 2454 wineItem->upsibling=prevsib->hItem; 2455 } 2456 } 2457 2458 /* Fill in info structure */ 2459 2460 wineItem->mask = tvItem->mask; 2461 wineItem->iIntegral = 1; 2462 2463 if (tvItem->mask & TVIF_CHILDREN) 2464 wineItem->cChildren=tvItem->cChildren; 2465 2466 wineItem->expandBox.left = 0; /* Initialize the expandBox */ 2467 wineItem->expandBox.top = 0; 2468 wineItem->expandBox.right = 0; 2469 wineItem->expandBox.bottom = 0; 2470 2471 if (tvItem->mask & TVIF_IMAGE) 2472 wineItem->iImage = tvItem->iImage; 2473 2474 /* If the application sets TVIF_INTEGRAL without 2475 supplying a TVITEMEX structure, it's toast */ 2476 2477 if (tvItem->mask & TVIF_INTEGRAL) 2478 wineItem->iIntegral = tvItem->iIntegral; 2479 2480 if (tvItem->mask & TVIF_SELECTEDIMAGE) 2481 wineItem->iSelectedImage = tvItem->iSelectedImage; 2482 2483 if (tvItem->mask & TVIF_STATE) 2484 { 2485 wineItem->state = tvItem->state; 2486 wineItem->stateMask = tvItem->stateMask; 2487 } 2488 2489 wineItem->calculated = FALSE; 2490 //TREEVIEW_Sort(hwnd,0,NULL,NULL); //CB: the Corel people do this, I think it's wrong 2491 TREEVIEW_QueueRefresh(hwnd); 2492 2493 return (LRESULT) iItem; 2494 } 2495 2496 2497 static LRESULT 2498 TREEVIEW_DeleteItem (HWND hwnd, WPARAM wParam, LPARAM lParam) 2499 { 2500 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2501 INT iItem; 2502 TREEVIEW_ITEM *wineItem; 2503 2504 if (lParam == (INT)TVI_ROOT) 2505 { 2506 TREEVIEW_RemoveTree (hwnd); 2507 } else 2508 { 2509 iItem = (INT)lParam; 2510 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem); 2511 if (!wineItem) return FALSE; 2512 2513 TREEVIEW_RemoveItem (hwnd, wineItem); 2514 } 2515 2516 TREEVIEW_QueueRefresh(hwnd); 2517 2518 return TRUE; 2519 } 2520 2521 2522 2523 static LRESULT 2524 TREEVIEW_GetIndent (HWND hwnd) 2525 { 2526 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2527 2528 return infoPtr->uIndent; 2529 } 2530 2531 static LRESULT 2532 TREEVIEW_SetIndent (HWND hwnd, WPARAM wParam) 2533 { 2534 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2535 INT newIndent; 2536 2537 newIndent = (INT)wParam; 2538 if (newIndent < MINIMUM_INDENT) newIndent = MINIMUM_INDENT; 2539 if (newIndent != infoPtr->uIndent) 2540 { 2541 infoPtr->uIndent = newIndent; 2542 infoPtr->uInternalStatus |= TV_CALCALL; 2543 TREEVIEW_QueueRefresh(hwnd); 2544 } 2545 2546 return 0; 2547 } 2548 2549 static LRESULT 2550 TREEVIEW_GetToolTips (HWND hwnd) 2551 { 2552 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2553 2554 return infoPtr->hwndToolTip; 2555 } 2556 2557 2558 static LRESULT 2559 TREEVIEW_SetToolTips (HWND hwnd, WPARAM wParam) 2560 { 2561 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2562 HWND prevToolTip; 2563 2564 prevToolTip = infoPtr->hwndToolTip; 2565 infoPtr->hwndToolTip = (HWND)wParam; 2566 2567 return prevToolTip; 2568 } 2569 2570 2571 static LRESULT CALLBACK 2572 TREEVIEW_GetEditControl (HWND hwnd) 2573 { 2574 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2575 2576 return infoPtr->hwndEdit; 2577 } 2578 2579 2580 //@@@PH: Note - this SubclassProc is sometimes called with the 2581 // wrong window handle. Therefore, infoPtr points to anything 2582 // but the expected structure. 2583 LRESULT CALLBACK 2584 TREEVIEW_Edit_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, 2585 LPARAM lParam) 2586 { 2587 BOOL bCancel = FALSE; 2588 static BOOL bIgnoreKillFocus = FALSE; 2589 2590 switch (uMsg) 2591 { 2592 case WM_PAINT: 2593 { 2594 LRESULT rc; 2595 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd)); 2596 //TRACE("WM_PAINT start\n"); 2597 rc = CallWindowProcA( infoPtr->wpEditOrig, hwnd, uMsg, wParam, lParam); 2598 //TRACE("WM_PAINT done\n"); 2599 return rc; 2600 } 2601 2602 case WM_KILLFOCUS: 2603 if(bIgnoreKillFocus) 2604 { 2605 return TRUE; 2606 } 2607 break; 2608 2609 case WM_GETDLGCODE: 2610 return DLGC_WANTARROWS | DLGC_WANTALLKEYS; 2611 2612 case WM_KEYDOWN: 2613 if (VK_ESCAPE == (INT)wParam) 2614 { 2615 bCancel = TRUE; 2616 break; 2617 } 2618 else if (VK_RETURN == (INT)wParam) 2619 { 2620 break; 2621 } 2622 2623 default: 2624 { 2625 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd)); 2626 2627 //@@@PH 1999/11/05 method called with freed infoPtr memory object 2628 if (infoPtr != NULL) 2629 return CallWindowProcA( infoPtr->wpEditOrig, hwnd, uMsg, wParam, lParam); 2630 else 2631 break; 2632 } 2633 } 2634 2635 /* Processing LVN_ENDLABELEDIT message could kill the focus */ 2636 /* eg. Using a messagebox */ 2637 bIgnoreKillFocus = TRUE; 2638 TREEVIEW_EndEditLabelNow(GetParent(hwnd), bCancel); 2639 bIgnoreKillFocus = FALSE; 2640 2641 return 0; 2642 } 2643 2644 /* should handle edit control messages here */ 2645 2646 static LRESULT 2647 TREEVIEW_Command (HWND hwnd, WPARAM wParam, LPARAM lParam) 2648 2649 { 2650 switch (HIWORD(wParam)) 2651 { 2652 case EN_UPDATE: 2653 { 2654 /* 2655 * Adjust the edit window size 2656 */ 2657 char buffer[1024]; 2658 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2659 TREEVIEW_ITEM *editItem = TREEVIEW_ValidItem(infoPtr, infoPtr->editItem); 2660 HDC hdc = GetDC(infoPtr->hwndEdit); 2661 SIZE sz; 2662 int len; 2663 HFONT hFont, hOldFont=0; 2664 2665 len = GetWindowTextA(infoPtr->hwndEdit, buffer, 1024); 2666 2667 /* Select font to get the right dimension of the string */ 2668 hFont = SendMessageA(infoPtr->hwndEdit, WM_GETFONT, 0, 0); 2669 if(hFont != 0) 2670 { 2671 hOldFont = SelectObject(hdc, hFont); 2672 } 2673 2674 if (GetTextExtentPoint32A(hdc, buffer, strlen(buffer), &sz)) 2675 { 2676 TEXTMETRICA textMetric; 2677 /* Add Extra spacing for the next character */ 2678 GetTextMetricsA(hdc, &textMetric); 2679 sz.cx += (textMetric.tmMaxCharWidth * 2); 2680 2681 SetWindowPos ( 2682 infoPtr->hwndEdit, 2683 HWND_TOP, 2684 0, 2685 0, 2686 sz.cx, 2687 editItem->text.bottom - editItem->text.top + 3, 2688 SWP_NOMOVE|SWP_DRAWFRAME); 2689 } 2690 2691 if(hFont != 0) 2692 { 2693 SelectObject(hdc, hOldFont); 2694 } 2695 2696 ReleaseDC(hwnd, hdc); 2697 break; 2698 } 2699 2700 default: 2701 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam); 2702 } 2703 2704 return 0; 2705 } 2706 2707 static LRESULT TREEVIEW_Size (HWND hwnd, WPARAM wParam, LPARAM lParam) 2708 { 2709 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2710 2711 if (wParam == SIZE_RESTORED) 2712 if (TREEVIEW_CalcItems(hwnd,0,infoPtr)) 2713 TREEVIEW_Refresh(hwnd); 2714 2715 return TRUE; 2716 } 2717 2718 static LRESULT 2719 TREEVIEW_StyleChanged (HWND hwnd, WPARAM wParam, LPARAM lParam) 2720 { 2721 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2722 2723 if (infoPtr->hwndEdit) SetFocus(hwnd); 2724 2725 infoPtr->uInternalStatus |= TV_CALCALL; 2726 TREEVIEW_QueueRefresh(hwnd); 2727 2728 return 0; 2729 } 2730 2731 static LRESULT 2732 TREEVIEW_SysColorChange(HWND hwnd,WPARAM wParam,LPARAM lParam) 2733 { 2734 TREEVIEW_Refresh(hwnd); 2735 2736 return DefWindowProcA(hwnd,WM_SYSCOLORCHANGE,wParam,lParam); 2737 } 2738 2739 static LRESULT 2740 TREEVIEW_Create (HWND hwnd, WPARAM wParam, LPARAM lParam) 2741 { 2742 LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam; 2743 TREEVIEW_INFO *infoPtr; 2744 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE); 2745 LOGFONTA logFont; 2746 TEXTMETRICA tm; 2747 HDC hdc; 2748 2749 /* allocate memory for info structure */ 2750 infoPtr = (TREEVIEW_INFO*)initControl(hwnd,sizeof(TREEVIEW_INFO)); 2751 2752 if (!infoPtr) return 0; 2753 2754 hdc = GetDC(hwnd); 2755 2756 /* set default settings */ 2757 infoPtr->uInternalStatus = TV_CALCALL; 2758 infoPtr->uNumItems = 0; 2759 infoPtr->clrBk = GetSysColor (COLOR_WINDOW); 2760 infoPtr->clrLine = GetSysColor (COLOR_WINDOWTEXT); 2761 infoPtr->clrInsertMark = GetSysColor (COLOR_BTNTEXT); 2762 infoPtr->lefttop.y = 0; 2763 infoPtr->lefttop.x = 0; 2764 infoPtr->uIndent = 15; 2765 infoPtr->himlNormal = NULL; 2766 infoPtr->himlState = NULL; 2767 infoPtr->uItemHeight = -1; 2768 infoPtr->uRealItemHeight = 0; 2769 infoPtr->uVScrollStep = 1; 2770 infoPtr->uVisibleHeight = lpcs->cy; 2771 infoPtr->uTotalHeight = 0; 2772 infoPtr->uVisibleWidth = lpcs->cx; 2773 infoPtr->uTotalWidth = 0; 2774 2775 GetTextMetricsA (hdc, &tm); 2776 infoPtr->hFont = GetStockObject (DEFAULT_GUI_FONT); 2777 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont); 2778 logFont.lfWeight = FW_BOLD; 2779 infoPtr->hBoldFont = CreateFontIndirectA (&logFont); 2780 2781 infoPtr->items = NULL; 2782 infoPtr->selectedItem = 0; 2783 infoPtr->clrText = -1; /* use system color */ 2784 infoPtr->dropItem = 0; 2785 infoPtr->insertMarkItem = 0; 2786 infoPtr->insertBeforeorAfter = 0; 2787 infoPtr->pCallBackSort = NULL; 2788 infoPtr->uScrollTime = 300; /* milliseconds */ 2789 infoPtr->hwndEdit = 0; 2790 infoPtr->pszISearch = NULL; 2791 infoPtr->uISearchLen = 0; 2792 2793 infoPtr->tipItem = 0; 2794 infoPtr->hwndToolTip = 0; 2795 if (!(dwStyle & TVS_NOTOOLTIPS)) 2796 { 2797 infoPtr->hwndToolTip = createToolTip(hwnd,TTF_TRACK | TTF_ABSOLUTE | TTF_TRANSPARENT,TRUE); 2798 SendMessageA(infoPtr->hwndToolTip,WM_SETFONT,infoPtr->hFont,0); 2799 } 2800 2801 if (dwStyle & TVS_CHECKBOXES) 2802 { 2803 HBITMAP hbmLoad; 2804 int nIndex; 2805 2806 infoPtr->himlState = ImageList_Create (16, 16,ILC_COLOR | ILC_MASK, 15, 1); 2807 2808 //MSDN docu says: uses DrawFrameControl but never believe what they write 2809 hbmLoad = LoadBitmapA (COMCTL32_hModule, MAKEINTRESOURCEA(IDT_CHECK)); 2810 nIndex = ImageList_AddMasked (infoPtr->himlState, hbmLoad, CLR_DEFAULT); 2811 DeleteObject (hbmLoad); 2812 } 2813 ReleaseDC (hwnd, hdc); 2814 2815 return 0; 2816 } 2817 2818 static LRESULT 2819 TREEVIEW_Destroy (HWND hwnd) 2820 { 2821 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2822 2823 TREEVIEW_RemoveTree (hwnd); 2824 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) 2825 KillTimer (hwnd, TV_REFRESH_TIMER); 2826 destroyToolTip(infoPtr->hwndToolTip); 2827 2828 /* Restore original windproc so that we can free infoPtr */ 2829 if (infoPtr->hwndEdit) 2830 SetWindowLongA (infoPtr->hwndEdit, GWL_WNDPROC, (DWORD)infoPtr->wpEditOrig); 2831 2832 DeleteObject(infoPtr->hBoldFont); 2833 COMCTL32_Free(infoPtr->pszISearch); 2834 doneControl(hwnd); 2835 2836 return 0; 2837 } 2838 2839 2840 static LRESULT 2841 TREEVIEW_Paint (HWND hwnd, WPARAM wParam, LPARAM lParam) 2842 { 2843 HDC hdc = (HDC)wParam; 2844 2845 if (!hdc) 2846 { 2847 PAINTSTRUCT ps; 2848 2849 hdc = BeginPaint(hwnd,&ps); 2850 TREEVIEW_Draw(hwnd, hdc,&ps.rcPaint); 2851 EndPaint(hwnd,&ps); 2852 } else 2853 TREEVIEW_Draw(hwnd,hdc,NULL); 2854 2855 return 0; 2856 } 2857 2858 static LRESULT 2859 TREEVIEW_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam) 2860 { 2861 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2862 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE); 2863 2864 sendNotify(hwnd,NM_SETFOCUS); 2865 2866 if (!(dwStyle & TVS_SHOWSELALWAYS)) 2867 { 2868 if (infoPtr->selectedItem) 2869 TREEVIEW_RefreshItem(hwnd,TREEVIEW_ValidItem(infoPtr,infoPtr->selectedItem),FALSE); 2870 else if (infoPtr->firstVisible) 2871 TREEVIEW_DoSelectItem(hwnd,TVGN_CARET,infoPtr->firstVisible,TVC_UNKNOWN); 2872 } 2873 2874 return 0; 2875 } 2876 2877 static LRESULT 2878 TREEVIEW_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam) 2879 { 2880 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2881 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE); 2882 2883 sendNotify(hwnd,NM_KILLFOCUS); 2884 2885 if (!(dwStyle & TVS_SHOWSELALWAYS) && infoPtr->selectedItem) 2886 TREEVIEW_RefreshItem(hwnd,TREEVIEW_ValidItem(infoPtr,infoPtr->selectedItem),FALSE); 2887 2888 return 0; 2889 } 2890 2891 static LRESULT TREEVIEW_Enable(HWND hwnd,WPARAM wParam,LPARAM lParam) 2892 { 2893 TREEVIEW_Refresh(hwnd); 2894 2895 return DefWindowProcA(hwnd,WM_ENABLE,wParam,lParam); 2896 } 2897 2898 static LRESULT 2899 TREEVIEW_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam) 2900 { 2901 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2902 HBRUSH hBrush = CreateSolidBrush (infoPtr->clrBk); 2903 RECT rect; 2904 2905 GetClientRect (hwnd, &rect); 2906 FillRect ((HDC)wParam, &rect, hBrush); 2907 DeleteObject (hBrush); 2726 } 2727 2728 TREEVIEW_CalcItems(infoPtr); 2729 TREEVIEW_Refresh(infoPtr); 2730 //CB: todo: check cx and cy to fit ranges! 2908 2731 2909 2732 return TRUE; 2910 2733 } 2911 2734 2912 static LRESULT TREEVIEW_GetDlgCode(HWND hwnd,WPARAM wParam,LPARAM lParam)2913 {2914 return DLGC_WANTARROWS | DLGC_WANTCHARS;2915 }2916 2917 /* Notifications */2918 2919 2735 static BOOL 2920 TREEVIEW_SendTreeviewNotify (HWND hwnd,UINT code,UINT action,HTREEITEM oldItem,HTREEITEM newItem) 2921 { 2922 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2923 NMTREEVIEWW nmhdr; 2924 TREEVIEW_ITEM *wineItem; 2925 CHAR *oldText = NULL,*newText = NULL; 2926 BOOL rc; 2927 2928 ZeroMemory(&nmhdr,sizeof(NMTREEVIEWW)); 2929 2930 nmhdr.action = action; 2931 if (oldItem) 2932 { 2933 wineItem = &infoPtr->items[(INT)oldItem]; 2934 nmhdr.itemOld.mask = wineItem->mask; 2935 nmhdr.itemOld.hItem = wineItem->hItem; 2936 nmhdr.itemOld.state = wineItem->state; 2937 nmhdr.itemOld.stateMask = wineItem->stateMask; 2938 nmhdr.itemOld.iImage = wineItem->iImage; 2939 if (!isUnicodeNotify(&infoPtr->header)) 2940 { 2941 if (!wineItem->pszText || (wineItem->pszText == LPSTR_TEXTCALLBACKW)) nmhdr.itemOld.pszText = NULL; else 2942 { 2943 INT len = lstrlenW(wineItem->pszText)+1; 2944 2945 oldText = (CHAR*)COMCTL32_Alloc(len); 2946 lstrcpyWtoA(oldText,wineItem->pszText); 2947 nmhdr.itemOld.pszText = (WCHAR*)oldText; 2948 } 2949 } else nmhdr.itemOld.pszText = wineItem->pszText; 2950 nmhdr.itemOld.cchTextMax= wineItem->cchTextMax; 2951 nmhdr.itemOld.iImage = wineItem->iImage; 2952 nmhdr.itemOld.iSelectedImage = wineItem->iSelectedImage; 2953 nmhdr.itemOld.cChildren = wineItem->cChildren; 2954 nmhdr.itemOld.lParam = wineItem->lParam; 2955 } 2956 2957 if (newItem) 2958 { 2959 wineItem = &infoPtr->items[(INT)newItem]; 2960 nmhdr.itemNew.mask = wineItem->mask; 2961 nmhdr.itemNew.hItem = wineItem->hItem; 2962 nmhdr.itemNew.state = wineItem->state; 2963 nmhdr.itemNew.stateMask = wineItem->stateMask; 2964 nmhdr.itemNew.iImage = wineItem->iImage; 2965 if (!isUnicodeNotify(&infoPtr->header)) 2966 { 2967 if (!wineItem->pszText || (wineItem->pszText == LPSTR_TEXTCALLBACKW)) nmhdr.itemNew.pszText = NULL; else 2968 { 2969 INT len = lstrlenW(wineItem->pszText)+1; 2970 2971 newText = (CHAR*)COMCTL32_Alloc(len); 2972 lstrcpyWtoA(newText,wineItem->pszText); 2973 nmhdr.itemNew.pszText = (WCHAR*)newText; 2974 } 2975 } else nmhdr.itemNew.pszText = wineItem->pszText; 2976 nmhdr.itemNew.cchTextMax= wineItem->cchTextMax; 2977 nmhdr.itemNew.iImage = wineItem->iImage; 2978 nmhdr.itemNew.iSelectedImage = wineItem->iSelectedImage; 2979 nmhdr.itemNew.cChildren = wineItem->cChildren; 2980 nmhdr.itemNew.lParam = wineItem->lParam; 2981 } 2982 2983 nmhdr.ptDrag.x = 0; 2984 nmhdr.ptDrag.y = 0; 2985 2986 rc = (BOOL)sendNotify(hwnd,code,&nmhdr.hdr); 2987 2988 if (oldText) COMCTL32_Free(oldText); 2989 if (newText) COMCTL32_Free(newText); 2990 2991 return rc; 2992 } 2993 2994 static BOOL 2995 TREEVIEW_SendTreeviewDnDNotify (HWND hwnd, UINT code, HTREEITEM dragItem, 2996 POINT pt) 2997 { 2998 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2999 NMTREEVIEWA nmhdr; 3000 TREEVIEW_ITEM *wineItem; 3001 3002 nmhdr.action = 0; 3003 wineItem=& infoPtr->items[(INT)dragItem]; 3004 nmhdr.itemNew.mask = wineItem->mask; 3005 nmhdr.itemNew.hItem = wineItem->hItem; 3006 nmhdr.itemNew.state = wineItem->state; 3007 nmhdr.itemNew.lParam = wineItem->lParam; 3008 3009 nmhdr.ptDrag.x = pt.x; 3010 nmhdr.ptDrag.y = pt.y; 3011 3012 return (BOOL)sendNotify(hwnd,code,&nmhdr.hdr); 3013 3014 } 3015 3016 static INT TREEVIEW_CallbackImage(HWND hwnd,TREEVIEW_ITEM *wineItem) 3017 { 3018 NMTVDISPINFOW tvdi; 3019 BOOL retval; 3020 3021 tvdi.item.mask = TVIF_IMAGE; 3022 tvdi.item.hItem = wineItem->hItem; 3023 tvdi.item.state = wineItem->state; 3024 tvdi.item.lParam = wineItem->lParam; 3025 tvdi.item.iImage = 0; 3026 3027 retval = (BOOL)sendNotify(hwnd,isUnicodeNotify(hwnd) ? TVN_GETDISPINFOW:TVN_GETDISPINFOA,&tvdi.hdr); 3028 3029 if (tvdi.item.mask & TVIF_DI_SETITEM) 3030 wineItem->iImage = tvdi.item.iImage; 3031 3032 return tvdi.item.iImage; 3033 } 3034 3035 static INT TREEVIEW_CallbackSelectedImage(HWND hwnd,TREEVIEW_ITEM *wineItem) 3036 { 3037 NMTVDISPINFOW tvdi; 3038 BOOL retval; 3039 3040 tvdi.item.mask = TVIF_SELECTEDIMAGE; 3041 tvdi.item.hItem = wineItem->hItem; 3042 tvdi.item.state = wineItem->state; 3043 tvdi.item.lParam = wineItem->lParam; 3044 tvdi.item.iSelectedImage = 0; 3045 3046 retval = (BOOL)sendNotify(hwnd,isUnicodeNotify(hwnd) ? TVN_GETDISPINFOW:TVN_GETDISPINFOA,&tvdi.hdr); 3047 3048 if (tvdi.item.mask & TVIF_DI_SETITEM) 3049 wineItem->iSelectedImage = tvdi.item.iSelectedImage; 3050 3051 return tvdi.item.iSelectedImage; 3052 } 3053 3054 static WCHAR* TREEVIEW_CallbackText(HWND hwnd,TREEVIEW_ITEM *wineItem,BOOL *mustFree) 3055 { 3056 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3057 NMTVDISPINFOW tvdi; 3058 BOOL retval; 3059 WCHAR *buf; 3060 3061 tvdi.item.mask = TVIF_TEXT; 3062 tvdi.item.hItem = wineItem->hItem; 3063 tvdi.item.state = wineItem->state; 3064 tvdi.item.lParam = wineItem->lParam; 3065 tvdi.item.pszText = (WCHAR*)COMCTL32_Alloc(128*(isUnicodeNotify(&infoPtr->header) ? sizeof(WCHAR):sizeof(CHAR))); 3066 tvdi.item.cchTextMax = 128; 3067 buf = tvdi.item.pszText; 3068 3069 retval = (BOOL)sendNotify(hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_GETDISPINFOW:TVN_GETDISPINFOA,&tvdi.hdr); 3070 3071 if (tvdi.item.pszText == LPSTR_TEXTCALLBACKW) 3072 { 3073 *mustFree = FALSE; 3074 return NULL; 3075 } 3076 3077 if (isUnicodeNotify(&infoPtr->header)) 3078 { 3079 if (tvdi.item.mask & TVIF_DI_SETITEM) 3080 { 3081 if (buf == tvdi.item.pszText) 3082 { 3083 wineItem->pszText = tvdi.item.pszText; 3084 wineItem->cchTextMax = 128; 3085 } else 3086 { //user-supplied buffer 3087 INT len = lstrlenW(tvdi.item.pszText); 3088 3089 COMCTL32_Free(buf); 3090 if (len > 0) 3091 { 3092 len++; 3093 wineItem->pszText = (WCHAR*)COMCTL32_Alloc(len*sizeof(WCHAR)); 3094 lstrcpyW(wineItem->pszText,tvdi.item.pszText); 3095 wineItem->cchTextMax = len; 3096 } else 3097 { 3098 wineItem->pszText = NULL; 3099 wineItem->cchTextMax = len; 3100 } 3101 } 3102 *mustFree = FALSE; 3103 return wineItem->pszText; 3104 } else 3105 { 3106 if (buf != tvdi.item.pszText) 3107 { 3108 COMCTL32_Free(buf); 3109 *mustFree = FALSE; 3110 } else *mustFree = TRUE; 3111 return tvdi.item.pszText; 3112 } 3113 } else 3114 { 3115 if (tvdi.item.mask & TVIF_DI_SETITEM) 3116 { 3117 if (buf == tvdi.item.pszText) 3118 { 3119 wineItem->cchTextMax = 128; 3120 wineItem->pszText = (WCHAR*)COMCTL32_Alloc(128*sizeof(WCHAR)); 3121 lstrcpynAtoW(wineItem->pszText,(CHAR*)tvdi.item.pszText,wineItem->cchTextMax); 3122 COMCTL32_Free(buf); 3123 } else 3124 { //user-supplied buffer 3125 INT len = lstrlenA((CHAR*)tvdi.item.pszText); 3126 3127 COMCTL32_Free(buf); 3128 if (len > 0) 3129 { 3130 len++; 3131 wineItem->pszText = (WCHAR*)COMCTL32_Alloc(len*sizeof(WCHAR)); 3132 lstrcpyAtoW(wineItem->pszText,(CHAR*)tvdi.item.pszText); 3133 wineItem->cchTextMax = len; 3134 } else 3135 { 3136 wineItem->pszText = NULL; 3137 wineItem->cchTextMax = len; 3138 } 3139 } 3140 *mustFree = FALSE; 3141 return wineItem->pszText; 3142 } else 3143 { 3144 INT len = lstrlenA((LPSTR)tvdi.item.pszText); 3145 WCHAR* textW = (WCHAR*)COMCTL32_Alloc((len+1)*sizeof(WCHAR)); 3146 3147 lstrcpyAtoW(textW,(LPSTR)tvdi.item.pszText); 3148 COMCTL32_Free(buf); 3149 *mustFree = TRUE; 3150 return textW; 3151 } 3152 } 3153 } 3154 3155 static INT TREEVIEW_CallbackChildren(HWND hwnd,TREEVIEW_ITEM *wineItem) 3156 { 3157 NMTVDISPINFOW tvdi; 3158 BOOL retval; 3159 3160 tvdi.item.mask = TVIF_CHILDREN; 3161 tvdi.item.hItem = wineItem->hItem; 3162 tvdi.item.state = wineItem->state; 3163 tvdi.item.lParam = wineItem->lParam; 3164 tvdi.item.cChildren = 0; 3165 3166 retval = (BOOL)sendNotify(hwnd,isUnicodeNotify(hwnd) ? TVN_GETDISPINFOW:TVN_GETDISPINFOA,&tvdi.hdr); 3167 3168 if (tvdi.item.mask & TVIF_DI_SETITEM) 3169 wineItem->cChildren = tvdi.item.cChildren; 3170 3171 return tvdi.item.cChildren; 3172 } 3173 3174 static BOOL 3175 TREEVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc, 3176 RECT rc) 3177 { 3178 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3179 NMTVCUSTOMDRAW nmcdhdr; 3180 LPNMCUSTOMDRAW nmcd; 3181 3182 nmcd = &nmcdhdr.nmcd; 3183 nmcd->dwDrawStage= dwDrawStage; 3184 nmcd->hdc = hdc; 3185 nmcd->rc.left = rc.left; 3186 nmcd->rc.right = rc.right; 3187 nmcd->rc.bottom = rc.bottom; 3188 nmcd->rc.top = rc.top; 3189 nmcd->dwItemSpec = 0; 3190 nmcd->uItemState = 0; 3191 nmcd->lItemlParam= 0; 3192 nmcdhdr.clrText = infoPtr->clrText; 3193 nmcdhdr.clrTextBk= infoPtr->clrBk; 3194 nmcdhdr.iLevel = 0; 3195 3196 return (BOOL)sendNotify(hwnd,NM_CUSTOMDRAW,&nmcdhdr.nmcd.hdr); 3197 } 3198 3199 /* FIXME: need to find out when the flags in uItemState need to be set */ 3200 3201 static BOOL 3202 TREEVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc, 3203 TREEVIEW_ITEM *wineItem, UINT uItemDrawState) 3204 { 3205 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3206 NMTVCUSTOMDRAW nmcdhdr; 3207 LPNMCUSTOMDRAW nmcd; 3208 DWORD dwDrawStage,dwItemSpec; 3209 UINT uItemState; 3210 INT retval; 3211 3212 dwDrawStage=CDDS_ITEM | uItemDrawState; 3213 dwItemSpec=(DWORD)wineItem->hItem; 3214 uItemState=0; 3215 if (wineItem->hItem == infoPtr->selectedItem) 3216 { 3217 uItemState|=CDIS_SELECTED; 3218 if (GetFocus() == hwnd) uItemState |= CDIS_FOCUS; 3219 } 3220 if (wineItem->hItem==infoPtr->hotItem) uItemState|=CDIS_HOT; 3221 3222 nmcd= & nmcdhdr.nmcd; 3223 nmcd->dwDrawStage= dwDrawStage; 3224 nmcd->hdc = hdc; 3225 nmcd->rc.left = wineItem->rect.left; 3226 nmcd->rc.right = wineItem->rect.right; 3227 nmcd->rc.bottom = wineItem->rect.bottom; 3228 nmcd->rc.top = wineItem->rect.top; 3229 nmcd->dwItemSpec = dwItemSpec; 3230 nmcd->uItemState = uItemState; 3231 nmcd->lItemlParam= wineItem->lParam; 3232 3233 nmcdhdr.clrText = infoPtr->clrText; 3234 nmcdhdr.clrTextBk= infoPtr->clrBk; 3235 nmcdhdr.iLevel = wineItem->iLevel; 3236 3237 //TRACE (treeview,"drawstage:%lx hdc:%x item:%lx, itemstate:%x\n", 3238 // dwDrawStage, hdc, dwItemSpec, uItemState); 3239 3240 retval = sendNotify(hwnd,NM_CUSTOMDRAW,&nmcdhdr.nmcd.hdr); 3241 3242 infoPtr->clrText=nmcdhdr.clrText; 3243 infoPtr->clrBk =nmcdhdr.clrTextBk; 3244 3245 return (BOOL) retval; 3246 } 3247 3248 static VOID TREEVIEW_SendKeyDownNotify(HWND hwnd,UINT code,WORD wVKey) 3249 { 3250 NMTVKEYDOWN nmkdhdr; 3251 3252 nmkdhdr.wVKey = wVKey; 3253 nmkdhdr.flags = 0; 3254 3255 sendNotify(hwnd,code,&nmkdhdr.hdr); 2736 TREEVIEW_Toggle(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, BOOL bUser) 2737 { 2738 if (wineItem->state & TVIS_EXPANDED) 2739 return TREEVIEW_Collapse(infoPtr, wineItem, FALSE, bUser); 2740 else 2741 return TREEVIEW_Expand(infoPtr, wineItem, FALSE, bUser); 2742 } 2743 2744 static VOID 2745 TREEVIEW_ExpandAll(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) 2746 { 2747 TREEVIEW_Expand(infoPtr, item, FALSE, TRUE); 2748 2749 for (item = item->firstChild; item != NULL; item = item->nextSibling) 2750 { 2751 if (TREEVIEW_HasChildren(infoPtr, item)) 2752 TREEVIEW_ExpandAll(infoPtr, item); 2753 } 3256 2754 } 3257 2755 … … 3263 2761 3264 2762 static LRESULT 3265 TREEVIEW_Expand (HWND hwnd, WPARAM wParam, LPARAM lParam) 3266 { 3267 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2763 TREEVIEW_ExpandMsg(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 2764 { 2765 TREEVIEW_ITEM *wineItem = (HTREEITEM)lParam; 2766 UINT flag = wParam; 2767 2768 if (!TREEVIEW_ValidItem(infoPtr, wineItem)) 2769 return 0; 2770 2771 switch (flag & TVE_TOGGLE) 2772 { 2773 case TVE_COLLAPSE: 2774 return TREEVIEW_Collapse(infoPtr, wineItem, flag & TVE_COLLAPSERESET, 2775 FALSE); 2776 2777 case TVE_EXPAND: 2778 return TREEVIEW_Expand(infoPtr, wineItem, flag & TVE_EXPANDPARTIAL, 2779 FALSE); 2780 2781 case TVE_TOGGLE: 2782 return TREEVIEW_Toggle(infoPtr, wineItem, TRUE); 2783 2784 default: 2785 return 0; 2786 } 2787 2788 } 2789 2790 /* Hit-Testing **********************************************************/ 2791 2792 static TREEVIEW_ITEM * 2793 TREEVIEW_HitTestPoint(TREEVIEW_INFO *infoPtr,POINT pt) 2794 { 3268 2795 TREEVIEW_ITEM *wineItem; 3269 UINT flag; 3270 INT expand; 3271 3272 flag = (UINT)wParam; 3273 expand = (INT)lParam; 3274 3275 wineItem = TREEVIEW_ValidItem (infoPtr,(HTREEITEM)expand); 3276 3277 if (!wineItem) 3278 return 0; 3279 3280 if (!TREEVIEW_HasChildren(hwnd, wineItem)) 3281 return 0; 3282 3283 if ((flag & 0xF) == TVE_TOGGLE) 3284 { 3285 if (wineItem->state & TVIS_EXPANDED) 3286 flag = (flag & ~0xF)+TVE_COLLAPSE; 2796 2797 if (!infoPtr->firstVisible) 2798 return NULL; 2799 2800 wineItem = infoPtr->firstVisible; 2801 2802 while (wineItem && (pt.y > wineItem->rect.bottom)) 2803 wineItem = TREEVIEW_GetNextListItem(infoPtr,wineItem); 2804 2805 return wineItem; 2806 } 2807 2808 static LRESULT 2809 TREEVIEW_HitTest(TREEVIEW_INFO *infoPtr,LPTVHITTESTINFO lpht,BOOL ignoreClientRect) 2810 { 2811 TREEVIEW_ITEM *wineItem; 2812 RECT rect; 2813 UINT status, x, y; 2814 2815 if (!lpht) return 0; 2816 2817 status = 0; 2818 x = lpht->pt.x; 2819 y = lpht->pt.y; 2820 lpht->hItem = 0; 2821 2822 if (!ignoreClientRect) 2823 { 2824 GetClientRect(infoPtr->hwnd,&rect); 2825 2826 if (x < rect.left) status |= TVHT_TOLEFT; 2827 else if (x > rect.right) status |= TVHT_TORIGHT; 2828 if (y < rect.top) status |= TVHT_ABOVE; 2829 else if (y > rect.bottom) status |= TVHT_BELOW; 2830 2831 if (status) 2832 { 2833 lpht->flags = status; 2834 return (LRESULT)(HTREEITEM)NULL; 2835 } 2836 } 2837 2838 wineItem = TREEVIEW_HitTestPoint(infoPtr,lpht->pt); 2839 if (!wineItem) 2840 { 2841 lpht->flags = TVHT_NOWHERE; 2842 return (LRESULT)(HTREEITEM)NULL; 2843 } 2844 2845 if (!wineItem->calculated) 2846 TREEVIEW_CalcItem(infoPtr,wineItem,0); 2847 2848 if (x >= wineItem->textOffset + wineItem->textWidth) 2849 { 2850 lpht->flags = TVHT_ONITEMRIGHT; 2851 } 2852 else if (x >= wineItem->textOffset) 2853 { 2854 lpht->flags = TVHT_ONITEMLABEL; 2855 } 2856 else if (x >= wineItem->imageOffset) 2857 { 2858 lpht->flags = TVHT_ONITEMICON; 2859 } 2860 else if (x >= wineItem->stateOffset) 2861 { 2862 lpht->flags = TVHT_ONITEMSTATEICON; 2863 } 2864 else if ((x >= wineItem->linesOffset) && (infoPtr->dwStyle & TVS_HASBUTTONS)) 2865 { 2866 lpht->flags = TVHT_ONITEMBUTTON; 2867 } 3287 2868 else 3288 flag = (flag & ~0xF)+TVE_EXPAND; 3289 } 3290 3291 switch (flag & 0xF) 3292 { 3293 case TVE_COLLAPSE: 3294 { 3295 POINT oldLeftTop = infoPtr->lefttop; 3296 3297 if (!wineItem->state & TVIS_EXPANDED) 3298 return 0; 3299 3300 if (flag & TVE_COLLAPSERESET) 3301 { 3302 wineItem->state &= ~(TVIS_EXPANDEDONCE | TVIS_EXPANDED); 3303 TREEVIEW_RemoveAllChildren (hwnd, wineItem); 3304 } else wineItem->state &= ~TVIS_EXPANDED; 3305 3306 //update window 3307 //CB: todo: optimize! 3308 TREEVIEW_UnqueueRefresh(hwnd,FALSE,FALSE); 3309 //CB: todo: precalc expanded items here 3310 TREEVIEW_CalcItems(hwnd,0,infoPtr); 3311 TREEVIEW_Refresh(hwnd); 3312 //CB: todo: check cx and cy to fit ranges! 3313 3314 //check selection 3315 HTREEITEM hItem = infoPtr->selectedItem; 3316 3317 if (!TREEVIEW_ValidItem (infoPtr, hItem)) 3318 hItem = wineItem->hItem; 3319 else 3320 { 3321 while (hItem) 2869 { 2870 lpht->flags = TVHT_ONITEMINDENT; 2871 } 2872 2873 lpht->hItem = wineItem; 2874 //TRACE("(%ld,%ld):result %x\n", lpht->pt.x, lpht->pt.y, lpht->flags); 2875 2876 return (LRESULT)wineItem; 2877 } 2878 2879 /* Item Label Editing ***************************************************/ 2880 2881 static LRESULT 2882 TREEVIEW_GetEditControl(TREEVIEW_INFO *infoPtr) 2883 { 2884 return infoPtr->hwndEdit; 2885 } 2886 2887 static LRESULT CALLBACK 2888 TREEVIEW_Edit_SubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 2889 { 2890 TREEVIEW_INFO *infoPtr; 2891 BOOL bCancel = FALSE; 2892 2893 switch (uMsg) 2894 { 2895 case WM_PAINT: 3322 2896 { 3323 hItem = infoPtr->items[(INT)hItem].parent; 3324 3325 if (hItem == wineItem->hItem) 2897 LRESULT rc; 2898 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd)); 2899 2900 //TRACE("WM_PAINT start\n"); 2901 rc = CallWindowProcA(infoPtr->wpEditOrig, hwnd, uMsg, wParam, 2902 lParam); 2903 //TRACE("WM_PAINT done\n"); 2904 return rc; 2905 } 2906 2907 case WM_KILLFOCUS: 2908 { 2909 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd)); 2910 if (infoPtr->bIgnoreEditKillFocus) 2911 return TRUE; 2912 2913 break; 2914 } 2915 2916 case WM_GETDLGCODE: 2917 return DLGC_WANTARROWS | DLGC_WANTALLKEYS; 2918 2919 case WM_KEYDOWN: 2920 if (wParam == (WPARAM)VK_ESCAPE) 2921 { 2922 bCancel = TRUE; 3326 2923 break; 3327 2924 } 3328 } 3329 3330 if (hItem) 3331 TREEVIEW_DoSelectItem(hwnd,TVGN_CARET,hItem,TVC_UNKNOWN); 3332 3333 break; 3334 } 3335 3336 case TVE_EXPAND: 3337 { 3338 POINT oldLeftTop = infoPtr->lefttop; 3339 3340 if (wineItem->state & TVIS_EXPANDED) 3341 return 0; 3342 3343 if (flag & TVE_EXPANDPARTIAL) 3344 { 3345 return FALSE; //CB: how does this work??? (only display one level? nonsense in MSDN docu) 3346 wineItem->state ^=TVIS_EXPANDED; 3347 wineItem->state |=TVIS_EXPANDEDONCE; 3348 break; 3349 } 3350 3351 if (!(wineItem->state & TVIS_EXPANDEDONCE)) 3352 { 3353 //TRACE(treeview, " and has never been expanded...\n"); 3354 wineItem->state |= TVIS_EXPANDED; 3355 3356 /* this item has never been expanded */ 3357 if (TREEVIEW_SendTreeviewNotify(hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_ITEMEXPANDINGW:TVN_ITEMEXPANDINGA,TVE_EXPAND,0,(HTREEITEM)expand)) 3358 return FALSE; 3359 3360 3361 /* FIXME 3362 * Since the TVN_ITEMEXPANDING message may has caused the parent to 3363 * insert new items which in turn may have cause items placeholder 3364 * reallocation, I reassign the current item pointer so we have 3365 * something valid to work with... 3366 * However, this should not be necessary, 3367 * investigation required in TREEVIEW_InsertItemA 3368 */ 3369 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand); 3370 if (!wineItem) 2925 else if (wParam == (WPARAM)VK_RETURN) 3371 2926 { 3372 //ERR(treeview, 3373 // "Catastropic situation, cannot retreive item #%d\n", 3374 // expand); 3375 return FALSE; 2927 break; 3376 2928 } 3377 2929 3378 wineItem->state |= TVIS_EXPANDEDONCE; 3379 3380 TREEVIEW_SendTreeviewNotify (hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_ITEMEXPANDEDW:TVN_ITEMEXPANDEDA,TVE_EXPAND,0,(HTREEITEM)expand); 3381 } else 3382 { 3383 /* this item has already been expanded */ 3384 wineItem->state |= TVIS_EXPANDED; 3385 } 3386 3387 //update window 3388 //CB: todo: optimize! 3389 TREEVIEW_UnqueueRefresh(hwnd,FALSE,FALSE); 3390 //CB: todo: precalc expanded items here 3391 TREEVIEW_CalcItems(hwnd,0,infoPtr); 3392 TREEVIEW_Refresh(hwnd); 3393 //CB: todo: check cx and cy to fit ranges! 3394 3395 break; 3396 } 3397 2930 /* fall through */ 3398 2931 default: 3399 return FALSE; 3400 } 3401 3402 return TRUE; 3403 } 3404 3405 static LRESULT TREEVIEW_HitTest(HWND hwnd,LPTVHITTESTINFO lpht,BOOL ignoreClientRect) 3406 { 3407 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3408 TREEVIEW_ITEM *wineItem; 3409 RECT rect; 3410 UINT status; 3411 INT x,y; 3412 3413 if (!lpht) return 0; 3414 3415 status = 0; 3416 x = lpht->pt.x; 3417 y = lpht->pt.y; 3418 3419 if (!ignoreClientRect) 3420 { 3421 GetClientRect (hwnd, &rect); 3422 3423 if (x < rect.left) status |= TVHT_TOLEFT; 3424 if (x > rect.right) status |= TVHT_TORIGHT; 3425 if (y < rect.top ) status |= TVHT_ABOVE; 3426 if (y > rect.bottom) status |= TVHT_BELOW; 3427 3428 if (status) 3429 { 3430 lpht->flags = status; 3431 lpht->hItem = 0; 3432 3433 return 0; 3434 } 3435 } 3436 3437 if (infoPtr->firstVisible) 3438 { 3439 wineItem = &infoPtr->items [(INT)infoPtr->firstVisible]; 3440 3441 while ((wineItem != NULL) && (y > wineItem->rect.bottom)) 3442 wineItem = TREEVIEW_GetNextListItem(hwnd,infoPtr,wineItem); 3443 } else wineItem = NULL; 3444 3445 if (!wineItem) 3446 { 3447 lpht->flags = TVHT_NOWHERE; 3448 lpht->hItem = 0; 2932 { 2933 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd)); 2934 2935 //@@@PH 1999/11/05 method called with freed infoPtr memory object 2936 if (infoPtr != NULL) 2937 return CallWindowProcA(infoPtr->wpEditOrig, hwnd, uMsg, wParam, lParam); 2938 else 2939 break; 2940 } 2941 } 2942 2943 /* Processing TVN_ENDLABELEDIT message could kill the focus */ 2944 /* eg. Using a messagebox */ 2945 2946 infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd)); 2947 infoPtr->bIgnoreEditKillFocus = TRUE; 2948 TREEVIEW_EndEditLabelNow(infoPtr, bCancel || !infoPtr->bLabelChanged); 2949 infoPtr->bIgnoreEditKillFocus = FALSE; 3449 2950 3450 2951 return 0; 3451 } 3452 3453 lpht->flags = 0; 3454 3455 if (x < wineItem->expandBox.left) { 3456 lpht->flags |= TVHT_ONITEMINDENT; 3457 goto done; 3458 } 3459 if ( PtInRect ( &wineItem->expandBox, lpht->pt)) { 3460 lpht->flags |= TVHT_ONITEMBUTTON; 3461 goto done; 3462 } 3463 if ( PtInRect ( &wineItem->bitmap, lpht->pt)) { 3464 lpht->flags |= TVHT_ONITEMICON; 3465 goto done; 3466 } 3467 if ( PtInRect ( &wineItem->statebitmap, lpht->pt)) { 3468 lpht->flags |= TVHT_ONITEMSTATEICON; 3469 goto done; 3470 } 3471 if ( PtInRect ( &wineItem->text, lpht->pt)) { 3472 lpht->flags |= TVHT_ONITEMLABEL; 3473 goto done; 3474 } 3475 3476 lpht->flags |= TVHT_ONITEMRIGHT; 3477 3478 done: 3479 lpht->hItem = wineItem->hItem; 3480 3481 return (LRESULT) wineItem->hItem; 3482 } 3483 3484 HWND TREEVIEW_EditLabel(HWND hwnd,HTREEITEM hItem,BOOL unicode) 2952 } 2953 2954 2955 /* should handle edit control messages here */ 2956 2957 static LRESULT 2958 TREEVIEW_Command(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 2959 { 2960 //TRACE("%x %ld\n", wParam, lParam); 2961 2962 switch (HIWORD(wParam)) 2963 { 2964 case EN_UPDATE: 2965 { 2966 /* 2967 * Adjust the edit window size 2968 */ 2969 char buffer[1024]; 2970 TREEVIEW_ITEM *editItem = infoPtr->selectedItem; 2971 HDC hdc = GetDC(infoPtr->hwndEdit); 2972 SIZE sz; 2973 int len; 2974 HFONT hFont, hOldFont = 0; 2975 2976 infoPtr->bLabelChanged = TRUE; 2977 2978 len = GetWindowTextA(infoPtr->hwndEdit, buffer, sizeof(buffer)); 2979 2980 /* Select font to get the right dimension of the string */ 2981 hFont = SendMessageA(infoPtr->hwndEdit, WM_GETFONT, 0, 0); 2982 if (hFont != 0) 2983 { 2984 hOldFont = SelectObject(hdc, hFont); 2985 } 2986 2987 if (GetTextExtentPoint32A(hdc, buffer, strlen(buffer), &sz)) 2988 { 2989 TEXTMETRICA textMetric; 2990 2991 /* Add Extra spacing for the next character */ 2992 GetTextMetricsA(hdc, &textMetric); 2993 sz.cx += (textMetric.tmMaxCharWidth * 2); 2994 2995 sz.cx = MAX(sz.cx, textMetric.tmMaxCharWidth * 3); 2996 sz.cx = MIN(sz.cx, 2997 infoPtr->clientWidth - editItem->textOffset + 2); 2998 2999 SetWindowPos(infoPtr->hwndEdit, 3000 HWND_TOP, 3001 0, 3002 0, 3003 sz.cx, 3004 editItem->rect.bottom - editItem->rect.top + 3, 3005 SWP_NOMOVE | SWP_DRAWFRAME); 3006 } 3007 3008 if (hFont != 0) 3009 { 3010 SelectObject(hdc, hOldFont); 3011 } 3012 3013 ReleaseDC(infoPtr->hwnd, hdc); 3014 break; 3015 } 3016 3017 default: 3018 return SendMessageA(GetParent(infoPtr->hwnd), WM_COMMAND, wParam, lParam); 3019 } 3020 3021 return 0; 3022 } 3023 3024 HWND TREEVIEW_EditLabel(TREEVIEW_INFO *infoPtr,HTREEITEM hItem,BOOL unicode) 3485 3025 { 3486 3026 SIZE sz; 3487 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3488 TREEVIEW_ITEM *editItem = TREEVIEW_ValidItem(infoPtr, (HTREEITEM)hItem); 3489 HINSTANCE hinst = GetWindowLongA(hwnd, GWL_HINSTANCE); 3027 TREEVIEW_ITEM *editItem = hItem; 3028 HINSTANCE hinst = GetWindowLongA(infoPtr->hwnd,GWL_HINSTANCE); 3490 3029 HDC hdc; 3491 3030 HFONT hOldFont = 0; 3492 3031 TEXTMETRICA textMetric; 3493 WCHAR* textW;3494 3032 CHAR* textA = NULL; 3495 BOOL mustFree = FALSE;3496 3033 NMTVDISPINFOW tvdi; 3497 3034 3498 if (! editItem)3499 return FALSE;3035 if (!TREEVIEW_ValidItem(infoPtr, editItem)) 3036 return (HWND)NULL; 3500 3037 3501 3038 if(infoPtr->hwndEdit) 3502 3039 return infoPtr->hwndEdit; 3503 3040 3041 infoPtr->bLabelChanged = FALSE; 3042 3504 3043 /* Make shure that edit item is selected */ 3505 3044 3506 TREEVIEW_DoSelectItem ( hwnd, TVGN_CARET, hItem, TVC_UNKNOWN); 3507 3508 if (editItem->pszText == LPSTR_TEXTCALLBACKW) 3509 textW = TREEVIEW_CallbackText(hwnd,editItem,&mustFree); 3510 else 3511 textW = editItem->pszText; 3512 3513 hdc = GetDC(hwnd); 3045 TREEVIEW_DoSelectItem ( infoPtr, TVGN_CARET, hItem, TVC_UNKNOWN); 3046 3047 TREEVIEW_UpdateDispInfo(infoPtr, editItem, TVIF_TEXT); 3048 3049 hdc = GetDC(infoPtr->hwnd); 3514 3050 /* Select the font to get appropriate metric dimensions */ 3515 3051 if(infoPtr->hFont != 0) … … 3519 3055 3520 3056 /*Get String Lenght in pixels */ 3521 GetTextExtentPoint32W(hdc, textW,lstrlenW(textW),&sz);3057 GetTextExtentPoint32W(hdc,editItem->pszText,lstrlenW(editItem->pszText),&sz); 3522 3058 3523 3059 /*Add Extra spacing for the next character */ … … 3525 3061 sz.cx += (textMetric.tmMaxCharWidth * 2); 3526 3062 3063 sz.cx = MAX(sz.cx, textMetric.tmMaxCharWidth * 3); 3064 sz.cx = MIN(sz.cx, infoPtr->clientWidth - editItem->textOffset + 2); 3065 3527 3066 if(infoPtr->hFont != 0) 3528 3067 { … … 3530 3069 } 3531 3070 3532 ReleaseDC( hwnd, hdc);3071 ReleaseDC(infoPtr->hwnd, hdc); 3533 3072 infoPtr->hwndEdit = CreateWindowExA ( 3534 3073 WS_EX_LEFT, … … 3537 3076 WS_CHILD | WS_BORDER | ES_AUTOHSCROLL | WS_CLIPSIBLINGS | 3538 3077 ES_WANTRETURN | ES_LEFT, 3539 editItem->text .left - 2, editItem->text.top - 1,3540 sz.cx+3, editItem-> text.bottom - editItem->text.top + 3,3541 hwnd,3078 editItem->textOffset - 2, editItem->rect.top - 1, 3079 sz.cx+3, editItem->rect.bottom - editItem->rect.top + 3, 3080 infoPtr->hwnd, 3542 3081 0,hinst,0); /* FIXME: (HMENU)IDTVEDIT,pcs->hInstance,0);*/ 3543 3082 3544 SendMessageA ( infoPtr->hwndEdit, WM_SETFONT, infoPtr->hFont, FALSE); 3545 infoPtr->wpEditOrig = (WNDPROC)SetWindowLongA ( 3546 infoPtr->hwndEdit, 3547 GWL_WNDPROC, 3548 (DWORD) TREEVIEW_Edit_SubclassProc); 3083 /* Get a 2D border. */ 3084 SetWindowLongA(infoPtr->hwndEdit, GWL_EXSTYLE,GetWindowLongA(infoPtr->hwndEdit, GWL_EXSTYLE) & ~WS_EX_CLIENTEDGE); 3085 SetWindowLongA(infoPtr->hwndEdit, GWL_STYLE,GetWindowLongA(infoPtr->hwndEdit, GWL_STYLE) | WS_BORDER); 3086 3087 SendMessageA(infoPtr->hwndEdit, WM_SETFONT, TREEVIEW_FontForItem(infoPtr, editItem),FALSE); 3088 3089 infoPtr->wpEditOrig = (WNDPROC)SetWindowLongA (infoPtr->hwndEdit,GWL_WNDPROC,(DWORD)TREEVIEW_Edit_SubclassProc); 3549 3090 3550 3091 tvdi.item.mask = TVIF_HANDLE | TVIF_TEXT | TVIF_STATE | TVIF_PARAM; 3551 tvdi.item.hItem = editItem ->hItem;3092 tvdi.item.hItem = editItem; 3552 3093 tvdi.item.state = editItem->state; 3553 3094 tvdi.item.lParam = editItem->lParam; 3554 3095 if (isUnicodeNotify(&infoPtr->header)) 3555 3096 { 3556 tvdi.item.pszText = textW;3097 tvdi.item.pszText = editItem->pszText; 3557 3098 } else 3558 3099 { 3559 textA = HEAP_strdupWtoA(GetProcessHeap(),0, textW);3100 textA = HEAP_strdupWtoA(GetProcessHeap(),0,editItem->pszText); 3560 3101 tvdi.item.pszText = (LPWSTR)textA; 3561 3102 } 3562 3103 3563 if (sendNotify( hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_BEGINLABELEDITW:TVN_BEGINLABELEDITA,&tvdi.hdr))3104 if (sendNotify(infoPtr->hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_BEGINLABELEDITW:TVN_BEGINLABELEDITA,&tvdi.hdr)) 3564 3105 { 3565 3106 DestroyWindow(infoPtr->hwndEdit); 3566 3107 infoPtr->hwndEdit = 0; 3567 if (mustFree) COMCTL32_Free(textW); 3568 if (textA) COMCTL32_Free(textA); 3108 if (textA) HeapFree(GetProcessHeap(),0,textA); 3569 3109 3570 3110 return (HWND)0; … … 3572 3112 if (textA) HeapFree(GetProcessHeap(),0,textA); 3573 3113 3574 infoPtr-> editItem = hItem;3575 SetWindowTextW(infoPtr->hwndEdit, textW);3114 infoPtr->selectedItem = hItem; 3115 SetWindowTextW(infoPtr->hwndEdit,editItem->pszText); 3576 3116 SetFocus(infoPtr->hwndEdit); 3577 3117 SendMessageA(infoPtr->hwndEdit, EM_SETSEL, 0, -1); 3578 3118 ShowWindow(infoPtr->hwndEdit, SW_SHOW); 3579 if (mustFree) COMCTL32_Free(textW);3580 3119 3581 3120 return infoPtr->hwndEdit; … … 3583 3122 3584 3123 3585 LRESULT WINAPI 3586 TREEVIEW_EndEditLabelNow(HWND hwnd,BOOL bCancel) 3587 { 3588 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3589 TREEVIEW_ITEM *editedItem = TREEVIEW_ValidItem (infoPtr, infoPtr->editItem); 3124 static LRESULT 3125 TREEVIEW_EndEditLabelNow(TREEVIEW_INFO *infoPtr,BOOL bCancel) 3126 { 3127 TREEVIEW_ITEM *editedItem = infoPtr->selectedItem; 3590 3128 NMTVDISPINFOW tvdi; 3591 DWORD dwStyle = GetWindowLongA( hwnd,GWL_STYLE);3129 DWORD dwStyle = GetWindowLongA(infoPtr->hwnd,GWL_STYLE); 3592 3130 BOOL bCommit; 3593 3131 WCHAR *textW = NULL; … … 3599 3137 3600 3138 tvdi.item.mask = 0; 3601 tvdi.item.hItem = editedItem ->hItem;3139 tvdi.item.hItem = editedItem; 3602 3140 tvdi.item.state = editedItem->state; 3603 3141 tvdi.item.lParam = editedItem->lParam; … … 3612 3150 INT len = iLength+1; 3613 3151 3614 textA = (CHAR*)COMCTL32_Alloc( len*sizeof(CHAR));3152 textA = (CHAR*)COMCTL32_Alloc(1024*sizeof(CHAR)); 3615 3153 lstrcpynWtoA(textA,textW,len); 3616 3154 tvdi.item.pszText = (WCHAR*)textA; … … 3623 3161 } 3624 3162 3625 bCommit = (BOOL)sendNotify( hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_ENDLABELEDITW:TVN_ENDLABELEDITA,&tvdi.hdr);3163 bCommit = (BOOL)sendNotify(infoPtr->hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_ENDLABELEDITW:TVN_ENDLABELEDITA,&tvdi.hdr); 3626 3164 3627 3165 if (!bCancel && bCommit) /* Apply the changes */ 3628 3166 { 3629 WCHAR* text;3630 3167 BOOL mustFree = FALSE; 3631 3168 … … 3633 3170 lstrcpynAtoW(textW,textA,iLength+1); 3634 3171 3635 if (editedItem->pszText == LPSTR_TEXTCALLBACKW) 3636 text = TREEVIEW_CallbackText(hwnd,editedItem,&mustFree); 3637 else 3638 text = editedItem->pszText; 3639 3640 if (lstrcmpW(textW,text) != 0) 3641 { 3642 if (editedItem->pszText == LPSTR_TEXTCALLBACKW) 3172 if (lstrcmpW(textW,editedItem->pszText) != 0) 3173 { 3174 if (editedItem->callbackMask & TVIF_TEXT) 3643 3175 { 3644 3176 NMTVDISPINFOW tvdi; … … 3646 3178 3647 3179 tvdi.item.mask = TVIF_TEXT; 3648 tvdi.item.hItem = editedItem ->hItem;3180 tvdi.item.hItem = editedItem; 3649 3181 tvdi.item.state = editedItem->state; 3650 3182 tvdi.item.lParam = editedItem->lParam; … … 3659 3191 } 3660 3192 3661 retval = (BOOL)sendNotify( hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_SETDISPINFOW:TVN_SETDISPINFOA,&tvdi.hdr);3193 retval = (BOOL)sendNotify(infoPtr->hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_SETDISPINFOW:TVN_SETDISPINFOA,&tvdi.hdr); 3662 3194 } else 3663 3195 { 3664 if (!COMCTL32_ReAlloc( text,(iLength+1)*sizeof(WCHAR)))3196 if (!COMCTL32_ReAlloc(editedItem->pszText,(iLength+1)*sizeof(WCHAR))) 3665 3197 { 3666 3198 //ERR("OutOfMemory, cannot allocate space for label"); … … 3669 3201 if (textA) COMCTL32_Free(textA); 3670 3202 if (textW) COMCTL32_Free(textW); 3671 if (mustFree) COMCTL32_Free(text);3672 3203 3673 3204 return FALSE; … … 3679 3210 } 3680 3211 } 3681 if (mustFree) COMCTL32_Free(text);3682 3212 } 3683 3213 … … 3685 3215 DestroyWindow(infoPtr->hwndEdit); 3686 3216 infoPtr->hwndEdit = 0; 3687 infoPtr->editItem = 0;3688 3217 if (textA) COMCTL32_Free(textA); 3689 3218 if (textW) COMCTL32_Free(textW); 3690 3219 3691 3220 editedItem->calculated = FALSE; 3692 TREEVIEW_CalcItem(hwnd,0,dwStyle,infoPtr,editedItem); 3693 TREEVIEW_RefreshItem(hwnd,editedItem,TRUE); 3221 TREEVIEW_RefreshItem(infoPtr,editedItem,0); 3694 3222 3695 3223 return TRUE; 3696 3224 } 3697 3225 3226 static LRESULT 3227 TREEVIEW_HandleTimer (TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 3228 { 3229 switch (wParam) 3230 { 3231 case TV_REFRESH_TIMER: 3232 KillTimer(infoPtr->hwnd,TV_REFRESH_TIMER); 3233 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET; 3234 TREEVIEW_CalcItems(infoPtr); 3235 TREEVIEW_Refresh(infoPtr); 3236 return 0; 3237 3238 case TV_EDIT_TIMER: 3239 KillTimer(infoPtr->hwnd,TV_EDIT_TIMER); 3240 infoPtr->Timer &= ~TV_EDIT_TIMER_SET; 3241 TREEVIEW_EditLabel(infoPtr,infoPtr->selectedItem,TRUE); 3242 return 0; 3243 3244 case TV_INFOTIP_TIMER: 3245 TREEVIEW_CheckInfoTip(infoPtr); 3246 return 0; 3247 } 3248 3249 return 1; 3250 } 3251 3252 /* Mouse Tracking/Drag **************************************************/ 3698 3253 3699 3254 /*************************************************************************** … … 3701 3256 * Windows. 3702 3257 */ 3703 static LRESULT TREEVIEW_TrackMouse(HWND hwnd, POINT pt) 3704 { 3705 INT cxDrag = GetSystemMetrics(SM_CXDRAG); 3706 INT cyDrag = GetSystemMetrics(SM_CYDRAG); 3707 RECT r; 3708 MSG msg; 3709 3710 r.top = pt.y - cyDrag; 3711 r.left = pt.x - cxDrag; 3712 r.bottom = pt.y + cyDrag; 3713 r.right = pt.x + cxDrag; 3714 3715 SetCapture(hwnd); 3716 3717 while(1) 3718 { 3719 if (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD)) 3720 { 3721 if (msg.message == WM_MOUSEMOVE) 3722 { 3723 pt.x = (INT)LOWORD(msg.lParam); 3724 pt.y = (INT)HIWORD(msg.lParam); 3725 if (PtInRect(&r, pt)) 3726 continue; 3727 else 3258 static LRESULT 3259 TREEVIEW_TrackMouse(TREEVIEW_INFO *infoPtr, POINT pt) 3260 { 3261 INT cxDrag = GetSystemMetrics(SM_CXDRAG); 3262 INT cyDrag = GetSystemMetrics(SM_CYDRAG); 3263 RECT r; 3264 MSG msg; 3265 3266 r.top = pt.y - cyDrag; 3267 r.left = pt.x - cxDrag; 3268 r.bottom = pt.y + cyDrag; 3269 r.right = pt.x + cxDrag; 3270 3271 SetCapture(infoPtr->hwnd); 3272 3273 while (1) 3274 { 3275 if (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD)) 3276 { 3277 if (msg.message == WM_MOUSEMOVE) 3728 3278 { 3729 ReleaseCapture(); 3730 return 1; 3279 pt.x = (INT)LOWORD(msg.lParam); 3280 pt.y = (INT)HIWORD(msg.lParam); 3281 if (PtInRect(&r, pt)) 3282 continue; 3283 else 3284 { 3285 ReleaseCapture(); 3286 return 1; 3287 } 3731 3288 } 3732 } 3733 else if (msg.message >= WM_LBUTTONDOWN && 3734 msg.message <= WM_RBUTTONDBLCLK) 3735 { 3736 if (msg.message == WM_RBUTTONUP) 3737 TREEVIEW_RButtonUp (hwnd, &pt); 3738 break; 3739 } 3740 3741 DispatchMessageA( &msg ); 3742 } 3743 3744 if (GetCapture() != hwnd) 3745 return 0; 3746 } 3747 3748 ReleaseCapture(); 3749 return 0; 3750 } 3751 3752 static LRESULT 3753 TREEVIEW_LButtonDoubleClick (HWND hwnd, WPARAM wParam, LPARAM lParam) 3754 { 3755 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3289 else if (msg.message >= WM_LBUTTONDOWN && 3290 msg.message <= WM_RBUTTONDBLCLK) 3291 { 3292 if (msg.message == WM_RBUTTONUP) 3293 TREEVIEW_RButtonUp(infoPtr, &pt); 3294 break; 3295 } 3296 3297 DispatchMessageA(&msg); 3298 } 3299 3300 if (GetCapture() != infoPtr->hwnd) 3301 return 0; 3302 } 3303 3304 ReleaseCapture(); 3305 return 0; 3306 } 3307 3308 static LRESULT 3309 TREEVIEW_LButtonDoubleClick(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 3310 { 3756 3311 TREEVIEW_ITEM *wineItem; 3757 TV_HITTESTINFO hit info;3758 3759 hit info.pt.x = (INT)LOWORD(lParam);3760 hit info.pt.y = (INT)HIWORD(lParam);3761 SetFocus ( hwnd);3312 TV_HITTESTINFO hit; 3313 3314 hit.pt.x = (INT)LOWORD(lParam); 3315 hit.pt.y = (INT)HIWORD(lParam); 3316 SetFocus (infoPtr->hwnd); 3762 3317 3763 3318 if (infoPtr->Timer & TV_EDIT_TIMER_SET) 3764 3319 { 3765 3320 /* If there is pending 'edit label' event - kill it now */ 3766 infoPtr->editItem = 0;3767 KillTimer (hwnd, TV_EDIT_TIMER);3768 } 3769 3770 if (! TREEVIEW_HitTest(hwnd,&hitinfo,FALSE) || !(hitinfo.flags & TVHT_ONITEM)) return FALSE;3771 wineItem = &infoPtr->items [(INT)hitinfo.hItem];3321 KillTimer(infoPtr->hwnd,TV_EDIT_TIMER); 3322 } 3323 3324 wineItem = (TREEVIEW_ITEM *)TREEVIEW_HitTest(infoPtr,&hit,FALSE); 3325 if (!wineItem) 3326 return 0; 3772 3327 3773 3328 //MSDN documentation says: stop on non zero. but this isn't true in this case 3774 if (!sendNotify(hwnd,NM_DBLCLK)) 3775 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) wineItem->hItem); 3329 if (!sendNotify(infoPtr->hwnd,NM_DBLCLK)) 3330 { /* FIXME! */ 3331 switch (hit.flags) 3332 { 3333 case TVHT_ONITEMRIGHT: 3334 /* FIXME: we should not have send NM_DBLCLK in this case. */ 3335 break; 3336 3337 case TVHT_ONITEMINDENT: 3338 if (!(infoPtr->dwStyle & TVS_HASLINES)) 3339 { 3340 break; 3341 } else 3342 { 3343 int level = hit.pt.x / infoPtr->uIndent; 3344 3345 if (!(infoPtr->dwStyle & TVS_LINESATROOT)) level++; 3346 3347 while (wineItem->iLevel > level) 3348 { 3349 wineItem = wineItem->parent; 3350 } 3351 3352 /* fall through */ 3353 } 3354 3355 case TVHT_ONITEMLABEL: 3356 case TVHT_ONITEMICON: 3357 case TVHT_ONITEMSTATEICON: 3358 case TVHT_ONITEMBUTTON: 3359 TREEVIEW_Toggle(infoPtr, wineItem, TRUE); 3360 break; 3361 } 3362 } 3776 3363 3777 3364 return TRUE; 3778 3365 } 3779 3366 3780 HTREEITEM TREEVIEW_GetInfoTipItem(HWND hwnd,TREEVIEW_INFO *infoPtr,POINT pt) 3781 { 3782 TVHITTESTINFO ht; 3783 3784 ht.pt = pt; 3785 TREEVIEW_HitTest(hwnd,&ht,FALSE); 3786 3787 if (ht.hItem && (ht.flags & TVHT_ONITEM)) 3788 { 3789 TREEVIEW_ITEM *item; 3790 3791 item = &infoPtr->items[(INT)ht.hItem]; 3792 if (item->visible && ((item->text.left < 0) || (item->text.right > infoPtr->uVisibleWidth))) 3793 return ht.hItem; 3794 } 3795 3796 //check tool rect -> no flickering on tip frame 3797 if (infoPtr->tipItem) 3798 { 3799 POINT pt2 = pt; 3800 RECT rect; 3801 3802 GetWindowRect(infoPtr->hwndToolTip,&rect); 3803 ClientToScreen(hwnd,&pt2); 3804 return PtInRect(&rect,pt2) ? infoPtr->tipItem:0; 3805 } 3806 3807 return 0; 3808 } 3809 3810 VOID TREEVIEW_ShowInfoTip(HWND hwnd,TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item) 3811 { 3812 LPWSTR text; 3813 BOOL mustFree = FALSE; 3814 TTTOOLINFOW ti; 3815 POINT pt; 3816 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE); 3817 3818 if (dwStyle & TVS_INFOTIP) 3819 { 3820 NMTVGETINFOTIPW tvgit; 3821 WCHAR* buf = (WCHAR*)COMCTL32_Alloc(isUnicodeNotify(&infoPtr->header) ? INFOTIPSIZE*sizeof(WCHAR):INFOTIPSIZE*sizeof(CHAR)); 3822 3823 tvgit.pszText = buf; 3824 tvgit.cchTextMax = INFOTIPSIZE; 3825 tvgit.hItem = item->hItem; 3826 tvgit.lParam = item->lParam; 3827 3828 sendNotify(hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_GETINFOTIPW:TVN_GETINFOTIPA,&tvgit.hdr); 3829 if (isUnicodeNotify(&infoPtr->header)) 3830 { 3831 if (buf != tvgit.pszText) COMCTL32_Free(buf); else mustFree = TRUE; 3832 text = tvgit.pszText; 3833 } else 3834 { 3835 text = (WCHAR*)COMCTL32_Alloc(tvgit.cchTextMax*sizeof(WCHAR)); 3836 lstrcpyAtoW(text,(LPSTR)tvgit.pszText); 3837 COMCTL32_Free(buf); 3838 } 3839 } else 3840 { 3841 if (item->pszText == LPSTR_TEXTCALLBACKW) 3842 text = TREEVIEW_CallbackText(hwnd,item,&mustFree); 3843 else 3844 text = item->pszText; 3845 } 3846 3847 infoPtr->tipItem = item->hItem; 3848 SetTimer(hwnd,TV_INFOTIP_TIMER,TV_INFOTIP_DELAY,0); 3849 infoPtr->Timer |= TV_INFOTIP_TIMER_SET; 3850 3851 ti.cbSize = sizeof(ti); 3852 ti.uId = 0; 3853 ti.hwnd = hwnd; 3854 ti.hinst = 0; 3855 ti.lpszText = text; 3856 SendMessageA(infoPtr->hwndToolTip,TTM_TRACKACTIVATE,(WPARAM)FALSE,(LPARAM)&ti); 3857 pt.x = item->text.left; 3858 pt.y = item->text.top; 3859 ClientToScreen(hwnd,&pt); 3860 SendMessageA(infoPtr->hwndToolTip,TTM_TRACKPOSITION,0,(LPARAM)MAKELPARAM(pt.x,pt.y)); 3861 SendMessageA(infoPtr->hwndToolTip,TTM_UPDATETIPTEXTW,0,(LPARAM)&ti); 3862 SendMessageA(infoPtr->hwndToolTip,TTM_TRACKACTIVATE,(WPARAM)TRUE,(LPARAM)&ti); 3863 3864 if (mustFree) COMCTL32_Free(text); 3865 } 3866 3867 VOID TREEVIEW_HideInfoTip(HWND hwnd,TREEVIEW_INFO *infoPtr) 3868 { 3869 if (infoPtr->tipItem) 3870 { 3871 TTTOOLINFOA ti; 3872 3873 infoPtr->tipItem = 0; 3874 KillTimer(hwnd,TV_INFOTIP_TIMER); 3875 infoPtr->Timer &= ~TV_INFOTIP_TIMER_SET; 3876 3877 ti.cbSize = sizeof(TTTOOLINFOA); 3878 ti.uId = 0; 3879 ti.hwnd = (UINT)hwnd; 3880 3881 SendMessageA(infoPtr->hwndToolTip,TTM_TRACKACTIVATE,(WPARAM)FALSE,(LPARAM)&ti); 3882 } 3883 } 3884 3885 static VOID TREEVIEW_CheckInfoTip(HWND hwnd) 3886 { 3887 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3888 HTREEITEM hItem; 3889 POINT pt; 3890 3891 GetCursorPos(&pt); 3892 ScreenToClient(hwnd,&pt); 3893 hItem = TREEVIEW_GetInfoTipItem(hwnd,infoPtr,pt); 3894 3895 if (hItem != infoPtr->tipItem) 3896 TREEVIEW_HideInfoTip(hwnd,infoPtr); 3897 } 3898 3899 HTREEITEM TREEVIEW_GetHottrackItem(HWND hwnd,TREEVIEW_INFO *infoPtr,POINT pt) 3900 { 3901 TVHITTESTINFO ht; 3902 3903 ht.pt = pt; 3904 TREEVIEW_HitTest(hwnd,&ht,FALSE); 3905 3906 return (ht.hItem && (ht.flags & TVHT_ONITEM)) ? ht.hItem:0; 3907 } 3908 3909 static LRESULT TREEVIEW_MouseMove(HWND hwnd,WPARAM wParam,LPARAM lParam) 3910 { 3911 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3912 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE); 3913 POINT pt; 3914 3915 pt.x = (INT)LOWORD(lParam); 3916 pt.y = (INT)HIWORD(lParam); 3917 3918 if (infoPtr->hwndToolTip) 3919 { 3920 HTREEITEM hItem = TREEVIEW_GetInfoTipItem(hwnd,infoPtr,pt); 3921 3922 if (infoPtr->tipItem != hItem) 3923 { 3924 if (hItem) 3925 { 3926 TREEVIEW_ITEM *item; 3927 3928 item = &infoPtr->items[(INT)hItem]; 3929 TREEVIEW_ShowInfoTip(hwnd,infoPtr,item); 3930 } else TREEVIEW_HideInfoTip(hwnd,infoPtr); 3931 } 3932 } 3933 3934 if (dwStyle & TVS_TRACKSELECT) 3935 { 3936 HTREEITEM hItem = TREEVIEW_GetHottrackItem(hwnd,infoPtr,pt); 3937 3938 if (infoPtr->hotItem != hItem) 3939 { 3940 TREEVIEW_ITEM *item; 3941 HDC hdc = 0; 3942 3943 item = TREEVIEW_ValidItem(infoPtr,infoPtr->hotItem); 3944 if (item) 3945 { 3946 if (!hdc) hdc = GetDC(hwnd); 3947 TREEVIEW_DrawHottrackLine(hdc,item); 3948 } 3949 if (hItem) 3950 { 3951 item = &infoPtr->items[(INT)hItem]; 3952 if (item) 3953 { 3954 if (!hdc) hdc = GetDC(hwnd); 3955 TREEVIEW_DrawHottrackLine(hdc,item); 3956 } 3957 } 3958 if (hdc) ReleaseDC(hwnd,hdc); 3959 } 3960 } 3961 3962 return 0; 3963 } 3964 3965 static LRESULT 3966 TREEVIEW_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam) 3967 { 3968 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3367 static LRESULT 3368 TREEVIEW_LButtonDown(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 3369 { 3969 3370 TVHITTESTINFO ht; 3970 3371 BOOL bTrack; 3971 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);3972 3372 3973 3373 /* If Edit control is active - kill it and return. … … 3978 3378 if (infoPtr->hwndEdit) 3979 3379 { 3980 SetFocus (hwnd);3380 SetFocus(infoPtr->hwnd); 3981 3381 return 0; 3982 3382 } … … 3985 3385 ht.pt.y = (INT)HIWORD(lParam); 3986 3386 3987 TREEVIEW_HitTest (hwnd,&ht,FALSE);3988 3989 bTrack = (ht.flags & TVHT_ONITEM) && !( dwStyle & TVS_DISABLEDRAGDROP);3387 TREEVIEW_HitTest(infoPtr,&ht,FALSE); 3388 3389 bTrack = (ht.flags & TVHT_ONITEM) && !(infoPtr->dwStyle & TVS_DISABLEDRAGDROP); 3990 3390 3991 3391 /* Send NM_CLICK right away */ 3992 3392 if (!bTrack) 3993 if (sendNotify( hwnd,NM_CLICK))3393 if (sendNotify(infoPtr->hwnd,NM_CLICK)) 3994 3394 goto setfocus; 3995 3395 3996 3396 if (ht.flags & TVHT_ONITEMBUTTON) 3997 3397 { 3998 TREEVIEW_ Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) ht.hItem);3398 TREEVIEW_Toggle(infoPtr,ht.hItem,TRUE); 3999 3399 goto setfocus; 4000 3400 } else if (bTrack) 4001 3401 { 4002 if (TREEVIEW_TrackMouse( hwnd,ht.pt))4003 { 4004 TREEVIEW_SendTreeviewDnDNotify (hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_BEGINDRAGW:TVN_BEGINDRAGA, ht.hItem, ht.pt);3402 if (TREEVIEW_TrackMouse(infoPtr,ht.pt)) 3403 { 3404 TREEVIEW_SendTreeviewDnDNotify(infoPtr,isUnicodeNotify(&infoPtr->header) ? TVN_BEGINDRAGW:TVN_BEGINDRAGA, ht.hItem, ht.pt); 4005 3405 infoPtr->dropItem = ht.hItem; 4006 3406 return 0; … … 4008 3408 } 4009 3409 4010 if (sendNotify( hwnd,NM_CLICK))3410 if (sendNotify(infoPtr->hwnd,NM_CLICK)) 4011 3411 goto setfocus; 4012 3412 … … 4015 3415 * and the click occured on the item label... 4016 3416 */ 4017 if (( dwStyle & TVS_EDITLABELS) && (ht.flags & TVHT_ONITEMLABEL) && (infoPtr->selectedItem == ht.hItem))3417 if ((infoPtr->dwStyle & TVS_EDITLABELS) && (ht.flags & TVHT_ONITEMLABEL) && (infoPtr->selectedItem == ht.hItem)) 4018 3418 { 4019 3419 if (infoPtr->Timer & TV_EDIT_TIMER_SET) 4020 KillTimer (hwnd, TV_EDIT_TIMER); 4021 4022 infoPtr->editItem = ht.hItem; 4023 SetTimer (hwnd, TV_EDIT_TIMER, GetDoubleClickTime(), 0); 4024 infoPtr->Timer|=TV_EDIT_TIMER_SET; 3420 KillTimer(infoPtr->hwnd,TV_EDIT_TIMER); 3421 3422 SetTimer(infoPtr->hwnd,TV_EDIT_TIMER,GetDoubleClickTime(),0); 3423 infoPtr->Timer |= TV_EDIT_TIMER_SET; 4025 3424 } else if (ht.flags & (TVHT_ONITEMLABEL | TVHT_ONITEMICON)) 4026 3425 { 4027 TREEVIEW_DoSelectItem( hwnd,TVGN_CARET,ht.hItem,TVC_BYMOUSE);3426 TREEVIEW_DoSelectItem(infoPtr,TVGN_CARET,ht.hItem,TVC_BYMOUSE); 4028 3427 } else if (ht.flags & TVHT_ONITEMSTATEICON) 4029 3428 { 4030 if (dwStyle & TVS_CHECKBOXES) /* TVS_CHECKBOXES requires _us_ */ 4031 { /* to toggle the current state */ 4032 int state; 4033 TREEVIEW_ITEM *wineItem; 4034 4035 wineItem = TREEVIEW_ValidItem(infoPtr, ht.hItem); 4036 4037 state = 1-(wineItem->state>>12); 4038 wineItem->state &= ~TVIS_STATEIMAGEMASK; 4039 wineItem->state |= state<<12; 4040 if (wineItem->visible) 4041 { 4042 TREEVIEW_UnqueueRefresh(hwnd,TRUE,TRUE); 4043 InvalidateRect(hwnd,&wineItem->statebitmap,TRUE); 4044 } 3429 if (infoPtr->dwStyle & TVS_CHECKBOXES) 3430 { 3431 /* TVS_CHECKBOXES requires us to toggle the current state */ 3432 if (infoPtr->dwStyle & TVS_CHECKBOXES) 3433 TREEVIEW_ToggleItemState(infoPtr,ht.hItem); 4045 3434 } 4046 3435 } 4047 3436 4048 3437 setfocus: 4049 SetFocus (hwnd);3438 SetFocus(infoPtr->hwnd); 4050 3439 4051 3440 return 0; 4052 3441 } 4053 3442 4054 4055 static LRESULT 4056 TREEVIEW_RButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam) 4057 { 4058 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3443 static LRESULT 3444 TREEVIEW_RButtonDown(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 3445 { 4059 3446 TVHITTESTINFO ht; 4060 3447 4061 3448 if (infoPtr->hwndEdit) 4062 3449 { 4063 SetFocus( hwnd);3450 SetFocus(infoPtr->hwnd); 4064 3451 return 0; 4065 3452 } … … 4068 3455 ht.pt.y = (INT)HIWORD(lParam); 4069 3456 4070 TREEVIEW_HitTest( hwnd,&ht,FALSE);4071 4072 if (TREEVIEW_TrackMouse( hwnd,ht.pt))3457 TREEVIEW_HitTest(infoPtr,&ht,FALSE); 3458 3459 if (TREEVIEW_TrackMouse(infoPtr,ht.pt)) 4073 3460 { 4074 3461 if (ht.hItem) 4075 3462 { 4076 TREEVIEW_SendTreeviewDnDNotify (hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_BEGINRDRAGW:TVN_BEGINDRAGA, ht.hItem, ht.pt);3463 TREEVIEW_SendTreeviewDnDNotify(infoPtr,isUnicodeNotify(&infoPtr->header) ? TVN_BEGINRDRAGW:TVN_BEGINDRAGA, ht.hItem, ht.pt); 4077 3464 infoPtr->dropItem = ht.hItem; 4078 3465 } … … 4080 3467 else 4081 3468 { 4082 SetFocus( hwnd);4083 sendNotify( hwnd,NM_RCLICK);3469 SetFocus(infoPtr->hwnd); 3470 sendNotify(infoPtr->hwnd,NM_RCLICK); 4084 3471 } 4085 3472 … … 4087 3474 } 4088 3475 4089 static LRESULT TREEVIEW_RButtonDoubleClick(HWND hwnd,WPARAM wParam,LPARAM lParam) 4090 { 4091 sendNotify(hwnd,NM_RDBLCLK); 4092 4093 return DefWindowProcA(hwnd,WM_RBUTTONDBLCLK,wParam,lParam); 4094 } 4095 4096 static LRESULT 4097 TREEVIEW_RButtonUp (HWND hwnd, LPPOINT pPt) 4098 { 4099 POINT pt; 4100 4101 pt.x = pPt->x; 4102 pt.y = pPt->y; 3476 static LRESULT 3477 TREEVIEW_RButtonUp(TREEVIEW_INFO *infoPtr, LPPOINT pPt) 3478 { 3479 POINT pt = *pPt; 4103 3480 4104 3481 /* Change to screen coordinate for WM_CONTEXTMENU */ 4105 ClientToScreen( hwnd, &pt);3482 ClientToScreen(infoPtr->hwnd, &pt); 4106 3483 4107 3484 /* Send the WM_CONTEXTMENU on a right click */ 4108 SendMessageA( hwnd, WM_CONTEXTMENU, (WPARAM)hwnd, MAKELPARAM(pt.x, pt.y));3485 SendMessageA( infoPtr->hwnd, WM_CONTEXTMENU, (WPARAM)infoPtr->hwnd, MAKELPARAM(pt.x, pt.y)); 4109 3486 return 0; 4110 3487 } 4111 3488 4112 static LRESULT TREEVIEW_CreateDragImage (HWND hwnd, WPARAM wParam, LPARAM lParam) 4113 { 4114 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3489 static LRESULT TREEVIEW_CreateDragImage (TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 3490 { 4115 3491 TREEVIEW_ITEM *dragItem; 4116 3492 INT cx,cy; … … 4121 3497 RECT rc; 4122 3498 HFONT hOldFont; 4123 WCHAR *itemtxt;4124 BOOL mustFree = FALSE;4125 3499 4126 3500 if (!(infoPtr->himlNormal)) return 0; 4127 dragItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM) lParam); 4128 4129 if (!dragItem) return 0; 4130 4131 if (dragItem->pszText == LPSTR_TEXTCALLBACKW) 4132 itemtxt = TREEVIEW_CallbackText(hwnd,dragItem,&mustFree); 4133 else 4134 itemtxt = dragItem->pszText; 3501 if (!dragItem || !TREEVIEW_ValidItem(infoPtr, dragItem)) 3502 return 0; 3503 3504 TREEVIEW_UpdateDispInfo(infoPtr, dragItem, TVIF_TEXT); 4135 3505 4136 3506 hwtop = GetDesktopWindow(); … … 4139 3509 4140 3510 hOldFont = SelectObject (hdc, infoPtr->hFont); 4141 GetTextExtentPoint32W (hdc, itemtxt, lstrlenW (itemtxt), &size);3511 GetTextExtentPoint32W (hdc, dragItem->pszText, lstrlenW (dragItem->pszText), &size); 4142 3512 4143 3513 hbmp = CreateCompatibleBitmap (htopdc, size.cx, size.cy); … … 4159 3529 4160 3530 SetRect (&rc, cx, 0, size.cx,size.cy); 4161 DrawTextW (hdc, itemtxt, lstrlenW (itemtxt), &rc, DT_LEFT);3531 DrawTextW (hdc, dragItem->pszText, lstrlenW(dragItem->pszText), &rc, DT_LEFT); 4162 3532 SelectObject (hdc, hOldFont); 4163 3533 SelectObject (hdc, hOldbmp); … … 4168 3538 DeleteObject (hbmp); 4169 3539 ReleaseDC (hwtop, htopdc); 4170 if (mustFree) COMCTL32_Free(itemtxt);4171 3540 4172 3541 return (LRESULT)infoPtr->dragList; 4173 3542 } 4174 3543 4175 4176 static LRESULT 4177 TREEVIEW_DoSelectItem (HWND hwnd, INT action, HTREEITEM newSelect, INT cause) 4178 { 4179 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 4180 TREEVIEW_ITEM *prevItem,*wineItem; 4181 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE); 4182 INT prevSelect; 3544 /* Selection ************************************************************/ 3545 3546 static LRESULT 3547 TREEVIEW_DoSelectItem(TREEVIEW_INFO *infoPtr, INT action, HTREEITEM newSelect, 3548 INT cause) 3549 { 3550 TREEVIEW_ITEM *prevSelect; 4183 3551 BOOL refreshPrev = FALSE,refreshNew = FALSE; 4184 3552 4185 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)newSelect); 4186 4187 if (wineItem && wineItem->parent) 4188 { 4189 TREEVIEW_ITEM *parent = TREEVIEW_ValidItem(infoPtr,wineItem->parent); 3553 assert(newSelect == NULL || TREEVIEW_ValidItem(infoPtr, newSelect)); 3554 3555 //TRACE("Entering item %p (%s), flag %x, cause %x, state %d\n", 3556 // newSelect, TREEVIEW_ItemName(newSelect), action, cause, 3557 // newSelect ? newSelect->state : 0); 3558 3559 if (newSelect && newSelect->parent) 3560 { 3561 TREEVIEW_ITEM *parent = newSelect->parent; 4190 3562 4191 3563 /* … … 4195 3567 while (parent && !(parent->state & TVIS_EXPANDED)) 4196 3568 { 4197 TREEVIEW_Expand(hwnd,TVE_EXPAND,(LPARAM)parent->hItem); 4198 parent = TREEVIEW_ValidItem(infoPtr,parent->parent); 4199 } 4200 } 3569 TREEVIEW_Expand(infoPtr,parent,FALSE,FALSE); 3570 parent = parent->parent; 3571 } 3572 } 3573 4201 3574 4202 3575 switch (action) 4203 3576 { 4204 3577 case TVGN_CARET: 4205 prevSelect = (INT)infoPtr->selectedItem; 4206 4207 if ((HTREEITEM)prevSelect == newSelect) 4208 return FALSE; 4209 4210 prevItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect); 3578 prevSelect = infoPtr->selectedItem; 3579 3580 if (prevSelect == newSelect) 3581 return FALSE; 3582 3583 if (TREEVIEW_SendTreeviewNotify(infoPtr, 3584 isUnicodeNotify(&infoPtr->header) ? TVN_SELCHANGINGW:TVN_SELCHANGINGA, 3585 cause, 3586 TVIF_HANDLE | TVIF_STATE | TVIF_PARAM, 3587 prevSelect, 3588 newSelect)) 3589 return FALSE; /* FIXME: OK? */ 3590 3591 if (prevSelect) 3592 { 3593 refreshPrev = prevSelect->state & TVIS_SELECTED; 3594 prevSelect->state &= ~TVIS_SELECTED; 3595 } 4211 3596 4212 3597 if (newSelect) 4213 if (TREEVIEW_SendTreeviewNotify(hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_SELCHANGINGW:TVN_SELCHANGINGA,cause,(HTREEITEM)prevSelect,(HTREEITEM)newSelect))4214 return FALSE; /* FIXME: OK? */4215 4216 if (prevItem)4217 3598 { 4218 refresh Prev = prevItem->state & TVIS_SELECTED;4219 prevItem->state &= ~TVIS_SELECTED;3599 refreshNew = !(newSelect->state & TVIS_SELECTED); 3600 newSelect->state |= TVIS_SELECTED; 4220 3601 } 4221 if (wineItem) 4222 { 4223 refreshNew = !(wineItem->state & TVIS_SELECTED); 4224 wineItem->state |= TVIS_SELECTED; 4225 } 4226 4227 infoPtr->selectedItem = (HTREEITEM)newSelect; 4228 4229 if ((cause == TVC_BYMOUSE) && (dwStyle & TVS_SINGLEEXPAND)) 3602 3603 infoPtr->selectedItem = newSelect; 3604 3605 if ((cause == TVC_BYMOUSE) && (infoPtr->dwStyle & TVS_SINGLEEXPAND)) 4230 3606 { 4231 3607 BOOL control = GetKeyState(VK_CONTROL) & 0x8000; 4232 UINT rc = TREEVIEW_SendTreeviewNotify( hwnd,TVN_SINGLEEXPAND,0,prevItem->hItem,wineItem->hItem);4233 4234 if (!(rc & TVNRET_SKIPOLD) && !control && prevItem->state & TVIS_EXPANDED)4235 TREEVIEW_ Expand(hwnd,TVE_COLLAPSE,(LPARAM)prevItem->hItem);4236 if (!(rc & TVNRET_SKIPNEW) && TREEVIEW_HasChildren( hwnd,wineItem))4237 TREEVIEW_ Expand(hwnd,TVE_TOGGLE,(LPARAM)wineItem->hItem);3608 UINT rc = TREEVIEW_SendTreeviewNotify(infoPtr,TVN_SINGLEEXPAND,0,TVIF_HANDLE | TVIF_STATE | TVIF_PARAM,prevSelect,newSelect); 3609 3610 if (!(rc & TVNRET_SKIPOLD) && !control && (prevSelect->state & TVIS_EXPANDED)) 3611 TREEVIEW_Collapse(infoPtr,prevSelect,FALSE,FALSE); 3612 if (!(rc & TVNRET_SKIPNEW) && TREEVIEW_HasChildren(infoPtr,newSelect)) 3613 TREEVIEW_Toggle(infoPtr,newSelect,FALSE); 4238 3614 } 4239 3615 4240 TREEVIEW_UnqueueRefresh(hwnd,TRUE,TRUE); 4241 if (dwStyle & TVS_FULLROWSELECT) 3616 TREEVIEW_UnqueueRefresh(infoPtr,TRUE,TRUE); 3617 TREEVIEW_EnsureVisible(infoPtr,infoPtr->selectedItem); 3618 if (infoPtr->dwStyle & TVS_FULLROWSELECT) 4242 3619 { 4243 3620 TREEVIEW_ITEM *item; 4244 3621 4245 3622 //deselect last selected row 4246 if (prev Item)3623 if (prevSelect) 4247 3624 { 4248 if (refreshPrev) TREEVIEW_RefreshItem( hwnd,prevItem,FALSE);4249 if (prev Item->upsibling)3625 if (refreshPrev) TREEVIEW_RefreshItem(infoPtr,prevSelect,TVIF_IMAGE | TVIF_TEXT); 3626 if (prevSelect->prevSibling) 4250 3627 { 4251 item = &infoPtr->items[(INT)prevItem->upsibling];3628 item = prevSelect->prevSibling; 4252 3629 while (item) 4253 3630 { … … 4255 3632 { 4256 3633 item->state &= ~TVIS_SELECTED; 4257 TREEVIEW_RefreshItem( hwnd,item,FALSE);3634 TREEVIEW_RefreshItem(infoPtr,item,TVIF_IMAGE | TVIF_TEXT); 4258 3635 } 4259 item = &infoPtr->items[(INT)item->upsibling];3636 item = item->prevSibling; 4260 3637 } 4261 3638 } 4262 if (prev Item->sibling)3639 if (prevSelect->nextSibling) 4263 3640 { 4264 item = &infoPtr->items[(INT)prevItem->sibling];3641 item = prevSelect->nextSibling; 4265 3642 while (item) 4266 3643 { … … 4268 3645 { 4269 3646 item->state &= ~TVIS_SELECTED; 4270 TREEVIEW_RefreshItem( hwnd,item,FALSE);3647 TREEVIEW_RefreshItem(infoPtr,item,TVIF_IMAGE | TVIF_TEXT); 4271 3648 } 4272 item = &infoPtr->items[(INT)item->sibling];3649 item = item->nextSibling; 4273 3650 } 4274 3651 } … … 4276 3653 4277 3654 //select new row 4278 if ( wineItem)3655 if (newSelect) 4279 3656 { 4280 if (refreshNew) TREEVIEW_RefreshItem( hwnd,wineItem,FALSE);4281 if ( wineItem->upsibling)3657 if (refreshNew) TREEVIEW_RefreshItem(infoPtr,newSelect,TVIF_IMAGE | TVIF_TEXT); 3658 if (newSelect->prevSibling) 4282 3659 { 4283 item = &infoPtr->items[(INT)wineItem->upsibling];3660 item = newSelect->prevSibling; 4284 3661 while (item) 4285 3662 { … … 4287 3664 { 4288 3665 item->state |= TVIS_SELECTED; 4289 TREEVIEW_RefreshItem( hwnd,item,FALSE);3666 TREEVIEW_RefreshItem(infoPtr,item,TVIF_IMAGE | TVIF_TEXT); 4290 3667 } 4291 item = &infoPtr->items[(INT)item->upsibling];3668 item = item->prevSibling; 4292 3669 } 4293 3670 } 4294 if ( wineItem->sibling)3671 if (newSelect->nextSibling) 4295 3672 { 4296 item = &infoPtr->items[(INT)wineItem->sibling];3673 item = newSelect->nextSibling; 4297 3674 while (item) 4298 3675 { … … 4300 3677 { 4301 3678 item->state |= TVIS_SELECTED; 4302 TREEVIEW_RefreshItem( hwnd,item,FALSE);3679 TREEVIEW_RefreshItem(infoPtr,item,TVIF_IMAGE | TVIF_TEXT); 4303 3680 } 4304 item = &infoPtr->items[(INT)item->sibling];3681 item = item->nextSibling; 4305 3682 } 4306 3683 } … … 4308 3685 } else 4309 3686 { 4310 if (refreshPrev) TREEVIEW_RefreshItem( hwnd,prevItem,FALSE);4311 if (refreshNew) TREEVIEW_RefreshItem( hwnd,wineItem,FALSE);3687 if (refreshPrev) TREEVIEW_RefreshItem(infoPtr,prevSelect,TVIF_IMAGE | TVIF_TEXT); 3688 if (refreshNew) TREEVIEW_RefreshItem(infoPtr,newSelect,TVIF_IMAGE | TVIF_TEXT); 4312 3689 } 4313 3690 4314 TREEVIEW_SendTreeviewNotify(hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_SELCHANGEDW:TVN_SELCHANGEDA,cause,(HTREEITEM)prevSelect,(HTREEITEM)newSelect); 4315 3691 TREEVIEW_SendTreeviewNotify(infoPtr, 3692 isUnicodeNotify(&infoPtr->header) ? TVN_SELCHANGEDW:TVN_SELCHANGEDA, 3693 cause, 3694 TVIF_HANDLE | TVIF_STATE | TVIF_PARAM, 3695 prevSelect, 3696 newSelect); 4316 3697 break; 4317 3698 4318 3699 case TVGN_DROPHILITE: 4319 prev Item = TREEVIEW_ValidItem (infoPtr, infoPtr->dropItem);4320 4321 if (prev Item)3700 prevSelect = infoPtr->dropItem; 3701 3702 if (prevSelect) 4322 3703 { 4323 refreshPrev = prev Item->state & TVIS_DROPHILITED;4324 prev Item->state &= ~TVIS_DROPHILITED;3704 refreshPrev = prevSelect->state & TVIS_DROPHILITED; 3705 prevSelect->state &= ~TVIS_DROPHILITED; 4325 3706 } 4326 3707 4327 infoPtr->dropItem = (HTREEITEM)newSelect;4328 4329 if ( wineItem)3708 infoPtr->dropItem = newSelect; 3709 3710 if (newSelect) 4330 3711 { 4331 refreshNew = !( wineItem->state & TVIS_DROPHILITED);4332 wineItem->state |=TVIS_DROPHILITED;3712 refreshNew = !(newSelect->state & TVIS_DROPHILITED); 3713 newSelect->state |= TVIS_DROPHILITED; 4333 3714 } 4334 3715 4335 TREEVIEW_UnqueueRefresh( hwnd,TRUE,TRUE);4336 if (refreshPrev) TREEVIEW_RefreshItem( hwnd,prevItem,FALSE);4337 if (refreshNew) TREEVIEW_RefreshItem( hwnd,wineItem,FALSE);3716 TREEVIEW_UnqueueRefresh(infoPtr,TRUE,TRUE); 3717 if (refreshPrev) TREEVIEW_RefreshItem(infoPtr,prevSelect,TVIF_IMAGE | TVIF_TEXT); 3718 if (refreshNew) TREEVIEW_RefreshItem(infoPtr,newSelect,TVIF_IMAGE | TVIF_TEXT); 4338 3719 4339 3720 break; … … 4346 3727 if (!infoPtr->firstVisible) return FALSE; 4347 3728 4348 firstVis = &infoPtr->items[(INT)infoPtr->firstVisible];4349 4350 if ( wineItem->rect.top < 0)4351 scrollY = wineItem->rect.top;3729 firstVis = infoPtr->firstVisible; 3730 3731 if (newSelect->rect.top < 0) 3732 scrollY = newSelect->rect.top; 4352 3733 else 4353 3734 { 4354 scrollY = MIN( wineItem->rect.top,(infoPtr->uTotalHeight-infoPtr->uVisibleHeight)-infoPtr->lefttop.y);4355 scrollY -= scrollY % infoPtr->u VScrollStep;3735 scrollY = MIN(newSelect->rect.top,(infoPtr->treeHeight-infoPtr->clientHeight)-infoPtr->lefttop.y); 3736 scrollY -= scrollY % infoPtr->uItemHeight; 4356 3737 } 4357 3738 … … 4359 3740 { 4360 3741 infoPtr->lefttop.y += scrollY; 4361 if (!TREEVIEW_UnqueueRefresh( hwnd,TRUE,TRUE))4362 TREEVIEW_CalcItems( hwnd,0,infoPtr);4363 4364 ScrollWindowEx( hwnd,0,-scrollY,NULL,NULL,0,NULL,SW_INVALIDATE | SW_SCROLLCHILDREN | (infoPtr->uScrollTime << 16));3742 if (!TREEVIEW_UnqueueRefresh(infoPtr,TRUE,TRUE)) 3743 TREEVIEW_CalcItems(infoPtr); 3744 3745 ScrollWindowEx(infoPtr->hwnd,0,-scrollY,NULL,NULL,0,NULL,SW_INVALIDATE | SW_SCROLLCHILDREN | (infoPtr->uScrollTime << 16)); 4365 3746 } 4366 3747 4367 3748 break; 4368 3749 } 4369 } 4370 4371 return TRUE; 4372 } 4373 4374 static LRESULT 4375 TREEVIEW_SelectItem (HWND hwnd, WPARAM wParam, LPARAM lParam) 4376 { 4377 return TREEVIEW_DoSelectItem(hwnd,wParam,(HTREEITEM)lParam,TVC_UNKNOWN); 4378 } 4379 4380 static LRESULT 4381 TREEVIEW_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam) 4382 { 4383 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 4384 4385 return infoPtr->hFont; 4386 } 4387 4388 static LRESULT 4389 TREEVIEW_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam) 4390 { 4391 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 4392 TEXTMETRICA tm; 4393 LOGFONTA logFont; 4394 HFONT hFont, hOldFont; 4395 INT height; 4396 HDC hdc; 4397 4398 infoPtr->hFont = (HFONT)wParam; 4399 4400 hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT); 4401 4402 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont); 4403 logFont.lfWeight = FW_BOLD; 4404 DeleteObject(infoPtr->hBoldFont); 4405 infoPtr->hBoldFont = CreateFontIndirectA (&logFont); 4406 4407 SendMessageA(infoPtr->hwndToolTip,WM_SETFONT,infoPtr->hFont,1); 4408 infoPtr->uInternalStatus |= TV_CALCALL; 4409 TREEVIEW_CalcItems(hwnd,0,infoPtr); 4410 4411 if (lParam) 4412 { 4413 TREEVIEW_UnqueueRefresh(hwnd,FALSE,FALSE); 4414 TREEVIEW_Refresh(hwnd); 4415 } 4416 4417 return 0; 4418 } 4419 4420 static LRESULT 4421 TREEVIEW_VScroll(HWND hwnd,WPARAM wParam,LPARAM lParam) 4422 { 4423 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3750 } 3751 3752 //TRACE("Leaving state %d\n", newSelect ? newSelect->state : 0); 3753 return TRUE; 3754 } 3755 3756 /* FIXME: handle NM_KILLFOCUS etc */ 3757 static LRESULT 3758 TREEVIEW_SelectItem(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 3759 { 3760 HTREEITEM item = (HTREEITEM)lParam; 3761 3762 if (item != NULL && !TREEVIEW_ValidItem(infoPtr, item)) 3763 return FALSE; 3764 3765 //TRACE("%p (%s) %d\n", item, TREEVIEW_ItemName(item), (int)wParam); 3766 3767 if (!TREEVIEW_DoSelectItem(infoPtr, wParam, item, TVC_UNKNOWN)) 3768 return FALSE; 3769 3770 return TRUE; 3771 } 3772 3773 /* Scrolling ************************************************************/ 3774 3775 static LRESULT TREEVIEW_EnsureVisible(TREEVIEW_INFO *infoPtr,HTREEITEM item) 3776 { 3777 RECT rect; 3778 INT scrollY; 3779 3780 if (!item) return FALSE; 3781 3782 if (!TREEVIEW_ValidItem(infoPtr,item)) 3783 return FALSE; 3784 3785 if (item && item->parent) 3786 { 3787 TREEVIEW_ITEM *parent = item->parent; 3788 3789 while (parent && !(parent->state & TVIS_EXPANDED)) 3790 { 3791 TREEVIEW_Expand(infoPtr,parent,FALSE,FALSE); 3792 parent = parent->parent; 3793 } 3794 } 3795 3796 TREEVIEW_UnqueueRefresh(infoPtr,TRUE,TRUE); 3797 GetClientRect(infoPtr->hwnd,&rect); 3798 if (item->rect.top < 0) 3799 scrollY = item->rect.top; 3800 else if (item->rect.bottom > rect.bottom) 3801 { 3802 INT mod; 3803 3804 scrollY = item->rect.bottom-rect.bottom; 3805 mod = scrollY % infoPtr->uItemHeight; 3806 if (mod) scrollY += infoPtr->uItemHeight-mod; 3807 } else return FALSE; 3808 3809 if (scrollY != 0) 3810 { 3811 infoPtr->lefttop.y += scrollY; 3812 TREEVIEW_CalcItems(infoPtr); 3813 ScrollWindowEx(infoPtr->hwnd,0,-scrollY,NULL,NULL,0,NULL,SW_INVALIDATE | SW_SCROLLCHILDREN | (infoPtr->uScrollTime << 16)); 3814 3815 return TRUE; 3816 } 3817 3818 return FALSE; 3819 } 3820 3821 static LRESULT 3822 TREEVIEW_VScroll(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 3823 { 4424 3824 INT newY,mod; 4425 INT maxY = infoPtr-> uTotalHeight-infoPtr->uVisibleHeight;3825 INT maxY = infoPtr->treeHeight-infoPtr->clientHeight; 4426 3826 4427 3827 if (!(infoPtr->uInternalStatus & TV_VSCROLL)) return FALSE; 4428 3828 4429 mod = maxY % infoPtr->u VScrollStep;4430 if (mod > 0) maxY += infoPtr->u VScrollStep-mod;3829 mod = maxY % infoPtr->uItemHeight; 3830 if (mod > 0) maxY += infoPtr->uItemHeight-mod; 4431 3831 4432 3832 switch (LOWORD (wParam)) 4433 3833 { 4434 3834 case SB_LINEUP: 4435 newY = infoPtr->lefttop.y-infoPtr->u VScrollStep;3835 newY = infoPtr->lefttop.y-infoPtr->uItemHeight; 4436 3836 if (newY < 0) newY = 0; 4437 3837 break; 4438 3838 4439 3839 case SB_LINEDOWN: 4440 newY = infoPtr->lefttop.y+infoPtr->u VScrollStep;3840 newY = infoPtr->lefttop.y+infoPtr->uItemHeight; 4441 3841 if (newY > maxY) newY = maxY; 4442 3842 break; 4443 3843 4444 3844 case SB_PAGEUP: 4445 newY = infoPtr->lefttop.y-MAX(((INT)(infoPtr-> uVisibleHeight/infoPtr->uVScrollStep))*infoPtr->uVScrollStep,infoPtr->uVScrollStep);3845 newY = infoPtr->lefttop.y-MAX(((INT)(infoPtr->clientHeight/infoPtr->uItemHeight))*infoPtr->uItemHeight,infoPtr->uItemHeight); 4446 3846 if (newY < 0) newY = 0; 4447 3847 break; 4448 3848 4449 3849 case SB_PAGEDOWN: 4450 newY = infoPtr->lefttop.y+MAX(((INT)(infoPtr-> uVisibleHeight/infoPtr->uVScrollStep))*infoPtr->uVScrollStep,infoPtr->uVScrollStep);3850 newY = infoPtr->lefttop.y+MAX(((INT)(infoPtr->clientHeight/infoPtr->uItemHeight))*infoPtr->uItemHeight,infoPtr->uItemHeight); 4451 3851 if (newY > maxY) newY = maxY; 4452 3852 break; … … 4454 3854 case SB_THUMBTRACK: 4455 3855 newY = HIWORD(wParam); 4456 mod = newY % infoPtr->u VScrollStep;3856 mod = newY % infoPtr->uItemHeight; 4457 3857 if (mod > 0) newY -= mod; 4458 3858 break; … … 4465 3865 { 4466 3866 INT scrollY = infoPtr->lefttop.y-newY; 4467 4468 TREEVIEW_HideInfoTip(hwnd,infoPtr); 3867 SCROLLINFO info; 3868 3869 TREEVIEW_HideInfoTip(infoPtr); 4469 3870 infoPtr->lefttop.y = newY; 4470 if (!TREEVIEW_UnqueueRefresh(hwnd,TRUE,TRUE)) 4471 TREEVIEW_CalcItems(hwnd,0,infoPtr); 4472 ScrollWindowEx(hwnd,0,scrollY,NULL,NULL,0,NULL,SW_INVALIDATE | SW_SCROLLCHILDREN | (infoPtr->uScrollTime << 16)); 3871 if (!TREEVIEW_UnqueueRefresh(infoPtr,TRUE,TRUE)) 3872 TREEVIEW_MoveItems(infoPtr,0,scrollY); 3873 3874 info.cbSize = sizeof(info); 3875 info.nPos = infoPtr->lefttop.y; 3876 info.fMask = SIF_POS; 3877 SetScrollInfo(infoPtr->hwnd,SB_VERT,&info,TRUE); 3878 3879 ScrollWindowEx(infoPtr->hwnd,0,scrollY,NULL,NULL,0,NULL,SW_INVALIDATE | SW_SCROLLCHILDREN | (infoPtr->uScrollTime << 16)); 4473 3880 4474 3881 return TRUE; … … 4479 3886 4480 3887 static LRESULT 4481 TREEVIEW_HScroll (HWND hwnd, WPARAM wParam, LPARAM lParam) 4482 { 4483 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3888 TREEVIEW_HScroll(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 3889 { 4484 3890 int maxWidth; 4485 3891 int lastPos = infoPtr->lefttop.x; 3892 SCROLLINFO info; 4486 3893 4487 3894 if (!(infoPtr->uInternalStatus & TV_HSCROLL)) return FALSE; … … 4491 3898 case SB_LINEUP: 4492 3899 if (!infoPtr->lefttop.x) return FALSE; 4493 infoPtr->lefttop.x -= infoPtr->u RealItemHeight;3900 infoPtr->lefttop.x -= infoPtr->uItemHeight; 4494 3901 if (infoPtr->lefttop.x < 0) infoPtr->lefttop.x = 0; 4495 3902 break; 4496 3903 4497 3904 case SB_LINEDOWN: 4498 maxWidth = infoPtr-> uTotalWidth-infoPtr->uVisibleWidth;3905 maxWidth = infoPtr->treeWidth-infoPtr->clientWidth; 4499 3906 if (maxWidth <= 0) return FALSE; 4500 3907 if (infoPtr->lefttop.x == maxWidth) return FALSE; 4501 infoPtr->lefttop.x += infoPtr->u RealItemHeight; /*FIXME */3908 infoPtr->lefttop.x += infoPtr->uItemHeight; /*FIXME */ 4502 3909 if (infoPtr->lefttop.x > maxWidth) 4503 3910 infoPtr->lefttop.x = maxWidth; … … 4506 3913 case SB_PAGEUP: 4507 3914 if (!infoPtr->lefttop.x) return FALSE; 4508 infoPtr->lefttop.x -= infoPtr-> uVisibleWidth;3915 infoPtr->lefttop.x -= infoPtr->clientWidth; 4509 3916 if (infoPtr->lefttop.x < 0) infoPtr->lefttop.x = 0; 4510 3917 break; 4511 3918 4512 3919 case SB_PAGEDOWN: 4513 maxWidth = infoPtr-> uTotalWidth-infoPtr->uVisibleWidth;3920 maxWidth = infoPtr->treeWidth-infoPtr->clientWidth; 4514 3921 if (maxWidth <= 0) return FALSE; 4515 3922 if (infoPtr->lefttop.x == maxWidth) return FALSE; 4516 infoPtr->lefttop.x += infoPtr-> uVisibleWidth;3923 infoPtr->lefttop.x += infoPtr->clientWidth; 4517 3924 if (infoPtr->lefttop.x > maxWidth) 4518 3925 infoPtr->lefttop.x = maxWidth; … … 4520 3927 4521 3928 case SB_THUMBTRACK: 4522 maxWidth = infoPtr-> uTotalWidth-infoPtr->uVisibleWidth;3929 maxWidth = infoPtr->treeWidth-infoPtr->clientWidth; 4523 3930 if (maxWidth <= 0) return FALSE; 4524 3931 infoPtr->lefttop.x = HIWORD(wParam); … … 4533 3940 if (lastPos != infoPtr->lefttop.x) 4534 3941 { 4535 TREEVIEW_HideInfoTip(hwnd,infoPtr); 4536 if (!TREEVIEW_UnqueueRefresh(hwnd,TRUE,TRUE)) 4537 TREEVIEW_CalcItems(hwnd,0,infoPtr); 4538 ScrollWindowEx(hwnd,lastPos-infoPtr->lefttop.x,0,NULL,NULL,0,NULL,SW_INVALIDATE | SW_SCROLLCHILDREN | (infoPtr->uScrollTime << 16)); 3942 TREEVIEW_HideInfoTip(infoPtr); 3943 if (!TREEVIEW_UnqueueRefresh(infoPtr,TRUE,TRUE)) 3944 TREEVIEW_MoveItems(infoPtr,lastPos-infoPtr->lefttop.x,0); 3945 3946 info.cbSize = sizeof(info); 3947 info.nPos = infoPtr->lefttop.x; 3948 info.fMask = SIF_POS; 3949 SetScrollInfo(infoPtr->hwnd,SB_HORZ,&info,TRUE); 3950 3951 ScrollWindowEx(infoPtr->hwnd,lastPos-infoPtr->lefttop.x,0,NULL,NULL,0,NULL,SW_INVALIDATE | SW_SCROLLCHILDREN | (infoPtr->uScrollTime << 16)); 4539 3952 4540 3953 return TRUE; … … 4544 3957 } 4545 3958 4546 static LRESULT TREEVIEW_MouseWheel (HWND hwnd, WPARAM wParam, LPARAM lParam) 4547 { 4548 4549 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 4550 short gcWheelDelta = 0; 3959 static LRESULT 3960 TREEVIEW_MouseWheel(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 3961 { 3962 short gcWheelDelta; 4551 3963 UINT pulScrollLines = 3; 4552 3964 4553 if (wParam & (MK_SHIFT | MK_CONTROL)) 4554 return DefWindowProcA( hwnd, WM_MOUSEWHEEL, wParam, lParam ); 4555 4556 4557 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0); 4558 4559 gcWheelDelta -= (short) HIWORD(wParam); 3965 if (infoPtr->firstVisible == NULL) 3966 return TRUE; 3967 3968 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES, 0, &pulScrollLines, 0); 3969 3970 gcWheelDelta = -(short)HIWORD(wParam); 4560 3971 pulScrollLines *= (gcWheelDelta / WHEEL_DELTA); 4561 3972 4562 3973 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines) 4563 3974 { 4564 int wheelDy = pulScrollLines * infoPtr->u RealItemHeight;3975 int wheelDy = pulScrollLines * infoPtr->uItemHeight; 4565 3976 int newDy = infoPtr->lefttop.y + wheelDy; 4566 int maxDy = infoPtr-> uTotalHeight-infoPtr->uVisibleHeight;3977 int maxDy = infoPtr->treeHeight-infoPtr->clientHeight; 4567 3978 4568 3979 if (newDy > maxDy) newDy = maxDy; 3980 4569 3981 if (newDy < 0) newDy = 0; 4570 3982 4571 if (newDy == infoPtr->lefttop.y) return TRUE; 4572 4573 TREEVIEW_VScroll(hwnd, MAKEWPARAM(SB_THUMBTRACK,newDy),0); 4574 } 4575 return TRUE; 4576 } 4577 4578 static LRESULT 4579 TREEVIEW_KeyDown (HWND hwnd, WPARAM wParam, LPARAM lParam) 4580 { 4581 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 4582 HTREEITEM hNewSelection = 0; 4583 INT prevSelect = (INT)infoPtr->selectedItem; 4584 TREEVIEW_ITEM *prevItem = 4585 (prevSelect != 0 ) ? 4586 TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect) : 4587 NULL; 4588 TREEVIEW_ITEM *newItem = NULL; 4589 BOOL control; 4590 4591 TREEVIEW_SendKeyDownNotify(hwnd,TVN_KEYDOWN,wParam); 4592 4593 control = GetKeyState(VK_CONTROL) & 0x8000; 4594 4595 if (control) 4596 { 4597 INT scrollMsg = -1; 4598 BOOL horz = FALSE; 4599 4600 switch (wParam) 4601 { 4602 case VK_UP: 4603 scrollMsg = SB_LINELEFT; 3983 TREEVIEW_VScroll(infoPtr, MAKEWPARAM(SB_THUMBTRACK, newDy), 0); 3984 } 3985 return TRUE; 3986 } 3987 3988 /* Create/Destroy *******************************************************/ 3989 3990 static LRESULT 3991 TREEVIEW_Create (HWND hwnd, WPARAM wParam, LPARAM lParam) 3992 { 3993 LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam; 3994 TREEVIEW_INFO *infoPtr; 3995 RECT rcClient; 3996 3997 /* allocate memory for info structure */ 3998 infoPtr = (TREEVIEW_INFO*)initControl(hwnd,sizeof(TREEVIEW_INFO)); 3999 4000 if (!infoPtr) return 0; 4001 4002 /* set default settings */ 4003 infoPtr->hwnd = hwnd; 4004 infoPtr->dwStyle = GetWindowLongA(hwnd, GWL_STYLE); 4005 infoPtr->uInternalStatus = TV_CALCALL; 4006 infoPtr->Timer = 0; 4007 infoPtr->uNumItems = 0; 4008 infoPtr->cdmode = 0; 4009 infoPtr->uScrollTime = 300; /* milliseconds */ 4010 4011 GetClientRect(hwnd,&rcClient); 4012 4013 /* No scroll bars yet. */ 4014 infoPtr->clientWidth = rcClient.right; 4015 infoPtr->clientHeight = rcClient.bottom; 4016 4017 infoPtr->treeWidth = 0; 4018 infoPtr->treeHeight = 0; 4019 4020 infoPtr->uIndent = 19; 4021 infoPtr->selectedItem = 0; 4022 infoPtr->firstVisible = 0; 4023 infoPtr->maxDisplayOrder = 0; 4024 infoPtr->dropItem = 0; 4025 infoPtr->insertMarkItem = 0; 4026 infoPtr->insertBeforeorAfter = 0; 4027 4028 infoPtr->clrBk = GetSysColor(COLOR_WINDOW); 4029 infoPtr->clrText = -1; /* use system color */ 4030 infoPtr->clrLine = RGB(128, 128, 128); 4031 infoPtr->clrInsertMark = GetSysColor(COLOR_BTNTEXT); 4032 4033 infoPtr->lefttop.y = 0; 4034 infoPtr->lefttop.x = 0; 4035 4036 infoPtr->hwndEdit = 0; 4037 infoPtr->wpEditOrig = NULL; 4038 infoPtr->bIgnoreEditKillFocus = FALSE; 4039 infoPtr->bLabelChanged = FALSE; 4040 4041 infoPtr->himlNormal = NULL; 4042 infoPtr->himlState = NULL; 4043 infoPtr->normalImageWidth = 0; 4044 infoPtr->normalImageHeight = 0; 4045 infoPtr->stateImageWidth = 0; 4046 infoPtr->stateImageHeight = 0; 4047 4048 infoPtr->items = DPA_Create(16); 4049 4050 infoPtr->hFont = GetStockObject(DEFAULT_GUI_FONT); 4051 infoPtr->hBoldFont = TREEVIEW_CreateBoldFont(infoPtr->hFont); 4052 4053 infoPtr->uItemHeight = TREEVIEW_NaturalHeight(infoPtr); 4054 4055 infoPtr->root = TREEVIEW_AllocateItem(infoPtr); 4056 infoPtr->root->state = TVIS_EXPANDED; 4057 infoPtr->root->iLevel = -1; 4058 infoPtr->root->displayOrder = -1; 4059 4060 infoPtr->pszISearch = NULL; 4061 infoPtr->uISearchLen = 0; 4062 4063 infoPtr->tipItem = 0; 4064 infoPtr->hwndToolTip = 0; 4065 if (!(infoPtr->dwStyle & TVS_NOTOOLTIPS)) 4066 { 4067 infoPtr->hwndToolTip = createToolTip(hwnd,TTF_TRACK | TTF_ABSOLUTE | TTF_TRANSPARENT,TRUE); 4068 SendMessageA(infoPtr->hwndToolTip,WM_SETFONT,infoPtr->hFont,0); 4069 } 4070 4071 if (infoPtr->dwStyle & TVS_CHECKBOXES) 4072 { 4073 HBITMAP hbmLoad; 4074 int nIndex; 4075 4076 infoPtr->himlState = ImageList_Create (16, 16,ILC_COLOR | ILC_MASK, 15, 1); 4077 4078 //MSDN docu says: uses DrawFrameControl but never believe what they write 4079 hbmLoad = LoadBitmapA (COMCTL32_hModule, MAKEINTRESOURCEA(IDT_CHECK)); 4080 nIndex = ImageList_AddMasked (infoPtr->himlState, hbmLoad, CLR_DEFAULT); 4081 DeleteObject (hbmLoad); 4082 4083 infoPtr->stateImageWidth = 16; 4084 infoPtr->stateImageHeight = 16; 4085 } 4086 4087 return 0; 4088 } 4089 4090 static LRESULT 4091 TREEVIEW_Destroy(TREEVIEW_INFO *infoPtr) 4092 { 4093 TREEVIEW_RemoveTree(infoPtr); 4094 4095 /* tool tip is automatically destroyed: we are its owner */ 4096 4097 /* Restore original windproc. */ 4098 if (infoPtr->hwndEdit) 4099 SetWindowLongA(infoPtr->hwndEdit, GWL_WNDPROC,(LONG)infoPtr->wpEditOrig); 4100 4101 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) 4102 KillTimer(infoPtr->hwnd, TV_REFRESH_TIMER); 4103 4104 DeleteObject(infoPtr->hBoldFont); 4105 COMCTL32_Free(infoPtr->pszISearch); 4106 doneControl(infoPtr->hwnd); 4107 4108 return 0; 4109 } 4110 4111 /* Miscellaneous Messages ***********************************************/ 4112 4113 static LRESULT 4114 TREEVIEW_ScrollKeyDown(TREEVIEW_INFO *infoPtr, WPARAM key) 4115 { 4116 static const struct 4117 { 4118 unsigned char code; 4119 } 4120 scroll[] = 4121 { 4122 #define SCROLL_ENTRY(dir, code) { ((dir) << 7) | (code) } 4123 SCROLL_ENTRY(SB_VERT, SB_PAGEUP), /* VK_PRIOR */ 4124 SCROLL_ENTRY(SB_VERT, SB_PAGEDOWN), /* VK_NEXT */ 4125 SCROLL_ENTRY(SB_VERT, SB_BOTTOM), /* VK_END */ 4126 SCROLL_ENTRY(SB_VERT, SB_TOP), /* VK_HOME */ 4127 SCROLL_ENTRY(SB_HORZ, SB_LINEUP), /* VK_LEFT */ 4128 SCROLL_ENTRY(SB_VERT, SB_LINEUP), /* VK_UP */ 4129 SCROLL_ENTRY(SB_HORZ, SB_LINEDOWN), /* VK_RIGHT */ 4130 SCROLL_ENTRY(SB_VERT, SB_LINEDOWN) /* VK_DOWN */ 4131 #undef SCROLL_ENTRY 4132 }; 4133 4134 if (key >= VK_PRIOR && key <= VK_DOWN) 4135 { 4136 unsigned char code = scroll[key - VK_PRIOR].code; 4137 4138 (((code & (1 << 7)) == (SB_HORZ << 7)) 4139 ? TREEVIEW_HScroll 4140 : TREEVIEW_VScroll)(infoPtr, code & 0x7F, 0); 4141 } 4142 4143 return 0; 4144 } 4145 4146 /************************************************************************ 4147 * TREEVIEW_KeyDown 4148 * 4149 * VK_UP Move selection to the previous non-hidden item. 4150 * VK_DOWN Move selection to the next non-hidden item. 4151 * VK_HOME Move selection to the first item. 4152 * VK_END Move selection to the last item. 4153 * VK_LEFT If expanded then collapse, otherwise move to parent. 4154 * VK_RIGHT If collapsed then expand, otherwise move to first child. 4155 * VK_ADD Expand. 4156 * VK_SUBTRACT Collapse. 4157 * VK_MULTIPLY Expand all. 4158 * VK_PRIOR Move up GetVisibleCount items. 4159 * VK_NEXT Move down GetVisibleCount items. 4160 * VK_BACK Move to parent. 4161 * CTRL-Left,Right,Up,Down,PgUp,PgDown,Home,End: Scroll without changing selection 4162 */ 4163 static LRESULT 4164 TREEVIEW_KeyDown(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 4165 { 4166 /* If it is non-NULL and different, it will be selected and visible. */ 4167 TREEVIEW_ITEM *newSelection = NULL; 4168 TREEVIEW_ITEM *prevItem = infoPtr->selectedItem; 4169 4170 TREEVIEW_SendKeyDownNotify(infoPtr,TVN_KEYDOWN,wParam); 4171 4172 //TRACE("%x %lx\n", wParam, lParam); 4173 4174 if (prevItem == NULL) 4175 return FALSE; 4176 4177 if (GetAsyncKeyState(VK_CONTROL) & 0x8000) 4178 return TREEVIEW_ScrollKeyDown(infoPtr, wParam); 4179 4180 switch (wParam) 4181 { 4182 case VK_UP: 4183 newSelection = TREEVIEW_GetPrevListItem(infoPtr, prevItem); 4184 if (!newSelection) 4185 newSelection = infoPtr->root->firstChild; 4604 4186 break; 4605 4187 4606 4607 scrollMsg = SB_LINERIGHT;4188 case VK_DOWN: 4189 newSelection = TREEVIEW_GetNextListItem(infoPtr, prevItem); 4608 4190 break; 4609 4191 4610 case VK_LEFT: 4611 scrollMsg = SB_LINELEFT; 4612 horz = TRUE; 4192 case VK_HOME: 4193 newSelection = infoPtr->root->firstChild; 4613 4194 break; 4614 4195 4615 case VK_RIGHT:4616 scrollMsg = SB_LINERIGHT;4617 horz = TRUE;4196 case VK_END: 4197 newSelection = TREEVIEW_GetLastListItem(infoPtr, 4198 infoPtr->root->lastChild); 4618 4199 break; 4619 4200 4620 case VK_PRIOR: 4621 scrollMsg = SB_PAGELEFT; 4201 case VK_LEFT: 4202 if (prevItem->state & TVIS_EXPANDED) 4203 { 4204 TREEVIEW_Collapse(infoPtr, prevItem, FALSE, TRUE); 4205 } 4206 else if (prevItem->parent != infoPtr->root) 4207 { 4208 newSelection = prevItem->parent; 4209 } 4622 4210 break; 4623 4211 4624 case VK_NEXT: 4625 scrollMsg = SB_PAGERIGHT; 4212 case VK_RIGHT: 4213 if (TREEVIEW_HasChildren(infoPtr, prevItem)) 4214 { 4215 if (!(prevItem->state & TVIS_EXPANDED)) 4216 TREEVIEW_Expand(infoPtr, prevItem, FALSE, TRUE); 4217 else 4218 { 4219 newSelection = prevItem->firstChild; 4220 } 4221 } 4222 4626 4223 break; 4627 } 4628 if (scrollMsg != -1) 4629 { 4630 SendMessageA(hwnd,horz ? WM_HSCROLL:WM_VSCROLL,MAKELONG(scrollMsg,0),0); 4631 return TRUE; 4632 } 4633 } 4634 4635 if (prevSelect == 0) 4636 return FALSE; 4637 4638 switch (wParam) 4639 { 4640 case VK_UP: 4641 newItem = TREEVIEW_GetPrevListItem(hwnd,infoPtr, prevItem); 4642 4643 if (!newItem) 4644 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem]; 4645 4646 hNewSelection = newItem->hItem; 4647 4224 4225 case VK_MULTIPLY: 4226 TREEVIEW_ExpandAll(infoPtr, prevItem); 4227 break; 4228 4229 case VK_ADD: 4230 if (!(prevItem->state & TVIS_EXPANDED)) 4231 TREEVIEW_Expand(infoPtr, prevItem, FALSE, TRUE); 4232 break; 4233 4234 case VK_SUBTRACT: 4235 if (prevItem->state & TVIS_EXPANDED) 4236 TREEVIEW_Collapse(infoPtr, prevItem, FALSE, TRUE); 4237 break; 4238 4239 case VK_PRIOR: 4240 newSelection 4241 = TREEVIEW_GetListItem(infoPtr, prevItem, 4242 -TREEVIEW_GetVisibleCount(infoPtr)); 4243 break; 4244 4245 case VK_NEXT: 4246 newSelection 4247 = TREEVIEW_GetListItem(infoPtr, prevItem, 4248 TREEVIEW_GetVisibleCount(infoPtr)); 4249 break; 4250 4251 case VK_RETURN: 4252 sendNotify(infoPtr->hwnd,NM_RETURN); 4648 4253 break; 4649 4254 4650 case VK_DOWN: 4651 newItem = TREEVIEW_GetNextListItem (hwnd,infoPtr, prevItem); 4652 4653 if (!newItem) 4654 newItem = prevItem; 4655 4656 hNewSelection = newItem->hItem; 4657 4658 break; 4659 4660 case VK_HOME: 4661 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem]; 4662 hNewSelection = newItem->hItem; 4663 4664 break; 4665 4666 case VK_END: 4667 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem]; 4668 newItem = TREEVIEW_GetLastListItem (hwnd,infoPtr, newItem); 4669 hNewSelection = newItem->hItem; 4670 4671 break; 4672 4673 case VK_LEFT: 4674 if ( (prevItem->state & TVIS_EXPANDED) && 4675 TREEVIEW_HasChildren(hwnd, prevItem)) 4255 case VK_BACK: 4256 newSelection = prevItem->parent; 4257 if (newSelection == infoPtr->root) 4258 newSelection = NULL; 4259 break; 4260 4261 case VK_SPACE: 4262 if (infoPtr->dwStyle & TVS_CHECKBOXES) 4263 TREEVIEW_ToggleItemState(infoPtr, prevItem); 4264 break; 4265 } 4266 4267 if (newSelection && newSelection != prevItem) 4268 { 4269 if (TREEVIEW_DoSelectItem(infoPtr,TVGN_CARET,newSelection,TVC_BYKEYBOARD)) 4270 { 4271 TREEVIEW_EnsureVisible(infoPtr, newSelection); 4272 } 4273 } 4274 4275 return FALSE; 4276 } 4277 4278 static LRESULT 4279 TREEVIEW_Size(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 4280 { 4281 if (wParam == SIZE_RESTORED) 4282 { 4283 infoPtr->clientWidth = LOWORD(lParam); 4284 infoPtr->clientHeight = HIWORD(lParam); 4285 if (TREEVIEW_CalcItems(infoPtr)) 4286 TREEVIEW_Refresh(infoPtr); 4287 } 4288 4289 return 0; 4290 } 4291 4292 static LRESULT 4293 TREEVIEW_StyleChanged(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 4294 { 4295 //TRACE("(%x %lx)\n", wParam, lParam); 4296 4297 if (wParam == GWL_STYLE) 4298 infoPtr->dwStyle = ((LPSTYLESTRUCT)lParam)->styleNew; 4299 4300 if (infoPtr->hwndEdit) SetFocus(infoPtr->hwnd); 4301 4302 infoPtr->uInternalStatus |= TV_CALCALL; 4303 TREEVIEW_QueueRefresh(infoPtr); 4304 4305 return 0; 4306 } 4307 4308 static LRESULT 4309 TREEVIEW_SetFocus(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 4310 { 4311 sendNotify(infoPtr->hwnd,NM_SETFOCUS); 4312 4313 if (!(infoPtr->dwStyle & TVS_SHOWSELALWAYS)) 4314 { 4315 if (infoPtr->selectedItem) 4316 TREEVIEW_RefreshItem(infoPtr,infoPtr->selectedItem,TVIF_IMAGE | TVIF_TEXT); 4317 else if (infoPtr->firstVisible) 4318 TREEVIEW_DoSelectItem(infoPtr,TVGN_CARET,infoPtr->firstVisible,TVC_UNKNOWN); 4319 } 4320 4321 return 0; 4322 } 4323 4324 static LRESULT 4325 TREEVIEW_KillFocus(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 4326 { 4327 sendNotify(infoPtr->hwnd,NM_KILLFOCUS); 4328 4329 if (!(infoPtr->dwStyle & TVS_SHOWSELALWAYS) && infoPtr->selectedItem) 4330 TREEVIEW_RefreshItem(infoPtr,infoPtr->selectedItem,TVIF_IMAGE | TVIF_TEXT); 4331 4332 return 0; 4333 } 4334 4335 static LRESULT TREEVIEW_RButtonDoubleClick(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 4336 { 4337 sendNotify(infoPtr->hwnd,NM_RDBLCLK); 4338 4339 return DefWindowProcA(infoPtr->hwnd,WM_RBUTTONDBLCLK,wParam,lParam); 4340 } 4341 4342 4343 HTREEITEM TREEVIEW_GetInfoTipItem(TREEVIEW_INFO *infoPtr,POINT pt) 4344 { 4345 TVHITTESTINFO ht; 4346 4347 ht.pt = pt; 4348 TREEVIEW_HitTest(infoPtr,&ht,FALSE); 4349 4350 if (ht.hItem && (ht.flags & TVHT_ONITEM)) 4351 { 4352 TREEVIEW_ITEM *item = ht.hItem; 4353 4354 if (item->inclient && ((item->textOffset < 0) || (item->textOffset+item->textWidth > infoPtr->clientWidth))) 4355 return ht.hItem; 4356 } 4357 4358 //check tool rect -> no flickering on tip frame 4359 if (infoPtr->tipItem) 4360 { 4361 POINT pt2 = pt; 4362 RECT rect; 4363 4364 GetWindowRect(infoPtr->hwndToolTip,&rect); 4365 ClientToScreen(infoPtr->hwnd,&pt2); 4366 return PtInRect(&rect,pt2) ? infoPtr->tipItem:0; 4367 } 4368 4369 return 0; 4370 } 4371 4372 VOID TREEVIEW_ShowInfoTip(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item) 4373 { 4374 LPWSTR text; 4375 BOOL mustFree = FALSE; 4376 TTTOOLINFOW ti; 4377 POINT pt; 4378 4379 if (infoPtr->dwStyle & TVS_INFOTIP) 4380 { 4381 NMTVGETINFOTIPW tvgit; 4382 WCHAR* buf = (WCHAR*)COMCTL32_Alloc(isUnicodeNotify(&infoPtr->header) ? INFOTIPSIZE*sizeof(WCHAR):INFOTIPSIZE*sizeof(CHAR)); 4383 4384 tvgit.pszText = buf; 4385 tvgit.cchTextMax = INFOTIPSIZE; 4386 tvgit.hItem = item; 4387 tvgit.lParam = item->lParam; 4388 4389 sendNotify(infoPtr->hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_GETINFOTIPW:TVN_GETINFOTIPA,&tvgit.hdr); 4390 if (isUnicodeNotify(&infoPtr->header)) 4391 { 4392 if (buf != tvgit.pszText) COMCTL32_Free(buf); else mustFree = TRUE; 4393 text = tvgit.pszText; 4394 } else 4395 { 4396 text = (WCHAR*)COMCTL32_Alloc(tvgit.cchTextMax*sizeof(WCHAR)); 4397 mustFree = TRUE; 4398 lstrcpyAtoW(text,(LPSTR)tvgit.pszText); 4399 COMCTL32_Free(buf); 4400 } 4401 } else 4402 { 4403 TREEVIEW_UpdateDispInfo(infoPtr,item,TVIF_TEXT); 4404 text = item->pszText; 4405 } 4406 4407 infoPtr->tipItem = item; 4408 SetTimer(infoPtr->hwnd,TV_INFOTIP_TIMER,TV_INFOTIP_DELAY,0); 4409 infoPtr->Timer |= TV_INFOTIP_TIMER_SET; 4410 4411 ti.cbSize = sizeof(ti); 4412 ti.uId = 0; 4413 ti.hwnd = infoPtr->hwnd; 4414 ti.hinst = 0; 4415 ti.lpszText = text; 4416 SendMessageA(infoPtr->hwndToolTip,TTM_TRACKACTIVATE,(WPARAM)FALSE,(LPARAM)&ti); 4417 pt.x = item->textOffset; 4418 pt.y = item->rect.top; 4419 ClientToScreen(infoPtr->hwnd,&pt); 4420 SendMessageA(infoPtr->hwndToolTip,TTM_TRACKPOSITION,0,(LPARAM)MAKELPARAM(pt.x,pt.y)); 4421 SendMessageA(infoPtr->hwndToolTip,TTM_UPDATETIPTEXTW,0,(LPARAM)&ti); 4422 SendMessageA(infoPtr->hwndToolTip,TTM_TRACKACTIVATE,(WPARAM)TRUE,(LPARAM)&ti); 4423 4424 if (mustFree) COMCTL32_Free(text); 4425 } 4426 4427 VOID TREEVIEW_HideInfoTip(TREEVIEW_INFO *infoPtr) 4428 { 4429 if (infoPtr->tipItem) 4430 { 4431 TTTOOLINFOA ti; 4432 4433 infoPtr->tipItem = 0; 4434 KillTimer(infoPtr->hwnd,TV_INFOTIP_TIMER); 4435 infoPtr->Timer &= ~TV_INFOTIP_TIMER_SET; 4436 4437 ti.cbSize = sizeof(TTTOOLINFOA); 4438 ti.uId = 0; 4439 ti.hwnd = (UINT)infoPtr->hwnd; 4440 4441 SendMessageA(infoPtr->hwndToolTip,TTM_TRACKACTIVATE,(WPARAM)FALSE,(LPARAM)&ti); 4442 } 4443 } 4444 4445 static VOID TREEVIEW_CheckInfoTip(TREEVIEW_INFO *infoPtr) 4446 { 4447 HTREEITEM hItem; 4448 POINT pt; 4449 4450 GetCursorPos(&pt); 4451 ScreenToClient(infoPtr->hwnd,&pt); 4452 hItem = TREEVIEW_GetInfoTipItem(infoPtr,pt); 4453 4454 if (hItem != infoPtr->tipItem) 4455 TREEVIEW_HideInfoTip(infoPtr); 4456 } 4457 4458 HTREEITEM TREEVIEW_GetHottrackItem(TREEVIEW_INFO *infoPtr,POINT pt) 4459 { 4460 TVHITTESTINFO ht; 4461 4462 ht.pt = pt; 4463 TREEVIEW_HitTest(infoPtr,&ht,FALSE); 4464 4465 return (ht.hItem && (ht.flags & TVHT_ONITEM)) ? ht.hItem:0; 4466 } 4467 4468 static LRESULT TREEVIEW_MouseMove(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 4469 { 4470 POINT pt; 4471 4472 pt.x = (INT)LOWORD(lParam); 4473 pt.y = (INT)HIWORD(lParam); 4474 4475 if (infoPtr->hwndToolTip) 4476 { 4477 HTREEITEM hItem = TREEVIEW_GetInfoTipItem(infoPtr,pt); 4478 4479 if (infoPtr->tipItem != hItem) 4480 { 4481 if (hItem) 4676 4482 { 4677 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect ); 4678 } else if ((INT)prevItem->parent) 4483 TREEVIEW_ITEM *item = hItem; 4484 4485 TREEVIEW_ShowInfoTip(infoPtr,item); 4486 } else TREEVIEW_HideInfoTip(infoPtr); 4487 } 4488 } 4489 4490 if (infoPtr->dwStyle & TVS_TRACKSELECT) 4491 { 4492 HTREEITEM hItem = TREEVIEW_GetHottrackItem(infoPtr,pt); 4493 4494 if (infoPtr->hotItem != hItem) 4495 { 4496 TREEVIEW_ITEM *item; 4497 HDC hdc = 0; 4498 4499 item = infoPtr->hotItem; 4500 if (TREEVIEW_ValidItem(infoPtr,infoPtr->hotItem)) 4679 4501 { 4680 newItem = (& infoPtr->items[(INT)prevItem->parent]); 4681 4682 hNewSelection = newItem->hItem; //CB: what does Win32??? Please not the Corel hack!!! 4502 if (!hdc) hdc = GetDC(infoPtr->hwnd); 4503 TREEVIEW_DrawHottrackLine(hdc,item); 4683 4504 } 4684 4685 break; 4686 4687 case VK_RIGHT: 4688 if (TREEVIEW_HasChildren(hwnd, prevItem)) 4505 if (hItem) 4689 4506 { 4690 if (!(prevItem->state & TVIS_EXPANDED)) 4691 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect ); 4692 else 4693 { 4694 newItem = (& infoPtr->items[(INT)prevItem->firstChild]); 4695 hNewSelection = newItem->hItem; 4696 } 4507 item = hItem; 4508 if (item) 4509 { 4510 if (!hdc) hdc = GetDC(infoPtr->hwnd); 4511 TREEVIEW_DrawHottrackLine(hdc,item); 4512 } 4697 4513 } 4698 4699 break; 4700 4701 case VK_ADD: 4702 if (!(prevItem->state & TVIS_EXPANDED)) 4703 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect ); 4704 break; 4705 4706 case VK_SUBTRACT: 4707 if (prevItem->state & TVIS_EXPANDED) 4708 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect ); 4709 break; 4710 4711 case VK_PRIOR: 4712 newItem=TREEVIEW_GetListItem( 4713 hwnd, 4714 infoPtr, 4715 prevItem, 4716 -1*(TREEVIEW_GetVisibleCount(hwnd,0,0)-3)); 4717 if (!newItem) 4718 newItem = prevItem; 4719 4720 hNewSelection = newItem->hItem; 4721 4722 break; 4723 4724 case VK_NEXT: 4725 newItem=TREEVIEW_GetListItem( 4726 hwnd, 4727 infoPtr, 4728 prevItem, 4729 TREEVIEW_GetVisibleCount(hwnd,0,0)-3); 4730 4731 if (!newItem) 4732 newItem = prevItem; 4733 4734 hNewSelection = newItem->hItem; 4735 4736 break; 4737 4738 case VK_RETURN: 4739 sendNotify(hwnd,NM_RETURN); 4740 break; 4741 4742 case VK_BACK: 4743 4744 default: 4745 break; 4746 } 4747 4748 if (hNewSelection) 4749 { 4750 if (TREEVIEW_DoSelectItem(hwnd,TVGN_CARET,(HTREEITEM)hNewSelection,TVC_BYKEYBOARD)) 4751 { 4752 TREEVIEW_EnsureVisible(hwnd,hNewSelection); 4753 } 4754 } 4755 4756 return FALSE; 4757 } 4758 4759 static LRESULT TREEVIEW_Char(HWND hwnd,WPARAM wParam,LPARAM lParam) 4514 if (hdc) ReleaseDC(infoPtr->hwnd,hdc); 4515 } 4516 } 4517 4518 return 0; 4519 } 4520 4521 static LRESULT TREEVIEW_SetRedraw(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 4522 { 4523 if (wParam) 4524 { 4525 if (!(infoPtr->uInternalStatus & TV_NOREDRAW)) return 0; 4526 infoPtr->uInternalStatus &= ~TV_NOREDRAW; 4527 TREEVIEW_CalcItems(infoPtr); 4528 TREEVIEW_Refresh(infoPtr); 4529 } else 4530 { 4531 infoPtr->uInternalStatus |= TV_NOREDRAW; 4532 } 4533 4534 return 0; 4535 } 4536 4537 static LRESULT 4538 TREEVIEW_SysColorChange(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 4539 { 4540 TREEVIEW_Refresh(infoPtr); 4541 4542 return DefWindowProcA(infoPtr->hwnd,WM_SYSCOLORCHANGE,wParam,lParam); 4543 } 4544 4545 static LRESULT TREEVIEW_Enable(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 4546 { 4547 TREEVIEW_Refresh(infoPtr); 4548 4549 return DefWindowProcA(infoPtr->hwnd,WM_ENABLE,wParam,lParam); 4550 } 4551 4552 static LRESULT 4553 TREEVIEW_EraseBackground(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 4554 { 4555 HBRUSH hBrush = CreateSolidBrush (infoPtr->clrBk); 4556 RECT rect; 4557 4558 GetClientRect (infoPtr->hwnd, &rect); 4559 FillRect ((HDC)wParam, &rect, hBrush); 4560 DeleteObject (hBrush); 4561 4562 return TRUE; 4563 } 4564 4565 static LRESULT TREEVIEW_GetDlgCode(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 4566 { 4567 return DLGC_WANTARROWS | DLGC_WANTCHARS; 4568 } 4569 4570 4571 static LRESULT TREEVIEW_Char(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 4760 4572 { 4761 4573 CHAR ch = (CHAR)wParam; 4762 4574 4763 TREEVIEW_ISearch( hwnd,ch);4575 TREEVIEW_ISearch(infoPtr,ch); 4764 4576 4765 4577 return 0; 4766 4578 } 4767 4579 4768 static LRESULT 4769 TREEVIEW_GetScrollTime (HWND hwnd) 4770 { 4771 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 4772 4773 return infoPtr->uScrollTime; 4774 } 4775 4776 static LRESULT 4777 TREEVIEW_SetScrollTime (HWND hwnd, UINT uScrollTime) 4778 { 4779 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 4780 UINT uOldScrollTime = infoPtr->uScrollTime; 4781 4782 infoPtr->uScrollTime = min (uScrollTime, 100); 4783 4784 return uOldScrollTime; 4785 } 4786 4787 static LRESULT TREEVIEW_EnsureVisible(HWND hwnd,HTREEITEM hItem) 4788 { 4789 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 4790 TREEVIEW_ITEM *item; 4791 RECT rect; 4792 INT scrollY; 4793 4794 item = TREEVIEW_ValidItem(infoPtr,hItem); 4795 4796 if (!item) return FALSE; 4797 4798 if (item && item->parent) 4799 { 4800 TREEVIEW_ITEM *parent = TREEVIEW_ValidItem(infoPtr,item->parent); 4801 4802 while (parent && !(parent->state & TVIS_EXPANDED)) 4803 { 4804 TREEVIEW_Expand(hwnd,TVE_EXPAND,(LPARAM)parent->hItem); 4805 parent = TREEVIEW_ValidItem(infoPtr,parent->parent); 4806 } 4807 } 4808 4809 TREEVIEW_UnqueueRefresh(hwnd,TRUE,TRUE); 4810 GetClientRect(hwnd,&rect); 4811 if (item->rect.top < 0) 4812 scrollY = item->rect.top; 4813 else if (item->rect.bottom > rect.bottom) 4814 { 4815 INT mod; 4816 4817 scrollY = item->rect.bottom-rect.bottom; 4818 mod = scrollY % infoPtr->uVScrollStep; 4819 if (mod) scrollY += infoPtr->uVScrollStep-mod; 4820 } else return FALSE; 4821 4822 if (scrollY != 0) 4823 { 4824 infoPtr->lefttop.y += scrollY; 4825 TREEVIEW_CalcItems(hwnd,0,infoPtr); 4826 ScrollWindowEx(hwnd,0,-scrollY,NULL,NULL,0,NULL,SW_INVALIDATE | SW_SCROLLCHILDREN | (infoPtr->uScrollTime << 16)); 4827 4828 return TRUE; 4829 } 4830 4831 return FALSE; 4832 } 4833 4834 static BOOL TREEVIEW_Compare(HWND hwnd,TREEVIEW_ITEM *item,LPWSTR text,INT textlen,BOOL *matchLast) 4835 { 4836 WCHAR* itemtext; 4837 BOOL mustFree = FALSE,res; 4580 static BOOL TREEVIEW_Compare(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item,LPWSTR text,INT textlen,BOOL *matchLast) 4581 { 4582 BOOL res; 4838 4583 INT itemlen; 4839 4584 4840 if (item->pszText == LPSTR_TEXTCALLBACKW) 4841 itemtext = TREEVIEW_CallbackText(hwnd,item,&mustFree); 4842 else 4843 itemtext = item->pszText; 4844 4845 itemlen = lstrlenW(itemtext); 4585 TREEVIEW_UpdateDispInfo(infoPtr,item,TVIF_TEXT); 4586 4587 itemlen = lstrlenW(item->pszText); 4846 4588 if (itemlen < textlen) 4847 4589 { … … 4849 4591 } else 4850 4592 { 4851 res = (lstrcmpniW(item text,text,textlen) == 0);4593 res = (lstrcmpniW(item->pszText,text,textlen) == 0); 4852 4594 } 4853 4595 if (!res && matchLast) … … 4855 4597 textlen--; 4856 4598 if ((textlen > 0) && (itemlen >= textlen)) 4857 *matchLast = (lstrcmpniW(item text,text,textlen) == 0);4599 *matchLast = (lstrcmpniW(item->pszText,text,textlen) == 0); 4858 4600 else 4859 4601 *matchLast = FALSE; 4860 4602 } 4861 if (mustFree) COMCTL32_Free(itemtext);4862 4603 4863 4604 return res; 4864 4605 } 4865 4606 4866 static TREEVIEW_ITEM* TREEVIEW_Search( HWND hwnd,TREEVIEW_INFO *infoPtr,INT iItem,LPWSTR text,INT textlen,TREEVIEW_ITEM **nearest)4867 { 4868 TREEVIEW_ITEM * item,*start;4607 static TREEVIEW_ITEM* TREEVIEW_Search(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item,LPWSTR text,INT textlen,TREEVIEW_ITEM **nearest) 4608 { 4609 TREEVIEW_ITEM *start; 4869 4610 BOOL bMatchLast; 4870 4611 4871 item = start = &infoPtr->items[iItem];4612 start = item; 4872 4613 if (nearest) *nearest = NULL; 4873 4614 … … 4877 4618 if (nearest) 4878 4619 { 4879 if (TREEVIEW_Compare( hwnd,item,text,textlen,(!*nearest) ? &bMatchLast:NULL))4620 if (TREEVIEW_Compare(infoPtr,item,text,textlen,(!*nearest) ? &bMatchLast:NULL)) 4880 4621 return item; 4881 4622 else if (!*nearest && bMatchLast) … … 4883 4624 } else 4884 4625 { 4885 if (TREEVIEW_Compare( hwnd,item,text,textlen,NULL))4626 if (TREEVIEW_Compare(infoPtr,item,text,textlen,NULL)) 4886 4627 return item; 4887 4628 } 4888 item = TREEVIEW_GetNextListItem(hwnd,infoPtr,item); 4889 } 4890 4891 iItem = (INT)infoPtr->TopRootItem; 4892 item = &infoPtr->items[iItem]; 4629 item = TREEVIEW_GetNextListItem(infoPtr,item); 4630 } 4631 4632 item = infoPtr->root; 4893 4633 4894 4634 //search first to start … … 4897 4637 if (nearest) 4898 4638 { 4899 if (TREEVIEW_Compare( hwnd,item,text,textlen,(!*nearest) ? &bMatchLast:NULL))4639 if (TREEVIEW_Compare(infoPtr,item,text,textlen,(!*nearest) ? &bMatchLast:NULL)) 4900 4640 return item; 4901 4641 else if (!*nearest && bMatchLast) … … 4903 4643 } else 4904 4644 { 4905 if (TREEVIEW_Compare( hwnd,item,text,textlen,NULL))4645 if (TREEVIEW_Compare(infoPtr,item,text,textlen,NULL)) 4906 4646 return item; 4907 4647 } 4908 item = TREEVIEW_GetNextListItem( hwnd,infoPtr,item);4648 item = TREEVIEW_GetNextListItem(infoPtr,item); 4909 4649 } 4910 4650 … … 4914 4654 //NOTE: sister function in listview control -> sync changes 4915 4655 4916 static VOID TREEVIEW_ISearch(HWND hwnd,CHAR ch) 4917 { 4918 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 4656 static VOID TREEVIEW_ISearch(TREEVIEW_INFO *infoPtr,CHAR ch) 4657 { 4919 4658 LPWSTR newString; 4920 INT len ,iItem;4659 INT len; 4921 4660 CHAR ch2[2]; 4922 4661 TREEVIEW_ITEM *item,*nearest = NULL; … … 4956 4695 if (infoPtr->selectedItem) 4957 4696 { 4958 iItem = (INT)infoPtr->selectedItem; 4959 item = &infoPtr->items[iItem]; 4697 item = infoPtr->selectedItem; 4960 4698 4961 4699 //check if new string is valid for old selection 4962 if (TREEVIEW_Compare( hwnd,item,newString,len,NULL))4700 if (TREEVIEW_Compare(infoPtr,item,newString,len,NULL)) 4963 4701 goto ISearchDone; 4964 4702 4965 4703 //no match, continue with next item 4966 item = TREEVIEW_GetNextListItem(hwnd,infoPtr,item); 4967 if (!item) item = &infoPtr->items[(INT)infoPtr->TopRootItem]; 4968 iItem = (INT)item->hItem; 4969 } else iItem = (INT)infoPtr->TopRootItem; 4704 item = TREEVIEW_GetNextListItem(infoPtr,item); 4705 if (!item) item = infoPtr->root; 4706 } else item = infoPtr->root; 4970 4707 4971 4708 //scan 4972 item = TREEVIEW_Search( hwnd,infoPtr,iItem,newString,len,checkNearest ? &nearest:NULL);4709 item = TREEVIEW_Search(infoPtr,item,newString,len,checkNearest ? &nearest:NULL); 4973 4710 4974 4711 if (!item && nearest) 4975 4712 { 4976 TREEVIEW_SelectItem( hwnd,(WPARAM)TVGN_CARET,(LPARAM)nearest->hItem);4977 TREEVIEW_EnsureVisible( hwnd,nearest->hItem);4713 TREEVIEW_SelectItem(infoPtr,(WPARAM)TVGN_CARET,(LPARAM)nearest); 4714 TREEVIEW_EnsureVisible(infoPtr,nearest); 4978 4715 infoPtr->dwISearchTime = GetTickCount(); 4979 4716 … … 4989 4726 infoPtr->pszISearch = newString; 4990 4727 infoPtr->uISearchLen = len; 4991 TREEVIEW_SelectItem( hwnd,(WPARAM)TVGN_CARET,(LPARAM)item->hItem);4992 TREEVIEW_EnsureVisible( hwnd,item->hItem);4728 TREEVIEW_SelectItem(infoPtr,(WPARAM)TVGN_CARET,(LPARAM)item); 4729 TREEVIEW_EnsureVisible(infoPtr,item); 4993 4730 infoPtr->dwISearchTime = GetTickCount(); 4994 4731 } else … … 4999 4736 } 5000 4737 5001 static LRESULT TREEVIEW_GetISearchString(HWND hwnd,LPWSTR lpsz,BOOL unicode) 5002 { 5003 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 5004 4738 static LRESULT TREEVIEW_GetISearchString(TREEVIEW_INFO *infoPtr,LPWSTR lpsz,BOOL unicode) 4739 { 5005 4740 if (infoPtr->uISearchLen == 0) return 0; 5006 4741 … … 5013 4748 } 5014 4749 5015 static LRESULT TREEVIEW_SetCursor(HWND hwnd,WPARAM wParam,LPARAM lParam) 5016 { 5017 sendNotify(hwnd,NM_SETCURSOR); //CB: todo: result 5018 5019 return DefWindowProcA(hwnd,WM_SETCURSOR,wParam,lParam); 4750 static LRESULT TREEVIEW_SetCursor(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 4751 { 4752 sendNotify(infoPtr->hwnd,NM_SETCURSOR); //CB: todo: result 4753 4754 return DefWindowProcA(infoPtr->hwnd,WM_SETCURSOR,wParam,lParam); 4755 } 4756 4757 static LRESULT TREEVIEW_NCCreate(HWND hwnd,WPARAM wParam,LPARAM lParam) 4758 { 4759 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE),oldStyle = dwStyle; 4760 4761 dwStyle &= ~(WS_HSCROLL | WS_VSCROLL); 4762 if (dwStyle != oldStyle) SetWindowLongA(hwnd,GWL_STYLE,dwStyle); 4763 4764 return DefWindowProcA(hwnd,WM_NCCREATE,wParam,lParam); 5020 4765 } 5021 4766 … … 5023 4768 TREEVIEW_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 5024 4769 { 5025 if (uMsg == WM_CREATE) 5026 return TREEVIEW_Create (hwnd, wParam, lParam); 5027 5028 if (!TREEVIEW_GetInfoPtr(hwnd)) 5029 return DefWindowProcA (hwnd, uMsg, wParam, lParam); 4770 TREEVIEW_INFO *infoPtr; 4771 4772 if (uMsg == WM_NCCREATE) 4773 { 4774 return TREEVIEW_NCCreate(hwnd,wParam,lParam); 4775 } else if (uMsg == WM_CREATE) 4776 { 4777 return TREEVIEW_Create(hwnd, wParam, lParam); 4778 } 4779 4780 infoPtr = TREEVIEW_GetInfoPtr(hwnd); 4781 if (infoPtr) TREEVIEW_VerifyTree(infoPtr); else goto def; 5030 4782 5031 4783 switch (uMsg) 5032 4784 { 5033 4785 case TVM_INSERTITEMA: 5034 return TREEVIEW_InsertItem( hwnd,wParam,lParam,FALSE);4786 return TREEVIEW_InsertItem(infoPtr,wParam,lParam,FALSE); 5035 4787 5036 4788 case TVM_INSERTITEMW: 5037 return TREEVIEW_InsertItem( hwnd,wParam,lParam,TRUE);4789 return TREEVIEW_InsertItem(infoPtr,wParam,lParam,TRUE); 5038 4790 5039 4791 case TVM_DELETEITEM: 5040 return TREEVIEW_DeleteItem (hwnd, wParam,lParam);4792 return TREEVIEW_DeleteItem(infoPtr,wParam,lParam); 5041 4793 5042 4794 case TVM_EXPAND: 5043 return TREEVIEW_Expand (hwnd, wParam,lParam);4795 return TREEVIEW_ExpandMsg(infoPtr,wParam,lParam); 5044 4796 5045 4797 case TVM_GETITEMRECT: 5046 return TREEVIEW_GetItemRect (hwnd, wParam,lParam);4798 return TREEVIEW_GetItemRect(infoPtr,wParam,lParam); 5047 4799 5048 4800 case TVM_GETCOUNT: 5049 return TREEVIEW_GetCount (hwnd, wParam,lParam);4801 return TREEVIEW_GetCount(infoPtr,wParam,lParam); 5050 4802 5051 4803 case TVM_GETINDENT: 5052 return TREEVIEW_GetIndent (hwnd);4804 return TREEVIEW_GetIndent(infoPtr); 5053 4805 5054 4806 case TVM_SETINDENT: 5055 return TREEVIEW_SetIndent (hwnd,wParam);4807 return TREEVIEW_SetIndent(infoPtr,wParam); 5056 4808 5057 4809 case TVM_GETIMAGELIST: 5058 return TREEVIEW_GetImageList (hwnd, wParam,lParam);4810 return TREEVIEW_GetImageList(infoPtr,wParam,lParam); 5059 4811 5060 4812 case TVM_SETIMAGELIST: 5061 return TREEVIEW_SetImageList ( hwnd, wParam, lParam);4813 return TREEVIEW_SetImageList (infoPtr, wParam, lParam); 5062 4814 5063 4815 case TVM_GETNEXTITEM: 5064 return TREEVIEW_GetNextItem ( hwnd, wParam, lParam);4816 return TREEVIEW_GetNextItem (infoPtr, wParam, lParam); 5065 4817 5066 4818 case TVM_SELECTITEM: 5067 return TREEVIEW_SelectItem ( hwnd, wParam, lParam);4819 return TREEVIEW_SelectItem (infoPtr, wParam, lParam); 5068 4820 5069 4821 case TVM_GETITEMA: 5070 return TREEVIEW_GetItem( hwnd,wParam,lParam,FALSE);4822 return TREEVIEW_GetItem(infoPtr,wParam,lParam,FALSE); 5071 4823 5072 4824 case TVM_GETITEMW: 5073 return TREEVIEW_GetItem( hwnd,wParam,lParam,TRUE);4825 return TREEVIEW_GetItem(infoPtr,wParam,lParam,TRUE); 5074 4826 5075 4827 case TVM_SETITEMA: 5076 return TREEVIEW_SetItem( hwnd,wParam,lParam,FALSE);4828 return TREEVIEW_SetItem(infoPtr,wParam,lParam,FALSE); 5077 4829 5078 4830 case TVM_SETITEMW: 5079 return TREEVIEW_SetItem( hwnd,wParam,lParam,TRUE);4831 return TREEVIEW_SetItem(infoPtr,wParam,lParam,TRUE); 5080 4832 5081 4833 case TVM_EDITLABELA: 5082 return TREEVIEW_EditLabel( hwnd,(HTREEITEM)lParam,FALSE);4834 return TREEVIEW_EditLabel(infoPtr,(HTREEITEM)lParam,FALSE); 5083 4835 5084 4836 case TVM_EDITLABELW: 5085 return TREEVIEW_EditLabel( hwnd,(HTREEITEM)lParam,TRUE);4837 return TREEVIEW_EditLabel(infoPtr,(HTREEITEM)lParam,TRUE); 5086 4838 5087 4839 case TVM_GETEDITCONTROL: 5088 return TREEVIEW_GetEditControl ( hwnd);4840 return TREEVIEW_GetEditControl (infoPtr); 5089 4841 5090 4842 case TVM_GETVISIBLECOUNT: 5091 return TREEVIEW_GetVisibleCount ( hwnd, wParam, lParam);4843 return TREEVIEW_GetVisibleCount (infoPtr); 5092 4844 5093 4845 case TVM_HITTEST: 5094 return TREEVIEW_HitTest( hwnd,(LPTVHITTESTINFO)lParam,FALSE);4846 return TREEVIEW_HitTest(infoPtr,(LPTVHITTESTINFO)lParam,FALSE); 5095 4847 5096 4848 case TVM_CREATEDRAGIMAGE: 5097 return TREEVIEW_CreateDragImage ( hwnd, wParam, lParam);4849 return TREEVIEW_CreateDragImage (infoPtr, wParam, lParam); 5098 4850 5099 4851 case TVM_SORTCHILDREN: 5100 return TREEVIEW_SortChildren( hwnd, wParam, lParam);4852 return TREEVIEW_SortChildren(infoPtr, wParam, lParam); 5101 4853 5102 4854 case TVM_ENSUREVISIBLE: 5103 return TREEVIEW_EnsureVisible( hwnd,(HTREEITEM)lParam);4855 return TREEVIEW_EnsureVisible(infoPtr,(HTREEITEM)lParam); 5104 4856 5105 4857 case TVM_SORTCHILDRENCB: 5106 return TREEVIEW_SortChildrenCB( hwnd, wParam, lParam);4858 return TREEVIEW_SortChildrenCB(infoPtr, wParam, lParam); 5107 4859 5108 4860 case TVM_ENDEDITLABELNOW: 5109 return TREEVIEW_EndEditLabelNow ( hwnd,(BOOL)wParam);4861 return TREEVIEW_EndEditLabelNow (infoPtr,(BOOL)wParam); 5110 4862 5111 4863 case TVM_GETISEARCHSTRINGA: 5112 return TREEVIEW_GetISearchString( hwnd,(LPWSTR)lParam,FALSE);4864 return TREEVIEW_GetISearchString(infoPtr,(LPWSTR)lParam,FALSE); 5113 4865 5114 4866 case TVM_GETISEARCHSTRINGW: 5115 return TREEVIEW_GetISearchString( hwnd,(LPWSTR)lParam,TRUE);4867 return TREEVIEW_GetISearchString(infoPtr,(LPWSTR)lParam,TRUE); 5116 4868 5117 4869 case TVM_GETTOOLTIPS: 5118 return TREEVIEW_GetToolTips ( hwnd);4870 return TREEVIEW_GetToolTips (infoPtr); 5119 4871 5120 4872 case TVM_SETTOOLTIPS: 5121 return TREEVIEW_SetToolTips ( hwnd, wParam);4873 return TREEVIEW_SetToolTips (infoPtr, wParam); 5122 4874 5123 4875 case TVM_SETINSERTMARK: 5124 return TREEVIEW_SetInsertMark ( hwnd,wParam, lParam);4876 return TREEVIEW_SetInsertMark (infoPtr,wParam, lParam); 5125 4877 5126 4878 case TVM_SETITEMHEIGHT: 5127 return TREEVIEW_SetItemHeight ( hwnd, wParam);4879 return TREEVIEW_SetItemHeight (infoPtr, wParam); 5128 4880 5129 4881 case TVM_GETITEMHEIGHT: 5130 return TREEVIEW_GetItemHeight ( hwnd);4882 return TREEVIEW_GetItemHeight (infoPtr); 5131 4883 5132 4884 case TVM_SETBKCOLOR: 5133 return TREEVIEW_SetBkColor ( hwnd, wParam, lParam);4885 return TREEVIEW_SetBkColor (infoPtr, wParam, lParam); 5134 4886 5135 4887 case TVM_SETTEXTCOLOR: 5136 return TREEVIEW_SetTextColor ( hwnd, wParam, lParam);4888 return TREEVIEW_SetTextColor (infoPtr, wParam, lParam); 5137 4889 5138 4890 case TVM_GETBKCOLOR: 5139 return TREEVIEW_GetBkColor ( hwnd);4891 return TREEVIEW_GetBkColor (infoPtr); 5140 4892 5141 4893 case TVM_GETTEXTCOLOR: 5142 return TREEVIEW_GetTextColor ( hwnd);4894 return TREEVIEW_GetTextColor (infoPtr); 5143 4895 5144 4896 case TVM_SETSCROLLTIME: 5145 return TREEVIEW_SetScrollTime ( hwnd, (UINT)wParam);4897 return TREEVIEW_SetScrollTime (infoPtr, (UINT)wParam); 5146 4898 5147 4899 case TVM_GETSCROLLTIME: 5148 return TREEVIEW_GetScrollTime ( hwnd);4900 return TREEVIEW_GetScrollTime (infoPtr); 5149 4901 5150 4902 case TVM_GETITEMSTATE: 5151 return TREEVIEW_GetItemState ( hwnd,wParam, lParam);4903 return TREEVIEW_GetItemState (infoPtr,wParam, lParam); 5152 4904 5153 4905 case TVM_GETLINECOLOR: 5154 return TREEVIEW_GetLineColor ( hwnd,wParam, lParam);4906 return TREEVIEW_GetLineColor (infoPtr,wParam, lParam); 5155 4907 5156 4908 case TVM_SETLINECOLOR: 5157 return TREEVIEW_SetLineColor ( hwnd,wParam, lParam);4909 return TREEVIEW_SetLineColor (infoPtr,wParam, lParam); 5158 4910 5159 4911 case TVM_SETINSERTMARKCOLOR: 5160 return TREEVIEW_SetInsertMarkColor ( hwnd,wParam, lParam);4912 return TREEVIEW_SetInsertMarkColor (infoPtr,wParam, lParam); 5161 4913 5162 4914 case TVM_GETINSERTMARKCOLOR: 5163 return TREEVIEW_GetInsertMarkColor ( hwnd,wParam, lParam);4915 return TREEVIEW_GetInsertMarkColor (infoPtr,wParam, lParam); 5164 4916 5165 4917 case WM_COMMAND: 5166 return TREEVIEW_Command ( hwnd, wParam, lParam);4918 return TREEVIEW_Command (infoPtr, wParam, lParam); 5167 4919 5168 4920 case WM_DESTROY: 5169 return TREEVIEW_Destroy ( hwnd);4921 return TREEVIEW_Destroy (infoPtr); 5170 4922 5171 4923 case WM_ENABLE: 5172 return TREEVIEW_Enable( hwnd,wParam,lParam);4924 return TREEVIEW_Enable(infoPtr,wParam,lParam); 5173 4925 5174 4926 case WM_ERASEBKGND: 5175 return TREEVIEW_EraseBackground ( hwnd, wParam, lParam);4927 return TREEVIEW_EraseBackground (infoPtr, wParam, lParam); 5176 4928 5177 4929 case WM_GETDLGCODE: 5178 return TREEVIEW_GetDlgCode( hwnd,wParam,lParam);4930 return TREEVIEW_GetDlgCode(infoPtr,wParam,lParam); 5179 4931 5180 4932 case WM_PAINT: 5181 return TREEVIEW_Paint ( hwnd, wParam, lParam);4933 return TREEVIEW_Paint (infoPtr, wParam, lParam); 5182 4934 5183 4935 case WM_GETFONT: 5184 return TREEVIEW_GetFont ( hwnd, wParam, lParam);4936 return TREEVIEW_GetFont (infoPtr, wParam, lParam); 5185 4937 5186 4938 case WM_SETFONT: 5187 return TREEVIEW_SetFont ( hwnd, wParam, lParam);4939 return TREEVIEW_SetFont (infoPtr, wParam, lParam); 5188 4940 5189 4941 case WM_KEYDOWN: 5190 return TREEVIEW_KeyDown ( hwnd, wParam, lParam);4942 return TREEVIEW_KeyDown (infoPtr, wParam, lParam); 5191 4943 5192 4944 case WM_CHAR: 5193 return TREEVIEW_Char( hwnd,wParam,lParam);4945 return TREEVIEW_Char(infoPtr,wParam,lParam); 5194 4946 5195 4947 case WM_SETFOCUS: 5196 return TREEVIEW_SetFocus ( hwnd, wParam, lParam);4948 return TREEVIEW_SetFocus (infoPtr, wParam, lParam); 5197 4949 5198 4950 case WM_KILLFOCUS: 5199 return TREEVIEW_KillFocus ( hwnd, wParam, lParam);4951 return TREEVIEW_KillFocus (infoPtr, wParam, lParam); 5200 4952 5201 4953 case WM_MOUSEMOVE: 5202 return TREEVIEW_MouseMove( hwnd,wParam,lParam);4954 return TREEVIEW_MouseMove(infoPtr,wParam,lParam); 5203 4955 5204 4956 case WM_LBUTTONDOWN: 5205 return TREEVIEW_LButtonDown ( hwnd, wParam, lParam);4957 return TREEVIEW_LButtonDown (infoPtr, wParam, lParam); 5206 4958 5207 4959 case WM_LBUTTONDBLCLK: 5208 return TREEVIEW_LButtonDoubleClick ( hwnd, wParam, lParam);4960 return TREEVIEW_LButtonDoubleClick (infoPtr, wParam, lParam); 5209 4961 5210 4962 case WM_RBUTTONDOWN: 5211 return TREEVIEW_RButtonDown ( hwnd, wParam, lParam);4963 return TREEVIEW_RButtonDown (infoPtr, wParam, lParam); 5212 4964 5213 4965 case WM_RBUTTONDBLCLK: 5214 return TREEVIEW_RButtonDoubleClick( hwnd,wParam,lParam);4966 return TREEVIEW_RButtonDoubleClick(infoPtr,wParam,lParam); 5215 4967 5216 4968 case WM_STYLECHANGED: 5217 return TREEVIEW_StyleChanged ( hwnd, wParam, lParam);4969 return TREEVIEW_StyleChanged (infoPtr, wParam, lParam); 5218 4970 5219 4971 case WM_SYSCOLORCHANGE: 5220 return TREEVIEW_SysColorChange( hwnd,wParam,lParam);4972 return TREEVIEW_SysColorChange(infoPtr,wParam,lParam); 5221 4973 5222 4974 case WM_SETCURSOR: 5223 return TREEVIEW_SetCursor( hwnd,wParam,lParam);4975 return TREEVIEW_SetCursor(infoPtr,wParam,lParam); 5224 4976 5225 4977 case WM_SETREDRAW: 5226 return TREEVIEW_SetRedraw( hwnd,wParam,lParam);4978 return TREEVIEW_SetRedraw(infoPtr,wParam,lParam); 5227 4979 5228 4980 case WM_TIMER: 5229 return TREEVIEW_HandleTimer ( hwnd, wParam, lParam);4981 return TREEVIEW_HandleTimer (infoPtr, wParam, lParam); 5230 4982 5231 4983 case WM_SIZE: 5232 return TREEVIEW_Size ( hwnd, wParam,lParam);4984 return TREEVIEW_Size (infoPtr, wParam,lParam); 5233 4985 5234 4986 case WM_HSCROLL: 5235 return TREEVIEW_HScroll ( hwnd, wParam, lParam);4987 return TREEVIEW_HScroll (infoPtr, wParam, lParam); 5236 4988 5237 4989 case WM_VSCROLL: 5238 return TREEVIEW_VScroll ( hwnd, wParam, lParam);4990 return TREEVIEW_VScroll (infoPtr, wParam, lParam); 5239 4991 5240 4992 case WM_MOUSEWHEEL: 5241 return TREEVIEW_MouseWheel ( hwnd, wParam, lParam);4993 return TREEVIEW_MouseWheel (infoPtr, wParam, lParam); 5242 4994 5243 4995 case WM_DRAWITEM: … … 5246 4998 5247 4999 default: 5000 def: 5248 5001 return defComCtl32ProcA(hwnd,uMsg,wParam,lParam); 5249 5002 } … … 5251 5004 } 5252 5005 5006 /* Tree Verification ****************************************************/ 5007 5008 #ifndef NDEBUG 5009 static inline void 5010 TREEVIEW_VerifyChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item); 5011 5012 static inline void TREEVIEW_VerifyItemCommon(TREEVIEW_INFO *infoPtr, 5013 TREEVIEW_ITEM *item) 5014 { 5015 TREEVIEW_WriteVerify("TV: checking infoPtr"); 5016 assert(infoPtr != NULL); 5017 TREEVIEW_WriteVerify("TV: checking item"); 5018 assert(item != NULL); 5019 5020 /* both NULL, or both non-null */ 5021 TREEVIEW_WriteVerify("TV: checking firstChild,lastChild"); 5022 assert((item->firstChild == NULL) == (item->lastChild == NULL)); 5023 5024 TREEVIEW_WriteVerify("TV: checking firstChild,lastChild != item"); 5025 assert(item->firstChild != item); 5026 assert(item->lastChild != item); 5027 5028 TREEVIEW_WriteVerify("TV: checking firstChild"); 5029 if (item->firstChild) 5030 { 5031 assert(item->firstChild->parent == item); 5032 assert(item->firstChild->prevSibling == NULL); 5033 } 5034 5035 TREEVIEW_WriteVerify("TV: checking lastChild"); 5036 if (item->lastChild) 5037 { 5038 TREEVIEW_WriteVerify("TV: checking lastChild->parent"); 5039 assert(item->lastChild->parent == item); 5040 TREEVIEW_WriteVerify("TV: checking lastChild->nextSibling"); 5041 assert(item->lastChild->nextSibling == NULL); 5042 } 5043 5044 TREEVIEW_WriteVerify("TV: checking nextSibling"); 5045 assert(item->nextSibling != item); 5046 if (item->nextSibling) 5047 { 5048 assert(item->nextSibling->parent == item->parent); 5049 assert(item->nextSibling->prevSibling == item); 5050 } 5051 5052 TREEVIEW_WriteVerify("TV: checking prevSibling"); 5053 assert(item->prevSibling != item); 5054 if (item->prevSibling) 5055 { 5056 assert(item->prevSibling->parent == item->parent); 5057 assert(item->prevSibling->nextSibling == item); 5058 } 5059 } 5060 5061 static inline void 5062 TREEVIEW_VerifyItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) 5063 { 5064 TREEVIEW_WriteVerify("TV: checking item"); 5065 assert(item != NULL); 5066 5067 TREEVIEW_WriteVerify("TV: checking parent, iLevel"); 5068 assert(item->parent != NULL); 5069 assert(item->parent != item); 5070 assert(item->iLevel == item->parent->iLevel + 1); 5071 5072 TREEVIEW_WriteVerify("TV: checking PtrIndex"); 5073 assert(DPA_GetPtrIndex(infoPtr->items, item) != -1); 5074 5075 TREEVIEW_VerifyItemCommon(infoPtr, item); 5076 5077 TREEVIEW_VerifyChildren(infoPtr, item); 5078 } 5079 5080 static inline void 5081 TREEVIEW_VerifyChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) 5082 { 5083 TREEVIEW_ITEM *child; 5084 assert(item != NULL); 5085 5086 for (child = item->firstChild; child != NULL; child = child->nextSibling) 5087 TREEVIEW_VerifyItem(infoPtr, child); 5088 } 5089 5090 static inline void 5091 TREEVIEW_VerifyRoot(TREEVIEW_INFO *infoPtr) 5092 { 5093 TREEVIEW_ITEM *root = infoPtr->root; 5094 5095 TREEVIEW_WriteVerify("TV: checking root"); 5096 assert(root != NULL); 5097 TREEVIEW_WriteVerify("TV: checking iLevel"); 5098 assert(root->iLevel == -1); 5099 TREEVIEW_WriteVerify("TV: checking parent"); 5100 assert(root->parent == NULL); 5101 TREEVIEW_WriteVerify("TV: checking prevSibling"); 5102 assert(root->prevSibling == NULL); 5103 5104 TREEVIEW_VerifyItemCommon(infoPtr, root); 5105 5106 TREEVIEW_VerifyChildren(infoPtr, root); 5107 } 5108 5109 static void 5110 TREEVIEW_VerifyTree(TREEVIEW_INFO *infoPtr) 5111 { 5112 TREEVIEW_WriteVerify("TV: checking infoPtr"); 5113 assert(infoPtr != NULL); 5114 5115 TREEVIEW_VerifyRoot(infoPtr); 5116 } 5117 #endif 5118 5119 /* Class Registration ***************************************************/ 5253 5120 5254 5121 VOID TREEVIEW_Register (VOID)
Note:
See TracChangeset
for help on using the changeset viewer.