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 happened 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.
48 #include "debugtools.h"
50 DEFAULT_DEBUG_CHANNEL(treeview)
52 /* ffs should be in <string.h>. */
54 /* Defines, since they do not need to return previous state, and nr
55 * has no side effects in this file.
57 #define tv_test_bit(nr,bf) (((LPBYTE)bf)[nr>>3]&(1<<(nr&7)))
58 #define tv_set_bit(nr,bf) ((LPBYTE)bf)[nr>>3]|=(1<<(nr&7))
59 #define tv_clear_bit(nr,bf) ((LPBYTE)bf)[nr>>3]&=~(1<<(nr&7))
62 #define TREEVIEW_GetInfoPtr(hwnd) \
63 ((TREEVIEW_INFO *) GetWindowLongA( hwnd, 0))
65 #define FOCUS_BORDER 3
68 TREEVIEW_SendSimpleNotify (HWND hwnd, UINT code);
70 TREEVIEW_SendTreeviewNotify (HWND hwnd, UINT code, UINT action,
71 HTREEITEM oldItem, HTREEITEM newItem);
73 TREEVIEW_SendTreeviewDnDNotify (HWND hwnd, UINT code, HTREEITEM dragItem,
76 TREEVIEW_SendDispInfoNotify (HWND hwnd, TREEVIEW_ITEM *wineItem,
77 UINT code, UINT what);
79 TREEVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
82 TREEVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
83 TREEVIEW_ITEM *tvItem, UINT uItemDrawState);
85 TREEVIEW_DoSelectItem (HWND hwnd, INT action, HTREEITEM newSelect, INT cause);
87 TREEVIEW_Refresh (HWND hwnd, HDC hdc);
89 static LRESULT CALLBACK
90 TREEVIEW_Edit_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam,
94 TREEVIEW_EditLabelA (HWND hwnd, WPARAM wParam, LPARAM lParam);
97 TREEVIEW_EndEditLabelNow (HWND hwnd, WPARAM wParam, LPARAM lParam);
102 /* helper functions. Work with the assumption that validity of operands
103 is checked beforehand, and that tree state is valid. */
105 /* FIXME: MS documentation says `GetNextVisibleItem' returns NULL
106 if not successfull. Probably only applies to dereferencing infoPtr
107 (i.e. we are offered a valid treeview structure)
108 and not whether there is a next `visible' child.
109 FIXME: check other failures.
112 /***************************************************************************
113 * This method returns the TREEVIEW_ITEM object given the handle
115 static TREEVIEW_ITEM* TREEVIEW_ValidItem(
116 TREEVIEW_INFO *infoPtr,
119 if ((!handle) || (handle>infoPtr->uMaxHandle))
122 if (tv_test_bit ((INT)handle, infoPtr->freeList))
125 return &infoPtr->items[(INT)handle];
128 /***************************************************************************
129 * This method returns the last expanded child item of a tree node
131 static TREEVIEW_ITEM *TREEVIEW_GetLastListItem(
132 TREEVIEW_INFO *infoPtr,
133 TREEVIEW_ITEM *tvItem)
135 TREEVIEW_ITEM *wineItem = tvItem;
138 * Get this item last sibling
140 while (wineItem->sibling)
141 wineItem=& infoPtr->items [(INT)wineItem->sibling];
144 * If the last sibling has expanded children, restart.
146 if ( ( wineItem->cChildren > 0 ) && ( wineItem->state & TVIS_EXPANDED) )
147 return TREEVIEW_GetLastListItem(
149 &(infoPtr->items[(INT)wineItem->firstChild]));
154 /***************************************************************************
155 * This method returns the previous physical item in the list not
156 * considering the tree hierarchy.
158 static TREEVIEW_ITEM *TREEVIEW_GetPrevListItem(
159 TREEVIEW_INFO *infoPtr,
160 TREEVIEW_ITEM *tvItem)
162 if (tvItem->upsibling)
165 * This item has a upsibling, get the last item. Since, GetLastListItem
166 * first looks at siblings, we must feed it with the first child.
168 TREEVIEW_ITEM *upItem = &infoPtr->items[(INT)tvItem->upsibling];
170 if ( ( upItem->cChildren > 0 ) && ( upItem->state & TVIS_EXPANDED) )
171 return TREEVIEW_GetLastListItem(
173 &infoPtr->items[(INT)upItem->firstChild]);
180 * this item does not have a upsibling, get the parent
183 return &infoPtr->items[(INT)tvItem->parent];
190 /***************************************************************************
191 * This method returns the next physical item in the treeview not
192 * considering the tree hierarchy.
194 static TREEVIEW_ITEM *TREEVIEW_GetNextListItem(
195 TREEVIEW_INFO *infoPtr,
196 TREEVIEW_ITEM *tvItem)
198 TREEVIEW_ITEM *wineItem = NULL;
201 * If this item has children and is expanded, return the first child
203 if ((tvItem->firstChild) && (tvItem->state & TVIS_EXPANDED))
204 return (& infoPtr->items[(INT)tvItem->firstChild]);
208 * try to get the sibling
211 return (& infoPtr->items[(INT)tvItem->sibling]);
214 * Otherwise, get the parent's sibling.
217 while (wineItem->parent) {
218 wineItem=& infoPtr->items [(INT)wineItem->parent];
219 if (wineItem->sibling)
220 return (& infoPtr->items [(INT)wineItem->sibling]);
226 /***************************************************************************
227 * This method returns the nth item starting at the given item. It returns
228 * the last item (or first) we we run out of items.
230 * Will scroll backward if count is <0.
231 * forward if count is >0.
233 static TREEVIEW_ITEM *TREEVIEW_GetListItem(
234 TREEVIEW_INFO *infoPtr,
235 TREEVIEW_ITEM *tvItem,
238 TREEVIEW_ITEM *previousItem = NULL;
239 TREEVIEW_ITEM *wineItem = tvItem;
244 /* Find count item downward */
245 while ((iter++ < count) && (wineItem != NULL))
247 /* Keep a pointer to the previous in case we ask for more than we got */
248 previousItem = wineItem;
249 wineItem = TREEVIEW_GetNextListItem(infoPtr, wineItem);
252 if (wineItem == NULL)
253 wineItem = previousItem;
257 /* Find count item upward */
258 while ((iter-- > count) && (wineItem != NULL))
260 /* Keep a pointer to the previous in case we ask for more than we got */
261 previousItem = wineItem;
262 wineItem = TREEVIEW_GetPrevListItem(infoPtr, wineItem);
265 if (wineItem == NULL)
266 wineItem = previousItem;
275 /***************************************************************************
278 static void TREEVIEW_RemoveAllChildren(
280 TREEVIEW_ITEM *parentItem)
282 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
283 TREEVIEW_ITEM *killItem;
286 kill=(INT)parentItem->firstChild;
288 tv_set_bit ( kill, infoPtr->freeList);
289 killItem=& infoPtr->items[kill];
290 if (killItem->pszText!=LPSTR_TEXTCALLBACKA)
291 COMCTL32_Free (killItem->pszText);
292 TREEVIEW_SendTreeviewNotify (hwnd, TVN_DELETEITEMA, 0, (HTREEITEM)kill, 0);
293 if (killItem->firstChild)
294 TREEVIEW_RemoveAllChildren (hwnd, killItem);
295 kill=(INT)killItem->sibling;
298 if (parentItem->cChildren>0) {
299 infoPtr->uNumItems -= parentItem->cChildren;
300 parentItem->firstChild = 0;
301 parentItem->cChildren = 0;
308 TREEVIEW_RemoveItem (HWND hwnd, TREEVIEW_ITEM *wineItem)
311 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
312 TREEVIEW_ITEM *parentItem, *upsiblingItem, *siblingItem;
315 iItem=(INT)wineItem->hItem;
316 tv_set_bit(iItem,infoPtr->freeList);
317 infoPtr->uNumItems--;
319 if (wineItem->pszText!=LPSTR_TEXTCALLBACKA)
320 COMCTL32_Free (wineItem->pszText);
322 TREEVIEW_SendTreeviewNotify (hwnd, TVN_DELETEITEMA, 0, (HTREEITEM)iItem, 0);
324 if (wineItem->firstChild)
325 TREEVIEW_RemoveAllChildren (hwnd,wineItem);
327 if (wineItem->parent) {
328 parentItem=& infoPtr->items [(INT)wineItem->parent];
329 switch (parentItem->cChildren) {
330 case I_CHILDRENCALLBACK:
331 FIXME("we don't handle I_CHILDRENCALLBACK yet\n");
334 parentItem->cChildren=0;
335 parentItem->firstChild=0;
338 parentItem->cChildren--;
339 if ((INT)parentItem->firstChild==iItem)
340 parentItem->firstChild=wineItem->sibling;
344 if (iItem==(INT)infoPtr->TopRootItem)
345 infoPtr->TopRootItem=(HTREEITEM)wineItem->sibling;
346 if (wineItem->upsibling) {
347 upsiblingItem=& infoPtr->items [(INT)wineItem->upsibling];
348 upsiblingItem->sibling=wineItem->sibling;
350 if (wineItem->sibling) {
351 siblingItem=& infoPtr->items [(INT)wineItem->sibling];
352 siblingItem->upsibling=wineItem->upsibling;
360 /* Note:TREEVIEW_RemoveTree doesn't remove infoPtr itself */
362 static void TREEVIEW_RemoveTree (HWND hwnd)
365 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
366 TREEVIEW_ITEM *killItem;
369 for (i = 1; i <= (INT)infoPtr->uMaxHandle; i++)
370 if (!tv_test_bit (i, infoPtr->freeList)) {
371 killItem = &infoPtr->items[i];
372 if (killItem->pszText != LPSTR_TEXTCALLBACKA)
373 COMCTL32_Free (killItem->pszText);
374 TREEVIEW_SendTreeviewNotify(hwnd, TVN_DELETEITEMA, 0,
377 if (infoPtr->uNumPtrsAlloced) {
378 COMCTL32_Free (infoPtr->items);
379 COMCTL32_Free (infoPtr->freeList);
380 infoPtr->uNumItems = 0;
381 infoPtr->uNumPtrsAlloced = 0;
382 infoPtr->uMaxHandle = 0;
383 infoPtr->TopRootItem = 0;
394 TREEVIEW_GetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
396 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
400 if ((INT)wParam == TVSIL_NORMAL)
401 return (LRESULT) infoPtr->himlNormal;
402 if ((INT)wParam == TVSIL_STATE)
403 return (LRESULT) infoPtr->himlState;
409 TREEVIEW_SetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
411 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
414 TRACE("%x,%lx\n", wParam, lParam);
415 switch ((INT)wParam) {
417 himlTemp = infoPtr->himlNormal;
418 infoPtr->himlNormal = (HIMAGELIST)lParam;
419 return (LRESULT)himlTemp;
422 himlTemp = infoPtr->himlState;
423 infoPtr->himlState = (HIMAGELIST)lParam;
424 return (LRESULT)himlTemp;
427 return (LRESULT)NULL;
433 TREEVIEW_SetItemHeight (HWND hwnd, WPARAM wParam)
435 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
436 INT cx,cy,prevHeight=infoPtr->uItemHeight;
440 infoPtr->uItemHeight=-1;
444 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &cy);
446 if (wParam>cy) cy=wParam;
447 infoPtr->uItemHeight=cy;
449 if (!( GetWindowLongA( hwnd, GWL_STYLE) & TVS_NONEVENHEIGHT))
450 infoPtr->uItemHeight = (INT) wParam & 0xfffffffe;
455 TREEVIEW_GetItemHeight (HWND hwnd)
457 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
460 return infoPtr->uItemHeight;
464 TREEVIEW_GetLineColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
466 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
469 return (LRESULT) infoPtr->clrLine;
473 TREEVIEW_SetLineColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
475 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
476 COLORREF prevColor=infoPtr->clrLine;
479 infoPtr->clrLine=(COLORREF) lParam;
480 return (LRESULT) prevColor;
484 TREEVIEW_GetInsertMarkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
486 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
489 return (LRESULT) infoPtr->clrInsertMark;
493 TREEVIEW_SetInsertMarkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
495 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
496 COLORREF prevColor=infoPtr->clrInsertMark;
498 TRACE("%d %ld\n",wParam,lParam);
499 infoPtr->clrInsertMark=(COLORREF) lParam;
500 return (LRESULT) prevColor;
504 TREEVIEW_SetInsertMark (HWND hwnd, WPARAM wParam, LPARAM lParam)
506 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
509 FIXME("%d %ld\n",wParam,lParam);
510 if (!TREEVIEW_ValidItem (infoPtr, (HTREEITEM)lParam)) return 0;
511 FIXME("%d %ld\n",wParam,lParam);
513 infoPtr->insertBeforeorAfter=(BOOL) wParam;
514 infoPtr->insertMarkItem=(HTREEITEM) lParam;
517 TREEVIEW_Refresh (hwnd, hdc);
524 TREEVIEW_SetTextColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
526 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
527 COLORREF prevColor=infoPtr->clrText;
530 infoPtr->clrText=(COLORREF) lParam;
531 return (LRESULT) prevColor;
535 TREEVIEW_GetBkColor (HWND hwnd)
537 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
540 return (LRESULT) infoPtr->clrBk;
544 TREEVIEW_SetBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
546 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
547 COLORREF prevColor=infoPtr->clrBk;
550 infoPtr->clrBk=(COLORREF) lParam;
551 return (LRESULT) prevColor;
555 TREEVIEW_GetTextColor (HWND hwnd)
557 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
560 return (LRESULT) infoPtr->clrText;
564 /* cdmode: custom draw mode as received from app. in first NMCUSTOMDRAW
567 #define TREEVIEW_LEFT_MARGIN 8
571 TREEVIEW_DrawItem (HWND hwnd, HDC hdc, TREEVIEW_ITEM *wineItem)
573 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
574 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
575 INT center,xpos,cx,cy, cditem;
577 UINT uTextJustify = DT_LEFT;
581 if (wineItem->state & TVIS_BOLD)
582 hOldFont = SelectObject (hdc, infoPtr->hBoldFont);
584 hOldFont = SelectObject (hdc, infoPtr->hFont);
587 TRACE ("cdmode:%x\n",infoPtr->cdmode);
588 if (infoPtr->cdmode & CDRF_NOTIFYITEMDRAW) {
589 cditem=TREEVIEW_SendCustomDrawItemNotify
590 (hwnd, hdc, wineItem, CDDS_ITEMPREPAINT);
591 TRACE("prepaint:cditem-app returns 0x%x\n",cditem);
593 if (cditem & CDRF_SKIPDEFAULT)
598 * Set drawing starting points
600 r = wineItem->rect; /* this item rectangle */
601 center = (r.top+r.bottom)/2; /* this item vertical center */
602 xpos = r.left + TREEVIEW_LEFT_MARGIN;/* horizontal starting point */
605 * Display the tree hierarchy
607 if ( dwStyle & TVS_HASLINES)
610 * Write links to parent node
611 * we draw the L starting from the child to the parent
613 * points[0] is attached to the current item
614 * points[1] is the L corner
615 * points[2] is attached to the parent or the up sibling
617 if ( dwStyle & TVS_LINESATROOT)
619 TREEVIEW_ITEM *upNode = NULL;
620 BOOL hasParentOrSibling = TRUE;
621 RECT upRect = {0,0,0,0};
622 HPEN hOldPen, hNewPen;
625 * determine the target location of the line at root, either be linked
626 * to the up sibling or to the parent node.
628 if (wineItem->upsibling)
629 upNode = TREEVIEW_ValidItem (infoPtr, wineItem->upsibling);
630 else if (wineItem->parent)
631 upNode = TREEVIEW_ValidItem (infoPtr, wineItem->parent);
633 hasParentOrSibling = FALSE;
636 upRect = upNode->rect;
638 if ( wineItem->iLevel == 0 )
640 points[2].x = points[1].x = upRect.left+8;
641 points[0].x = points[2].x + 10;
642 points[2].y = upRect.bottom-3;
643 points[1].y = points[0].y = center;
647 points[2].x = points[1].x = 8 + (20*wineItem->iLevel);
648 points[2].y = ( upNode->cChildren == 0) ?
649 upRect.top : /* is linked to the "L" above */
650 ( wineItem->upsibling != NULL) ?
651 upRect.bottom-3: /* is linked to an icon */
652 upRect.bottom+1; /* is linked to a +/- box */
653 points[1].y = points[0].y = center;
654 points[0].x = points[1].x + 10;
660 hNewPen = CreatePen(PS_DOT, 0, infoPtr->clrLine);
661 hOldPen = SelectObject( hdc, hNewPen );
663 if (hasParentOrSibling)
664 Polyline (hdc,points,3);
666 Polyline (hdc,points,2);
668 DeleteObject(hNewPen);
669 SelectObject(hdc, hOldPen);
674 * Display the (+/-) signs
676 if (wineItem->iLevel != 0)/* update position only for non root node */
677 xpos+=(5*wineItem->iLevel);
679 if (( dwStyle & TVS_HASBUTTONS) && ( dwStyle & TVS_HASLINES))
681 if ( (wineItem->cChildren) ||
682 (wineItem->cChildren == I_CHILDRENCALLBACK))
684 /* Setup expand box coordinate to facilitate the LMBClick handling */
685 wineItem->expandBox.left = xpos-4;
686 wineItem->expandBox.top = center-4;
687 wineItem->expandBox.right = xpos+5;
688 wineItem->expandBox.bottom = center+5;
692 wineItem->expandBox.left,
693 wineItem->expandBox.top ,
694 wineItem->expandBox.right,
695 wineItem->expandBox.bottom);
697 MoveToEx (hdc, xpos-2, center, NULL);
698 LineTo (hdc, xpos+3, center);
700 if (!(wineItem->state & TVIS_EXPANDED)) {
701 MoveToEx (hdc, xpos, center-2, NULL);
702 LineTo (hdc, xpos, center+3);
708 * Display the image associated with this item
710 xpos += 13; /* update position */
711 if (wineItem->mask & (TVIF_IMAGE|TVIF_SELECTEDIMAGE)) {
713 HIMAGELIST *himlp = NULL;
715 /* State images are displayed to the left of the Normal image
716 * image number is in state; zero should be `display no image'.
717 * FIXME: that last sentence looks like it needs some checking.
719 if (infoPtr->himlState)
720 himlp=&infoPtr->himlState;
721 imageIndex=wineItem->state>>12;
722 imageIndex++; /* yeah, right */
723 TRACE ("imindex:%d\n",imageIndex);
724 if ((himlp) && (imageIndex))
726 imageIndex--; /* see FIXME */
727 ImageList_Draw ( *himlp, imageIndex, hdc, xpos-2, r.top+1, ILD_NORMAL);
728 ImageList_GetIconSize (*himlp, &cx, &cy);
729 wineItem->statebitmap.left=xpos-2;
730 wineItem->statebitmap.right=xpos-2+cx;
731 wineItem->statebitmap.top=r.top+1;
732 wineItem->statebitmap.bottom=r.top+1+cy;
736 /* Now, draw the normal image; can be either selected or
737 * non-selected image.
741 if (infoPtr->himlNormal)
742 himlp=&infoPtr->himlNormal; /* get the image list */
744 imageIndex = wineItem->iImage;
745 if ( (wineItem->state & TVIS_SELECTED) &&
746 (wineItem->iSelectedImage)) {
748 /* The item is curently selected */
749 if (wineItem->iSelectedImage == I_IMAGECALLBACK)
750 TREEVIEW_SendDispInfoNotify
751 (hwnd, wineItem, TVN_GETDISPINFOA, TVIF_SELECTEDIMAGE);
753 imageIndex = wineItem->iSelectedImage;
755 /* The item is not selected */
756 if (wineItem->iImage == I_IMAGECALLBACK)
757 TREEVIEW_SendDispInfoNotify
758 (hwnd, wineItem, TVN_GETDISPINFOA, TVIF_IMAGE);
760 imageIndex = wineItem->iImage;
767 if(wineItem->stateMask & TVIS_OVERLAYMASK)
768 ovlIdx = wineItem->state & TVIS_OVERLAYMASK;
770 ImageList_Draw ( *himlp, imageIndex, hdc, xpos-2, r.top+1, ILD_NORMAL|ovlIdx);
771 ImageList_GetIconSize (*himlp, &cx, &cy);
772 wineItem->bitmap.left=xpos-2;
773 wineItem->bitmap.right=xpos-2+cx;
774 wineItem->bitmap.top=r.top+1;
775 wineItem->bitmap.bottom=r.top+1+cy;
782 * Display the text associated with this item
785 if ((wineItem->mask & TVIF_TEXT) && (wineItem->pszText))
787 COLORREF oldBkColor = 0;
788 COLORREF oldTextColor = 0;
794 wineItem->text.left = r.left;
795 wineItem->text.right = r.right;
796 wineItem->text.top = r.top;
797 wineItem->text.bottom= r.bottom;
799 if (wineItem->pszText== LPSTR_TEXTCALLBACKA) {
800 TRACE("LPSTR_TEXTCALLBACK\n");
801 TREEVIEW_SendDispInfoNotify (hwnd, wineItem, TVN_GETDISPINFOA, TVIF_TEXT);
804 /* Yep, there are some things that need to be straightened out here.
805 Removing the comments around the setTextColor does not give the right
806 results. Dito FillRect.
810 /* GetTextExtentPoint32A (hdc, wineItem->pszText,
811 strlen (wineItem->pszText), &size); */
813 /* FillRect ( hdc, &wineItem->text, GetSysColorBrush (infoPtr->clrBk));
817 if (!(cditem & CDRF_NOTIFYPOSTPAINT) &&
818 (wineItem->state & (TVIS_SELECTED | TVIS_DROPHILITED)) ) {
819 oldBkMode = SetBkMode (hdc, OPAQUE);
820 oldBkColor = SetBkColor (hdc, GetSysColor( COLOR_HIGHLIGHT));
821 oldTextColor = SetTextColor(hdc, GetSysColor( COLOR_HIGHLIGHTTEXT));
823 oldBkMode = SetBkMode (hdc, TRANSPARENT);
824 oldBkColor = SetBkColor (hdc, infoPtr->clrBk);
825 /* oldTextColor = SetTextColor(hdc, infoPtr->clrText); */
833 lstrlenA(wineItem->pszText),
835 uTextJustify | DT_VCENTER | DT_SINGLELINE );
837 /* Obtain the text coordinate */
841 lstrlenA(wineItem->pszText),
843 uTextJustify | DT_VCENTER | DT_SINGLELINE | DT_CALCRECT);
845 /* Restore the hdc state */
846 SetTextColor( hdc, oldTextColor);
848 if (oldBkMode != TRANSPARENT)
849 SetBkMode(hdc, oldBkMode);
850 if (wineItem->state & (TVIS_SELECTED | TVIS_DROPHILITED))
851 SetBkColor (hdc, oldBkColor);
853 /* Draw the box arround the selected item */
854 if (wineItem->state & TVIS_SELECTED )
856 HPEN hNewPen = CreatePen(PS_DOT, 0, GetSysColor(COLOR_WINDOWTEXT) );
857 HPEN hOldPen = SelectObject( hdc, hNewPen );
860 points[0].x = wineItem->text.left-1;
861 points[0].y = wineItem->text.top+1;
862 points[1].x = wineItem->text.right;
863 points[1].y = wineItem->text.top+1;
864 points[2].x = wineItem->text.right;
865 points[2].y = wineItem->text.bottom;
866 points[3].x = wineItem->text.left-1;
867 points[3].y = wineItem->text.bottom;
869 Polyline (hdc,points,4);
871 DeleteObject(hNewPen);
872 SelectObject(hdc, hOldPen);
876 /* Draw insertion mark if necessary */
878 if (infoPtr->insertMarkItem)
879 TRACE ("item:%d,mark:%d\n", (int)wineItem->hItem,
880 (int) infoPtr->insertMarkItem);
881 if (wineItem->hItem==infoPtr->insertMarkItem) {
882 HPEN hNewPen, hOldPen;
885 hNewPen = CreatePen(PS_SOLID, 2, infoPtr->clrInsertMark);
886 hOldPen = SelectObject( hdc, hNewPen );
888 if (infoPtr->insertBeforeorAfter)
889 offset=wineItem->text.top+1;
891 offset=wineItem->text.bottom-1;
893 MoveToEx (hdc, wineItem->text.left, offset-3, NULL);
894 LineTo (hdc, wineItem->text.left, offset+3);
896 MoveToEx (hdc, wineItem->text.left, offset, NULL);
897 LineTo (hdc, r.right-2, offset);
899 MoveToEx (hdc, r.right-2, offset+3, NULL);
900 LineTo (hdc, r.right-2, offset-3);
902 DeleteObject(hNewPen);
904 SelectObject(hdc, hOldPen);
907 if (cditem & CDRF_NOTIFYPOSTPAINT) {
908 cditem=TREEVIEW_SendCustomDrawItemNotify
909 (hwnd, hdc, wineItem, CDDS_ITEMPOSTPAINT);
910 TRACE("postpaint:cditem-app returns 0x%x\n",cditem);
913 SelectObject (hdc, hOldFont);
917 TREEVIEW_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
919 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
920 TREEVIEW_ITEM *wineItem;
922 LPRECT lpRect = (LPRECT)lParam;
927 * validate parameters
932 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
934 TREEVIEW_Refresh (hwnd, hdc); /* we want a rect for the current view */
940 * retrieve the item ptr
942 iItem = (HTREEITEM *) lParam;
943 wineItem = TREEVIEW_ValidItem (infoPtr, *iItem);
944 if ((!wineItem) || (!wineItem->visible))
948 * If wParam is TRUE return the text size otherwise return
949 * the whole item size
952 lpRect->left = wineItem->text.left;
953 lpRect->right = wineItem->text.right;
954 lpRect->bottom = wineItem->text.bottom;
955 lpRect->top = wineItem->text.top;
957 lpRect->left = wineItem->rect.left;
958 lpRect->right = wineItem->rect.right;
959 lpRect->bottom = wineItem->rect.bottom;
960 lpRect->top = wineItem->rect.top;
963 TRACE("[L:%d R:%d T:%d B:%d]\n",
964 lpRect->left,lpRect->right,
965 lpRect->top,lpRect->bottom);
971 TREEVIEW_GetVisibleCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
974 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
976 return (LRESULT) infoPtr->uVisibleHeight / infoPtr->uRealItemHeight;
982 TREEVIEW_SetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
984 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
985 TREEVIEW_ITEM *wineItem;
989 tvItem=(LPTVITEMEXA) lParam;
990 iItem=(INT)tvItem->hItem;
991 TRACE("item %d,mask %x\n",iItem,tvItem->mask);
993 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
994 if (!wineItem) return FALSE;
996 if (tvItem->mask & TVIF_CHILDREN) {
997 wineItem->cChildren=tvItem->cChildren;
1000 if (tvItem->mask & TVIF_IMAGE) {
1001 wineItem->iImage=tvItem->iImage;
1004 if (tvItem->mask & TVIF_INTEGRAL) {
1005 wineItem->iIntegral=tvItem->iIntegral;
1008 if (tvItem->mask & TVIF_PARAM) {
1009 wineItem->lParam=tvItem->lParam;
1012 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
1013 wineItem->iSelectedImage=tvItem->iSelectedImage;
1016 if (tvItem->mask & TVIF_STATE) {
1017 TRACE ("prevstate,state,mask:%x,%x,%x\n",wineItem->state,tvItem->state,
1019 wineItem->state&= ~tvItem->stateMask;
1020 wineItem->state|= (tvItem->state & tvItem->stateMask);
1021 wineItem->stateMask|= tvItem->stateMask;
1024 if (tvItem->mask & TVIF_TEXT) {
1025 if (tvItem->pszText!=LPSTR_TEXTCALLBACKA) {
1026 len=lstrlenA (tvItem->pszText);
1027 if (len>wineItem->cchTextMax)
1028 wineItem->pszText= COMCTL32_ReAlloc (wineItem->pszText, len+1);
1029 lstrcpynA (wineItem->pszText, tvItem->pszText,len+1);
1031 if (wineItem->cchTextMax) {
1032 COMCTL32_Free (wineItem->pszText);
1033 wineItem->cchTextMax=0;
1035 wineItem->pszText=LPSTR_TEXTCALLBACKA;
1039 wineItem->mask |= tvItem->mask;
1045 TREEVIEW_GetItemState (HWND hwnd, WPARAM wParam, LPARAM lParam)
1048 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1049 TREEVIEW_ITEM *wineItem;
1052 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)wParam);
1053 if (!wineItem) return 0;
1055 return (wineItem->state & lParam);
1062 TREEVIEW_Refresh (HWND hwnd, HDC hdc)
1064 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1070 INT iItem, indent, x, y, height, itemHeight;
1071 INT viewtop,viewbottom,viewleft,viewright;
1072 TREEVIEW_ITEM *wineItem, *prevItem;
1077 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
1078 KillTimer (hwnd, TV_REFRESH_TIMER);
1079 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
1083 GetClientRect (hwnd, &rect);
1084 if ((rect.left >= rect.right) || (rect.top >= rect.bottom)) return;
1086 infoPtr->cdmode=TREEVIEW_SendCustomDrawNotify(hwnd,CDDS_PREPAINT,hdc,rect);
1088 if (infoPtr->cdmode==CDRF_SKIPDEFAULT) return;
1090 infoPtr->uVisibleHeight= rect.bottom-rect.top + 1;
1091 infoPtr->uVisibleWidth= rect.right-rect.left + 1;
1093 viewtop=infoPtr->cy;
1094 viewbottom=infoPtr->cy + rect.bottom-rect.top;
1095 viewleft=infoPtr->cx;
1096 viewright=infoPtr->cx + rect.right-rect.left;
1098 TRACE("[%d %d %d %d]\n",viewtop,viewbottom,viewleft,viewright);
1100 /* draw background */
1102 hbrBk = CreateSolidBrush (infoPtr->clrBk);
1103 FillRect(hdc, &rect, hbrBk);
1104 DeleteObject(hbrBk);
1106 ImageList_GetIconSize (infoPtr->himlNormal, &x, &itemHeight);
1107 if (infoPtr->uItemHeight>itemHeight)
1108 itemHeight=infoPtr->uItemHeight;
1110 // assume that bold and normal fonts have same height
1111 hOldFont = SelectObject (hdc, infoPtr->hBoldFont);
1112 GetTextMetricsA (hdc, &tm);
1113 if ((tm.tmHeight + tm.tmExternalLeading + FOCUS_BORDER) > itemHeight)
1114 itemHeight=tm.tmHeight + tm.tmExternalLeading + FOCUS_BORDER;
1115 SelectObject (hdc, hOldFont);
1117 infoPtr->uRealItemHeight=itemHeight;
1119 iItem=(INT)infoPtr->TopRootItem;
1120 infoPtr->firstVisible=0;
1127 wineItem= & infoPtr->items[iItem];
1128 wineItem->iLevel=indent;
1130 /* FIXME: remove this in later stage */
1132 if (wineItem->pszText!=LPSTR_TEXTCALLBACK32A)
1133 TRACE (treeview, "%d %d [%d %d %d %d] (%s)\n",y,x,
1134 wineItem->rect.top, wineItem->rect.bottom,
1135 wineItem->rect.left, wineItem->rect.right,
1138 TRACE (treeview, "%d [%d %d %d %d] (CALLBACK)\n",
1140 wineItem->rect.top, wineItem->rect.bottom,
1141 wineItem->rect.left, wineItem->rect.right);
1144 height=itemHeight * wineItem->iIntegral;
1145 if ((y >= viewtop) && (y <= viewbottom) &&
1146 (x >= viewleft ) && (x <= viewright)) {
1147 wineItem->visible = TRUE;
1148 wineItem->rect.top = y - infoPtr->cy + rect.top;
1149 wineItem->rect.bottom = wineItem->rect.top + height-1;
1150 wineItem->rect.left = x - infoPtr->cx + rect.left;
1151 wineItem->rect.right = rect.right;
1152 if (!infoPtr->firstVisible)
1153 infoPtr->firstVisible=wineItem->hItem;
1154 TREEVIEW_DrawItem (hwnd, hdc, wineItem);
1157 wineItem->visible = FALSE;
1158 wineItem->rect.left = wineItem->rect.top = 0;
1159 wineItem->rect.right= wineItem->rect.bottom = 0;
1160 wineItem->text.left = wineItem->text.top = 0;
1161 wineItem->text.right= wineItem->text.bottom = 0;
1164 /* look up next item */
1166 if ((wineItem->firstChild) && (wineItem->state & TVIS_EXPANDED)) {
1167 iItem=(INT)wineItem->firstChild;
1169 x+=infoPtr->uIndent;
1170 if (x>infoPtr->uTotalWidth)
1171 infoPtr->uTotalWidth=x;
1174 iItem=(INT)wineItem->sibling;
1175 while ((!iItem) && (indent>0)) {
1177 x-=infoPtr->uIndent;
1178 wineItem=&infoPtr->items[(INT)wineItem->parent];
1179 iItem=(INT)wineItem->sibling;
1185 /* FIXME: infoPtr->uTotalWidth should also take item label into account */
1186 /* FIXME: or should query item sizes (ie check CDRF_NEWFONT) */
1188 infoPtr->uTotalHeight=y;
1189 if (y >= (viewbottom-viewtop)) {
1190 if (!(infoPtr->uInternalStatus & TV_VSCROLL))
1191 ShowScrollBar (hwnd, SB_VERT, TRUE);
1192 infoPtr->uInternalStatus |=TV_VSCROLL;
1193 SetScrollRange (hwnd, SB_VERT, 0,
1194 y - infoPtr->uVisibleHeight, FALSE);
1195 SetScrollPos (hwnd, SB_VERT, infoPtr->cy, TRUE);
1198 if (infoPtr->uInternalStatus & TV_VSCROLL)
1199 ShowScrollBar (hwnd, SB_VERT, FALSE);
1200 infoPtr->uInternalStatus &= ~TV_VSCROLL;
1204 if (infoPtr->cdmode & CDRF_NOTIFYPOSTPAINT)
1205 infoPtr->cdmode=TREEVIEW_SendCustomDrawNotify
1206 (hwnd, CDDS_POSTPAINT, hdc, rect);
1213 TREEVIEW_HandleTimer (HWND hwnd, WPARAM wParam, LPARAM lParam)
1215 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1217 TRACE(" %d\n",wParam);
1220 case TV_REFRESH_TIMER:
1221 KillTimer (hwnd, TV_REFRESH_TIMER);
1222 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
1223 InvalidateRect(hwnd, NULL, FALSE);
1226 KillTimer (hwnd, TV_EDIT_TIMER);
1227 infoPtr->Timer &= ~TV_EDIT_TIMER_SET;
1230 ERR("got unknown timer\n");
1238 TREEVIEW_QueueRefresh (HWND hwnd)
1241 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1244 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
1245 KillTimer (hwnd, TV_REFRESH_TIMER);
1248 SetTimer (hwnd, TV_REFRESH_TIMER, TV_REFRESH_DELAY, 0);
1249 infoPtr->Timer|=TV_REFRESH_TIMER_SET;
1255 TREEVIEW_GetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1257 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1259 TREEVIEW_ITEM *wineItem;
1262 tvItem=(LPTVITEMEXA) lParam;
1263 iItem=(INT)tvItem->hItem;
1265 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1266 if (!wineItem) return FALSE;
1268 if (tvItem->mask & TVIF_CHILDREN) {
1269 if (TVIF_CHILDREN==I_CHILDRENCALLBACK)
1270 FIXME("I_CHILDRENCALLBACK not supported\n");
1271 tvItem->cChildren=wineItem->cChildren;
1274 if (tvItem->mask & TVIF_HANDLE) {
1275 tvItem->hItem=wineItem->hItem;
1278 if (tvItem->mask & TVIF_IMAGE) {
1279 tvItem->iImage=wineItem->iImage;
1282 if (tvItem->mask & TVIF_INTEGRAL) {
1283 tvItem->iIntegral=wineItem->iIntegral;
1286 /* undocumented: windows ignores TVIF_PARAM and
1287 * always sets lParam
1289 tvItem->lParam=wineItem->lParam;
1291 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
1292 tvItem->iSelectedImage=wineItem->iSelectedImage;
1295 if (tvItem->mask & TVIF_STATE) {
1296 tvItem->state=wineItem->state & tvItem->stateMask;
1299 if (tvItem->mask & TVIF_TEXT) {
1300 if (wineItem->pszText == LPSTR_TEXTCALLBACKA) {
1301 tvItem->pszText = LPSTR_TEXTCALLBACKA; /* FIXME:send notification? */
1302 ERR(" GetItem called with LPSTR_TEXTCALLBACK\n");
1304 else if (wineItem->pszText) {
1305 lstrcpynA (tvItem->pszText, wineItem->pszText, tvItem->cchTextMax);
1309 TRACE("item %d<%p>, txt %p, img %p, action %x\n",
1310 iItem, tvItem, tvItem->pszText, &tvItem->iImage, tvItem->mask);
1317 TREEVIEW_GetItemW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1319 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1321 TREEVIEW_ITEM *wineItem;
1324 tvItem=(LPTVITEMEXA) lParam;
1325 iItem=(INT)tvItem->hItem;
1327 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1328 if (!wineItem) return FALSE;
1330 if (tvItem->mask & TVIF_CHILDREN) {
1331 if (TVIF_CHILDREN==I_CHILDRENCALLBACK)
1332 FIXME("I_CHILDRENCALLBACK not supported\n");
1333 tvItem->cChildren=wineItem->cChildren;
1336 if (tvItem->mask & TVIF_HANDLE) {
1337 tvItem->hItem=wineItem->hItem;
1340 if (tvItem->mask & TVIF_IMAGE) {
1341 tvItem->iImage=wineItem->iImage;
1344 if (tvItem->mask & TVIF_INTEGRAL) {
1345 tvItem->iIntegral=wineItem->iIntegral;
1348 /* undocumented: windows ignores TVIF_PARAM and
1349 * always sets lParam
1351 tvItem->lParam=wineItem->lParam;
1353 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
1354 tvItem->iSelectedImage=wineItem->iSelectedImage;
1357 if (tvItem->mask & TVIF_STATE) {
1358 tvItem->state=wineItem->state & tvItem->stateMask;
1362 if (tvItem->mask & TVIF_TEXT) {
1363 if (wineItem->pszText == LPSTR_TEXTCALLBACKW) {
1364 tvItem->pszText = LPSTR_TEXTCALLBACKW; /* FIXME:send notification? */
1365 ERR(" GetItem called with LPSTR_TEXTCALLBACK\n");
1367 else if (wineItem->pszText) {
1368 lstrcpynAtoW (tvItem->pszText, wineItem->pszText, tvItem->cchTextMax);
1372 wineItem->pszText = NULL;
1374 TRACE("item %d<%p>, txt %p, img %p, action %x\n",
1375 iItem, tvItem, tvItem->pszText, &tvItem->iImage, tvItem->mask);
1382 /* FIXME: check implementation of TVGN_NEXT/TVGN_NEXTVISIBLE */
1385 TREEVIEW_GetNextItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
1388 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1389 TREEVIEW_ITEM *wineItem, *returnItem;
1390 INT iItem = (INT)lParam, retval = 0, flag = (INT)wParam;
1395 retval = (INT)infoPtr->TopRootItem;
1399 retval = (INT)infoPtr->selectedItem;
1402 case TVGN_FIRSTVISIBLE: /* FIXME:we should only recalculate, not redraw */
1404 TREEVIEW_Refresh (hwnd, hdc);
1405 ReleaseDC(hwnd,hdc);
1406 retval = (INT)infoPtr->firstVisible;
1409 case TVGN_DROPHILITE:
1410 retval = (INT)infoPtr->dropItem;
1414 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1415 retval = wineItem ? (INT)wineItem->sibling : 0;
1419 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1420 retval = wineItem ? (INT)wineItem->upsibling : 0;
1424 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1425 retval = wineItem ? (INT)wineItem->parent : 0;
1429 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1430 retval = wineItem ? (INT)wineItem->firstChild : 0;
1433 case TVGN_LASTVISIBLE:
1434 if((wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem))) {
1435 returnItem = TREEVIEW_GetLastListItem (infoPtr,wineItem);
1436 retval = returnItem ? (INT)returnItem->hItem : 0;
1440 case TVGN_NEXTVISIBLE:
1441 if((wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem))) {
1442 returnItem = TREEVIEW_GetNextListItem (infoPtr,wineItem);
1443 retval = returnItem ? (INT)returnItem->hItem : 0;
1447 case TVGN_PREVIOUSVISIBLE:
1448 if((wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem))) {
1449 returnItem = TREEVIEW_GetPrevListItem (infoPtr, wineItem);
1450 retval = returnItem ? (INT)returnItem->hItem : 0;
1455 FIXME("Unknown msg %x,item %x\n", flag,iItem);
1459 TRACE("flags %x, item %d returns %d\n", flag, iItem, retval);
1465 TREEVIEW_GetCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
1467 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1469 TRACE(" %d\n",infoPtr->uNumItems);
1470 return (LRESULT) infoPtr->uNumItems;
1473 /***************************************************************************
1474 * This method does the chaining of the insertion of a treeview item
1476 * If parent is NULL, we're inserting at the root of the list.
1478 static void TREEVIEW_InsertBefore(
1479 TREEVIEW_INFO *infoPtr,
1480 TREEVIEW_ITEM *newItem,
1481 TREEVIEW_ITEM *sibling,
1482 TREEVIEW_ITEM *parent)
1484 HTREEITEM siblingHandle = 0;
1485 HTREEITEM upSiblingHandle = 0;
1486 TREEVIEW_ITEM *upSibling = NULL;
1488 if (newItem == NULL)
1489 ERR("NULL newItem, impossible condition\n");
1491 if (sibling != NULL) /* Insert before this sibling for this parent */
1493 /* Store the new item sibling up sibling and sibling tem handle */
1494 siblingHandle = sibling->hItem;
1495 upSiblingHandle = sibling->upsibling;
1496 /* As well as a pointer to the upsibling sibling object */
1497 if ( (INT)sibling->upsibling != 0 )
1498 upSibling = &infoPtr->items[(INT)sibling->upsibling];
1500 /* Adjust the sibling pointer */
1501 sibling->upsibling = newItem->hItem;
1503 /* Adjust the new item pointers */
1504 newItem->upsibling = upSiblingHandle;
1505 newItem->sibling = siblingHandle;
1507 /* Adjust the up sibling pointer */
1508 if ( upSibling != NULL )
1509 upSibling->sibling = newItem->hItem;
1511 /* this item is the first child of this parent, adjust parent pointers */
1513 parent->firstChild = newItem->hItem;
1515 infoPtr->TopRootItem= newItem->hItem;
1517 else /* Insert as first child of this parent */
1519 parent->firstChild = newItem->hItem;
1522 /***************************************************************************
1523 * This method does the chaining of the insertion of a treeview item
1525 * If parent is NULL, we're inserting at the root of the list.
1527 static void TREEVIEW_InsertAfter(
1528 TREEVIEW_INFO *infoPtr,
1529 TREEVIEW_ITEM *newItem,
1530 TREEVIEW_ITEM *upSibling,
1531 TREEVIEW_ITEM *parent)
1533 HTREEITEM upSiblingHandle = 0;
1534 HTREEITEM siblingHandle = 0;
1535 TREEVIEW_ITEM *sibling = NULL;
1538 if (newItem == NULL)
1539 ERR("NULL newItem, impossible condition\n");
1541 if (upSibling != NULL) /* Insert after this upsibling for this parent */
1543 /* Store the new item up sibling and sibling item handle */
1544 upSiblingHandle = upSibling->hItem;
1545 siblingHandle = upSibling->sibling;
1546 /* As well as a pointer to the upsibling sibling object */
1547 if ( (INT)upSibling->sibling != 0 )
1548 sibling = &infoPtr->items[(INT)upSibling->sibling];
1550 /* Adjust the up sibling pointer */
1551 upSibling->sibling = newItem->hItem;
1553 /* Adjust the new item pointers */
1554 newItem->upsibling = upSiblingHandle;
1555 newItem->sibling = siblingHandle;
1557 /* Adjust the sibling pointer */
1558 if ( sibling != NULL )
1559 sibling->upsibling = newItem->hItem;
1562 newItem is the last of the level, nothing else to do
1565 else /* Insert as first child of this parent */
1567 parent->firstChild = newItem->hItem;
1570 /***************************************************************************
1571 * Forward the DPA local callback to the treeview owner callback
1573 static INT WINAPI TREEVIEW_CallBackCompare(
1578 /* Forward the call to the client define callback */
1579 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr((HWND)tvInfoPtr);
1580 return (infoPtr->pCallBackSort->lpfnCompare)(
1581 ((TREEVIEW_ITEM*)first)->lParam,
1582 ((TREEVIEW_ITEM*)second)->lParam,
1583 infoPtr->pCallBackSort->lParam);
1586 /***************************************************************************
1587 * Treeview native sort routine: sort on item text.
1589 static INT WINAPI TREEVIEW_SortOnName (
1594 HWND hwnd=(HWND) tvInfoPtr;
1596 TREEVIEW_ITEM *item;
1599 item=(TREEVIEW_ITEM *) first;
1600 if (item->pszText==LPSTR_TEXTCALLBACKA) {
1601 TREEVIEW_SendDispInfoNotify (hwnd, item, TVN_GETDISPINFOA, TVIF_TEXT);
1605 item=(TREEVIEW_ITEM *) second;
1606 if (item->pszText==LPSTR_TEXTCALLBACKA) {
1607 TREEVIEW_SendDispInfoNotify (hwnd, item, TVN_GETDISPINFOA, TVIF_TEXT);
1611 return -strcmp (txt1,txt2);
1614 /***************************************************************************
1615 * Setup the treeview structure with regards of the sort method
1616 * and sort the children of the TV item specified in lParam
1617 * fRecurse: currently unused. Should be zero.
1618 * parent: if pSort!=NULL, should equal pSort->hParent.
1619 * otherwise, item which child items are to be sorted.
1620 * pSort: sort method info. if NULL, sort on item text.
1621 * if non-NULL, sort on item's lParam content, and let the
1622 * application decide what that means. See also TVM_SORTCHILDRENCB.
1625 static LRESULT WINAPI TREEVIEW_Sort (
1632 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1633 TREEVIEW_ITEM *sortMe = NULL; /* Node for which we sort the children */
1635 /* Obtain the TVSORTBC struct */
1636 infoPtr->pCallBackSort = pSort;
1638 /* undocumented feature: TVI_ROOT means `sort the whole tree' */
1640 if (parent==TVI_ROOT)
1641 parent=infoPtr->TopRootItem;
1643 /* Check for a valid handle to the parent item */
1644 if (!TREEVIEW_ValidItem(infoPtr, parent))
1646 ERR ("invalid item hParent=%x\n", (INT)parent);
1650 /* Obtain the parent node to sort */
1651 sortMe = &infoPtr->items[ (INT)parent ];
1653 /* Make sure there is something to sort */
1654 if ( sortMe->cChildren > 1 )
1656 /* pointer organization */
1657 HDPA sortList = DPA_Create(sortMe->cChildren);
1658 HTREEITEM itemHandle = sortMe->firstChild;
1659 TREEVIEW_ITEM *itemPtr = & infoPtr->items[ (INT)itemHandle ];
1661 /* TREEVIEW_ITEM rechaining */
1667 /* Build the list of item to sort */
1671 sortList, /* the list */
1672 sortMe->cChildren+1, /* force the insertion to be an append */
1673 itemPtr); /* the ptr to store */
1675 /* Get the next sibling */
1676 itemHandle = itemPtr->sibling;
1677 itemPtr = & infoPtr->items[ (INT)itemHandle ];
1678 } while ( itemHandle != NULL );
1680 /* let DPA perform the sort activity */
1683 sortList, /* what */
1684 TREEVIEW_CallBackCompare, /* how */
1688 sortList, /* what */
1689 TREEVIEW_SortOnName, /* how */
1693 * Reorganized TREEVIEW_ITEM structures.
1694 * Note that we know we have at least two elements.
1697 /* Get the first item and get ready to start... */
1698 item = DPA_GetPtr(sortList, count++);
1699 while ( (nextItem = DPA_GetPtr(sortList, count++)) != NULL )
1701 /* link the two current item toghether */
1702 ((TREEVIEW_ITEM*)item)->sibling = ((TREEVIEW_ITEM*)nextItem)->hItem;
1703 ((TREEVIEW_ITEM*)nextItem)->upsibling = ((TREEVIEW_ITEM*)item)->hItem;
1705 if (prevItem == NULL) /* this is the first item, update the parent */
1707 sortMe->firstChild = ((TREEVIEW_ITEM*)item)->hItem;
1708 ((TREEVIEW_ITEM*)item)->upsibling = NULL;
1710 else /* fix the back chaining */
1712 ((TREEVIEW_ITEM*)item)->upsibling = ((TREEVIEW_ITEM*)prevItem)->hItem;
1715 /* get ready for the next one */
1720 /* the last item is pointed to by item and never has a sibling */
1721 ((TREEVIEW_ITEM*)item)->sibling = NULL;
1723 DPA_Destroy(sortList);
1731 /***************************************************************************
1732 * Setup the treeview structure with regards of the sort method
1733 * and sort the children of the TV item specified in lParam
1735 static LRESULT WINAPI TREEVIEW_SortChildrenCB(
1741 LPTVSORTCB pSort=(LPTVSORTCB) lParam;
1743 return TREEVIEW_Sort (hwnd, wParam, pSort->hParent, pSort);
1747 /***************************************************************************
1748 * Sort the children of the TV item specified in lParam.
1750 static LRESULT WINAPI TREEVIEW_SortChildren (
1755 return TREEVIEW_Sort (hwnd, (BOOL) wParam, (HTREEITEM) lParam, NULL);
1760 /* the method used below isn't the most memory-friendly, but it avoids
1761 a lot of memory reallocations */
1763 /* BTW: we waste handle 0; 0 is not an allowed handle. */
1766 TREEVIEW_InsertItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1769 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1770 TVINSERTSTRUCTA *ptdi;
1772 TREEVIEW_ITEM *wineItem, *parentItem, *prevsib, *sibItem;
1773 INT iItem,listItems,i,len;
1775 /* Item to insert */
1776 ptdi = (LPTVINSERTSTRUCTA) lParam;
1778 /* check if memory is available */
1780 if (infoPtr->uNumPtrsAlloced==0) {
1781 infoPtr->items = COMCTL32_Alloc (TVITEM_ALLOC*sizeof (TREEVIEW_ITEM));
1782 infoPtr->freeList= COMCTL32_Alloc ((1+(TVITEM_ALLOC>>5)) * sizeof (INT));
1783 infoPtr->uNumPtrsAlloced=TVITEM_ALLOC;
1784 infoPtr->TopRootItem=(HTREEITEM)1;
1788 * Reallocate contiguous space for items
1790 if (infoPtr->uNumItems == (infoPtr->uNumPtrsAlloced-1) ) {
1791 TREEVIEW_ITEM *oldItems = infoPtr->items;
1792 INT *oldfreeList = infoPtr->freeList;
1794 infoPtr->uNumPtrsAlloced*=2;
1795 infoPtr->items = COMCTL32_Alloc (infoPtr->uNumPtrsAlloced*sizeof (TREEVIEW_ITEM));
1796 infoPtr->freeList= COMCTL32_Alloc ((1+(infoPtr->uNumPtrsAlloced>>5))*sizeof (INT));
1798 memcpy (&infoPtr->items[0], &oldItems[0],
1799 infoPtr->uNumPtrsAlloced/2 * sizeof(TREEVIEW_ITEM));
1800 memcpy (&infoPtr->freeList[0], &oldfreeList[0],
1801 (infoPtr->uNumPtrsAlloced>>6) * sizeof(INT));
1803 COMCTL32_Free (oldItems);
1804 COMCTL32_Free (oldfreeList);
1808 * Reset infoPtr structure with new stat according to current TV picture
1811 infoPtr->uNumItems++;
1812 if ((INT)infoPtr->uMaxHandle==(infoPtr->uNumItems-1)) {
1813 iItem=infoPtr->uNumItems;
1814 infoPtr->uMaxHandle = (HTREEITEM)((INT)infoPtr->uMaxHandle + 1);
1815 } else { /* check freelist */
1816 for (i=0; i<=infoPtr->uNumPtrsAlloced>>5; i++) {
1817 if (infoPtr->freeList[i]) {
1818 iItem=ffs (infoPtr->freeList[i])-1;
1819 tv_clear_bit(iItem,&infoPtr->freeList[i]);
1826 if (TRACE_ON(treeview)) {
1827 for (i=0; i<=infoPtr->uNumPtrsAlloced>>5; i++)
1828 TRACE("%8x\n",infoPtr->freeList[i]);
1831 if (!iItem) ERR("Argh -- can't find free item.\n");
1834 * Find the parent item of the new item
1836 tvItem= & ptdi->DUMMYUNIONNAME.itemex;
1837 wineItem=& infoPtr->items[iItem];
1839 if ((ptdi->hParent==TVI_ROOT) || (ptdi->hParent==0)) {
1841 wineItem->parent = 0;
1842 sibItem = &infoPtr->items [(INT)infoPtr->TopRootItem];
1843 listItems = infoPtr->uNumItems;
1846 parentItem = &infoPtr->items[(INT)ptdi->hParent];
1848 /* Do the insertion here it if it's the only item of this parent */
1849 if (!parentItem->firstChild)
1850 parentItem->firstChild=(HTREEITEM)iItem;
1852 wineItem->parent = ptdi->hParent;
1853 sibItem = &infoPtr->items [(INT)parentItem->firstChild];
1854 listItems = parentItem->cChildren;
1855 parentItem->cChildren++;
1859 /* NOTE: I am moving some setup of the wineItem object that was initialy
1860 * done at the end of the function since some of the values are
1861 * required by the Callback sorting
1864 if (tvItem->mask & TVIF_TEXT)
1867 * Setup the item text stuff here since it's required by the Sort method
1868 * when the insertion are ordered
1870 if (tvItem->pszText!=LPSTR_TEXTCALLBACKA)
1872 TRACE("(%p,%s)\n", &tvItem->pszText, tvItem->pszText);
1873 len = lstrlenA (tvItem->pszText)+1;
1874 wineItem->pszText= COMCTL32_Alloc (len+1);
1875 lstrcpyA (wineItem->pszText, tvItem->pszText);
1876 wineItem->cchTextMax=len;
1880 TRACE("LPSTR_TEXTCALLBACK\n");
1881 wineItem->pszText = LPSTR_TEXTCALLBACKA;
1882 wineItem->cchTextMax = 0;
1886 if (tvItem->mask & TVIF_PARAM)
1887 wineItem->lParam=tvItem->lParam;
1890 wineItem->upsibling=0; /* needed in case we're the first item in a list */
1891 wineItem->sibling=0;
1892 wineItem->firstChild=0;
1893 wineItem->hItem=(HTREEITEM)iItem;
1898 switch ((DWORD) ptdi->hInsertAfter) {
1899 case (DWORD) TVI_FIRST:
1900 if (sibItem==wineItem) break;
1901 if (wineItem->parent) {
1902 wineItem->sibling=parentItem->firstChild;
1903 parentItem->firstChild=(HTREEITEM)iItem;
1905 wineItem->sibling=infoPtr->TopRootItem;
1906 infoPtr->TopRootItem=(HTREEITEM)iItem;
1908 sibItem->upsibling=(HTREEITEM)iItem;
1911 case (DWORD) TVI_SORT:
1912 if (sibItem==wineItem)
1914 * This item is the first child of the level and it
1915 * has already been inserted
1920 TREEVIEW_ITEM *aChild;
1923 TREEVIEW_ITEM *previousChild = NULL;
1924 BOOL bItemInserted = FALSE;
1927 aChild = &infoPtr->items[(INT)parentItem->firstChild];
1929 aChild = &infoPtr->items[(INT)infoPtr->TopRootItem];
1931 /* lookup the text if using LPSTR_TEXTCALLBACKs */
1932 if (wineItem->pszText==LPSTR_TEXTCALLBACKA) {
1933 TREEVIEW_SendDispInfoNotify (hwnd, wineItem, TVN_GETDISPINFOA, TVIF_TEXT);
1936 /* Iterate the parent children to see where we fit in */
1937 while ( aChild != NULL )
1941 /* lookup the text if using LPSTR_TEXTCALLBACKs */
1942 if (aChild->pszText==LPSTR_TEXTCALLBACKA) {
1943 TREEVIEW_SendDispInfoNotify (hwnd, aChild, TVN_GETDISPINFOA, TVIF_TEXT);
1946 comp = strcmp(wineItem->pszText, aChild->pszText);
1947 if ( comp < 0 ) /* we are smaller than the current one */
1949 TREEVIEW_InsertBefore(infoPtr, wineItem, aChild, parentItem);
1950 bItemInserted = TRUE;
1953 else if ( comp > 0 ) /* we are bigger than the current one */
1955 previousChild = aChild;
1956 aChild = (aChild->sibling == 0) /* This will help us to exit */
1957 ? NULL /* if there is no more sibling */
1958 : &infoPtr->items[(INT)aChild->sibling];
1960 /* Look at the next item */
1963 else if ( comp == 0 )
1966 * An item with this name is already existing, therefore,
1967 * we add after the one we found
1969 TREEVIEW_InsertAfter(infoPtr, wineItem, aChild, parentItem);
1970 bItemInserted = TRUE;
1976 * we reach the end of the child list and the item as not
1977 * yet been inserted, therefore, insert it after the last child.
1979 if ( (! bItemInserted ) && (aChild == NULL) )
1980 TREEVIEW_InsertAfter(infoPtr, wineItem, previousChild, parentItem);
1986 case (DWORD) TVI_LAST:
1987 if (sibItem==wineItem) break;
1988 while (sibItem->sibling) {
1990 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1992 sibItem->sibling=(HTREEITEM)iItem;
1993 wineItem->upsibling=sibItem->hItem;
1997 TREEVIEW_ITEM *localsibItem = sibItem;
1998 while ((localsibItem->sibling) &&
1999 (localsibItem->hItem!=ptdi->hInsertAfter))
2001 prevsib=localsibItem;
2002 localsibItem=&infoPtr->items [(INT)localsibItem->sibling];
2004 if (localsibItem->hItem!=ptdi->hInsertAfter) {
2005 WARN("tried to insert item after nonexisting handle %d treating as TVI_LAST.\n",
2006 (INT) ptdi->hInsertAfter);
2008 * retry placing it last
2010 if (sibItem==wineItem) break;
2011 while (sibItem->sibling) {
2013 sibItem=&infoPtr->items [(INT)sibItem->sibling];
2015 sibItem->sibling=(HTREEITEM)iItem;
2016 wineItem->upsibling=sibItem->hItem;
2019 prevsib=localsibItem;
2020 if (localsibItem->sibling) {
2021 localsibItem=&infoPtr->items [(INT)localsibItem->sibling];
2022 localsibItem->upsibling=(HTREEITEM)iItem;
2023 wineItem->sibling=localsibItem->hItem;
2025 prevsib->sibling=(HTREEITEM)iItem;
2026 wineItem->upsibling=prevsib->hItem;
2033 /* Fill in info structure */
2035 TRACE("new item %d; parent %d, mask %x\n", iItem,
2036 (INT)wineItem->parent,tvItem->mask);
2038 wineItem->mask=tvItem->mask;
2039 wineItem->iIntegral=1;
2041 if (tvItem->mask & TVIF_CHILDREN) {
2042 wineItem->cChildren=tvItem->cChildren;
2043 if (tvItem->cChildren==I_CHILDRENCALLBACK)
2044 FIXME(" I_CHILDRENCALLBACK not supported\n");
2047 wineItem->expandBox.left = 0; /* Initialize the expandBox */
2048 wineItem->expandBox.top = 0;
2049 wineItem->expandBox.right = 0;
2050 wineItem->expandBox.bottom = 0;
2052 if (tvItem->mask & TVIF_IMAGE)
2053 wineItem->iImage=tvItem->iImage;
2055 /* If the application sets TVIF_INTEGRAL without
2056 supplying a TVITEMEX structure, it's toast */
2058 if (tvItem->mask & TVIF_INTEGRAL)
2059 wineItem->iIntegral=tvItem->iIntegral;
2061 if (tvItem->mask & TVIF_SELECTEDIMAGE)
2062 wineItem->iSelectedImage=tvItem->iSelectedImage;
2064 if (tvItem->mask & TVIF_STATE) {
2065 TRACE("item state: %x ->%x\n", wineItem->state, tvItem->state);
2066 TRACE("statemask: %x ->%x\n", wineItem->stateMask, tvItem->stateMask);
2067 wineItem->state=tvItem->state;
2068 wineItem->stateMask=tvItem->stateMask;
2071 TREEVIEW_QueueRefresh (hwnd);
2073 return (LRESULT) iItem;
2078 TREEVIEW_InsertItemW(HWND hwnd, WPARAM wParam, LPARAM lParam)
2080 TVINSERTSTRUCTW *tvisW;
2081 TVINSERTSTRUCTA tvisA;
2084 tvisW = (LPTVINSERTSTRUCTW)lParam;
2086 tvisA.hParent = tvisW->hParent;
2087 tvisA.hInsertAfter = tvisW->hInsertAfter;
2089 tvisA.DUMMYUNIONNAME.item.mask = tvisW->DUMMYUNIONNAME.item.mask;
2090 tvisA.DUMMYUNIONNAME.item.hItem = tvisW->DUMMYUNIONNAME.item.hItem;
2091 tvisA.DUMMYUNIONNAME.item.state = tvisW->DUMMYUNIONNAME.item.state;
2092 tvisA.DUMMYUNIONNAME.item.stateMask = tvisW->DUMMYUNIONNAME.item.stateMask;
2093 tvisA.DUMMYUNIONNAME.item.cchTextMax = tvisW->DUMMYUNIONNAME.item.cchTextMax;
2095 if(tvisW->DUMMYUNIONNAME.item.pszText)
2097 if (tvisW->DUMMYUNIONNAME.item.pszText!=LPSTR_TEXTCALLBACKW)
2099 int len = lstrlenW (tvisW->DUMMYUNIONNAME.item.pszText)+1;
2100 tvisA.DUMMYUNIONNAME.item.pszText = COMCTL32_Alloc (len);
2101 lstrcpyWtoA (tvisA.DUMMYUNIONNAME.item.pszText,
2102 tvisW->DUMMYUNIONNAME.item.pszText );
2106 tvisA.DUMMYUNIONNAME.item.pszText = LPSTR_TEXTCALLBACKA;
2107 tvisA.DUMMYUNIONNAME.item.cchTextMax = 0;
2111 tvisA.DUMMYUNIONNAME.item.iImage = tvisW->DUMMYUNIONNAME.item.iImage;
2112 tvisA.DUMMYUNIONNAME.item.iSelectedImage = tvisW->DUMMYUNIONNAME.item.iSelectedImage;
2113 tvisA.DUMMYUNIONNAME.item.cChildren = tvisW->DUMMYUNIONNAME.item.cChildren;
2114 tvisA.DUMMYUNIONNAME.item.lParam = tvisW->DUMMYUNIONNAME.item.lParam;
2116 lRes = TREEVIEW_InsertItemA(hwnd,wParam,(LPARAM)&tvisA);
2118 if (tvisA.DUMMYUNIONNAME.item.pszText!=LPSTR_TEXTCALLBACKA)
2120 COMCTL32_Free(tvisA.DUMMYUNIONNAME.item.pszText);
2129 TREEVIEW_DeleteItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
2131 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2133 TREEVIEW_ITEM *wineItem;
2135 TRACE("item = %08lx\n", lParam);
2137 if (lParam == (INT)TVI_ROOT) {
2138 TREEVIEW_RemoveTree (hwnd);
2140 iItem= (INT) lParam;
2141 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
2142 if (!wineItem) return FALSE;
2144 if (wineItem->pszText==LPSTR_TEXTCALLBACKA)
2145 TRACE("LPSTR_TEXTCALLBACK\n");
2147 TRACE("%s\n",wineItem->pszText);
2148 TREEVIEW_RemoveItem (hwnd, wineItem);
2151 TREEVIEW_QueueRefresh (hwnd);
2159 TREEVIEW_GetIndent (HWND hwnd)
2161 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2164 return infoPtr->uIndent;
2168 TREEVIEW_SetIndent (HWND hwnd, WPARAM wParam)
2170 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2174 newIndent=(INT) wParam;
2175 if (newIndent < MINIMUM_INDENT) newIndent=MINIMUM_INDENT;
2176 infoPtr->uIndent=newIndent;
2182 TREEVIEW_GetToolTips (HWND hwnd)
2185 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2188 return infoPtr->hwndToolTip;
2193 TREEVIEW_SetToolTips (HWND hwnd, WPARAM wParam)
2196 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2200 prevToolTip=infoPtr->hwndToolTip;
2201 infoPtr->hwndToolTip= (HWND) wParam;
2207 static LRESULT CALLBACK
2208 TREEVIEW_GetEditControl (HWND hwnd)
2211 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2213 return infoPtr->hwndEdit;
2217 TREEVIEW_Edit_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam,
2225 HDC hdc = (HDC) wParam;
2226 GetClientRect (hwnd, &rc);
2227 Rectangle (hdc, rc.left, rc.top, rc.right, rc.bottom);
2233 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
2237 if (wParam == VK_ESCAPE)
2239 TREEVIEW_EndEditLabelNow(GetParent(hwnd), (WPARAM)TRUE, 0);
2242 else if (wParam == VK_RETURN)
2243 TREEVIEW_EndEditLabelNow(GetParent(hwnd), (WPARAM)FALSE, 0);
2250 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd));
2252 return CallWindowProcA (infoPtr->wpEditOrig, hwnd, uMsg, wParam, lParam);
2263 /* should handle edit control messages here */
2266 TREEVIEW_Command (HWND hwnd, WPARAM wParam, LPARAM lParam)
2269 TRACE("%x %ld\n",wParam, lParam);
2271 switch (HIWORD(wParam))
2276 * Adjust the edit window size
2278 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2279 TREEVIEW_ITEM *editItem = TREEVIEW_ValidItem(infoPtr, infoPtr->editItem);
2280 INT iLength = GetWindowTextLengthA(infoPtr->hwndEdit);
2281 HDC hdc = GetDC(infoPtr->hwndEdit);
2284 if ( GetTextMetricsA(hdc, &tm) )
2286 LONG newWidth = (iLength * tm.tmAveCharWidth) + 15;
2291 editItem->text.left - 2,
2292 editItem->text.top - 1,
2294 editItem->text.bottom - editItem->text.top + 3,
2297 ReleaseDC(hwnd, hdc);
2303 /* TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
2308 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
2315 TREEVIEW_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
2318 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2320 if (infoPtr->bAutoSize)
2322 infoPtr->bAutoSize = FALSE;
2325 infoPtr->bAutoSize = TRUE;
2327 if (wParam == SIZE_RESTORED)
2329 infoPtr->uTotalWidth = LOWORD (lParam);
2330 infoPtr->uTotalHeight = HIWORD (lParam);
2332 FIXME("WM_SIZE flag %x %lx not handled\n", wParam, lParam);
2335 TREEVIEW_QueueRefresh (hwnd);
2342 TREEVIEW_StyleChanged (HWND hwnd, WPARAM wParam, LPARAM lParam)
2346 TRACE("(%x %lx)\n",wParam,lParam);
2348 TREEVIEW_Refresh (hwnd, hdc);
2349 ReleaseDC(hwnd,hdc);
2355 TREEVIEW_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
2357 TREEVIEW_INFO *infoPtr;
2358 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
2363 TRACE("wnd %x, style %lx\n",hwnd,dwStyle);
2364 /* allocate memory for info structure */
2365 infoPtr = (TREEVIEW_INFO *) COMCTL32_Alloc (sizeof(TREEVIEW_INFO));
2367 SetWindowLongA( hwnd, 0, (DWORD)infoPtr);
2369 if (infoPtr == NULL) {
2370 ERR("could not allocate info memory!\n");
2374 if ((TREEVIEW_INFO*) GetWindowLongA( hwnd, 0) != infoPtr) {
2375 ERR("pointer assignment error!\n");
2381 /* set default settings */
2382 infoPtr->uInternalStatus=0;
2383 infoPtr->uNumItems=0;
2384 infoPtr->clrBk = GetSysColor (COLOR_WINDOW);
2385 infoPtr->clrText = GetSysColor (COLOR_WINDOWTEXT);
2386 infoPtr->clrLine = GetSysColor (COLOR_WINDOWTEXT);
2387 infoPtr->clrInsertMark = GetSysColor (COLOR_BTNTEXT);
2390 infoPtr->uIndent = 15;
2391 infoPtr->himlNormal = NULL;
2392 infoPtr->himlState = NULL;
2393 infoPtr->uItemHeight = -1;
2394 GetTextMetricsA (hdc, &tm);
2395 infoPtr->hFont = GetStockObject (DEFAULT_GUI_FONT);
2396 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
2397 logFont.lfWeight=FW_BOLD;
2398 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
2400 infoPtr->items = NULL;
2401 infoPtr->selectedItem=0;
2402 infoPtr->clrText=-1; /* use system color */
2403 infoPtr->dropItem=0;
2404 infoPtr->insertMarkItem=0;
2405 infoPtr->insertBeforeorAfter=0;
2406 infoPtr->pCallBackSort=NULL;
2407 infoPtr->uScrollTime = 300; /* milliseconds */
2408 infoPtr->wpEditOrig = NULL; /* we haven't subclassed anything yet */
2410 infoPtr->hwndToolTip=0;
2411 if (!(dwStyle & TVS_NOTOOLTIPS)) { /* Create tooltip control */
2414 infoPtr->hwndToolTip =
2415 CreateWindowExA (0, TOOLTIPS_CLASSA, NULL, 0,
2416 CW_USEDEFAULT, CW_USEDEFAULT,
2417 CW_USEDEFAULT, CW_USEDEFAULT,
2420 /* Send NM_TOOLTIPSCREATED notification */
2421 if (infoPtr->hwndToolTip) {
2422 NMTOOLTIPSCREATED nmttc;
2424 nmttc.hdr.hwndFrom = hwnd;
2425 nmttc.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2426 nmttc.hdr.code = NM_TOOLTIPSCREATED;
2427 nmttc.hwndToolTips = infoPtr->hwndToolTip;
2429 SendMessageA (GetParent (hwnd), WM_NOTIFY,
2430 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmttc);
2433 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
2434 ti.cbSize = sizeof(TTTOOLINFOA);
2435 ti.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_TRANSPARENT ;
2438 ti.lpszText = "Test"; /* LPSTR_TEXTCALLBACK; */
2439 SetRectEmpty (&ti.rect);
2441 SendMessageA (infoPtr->hwndToolTip, TTM_ADDTOOLA, 0, (LPARAM)&ti);
2444 infoPtr->hwndEdit = CreateWindowExA (
2448 WS_CHILD | WS_BORDER | ES_AUTOHSCROLL |
2449 ES_WANTRETURN | ES_LEFT,
2452 0,0,0); /* FIXME: (HMENU)IDTVEDIT,pcs->hInstance,0);*/
2454 SendMessageA ( infoPtr->hwndEdit, WM_SETFONT, infoPtr->hFont, FALSE);
2455 infoPtr->wpEditOrig = (WNDPROC)SetWindowLongA (
2458 (LONG) TREEVIEW_Edit_SubclassProc);
2460 if (dwStyle & TVS_CHECKBOXES) {
2464 infoPtr->himlState =
2465 ImageList_Create (16, 16,ILC_COLOR|ILC_MASK, 15, 1);
2467 hbmLoad = LoadBitmapA (COMCTL32_hModule, MAKEINTRESOURCEA(IDT_CHECK));
2468 TRACE ("%x\n",hbmLoad);
2469 nIndex = ImageList_AddMasked (infoPtr->himlState, hbmLoad, CLR_DEFAULT);
2470 TRACE ("%d\n",nIndex);
2471 DeleteObject (hbmLoad);
2473 ReleaseDC (hwnd, hdc);
2480 TREEVIEW_Destroy (HWND hwnd)
2482 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2485 TREEVIEW_RemoveTree (hwnd);
2486 SetWindowLongA (hwnd, 0, (DWORD)NULL);
2488 if (infoPtr->Timer & TV_REFRESH_TIMER_SET)
2489 KillTimer (hwnd, TV_REFRESH_TIMER);
2490 if (infoPtr->hwndToolTip)
2491 DestroyWindow (infoPtr->hwndToolTip);
2493 COMCTL32_Free (infoPtr);
2499 TREEVIEW_Paint (HWND hwnd, WPARAM wParam, LPARAM lParam)
2505 hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
2506 TREEVIEW_Refresh (hwnd, hdc);
2507 if(!wParam) EndPaint (hwnd, &ps);
2514 TREEVIEW_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2516 TREEVIEW_SendSimpleNotify (hwnd, NM_SETFOCUS);
2517 InvalidateRect(hwnd, NULL, FALSE);
2522 TREEVIEW_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2524 TREEVIEW_SendSimpleNotify (hwnd, NM_KILLFOCUS);
2525 InvalidateRect(hwnd, NULL, FALSE);
2530 TREEVIEW_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
2532 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2533 HBRUSH hBrush = CreateSolidBrush (infoPtr->clrBk);
2537 GetClientRect (hwnd, &rect);
2538 FillRect ((HDC)wParam, &rect, hBrush);
2539 DeleteObject (hBrush);
2555 TREEVIEW_SendSimpleNotify (HWND hwnd, UINT code)
2560 nmhdr.hwndFrom = hwnd;
2561 nmhdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2564 return (BOOL) SendMessageA (GetParent (hwnd), WM_NOTIFY,
2565 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
2571 TREEVIEW_SendTreeviewNotify (HWND hwnd, UINT code, UINT action,
2572 HTREEITEM oldItem, HTREEITEM newItem)
2575 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2577 TREEVIEW_ITEM *wineItem;
2579 TRACE("code:%x action:%x olditem:%x newitem:%x\n",
2580 code,action,(INT)oldItem,(INT)newItem);
2581 nmhdr.hdr.hwndFrom = hwnd;
2582 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2583 nmhdr.hdr.code = code;
2584 nmhdr.action = action;
2586 wineItem=& infoPtr->items[(INT)oldItem];
2587 nmhdr.itemOld.mask = wineItem->mask;
2588 nmhdr.itemOld.hItem = wineItem->hItem;
2589 nmhdr.itemOld.state = wineItem->state;
2590 nmhdr.itemOld.stateMask = wineItem->stateMask;
2591 nmhdr.itemOld.iImage = wineItem->iImage;
2592 nmhdr.itemOld.pszText = wineItem->pszText;
2593 nmhdr.itemOld.cchTextMax= wineItem->cchTextMax;
2594 nmhdr.itemOld.iImage = wineItem->iImage;
2595 nmhdr.itemOld.iSelectedImage = wineItem->iSelectedImage;
2596 nmhdr.itemOld.cChildren = wineItem->cChildren;
2597 nmhdr.itemOld.lParam = wineItem->lParam;
2601 wineItem=& infoPtr->items[(INT)newItem];
2602 nmhdr.itemNew.mask = wineItem->mask;
2603 nmhdr.itemNew.hItem = wineItem->hItem;
2604 nmhdr.itemNew.state = wineItem->state;
2605 nmhdr.itemNew.stateMask = wineItem->stateMask;
2606 nmhdr.itemNew.iImage = wineItem->iImage;
2607 nmhdr.itemNew.pszText = wineItem->pszText;
2608 nmhdr.itemNew.cchTextMax= wineItem->cchTextMax;
2609 nmhdr.itemNew.iImage = wineItem->iImage;
2610 nmhdr.itemNew.iSelectedImage = wineItem->iSelectedImage;
2611 nmhdr.itemNew.cChildren = wineItem->cChildren;
2612 nmhdr.itemNew.lParam = wineItem->lParam;
2618 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2619 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2624 TREEVIEW_SendTreeviewDnDNotify (HWND hwnd, UINT code, HTREEITEM dragItem,
2627 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2629 TREEVIEW_ITEM *wineItem;
2631 TRACE("code:%x dragitem:%x\n", code,(INT)dragItem);
2633 nmhdr.hdr.hwndFrom = hwnd;
2634 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2635 nmhdr.hdr.code = code;
2637 wineItem=& infoPtr->items[(INT)dragItem];
2638 nmhdr.itemNew.mask = wineItem->mask;
2639 nmhdr.itemNew.hItem = wineItem->hItem;
2640 nmhdr.itemNew.state = wineItem->state;
2641 nmhdr.itemNew.lParam = wineItem->lParam;
2643 nmhdr.ptDrag.x = pt.x;
2644 nmhdr.ptDrag.y = pt.y;
2646 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2647 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2654 TREEVIEW_SendDispInfoNotify (HWND hwnd, TREEVIEW_ITEM *wineItem,
2655 UINT code, UINT what)
2661 TRACE("item %d, action %x, state %d\n",
2662 (INT)wineItem->hItem,
2664 (INT)wineItem->state);
2666 tvdi.hdr.hwndFrom = hwnd;
2667 tvdi.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2668 tvdi.hdr.code = code;
2669 tvdi.item.mask = what;
2670 tvdi.item.hItem = wineItem->hItem;
2671 tvdi.item.state = wineItem->state;
2672 tvdi.item.lParam = wineItem->lParam;
2673 tvdi.item.pszText = COMCTL32_Alloc (128*sizeof(char));
2674 tvdi.item.cchTextMax = 128;
2675 buf = tvdi.item.pszText;
2677 retval=(BOOL)SendMessageA (
2680 (WPARAM)tvdi.hdr.idFrom,
2683 if (what & TVIF_TEXT) {
2684 wineItem->pszText = tvdi.item.pszText;
2685 if (buf==tvdi.item.pszText) {
2686 wineItem->cchTextMax = 128;
2688 TRACE("user-supplied buffer\n");
2689 COMCTL32_Free (buf);
2690 wineItem->cchTextMax = 0;
2693 if (what & TVIF_SELECTEDIMAGE)
2694 wineItem->iSelectedImage = tvdi.item.iSelectedImage;
2695 if (what & TVIF_IMAGE)
2696 wineItem->iImage = tvdi.item.iImage;
2697 if (what & TVIF_CHILDREN)
2698 wineItem->cChildren = tvdi.item.cChildren;
2706 TREEVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
2709 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2710 NMTVCUSTOMDRAW nmcdhdr;
2711 LPNMCUSTOMDRAW nmcd;
2713 TRACE("drawstage:%lx hdc:%x\n", dwDrawStage, hdc);
2715 nmcd= & nmcdhdr.nmcd;
2716 nmcd->hdr.hwndFrom = hwnd;
2717 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2718 nmcd->hdr.code = NM_CUSTOMDRAW;
2719 nmcd->dwDrawStage= dwDrawStage;
2721 nmcd->rc.left = rc.left;
2722 nmcd->rc.right = rc.right;
2723 nmcd->rc.bottom = rc.bottom;
2724 nmcd->rc.top = rc.top;
2725 nmcd->dwItemSpec = 0;
2726 nmcd->uItemState = 0;
2727 nmcd->lItemlParam= 0;
2728 nmcdhdr.clrText = infoPtr->clrText;
2729 nmcdhdr.clrTextBk= infoPtr->clrBk;
2732 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2733 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2739 /* FIXME: need to find out when the flags in uItemState need to be set */
2742 TREEVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
2743 TREEVIEW_ITEM *wineItem, UINT uItemDrawState)
2745 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2746 NMTVCUSTOMDRAW nmcdhdr;
2747 LPNMCUSTOMDRAW nmcd;
2748 DWORD dwDrawStage,dwItemSpec;
2752 dwDrawStage=CDDS_ITEM | uItemDrawState;
2753 dwItemSpec=(DWORD)wineItem->hItem;
2755 if (wineItem->hItem==infoPtr->selectedItem) uItemState|=CDIS_SELECTED;
2756 if (wineItem->hItem==infoPtr->focusItem) uItemState|=CDIS_FOCUS;
2757 if (wineItem->hItem==infoPtr->hotItem) uItemState|=CDIS_HOT;
2759 nmcd= & nmcdhdr.nmcd;
2760 nmcd->hdr.hwndFrom = hwnd;
2761 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2762 nmcd->hdr.code = NM_CUSTOMDRAW;
2763 nmcd->dwDrawStage= dwDrawStage;
2765 nmcd->rc.left = wineItem->rect.left;
2766 nmcd->rc.right = wineItem->rect.right;
2767 nmcd->rc.bottom = wineItem->rect.bottom;
2768 nmcd->rc.top = wineItem->rect.top;
2769 nmcd->dwItemSpec = dwItemSpec;
2770 nmcd->uItemState = uItemState;
2771 nmcd->lItemlParam= wineItem->lParam;
2772 nmcdhdr.clrText = infoPtr->clrText;
2773 nmcdhdr.clrTextBk= infoPtr->clrBk;
2774 nmcdhdr.iLevel = wineItem->iLevel;
2776 TRACE("drawstage:%lx hdc:%x item:%lx, itemstate:%x, lItemlParam:%lx\n",
2777 nmcd->dwDrawStage, nmcd->hdc, nmcd->dwItemSpec,
2778 nmcd->uItemState, nmcd->lItemlParam);
2780 retval=SendMessageA (GetParent (hwnd), WM_NOTIFY,
2781 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2783 infoPtr->clrText=nmcdhdr.clrText;
2784 infoPtr->clrBk =nmcdhdr.clrTextBk;
2785 return (BOOL) retval;
2790 /* Note:If the specified item is the child of a collapsed parent item,
2791 the parent's list of child items is (recursively) expanded to reveal the
2792 specified item. This is mentioned for TREEVIEW_SelectItem; don't
2793 know if it also applies here.
2797 TREEVIEW_Expand (HWND hwnd, WPARAM wParam, LPARAM lParam)
2799 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2800 TREEVIEW_ITEM *wineItem;
2804 flag = (UINT) wParam;
2805 expand = (INT) lParam;
2807 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2811 if (!wineItem->cChildren)
2814 if (wineItem->pszText==LPSTR_TEXTCALLBACKA)
2815 TRACE ("For item %d, flags %d, state %d\n",
2816 expand, flag, wineItem->state);
2818 TRACE("For (%s) item:%d, flags %x, state:%d\n",
2819 wineItem->pszText, flag, expand, wineItem->state);
2821 if (wineItem->cChildren==I_CHILDRENCALLBACK) {
2822 FIXME("we don't handle I_CHILDRENCALLBACK yet\n");
2826 if (flag == TVE_TOGGLE) { /* FIXME: check exact behaviour here */
2827 flag &= ~TVE_TOGGLE; /* ie: bitwise ops or 'case' ops */
2828 if (wineItem->state & TVIS_EXPANDED)
2829 flag |= TVE_COLLAPSE;
2836 case TVE_COLLAPSERESET:
2837 TRACE(" case TVE_COLLAPSERESET\n");
2838 if (!wineItem->state & TVIS_EXPANDED)
2841 wineItem->state &= ~(TVIS_EXPANDEDONCE | TVIS_EXPANDED);
2842 TREEVIEW_RemoveAllChildren (hwnd, wineItem);
2846 TRACE(" case TVE_COLLAPSE\n");
2847 if (!wineItem->state & TVIS_EXPANDED)
2850 wineItem->state &= ~TVIS_EXPANDED;
2854 TRACE(" case TVE_EXPAND\n");
2855 if (wineItem->state & TVIS_EXPANDED)
2858 TRACE(" is not expanded...\n");
2860 if (!(wineItem->state & TVIS_EXPANDEDONCE))
2862 TRACE(" and has never been expanded...\n");
2863 wineItem->state |= TVIS_EXPANDED;
2865 /* this item has never been expanded */
2866 if (TREEVIEW_SendTreeviewNotify (
2873 TRACE(" TVN_ITEMEXPANDINGA returned TRUE, exiting...\n");
2878 * Since the TVN_ITEMEXPANDINGA message may has caused the parent to
2879 * insert new items which in turn may have cause items placeholder
2880 * reallocation, I reassign the current item pointer so we have
2881 * something valid to work with...
2882 * However, this should not be necessary,
2883 * investigation required in TREEVIEW_InsertItemA
2885 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2889 "Catastropic situation, cannot retreive item #%d\n",
2894 wineItem->state |= TVIS_EXPANDEDONCE;
2895 TRACE(" TVN_ITEMEXPANDINGA sent...\n");
2897 TREEVIEW_SendTreeviewNotify (
2904 TRACE(" TVN_ITEMEXPANDEDA sent...\n");
2909 /* this item has already been expanded */
2910 wineItem->state |= TVIS_EXPANDED;
2914 case TVE_EXPANDPARTIAL:
2915 TRACE(" case TVE_EXPANDPARTIAL\n");
2916 FIXME("TVE_EXPANDPARTIAL not implemented\n");
2917 wineItem->state ^=TVIS_EXPANDED;
2918 wineItem->state |=TVIS_EXPANDEDONCE;
2922 TRACE("Exiting, Item %d state is now %d...\n",
2926 TREEVIEW_QueueRefresh (hwnd);
2932 static TREEVIEW_ITEM *
2933 TREEVIEW_HitTestPoint (HWND hwnd, POINT pt)
2935 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2936 TREEVIEW_ITEM *wineItem;
2939 GetClientRect (hwnd, &rect);
2941 if (!infoPtr->firstVisible) return NULL;
2943 wineItem=&infoPtr->items [(INT)infoPtr->firstVisible];
2945 while ((wineItem!=NULL) && (pt.y > wineItem->rect.bottom))
2946 wineItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
2958 TREEVIEW_HitTest (HWND hwnd, LPARAM lParam)
2960 LPTVHITTESTINFO lpht=(LPTVHITTESTINFO) lParam;
2961 TREEVIEW_ITEM *wineItem;
2965 GetClientRect (hwnd, &rect);
2969 if (x < rect.left) status|=TVHT_TOLEFT;
2970 if (x > rect.right) status|=TVHT_TORIGHT;
2971 if (y < rect.top ) status|=TVHT_ABOVE;
2972 if (y > rect.bottom) status|=TVHT_BELOW;
2979 wineItem=TREEVIEW_HitTestPoint (hwnd, lpht->pt);
2981 lpht->flags=TVHT_NOWHERE;
2987 if (x < wineItem->expandBox.left) {
2988 lpht->flags |= TVHT_ONITEMINDENT;
2991 if ( PtInRect ( &wineItem->expandBox, lpht->pt)) {
2992 lpht->flags |= TVHT_ONITEMBUTTON;
2995 if ( PtInRect ( &wineItem->bitmap, lpht->pt)) {
2996 lpht->flags |= TVHT_ONITEMICON;
2999 if ( PtInRect ( &wineItem->statebitmap, lpht->pt)) {
3000 lpht->flags |= TVHT_ONITEMSTATEICON;
3003 if ( PtInRect ( &wineItem->text, lpht->pt)) {
3004 lpht->flags |= TVHT_ONITEMLABEL;
3008 lpht->flags|=TVHT_ONITEMRIGHT;
3012 lpht->hItem=wineItem->hItem;
3013 TRACE ("(%ld,%ld):result %x\n",lpht->pt.x,lpht->pt.y,lpht->flags);
3015 return (LRESULT) wineItem->hItem;
3019 TREEVIEW_EditLabelA (HWND hwnd, WPARAM wParam, LPARAM lParam)
3021 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3022 TREEVIEW_ITEM *wineItem;
3025 * If the style allow editing...
3027 if ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_EDITLABELS )
3030 if ( infoPtr->editItem == 0 ) /* If we are not curently editing */
3032 wineItem = TREEVIEW_ValidItem(infoPtr,(HTREEITEM) lParam);
3033 if ( wineItem == NULL )
3035 ERR("Cannot get valid TREEVIEW_ITEM for lParam\n");
3039 TRACE("Edit started for %s.\n", wineItem->pszText);
3040 infoPtr->editItem = wineItem->hItem;
3044 * It is common practice for a windows program to get this
3045 * edit control and then subclass it. It is assumed that a
3046 * new edit control is given every time.
3048 * As a result some programs really mess up the edit control
3049 * so we need to destory our old edit control and create a new
3050 * one. Recycling would be nice but we would need to reset
3051 * everything. So recreating may just be easyier
3054 DestroyWindow(infoPtr->hwndEdit);
3055 infoPtr->hwndEdit = CreateWindowExA (
3059 WS_CHILD | WS_BORDER | ES_AUTOHSCROLL |
3060 ES_WANTRETURN | ES_LEFT,
3063 0,0,0); /* FIXME: (HMENU)IDTVEDIT,pcs->hInstance,0);*/
3068 (LONG) TREEVIEW_Edit_SubclassProc);
3071 SendMessageA ( infoPtr->hwndEdit, WM_SETFONT, infoPtr->hFont, FALSE);
3073 SetWindowTextA( infoPtr->hwndEdit, wineItem->pszText );
3074 SendMessageA ( infoPtr->hwndEdit, EM_SETSEL, 0, -1 );
3077 ** NOTE: this must be after the edit control is created
3078 ** (according to TVN_BEGINLABELEDITA docs), before position is set.
3080 if ( TREEVIEW_SendDispInfoNotify( /* Return true to cancel edition */
3083 TVN_BEGINLABELEDITA,
3087 ** FIXME: Is this right, should we return a handle even though edit was cancelled?
3089 TRACE("Edit cancelled by TVN_BEGINLABELEDITA for %s.\n", wineItem->pszText);
3091 TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)TRUE, 0);
3099 wineItem->text.left - 2,
3100 wineItem->text.top - 1,
3101 wineItem->text.right - wineItem->text.left + 20 ,
3102 wineItem->text.bottom - wineItem->text.top + 3,
3105 SetFocus ( infoPtr->hwndEdit);
3106 ShowWindow ( infoPtr->hwndEdit, SW_SHOW);
3112 ** return NULL since we cannot edit this.
3118 return infoPtr->hwndEdit;
3122 TREEVIEW_EndEditLabelNow (HWND hwnd, WPARAM wParam, LPARAM lParam)
3124 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3125 TREEVIEW_ITEM *editedItem = TREEVIEW_ValidItem (infoPtr, infoPtr->editItem);
3126 BOOL bRevert = (BOOL)wParam;
3134 ** NOTE: we have to get the new text before calling TVN_ENDLABELEDITA
3135 ** since some apps(eg regedit, win98) validate the text in TVN_ENDLABELEDITA.
3138 oldText = editedItem->pszText;
3140 if ( !bRevert ) /* wParam is set to true to cancel the edition */
3143 iLength = GetWindowTextLengthA( infoPtr->hwndEdit );
3146 WARN("Zero length string for new label(not changing).");
3150 newText = COMCTL32_Alloc( iLength+1 );
3151 if( newText == NULL )
3153 ERR("OutOfMemory, cannot allocate space for label");
3156 GetWindowTextA( infoPtr->hwndEdit, newText, iLength+1);
3165 * notify our parent with the new string(or NULL if wParam==TRUE)
3167 tvdi.hdr.hwndFrom = hwnd;
3168 tvdi.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
3169 tvdi.hdr.code = TVN_ENDLABELEDITA;
3170 tvdi.item.hItem = editedItem->hItem;
3171 tvdi.item.lParam = editedItem->lParam;
3172 tvdi.item.mask = TVIF_TEXT|TVIF_HANDLE|TVIF_PARAM;
3173 tvdi.item.pszText = newText;
3175 if(!SendMessageA ( /* return false to cancel edition */
3178 (WPARAM)tvdi.hdr.idFrom,
3181 if( newText == NULL ) /*we are supposed to ignore the return if (and pszText==NULL), MSDOCs */
3185 if (oldText != LPSTR_TEXTCALLBACKA)
3190 if( newText != NULL )
3191 COMCTL32_Free(newText);
3193 editedItem->pszText=oldText; /* revert back to the old label */
3197 COMCTL32_Free(oldText);
3199 editedItem->pszText=newText; /* use the new label */
3202 else if( newText!=NULL )
3205 ** Is really this necessary? shouldnt an app update its internal data in TVN_ENDLABELEDITA?
3210 * This is a callback string so we need
3211 * to inform the parent that the string
3215 tvdi.hdr.hwndFrom = hwnd;
3216 tvdi.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
3217 tvdi.hdr.code = TVN_SETDISPINFOA;
3218 tvdi.item.mask = TVIF_TEXT;
3219 tvdi.item.pszText = newText;
3224 (WPARAM)tvdi.hdr.idFrom,
3229 COMCTL32_Free(newText);
3233 ShowWindow(infoPtr->hwndEdit, SW_HIDE);
3234 EnableWindow(infoPtr->hwndEdit, FALSE);
3236 /* update the window to eliminate fragments and the like */
3237 TreeView_GetItemRect(hwnd,infoPtr->editItem,&itemRect,FALSE);
3238 RedrawWindow(hwnd,&itemRect,0,RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW);
3240 infoPtr->editItem = 0;
3242 return !bRevert; /* return true if label edit succesful, otherwise false */
3248 TREEVIEW_LButtonDoubleClick (HWND hwnd, WPARAM wParam, LPARAM lParam)
3250 TREEVIEW_ITEM *wineItem;
3254 pt.x = (INT)LOWORD(lParam);
3255 pt.y = (INT)HIWORD(lParam);
3258 wineItem=TREEVIEW_HitTestPoint (hwnd, pt);
3259 if (!wineItem) return 0;
3260 TRACE("item %d \n",(INT)wineItem->hItem);
3262 if (TREEVIEW_SendSimpleNotify (hwnd, NM_DBLCLK)!=TRUE) { /* FIXME!*/
3263 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) wineItem->hItem);
3270 TREEVIEW_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
3272 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3276 ht.pt.x = (INT)LOWORD(lParam);
3277 ht.pt.y = (INT)HIWORD(lParam);
3280 iItem=TREEVIEW_HitTest (hwnd, (LPARAM) &ht);
3281 TRACE("item %d \n",iItem);
3283 if (ht.flags & TVHT_ONITEMBUTTON) {
3284 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) iItem);
3288 infoPtr->uInternalStatus|=TV_LDRAG;
3295 TREEVIEW_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
3297 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3299 TREEVIEW_ITEM *wineItem;
3301 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
3303 ht.pt.x = (INT)LOWORD(lParam);
3304 ht.pt.y = (INT)HIWORD(lParam);
3308 /* Return true to cancel default behaviour */
3309 if ( TREEVIEW_SendSimpleNotify (hwnd, NM_CLICK) )
3313 iItem = TREEVIEW_HitTest (hwnd, (LPARAM) &ht);
3314 TRACE ("%d\n",iItem);
3318 wineItem = TREEVIEW_ValidItem(infoPtr, (HTREEITEM)iItem);
3321 * if we are TVS_SINGLEEXPAND then we want this single click to
3322 * do a bunch of things.
3324 if ((dwStyle & TVS_SINGLEEXPAND)&&
3325 ( ht.flags & (TVHT_ONITEMLABEL | TVHT_ONITEMICON))&&
3326 ( infoPtr->editItem == 0 ))
3328 TREEVIEW_ITEM *SelItem;
3330 * Send the notification
3332 TREEVIEW_SendTreeviewNotify (hwnd,TVN_SINGLEEXPAND,0,
3333 (HTREEITEM)iItem,0);
3335 * Close the previous selection all the way to the root
3336 * as long as the new selection is not a child
3339 if ((infoPtr->selectedItem)&&(infoPtr->selectedItem != (HTREEITEM)iItem))
3341 BOOL closeit = TRUE;
3344 while (closeit && SelItem)
3346 closeit = (SelItem->hItem != infoPtr->selectedItem);
3347 SelItem = TREEVIEW_ValidItem(infoPtr,SelItem->parent);
3352 SelItem = TREEVIEW_ValidItem(infoPtr,infoPtr->selectedItem);
3353 while ((SelItem)&&(SelItem->hItem != wineItem->hItem))
3355 TREEVIEW_Expand (hwnd,(WPARAM)TVE_COLLAPSE,(LPARAM)SelItem->hItem);
3356 SelItem = TREEVIEW_ValidItem(infoPtr,SelItem->parent);
3362 * Expand the current item
3364 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) wineItem->hItem);
3367 infoPtr->uInternalStatus &= ~(TV_LDRAG | TV_LDRAGGING);
3370 * If the style allow editing and the node is already selected
3371 * and the click occured on the item label...
3373 if ( ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_EDITLABELS ) &&
3374 ( wineItem->state & TVIS_SELECTED ) &&
3375 ( ht.flags & TVHT_ONITEMLABEL ))
3377 if ( infoPtr->editItem == 0 ) /* If we are not curently editing */
3379 if( SendMessageA(hwnd, TVM_EDITLABELA, 0, (LPARAM)iItem) == 0)
3383 else if ( infoPtr->editItem != 0 ) /* If we are curently editing */
3385 TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
3387 else if ( ht.flags & (TVHT_ONITEMLABEL | TVHT_ONITEMICON))
3389 TREEVIEW_DoSelectItem ( hwnd, TVGN_CARET, (HTREEITEM)iItem, TVC_BYMOUSE);
3392 if (ht.flags & TVHT_ONITEMSTATEICON) {
3395 if (dwStyle & TVS_CHECKBOXES) { /* TVS_CHECKBOXES requires _us_ */
3396 int state; /* to toggle the current state */
3397 state=1-(wineItem->state>>12);
3398 TRACE ("state:%x\n", state);
3399 wineItem->state&= ~TVIS_STATEIMAGEMASK;
3400 wineItem->state|=state<<12;
3401 TRACE ("state:%x\n", wineItem->state);
3402 TREEVIEW_QueueRefresh (hwnd);
3410 TREEVIEW_RButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
3412 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3415 infoPtr->uInternalStatus|=TV_RDRAG;
3420 TREEVIEW_RButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
3422 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3425 if (TREEVIEW_SendSimpleNotify (hwnd, NM_RCLICK)) return 0;
3426 infoPtr->uInternalStatus&= ~(TV_RDRAG | TV_RDRAGGING);
3432 TREEVIEW_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
3434 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3435 TREEVIEW_ITEM *hotItem;
3438 pt.x=(INT) LOWORD (lParam);
3439 pt.y=(INT) HIWORD (lParam);
3440 hotItem=TREEVIEW_HitTestPoint (hwnd, pt);
3441 if (!hotItem) return 0;
3442 infoPtr->focusItem=hotItem->hItem;
3444 if ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_DISABLEDRAGDROP) return 0;
3446 if (infoPtr->uInternalStatus & TV_LDRAG) {
3447 TREEVIEW_SendTreeviewDnDNotify (hwnd, TVN_BEGINDRAGA, hotItem->hItem, pt);
3448 infoPtr->uInternalStatus &= ~TV_LDRAG;
3449 infoPtr->uInternalStatus |= TV_LDRAGGING;
3450 infoPtr->dropItem=hotItem->hItem;
3454 if (infoPtr->uInternalStatus & TV_RDRAG) {
3455 TREEVIEW_SendTreeviewDnDNotify (hwnd, TVN_BEGINRDRAGA, hotItem->hItem, pt);
3456 infoPtr->uInternalStatus &= ~TV_RDRAG;
3457 infoPtr->uInternalStatus |= TV_RDRAGGING;
3458 infoPtr->dropItem=hotItem->hItem;
3467 TREEVIEW_CreateDragImage (HWND hwnd, WPARAM wParam, LPARAM lParam)
3469 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3470 TREEVIEW_ITEM *dragItem;
3474 HBITMAP hbmp,hOldbmp;
3481 if (!(infoPtr->himlNormal)) return 0;
3482 dragItem=TREEVIEW_ValidItem (infoPtr, (HTREEITEM) lParam);
3484 if (!dragItem) return 0;
3486 if (dragItem->pszText==LPSTR_TEXTCALLBACKA) {
3487 TREEVIEW_SendDispInfoNotify (hwnd, dragItem, TVN_GETDISPINFOA, TVIF_TEXT);
3489 itemtxt=dragItem->pszText;
3491 hwtop=GetDesktopWindow ();
3492 htopdc= GetDC (hwtop);
3493 hdc=CreateCompatibleDC (htopdc);
3495 hOldFont=SelectObject (hdc, infoPtr->hFont);
3496 GetTextExtentPoint32A (hdc, itemtxt, lstrlenA (itemtxt), &size);
3497 TRACE("%d %d %s %d\n",size.cx,size.cy,itemtxt,lstrlenA(itemtxt));
3498 hbmp=CreateCompatibleBitmap (htopdc, size.cx, size.cy);
3499 hOldbmp=SelectObject (hdc, hbmp);
3501 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &cy);
3503 if (cy>size.cy) size.cy=cy;
3505 infoPtr->dragList=ImageList_Create (size.cx, size.cy, ILC_COLOR, 10, 10);
3506 ImageList_Draw (infoPtr->himlNormal, dragItem->iImage, hdc, 0, 0, ILD_NORMAL);
3509 ImageList_GetImageInfo (infoPtr->himlNormal, dragItem->hItem, &iminfo);
3510 ImageList_AddMasked (infoPtr->dragList, iminfo.hbmImage, CLR_DEFAULT);
3513 /* draw item text */
3515 SetRect (&rc, cx, 0, size.cx,size.cy);
3516 DrawTextA (hdc, itemtxt, lstrlenA (itemtxt), &rc, DT_LEFT);
3517 SelectObject (hdc, hOldFont);
3518 SelectObject (hdc, hOldbmp);
3520 ImageList_Add (infoPtr->dragList, hbmp, 0);
3523 DeleteObject (hbmp);
3524 ReleaseDC (hwtop, htopdc);
3526 return (LRESULT)infoPtr->dragList;
3531 TREEVIEW_DoSelectItem (HWND hwnd, INT action, HTREEITEM newSelect, INT cause)
3534 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3535 TREEVIEW_ITEM *prevItem,*wineItem;
3538 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)newSelect);
3540 TRACE("Entering item %d, flag %x, cause %x, state %d\n",
3546 if ( (wineItem) && (wineItem->parent))
3549 * If the item has a collapse parent expand the parent so he
3550 * can expose the item
3552 TREEVIEW_ITEM *parentItem = TREEVIEW_ValidItem (infoPtr, wineItem->parent);
3553 if ( !(parentItem->state & TVIS_EXPANDED))
3554 TREEVIEW_Expand (hwnd, TVE_EXPAND, (LPARAM) wineItem->parent);
3560 prevSelect=(INT)infoPtr->selectedItem;
3562 if ((HTREEITEM)prevSelect==newSelect)
3565 prevItem= TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect);
3568 if (TREEVIEW_SendTreeviewNotify(
3572 (HTREEITEM)prevSelect,
3573 (HTREEITEM)newSelect))
3574 return FALSE; /* FIXME: OK? */
3577 prevItem->state &= ~TVIS_SELECTED;
3579 wineItem->state |= TVIS_SELECTED;
3581 infoPtr->selectedItem=(HTREEITEM)newSelect;
3583 TREEVIEW_SendTreeviewNotify(
3587 (HTREEITEM)prevSelect,
3588 (HTREEITEM)newSelect);
3592 case TVGN_DROPHILITE:
3593 prevItem= TREEVIEW_ValidItem (infoPtr, infoPtr->dropItem);
3596 prevItem->state &= ~TVIS_DROPHILITED;
3598 infoPtr->dropItem=(HTREEITEM)newSelect;
3601 wineItem->state |=TVIS_DROPHILITED;
3605 case TVGN_FIRSTVISIBLE:
3606 FIXME("FIRSTVISIBLE not implemented\n");
3610 TREEVIEW_QueueRefresh (hwnd);
3612 TRACE("Leaving state %d\n", wineItem->state);
3616 /* FIXME: handle NM_KILLFocus etc */
3618 TREEVIEW_SelectItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
3621 return TREEVIEW_DoSelectItem (hwnd, wParam, (HTREEITEM) lParam, TVC_UNKNOWN);
3628 TREEVIEW_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
3631 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3633 TRACE("%x\n",infoPtr->hFont);
3634 return infoPtr->hFont;
3638 TREEVIEW_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
3641 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3644 HFONT hFont, hOldFont;
3648 TRACE("%x %lx\n",wParam, lParam);
3650 infoPtr->hFont = (HFONT)wParam;
3652 hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
3654 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
3655 logFont.lfWeight=FW_BOLD;
3656 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
3659 hOldFont = SelectObject (hdc, hFont);
3660 GetTextMetricsA (hdc, &tm);
3661 height= tm.tmHeight + tm.tmExternalLeading + FOCUS_BORDER;
3662 if (height>infoPtr->uRealItemHeight)
3663 infoPtr->uRealItemHeight=height;
3664 SelectObject (hdc, hOldFont);
3668 TREEVIEW_QueueRefresh (hwnd);
3676 TREEVIEW_VScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
3679 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3683 TRACE("wp %x, lp %lx\n", wParam, lParam);
3684 if (!infoPtr->uInternalStatus & TV_VSCROLL) return FALSE;
3686 switch (LOWORD (wParam)) {
3688 if (!infoPtr->cy) return FALSE;
3689 infoPtr->cy -= infoPtr->uRealItemHeight;
3690 if (infoPtr->cy < 0) infoPtr->cy=0;
3693 nVisibleItems = infoPtr->uVisibleHeight / infoPtr->uRealItemHeight;
3694 maxHeight=infoPtr->uTotalHeight - nVisibleItems * infoPtr->uRealItemHeight;
3695 if (infoPtr->cy >= maxHeight) return FALSE;
3696 infoPtr->cy += infoPtr->uRealItemHeight;
3697 if (infoPtr->cy >= maxHeight)
3698 infoPtr->cy = maxHeight;
3701 if (!infoPtr->cy) return FALSE;
3702 infoPtr->cy -= infoPtr->uVisibleHeight;
3703 if (infoPtr->cy < 0) infoPtr->cy=0;
3706 nVisibleItems = infoPtr->uVisibleHeight / infoPtr->uRealItemHeight;
3707 maxHeight=infoPtr->uTotalHeight - nVisibleItems * infoPtr->uRealItemHeight;
3708 if (infoPtr->cy == maxHeight) return FALSE;
3709 infoPtr->cy += infoPtr->uVisibleHeight;
3710 if (infoPtr->cy >= maxHeight)
3711 infoPtr->cy = maxHeight;
3714 infoPtr->cy = HIWORD (wParam);
3719 TREEVIEW_QueueRefresh (hwnd);
3724 TREEVIEW_HScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
3726 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3729 TRACE("wp %lx, lp %x\n", lParam, wParam);
3731 if (!infoPtr->uInternalStatus & TV_HSCROLL) return FALSE;
3733 switch (LOWORD (wParam)) {
3735 if (!infoPtr->cx) return FALSE;
3736 infoPtr->cx -= infoPtr->uRealItemHeight;
3737 if (infoPtr->cx < 0) infoPtr->cx=0;
3740 maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
3741 if (infoPtr->cx == maxWidth) return FALSE;
3742 infoPtr->cx += infoPtr->uRealItemHeight; /*FIXME */
3743 if (infoPtr->cx > maxWidth)
3744 infoPtr->cx = maxWidth;
3747 if (!infoPtr->cx) return FALSE;
3748 infoPtr->cx -= infoPtr->uVisibleWidth;
3749 if (infoPtr->cx < 0) infoPtr->cx=0;
3752 maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
3753 if (infoPtr->cx == maxWidth) return FALSE;
3754 infoPtr->cx += infoPtr->uVisibleWidth;
3755 if (infoPtr->cx > maxWidth)
3756 infoPtr->cx = maxWidth;
3759 infoPtr->cx = HIWORD (wParam);
3764 TREEVIEW_QueueRefresh (hwnd);
3768 static LRESULT TREEVIEW_MouseWheel (HWND hwnd, WPARAM wParam, LPARAM lParam)
3771 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3772 short gcWheelDelta = 0;
3773 UINT pulScrollLines = 3;
3775 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
3777 gcWheelDelta -= (short) HIWORD(wParam);
3778 pulScrollLines *= (gcWheelDelta / WHEEL_DELTA);
3780 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
3782 int wheelDy = pulScrollLines * infoPtr->uRealItemHeight;
3783 int newDy = infoPtr->cy + wheelDy;
3784 int maxDy = infoPtr->uTotalHeight - infoPtr->uVisibleHeight;
3786 if (newDy > maxDy) newDy = maxDy;
3787 if (newDy < 0) newDy = 0;
3789 if (newDy == infoPtr->cy) return TRUE;
3791 TREEVIEW_VScroll(hwnd, MAKEWPARAM(SB_THUMBTRACK,newDy),0);
3797 TREEVIEW_KeyDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
3799 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3800 HTREEITEM hNewSelection = 0;
3801 INT scrollNeeds = -1;
3802 INT cyChangeNeeds = -1;
3803 INT prevSelect = (INT)infoPtr->selectedItem;
3805 TREEVIEW_ITEM *prevItem =
3806 (prevSelect != 0 ) ?
3807 TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect) :
3810 TREEVIEW_ITEM *newItem = NULL;
3812 TRACE("%x %lx\n",wParam, lParam);
3814 if (prevSelect == 0)
3819 newItem=TREEVIEW_GetPrevListItem (infoPtr, prevItem);
3822 newItem=& infoPtr->items[(INT)infoPtr->TopRootItem];
3824 hNewSelection = newItem->hItem;
3826 if (! newItem->visible)
3827 scrollNeeds = SB_LINEUP;
3831 newItem=TREEVIEW_GetNextListItem (infoPtr, prevItem);
3836 hNewSelection = newItem->hItem;
3838 if (! newItem->visible)
3839 scrollNeeds = SB_LINEDOWN;
3844 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem];
3845 hNewSelection = newItem->hItem;
3850 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem];
3851 newItem = TREEVIEW_GetLastListItem (infoPtr, newItem);
3852 hNewSelection = newItem->hItem;
3854 if (! newItem->visible)
3855 cyChangeNeeds = infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3860 if ( (prevItem->cChildren > 0) && (prevItem->state & TVIS_EXPANDED) )
3862 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect );
3864 else if ((INT)prevItem->parent)
3866 newItem = (& infoPtr->items[(INT)prevItem->parent]);
3867 if (! newItem->visible)
3868 /* FIXME find a way to make this item the first visible... */
3871 hNewSelection = newItem->hItem;
3877 if ( ( prevItem->cChildren > 0) ||
3878 ( prevItem->cChildren == I_CHILDRENCALLBACK))
3880 if (! (prevItem->state & TVIS_EXPANDED))
3881 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect );
3884 newItem = (& infoPtr->items[(INT)prevItem->firstChild]);
3885 hNewSelection = newItem->hItem;
3892 if (! (prevItem->state & TVIS_EXPANDED))
3893 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect );
3897 if (prevItem->state & TVIS_EXPANDED)
3898 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect );
3903 newItem=TREEVIEW_GetListItem(
3906 -1*(TREEVIEW_GetVisibleCount(hwnd,0,0)-3));
3910 hNewSelection = newItem->hItem;
3912 if (! newItem->visible)
3913 scrollNeeds = SB_PAGEUP;
3918 newItem=TREEVIEW_GetListItem(
3921 TREEVIEW_GetVisibleCount(hwnd,0,0)-3);
3926 hNewSelection = newItem->hItem;
3928 if (! newItem->visible)
3929 scrollNeeds = SB_PAGEDOWN;
3938 FIXME("%x not implemented\n", wParam);
3945 This works but does not send notification...
3947 prevItem->state &= ~TVIS_SELECTED;
3948 newItem->state |= TVIS_SELECTED;
3949 infoPtr->selectedItem = hNewSelection;
3950 TREEVIEW_QueueRefresh (hwnd);
3953 if ( TREEVIEW_DoSelectItem(
3956 (HTREEITEM)hNewSelection,
3959 /* If selection change is allowed for the new item, perform scrolling */
3960 if (scrollNeeds != -1)
3961 TREEVIEW_VScroll(hwnd, scrollNeeds, 0);
3963 if (cyChangeNeeds != -1)
3964 infoPtr->cy = cyChangeNeeds;
3966 /* FIXME: Something happen in the load the in the two weeks before
3967 april 1st 1999 which makes this SetFocus mandatory otherwise, the focus
3968 is lost... However the SetFocus should not be required...*/
3979 TREEVIEW_GetScrollTime (HWND hwnd)
3981 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3983 return infoPtr->uScrollTime;
3988 TREEVIEW_SetScrollTime (HWND hwnd, UINT uScrollTime)
3990 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3991 UINT uOldScrollTime = infoPtr->uScrollTime;
3993 infoPtr->uScrollTime = min (uScrollTime, 100);
3995 return uOldScrollTime;
3999 static LRESULT WINAPI
4000 TREEVIEW_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
4002 TREEVIEW_INFO *infoPtr;
4003 if (uMsg==WM_CREATE)
4004 return TREEVIEW_Create (hwnd, wParam, lParam);
4006 if (!(infoPtr = TREEVIEW_GetInfoPtr(hwnd)))
4007 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
4011 case TVM_INSERTITEMA:
4012 return TREEVIEW_InsertItemA (hwnd, wParam, lParam);
4014 case TVM_INSERTITEMW:
4015 return TREEVIEW_InsertItemW(hwnd,wParam,lParam);;
4017 case TVM_DELETEITEM:
4018 return TREEVIEW_DeleteItem (hwnd, wParam, lParam);
4021 return TREEVIEW_Expand (hwnd, wParam, lParam);
4023 case TVM_GETITEMRECT:
4024 return TREEVIEW_GetItemRect (hwnd, wParam, lParam);
4027 return TREEVIEW_GetCount (hwnd, wParam, lParam);
4030 return TREEVIEW_GetIndent (hwnd);
4033 return TREEVIEW_SetIndent (hwnd, wParam);
4035 case TVM_GETIMAGELIST:
4036 return TREEVIEW_GetImageList (hwnd, wParam, lParam);
4038 case TVM_SETIMAGELIST:
4039 return TREEVIEW_SetImageList (hwnd, wParam, lParam);
4041 case TVM_GETNEXTITEM:
4042 return TREEVIEW_GetNextItem (hwnd, wParam, lParam);
4044 case TVM_SELECTITEM:
4045 return TREEVIEW_SelectItem (hwnd, wParam, lParam);
4048 return TREEVIEW_GetItemA (hwnd, wParam, lParam);
4051 return TREEVIEW_GetItemW (hwnd, wParam, lParam);
4054 return TREEVIEW_SetItemA (hwnd, wParam, lParam);
4057 FIXME("Unimplemented msg TVM_SETITEMW\n");
4060 case TVM_EDITLABELA:
4061 return TREEVIEW_EditLabelA(hwnd, wParam, lParam);
4063 case TVM_EDITLABELW:
4064 FIXME("Unimplemented msg TVM_EDITLABELW \n");
4067 case TVM_GETEDITCONTROL:
4068 return TREEVIEW_GetEditControl (hwnd);
4070 case TVM_GETVISIBLECOUNT:
4071 return TREEVIEW_GetVisibleCount (hwnd, wParam, lParam);
4074 return TREEVIEW_HitTest (hwnd, lParam);
4076 case TVM_CREATEDRAGIMAGE:
4077 return TREEVIEW_CreateDragImage (hwnd, wParam, lParam);
4079 case TVM_SORTCHILDREN:
4080 return TREEVIEW_SortChildren (hwnd, wParam, lParam);
4082 case TVM_ENSUREVISIBLE:
4083 FIXME("Unimplemented msg TVM_ENSUREVISIBLE\n");
4086 case TVM_SORTCHILDRENCB:
4087 return TREEVIEW_SortChildrenCB(hwnd, wParam, lParam);
4089 case TVM_ENDEDITLABELNOW:
4090 if (infoPtr->editItem)
4091 return TREEVIEW_EndEditLabelNow (hwnd, wParam, lParam);
4093 case TVM_GETISEARCHSTRINGA:
4094 FIXME("Unimplemented msg TVM_GETISEARCHSTRINGA\n");
4097 case TVM_GETISEARCHSTRINGW:
4098 FIXME("Unimplemented msg TVM_GETISEARCHSTRINGW\n");
4101 case TVM_GETTOOLTIPS:
4102 return TREEVIEW_GetToolTips (hwnd);
4104 case TVM_SETTOOLTIPS:
4105 return TREEVIEW_SetToolTips (hwnd, wParam);
4107 case TVM_SETINSERTMARK:
4108 return TREEVIEW_SetInsertMark (hwnd,wParam, lParam);
4110 case TVM_SETITEMHEIGHT:
4111 return TREEVIEW_SetItemHeight (hwnd, wParam);
4113 case TVM_GETITEMHEIGHT:
4114 return TREEVIEW_GetItemHeight (hwnd);
4116 case TVM_SETBKCOLOR:
4117 return TREEVIEW_SetBkColor (hwnd, wParam, lParam);
4119 case TVM_SETTEXTCOLOR:
4120 return TREEVIEW_SetTextColor (hwnd, wParam, lParam);
4122 case TVM_GETBKCOLOR:
4123 return TREEVIEW_GetBkColor (hwnd);
4125 case TVM_GETTEXTCOLOR:
4126 return TREEVIEW_GetTextColor (hwnd);
4128 case TVM_SETSCROLLTIME:
4129 return TREEVIEW_SetScrollTime (hwnd, (UINT)wParam);
4131 case TVM_GETSCROLLTIME:
4132 return TREEVIEW_GetScrollTime (hwnd);
4134 case TVM_GETITEMSTATE:
4135 return TREEVIEW_GetItemState (hwnd,wParam, lParam);
4137 case TVM_GETLINECOLOR:
4138 return TREEVIEW_GetLineColor (hwnd,wParam, lParam);
4140 case TVM_SETLINECOLOR:
4141 return TREEVIEW_SetLineColor (hwnd,wParam, lParam);
4143 case TVM_SETINSERTMARKCOLOR:
4144 return TREEVIEW_SetInsertMarkColor (hwnd,wParam, lParam);
4146 case TVM_GETINSERTMARKCOLOR:
4147 return TREEVIEW_GetInsertMarkColor (hwnd,wParam, lParam);
4149 case TVM_SETUNICODEFORMAT:
4150 FIXME("Unimplemented msg TVM_SETUNICODEFORMAT\n");
4153 case TVM_GETUNICODEFORMAT:
4154 FIXME("Unimplemented msg TVM_GETUNICODEFORMAT\n");
4158 return TREEVIEW_Command (hwnd, wParam, lParam);
4161 return TREEVIEW_Destroy (hwnd);
4163 /* case WM_ENABLE: */
4166 return TREEVIEW_EraseBackground (hwnd, wParam, lParam);
4169 return DLGC_WANTARROWS | DLGC_WANTCHARS;
4172 return TREEVIEW_Paint (hwnd, wParam, lParam);
4175 return TREEVIEW_GetFont (hwnd, wParam, lParam);
4178 return TREEVIEW_SetFont (hwnd, wParam, lParam);
4181 return TREEVIEW_KeyDown (hwnd, wParam, lParam);
4184 return TREEVIEW_SetFocus (hwnd, wParam, lParam);
4187 return TREEVIEW_KillFocus (hwnd, wParam, lParam);
4189 case WM_LBUTTONDOWN:
4190 return TREEVIEW_LButtonDown (hwnd, wParam, lParam);
4193 return TREEVIEW_LButtonUp (hwnd, wParam, lParam);
4195 case WM_LBUTTONDBLCLK:
4196 return TREEVIEW_LButtonDoubleClick (hwnd, wParam, lParam);
4198 case WM_RBUTTONDOWN:
4199 return TREEVIEW_RButtonDown (hwnd, wParam, lParam);
4202 return TREEVIEW_RButtonUp (hwnd, wParam, lParam);
4205 return TREEVIEW_MouseMove (hwnd, wParam, lParam);
4207 case WM_STYLECHANGED:
4208 return TREEVIEW_StyleChanged (hwnd, wParam, lParam);
4210 /* case WM_SYSCOLORCHANGE: */
4211 /* case WM_SETREDRAW: */
4214 return TREEVIEW_HandleTimer (hwnd, wParam, lParam);
4217 return TREEVIEW_Size (hwnd, wParam,lParam);
4220 return TREEVIEW_HScroll (hwnd, wParam, lParam);
4222 return TREEVIEW_VScroll (hwnd, wParam, lParam);
4225 if (wParam & (MK_SHIFT | MK_CONTROL))
4226 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
4227 return TREEVIEW_MouseWheel (hwnd, wParam, lParam);
4230 TRACE ("drawItem\n");
4231 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
4234 if (uMsg >= WM_USER)
4235 FIXME("Unknown msg %04x wp=%08x lp=%08lx\n",
4236 uMsg, wParam, lParam);
4237 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
4244 TREEVIEW_Register (void)
4250 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
4251 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
4252 wndClass.lpfnWndProc = (WNDPROC)TREEVIEW_WindowProc;
4253 wndClass.cbClsExtra = 0;
4254 wndClass.cbWndExtra = sizeof(TREEVIEW_INFO *);
4255 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
4256 wndClass.hbrBackground = 0;
4257 wndClass.lpszClassName = WC_TREEVIEWA;
4259 RegisterClassA (&wndClass);
4264 TREEVIEW_Unregister (void)
4266 UnregisterClassA (WC_TREEVIEWA, (HINSTANCE)NULL);