Index: dll/win32/comctl32/treeview.c =================================================================== --- dll/win32/comctl32/treeview.c (revision 50872) +++ dll/win32/comctl32/treeview.c (working copy) @@ -33,7 +33,8 @@ * * missing styles: TVS_FULLROWSELECT, TVS_INFOTIP, TVS_RTLREADING, * - * missing item styles: TVIS_CUT, TVIS_EXPANDPARTIAL + * missing item styles: TVIS_CUT, TVIS_EXPANDPARTIAL, TVIS_EX_FLAT, + * TVIS_EX_DISABLED * * Make the insertion mark look right. * Scroll (instead of repaint) as much as possible. @@ -69,6 +70,10 @@ typedef struct _TREEITEM /* HTREEITEM is a _TREEINFO *. */ { + HTREEITEM parent; /* handle to parent or 0 if at root */ + HTREEITEM nextSibling; /* handle to next item in list, 0 if last */ + HTREEITEM firstChild; /* handle to first child or 0 if no child */ + UINT callbackMask; UINT state; UINT stateMask; @@ -81,11 +86,8 @@ LPARAM lParam; int iIntegral; /* item height multiplier (1 is normal) */ int iLevel; /* indentation level:0=root level */ - HTREEITEM parent; /* handle to parent or 0 if at root */ - HTREEITEM firstChild; /* handle to first child or 0 if no child */ HTREEITEM lastChild; HTREEITEM prevSibling; /* handle to prev item in list, 0 if first */ - HTREEITEM nextSibling; /* handle to next item in list, 0 if last */ RECT rect; LONG linesOffset; LONG stateOffset; @@ -488,10 +490,10 @@ } static inline BOOL -TREEVIEW_SendRealNotify(const TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +TREEVIEW_SendRealNotify(const TREEVIEW_INFO *infoPtr, WPARAM wParam, LPNMHDR pnmh) { - TRACE("wParam=%ld, lParam=%ld\n", wParam, lParam); - return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, wParam, lParam); + TRACE("wParam=%ld, lParam=%p\n", wParam, pnmh); + return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, wParam, (LPARAM)pnmh); } static BOOL @@ -505,7 +507,7 @@ nmhdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID); nmhdr.code = get_notifycode(infoPtr, code); - return TREEVIEW_SendRealNotify(infoPtr, nmhdr.idFrom, (LPARAM)&nmhdr); + return TREEVIEW_SendRealNotify(infoPtr, nmhdr.idFrom, &nmhdr); } static VOID @@ -568,7 +570,7 @@ nmhdr.ptDrag.x = 0; nmhdr.ptDrag.y = 0; - ret = TREEVIEW_SendRealNotify(infoPtr, nmhdr.hdr.idFrom, (LPARAM)&nmhdr); + ret = TREEVIEW_SendRealNotify(infoPtr, nmhdr.hdr.idFrom, &nmhdr.hdr); if (!infoPtr->bNtfUnicode) { Free(nmhdr.itemOld.pszText); @@ -598,7 +600,7 @@ nmhdr.ptDrag.x = pt.x; nmhdr.ptDrag.y = pt.y; - return TREEVIEW_SendRealNotify(infoPtr, nmhdr.hdr.idFrom, (LPARAM)&nmhdr); + return TREEVIEW_SendRealNotify(infoPtr, nmhdr.hdr.idFrom, &nmhdr.hdr); } @@ -626,7 +628,7 @@ nmcdhdr.clrTextBk = infoPtr->clrBk; nmcdhdr.iLevel = 0; - return TREEVIEW_SendRealNotify(infoPtr, nmcd->hdr.idFrom, (LPARAM)&nmcdhdr); + return TREEVIEW_SendRealNotify(infoPtr, nmcd->hdr.idFrom, &nmcdhdr.nmcd.hdr); } @@ -670,7 +672,7 @@ nmcd->dwDrawStage, nmcd->hdc, nmcd->dwItemSpec, nmcd->uItemState, nmcd->lItemlParam); - return TREEVIEW_SendRealNotify(infoPtr, nmcd->hdr.idFrom, (LPARAM)nmcdhdr); + return TREEVIEW_SendRealNotify(infoPtr, nmcd->hdr.idFrom, &nmcdhdr->nmcd.hdr); } static BOOL @@ -687,7 +689,7 @@ TREEVIEW_TVItemFromItem(infoPtr, TVIF_HANDLE | TVIF_STATE | TVIF_PARAM | TVIF_TEXT, &tvdi.item, editItem); - ret = TREEVIEW_SendRealNotify(infoPtr, tvdi.hdr.idFrom, (LPARAM)&tvdi); + ret = TREEVIEW_SendRealNotify(infoPtr, tvdi.hdr.idFrom, &tvdi.hdr); if (!infoPtr->bNtfUnicode) Free(tvdi.item.pszText); @@ -725,7 +727,8 @@ if (mask & TVIF_TEXT) wineItem->textWidth = 0; - TREEVIEW_SendRealNotify(infoPtr, callback.hdr.idFrom, (LPARAM)&callback); + TREEVIEW_SendRealNotify(infoPtr, callback.hdr.idFrom, &callback.hdr); + TRACE("resulting code 0x%08x\n", callback.hdr.code); /* It may have changed due to a call to SetItem. */ mask &= wineItem->callbackMask; @@ -733,7 +736,7 @@ if ((mask & TVIF_TEXT) && callback.item.pszText != wineItem->pszText) { /* Instead of copying text into our buffer user specified its own */ - if (!infoPtr->bNtfUnicode) { + if (!infoPtr->bNtfUnicode && (callback.hdr.code == TVN_GETDISPINFOA)) { LPWSTR newText; int buflen; int len = MultiByteToWideChar( CP_ACP, 0, @@ -774,7 +777,7 @@ } else if (mask & TVIF_TEXT) { /* User put text into our buffer, that is ok unless A string */ - if (!infoPtr->bNtfUnicode) { + if (!infoPtr->bNtfUnicode && (callback.hdr.code == TVN_GETDISPINFOA)) { LPWSTR newText; LPWSTR oldText = NULL; int buflen; @@ -1005,7 +1008,7 @@ * inc/dec to toggle the images. */ newItem->iImage = 0; newItem->iSelectedImage = 0; - newItem->iExpandedImage = 0; + newItem->iExpandedImage = (WORD)I_IMAGENONE; if (DPA_InsertPtr(infoPtr->items, INT_MAX, newItem) == -1) { @@ -1478,12 +1481,12 @@ { TRACE("%p, (%s)\n", wineItem, TREEVIEW_ItemName(wineItem)); + if (wineItem->firstChild) + TREEVIEW_RemoveAllChildren(infoPtr, wineItem); + TREEVIEW_SendTreeviewNotify(infoPtr, TVN_DELETEITEMW, TVC_UNKNOWN, TVIF_HANDLE | TVIF_PARAM, wineItem, 0); - if (wineItem->firstChild) - TREEVIEW_RemoveAllChildren(infoPtr, wineItem); - TREEVIEW_UnlinkItem(wineItem); infoPtr->uNumItems--; @@ -1512,7 +1515,7 @@ TREEVIEW_ITEM *parent, *prev = NULL; BOOL visible = FALSE; - if (wineItem == TVI_ROOT) + if (wineItem == TVI_ROOT || !wineItem) { TRACE("TVI_ROOT\n"); parent = infoPtr->root; @@ -1827,7 +1830,7 @@ { INT prevHeight = infoPtr->uItemHeight; - TRACE("%d\n", newHeight); + TRACE("new=%d, old=%d\n", newHeight, prevHeight); if (newHeight == -1) { infoPtr->uItemHeight = TREEVIEW_NaturalHeight(infoPtr); @@ -1835,13 +1838,17 @@ } else { - infoPtr->uItemHeight = newHeight; - infoPtr->bHeightSet = TRUE; + if (newHeight == 0) newHeight = 1; + infoPtr->uItemHeight = newHeight; + infoPtr->bHeightSet = TRUE; } /* Round down, unless we support odd ("non even") heights. */ - if (!(infoPtr->dwStyle & TVS_NONEVENHEIGHT)) - infoPtr->uItemHeight &= ~1; + if (!(infoPtr->dwStyle & TVS_NONEVENHEIGHT) && infoPtr->uItemHeight != 1) + { + infoPtr->uItemHeight &= ~1; + TRACE("after rounding=%d\n", infoPtr->uItemHeight); + } if (infoPtr->uItemHeight != prevHeight) { @@ -2061,6 +2068,7 @@ TREEVIEW_GetVisibleCount(const TREEVIEW_INFO *infoPtr) { /* Surprise! This does not take integral height into account. */ + TRACE("client=%d, item=%d\n", infoPtr->clientHeight, infoPtr->uItemHeight); return infoPtr->clientHeight / infoPtr->uItemHeight; } @@ -2142,6 +2150,13 @@ } } } + + if (tvItem->mask & TVIF_STATEEX) + { + FIXME("Extended item state not supported, returning 0.\n"); + tvItem->uStateEx = 0; + } + TRACE("item <%p>, txt %p, img %p, mask %x\n", wineItem, tvItem->pszText, &tvItem->iImage, tvItem->mask); @@ -2575,7 +2590,7 @@ /* The item is currently selected */ imageIndex = wineItem->iSelectedImage; } - else if ((wineItem->state & TVIS_EXPANDED) && (wineItem->iExpandedImage >= 0)) + else if ((wineItem->state & TVIS_EXPANDED) && (wineItem->iExpandedImage != (WORD)I_IMAGENONE)) { /* The item is currently not selected but expanded */ imageIndex = wineItem->iExpandedImage; @@ -2878,11 +2893,12 @@ } } - // This is correct, but is causes and infinite loop of WM_PAINT messages, resulting - // in continuous painting of the scroll bar in reactos. Comment out until the real - // bug is found - // - //TREEVIEW_UpdateScrollBars(infoPtr); + // + // This is correct, but is causes and infinite loop of WM_PAINT messages, resulting + // in continuous painting of the scroll bar in reactos. Comment out until the real + // bug is found + // + //TREEVIEW_UpdateScrollBars(infoPtr); if (infoPtr->cdmode & CDRF_NOTIFYPOSTPAINT) infoPtr->cdmode = @@ -2917,6 +2933,7 @@ { hdc = hdc_ref; GetClientRect(infoPtr->hwnd, &rc); + TREEVIEW_FillBkgnd(infoPtr, hdc, &rc); } else { @@ -3309,7 +3326,7 @@ static BOOL TREEVIEW_Expand(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, - BOOL bExpandPartial, BOOL bUser) + BOOL partial, BOOL user) { LONG scrollDist; LONG orgNextTop = 0; @@ -3317,7 +3334,7 @@ TREEVIEW_ITEM *nextItem, *tmpItem; BOOL sendsNotifications; - TRACE("(%p, %p, partial=%d, %d\n", infoPtr, wineItem, bExpandPartial, bUser); + TRACE("(%p, %p, partial=%d, %d\n", infoPtr, wineItem, partial, user); if (wineItem->state & TVIS_EXPANDED) return TRUE; @@ -3338,7 +3355,7 @@ TRACE("TVE_EXPAND %p %s\n", wineItem, TREEVIEW_ItemName(wineItem)); - sendsNotifications = bUser || ((wineItem->cChildren != 0) && + sendsNotifications = user || ((wineItem->cChildren != 0) && !(wineItem->state & TVIS_EXPANDEDONCE)); if (sendsNotifications) { @@ -3353,7 +3370,7 @@ wineItem->state |= TVIS_EXPANDED; - if (bExpandPartial) + if (partial) FIXME("TVE_EXPANDPARTIAL not implemented\n"); if (ISVISIBLE(wineItem)) @@ -3419,6 +3436,58 @@ return TRUE; } +/* Handler for TVS_SINGLEEXPAND behaviour. Used on response + to mouse messages and TVM_SELECTITEM. + + selection - previously selected item, used to collapse a part of a tree + item - new selected item +*/ +static void TREEVIEW_SingleExpand(TREEVIEW_INFO *infoPtr, + HTREEITEM selection, HTREEITEM item) +{ + TREEVIEW_ITEM *SelItem; + + if ((infoPtr->dwStyle & TVS_SINGLEEXPAND) == 0 || infoPtr->hwndEdit || !item) return; + + TREEVIEW_SendTreeviewNotify(infoPtr, TVN_SINGLEEXPAND, TVC_UNKNOWN, TVIF_HANDLE | TVIF_PARAM, item, 0); + + /* + * Close the previous selection all the way to the root + * as long as the new selection is not a child + */ + if(selection && (selection != item)) + { + BOOL closeit = TRUE; + SelItem = item; + + /* determine if the hitItem is a child of the currently selected item */ + while(closeit && SelItem && TREEVIEW_ValidItem(infoPtr, SelItem) && + (SelItem->parent != infoPtr->root)) + { + closeit = (SelItem != selection); + SelItem = SelItem->parent; + } + + if(closeit) + { + if(TREEVIEW_ValidItem(infoPtr, selection)) + SelItem = selection; + + while(SelItem && (SelItem != item) && TREEVIEW_ValidItem(infoPtr, SelItem) && + SelItem->parent != infoPtr->root) + { + TREEVIEW_Collapse(infoPtr, SelItem, FALSE, FALSE); + SelItem = SelItem->parent; + } + } + } + + /* + * Expand the current item + */ + TREEVIEW_Expand(infoPtr, item, FALSE, FALSE); +} + static BOOL TREEVIEW_Toggle(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, BOOL bUser) { @@ -3865,7 +3934,7 @@ tvdi.item.cchTextMax = 0; } - bCommit = TREEVIEW_SendRealNotify(infoPtr, tvdi.hdr.idFrom, (LPARAM)&tvdi); + bCommit = TREEVIEW_SendRealNotify(infoPtr, tvdi.hdr.idFrom, &tvdi.hdr); if (!bCancel && bCommit) /* Apply the changes */ { @@ -4136,58 +4205,11 @@ } else if (ht.flags & (TVHT_ONITEMICON|TVHT_ONITEMLABEL)) /* select the item if the hit was inside of the icon or text */ { - /* - * if we are TVS_SINGLEEXPAND then we want this single click to - * do a bunch of things. - */ - if((infoPtr->dwStyle & TVS_SINGLEEXPAND) && - (infoPtr->hwndEdit == 0)) - { - TREEVIEW_ITEM *SelItem; + TREEVIEW_ITEM *selection = infoPtr->selectedItem; - /* - * Send the notification - */ - TREEVIEW_SendTreeviewNotify(infoPtr, TVN_SINGLEEXPAND, TVC_UNKNOWN, TVIF_HANDLE | TVIF_PARAM, ht.hItem, 0); - - /* - * Close the previous selection all the way to the root - * as long as the new selection is not a child - */ - if((infoPtr->selectedItem) - && (infoPtr->selectedItem != ht.hItem)) - { - BOOL closeit = TRUE; - SelItem = ht.hItem; - - /* determine if the hitItem is a child of the currently selected item */ - while(closeit && SelItem && TREEVIEW_ValidItem(infoPtr, SelItem) && (SelItem != infoPtr->root)) - { - closeit = (SelItem != infoPtr->selectedItem); - SelItem = SelItem->parent; - } - - if(closeit) - { - if(TREEVIEW_ValidItem(infoPtr, infoPtr->selectedItem)) - SelItem = infoPtr->selectedItem; - - while(SelItem && (SelItem != ht.hItem) && TREEVIEW_ValidItem(infoPtr, SelItem) && (SelItem != infoPtr->root)) - { - TREEVIEW_Collapse(infoPtr, SelItem, FALSE, FALSE); - SelItem = SelItem->parent; - } - } - } - - /* - * Expand the current item - */ - TREEVIEW_Expand(infoPtr, ht.hItem, TVE_TOGGLE, FALSE); - } - /* Select the current item */ TREEVIEW_DoSelectItem(infoPtr, TVGN_CARET, ht.hItem, TVC_BYMOUSE); + TREEVIEW_SingleExpand(infoPtr, selection, ht.hItem); } else if (ht.flags & TVHT_ONITEMSTATEICON) { @@ -4350,6 +4372,9 @@ switch (action) { + case TVGN_CARET|TVSI_NOSINGLEEXPAND: + FIXME("TVSI_NOSINGLEEXPAND specified.\n"); + /* Fall through */ case TVGN_CARET: prevSelect = infoPtr->selectedItem; @@ -4419,7 +4444,9 @@ static LRESULT TREEVIEW_SelectItem(TREEVIEW_INFO *infoPtr, INT wParam, HTREEITEM item) { - if (item != NULL && !TREEVIEW_ValidItem(infoPtr, item)) + TREEVIEW_ITEM *selection = infoPtr->selectedItem; + + if (item && !TREEVIEW_ValidItem(infoPtr, item)) return FALSE; TRACE("%p (%s) %d\n", item, TREEVIEW_ItemName(item), wParam); @@ -4427,6 +4454,8 @@ if (!TREEVIEW_DoSelectItem(infoPtr, wParam, item, TVC_UNKNOWN)) return FALSE; + TREEVIEW_SingleExpand(infoPtr, selection, item); + return TRUE; } @@ -5474,7 +5503,7 @@ nmmouse.pt.x = 0; nmmouse.pt.y = 0; nmmouse.dwHitInfo = lParam; - if (TREEVIEW_SendRealNotify(infoPtr, nmmouse.hdr.idFrom, (LPARAM)&nmmouse)) + if (TREEVIEW_SendRealNotify(infoPtr, nmmouse.hdr.idFrom, &nmmouse.hdr)) return 0; if (item && (infoPtr->dwStyle & TVS_TRACKSELECT)) @@ -5824,10 +5853,10 @@ /* Tree Verification ****************************************************/ static inline void -TREEVIEW_VerifyChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item); +TREEVIEW_VerifyChildren(TREEVIEW_INFO *infoPtr, const TREEVIEW_ITEM *item); static inline void TREEVIEW_VerifyItemCommon(TREEVIEW_INFO *infoPtr, - TREEVIEW_ITEM *item) + const TREEVIEW_ITEM *item) { assert(infoPtr != NULL); assert(item != NULL); @@ -5866,7 +5895,7 @@ } static inline void -TREEVIEW_VerifyItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) +TREEVIEW_VerifyItem(TREEVIEW_INFO *infoPtr, const TREEVIEW_ITEM *item) { assert(item != NULL); @@ -5882,9 +5911,9 @@ } static inline void -TREEVIEW_VerifyChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) +TREEVIEW_VerifyChildren(TREEVIEW_INFO *infoPtr, const TREEVIEW_ITEM *item) { - TREEVIEW_ITEM *child; + const TREEVIEW_ITEM *child; assert(item != NULL); for (child = item->firstChild; child != NULL; child = child->nextSibling)