3 * Copyright 1998 Eric Kohl <ekohl@abo.rhein-zeitung.de>
4 * Copyright 1998,1999 Alex Priem <alexp@sci.kun.nl>
5 * Copyright 1999 Sylvain St-Germain
9 * Using DPA to store the item ptr would be good.
10 * Node label edition is implemented but something appened in wine in the
11 * two last weeks of march 99 that broke it.
13 -small array containing info about positions.
14 -better implementation of RefreshItem:
15 1) draw lines between parents
17 3) draw lines from parent<->items.
18 -implement partial drawing?
19 * -drag&drop: TVM_CREATEDRAGIMAGE should create drag bitmap.
20 * -scrollbars: horizontal scrollbar doesn't work.
24 * FIXME: check fontsize. (uRealItemHeight)
25 * test focusItem (redraw in different color)
28 better implementation.
29 * WM_HSCROLL is broken.
30 * use separate routine to get item text/image.
32 * Separate drawing/calculation.
34 * FIXMEs (for personal use)
35 Expand: -ctlmacro expands twice ->toggle.
36 -DblClick: ctlmacro.exe's NM_DBLCLK seems to go wrong (returns FALSE).
37 -treehelper: stack corruption makes big window.
47 #include "debugtools.h"
49 DEFAULT_DEBUG_CHANNEL(treeview)
51 /* ffs should be in <string.h>. */
53 /* Defines, since they do not need to return previous state, and nr
54 * has no side effects in this file.
56 #define tv_test_bit(nr,bf) (((LPBYTE)bf)[nr>>3]&(1<<(nr&7)))
57 #define tv_set_bit(nr,bf) ((LPBYTE)bf)[nr>>3]|=(1<<(nr&7))
58 #define tv_clear_bit(nr,bf) ((LPBYTE)bf)[nr>>3]&=~(1<<(nr&7))
61 #define TREEVIEW_GetInfoPtr(hwnd) \
62 ((TREEVIEW_INFO *) GetWindowLongA( hwnd, 0))
65 TREEVIEW_SendSimpleNotify (HWND hwnd, UINT code);
67 TREEVIEW_SendTreeviewNotify (HWND hwnd, UINT code, UINT action,
68 HTREEITEM oldItem, HTREEITEM newItem);
70 TREEVIEW_SendTreeviewDnDNotify (HWND hwnd, UINT code, HTREEITEM dragItem,
73 TREEVIEW_SendDispInfoNotify (HWND hwnd, TREEVIEW_ITEM *wineItem,
74 UINT code, UINT what);
76 TREEVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
79 TREEVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
80 TREEVIEW_ITEM *tvItem, UINT uItemDrawState);
82 TREEVIEW_DoSelectItem (HWND hwnd, INT action, HTREEITEM newSelect, INT cause);
84 TREEVIEW_Refresh (HWND hwnd);
86 static LRESULT CALLBACK
87 TREEVIEW_Edit_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam,
91 TREEVIEW_EndEditLabelNow (HWND hwnd, WPARAM wParam, LPARAM lParam);
96 /* helper functions. Work with the assumption that validity of operands
97 is checked beforehand, and that tree state is valid. */
99 /* FIXME: MS documentation says `GetNextVisibleItem' returns NULL
100 if not succesfull'. Probably only applies to derefencing infoPtr
101 (ie we are offered a valid treeview structure)
102 and not whether there is a next `visible' child.
103 FIXME: check other failures.
106 /***************************************************************************
107 * This method returns the TREEVIEW_ITEM object given the handle
109 static TREEVIEW_ITEM* TREEVIEW_ValidItem(
110 TREEVIEW_INFO *infoPtr,
113 if ((!handle) || (handle>infoPtr->uMaxHandle))
116 if (tv_test_bit ((INT)handle, infoPtr->freeList))
119 return &infoPtr->items[(INT)handle];
122 /***************************************************************************
123 * This method returns the last expanded child item of a tree node
125 static TREEVIEW_ITEM *TREEVIEW_GetLastListItem(
126 TREEVIEW_INFO *infoPtr,
127 TREEVIEW_ITEM *tvItem)
130 TREEVIEW_ITEM *wineItem = tvItem;
133 * Get this item last sibling
135 while (wineItem->sibling)
136 wineItem=& infoPtr->items [(INT)wineItem->sibling];
139 * If the last sibling has expanded children, restart.
141 if ( ( wineItem->cChildren > 0 ) && ( wineItem->state & TVIS_EXPANDED) )
142 return TREEVIEW_GetLastListItem(
144 &(infoPtr->items[(INT)wineItem->firstChild]));
149 /***************************************************************************
150 * This method returns the previous physical item in the list not
151 * considering the tree hierarchy.
153 static TREEVIEW_ITEM *TREEVIEW_GetPrevListItem(
154 TREEVIEW_INFO *infoPtr,
155 TREEVIEW_ITEM *tvItem)
157 if (tvItem->upsibling)
160 * This item has a upsibling, get the last item. Since, GetLastListItem
161 * first looks at siblings, we must feed it with the first child.
163 TREEVIEW_ITEM *upItem = &infoPtr->items[(INT)tvItem->upsibling];
165 if ( ( upItem->cChildren > 0 ) && ( upItem->state & TVIS_EXPANDED) )
166 return TREEVIEW_GetLastListItem(
168 &infoPtr->items[(INT)upItem->firstChild]);
175 * this item does not have a upsibling, get the parent
178 return &infoPtr->items[(INT)tvItem->parent];
185 /***************************************************************************
186 * This method returns the next physical item in the treeview not
187 * considering the tree hierarchy.
189 static TREEVIEW_ITEM *TREEVIEW_GetNextListItem(
190 TREEVIEW_INFO *infoPtr,
191 TREEVIEW_ITEM *tvItem)
193 TREEVIEW_ITEM *wineItem = NULL;
196 * If this item has children and is expanded, return the first child
198 if ((tvItem->firstChild) && (tvItem->state & TVIS_EXPANDED))
199 return (& infoPtr->items[(INT)tvItem->firstChild]);
203 * try to get the sibling
206 return (& infoPtr->items[(INT)tvItem->sibling]);
209 * Otherwise, get the parent's sibling.
212 while (wineItem->parent) {
213 wineItem=& infoPtr->items [(INT)wineItem->parent];
214 if (wineItem->sibling)
215 return (& infoPtr->items [(INT)wineItem->sibling]);
221 /***************************************************************************
222 * This method returns the nth item starting at the given item. It returns
223 * the last item (or first) we we run out of items.
225 * Will scroll backward if count is <0.
226 * forward if count is >0.
228 static TREEVIEW_ITEM *TREEVIEW_GetListItem(
229 TREEVIEW_INFO *infoPtr,
230 TREEVIEW_ITEM *tvItem,
233 TREEVIEW_ITEM *previousItem = NULL;
234 TREEVIEW_ITEM *wineItem = tvItem;
239 /* Find count item downward */
240 while ((iter++ < count) && (wineItem != NULL))
242 /* Keep a pointer to the previous in case we ask for more than we got */
243 previousItem = wineItem;
244 wineItem = TREEVIEW_GetNextListItem(infoPtr, wineItem);
247 if (wineItem == NULL)
248 wineItem = previousItem;
252 /* Find count item upward */
253 while ((iter-- > count) && (wineItem != NULL))
255 /* Keep a pointer to the previous in case we ask for more than we got */
256 previousItem = wineItem;
257 wineItem = TREEVIEW_GetPrevListItem(infoPtr, wineItem);
260 if (wineItem == NULL)
261 wineItem = previousItem;
270 /***************************************************************************
273 static void TREEVIEW_RemoveAllChildren(
275 TREEVIEW_ITEM *parentItem)
277 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
278 TREEVIEW_ITEM *killItem;
281 kill=(INT)parentItem->firstChild;
283 tv_set_bit ( kill, infoPtr->freeList);
284 killItem=& infoPtr->items[kill];
285 if (killItem->pszText!=LPSTR_TEXTCALLBACKA)
286 COMCTL32_Free (killItem->pszText);
287 TREEVIEW_SendTreeviewNotify (hwnd, TVN_DELETEITEM, 0, (HTREEITEM)kill, 0);
288 if (killItem->firstChild)
289 TREEVIEW_RemoveAllChildren (hwnd, killItem);
290 kill=(INT)killItem->sibling;
293 if (parentItem->cChildren>0) {
294 infoPtr->uNumItems -= parentItem->cChildren;
295 parentItem->firstChild = 0;
296 parentItem->cChildren = 0;
303 TREEVIEW_RemoveItem (HWND hwnd, TREEVIEW_ITEM *wineItem)
306 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
307 TREEVIEW_ITEM *parentItem, *upsiblingItem, *siblingItem;
310 iItem=(INT)wineItem->hItem;
311 tv_set_bit(iItem,infoPtr->freeList);
312 infoPtr->uNumItems--;
314 if (wineItem->pszText!=LPSTR_TEXTCALLBACKA)
315 COMCTL32_Free (wineItem->pszText);
317 TREEVIEW_SendTreeviewNotify (hwnd, TVN_DELETEITEM, 0, (HTREEITEM)iItem, 0);
319 if (wineItem->firstChild)
320 TREEVIEW_RemoveAllChildren (hwnd,wineItem);
322 if (wineItem->parent) {
323 parentItem=& infoPtr->items [(INT)wineItem->parent];
324 switch (parentItem->cChildren) {
325 case I_CHILDRENCALLBACK:
326 FIXME("we don't handle I_CHILDRENCALLBACK yet\n");
329 parentItem->cChildren=0;
330 parentItem->firstChild=0;
333 parentItem->cChildren--;
334 if ((INT)parentItem->firstChild==iItem)
335 parentItem->firstChild=wineItem->sibling;
339 if (iItem==(INT)infoPtr->TopRootItem)
340 infoPtr->TopRootItem=(HTREEITEM)wineItem->sibling;
341 if (wineItem->upsibling) {
342 upsiblingItem=& infoPtr->items [(INT)wineItem->upsibling];
343 upsiblingItem->sibling=wineItem->sibling;
345 if (wineItem->sibling) {
346 siblingItem=& infoPtr->items [(INT)wineItem->sibling];
347 siblingItem->upsibling=wineItem->upsibling;
355 /* Note:TREEVIEW_RemoveTree doesn't remove infoPtr itself */
357 static void TREEVIEW_RemoveTree (HWND hwnd)
360 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
361 TREEVIEW_ITEM *killItem;
364 for (i=1; i<=(INT)infoPtr->uMaxHandle; i++)
365 if (!tv_test_bit (i, infoPtr->freeList)) {
366 killItem=& infoPtr->items [i];
367 if (killItem->pszText!=LPSTR_TEXTCALLBACKA)
368 COMCTL32_Free (killItem->pszText);
369 TREEVIEW_SendTreeviewNotify
370 (hwnd, TVN_DELETEITEM, 0, killItem->hItem, 0);
373 if (infoPtr->uNumPtrsAlloced) {
374 COMCTL32_Free (infoPtr->items);
375 COMCTL32_Free (infoPtr->freeList);
376 infoPtr->uNumItems=0;
377 infoPtr->uNumPtrsAlloced=0;
378 infoPtr->uMaxHandle=0;
389 TREEVIEW_GetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
391 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
394 if (infoPtr==NULL) return 0;
396 if ((INT)wParam == TVSIL_NORMAL)
397 return (LRESULT) infoPtr->himlNormal;
398 if ((INT)wParam == TVSIL_STATE)
399 return (LRESULT) infoPtr->himlState;
405 TREEVIEW_SetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
407 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
411 switch ((INT)wParam) {
413 himlTemp = infoPtr->himlNormal;
414 infoPtr->himlNormal = (HIMAGELIST)lParam;
415 return (LRESULT)himlTemp;
418 himlTemp = infoPtr->himlState;
419 infoPtr->himlState = (HIMAGELIST)lParam;
420 return (LRESULT)himlTemp;
423 return (LRESULT)NULL;
429 TREEVIEW_SetItemHeight (HWND hwnd, WPARAM wParam)
431 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
432 INT cx,cy,prevHeight=infoPtr->uItemHeight;
438 infoPtr->uItemHeight=-1;
442 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &cy);
444 if (wParam>cy) cy=wParam;
445 infoPtr->uItemHeight=cy;
447 if (!( GetWindowLongA( hwnd, GWL_STYLE) & TVS_NONEVENHEIGHT))
448 infoPtr->uItemHeight = (INT) wParam & 0xfffffffe;
453 TREEVIEW_GetItemHeight (HWND hwnd)
455 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
458 return infoPtr->uItemHeight;
462 TREEVIEW_SetTextColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
464 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
465 COLORREF prevColor=infoPtr->clrText;
468 infoPtr->clrText=(COLORREF) lParam;
469 return (LRESULT) prevColor;
473 TREEVIEW_GetBkColor (HWND hwnd)
475 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
478 return (LRESULT) infoPtr->clrText;
482 TREEVIEW_SetBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
484 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
485 COLORREF prevColor=infoPtr->clrBk;
488 infoPtr->clrBk=(COLORREF) lParam;
489 return (LRESULT) prevColor;
493 TREEVIEW_GetTextColor (HWND hwnd)
495 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
498 return (LRESULT) infoPtr->clrBk;
502 /* cdmode: custom draw mode as received from app. in first NMCUSTOMDRAW
505 #define TREEVIEW_LEFT_MARGIN 8
509 TREEVIEW_DrawItem (HWND hwnd, HDC hdc, TREEVIEW_ITEM *wineItem)
511 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
513 INT center,xpos,cx,cy, cditem, drawmode;
515 UINT uTextJustify = DT_LEFT;
519 if (wineItem->state & TVIS_BOLD)
520 hOldFont = SelectObject (hdc, infoPtr->hBoldFont);
522 hOldFont = SelectObject (hdc, infoPtr->hFont);
525 if (infoPtr->cdmode & CDRF_NOTIFYITEMDRAW) {
526 drawmode=CDDS_ITEMPREPAINT;
528 if (infoPtr->cdmode & CDRF_NOTIFYSUBITEMDRAW)
529 drawmode|=CDDS_SUBITEM;
531 cditem=TREEVIEW_SendCustomDrawItemNotify (hwnd, hdc, wineItem, drawmode);
533 TRACE("cditem:%d\n",cditem);
535 if (cditem & CDRF_SKIPDEFAULT)
540 * Set drawing starting points
542 r = wineItem->rect; /* this item rectangle */
543 center = (r.top+r.bottom)/2; /* this item vertical center */
544 xpos = r.left + TREEVIEW_LEFT_MARGIN;/* horizontal starting point */
547 * Display the tree hierarchy
549 if ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_HASLINES)
552 * Write links to parent node
553 * we draw the L starting from the child to the parent
555 * points[0] is attached to the current item
556 * points[1] is the L corner
557 * points[2] is attached to the parent or the up sibling
559 if ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_LINESATROOT)
561 TREEVIEW_ITEM *upNode = NULL;
562 BOOL hasParentOrSibling = TRUE;
563 RECT upRect = {0,0,0,0};
564 HPEN hOldPen, hnewPen;
567 * determine the target location of the line at root, either be linked
568 * to the up sibling or to the parent node.
570 if (wineItem->upsibling)
571 upNode = TREEVIEW_ValidItem (infoPtr, wineItem->upsibling);
572 else if (wineItem->parent)
573 upNode = TREEVIEW_ValidItem (infoPtr, wineItem->parent);
575 hasParentOrSibling = FALSE;
578 upRect = upNode->rect;
580 if ( wineItem->iLevel == 0 )
582 points[2].x = points[1].x = upRect.left+8;
583 points[0].x = points[2].x + 10;
584 points[2].y = upRect.bottom-3;
585 points[1].y = points[0].y = center;
589 points[2].x = points[1].x = 8 + (20*wineItem->iLevel);
590 points[2].y = ( upNode->cChildren == 0) ?
591 upRect.top : /* is linked to the "L" above */
592 ( wineItem->upsibling != NULL) ?
593 upRect.bottom-3: /* is linked to an icon */
594 upRect.bottom+1; /* is linked to a +/- box */
595 points[1].y = points[0].y = center;
596 points[0].x = points[1].x + 10;
602 hnewPen = CreatePen(PS_DOT, 0, GetSysColor(COLOR_WINDOWTEXT) );
603 hOldPen = SelectObject( hdc, hnewPen );
605 if (hasParentOrSibling)
606 Polyline (hdc,points,3);
608 Polyline (hdc,points,2);
610 DeleteObject(hnewPen);
611 SelectObject(hdc, hOldPen);
616 * Display the (+/-) signs
618 if (wineItem->iLevel != 0)/* update position only for non root node */
619 xpos+=(5*wineItem->iLevel);
621 if (( GetWindowLongA( hwnd, GWL_STYLE) & TVS_HASBUTTONS) &&
622 ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_HASLINES))
624 if ( (wineItem->cChildren) ||
625 (wineItem->cChildren == I_CHILDRENCALLBACK))
627 /* Setup expand box coordinate to facilitate the LMBClick handling */
628 wineItem->expandBox.left = xpos-4;
629 wineItem->expandBox.top = center-4;
630 wineItem->expandBox.right = xpos+5;
631 wineItem->expandBox.bottom = center+5;
635 wineItem->expandBox.left,
636 wineItem->expandBox.top ,
637 wineItem->expandBox.right,
638 wineItem->expandBox.bottom);
640 MoveToEx (hdc, xpos-2, center, NULL);
641 LineTo (hdc, xpos+3, center);
643 if (!(wineItem->state & TVIS_EXPANDED)) {
644 MoveToEx (hdc, xpos, center-2, NULL);
645 LineTo (hdc, xpos, center+3);
651 * Display the image assiciated with this item
653 xpos += 13; /* update position */
654 if (wineItem->mask & (TVIF_IMAGE|TVIF_SELECTEDIMAGE)) {
656 HIMAGELIST *himlp = NULL;
658 if (infoPtr->himlNormal)
659 himlp=&infoPtr->himlNormal; /* get the image list */
661 if ( (wineItem->state & TVIS_SELECTED) &&
662 (wineItem->iSelectedImage)) {
664 /* State images are displayed to the left of the Normal image*/
665 if (infoPtr->himlState)
666 himlp=&infoPtr->himlState;
668 /* The item is curently selected */
669 if (wineItem->iSelectedImage == I_IMAGECALLBACK)
670 TREEVIEW_SendDispInfoNotify (
676 imageIndex = wineItem->iSelectedImage;
679 /* This item is not selected */
680 if (wineItem->iImage == I_IMAGECALLBACK)
681 TREEVIEW_SendDispInfoNotify (
687 imageIndex = wineItem->iImage;
692 /* We found an image to display? Draw it. */
701 ImageList_GetIconSize (*himlp, &cx, &cy);
707 * Display the text assiciated with this item
710 if ((wineItem->mask & TVIF_TEXT) && (wineItem->pszText))
712 COLORREF oldBkColor = 0;
713 COLORREF oldTextColor = 0;
719 wineItem->text.left = r.left;
720 wineItem->text.right = r.right;
721 wineItem->text.top = r.top;
722 wineItem->text.bottom= r.bottom;
724 if (wineItem->state & (TVIS_SELECTED | TVIS_DROPHILITED) ) {
725 oldBkMode = SetBkMode (hdc, OPAQUE);
726 oldBkColor = SetBkColor (hdc, GetSysColor( COLOR_HIGHLIGHT));
727 oldTextColor = SetTextColor(hdc, GetSysColor( COLOR_HIGHLIGHTTEXT));
731 oldBkMode = SetBkMode(hdc, TRANSPARENT);
732 oldTextColor = SetTextColor(hdc, GetSysColor( COLOR_WINDOWTEXT));
735 if (wineItem->pszText== LPSTR_TEXTCALLBACKA) {
736 TRACE("LPSTR_TEXTCALLBACK\n");
737 TREEVIEW_SendDispInfoNotify (hwnd, wineItem, TVN_GETDISPINFO, TVIF_TEXT);
744 lstrlenA(wineItem->pszText),
746 uTextJustify | DT_VCENTER | DT_SINGLELINE );
748 /* Obtain the text coordinate */
752 lstrlenA(wineItem->pszText),
754 uTextJustify | DT_VCENTER | DT_SINGLELINE | DT_CALCRECT);
756 /* Restore the hdc state */
757 SetTextColor( hdc, oldTextColor);
759 if (oldBkMode != TRANSPARENT)
760 SetBkMode(hdc, oldBkMode);
761 if (wineItem->state & (TVIS_SELECTED | TVIS_DROPHILITED))
762 SetBkColor (hdc, oldBkColor);
764 /* Draw the box arround the selected item */
765 if (wineItem->state & TVIS_SELECTED )
767 HPEN hnewPen = CreatePen(PS_DOT, 0, GetSysColor(COLOR_WINDOWTEXT) );
768 HPEN hOldPen = SelectObject( hdc, hnewPen );
771 points[0].x = wineItem->text.left-1;
772 points[0].y = wineItem->text.top+1;
773 points[1].x = wineItem->text.right;
774 points[1].y = wineItem->text.top+1;
775 points[2].x = wineItem->text.right;
776 points[2].y = wineItem->text.bottom;
777 points[3].x = wineItem->text.left-1;
778 points[3].y = wineItem->text.bottom;
780 Polyline (hdc,points,4);
782 DeleteObject(hnewPen);
783 SelectObject(hdc, hOldPen);
787 if (cditem & CDRF_NOTIFYPOSTPAINT)
788 TREEVIEW_SendCustomDrawItemNotify (hwnd, hdc, wineItem, CDDS_ITEMPOSTPAINT);
790 SelectObject (hdc, hOldFont);
794 TREEVIEW_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
796 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
797 TREEVIEW_ITEM *wineItem;
799 LPRECT lpRect = (LPRECT)lParam;
803 * validate parameters
805 if ( (infoPtr==NULL) || (lpRect == NULL) )
808 if (infoPtr->Timer & TV_REFRESH_TIMER_SET)
809 TREEVIEW_Refresh (hwnd); /* we want a rect for the current view */
812 * retrive the item ptr
814 iItem = (HTREEITEM *) lParam;
815 wineItem = TREEVIEW_ValidItem (infoPtr, *iItem);
816 if ((!wineItem) || (!wineItem->visible))
820 * If wParam is TRUE return the text size otherwise return
821 * the whole item size
824 lpRect->left = wineItem->text.left;
825 lpRect->right = wineItem->text.right;
826 lpRect->bottom = wineItem->text.bottom;
827 lpRect->top = wineItem->text.top;
829 lpRect->left = wineItem->rect.left;
830 lpRect->right = wineItem->rect.right;
831 lpRect->bottom = wineItem->rect.bottom;
832 lpRect->top = wineItem->rect.top;
835 TRACE("[L:%d R:%d T:%d B:%d]\n",
836 lpRect->left,lpRect->right,
837 lpRect->top,lpRect->bottom);
843 TREEVIEW_GetVisibleCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
846 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
848 return (LRESULT) infoPtr->uVisibleHeight / infoPtr->uRealItemHeight;
854 TREEVIEW_SetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
856 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
857 TREEVIEW_ITEM *wineItem;
861 tvItem=(LPTVITEMEXA) lParam;
862 iItem=(INT)tvItem->hItem;
863 TRACE("item %d,mask %x\n",iItem,tvItem->mask);
865 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
866 if (!wineItem) return FALSE;
868 if (tvItem->mask & TVIF_CHILDREN) {
869 wineItem->cChildren=tvItem->cChildren;
872 if (tvItem->mask & TVIF_IMAGE) {
873 wineItem->iImage=tvItem->iImage;
876 if (tvItem->mask & TVIF_INTEGRAL) {
877 wineItem->iIntegral=tvItem->iIntegral;
878 FIXME(" TVIF_INTEGRAL not supported yet\n");
881 if (tvItem->mask & TVIF_PARAM) {
882 wineItem->lParam=tvItem->lParam;
885 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
886 wineItem->iSelectedImage=tvItem->iSelectedImage;
889 if (tvItem->mask & TVIF_STATE) {
890 wineItem->state=tvItem->state & tvItem->stateMask;
893 if (tvItem->mask & TVIF_TEXT) {
894 if (tvItem->pszText!=LPSTR_TEXTCALLBACKA) {
895 len=lstrlenA (tvItem->pszText);
896 if (len>wineItem->cchTextMax)
897 wineItem->pszText= COMCTL32_ReAlloc (wineItem->pszText, len+1);
898 lstrcpynA (wineItem->pszText, tvItem->pszText,len);
900 if (wineItem->cchTextMax) {
901 COMCTL32_Free (wineItem->pszText);
902 wineItem->cchTextMax=0;
904 wineItem->pszText=LPSTR_TEXTCALLBACKA;
916 TREEVIEW_Refresh (HWND hwnd)
919 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
924 INT iItem, indent, x, y, cx, height, itemHeight;
925 INT viewtop,viewbottom,viewleft,viewright;
926 TREEVIEW_ITEM *wineItem, *prevItem;
932 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
933 KillTimer (hwnd, TV_REFRESH_TIMER);
934 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
938 GetClientRect (hwnd, &rect);
939 if ((rect.left-rect.right ==0) || (rect.top-rect.bottom==0)) return;
941 infoPtr->cdmode=TREEVIEW_SendCustomDrawNotify
942 (hwnd, CDDS_PREPAINT, hdc, rect);
944 if (infoPtr->cdmode==CDRF_SKIPDEFAULT) {
945 ReleaseDC (hwnd, hdc);
949 infoPtr->uVisibleHeight= rect.bottom-rect.top;
950 infoPtr->uVisibleWidth= rect.right-rect.left;
953 viewbottom=infoPtr->cy + rect.bottom-rect.top;
954 viewleft=infoPtr->cx;
955 viewright=infoPtr->cx + rect.right-rect.left;
959 /* draw background */
961 hbrBk = GetSysColorBrush (COLOR_WINDOW);
962 FillRect(hdc, &rect, hbrBk);
965 iItem=(INT)infoPtr->TopRootItem;
966 infoPtr->firstVisible=0;
970 TRACE("[%d %d %d %d]\n",viewtop,viewbottom,viewleft,viewright);
974 wineItem= & infoPtr->items[iItem];
975 wineItem->iLevel=indent;
977 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &itemHeight);
978 if (infoPtr->uItemHeight>itemHeight)
979 itemHeight=infoPtr->uItemHeight;
981 GetTextMetricsA (hdc, &tm);
982 if ((tm.tmHeight + tm.tmExternalLeading) > itemHeight)
983 itemHeight=tm.tmHeight + tm.tmExternalLeading;
985 infoPtr->uRealItemHeight=itemHeight;
988 /* FIXME: remove this in later stage */
990 if (wineItem->pszText!=LPSTR_TEXTCALLBACK32A)
991 TRACE (treeview, "%d %d [%d %d %d %d] (%s)\n",y,x,
992 wineItem->rect.top, wineItem->rect.bottom,
993 wineItem->rect.left, wineItem->rect.right,
996 TRACE (treeview, "%d [%d %d %d %d] (CALLBACK)\n",
998 wineItem->rect.top, wineItem->rect.bottom,
999 wineItem->rect.left, wineItem->rect.right);
1002 height=itemHeight * wineItem->iIntegral +1;
1003 if ((y >= viewtop) && (y <= viewbottom) &&
1004 (x >= viewleft ) && (x <= viewright)) {
1005 wineItem->visible = TRUE;
1006 wineItem->rect.top = y - infoPtr->cy + rect.top;
1007 wineItem->rect.bottom = wineItem->rect.top + height ;
1008 wineItem->rect.left = x - infoPtr->cx + rect.left;
1009 wineItem->rect.right = rect.right;
1010 if (!infoPtr->firstVisible)
1011 infoPtr->firstVisible=wineItem->hItem;
1012 TREEVIEW_DrawItem (hwnd, hdc, wineItem);
1015 wineItem->visible = FALSE;
1016 wineItem->rect.left = wineItem->rect.top = 0;
1017 wineItem->rect.right= wineItem->rect.bottom = 0;
1018 wineItem->text.left = wineItem->text.top = 0;
1019 wineItem->text.right= wineItem->text.bottom = 0;
1022 /* look up next item */
1024 if ((wineItem->firstChild) && (wineItem->state & TVIS_EXPANDED)) {
1025 iItem=(INT)wineItem->firstChild;
1027 x+=infoPtr->uIndent;
1028 if (x>infoPtr->uTotalWidth)
1029 infoPtr->uTotalWidth=x;
1032 iItem=(INT)wineItem->sibling;
1033 while ((!iItem) && (indent>0)) {
1035 x-=infoPtr->uIndent;
1037 wineItem=&infoPtr->items[(INT)wineItem->parent];
1038 iItem=(INT)wineItem->sibling;
1044 /* FIXME: infoPtr->uTotalWidth should also take item label into account */
1045 /* FIXME: or should query item sizes (ie check CDRF_NEWFONT) */
1047 infoPtr->uTotalHeight=y;
1048 if (y >= (viewbottom-viewtop)) {
1049 if (!(infoPtr->uInternalStatus & TV_VSCROLL))
1050 ShowScrollBar (hwnd, SB_VERT, TRUE);
1051 infoPtr->uInternalStatus |=TV_VSCROLL;
1052 SetScrollRange (hwnd, SB_VERT, 0,
1053 y - infoPtr->uVisibleHeight, FALSE);
1054 SetScrollPos (hwnd, SB_VERT, infoPtr->cy, TRUE);
1057 if (infoPtr->uInternalStatus & TV_VSCROLL)
1058 ShowScrollBar (hwnd, SB_VERT, FALSE);
1059 infoPtr->uInternalStatus &= ~TV_VSCROLL;
1063 if (infoPtr->cdmode & CDRF_NOTIFYPOSTPAINT)
1064 infoPtr->cdmode=TREEVIEW_SendCustomDrawNotify
1065 (hwnd, CDDS_POSTPAINT, hdc, rect);
1067 ReleaseDC (hwnd, hdc);
1073 TREEVIEW_HandleTimer (HWND hwnd, WPARAM wParam, LPARAM lParam)
1075 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1077 TRACE(" %d\n",wParam);
1078 if (!infoPtr) return FALSE;
1081 case TV_REFRESH_TIMER:
1082 KillTimer (hwnd, TV_REFRESH_TIMER);
1083 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
1084 InvalidateRect(hwnd, NULL, FALSE);
1087 KillTimer (hwnd, TV_EDIT_TIMER);
1088 infoPtr->Timer &= ~TV_EDIT_TIMER_SET;
1091 ERR("got unknown timer\n");
1099 TREEVIEW_QueueRefresh (HWND hwnd)
1102 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1105 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
1106 KillTimer (hwnd, TV_REFRESH_TIMER);
1109 SetTimer (hwnd, TV_REFRESH_TIMER, TV_REFRESH_DELAY, 0);
1110 infoPtr->Timer|=TV_REFRESH_TIMER_SET;
1116 TREEVIEW_GetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1118 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1120 TREEVIEW_ITEM *wineItem;
1123 tvItem=(LPTVITEMEXA) lParam;
1124 iItem=(INT)tvItem->hItem;
1126 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1127 if (!wineItem) return FALSE;
1129 if (tvItem->mask & TVIF_CHILDREN) {
1130 if (TVIF_CHILDREN==I_CHILDRENCALLBACK)
1131 FIXME("I_CHILDRENCALLBACK not supported\n");
1132 tvItem->cChildren=wineItem->cChildren;
1135 if (tvItem->mask & TVIF_HANDLE) {
1136 tvItem->hItem=wineItem->hItem;
1139 if (tvItem->mask & TVIF_IMAGE) {
1140 tvItem->iImage=wineItem->iImage;
1143 if (tvItem->mask & TVIF_INTEGRAL) {
1144 tvItem->iIntegral=wineItem->iIntegral;
1145 FIXME(" TVIF_INTEGRAL not supported yet\n");
1148 /* undocumented: windows ignores TVIF_PARAM and
1149 * always sets lParam
1151 tvItem->lParam=wineItem->lParam;
1153 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
1154 tvItem->iSelectedImage=wineItem->iSelectedImage;
1157 if (tvItem->mask & TVIF_STATE) {
1158 tvItem->state=wineItem->state & tvItem->stateMask;
1161 if (tvItem->mask & TVIF_TEXT) {
1162 if (wineItem->pszText == LPSTR_TEXTCALLBACKA) {
1163 tvItem->pszText = LPSTR_TEXTCALLBACKA; /* FIXME:send notification? */
1164 ERR(" GetItem called with LPSTR_TEXTCALLBACK\n");
1166 else if (wineItem->pszText) {
1167 lstrcpynA (tvItem->pszText, wineItem->pszText, tvItem->cchTextMax);
1171 TRACE("item %d<%p>, txt %p, img %p, action %x\n",
1183 /* FIXME: check implementation of TVGN_NEXT/TVGN_NEXTVISIBLE */
1186 TREEVIEW_GetNextItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
1189 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1190 TREEVIEW_ITEM *wineItem, *returnItem;
1191 INT iItem, retval, flag;
1194 if (!infoPtr) return FALSE;
1195 flag = (INT) wParam;
1196 iItem = (INT) lParam;
1199 case TVGN_ROOT: retval=(INT)infoPtr->TopRootItem;
1201 case TVGN_CARET:retval=(INT)infoPtr->selectedItem;
1203 case TVGN_FIRSTVISIBLE:
1204 TREEVIEW_Refresh (hwnd);
1205 /* FIXME:we should only recalculate, not redraw */
1206 retval=(INT)infoPtr->firstVisible;
1208 case TVGN_DROPHILITE:
1209 retval=(INT)infoPtr->dropItem;
1213 TRACE("flags:%x, returns %u\n", flag, retval);
1217 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1219 if (!wineItem) return FALSE;
1222 case TVGN_NEXT: retval=(INT)wineItem->sibling;
1225 retval=(INT)wineItem->upsibling;
1228 retval=(INT)wineItem->parent;
1231 retval=(INT)wineItem->firstChild;
1233 case TVGN_LASTVISIBLE:
1234 returnItem=TREEVIEW_GetLastListItem (infoPtr,wineItem);
1236 case TVGN_NEXTVISIBLE:
1237 returnItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
1239 case TVGN_PREVIOUSVISIBLE:
1240 returnItem=TREEVIEW_GetPrevListItem (infoPtr, wineItem);
1242 default: FIXME("Unknown msg %x,item %x\n", flag,iItem);
1247 TRACE("flags:%x, item %d;returns %d\n", flag, iItem,
1248 (INT)returnItem->hItem);
1249 return (INT)returnItem->hItem;
1252 TRACE("flags:%x, item %d;returns %d\n", flag, iItem,retval);
1258 TREEVIEW_GetCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
1260 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1262 TRACE(" %d\n",infoPtr->uNumItems);
1263 return (LRESULT) infoPtr->uNumItems;
1266 /***************************************************************************
1267 * This method does the chaining of the insertion of a treeview item
1269 * If parent is NULL, we're inserting at the root of the list.
1271 static void TREEVIEW_InsertBefore(
1272 TREEVIEW_INFO *infoPtr,
1273 TREEVIEW_ITEM *newItem,
1274 TREEVIEW_ITEM *sibling,
1275 TREEVIEW_ITEM *parent)
1277 HTREEITEM siblingHandle = 0;
1278 HTREEITEM upSiblingHandle = 0;
1279 TREEVIEW_ITEM *upSibling = NULL;
1281 if (newItem == NULL)
1282 ERR("NULL newItem, impossible condition\n");
1284 if (sibling != NULL) /* Insert before this sibling for this parent */
1286 /* Store the new item sibling up sibling and sibling tem handle */
1287 siblingHandle = sibling->hItem;
1288 upSiblingHandle = sibling->upsibling;
1289 /* As well as a pointer to the upsibling sibling object */
1290 if ( (INT)sibling->upsibling != 0 )
1291 upSibling = &infoPtr->items[(INT)sibling->upsibling];
1293 /* Adjust the sibling pointer */
1294 sibling->upsibling = newItem->hItem;
1296 /* Adjust the new item pointers */
1297 newItem->upsibling = upSiblingHandle;
1298 newItem->sibling = siblingHandle;
1300 /* Adjust the up sibling pointer */
1301 if ( upSibling != NULL )
1302 upSibling->sibling = newItem->hItem;
1304 /* this item is the first child of this parent, adjust parent pointers */
1306 parent->firstChild = newItem->hItem;
1308 infoPtr->TopRootItem= newItem->hItem;
1310 else /* Insert as first child of this parent */
1312 parent->firstChild = newItem->hItem;
1315 /***************************************************************************
1316 * This method does the chaining of the insertion of a treeview item
1318 * If parent is NULL, we're inserting at the root of the list.
1320 static void TREEVIEW_InsertAfter(
1321 TREEVIEW_INFO *infoPtr,
1322 TREEVIEW_ITEM *newItem,
1323 TREEVIEW_ITEM *upSibling,
1324 TREEVIEW_ITEM *parent)
1326 HTREEITEM upSiblingHandle = 0;
1327 HTREEITEM siblingHandle = 0;
1328 TREEVIEW_ITEM *sibling = NULL;
1331 if (newItem == NULL)
1332 ERR("NULL newItem, impossible condition\n");
1334 if (upSibling != NULL) /* Insert after this upsibling for this parent */
1336 /* Store the new item up sibling and sibling item handle */
1337 upSiblingHandle = upSibling->hItem;
1338 siblingHandle = upSibling->sibling;
1339 /* As well as a pointer to the upsibling sibling object */
1340 if ( (INT)upSibling->sibling != 0 )
1341 sibling = &infoPtr->items[(INT)upSibling->sibling];
1343 /* Adjust the up sibling pointer */
1344 upSibling->sibling = newItem->hItem;
1346 /* Adjust the new item pointers */
1347 newItem->upsibling = upSiblingHandle;
1348 newItem->sibling = siblingHandle;
1350 /* Adjust the sibling pointer */
1351 if ( sibling != NULL )
1352 sibling->upsibling = newItem->hItem;
1355 newItem is the last of the level, nothing else to do
1358 else /* Insert as first child of this parent */
1360 parent->firstChild = newItem->hItem;
1363 /***************************************************************************
1364 * Forward the DPA local callback to the treeview owner callback
1366 static INT WINAPI TREEVIEW_CallBackCompare(
1371 /* Forward the call to the client define callback */
1372 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr((HWND)tvInfoPtr);
1373 return (infoPtr->pCallBackSort->lpfnCompare)(
1374 ((TREEVIEW_ITEM*)first)->lParam,
1375 ((TREEVIEW_ITEM*)second)->lParam,
1376 infoPtr->pCallBackSort->lParam);
1379 /***************************************************************************
1380 * Treeview native sort routine: sort on item text.
1382 static INT WINAPI TREEVIEW_SortOnName (
1387 HWND hwnd=(HWND) tvInfoPtr;
1389 TREEVIEW_ITEM *item;
1392 item=(TREEVIEW_ITEM *) first;
1393 if (item->pszText==LPSTR_TEXTCALLBACKA) {
1394 TREEVIEW_SendDispInfoNotify (hwnd, item, TVN_GETDISPINFO, TVIF_TEXT);
1398 item=(TREEVIEW_ITEM *) second;
1399 if (item->pszText==LPSTR_TEXTCALLBACKA) {
1400 TREEVIEW_SendDispInfoNotify (hwnd, item, TVN_GETDISPINFO, TVIF_TEXT);
1404 return -strcmp (txt1,txt2);
1407 /***************************************************************************
1408 * Setup the treeview structure with regards of the sort method
1409 * and sort the children of the TV item specified in lParam
1410 * fRecurse: currently unused. Should be zero.
1411 * parent: if pSort!=NULL, should equal pSort->hParent.
1412 * otherwise, item which child items are to be sorted.
1413 * pSort: sort method info. if NULL, sort on item text.
1414 * if non-NULL, sort on item's lParam content, and let the
1415 * application decide what that means. See also TVM_SORTCHILDRENCB.
1418 LRESULT WINAPI TREEVIEW_Sort (
1425 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1426 TREEVIEW_ITEM *sortMe = NULL; /* Node for which we sort the children */
1428 /* Obtain the TVSORTBC struct */
1429 infoPtr->pCallBackSort = pSort;
1431 /* Check for a valid handle to the parent item */
1432 if (!TREEVIEW_ValidItem(infoPtr, parent))
1434 ERR ("invalid item hParent=%d\n", (INT)parent);
1438 /* Obtain the parent node to sort */
1439 sortMe = &infoPtr->items[ (INT)parent ];
1441 /* Make sure there is something to sort */
1442 if ( sortMe->cChildren > 1 )
1444 /* pointer organization */
1445 HDPA sortList = DPA_Create(sortMe->cChildren);
1446 HTREEITEM itemHandle = sortMe->firstChild;
1447 TREEVIEW_ITEM *itemPtr = & infoPtr->items[ (INT)itemHandle ];
1449 /* TREEVIEW_ITEM rechaining */
1455 /* Build the list of item to sort */
1459 sortList, /* the list */
1460 sortMe->cChildren+1, /* force the insertion to be an append */
1461 itemPtr); /* the ptr to store */
1463 /* Get the next sibling */
1464 itemHandle = itemPtr->sibling;
1465 itemPtr = & infoPtr->items[ (INT)itemHandle ];
1466 } while ( itemHandle != NULL );
1468 /* let DPA perform the sort activity */
1471 sortList, /* what */
1472 TREEVIEW_CallBackCompare, /* how */
1476 sortList, /* what */
1477 TREEVIEW_SortOnName, /* how */
1481 * Reorganized TREEVIEW_ITEM structures.
1482 * Note that we know we have at least two elements.
1485 /* Get the first item and get ready to start... */
1486 item = DPA_GetPtr(sortList, count++);
1487 while ( (nextItem = DPA_GetPtr(sortList, count++)) != NULL )
1489 /* link the two current item toghether */
1490 ((TREEVIEW_ITEM*)item)->sibling = ((TREEVIEW_ITEM*)nextItem)->hItem;
1491 ((TREEVIEW_ITEM*)nextItem)->upsibling = ((TREEVIEW_ITEM*)item)->hItem;
1493 if (prevItem == NULL) /* this is the first item, update the parent */
1495 sortMe->firstChild = ((TREEVIEW_ITEM*)item)->hItem;
1496 ((TREEVIEW_ITEM*)item)->upsibling = NULL;
1498 else /* fix the back chaining */
1500 ((TREEVIEW_ITEM*)item)->upsibling = ((TREEVIEW_ITEM*)prevItem)->hItem;
1503 /* get ready for the next one */
1508 /* the last item is pointed to by item and never has a sibling */
1509 ((TREEVIEW_ITEM*)item)->sibling = NULL;
1511 DPA_Destroy(sortList);
1519 /***************************************************************************
1520 * Setup the treeview structure with regards of the sort method
1521 * and sort the children of the TV item specified in lParam
1523 LRESULT WINAPI TREEVIEW_SortChildrenCB(
1529 LPTVSORTCB pSort=(LPTVSORTCB) lParam;
1531 return TREEVIEW_Sort (hwnd, wParam, pSort->hParent, pSort);
1535 /***************************************************************************
1536 * Sort the children of the TV item specified in lParam.
1538 LRESULT WINAPI TREEVIEW_SortChildren (
1543 return TREEVIEW_Sort (hwnd, (BOOL) wParam, (HTREEITEM) lParam, NULL);
1548 /* the method used below isn't the most memory-friendly, but it avoids
1549 a lot of memory reallocations */
1551 /* BTW: we waste handle 0; 0 is not an allowed handle. */
1554 TREEVIEW_InsertItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1557 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1558 TVINSERTSTRUCTA *ptdi;
1560 TREEVIEW_ITEM *wineItem, *parentItem, *prevsib, *sibItem;
1561 INT iItem,listItems,i,len;
1563 /* Item to insert */
1564 ptdi = (LPTVINSERTSTRUCTA) lParam;
1566 /* check if memory is available */
1568 if (infoPtr->uNumPtrsAlloced==0) {
1569 infoPtr->items = COMCTL32_Alloc (TVITEM_ALLOC*sizeof (TREEVIEW_ITEM));
1570 infoPtr->freeList= COMCTL32_Alloc ((1+(TVITEM_ALLOC>>5)) * sizeof (INT));
1571 infoPtr->uNumPtrsAlloced=TVITEM_ALLOC;
1572 infoPtr->TopRootItem=(HTREEITEM)1;
1576 * Reallocate contiguous space for items
1578 if (infoPtr->uNumItems == (infoPtr->uNumPtrsAlloced-1) ) {
1579 TREEVIEW_ITEM *oldItems = infoPtr->items;
1580 INT *oldfreeList = infoPtr->freeList;
1582 infoPtr->uNumPtrsAlloced*=2;
1583 infoPtr->items = COMCTL32_Alloc (infoPtr->uNumPtrsAlloced*sizeof (TREEVIEW_ITEM));
1584 infoPtr->freeList= COMCTL32_Alloc ((1+(infoPtr->uNumPtrsAlloced>>5))*sizeof (INT));
1586 memcpy (&infoPtr->items[0], &oldItems[0],
1587 infoPtr->uNumPtrsAlloced/2 * sizeof(TREEVIEW_ITEM));
1588 memcpy (&infoPtr->freeList[0], &oldfreeList[0],
1589 (infoPtr->uNumPtrsAlloced>>6) * sizeof(INT));
1591 COMCTL32_Free (oldItems);
1592 COMCTL32_Free (oldfreeList);
1596 * Reset infoPtr structure with new stat according to current TV picture
1599 infoPtr->uNumItems++;
1600 if ((INT)infoPtr->uMaxHandle==(infoPtr->uNumItems-1)) {
1601 iItem=infoPtr->uNumItems;
1602 infoPtr->uMaxHandle = (HTREEITEM)((INT)infoPtr->uMaxHandle + 1);
1603 } else { /* check freelist */
1604 for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++) {
1605 if (infoPtr->freeList[i]) {
1606 iItem=ffs (infoPtr->freeList[i])-1;
1607 tv_clear_bit(iItem,&infoPtr->freeList[i]);
1614 if (TRACE_ON(treeview)) {
1615 for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++)
1616 TRACE("%8x\n",infoPtr->freeList[i]);
1619 if (!iItem) ERR("Argh -- can't find free item.\n");
1622 * Find the parent item of the new item
1624 tvItem= & ptdi->DUMMYUNIONNAME.itemex;
1625 wineItem=& infoPtr->items[iItem];
1627 if ((ptdi->hParent==TVI_ROOT) || (ptdi->hParent==0)) {
1629 wineItem->parent = 0;
1630 sibItem = &infoPtr->items [(INT)infoPtr->TopRootItem];
1631 listItems = infoPtr->uNumItems;
1634 parentItem = &infoPtr->items[(INT)ptdi->hParent];
1636 /* Do the insertion here it if it's the only item of this parent */
1637 if (!parentItem->firstChild)
1638 parentItem->firstChild=(HTREEITEM)iItem;
1640 wineItem->parent = ptdi->hParent;
1641 sibItem = &infoPtr->items [(INT)parentItem->firstChild];
1642 parentItem->cChildren++;
1643 listItems = parentItem->cChildren;
1647 /* NOTE: I am moving some setup of the wineItem object that was initialy
1648 * done at the end of the function since some of the values are
1649 * required by the Callback sorting
1652 if (tvItem->mask & TVIF_TEXT)
1655 * Setup the item text stuff here since it's required by the Sort method
1656 * when the insertion are ordered
1658 if (tvItem->pszText!=LPSTR_TEXTCALLBACKA)
1660 TRACE("(%p,%s)\n", &tvItem->pszText, tvItem->pszText);
1661 len = lstrlenA (tvItem->pszText)+1;
1662 wineItem->pszText= COMCTL32_Alloc (len+1);
1663 lstrcpyA (wineItem->pszText, tvItem->pszText);
1664 wineItem->cchTextMax=len;
1668 TRACE("LPSTR_TEXTCALLBACK\n");
1669 wineItem->pszText = LPSTR_TEXTCALLBACKA;
1670 wineItem->cchTextMax = 0;
1674 if (tvItem->mask & TVIF_PARAM)
1675 wineItem->lParam=tvItem->lParam;
1678 wineItem->upsibling=0; /* needed in case we're the first item in a list */
1679 wineItem->sibling=0;
1680 wineItem->firstChild=0;
1681 wineItem->hItem=(HTREEITEM)iItem;
1686 switch ((DWORD) ptdi->hInsertAfter) {
1687 case (DWORD) TVI_FIRST:
1688 if (wineItem->parent) {
1689 wineItem->sibling=parentItem->firstChild;
1690 parentItem->firstChild=(HTREEITEM)iItem;
1692 wineItem->sibling=infoPtr->TopRootItem;
1693 infoPtr->TopRootItem=(HTREEITEM)iItem;
1695 sibItem->upsibling=(HTREEITEM)iItem;
1698 case (DWORD) TVI_SORT:
1699 if (sibItem==wineItem)
1701 * This item is the first child of the level and it
1702 * has already been inserted
1707 TREEVIEW_ITEM *aChild;
1710 TREEVIEW_ITEM *previousChild = NULL;
1711 BOOL bItemInserted = FALSE;
1714 aChild = &infoPtr->items[(INT)parentItem->firstChild];
1716 aChild = &infoPtr->items[(INT)infoPtr->TopRootItem];
1718 /* Iterate the parent children to see where we fit in */
1719 while ( aChild != NULL )
1721 INT comp = strcmp(wineItem->pszText, aChild->pszText);
1722 if ( comp < 0 ) /* we are smaller than the current one */
1724 TREEVIEW_InsertBefore(infoPtr, wineItem, aChild, parentItem);
1725 bItemInserted = TRUE;
1728 else if ( comp > 0 ) /* we are bigger than the current one */
1730 previousChild = aChild;
1731 aChild = (aChild->sibling == 0) /* This will help us to exit */
1732 ? NULL /* if there is no more sibling */
1733 : &infoPtr->items[(INT)aChild->sibling];
1735 /* Look at the next item */
1738 else if ( comp == 0 )
1741 * An item with this name is already existing, therefore,
1742 * we add after the one we found
1744 TREEVIEW_InsertAfter(infoPtr, wineItem, aChild, parentItem);
1745 bItemInserted = TRUE;
1751 * we reach the end of the child list and the item as not
1752 * yet been inserted, therefore, insert it after the last child.
1754 if ( (! bItemInserted ) && (aChild == NULL) )
1755 TREEVIEW_InsertAfter(infoPtr, wineItem, previousChild, parentItem);
1761 case (DWORD) TVI_LAST:
1762 if (sibItem==wineItem) break;
1763 while (sibItem->sibling) {
1765 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1767 sibItem->sibling=(HTREEITEM)iItem;
1768 wineItem->upsibling=sibItem->hItem;
1771 while ((sibItem->sibling) && (sibItem->hItem!=ptdi->hInsertAfter))
1774 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1776 if (sibItem->hItem!=ptdi->hInsertAfter) {
1777 ERR("tried to insert item after nonexisting handle %d.\n",
1778 (INT) ptdi->hInsertAfter);
1782 if (sibItem->sibling) {
1783 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1784 sibItem->upsibling=(HTREEITEM)iItem;
1785 wineItem->sibling=sibItem->hItem;
1787 prevsib->sibling=(HTREEITEM)iItem;
1788 wineItem->upsibling=prevsib->hItem;
1794 /* Fill in info structure */
1796 TRACE("new item %d; parent %d, mask %x\n", iItem,
1797 (INT)wineItem->parent,tvItem->mask);
1799 wineItem->mask=tvItem->mask;
1800 wineItem->iIntegral=1;
1802 if (tvItem->mask & TVIF_CHILDREN) {
1803 wineItem->cChildren=tvItem->cChildren;
1804 if (tvItem->cChildren==I_CHILDRENCALLBACK)
1805 FIXME(" I_CHILDRENCALLBACK not supported\n");
1808 wineItem->expandBox.left = 0; /* Initialize the expandBox */
1809 wineItem->expandBox.top = 0;
1810 wineItem->expandBox.right = 0;
1811 wineItem->expandBox.bottom = 0;
1813 if (tvItem->mask & TVIF_IMAGE)
1814 wineItem->iImage=tvItem->iImage;
1816 /* If the application sets TVIF_INTEGRAL without
1817 supplying a TVITEMEX structure, it's toast */
1819 if (tvItem->mask & TVIF_INTEGRAL)
1820 wineItem->iIntegral=tvItem->iIntegral;
1822 if (tvItem->mask & TVIF_SELECTEDIMAGE)
1823 wineItem->iSelectedImage=tvItem->iSelectedImage;
1825 if (tvItem->mask & TVIF_STATE) {
1826 TRACE("Changing item state from %d to %d\n",
1829 wineItem->state=tvItem->state;
1830 wineItem->stateMask=tvItem->stateMask;
1834 TREEVIEW_QueueRefresh (hwnd);
1836 return (LRESULT) iItem;
1844 TREEVIEW_DeleteItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
1846 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1848 TREEVIEW_ITEM *wineItem;
1851 if (!infoPtr) return FALSE;
1853 if (lParam == (INT)TVI_ROOT) {
1854 TREEVIEW_RemoveTree (hwnd);
1856 iItem= (INT) lParam;
1857 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1858 if (!wineItem) return FALSE;
1859 TRACE("%s\n",wineItem->pszText);
1860 TREEVIEW_RemoveItem (hwnd, wineItem);
1863 TREEVIEW_QueueRefresh (hwnd);
1871 TREEVIEW_GetIndent (HWND hwnd)
1873 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1876 return infoPtr->uIndent;
1880 TREEVIEW_SetIndent (HWND hwnd, WPARAM wParam)
1882 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1886 newIndent=(INT) wParam;
1887 if (newIndent < MINIMUM_INDENT) newIndent=MINIMUM_INDENT;
1888 infoPtr->uIndent=newIndent;
1894 TREEVIEW_GetToolTips (HWND hwnd)
1897 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1900 return infoPtr->hwndToolTip;
1905 TREEVIEW_SetToolTips (HWND hwnd, WPARAM wParam)
1908 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1912 prevToolTip=infoPtr->hwndToolTip;
1913 infoPtr->hwndToolTip= (HWND) wParam;
1920 TREEVIEW_GetEditControl (HWND hwnd)
1923 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1925 return infoPtr->hwndEdit;
1929 TREEVIEW_Edit_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam,
1937 HDC hdc = (HDC) wParam;
1938 GetClientRect (hwnd, &rc);
1939 Rectangle (hdc, rc.left, rc.top, rc.right, rc.bottom);
1945 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
1950 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd));
1951 return CallWindowProcA( infoPtr->wpEditOrig, hwnd, uMsg, wParam, lParam);
1959 /* should handle edit control messages here */
1962 TREEVIEW_Command (HWND hwnd, WPARAM wParam, LPARAM lParam)
1965 TRACE("%x %ld\n",wParam, lParam);
1967 switch (HIWORD(wParam))
1972 * Adjust the edit window size
1974 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1975 TREEVIEW_ITEM *editItem = TREEVIEW_ValidItem(infoPtr, infoPtr->editItem);
1976 INT iLength = GetWindowTextLengthA(infoPtr->hwndEdit);
1977 HDC hdc = GetDC(infoPtr->hwndEdit);
1980 if ( GetTextMetricsA(hdc, &tm) )
1982 LONG newWidth = (iLength * tm.tmAveCharWidth) + 15;
1987 editItem->text.left - 2,
1988 editItem->text.top - 1,
1990 editItem->text.bottom - editItem->text.top + 3,
1993 ReleaseDC(hwnd, hdc);
1999 /* TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
2004 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
2011 TREEVIEW_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
2014 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2016 if (infoPtr->bAutoSize)
2018 infoPtr->bAutoSize = FALSE;
2021 infoPtr->bAutoSize = TRUE;
2023 if (wParam == SIZE_RESTORED)
2025 infoPtr->uTotalWidth = LOWORD (lParam);
2026 infoPtr->uTotalHeight = HIWORD (lParam);
2028 FIXME("WM_SIZE flag %x %lx not handled\n", wParam, lParam);
2031 TREEVIEW_QueueRefresh (hwnd);
2038 TREEVIEW_StyleChanged (HWND hwnd, WPARAM wParam, LPARAM lParam)
2040 LPSTYLESTRUCT lpss=(LPSTYLESTRUCT) lParam;
2042 TRACE("(%x %lx)\n",wParam,lParam);
2044 if (wParam & (GWL_STYLE))
2045 SetWindowLongA( hwnd, GWL_STYLE, lpss->styleNew);
2046 if (wParam & (GWL_EXSTYLE))
2047 SetWindowLongA( hwnd, GWL_STYLE, lpss->styleNew);
2053 TREEVIEW_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
2055 TREEVIEW_INFO *infoPtr;
2060 TRACE("wnd %x\n",hwnd);
2061 /* allocate memory for info structure */
2062 infoPtr = (TREEVIEW_INFO *) COMCTL32_Alloc (sizeof(TREEVIEW_INFO));
2064 SetWindowLongA( hwnd, 0, (DWORD)infoPtr);
2066 if (infoPtr == NULL) {
2067 ERR("could not allocate info memory!\n");
2071 if ((TREEVIEW_INFO*) GetWindowLongA( hwnd, 0) != infoPtr) {
2072 ERR("pointer assignment error!\n");
2078 /* set default settings */
2079 infoPtr->uInternalStatus=0;
2080 infoPtr->uNumItems=0;
2081 infoPtr->clrBk = GetSysColor (COLOR_WINDOW);
2082 infoPtr->clrText = GetSysColor (COLOR_BTNTEXT);
2085 infoPtr->uIndent = 15;
2086 infoPtr->himlNormal = NULL;
2087 infoPtr->himlState = NULL;
2088 infoPtr->uItemHeight = -1;
2089 GetTextMetricsA (hdc, &tm);
2090 infoPtr->hFont = GetStockObject (DEFAULT_GUI_FONT);
2091 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
2092 logFont.lfWeight=FW_BOLD;
2093 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
2095 infoPtr->items = NULL;
2096 infoPtr->selectedItem=0;
2097 infoPtr->clrText=-1; /* use system color */
2098 infoPtr->dropItem=0;
2099 infoPtr->pCallBackSort=NULL;
2102 infoPtr->hwndNotify = GetParent32 (hwnd);
2103 infoPtr->bTransparent = ( GetWindowLongA( hwnd, GWL_STYLE) & TBSTYLE_FLAT);
2106 infoPtr->hwndToolTip=0;
2107 if (!( GetWindowLongA( hwnd, GWL_STYLE) & TVS_NOTOOLTIPS)) { /* Create tooltip control */
2110 infoPtr->hwndToolTip =
2111 CreateWindowExA (0, TOOLTIPS_CLASSA, NULL, 0,
2112 CW_USEDEFAULT, CW_USEDEFAULT,
2113 CW_USEDEFAULT, CW_USEDEFAULT,
2116 /* Send NM_TOOLTIPSCREATED notification */
2117 if (infoPtr->hwndToolTip) {
2118 NMTOOLTIPSCREATED nmttc;
2120 nmttc.hdr.hwndFrom = hwnd;
2121 nmttc.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2122 nmttc.hdr.code = NM_TOOLTIPSCREATED;
2123 nmttc.hwndToolTips = infoPtr->hwndToolTip;
2125 SendMessageA (GetParent (hwnd), WM_NOTIFY,
2126 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmttc);
2129 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
2130 ti.cbSize = sizeof(TTTOOLINFOA);
2131 ti.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_TRANSPARENT ;
2134 ti.lpszText = "Test"; /* LPSTR_TEXTCALLBACK; */
2135 SetRectEmpty (&ti.rect);
2137 SendMessageA (infoPtr->hwndToolTip, TTM_ADDTOOLA, 0, (LPARAM)&ti);
2140 infoPtr->hwndEdit = CreateWindowExA (
2144 WS_CHILD | WS_BORDER | ES_AUTOHSCROLL |
2145 ES_WANTRETURN | ES_LEFT,
2148 0,0,0); /* FIXME: (HMENU)IDTVEDIT,pcs->hInstance,0);*/
2150 SendMessageA ( infoPtr->hwndEdit, WM_SETFONT, infoPtr->hFont, FALSE);
2151 infoPtr->wpEditOrig = (WNDPROC)SetWindowLongA (
2154 (LONG) TREEVIEW_Edit_SubclassProc);
2156 ReleaseDC (hwnd, hdc);
2163 TREEVIEW_Destroy (HWND hwnd)
2165 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2168 TREEVIEW_RemoveTree (hwnd);
2169 if (infoPtr->Timer & TV_REFRESH_TIMER_SET)
2170 KillTimer (hwnd, TV_REFRESH_TIMER);
2171 if (infoPtr->hwndToolTip)
2172 DestroyWindow (infoPtr->hwndToolTip);
2174 COMCTL32_Free (infoPtr);
2180 TREEVIEW_Paint (HWND hwnd, WPARAM wParam, LPARAM lParam)
2186 hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
2187 TREEVIEW_Refresh (hwnd);
2189 EndPaint (hwnd, &ps);
2192 return DefWindowProcA (hwnd, WM_PAINT, wParam, lParam);
2196 TREEVIEW_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2198 TREEVIEW_SendSimpleNotify (hwnd, NM_SETFOCUS);
2199 InvalidateRect(hwnd, NULL, FALSE);
2204 TREEVIEW_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2206 TREEVIEW_SendSimpleNotify (hwnd, NM_KILLFOCUS);
2207 InvalidateRect(hwnd, NULL, FALSE);
2212 TREEVIEW_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
2214 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2215 HBRUSH hBrush = CreateSolidBrush (infoPtr->clrBk);
2219 GetClientRect (hwnd, &rect);
2220 FillRect ((HDC)wParam, &rect, hBrush);
2221 DeleteObject (hBrush);
2237 TREEVIEW_SendSimpleNotify (HWND hwnd, UINT code)
2242 nmhdr.hwndFrom = hwnd;
2243 nmhdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2246 return (BOOL) SendMessageA (GetParent (hwnd), WM_NOTIFY,
2247 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
2253 TREEVIEW_SendTreeviewNotify (HWND hwnd, UINT code, UINT action,
2254 HTREEITEM oldItem, HTREEITEM newItem)
2257 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2259 TREEVIEW_ITEM *wineItem;
2261 TRACE("code:%x action:%x olditem:%x newitem:%x\n",
2262 code,action,(INT)oldItem,(INT)newItem);
2263 nmhdr.hdr.hwndFrom = hwnd;
2264 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2265 nmhdr.hdr.code = code;
2266 nmhdr.action = action;
2268 wineItem=& infoPtr->items[(INT)oldItem];
2269 nmhdr.itemOld.mask = wineItem->mask;
2270 nmhdr.itemOld.hItem = wineItem->hItem;
2271 nmhdr.itemOld.state = wineItem->state;
2272 nmhdr.itemOld.stateMask = wineItem->stateMask;
2273 nmhdr.itemOld.iImage = wineItem->iImage;
2274 nmhdr.itemOld.pszText = wineItem->pszText;
2275 nmhdr.itemOld.cchTextMax= wineItem->cchTextMax;
2276 nmhdr.itemOld.iImage = wineItem->iImage;
2277 nmhdr.itemOld.iSelectedImage = wineItem->iSelectedImage;
2278 nmhdr.itemOld.cChildren = wineItem->cChildren;
2279 nmhdr.itemOld.lParam = wineItem->lParam;
2283 wineItem=& infoPtr->items[(INT)newItem];
2284 nmhdr.itemNew.mask = wineItem->mask;
2285 nmhdr.itemNew.hItem = wineItem->hItem;
2286 nmhdr.itemNew.state = wineItem->state;
2287 nmhdr.itemNew.stateMask = wineItem->stateMask;
2288 nmhdr.itemNew.iImage = wineItem->iImage;
2289 nmhdr.itemNew.pszText = wineItem->pszText;
2290 nmhdr.itemNew.cchTextMax= wineItem->cchTextMax;
2291 nmhdr.itemNew.iImage = wineItem->iImage;
2292 nmhdr.itemNew.iSelectedImage = wineItem->iSelectedImage;
2293 nmhdr.itemNew.cChildren = wineItem->cChildren;
2294 nmhdr.itemNew.lParam = wineItem->lParam;
2300 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2301 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2306 TREEVIEW_SendTreeviewDnDNotify (HWND hwnd, UINT code, HTREEITEM dragItem,
2309 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2311 TREEVIEW_ITEM *wineItem;
2313 TRACE("code:%x dragitem:%x\n", code,(INT)dragItem);
2315 nmhdr.hdr.hwndFrom = hwnd;
2316 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2317 nmhdr.hdr.code = code;
2319 wineItem=& infoPtr->items[(INT)dragItem];
2320 nmhdr.itemNew.mask = wineItem->mask;
2321 nmhdr.itemNew.hItem = wineItem->hItem;
2322 nmhdr.itemNew.state = wineItem->state;
2323 nmhdr.itemNew.lParam = wineItem->lParam;
2325 nmhdr.ptDrag.x = pt.x;
2326 nmhdr.ptDrag.y = pt.y;
2328 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2329 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2336 TREEVIEW_SendDispInfoNotify (HWND hwnd, TREEVIEW_ITEM *wineItem,
2337 UINT code, UINT what)
2343 TRACE("item %d, action %x, state %d\n",
2344 (INT)wineItem->hItem,
2346 (INT)wineItem->state);
2348 tvdi.hdr.hwndFrom = hwnd;
2349 tvdi.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2350 tvdi.hdr.code = code;
2351 tvdi.item.mask = what;
2352 tvdi.item.hItem = wineItem->hItem;
2353 tvdi.item.state = wineItem->state;
2354 tvdi.item.lParam = wineItem->lParam;
2355 tvdi.item.pszText = COMCTL32_Alloc (128*sizeof(char));
2356 buf = tvdi.item.pszText;
2358 retval=(BOOL)SendMessageA (
2361 (WPARAM)tvdi.hdr.idFrom,
2364 if (what & TVIF_TEXT) {
2365 wineItem->pszText = tvdi.item.pszText;
2366 if (buf==tvdi.item.pszText) {
2367 wineItem->cchTextMax = 128;
2369 TRACE("user-supplied buffer\n");
2370 COMCTL32_Free (buf);
2371 wineItem->cchTextMax = 0;
2374 if (what & TVIF_SELECTEDIMAGE)
2375 wineItem->iSelectedImage = tvdi.item.iSelectedImage;
2376 if (what & TVIF_IMAGE)
2377 wineItem->iImage = tvdi.item.iImage;
2378 if (what & TVIF_CHILDREN)
2379 wineItem->cChildren = tvdi.item.cChildren;
2387 TREEVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
2390 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2391 NMTVCUSTOMDRAW nmcdhdr;
2392 LPNMCUSTOMDRAW nmcd;
2394 TRACE("drawstage:%lx hdc:%x\n", dwDrawStage, hdc);
2396 nmcd= & nmcdhdr.nmcd;
2397 nmcd->hdr.hwndFrom = hwnd;
2398 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2399 nmcd->hdr.code = NM_CUSTOMDRAW;
2400 nmcd->dwDrawStage= dwDrawStage;
2402 nmcd->rc.left = rc.left;
2403 nmcd->rc.right = rc.right;
2404 nmcd->rc.bottom = rc.bottom;
2405 nmcd->rc.top = rc.top;
2406 nmcd->dwItemSpec = 0;
2407 nmcd->uItemState = 0;
2408 nmcd->lItemlParam= 0;
2409 nmcdhdr.clrText = infoPtr->clrText;
2410 nmcdhdr.clrTextBk= infoPtr->clrBk;
2413 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2414 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2420 /* FIXME: need to find out when the flags in uItemState need to be set */
2423 TREEVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
2424 TREEVIEW_ITEM *wineItem, UINT uItemDrawState)
2426 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2427 NMTVCUSTOMDRAW nmcdhdr;
2428 LPNMCUSTOMDRAW nmcd;
2429 DWORD dwDrawStage,dwItemSpec;
2432 dwDrawStage=CDDS_ITEM | uItemDrawState;
2433 dwItemSpec=(DWORD)wineItem->hItem;
2435 if (wineItem->hItem==infoPtr->selectedItem) uItemState|=CDIS_SELECTED;
2436 if (wineItem->hItem==infoPtr->focusItem) uItemState|=CDIS_FOCUS;
2437 if (wineItem->hItem==infoPtr->hotItem) uItemState|=CDIS_HOT;
2439 nmcd= & nmcdhdr.nmcd;
2440 nmcd->hdr.hwndFrom = hwnd;
2441 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2442 nmcd->hdr.code = NM_CUSTOMDRAW;
2443 nmcd->dwDrawStage= dwDrawStage;
2445 nmcd->rc.left = wineItem->rect.left;
2446 nmcd->rc.right = wineItem->rect.right;
2447 nmcd->rc.bottom = wineItem->rect.bottom;
2448 nmcd->rc.top = wineItem->rect.top;
2449 nmcd->dwItemSpec = dwItemSpec;
2450 nmcd->uItemState = uItemState;
2451 nmcd->lItemlParam= wineItem->lParam;
2453 nmcdhdr.clrText = infoPtr->clrText;
2454 nmcdhdr.clrTextBk= infoPtr->clrBk;
2455 nmcdhdr.iLevel = wineItem->iLevel;
2457 TRACE("drawstage:%lx hdc:%x item:%lx, itemstate:%x\n",
2458 dwDrawStage, hdc, dwItemSpec, uItemState);
2460 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2461 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2466 /* Note:If the specified item is the child of a collapsed parent item,
2467 the parent's list of child items is (recursively) expanded to reveal the
2468 specified item. This is mentioned for TREEVIEW_SelectItem; don't
2469 know if it also applies here.
2473 TREEVIEW_Expand (HWND hwnd, WPARAM wParam, LPARAM lParam)
2475 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2476 TREEVIEW_ITEM *wineItem;
2480 flag = (UINT) wParam;
2481 expand = (INT) lParam;
2483 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2487 if (!wineItem->cChildren)
2490 TRACE("For (%s) flags:%x item:%d state:%d\n",
2496 if (wineItem->cChildren==I_CHILDRENCALLBACK) {
2497 FIXME("we don't handle I_CHILDRENCALLBACK yet\n");
2501 if (flag == TVE_TOGGLE) { /* FIXME: check exact behaviour here */
2502 flag &= ~TVE_TOGGLE; /* ie: bitwise ops or 'case' ops */
2503 if (wineItem->state & TVIS_EXPANDED)
2504 flag |= TVE_COLLAPSE;
2511 case TVE_COLLAPSERESET:
2512 TRACE(" case TVE_COLLAPSERESET\n");
2513 if (!wineItem->state & TVIS_EXPANDED)
2516 wineItem->state &= ~(TVIS_EXPANDEDONCE | TVIS_EXPANDED);
2517 TREEVIEW_RemoveAllChildren (hwnd, wineItem);
2521 TRACE(" case TVE_COLLAPSE\n");
2522 if (!wineItem->state & TVIS_EXPANDED)
2525 wineItem->state &= ~TVIS_EXPANDED;
2529 TRACE(" case TVE_EXPAND\n");
2530 if (wineItem->state & TVIS_EXPANDED)
2533 TRACE(" is not expanded...\n");
2535 if (!(wineItem->state & TVIS_EXPANDEDONCE))
2537 TRACE(" and has never been expanded...\n");
2538 wineItem->state |= TVIS_EXPANDED;
2540 /* this item has never been expanded */
2541 if (TREEVIEW_SendTreeviewNotify (
2548 TRACE(" TVN_ITEMEXPANDING returned TRUE, exiting...\n");
2553 * Since the TVN_ITEMEXPANDING message may has caused the parent to
2554 * insert new items which in turn may have cause items placeholder
2555 * reallocation, I reassign the current item pointer so we have
2556 * something valid to work with...
2557 * However, this should not be necessary,
2558 * investigation required in TREEVIEW_InsertItemA
2560 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2564 "Catastropic situation, cannot retreive item #%d\n",
2569 wineItem->state |= TVIS_EXPANDEDONCE;
2570 TRACE(" TVN_ITEMEXPANDING sent...\n");
2572 TREEVIEW_SendTreeviewNotify (
2579 TRACE(" TVN_ITEMEXPANDED sent...\n");
2584 /* this item has already been expanded */
2585 wineItem->state |= TVIS_EXPANDED;
2589 case TVE_EXPANDPARTIAL:
2590 TRACE(" case TVE_EXPANDPARTIAL\n");
2591 FIXME("TVE_EXPANDPARTIAL not implemented\n");
2592 wineItem->state ^=TVIS_EXPANDED;
2593 wineItem->state |=TVIS_EXPANDEDONCE;
2597 TRACE("Exiting, Item %d state is now %d...\n",
2601 TREEVIEW_QueueRefresh (hwnd);
2607 static TREEVIEW_ITEM *
2608 TREEVIEW_HitTestPoint (HWND hwnd, POINT pt)
2610 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2611 TREEVIEW_ITEM *wineItem;
2614 GetClientRect (hwnd, &rect);
2616 if (!infoPtr->firstVisible) return NULL;
2618 wineItem=&infoPtr->items [(INT)infoPtr->firstVisible];
2620 while ((wineItem!=NULL) && (pt.y > wineItem->rect.bottom))
2621 wineItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
2633 TREEVIEW_HitTest (HWND hwnd, LPARAM lParam)
2635 LPTVHITTESTINFO lpht=(LPTVHITTESTINFO) lParam;
2636 TREEVIEW_ITEM *wineItem;
2640 GetClientRect (hwnd, &rect);
2644 if (x < rect.left) status|=TVHT_TOLEFT;
2645 if (x > rect.right) status|=TVHT_TORIGHT;
2646 if (y < rect.top ) status|=TVHT_ABOVE;
2647 if (y > rect.bottom) status|=TVHT_BELOW;
2654 wineItem=TREEVIEW_HitTestPoint (hwnd, lpht->pt);
2656 lpht->flags=TVHT_NOWHERE;
2660 /* FIXME: implement other flags
2661 * Assign the appropriate flags depending on the click location
2662 * Intitialize flags before to "|=" it...
2666 if (x < wineItem->expandBox.left)
2668 lpht->flags |= TVHT_ONITEMINDENT;
2670 else if ( ( x >= wineItem->expandBox.left) &&
2671 ( x <= wineItem->expandBox.right))
2673 lpht->flags |= TVHT_ONITEMBUTTON;
2675 else if (x < wineItem->rect.right)
2677 lpht->flags |= TVHT_ONITEMLABEL;
2681 lpht->flags|=TVHT_ONITEMRIGHT;
2684 lpht->hItem=wineItem->hItem;
2686 return (LRESULT) wineItem->hItem;
2690 TREEVIEW_EndEditLabelNow (HWND hwnd, WPARAM wParam, LPARAM lParam)
2692 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2693 TREEVIEW_ITEM *editedItem = TREEVIEW_ValidItem (infoPtr, infoPtr->editItem);
2694 BOOL bRevert = (BOOL)wParam;
2695 BOOL bReturn = ! bRevert;
2697 if ( ! (BOOL)wParam ) /* wParam is set to true to cancel the edition */
2699 if ( TREEVIEW_SendDispInfoNotify( /* return true to cancel edition */
2710 if (bRevert == FALSE) /* Apply the changes */
2713 int iLength = GetWindowTextA(infoPtr->hwndEdit, tmpText, 1023);
2718 ERR("Problem retreiving new item label.");
2720 else if (iLength >= 1023)
2723 "Insuficient space to retrieve new item label, new label ignored.");
2727 if (strcmp( tmpText, editedItem->pszText ) == 0)
2728 /* Do nothing if the label has not changed */
2732 LPSTR tmpLabel = COMCTL32_Alloc( iLength+1 );
2734 if ( tmpLabel == NULL )
2736 "OutOfMemory, cannot allocate space for label");
2739 COMCTL32_Free(editedItem->pszText);
2740 editedItem->pszText = tmpLabel;
2741 lstrcpyA( editedItem->pszText, tmpText);
2747 ShowWindow(infoPtr->hwndEdit, SW_HIDE);
2748 EnableWindow(infoPtr->hwndEdit, FALSE);
2749 infoPtr->editItem = 0;
2758 TREEVIEW_LButtonDoubleClick (HWND hwnd, WPARAM wParam, LPARAM lParam)
2760 TREEVIEW_ITEM *wineItem;
2764 pt.x = (INT)LOWORD(lParam);
2765 pt.y = (INT)HIWORD(lParam);
2768 wineItem=TREEVIEW_HitTestPoint (hwnd, pt);
2769 if (!wineItem) return 0;
2770 TRACE("item %d \n",(INT)wineItem->hItem);
2772 if (TREEVIEW_SendSimpleNotify (hwnd, NM_DBLCLK)!=TRUE) { /* FIXME!*/
2773 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) wineItem->hItem);
2780 TREEVIEW_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
2782 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2786 ht.pt.x = (INT)LOWORD(lParam);
2787 ht.pt.y = (INT)HIWORD(lParam);
2790 iItem=TREEVIEW_HitTest (hwnd, (LPARAM) &ht);
2791 TRACE("item %d \n",iItem);
2793 if (ht.flags & TVHT_ONITEMBUTTON) {
2794 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) iItem);
2798 infoPtr->uInternalStatus|=TV_LDRAG;
2805 TREEVIEW_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
2807 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2809 TREEVIEW_ITEM *editItem;
2812 ht.pt.x = (INT)LOWORD(lParam);
2813 ht.pt.y = (INT)HIWORD(lParam);
2817 /* Return true to cancel default behaviour */
2818 if ( TREEVIEW_SendSimpleNotify (hwnd, NM_CLICK) )
2822 iItem = TREEVIEW_HitTest (hwnd, (LPARAM) &ht);
2826 editItem = TREEVIEW_ValidItem(infoPtr, (HTREEITEM)iItem);
2828 infoPtr->uInternalStatus &= ~(TV_LDRAG | TV_LDRAGGING);
2831 * If the style allow editing and the node is already selected
2832 * and the click occured on the item label...
2834 if ( ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_EDITLABELS ) &&
2835 ( editItem->state & TVIS_SELECTED ) &&
2836 ( ht.flags & TVHT_ONITEMLABEL ))
2838 if ( infoPtr->editItem == 0 ) /* If we are not curently editing */
2840 if ( TREEVIEW_SendDispInfoNotify( /* Return true to cancel edition */
2849 TRACE("Edit started for %s.\n", editItem->pszText);
2850 infoPtr->editItem = editItem->hItem;
2855 editItem->text.left - 2,
2856 editItem->text.top - 1,
2857 editItem->text.right - editItem->text.left + 20 ,
2858 editItem->text.bottom - editItem->text.top + 3,
2861 SetWindowTextA( infoPtr->hwndEdit, editItem->pszText );
2862 SendMessageA ( infoPtr->hwndEdit, EM_SETSEL, 0, -1 );
2863 SetFocus ( infoPtr->hwndEdit);
2864 ShowWindow ( infoPtr->hwndEdit, SW_SHOW);
2867 else if ( infoPtr->editItem != 0 ) /* If we are curently editing */
2869 TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
2871 else if ( ht.flags & (TVHT_ONITEMLABEL | TVHT_ONITEMICON))
2873 TREEVIEW_DoSelectItem (
2885 TREEVIEW_RButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
2887 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2890 infoPtr->uInternalStatus|=TV_RDRAG;
2895 TREEVIEW_RButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
2897 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2900 if (TREEVIEW_SendSimpleNotify (hwnd, NM_RCLICK)) return 0;
2901 infoPtr->uInternalStatus&= ~(TV_RDRAG | TV_RDRAGGING);
2907 TREEVIEW_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
2909 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2910 TREEVIEW_ITEM *hotItem;
2913 pt.x=(INT) LOWORD (lParam);
2914 pt.y=(INT) HIWORD (lParam);
2915 hotItem=TREEVIEW_HitTestPoint (hwnd, pt);
2916 if (!hotItem) return 0;
2917 infoPtr->focusItem=hotItem->hItem;
2919 if ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_DISABLEDRAGDROP) return 0;
2921 if (infoPtr->uInternalStatus & TV_LDRAG) {
2922 TREEVIEW_SendTreeviewDnDNotify (hwnd, TVN_BEGINDRAG, hotItem->hItem, pt);
2923 infoPtr->uInternalStatus &= ~TV_LDRAG;
2924 infoPtr->uInternalStatus |= TV_LDRAGGING;
2925 infoPtr->dropItem=hotItem->hItem;
2929 if (infoPtr->uInternalStatus & TV_RDRAG) {
2930 TREEVIEW_SendTreeviewDnDNotify (hwnd, TVN_BEGINRDRAG, hotItem->hItem, pt);
2931 infoPtr->uInternalStatus &= ~TV_RDRAG;
2932 infoPtr->uInternalStatus |= TV_RDRAGGING;
2933 infoPtr->dropItem=hotItem->hItem;
2942 TREEVIEW_CreateDragImage (HWND hwnd, WPARAM wParam, LPARAM lParam)
2944 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2945 TREEVIEW_ITEM *dragItem;
2949 HBITMAP hbmp,hOldbmp;
2956 if (!(infoPtr->himlNormal)) return 0;
2957 dragItem=TREEVIEW_ValidItem (infoPtr, (HTREEITEM) lParam);
2959 if (!dragItem) return 0;
2960 itemtxt=dragItem->pszText;
2962 hwtop=GetDesktopWindow ();
2963 htopdc= GetDC (hwtop);
2964 hdc=CreateCompatibleDC (htopdc);
2966 hOldFont=SelectObject (hdc, infoPtr->hFont);
2967 GetTextExtentPoint32A (hdc, itemtxt, lstrlenA (itemtxt), &size);
2968 TRACE("%d %d %s %d\n",size.cx,size.cy,itemtxt,lstrlenA(itemtxt));
2969 hbmp=CreateCompatibleBitmap (htopdc, size.cx, size.cy);
2970 hOldbmp=SelectObject (hdc, hbmp);
2972 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &cy);
2974 if (cy>size.cy) size.cy=cy;
2976 infoPtr->dragList=ImageList_Create (size.cx, size.cy, ILC_COLOR, 10, 10);
2977 ImageList_Draw (infoPtr->himlNormal, dragItem->iImage, hdc, 0, 0, ILD_NORMAL);
2980 ImageList_GetImageInfo (infoPtr->himlNormal, dragItem->hItem, &iminfo);
2981 ImageList_AddMasked (infoPtr->dragList, iminfo.hbmImage, CLR_DEFAULT);
2984 /* draw item text */
2986 SetRect (&rc, cx, 0, size.cx,size.cy);
2987 DrawTextA (hdc, itemtxt, lstrlenA (itemtxt), &rc, DT_LEFT);
2988 SelectObject (hdc, hOldFont);
2989 SelectObject (hdc, hOldbmp);
2991 ImageList_Add (infoPtr->dragList, hbmp, 0);
2994 DeleteObject (hbmp);
2995 ReleaseDC (hwtop, htopdc);
2997 return (LRESULT)infoPtr->dragList;
3002 TREEVIEW_DoSelectItem (HWND hwnd, INT action, HTREEITEM newSelect, INT cause)
3005 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3006 TREEVIEW_ITEM *prevItem,*wineItem;
3009 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)newSelect);
3011 TRACE("Entering item %d, flag %x, cause %x, state %d\n",
3017 if ( (wineItem) && (wineItem->parent))
3020 * If the item has a collapse parent expand the parent so he
3021 * can expose the item
3023 TREEVIEW_ITEM *parentItem = TREEVIEW_ValidItem (infoPtr, wineItem->parent);
3024 if ( !(parentItem->state & TVIS_EXPANDED))
3025 TREEVIEW_Expand (hwnd, TVE_EXPAND, (LPARAM) wineItem->parent);
3031 prevSelect=(INT)infoPtr->selectedItem;
3033 if ((HTREEITEM)prevSelect==newSelect)
3036 prevItem= TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect);
3039 if (TREEVIEW_SendTreeviewNotify(
3043 (HTREEITEM)prevSelect,
3044 (HTREEITEM)newSelect))
3045 return FALSE; /* FIXME: OK? */
3048 prevItem->state &= ~TVIS_SELECTED;
3050 wineItem->state |= TVIS_SELECTED;
3052 infoPtr->selectedItem=(HTREEITEM)newSelect;
3054 TREEVIEW_SendTreeviewNotify(
3058 (HTREEITEM)prevSelect,
3059 (HTREEITEM)newSelect);
3063 case TVGN_DROPHILITE:
3064 prevItem= TREEVIEW_ValidItem (infoPtr, infoPtr->dropItem);
3067 prevItem->state &= ~TVIS_DROPHILITED;
3069 infoPtr->dropItem=(HTREEITEM)newSelect;
3072 wineItem->state |=TVIS_DROPHILITED;
3076 case TVGN_FIRSTVISIBLE:
3077 FIXME("FIRSTVISIBLE not implemented\n");
3081 TREEVIEW_QueueRefresh (hwnd);
3083 TRACE("Leaving state %d\n", wineItem->state);
3087 /* FIXME: handle NM_KILLFocus enzo */
3089 TREEVIEW_SelectItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
3092 return TREEVIEW_DoSelectItem (hwnd, wParam, (HTREEITEM) lParam, TVC_UNKNOWN);
3099 TREEVIEW_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
3102 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3104 TRACE("%x\n",infoPtr->hFont);
3105 return infoPtr->hFont;
3109 TREEVIEW_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
3112 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3115 HFONT hFont, hOldFont;
3119 TRACE("%x %lx\n",wParam, lParam);
3121 infoPtr->hFont = (HFONT)wParam;
3123 hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
3125 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
3126 logFont.lfWeight=FW_BOLD;
3127 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
3130 hOldFont = SelectObject (hdc, hFont);
3131 GetTextMetricsA (hdc, &tm);
3132 height= tm.tmHeight + tm.tmExternalLeading;
3133 if (height>infoPtr->uRealItemHeight)
3134 infoPtr->uRealItemHeight=height;
3135 SelectObject (hdc, hOldFont);
3139 TREEVIEW_QueueRefresh (hwnd);
3147 TREEVIEW_VScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
3150 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3153 TRACE("wp %x, lp %lx\n", wParam, lParam);
3154 if (!infoPtr->uInternalStatus & TV_VSCROLL) return FALSE;
3156 switch (LOWORD (wParam)) {
3158 if (!infoPtr->cy) return FALSE;
3159 infoPtr->cy -= infoPtr->uRealItemHeight;
3160 if (infoPtr->cy < 0) infoPtr->cy=0;
3163 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3164 if (infoPtr->cy == maxHeight) return FALSE;
3165 infoPtr->cy += infoPtr->uRealItemHeight;
3166 if (infoPtr->cy > maxHeight)
3167 infoPtr->cy = maxHeight;
3170 if (!infoPtr->cy) return FALSE;
3171 infoPtr->cy -= infoPtr->uVisibleHeight;
3172 if (infoPtr->cy < 0) infoPtr->cy=0;
3175 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3176 if (infoPtr->cy == maxHeight) return FALSE;
3177 infoPtr->cy += infoPtr->uVisibleHeight;
3178 if (infoPtr->cy > maxHeight)
3179 infoPtr->cy = maxHeight;
3182 infoPtr->cy = HIWORD (wParam);
3187 TREEVIEW_QueueRefresh (hwnd);
3192 TREEVIEW_HScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
3194 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3197 TRACE("wp %lx, lp %x\n", lParam, wParam);
3199 if (!infoPtr->uInternalStatus & TV_HSCROLL) return FALSE;
3201 switch (LOWORD (wParam)) {
3203 if (!infoPtr->cx) return FALSE;
3204 infoPtr->cx -= infoPtr->uRealItemHeight;
3205 if (infoPtr->cx < 0) infoPtr->cx=0;
3208 maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
3209 if (infoPtr->cx == maxWidth) return FALSE;
3210 infoPtr->cx += infoPtr->uRealItemHeight; /*FIXME */
3211 if (infoPtr->cx > maxWidth)
3212 infoPtr->cx = maxWidth;
3215 if (!infoPtr->cx) return FALSE;
3216 infoPtr->cx -= infoPtr->uVisibleWidth;
3217 if (infoPtr->cx < 0) infoPtr->cx=0;
3220 maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
3221 if (infoPtr->cx == maxWidth) return FALSE;
3222 infoPtr->cx += infoPtr->uVisibleWidth;
3223 if (infoPtr->cx > maxWidth)
3224 infoPtr->cx = maxWidth;
3227 infoPtr->cx = HIWORD (wParam);
3232 TREEVIEW_QueueRefresh (hwnd);
3238 TREEVIEW_KeyDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
3240 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3241 HTREEITEM hNewSelection = 0;
3242 INT scrollNeeds = -1;
3243 INT cyChangeNeeds = -1;
3244 INT prevSelect = (INT)infoPtr->selectedItem;
3246 TREEVIEW_ITEM *prevItem =
3247 (prevSelect != 0 ) ?
3248 TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect) :
3251 TREEVIEW_ITEM *newItem = NULL;
3253 TRACE("%x %lx\n",wParam, lParam);
3255 if (prevSelect == 0)
3260 newItem=TREEVIEW_GetPrevListItem (infoPtr, prevItem);
3263 newItem=& infoPtr->items[(INT)infoPtr->TopRootItem];
3265 hNewSelection = newItem->hItem;
3267 if (! newItem->visible)
3268 scrollNeeds = SB_LINEUP;
3273 newItem=TREEVIEW_GetNextListItem (infoPtr, prevItem);
3278 hNewSelection = newItem->hItem;
3280 if (! newItem->visible)
3281 scrollNeeds = SB_LINEDOWN;
3286 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem];
3287 hNewSelection = newItem->hItem;
3292 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem];
3293 newItem = TREEVIEW_GetLastListItem (infoPtr, newItem);
3294 hNewSelection = newItem->hItem;
3296 if (! newItem->visible)
3297 cyChangeNeeds = infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3302 if ( (prevItem->cChildren > 0) && (prevItem->state & TVIS_EXPANDED) )
3304 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect );
3306 else if ((INT)prevItem->parent)
3308 newItem = (& infoPtr->items[(INT)prevItem->parent]);
3309 if (! newItem->visible)
3310 /* FIXME find a way to make this item the first visible... */
3313 hNewSelection = newItem->hItem;
3319 if ( ( prevItem->cChildren > 0) ||
3320 ( prevItem->cChildren == I_CHILDRENCALLBACK))
3322 if (! (prevItem->state & TVIS_EXPANDED))
3323 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect );
3326 newItem = (& infoPtr->items[(INT)prevItem->firstChild]);
3327 hNewSelection = newItem->hItem;
3334 if (! (prevItem->state & TVIS_EXPANDED))
3335 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect );
3339 if (prevItem->state & TVIS_EXPANDED)
3340 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect );
3345 newItem=TREEVIEW_GetListItem(
3348 -1*(TREEVIEW_GetVisibleCount(hwnd,0,0)-3));
3352 hNewSelection = newItem->hItem;
3354 if (! newItem->visible)
3355 scrollNeeds = SB_PAGEUP;
3360 newItem=TREEVIEW_GetListItem(
3363 TREEVIEW_GetVisibleCount(hwnd,0,0)-3);
3368 hNewSelection = newItem->hItem;
3370 if (! newItem->visible)
3371 scrollNeeds = SB_PAGEDOWN;
3380 FIXME("%x not implemented\n", wParam);
3387 This works but does not send notification...
3389 prevItem->state &= ~TVIS_SELECTED;
3390 newItem->state |= TVIS_SELECTED;
3391 infoPtr->selectedItem = hNewSelection;
3392 TREEVIEW_QueueRefresh (hwnd);
3395 if ( TREEVIEW_DoSelectItem(
3398 (HTREEITEM)hNewSelection,
3401 /* If selection change is allowed for the new item, perform scrolling */
3402 if (scrollNeeds != -1)
3403 TREEVIEW_VScroll(hwnd, scrollNeeds, 0);
3405 if (cyChangeNeeds != -1)
3406 infoPtr->cy = cyChangeNeeds;
3408 /* FIXME: Something happen in the load the in the two weeks before
3409 april 1st 1999 which makes this SetFocus mandatory otherwise, the focus
3410 is lost... However the SetFocus should not be required...*/
3421 TREEVIEW_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3424 case TVM_INSERTITEMA:
3425 return TREEVIEW_InsertItemA (hwnd, wParam, lParam);
3427 case TVM_INSERTITEMW:
3428 FIXME("Unimplemented msg TVM_INSERTITEM32W\n");
3431 case TVM_DELETEITEM:
3432 return TREEVIEW_DeleteItem (hwnd, wParam, lParam);
3435 return TREEVIEW_Expand (hwnd, wParam, lParam);
3437 case TVM_GETITEMRECT:
3438 return TREEVIEW_GetItemRect (hwnd, wParam, lParam);
3441 return TREEVIEW_GetCount (hwnd, wParam, lParam);
3444 return TREEVIEW_GetIndent (hwnd);
3447 return TREEVIEW_SetIndent (hwnd, wParam);
3449 case TVM_GETIMAGELIST:
3450 return TREEVIEW_GetImageList (hwnd, wParam, lParam);
3452 case TVM_SETIMAGELIST:
3453 return TREEVIEW_SetImageList (hwnd, wParam, lParam);
3455 case TVM_GETNEXTITEM:
3456 return TREEVIEW_GetNextItem (hwnd, wParam, lParam);
3458 case TVM_SELECTITEM:
3459 return TREEVIEW_SelectItem (hwnd, wParam, lParam);
3462 return TREEVIEW_GetItemA (hwnd, wParam, lParam);
3465 FIXME("Unimplemented msg TVM_GETITEM32W\n");
3469 return TREEVIEW_SetItemA (hwnd, wParam, lParam);
3472 FIXME("Unimplemented msg TVM_SETITEMW\n");
3475 case TVM_EDITLABELA:
3476 FIXME("Unimplemented msg TVM_EDITLABEL32A \n");
3479 case TVM_EDITLABELW:
3480 FIXME("Unimplemented msg TVM_EDITLABEL32W \n");
3483 case TVM_GETEDITCONTROL:
3484 return TREEVIEW_GetEditControl (hwnd);
3486 case TVM_GETVISIBLECOUNT:
3487 return TREEVIEW_GetVisibleCount (hwnd, wParam, lParam);
3490 return TREEVIEW_HitTest (hwnd, lParam);
3492 case TVM_CREATEDRAGIMAGE:
3493 return TREEVIEW_CreateDragImage (hwnd, wParam, lParam);
3495 case TVM_SORTCHILDREN:
3496 return TREEVIEW_SortChildren (hwnd, wParam, lParam);
3498 case TVM_ENSUREVISIBLE:
3499 FIXME("Unimplemented msg TVM_ENSUREVISIBLE\n");
3502 case TVM_SORTCHILDRENCB:
3503 return TREEVIEW_SortChildrenCB(hwnd, wParam, lParam);
3505 case TVM_ENDEDITLABELNOW:
3506 return TREEVIEW_EndEditLabelNow (hwnd, wParam, lParam);
3508 case TVM_GETISEARCHSTRINGA:
3509 FIXME("Unimplemented msg TVM_GETISEARCHSTRING32A\n");
3512 case TVM_GETISEARCHSTRINGW:
3513 FIXME("Unimplemented msg TVM_GETISEARCHSTRING32W\n");
3516 case TVM_GETTOOLTIPS:
3517 return TREEVIEW_GetToolTips (hwnd);
3519 case TVM_SETTOOLTIPS:
3520 return TREEVIEW_SetToolTips (hwnd, wParam);
3522 case TVM_SETINSERTMARK:
3523 FIXME("Unimplemented msg TVM_SETINSERTMARK\n");
3526 case TVM_SETITEMHEIGHT:
3527 return TREEVIEW_SetItemHeight (hwnd, wParam);
3529 case TVM_GETITEMHEIGHT:
3530 return TREEVIEW_GetItemHeight (hwnd);
3532 case TVM_SETBKCOLOR:
3533 return TREEVIEW_SetBkColor (hwnd, wParam, lParam);
3535 case TVM_SETTEXTCOLOR:
3536 return TREEVIEW_SetTextColor (hwnd, wParam, lParam);
3538 case TVM_GETBKCOLOR:
3539 return TREEVIEW_GetBkColor (hwnd);
3541 case TVM_GETTEXTCOLOR:
3542 return TREEVIEW_GetTextColor (hwnd);
3544 case TVM_SETSCROLLTIME:
3545 FIXME("Unimplemented msg TVM_SETSCROLLTIME\n");
3548 case TVM_GETSCROLLTIME:
3549 FIXME("Unimplemented msg TVM_GETSCROLLTIME\n");
3552 case TVM_SETINSERTMARKCOLOR:
3553 FIXME("Unimplemented msg TVM_SETINSERTMARKCOLOR\n");
3556 case TVM_SETUNICODEFORMAT:
3557 FIXME("Unimplemented msg TVM_SETUNICODEFORMAT\n");
3560 case TVM_GETUNICODEFORMAT:
3561 FIXME("Unimplemented msg TVM_GETUNICODEFORMAT\n");
3565 return TREEVIEW_Command (hwnd, wParam, lParam);
3568 return TREEVIEW_Create (hwnd, wParam, lParam);
3571 return TREEVIEW_Destroy (hwnd);
3573 /* case WM_ENABLE: */
3576 return TREEVIEW_EraseBackground (hwnd, wParam, lParam);
3579 return DLGC_WANTARROWS | DLGC_WANTCHARS;
3582 return TREEVIEW_Paint (hwnd, wParam, lParam);
3585 return TREEVIEW_GetFont (hwnd, wParam, lParam);
3588 return TREEVIEW_SetFont (hwnd, wParam, lParam);
3591 return TREEVIEW_KeyDown (hwnd, wParam, lParam);
3595 return TREEVIEW_SetFocus (hwnd, wParam, lParam);
3598 return TREEVIEW_KillFocus (hwnd, wParam, lParam);
3601 case WM_LBUTTONDOWN:
3602 return TREEVIEW_LButtonDown (hwnd, wParam, lParam);
3605 return TREEVIEW_LButtonUp (hwnd, wParam, lParam);
3607 case WM_LBUTTONDBLCLK:
3608 return TREEVIEW_LButtonDoubleClick (hwnd, wParam, lParam);
3610 case WM_RBUTTONDOWN:
3611 return TREEVIEW_RButtonDown (hwnd, wParam, lParam);
3614 return TREEVIEW_RButtonUp (hwnd, wParam, lParam);
3617 return TREEVIEW_MouseMove (hwnd, wParam, lParam);
3620 /* case WM_SYSCOLORCHANGE: */
3621 case WM_STYLECHANGED:
3622 return TREEVIEW_StyleChanged (hwnd, wParam, lParam);
3624 /* case WM_SETREDRAW: */
3627 return TREEVIEW_HandleTimer (hwnd, wParam, lParam);
3630 return TREEVIEW_Size (hwnd, wParam,lParam);
3633 return TREEVIEW_HScroll (hwnd, wParam, lParam);
3635 return TREEVIEW_VScroll (hwnd, wParam, lParam);
3638 TRACE ("drawItem\n");
3639 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
3642 if (uMsg >= WM_USER)
3643 FIXME("Unknown msg %04x wp=%08x lp=%08lx\n",
3644 uMsg, wParam, lParam);
3645 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
3652 TREEVIEW_Register (void)
3658 if (GlobalFindAtomA (WC_TREEVIEWA)) return;
3660 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
3661 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
3662 wndClass.lpfnWndProc = (WNDPROC)TREEVIEW_WindowProc;
3663 wndClass.cbClsExtra = 0;
3664 wndClass.cbWndExtra = sizeof(TREEVIEW_INFO *);
3665 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
3666 wndClass.hbrBackground = 0;
3667 wndClass.lpszClassName = WC_TREEVIEWA;
3669 RegisterClassA (&wndClass);
3674 TREEVIEW_Unregister (void)
3676 if (GlobalFindAtomA (WC_TREEVIEWA))
3677 UnregisterClassA (WC_TREEVIEWA, (HINSTANCE)NULL);