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))
66 TREEVIEW_SendSimpleNotify (HWND hwnd, UINT code);
68 TREEVIEW_SendTreeviewNotify (HWND hwnd, UINT code, UINT action,
69 HTREEITEM oldItem, HTREEITEM newItem);
71 TREEVIEW_SendTreeviewDnDNotify (HWND hwnd, UINT code, HTREEITEM dragItem,
74 TREEVIEW_SendDispInfoNotify (HWND hwnd, TREEVIEW_ITEM *wineItem,
75 UINT code, UINT what);
77 TREEVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
80 TREEVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
81 TREEVIEW_ITEM *tvItem, UINT uItemDrawState);
83 TREEVIEW_DoSelectItem (HWND hwnd, INT action, HTREEITEM newSelect, INT cause);
85 TREEVIEW_Refresh (HWND hwnd, HDC hdc);
87 static LRESULT CALLBACK
88 TREEVIEW_Edit_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam,
92 TREEVIEW_EditLabelA (HWND hwnd, WPARAM wParam, LPARAM lParam);
95 TREEVIEW_EndEditLabelNow (HWND hwnd, WPARAM wParam, LPARAM lParam);
100 /* helper functions. Work with the assumption that validity of operands
101 is checked beforehand, and that tree state is valid. */
103 /* FIXME: MS documentation says `GetNextVisibleItem' returns NULL
104 if not successfull. Probably only applies to dereferencing infoPtr
105 (i.e. we are offered a valid treeview structure)
106 and not whether there is a next `visible' child.
107 FIXME: check other failures.
110 /***************************************************************************
111 * This method returns the TREEVIEW_ITEM object given the handle
113 static TREEVIEW_ITEM* TREEVIEW_ValidItem(
114 TREEVIEW_INFO *infoPtr,
117 if ((!handle) || (handle>infoPtr->uMaxHandle))
120 if (tv_test_bit ((INT)handle, infoPtr->freeList))
123 return &infoPtr->items[(INT)handle];
126 /***************************************************************************
127 * This method returns the last expanded child item of a tree node
129 static TREEVIEW_ITEM *TREEVIEW_GetLastListItem(
130 TREEVIEW_INFO *infoPtr,
131 TREEVIEW_ITEM *tvItem)
133 TREEVIEW_ITEM *wineItem = tvItem;
136 * Get this item last sibling
138 while (wineItem->sibling)
139 wineItem=& infoPtr->items [(INT)wineItem->sibling];
142 * If the last sibling has expanded children, restart.
144 if ( ( wineItem->cChildren > 0 ) && ( wineItem->state & TVIS_EXPANDED) )
145 return TREEVIEW_GetLastListItem(
147 &(infoPtr->items[(INT)wineItem->firstChild]));
152 /***************************************************************************
153 * This method returns the previous physical item in the list not
154 * considering the tree hierarchy.
156 static TREEVIEW_ITEM *TREEVIEW_GetPrevListItem(
157 TREEVIEW_INFO *infoPtr,
158 TREEVIEW_ITEM *tvItem)
160 if (tvItem->upsibling)
163 * This item has a upsibling, get the last item. Since, GetLastListItem
164 * first looks at siblings, we must feed it with the first child.
166 TREEVIEW_ITEM *upItem = &infoPtr->items[(INT)tvItem->upsibling];
168 if ( ( upItem->cChildren > 0 ) && ( upItem->state & TVIS_EXPANDED) )
169 return TREEVIEW_GetLastListItem(
171 &infoPtr->items[(INT)upItem->firstChild]);
178 * this item does not have a upsibling, get the parent
181 return &infoPtr->items[(INT)tvItem->parent];
188 /***************************************************************************
189 * This method returns the next physical item in the treeview not
190 * considering the tree hierarchy.
192 static TREEVIEW_ITEM *TREEVIEW_GetNextListItem(
193 TREEVIEW_INFO *infoPtr,
194 TREEVIEW_ITEM *tvItem)
196 TREEVIEW_ITEM *wineItem = NULL;
199 * If this item has children and is expanded, return the first child
201 if ((tvItem->firstChild) && (tvItem->state & TVIS_EXPANDED))
202 return (& infoPtr->items[(INT)tvItem->firstChild]);
206 * try to get the sibling
209 return (& infoPtr->items[(INT)tvItem->sibling]);
212 * Otherwise, get the parent's sibling.
215 while (wineItem->parent) {
216 wineItem=& infoPtr->items [(INT)wineItem->parent];
217 if (wineItem->sibling)
218 return (& infoPtr->items [(INT)wineItem->sibling]);
224 /***************************************************************************
225 * This method returns the nth item starting at the given item. It returns
226 * the last item (or first) we we run out of items.
228 * Will scroll backward if count is <0.
229 * forward if count is >0.
231 static TREEVIEW_ITEM *TREEVIEW_GetListItem(
232 TREEVIEW_INFO *infoPtr,
233 TREEVIEW_ITEM *tvItem,
236 TREEVIEW_ITEM *previousItem = NULL;
237 TREEVIEW_ITEM *wineItem = tvItem;
242 /* Find count item downward */
243 while ((iter++ < count) && (wineItem != NULL))
245 /* Keep a pointer to the previous in case we ask for more than we got */
246 previousItem = wineItem;
247 wineItem = TREEVIEW_GetNextListItem(infoPtr, wineItem);
250 if (wineItem == NULL)
251 wineItem = previousItem;
255 /* Find count item upward */
256 while ((iter-- > count) && (wineItem != NULL))
258 /* Keep a pointer to the previous in case we ask for more than we got */
259 previousItem = wineItem;
260 wineItem = TREEVIEW_GetPrevListItem(infoPtr, wineItem);
263 if (wineItem == NULL)
264 wineItem = previousItem;
273 /***************************************************************************
276 static void TREEVIEW_RemoveAllChildren(
278 TREEVIEW_ITEM *parentItem)
280 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
281 TREEVIEW_ITEM *killItem;
284 kill=(INT)parentItem->firstChild;
286 tv_set_bit ( kill, infoPtr->freeList);
287 killItem=& infoPtr->items[kill];
288 if (killItem->pszText!=LPSTR_TEXTCALLBACKA)
289 COMCTL32_Free (killItem->pszText);
290 TREEVIEW_SendTreeviewNotify (hwnd, TVN_DELETEITEMA, 0, (HTREEITEM)kill, 0);
291 if (killItem->firstChild)
292 TREEVIEW_RemoveAllChildren (hwnd, killItem);
293 kill=(INT)killItem->sibling;
296 if (parentItem->cChildren>0) {
297 infoPtr->uNumItems -= parentItem->cChildren;
298 parentItem->firstChild = 0;
299 parentItem->cChildren = 0;
306 TREEVIEW_RemoveItem (HWND hwnd, TREEVIEW_ITEM *wineItem)
309 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
310 TREEVIEW_ITEM *parentItem, *upsiblingItem, *siblingItem;
313 iItem=(INT)wineItem->hItem;
314 tv_set_bit(iItem,infoPtr->freeList);
315 infoPtr->uNumItems--;
317 if (wineItem->pszText!=LPSTR_TEXTCALLBACKA)
318 COMCTL32_Free (wineItem->pszText);
320 TREEVIEW_SendTreeviewNotify (hwnd, TVN_DELETEITEMA, 0, (HTREEITEM)iItem, 0);
322 if (wineItem->firstChild)
323 TREEVIEW_RemoveAllChildren (hwnd,wineItem);
325 if (wineItem->parent) {
326 parentItem=& infoPtr->items [(INT)wineItem->parent];
327 switch (parentItem->cChildren) {
328 case I_CHILDRENCALLBACK:
329 FIXME("we don't handle I_CHILDRENCALLBACK yet\n");
332 parentItem->cChildren=0;
333 parentItem->firstChild=0;
336 parentItem->cChildren--;
337 if ((INT)parentItem->firstChild==iItem)
338 parentItem->firstChild=wineItem->sibling;
342 if (iItem==(INT)infoPtr->TopRootItem)
343 infoPtr->TopRootItem=(HTREEITEM)wineItem->sibling;
344 if (wineItem->upsibling) {
345 upsiblingItem=& infoPtr->items [(INT)wineItem->upsibling];
346 upsiblingItem->sibling=wineItem->sibling;
348 if (wineItem->sibling) {
349 siblingItem=& infoPtr->items [(INT)wineItem->sibling];
350 siblingItem->upsibling=wineItem->upsibling;
358 /* Note:TREEVIEW_RemoveTree doesn't remove infoPtr itself */
360 static void TREEVIEW_RemoveTree (HWND hwnd)
363 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
364 TREEVIEW_ITEM *killItem;
367 for (i = 1; i <= (INT)infoPtr->uMaxHandle; i++)
368 if (!tv_test_bit (i, infoPtr->freeList)) {
369 killItem = &infoPtr->items[i];
370 if (killItem->pszText != LPSTR_TEXTCALLBACKA)
371 COMCTL32_Free (killItem->pszText);
372 TREEVIEW_SendTreeviewNotify(hwnd, TVN_DELETEITEMA, 0,
375 if (infoPtr->uNumPtrsAlloced) {
376 COMCTL32_Free (infoPtr->items);
377 COMCTL32_Free (infoPtr->freeList);
378 infoPtr->uNumItems = 0;
379 infoPtr->uNumPtrsAlloced = 0;
380 infoPtr->uMaxHandle = 0;
381 infoPtr->TopRootItem = 0;
392 TREEVIEW_GetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
394 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
398 if ((INT)wParam == TVSIL_NORMAL)
399 return (LRESULT) infoPtr->himlNormal;
400 if ((INT)wParam == TVSIL_STATE)
401 return (LRESULT) infoPtr->himlState;
407 TREEVIEW_SetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
409 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
412 TRACE("%x,%lx\n", wParam, lParam);
413 switch ((INT)wParam) {
415 himlTemp = infoPtr->himlNormal;
416 infoPtr->himlNormal = (HIMAGELIST)lParam;
417 return (LRESULT)himlTemp;
420 himlTemp = infoPtr->himlState;
421 infoPtr->himlState = (HIMAGELIST)lParam;
422 return (LRESULT)himlTemp;
425 return (LRESULT)NULL;
431 TREEVIEW_SetItemHeight (HWND hwnd, WPARAM wParam)
433 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
434 INT cx,cy,prevHeight=infoPtr->uItemHeight;
438 infoPtr->uItemHeight=-1;
442 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &cy);
444 if (wParam>cy) cy=wParam;
445 infoPtr->uItemHeight=cy;
447 if (!( GetWindowLongA( hwnd, GWL_STYLE) & TVS_NONEVENHEIGHT))
448 infoPtr->uItemHeight = (INT) wParam & 0xfffffffe;
453 TREEVIEW_GetItemHeight (HWND hwnd)
455 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
458 return infoPtr->uItemHeight;
462 TREEVIEW_GetLineColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
464 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
467 return (LRESULT) infoPtr->clrLine;
471 TREEVIEW_SetLineColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
473 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
474 COLORREF prevColor=infoPtr->clrLine;
477 infoPtr->clrLine=(COLORREF) lParam;
478 return (LRESULT) prevColor;
482 TREEVIEW_GetInsertMarkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
484 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
487 return (LRESULT) infoPtr->clrInsertMark;
491 TREEVIEW_SetInsertMarkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
493 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
494 COLORREF prevColor=infoPtr->clrInsertMark;
496 TRACE("%d %ld\n",wParam,lParam);
497 infoPtr->clrInsertMark=(COLORREF) lParam;
498 return (LRESULT) prevColor;
502 TREEVIEW_SetInsertMark (HWND hwnd, WPARAM wParam, LPARAM lParam)
504 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
507 FIXME("%d %ld\n",wParam,lParam);
508 if (!TREEVIEW_ValidItem (infoPtr, (HTREEITEM)lParam)) return 0;
509 FIXME("%d %ld\n",wParam,lParam);
511 infoPtr->insertBeforeorAfter=(BOOL) wParam;
512 infoPtr->insertMarkItem=(HTREEITEM) lParam;
515 TREEVIEW_Refresh (hwnd, hdc);
522 TREEVIEW_SetTextColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
524 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
525 COLORREF prevColor=infoPtr->clrText;
528 infoPtr->clrText=(COLORREF) lParam;
529 return (LRESULT) prevColor;
533 TREEVIEW_GetBkColor (HWND hwnd)
535 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
538 return (LRESULT) infoPtr->clrBk;
542 TREEVIEW_SetBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
544 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
545 COLORREF prevColor=infoPtr->clrBk;
548 infoPtr->clrBk=(COLORREF) lParam;
549 return (LRESULT) prevColor;
553 TREEVIEW_GetTextColor (HWND hwnd)
555 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
558 return (LRESULT) infoPtr->clrText;
562 /* cdmode: custom draw mode as received from app. in first NMCUSTOMDRAW
565 #define TREEVIEW_LEFT_MARGIN 8
569 TREEVIEW_DrawItem (HWND hwnd, HDC hdc, TREEVIEW_ITEM *wineItem)
571 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
572 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
573 INT center,xpos,cx,cy, cditem;
575 UINT uTextJustify = DT_LEFT;
579 if (wineItem->state & TVIS_BOLD)
580 hOldFont = SelectObject (hdc, infoPtr->hBoldFont);
582 hOldFont = SelectObject (hdc, infoPtr->hFont);
585 TRACE ("cdmode:%x\n",infoPtr->cdmode);
586 if (infoPtr->cdmode & CDRF_NOTIFYITEMDRAW) {
587 cditem=TREEVIEW_SendCustomDrawItemNotify
588 (hwnd, hdc, wineItem, CDDS_ITEMPREPAINT);
589 TRACE("prepaint:cditem-app returns 0x%x\n",cditem);
591 if (cditem & CDRF_SKIPDEFAULT)
596 * Set drawing starting points
598 r = wineItem->rect; /* this item rectangle */
599 center = (r.top+r.bottom)/2; /* this item vertical center */
600 xpos = r.left + TREEVIEW_LEFT_MARGIN;/* horizontal starting point */
603 * Display the tree hierarchy
605 if ( dwStyle & TVS_HASLINES)
608 * Write links to parent node
609 * we draw the L starting from the child to the parent
611 * points[0] is attached to the current item
612 * points[1] is the L corner
613 * points[2] is attached to the parent or the up sibling
615 if ( dwStyle & TVS_LINESATROOT)
617 TREEVIEW_ITEM *upNode = NULL;
618 BOOL hasParentOrSibling = TRUE;
619 RECT upRect = {0,0,0,0};
620 HPEN hOldPen, hNewPen;
623 * determine the target location of the line at root, either be linked
624 * to the up sibling or to the parent node.
626 if (wineItem->upsibling)
627 upNode = TREEVIEW_ValidItem (infoPtr, wineItem->upsibling);
628 else if (wineItem->parent)
629 upNode = TREEVIEW_ValidItem (infoPtr, wineItem->parent);
631 hasParentOrSibling = FALSE;
634 upRect = upNode->rect;
636 if ( wineItem->iLevel == 0 )
638 points[2].x = points[1].x = upRect.left+8;
639 points[0].x = points[2].x + 10;
640 points[2].y = upRect.bottom-3;
641 points[1].y = points[0].y = center;
645 points[2].x = points[1].x = 8 + (20*wineItem->iLevel);
646 points[2].y = ( upNode->cChildren == 0) ?
647 upRect.top : /* is linked to the "L" above */
648 ( wineItem->upsibling != NULL) ?
649 upRect.bottom-3: /* is linked to an icon */
650 upRect.bottom+1; /* is linked to a +/- box */
651 points[1].y = points[0].y = center;
652 points[0].x = points[1].x + 10;
658 hNewPen = CreatePen(PS_DOT, 0, infoPtr->clrLine);
659 hOldPen = SelectObject( hdc, hNewPen );
661 if (hasParentOrSibling)
662 Polyline (hdc,points,3);
664 Polyline (hdc,points,2);
666 DeleteObject(hNewPen);
667 SelectObject(hdc, hOldPen);
672 * Display the (+/-) signs
674 if (wineItem->iLevel != 0)/* update position only for non root node */
675 xpos+=(5*wineItem->iLevel);
677 if (( dwStyle & TVS_HASBUTTONS) && ( dwStyle & TVS_HASLINES))
679 if ( (wineItem->cChildren) ||
680 (wineItem->cChildren == I_CHILDRENCALLBACK))
682 /* Setup expand box coordinate to facilitate the LMBClick handling */
683 wineItem->expandBox.left = xpos-4;
684 wineItem->expandBox.top = center-4;
685 wineItem->expandBox.right = xpos+5;
686 wineItem->expandBox.bottom = center+5;
690 wineItem->expandBox.left,
691 wineItem->expandBox.top ,
692 wineItem->expandBox.right,
693 wineItem->expandBox.bottom);
695 MoveToEx (hdc, xpos-2, center, NULL);
696 LineTo (hdc, xpos+3, center);
698 if (!(wineItem->state & TVIS_EXPANDED)) {
699 MoveToEx (hdc, xpos, center-2, NULL);
700 LineTo (hdc, xpos, center+3);
706 * Display the image associated with this item
708 xpos += 13; /* update position */
709 if (wineItem->mask & (TVIF_IMAGE|TVIF_SELECTEDIMAGE)) {
711 HIMAGELIST *himlp = NULL;
713 /* State images are displayed to the left of the Normal image
714 * image number is in state; zero should be `display no image'.
715 * FIXME: that last sentence looks like it needs some checking.
717 if (infoPtr->himlState)
718 himlp=&infoPtr->himlState;
719 imageIndex=wineItem->state>>12;
720 imageIndex++; /* yeah, right */
721 TRACE ("imindex:%d\n",imageIndex);
722 if ((himlp) && (imageIndex))
724 imageIndex--; /* see FIXME */
725 ImageList_Draw ( *himlp, imageIndex, hdc, xpos-2, r.top+1, ILD_NORMAL);
726 ImageList_GetIconSize (*himlp, &cx, &cy);
727 wineItem->statebitmap.left=xpos-2;
728 wineItem->statebitmap.right=xpos-2+cx;
729 wineItem->statebitmap.top=r.top+1;
730 wineItem->statebitmap.bottom=r.top+1+cy;
734 /* Now, draw the normal image; can be either selected or
735 * non-selected image.
739 if (infoPtr->himlNormal)
740 himlp=&infoPtr->himlNormal; /* get the image list */
742 imageIndex = wineItem->iImage;
743 if ( (wineItem->state & TVIS_SELECTED) &&
744 (wineItem->iSelectedImage)) {
746 /* The item is curently selected */
747 if (wineItem->iSelectedImage == I_IMAGECALLBACK)
748 TREEVIEW_SendDispInfoNotify
749 (hwnd, wineItem, TVN_GETDISPINFOA, TVIF_SELECTEDIMAGE);
751 imageIndex = wineItem->iSelectedImage;
753 /* The item is not selected */
754 if (wineItem->iImage == I_IMAGECALLBACK)
755 TREEVIEW_SendDispInfoNotify
756 (hwnd, wineItem, TVN_GETDISPINFOA, TVIF_IMAGE);
758 imageIndex = wineItem->iImage;
765 if(wineItem->stateMask & TVIS_OVERLAYMASK)
766 ovlIdx = wineItem->state & TVIS_OVERLAYMASK;
768 ImageList_Draw ( *himlp, imageIndex, hdc, xpos-2, r.top+1, ILD_NORMAL|ovlIdx);
769 ImageList_GetIconSize (*himlp, &cx, &cy);
770 wineItem->bitmap.left=xpos-2;
771 wineItem->bitmap.right=xpos-2+cx;
772 wineItem->bitmap.top=r.top+1;
773 wineItem->bitmap.bottom=r.top+1+cy;
780 * Display the text associated with this item
783 if ((wineItem->mask & TVIF_TEXT) && (wineItem->pszText))
785 COLORREF oldBkColor = 0;
786 COLORREF oldTextColor = 0;
792 wineItem->text.left = r.left;
793 wineItem->text.right = r.right;
794 wineItem->text.top = r.top;
795 wineItem->text.bottom= r.bottom;
797 if (wineItem->pszText== LPSTR_TEXTCALLBACKA) {
798 TRACE("LPSTR_TEXTCALLBACK\n");
799 TREEVIEW_SendDispInfoNotify (hwnd, wineItem, TVN_GETDISPINFOA, TVIF_TEXT);
802 /* Yep, there are some things that need to be straightened out here.
803 Removing the comments around the setTextColor does not give the right
804 results. Dito FillRect.
808 /* GetTextExtentPoint32A (hdc, wineItem->pszText,
809 strlen (wineItem->pszText), &size); */
811 /* FillRect ( hdc, &wineItem->text, GetSysColorBrush (infoPtr->clrBk));
815 if (!(cditem & CDRF_NOTIFYPOSTPAINT) &&
816 (wineItem->state & (TVIS_SELECTED | TVIS_DROPHILITED)) ) {
817 oldBkMode = SetBkMode (hdc, OPAQUE);
818 oldBkColor = SetBkColor (hdc, GetSysColor( COLOR_HIGHLIGHT));
819 oldTextColor = SetTextColor(hdc, GetSysColor( COLOR_HIGHLIGHTTEXT));
821 oldBkMode = SetBkMode (hdc, TRANSPARENT);
822 oldBkColor = SetBkColor (hdc, infoPtr->clrBk);
823 /* oldTextColor = SetTextColor(hdc, infoPtr->clrText); */
831 lstrlenA(wineItem->pszText),
833 uTextJustify | DT_VCENTER | DT_SINGLELINE );
835 /* Obtain the text coordinate */
839 lstrlenA(wineItem->pszText),
841 uTextJustify | DT_VCENTER | DT_SINGLELINE | DT_CALCRECT);
843 /* Restore the hdc state */
844 SetTextColor( hdc, oldTextColor);
846 if (oldBkMode != TRANSPARENT)
847 SetBkMode(hdc, oldBkMode);
848 if (wineItem->state & (TVIS_SELECTED | TVIS_DROPHILITED))
849 SetBkColor (hdc, oldBkColor);
851 /* Draw the box arround the selected item */
852 if (wineItem->state & TVIS_SELECTED )
854 HPEN hNewPen = CreatePen(PS_DOT, 0, GetSysColor(COLOR_WINDOWTEXT) );
855 HPEN hOldPen = SelectObject( hdc, hNewPen );
858 points[0].x = wineItem->text.left-1;
859 points[0].y = wineItem->text.top+1;
860 points[1].x = wineItem->text.right;
861 points[1].y = wineItem->text.top+1;
862 points[2].x = wineItem->text.right;
863 points[2].y = wineItem->text.bottom;
864 points[3].x = wineItem->text.left-1;
865 points[3].y = wineItem->text.bottom;
867 Polyline (hdc,points,4);
869 DeleteObject(hNewPen);
870 SelectObject(hdc, hOldPen);
874 /* Draw insertion mark if necessary */
876 if (infoPtr->insertMarkItem)
877 TRACE ("item:%d,mark:%d\n", (int)wineItem->hItem,
878 (int) infoPtr->insertMarkItem);
879 if (wineItem->hItem==infoPtr->insertMarkItem) {
880 HPEN hNewPen, hOldPen;
883 hNewPen = CreatePen(PS_SOLID, 2, infoPtr->clrInsertMark);
884 hOldPen = SelectObject( hdc, hNewPen );
886 if (infoPtr->insertBeforeorAfter)
887 offset=wineItem->text.top+1;
889 offset=wineItem->text.bottom-1;
891 MoveToEx (hdc, wineItem->text.left, offset-3, NULL);
892 LineTo (hdc, wineItem->text.left, offset+3);
894 MoveToEx (hdc, wineItem->text.left, offset, NULL);
895 LineTo (hdc, r.right-2, offset);
897 MoveToEx (hdc, r.right-2, offset+3, NULL);
898 LineTo (hdc, r.right-2, offset-3);
900 DeleteObject(hNewPen);
902 SelectObject(hdc, hOldPen);
905 if (cditem & CDRF_NOTIFYPOSTPAINT) {
906 cditem=TREEVIEW_SendCustomDrawItemNotify
907 (hwnd, hdc, wineItem, CDDS_ITEMPOSTPAINT);
908 TRACE("postpaint:cditem-app returns 0x%x\n",cditem);
911 SelectObject (hdc, hOldFont);
915 TREEVIEW_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
917 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
918 TREEVIEW_ITEM *wineItem;
920 LPRECT lpRect = (LPRECT)lParam;
925 * validate parameters
930 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
932 TREEVIEW_Refresh (hwnd, hdc); /* we want a rect for the current view */
938 * retrieve the item ptr
940 iItem = (HTREEITEM *) lParam;
941 wineItem = TREEVIEW_ValidItem (infoPtr, *iItem);
942 if ((!wineItem) || (!wineItem->visible))
946 * If wParam is TRUE return the text size otherwise return
947 * the whole item size
950 lpRect->left = wineItem->text.left;
951 lpRect->right = wineItem->text.right;
952 lpRect->bottom = wineItem->text.bottom;
953 lpRect->top = wineItem->text.top;
955 lpRect->left = wineItem->rect.left;
956 lpRect->right = wineItem->rect.right;
957 lpRect->bottom = wineItem->rect.bottom;
958 lpRect->top = wineItem->rect.top;
961 TRACE("[L:%d R:%d T:%d B:%d]\n",
962 lpRect->left,lpRect->right,
963 lpRect->top,lpRect->bottom);
969 TREEVIEW_GetVisibleCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
972 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
974 return (LRESULT) infoPtr->uVisibleHeight / infoPtr->uRealItemHeight;
980 TREEVIEW_SetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
982 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
983 TREEVIEW_ITEM *wineItem;
987 tvItem=(LPTVITEMEXA) lParam;
988 iItem=(INT)tvItem->hItem;
989 TRACE("item %d,mask %x\n",iItem,tvItem->mask);
991 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
992 if (!wineItem) return FALSE;
994 if (tvItem->mask & TVIF_CHILDREN) {
995 wineItem->cChildren=tvItem->cChildren;
998 if (tvItem->mask & TVIF_IMAGE) {
999 wineItem->iImage=tvItem->iImage;
1002 if (tvItem->mask & TVIF_INTEGRAL) {
1003 wineItem->iIntegral=tvItem->iIntegral;
1006 if (tvItem->mask & TVIF_PARAM) {
1007 wineItem->lParam=tvItem->lParam;
1010 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
1011 wineItem->iSelectedImage=tvItem->iSelectedImage;
1014 if (tvItem->mask & TVIF_STATE) {
1015 TRACE ("prevstate,state,mask:%x,%x,%x\n",wineItem->state,tvItem->state,
1017 wineItem->state&= ~tvItem->stateMask;
1018 wineItem->state|= (tvItem->state & tvItem->stateMask);
1019 wineItem->stateMask|= tvItem->stateMask;
1022 if (tvItem->mask & TVIF_TEXT) {
1023 if (tvItem->pszText!=LPSTR_TEXTCALLBACKA) {
1024 len=lstrlenA (tvItem->pszText);
1025 if (len>wineItem->cchTextMax)
1026 wineItem->pszText= COMCTL32_ReAlloc (wineItem->pszText, len+1);
1027 lstrcpynA (wineItem->pszText, tvItem->pszText,len+1);
1029 if (wineItem->cchTextMax) {
1030 COMCTL32_Free (wineItem->pszText);
1031 wineItem->cchTextMax=0;
1033 wineItem->pszText=LPSTR_TEXTCALLBACKA;
1037 wineItem->mask |= tvItem->mask;
1043 TREEVIEW_GetItemState (HWND hwnd, WPARAM wParam, LPARAM lParam)
1046 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1047 TREEVIEW_ITEM *wineItem;
1050 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)wParam);
1051 if (!wineItem) return 0;
1053 return (wineItem->state & lParam);
1060 TREEVIEW_Refresh (HWND hwnd, HDC hdc)
1062 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1066 INT iItem, indent, x, y, height, itemHeight;
1067 INT viewtop,viewbottom,viewleft,viewright;
1068 TREEVIEW_ITEM *wineItem, *prevItem;
1073 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
1074 KillTimer (hwnd, TV_REFRESH_TIMER);
1075 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
1079 GetClientRect (hwnd, &rect);
1080 if ((rect.left-rect.right ==0) || (rect.top-rect.bottom==0)) return;
1082 infoPtr->cdmode=TREEVIEW_SendCustomDrawNotify(hwnd,CDDS_PREPAINT,hdc,rect);
1084 if (infoPtr->cdmode==CDRF_SKIPDEFAULT) return;
1086 infoPtr->uVisibleHeight= rect.bottom-rect.top;
1087 infoPtr->uVisibleWidth= rect.right-rect.left;
1089 viewtop=infoPtr->cy;
1090 viewbottom=infoPtr->cy + rect.bottom-rect.top;
1091 viewleft=infoPtr->cx;
1092 viewright=infoPtr->cx + rect.right-rect.left;
1094 TRACE("[%d %d %d %d]\n",viewtop,viewbottom,viewleft,viewright);
1096 /* draw background */
1098 hbrBk = CreateSolidBrush (infoPtr->clrBk);
1099 FillRect(hdc, &rect, hbrBk);
1100 DeleteObject(hbrBk);
1102 ImageList_GetIconSize (infoPtr->himlNormal, &x, &itemHeight);
1103 if (infoPtr->uItemHeight>itemHeight)
1104 itemHeight=infoPtr->uItemHeight;
1106 GetTextMetricsA (hdc, &tm);
1107 if ((tm.tmHeight + tm.tmExternalLeading) > itemHeight)
1108 itemHeight=tm.tmHeight + tm.tmExternalLeading;
1110 infoPtr->uRealItemHeight=itemHeight;
1112 iItem=(INT)infoPtr->TopRootItem;
1113 infoPtr->firstVisible=0;
1120 wineItem= & infoPtr->items[iItem];
1121 wineItem->iLevel=indent;
1123 /* FIXME: remove this in later stage */
1125 if (wineItem->pszText!=LPSTR_TEXTCALLBACK32A)
1126 TRACE (treeview, "%d %d [%d %d %d %d] (%s)\n",y,x,
1127 wineItem->rect.top, wineItem->rect.bottom,
1128 wineItem->rect.left, wineItem->rect.right,
1131 TRACE (treeview, "%d [%d %d %d %d] (CALLBACK)\n",
1133 wineItem->rect.top, wineItem->rect.bottom,
1134 wineItem->rect.left, wineItem->rect.right);
1137 height=itemHeight * wineItem->iIntegral +1;
1138 if ((y >= viewtop) && (y <= viewbottom) &&
1139 (x >= viewleft ) && (x <= viewright)) {
1140 wineItem->visible = TRUE;
1141 wineItem->rect.top = y - infoPtr->cy + rect.top;
1142 wineItem->rect.bottom = wineItem->rect.top + height ;
1143 wineItem->rect.left = x - infoPtr->cx + rect.left;
1144 wineItem->rect.right = rect.right;
1145 if (!infoPtr->firstVisible)
1146 infoPtr->firstVisible=wineItem->hItem;
1147 TREEVIEW_DrawItem (hwnd, hdc, wineItem);
1150 wineItem->visible = FALSE;
1151 wineItem->rect.left = wineItem->rect.top = 0;
1152 wineItem->rect.right= wineItem->rect.bottom = 0;
1153 wineItem->text.left = wineItem->text.top = 0;
1154 wineItem->text.right= wineItem->text.bottom = 0;
1157 /* look up next item */
1159 if ((wineItem->firstChild) && (wineItem->state & TVIS_EXPANDED)) {
1160 iItem=(INT)wineItem->firstChild;
1162 x+=infoPtr->uIndent;
1163 if (x>infoPtr->uTotalWidth)
1164 infoPtr->uTotalWidth=x;
1167 iItem=(INT)wineItem->sibling;
1168 while ((!iItem) && (indent>0)) {
1170 x-=infoPtr->uIndent;
1171 wineItem=&infoPtr->items[(INT)wineItem->parent];
1172 iItem=(INT)wineItem->sibling;
1178 /* FIXME: infoPtr->uTotalWidth should also take item label into account */
1179 /* FIXME: or should query item sizes (ie check CDRF_NEWFONT) */
1181 infoPtr->uTotalHeight=y;
1182 if (y >= (viewbottom-viewtop)) {
1183 if (!(infoPtr->uInternalStatus & TV_VSCROLL))
1184 ShowScrollBar (hwnd, SB_VERT, TRUE);
1185 infoPtr->uInternalStatus |=TV_VSCROLL;
1186 SetScrollRange (hwnd, SB_VERT, 0,
1187 y - infoPtr->uVisibleHeight, FALSE);
1188 SetScrollPos (hwnd, SB_VERT, infoPtr->cy, TRUE);
1191 if (infoPtr->uInternalStatus & TV_VSCROLL)
1192 ShowScrollBar (hwnd, SB_VERT, FALSE);
1193 infoPtr->uInternalStatus &= ~TV_VSCROLL;
1197 if (infoPtr->cdmode & CDRF_NOTIFYPOSTPAINT)
1198 infoPtr->cdmode=TREEVIEW_SendCustomDrawNotify
1199 (hwnd, CDDS_POSTPAINT, hdc, rect);
1206 TREEVIEW_HandleTimer (HWND hwnd, WPARAM wParam, LPARAM lParam)
1208 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1210 TRACE(" %d\n",wParam);
1213 case TV_REFRESH_TIMER:
1214 KillTimer (hwnd, TV_REFRESH_TIMER);
1215 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
1216 InvalidateRect(hwnd, NULL, FALSE);
1219 KillTimer (hwnd, TV_EDIT_TIMER);
1220 infoPtr->Timer &= ~TV_EDIT_TIMER_SET;
1223 ERR("got unknown timer\n");
1231 TREEVIEW_QueueRefresh (HWND hwnd)
1234 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1237 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
1238 KillTimer (hwnd, TV_REFRESH_TIMER);
1241 SetTimer (hwnd, TV_REFRESH_TIMER, TV_REFRESH_DELAY, 0);
1242 infoPtr->Timer|=TV_REFRESH_TIMER_SET;
1248 TREEVIEW_GetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1250 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1252 TREEVIEW_ITEM *wineItem;
1255 tvItem=(LPTVITEMEXA) lParam;
1256 iItem=(INT)tvItem->hItem;
1258 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1259 if (!wineItem) return FALSE;
1261 if (tvItem->mask & TVIF_CHILDREN) {
1262 if (TVIF_CHILDREN==I_CHILDRENCALLBACK)
1263 FIXME("I_CHILDRENCALLBACK not supported\n");
1264 tvItem->cChildren=wineItem->cChildren;
1267 if (tvItem->mask & TVIF_HANDLE) {
1268 tvItem->hItem=wineItem->hItem;
1271 if (tvItem->mask & TVIF_IMAGE) {
1272 tvItem->iImage=wineItem->iImage;
1275 if (tvItem->mask & TVIF_INTEGRAL) {
1276 tvItem->iIntegral=wineItem->iIntegral;
1279 /* undocumented: windows ignores TVIF_PARAM and
1280 * always sets lParam
1282 tvItem->lParam=wineItem->lParam;
1284 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
1285 tvItem->iSelectedImage=wineItem->iSelectedImage;
1288 if (tvItem->mask & TVIF_STATE) {
1289 tvItem->state=wineItem->state & tvItem->stateMask;
1292 if (tvItem->mask & TVIF_TEXT) {
1293 if (wineItem->pszText == LPSTR_TEXTCALLBACKA) {
1294 tvItem->pszText = LPSTR_TEXTCALLBACKA; /* FIXME:send notification? */
1295 ERR(" GetItem called with LPSTR_TEXTCALLBACK\n");
1297 else if (wineItem->pszText) {
1298 lstrcpynA (tvItem->pszText, wineItem->pszText, tvItem->cchTextMax);
1302 TRACE("item %d<%p>, txt %p, img %p, action %x\n",
1303 iItem, tvItem, tvItem->pszText, &tvItem->iImage, tvItem->mask);
1310 /* FIXME: check implementation of TVGN_NEXT/TVGN_NEXTVISIBLE */
1313 TREEVIEW_GetNextItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
1316 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1317 TREEVIEW_ITEM *wineItem, *returnItem;
1318 INT iItem = (INT)lParam, retval = 0, flag = (INT)wParam;
1323 retval = (INT)infoPtr->TopRootItem;
1327 retval = (INT)infoPtr->selectedItem;
1330 case TVGN_FIRSTVISIBLE: /* FIXME:we should only recalculate, not redraw */
1332 TREEVIEW_Refresh (hwnd, hdc);
1333 ReleaseDC(hwnd,hdc);
1334 retval = (INT)infoPtr->firstVisible;
1337 case TVGN_DROPHILITE:
1338 retval = (INT)infoPtr->dropItem;
1342 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1343 retval = wineItem ? (INT)wineItem->sibling : 0;
1347 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1348 retval = wineItem ? (INT)wineItem->upsibling : 0;
1352 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1353 retval = wineItem ? (INT)wineItem->parent : 0;
1357 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1358 retval = wineItem ? (INT)wineItem->firstChild : 0;
1361 case TVGN_LASTVISIBLE:
1362 if((wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem))) {
1363 returnItem = TREEVIEW_GetLastListItem (infoPtr,wineItem);
1364 retval = returnItem ? (INT)returnItem->hItem : 0;
1368 case TVGN_NEXTVISIBLE:
1369 if((wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem))) {
1370 returnItem = TREEVIEW_GetNextListItem (infoPtr,wineItem);
1371 retval = returnItem ? (INT)returnItem->hItem : 0;
1375 case TVGN_PREVIOUSVISIBLE:
1376 if((wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem))) {
1377 returnItem = TREEVIEW_GetPrevListItem (infoPtr, wineItem);
1378 retval = returnItem ? (INT)returnItem->hItem : 0;
1383 FIXME("Unknown msg %x,item %x\n", flag,iItem);
1387 TRACE("flags %x, item %d returns %d\n", flag, iItem, retval);
1393 TREEVIEW_GetCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
1395 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1397 TRACE(" %d\n",infoPtr->uNumItems);
1398 return (LRESULT) infoPtr->uNumItems;
1401 /***************************************************************************
1402 * This method does the chaining of the insertion of a treeview item
1404 * If parent is NULL, we're inserting at the root of the list.
1406 static void TREEVIEW_InsertBefore(
1407 TREEVIEW_INFO *infoPtr,
1408 TREEVIEW_ITEM *newItem,
1409 TREEVIEW_ITEM *sibling,
1410 TREEVIEW_ITEM *parent)
1412 HTREEITEM siblingHandle = 0;
1413 HTREEITEM upSiblingHandle = 0;
1414 TREEVIEW_ITEM *upSibling = NULL;
1416 if (newItem == NULL)
1417 ERR("NULL newItem, impossible condition\n");
1419 if (sibling != NULL) /* Insert before this sibling for this parent */
1421 /* Store the new item sibling up sibling and sibling tem handle */
1422 siblingHandle = sibling->hItem;
1423 upSiblingHandle = sibling->upsibling;
1424 /* As well as a pointer to the upsibling sibling object */
1425 if ( (INT)sibling->upsibling != 0 )
1426 upSibling = &infoPtr->items[(INT)sibling->upsibling];
1428 /* Adjust the sibling pointer */
1429 sibling->upsibling = newItem->hItem;
1431 /* Adjust the new item pointers */
1432 newItem->upsibling = upSiblingHandle;
1433 newItem->sibling = siblingHandle;
1435 /* Adjust the up sibling pointer */
1436 if ( upSibling != NULL )
1437 upSibling->sibling = newItem->hItem;
1439 /* this item is the first child of this parent, adjust parent pointers */
1441 parent->firstChild = newItem->hItem;
1443 infoPtr->TopRootItem= newItem->hItem;
1445 else /* Insert as first child of this parent */
1447 parent->firstChild = newItem->hItem;
1450 /***************************************************************************
1451 * This method does the chaining of the insertion of a treeview item
1453 * If parent is NULL, we're inserting at the root of the list.
1455 static void TREEVIEW_InsertAfter(
1456 TREEVIEW_INFO *infoPtr,
1457 TREEVIEW_ITEM *newItem,
1458 TREEVIEW_ITEM *upSibling,
1459 TREEVIEW_ITEM *parent)
1461 HTREEITEM upSiblingHandle = 0;
1462 HTREEITEM siblingHandle = 0;
1463 TREEVIEW_ITEM *sibling = NULL;
1466 if (newItem == NULL)
1467 ERR("NULL newItem, impossible condition\n");
1469 if (upSibling != NULL) /* Insert after this upsibling for this parent */
1471 /* Store the new item up sibling and sibling item handle */
1472 upSiblingHandle = upSibling->hItem;
1473 siblingHandle = upSibling->sibling;
1474 /* As well as a pointer to the upsibling sibling object */
1475 if ( (INT)upSibling->sibling != 0 )
1476 sibling = &infoPtr->items[(INT)upSibling->sibling];
1478 /* Adjust the up sibling pointer */
1479 upSibling->sibling = newItem->hItem;
1481 /* Adjust the new item pointers */
1482 newItem->upsibling = upSiblingHandle;
1483 newItem->sibling = siblingHandle;
1485 /* Adjust the sibling pointer */
1486 if ( sibling != NULL )
1487 sibling->upsibling = newItem->hItem;
1490 newItem is the last of the level, nothing else to do
1493 else /* Insert as first child of this parent */
1495 parent->firstChild = newItem->hItem;
1498 /***************************************************************************
1499 * Forward the DPA local callback to the treeview owner callback
1501 static INT WINAPI TREEVIEW_CallBackCompare(
1506 /* Forward the call to the client define callback */
1507 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr((HWND)tvInfoPtr);
1508 return (infoPtr->pCallBackSort->lpfnCompare)(
1509 ((TREEVIEW_ITEM*)first)->lParam,
1510 ((TREEVIEW_ITEM*)second)->lParam,
1511 infoPtr->pCallBackSort->lParam);
1514 /***************************************************************************
1515 * Treeview native sort routine: sort on item text.
1517 static INT WINAPI TREEVIEW_SortOnName (
1522 HWND hwnd=(HWND) tvInfoPtr;
1524 TREEVIEW_ITEM *item;
1527 item=(TREEVIEW_ITEM *) first;
1528 if (item->pszText==LPSTR_TEXTCALLBACKA) {
1529 TREEVIEW_SendDispInfoNotify (hwnd, item, TVN_GETDISPINFOA, TVIF_TEXT);
1533 item=(TREEVIEW_ITEM *) second;
1534 if (item->pszText==LPSTR_TEXTCALLBACKA) {
1535 TREEVIEW_SendDispInfoNotify (hwnd, item, TVN_GETDISPINFOA, TVIF_TEXT);
1539 return -strcmp (txt1,txt2);
1542 /***************************************************************************
1543 * Setup the treeview structure with regards of the sort method
1544 * and sort the children of the TV item specified in lParam
1545 * fRecurse: currently unused. Should be zero.
1546 * parent: if pSort!=NULL, should equal pSort->hParent.
1547 * otherwise, item which child items are to be sorted.
1548 * pSort: sort method info. if NULL, sort on item text.
1549 * if non-NULL, sort on item's lParam content, and let the
1550 * application decide what that means. See also TVM_SORTCHILDRENCB.
1553 static LRESULT WINAPI TREEVIEW_Sort (
1560 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1561 TREEVIEW_ITEM *sortMe = NULL; /* Node for which we sort the children */
1563 /* Obtain the TVSORTBC struct */
1564 infoPtr->pCallBackSort = pSort;
1566 /* undocumented feature: TVI_ROOT means `sort the whole tree' */
1568 if (parent==TVI_ROOT)
1569 parent=infoPtr->TopRootItem;
1571 /* Check for a valid handle to the parent item */
1572 if (!TREEVIEW_ValidItem(infoPtr, parent))
1574 ERR ("invalid item hParent=%x\n", (INT)parent);
1578 /* Obtain the parent node to sort */
1579 sortMe = &infoPtr->items[ (INT)parent ];
1581 /* Make sure there is something to sort */
1582 if ( sortMe->cChildren > 1 )
1584 /* pointer organization */
1585 HDPA sortList = DPA_Create(sortMe->cChildren);
1586 HTREEITEM itemHandle = sortMe->firstChild;
1587 TREEVIEW_ITEM *itemPtr = & infoPtr->items[ (INT)itemHandle ];
1589 /* TREEVIEW_ITEM rechaining */
1595 /* Build the list of item to sort */
1599 sortList, /* the list */
1600 sortMe->cChildren+1, /* force the insertion to be an append */
1601 itemPtr); /* the ptr to store */
1603 /* Get the next sibling */
1604 itemHandle = itemPtr->sibling;
1605 itemPtr = & infoPtr->items[ (INT)itemHandle ];
1606 } while ( itemHandle != NULL );
1608 /* let DPA perform the sort activity */
1611 sortList, /* what */
1612 TREEVIEW_CallBackCompare, /* how */
1616 sortList, /* what */
1617 TREEVIEW_SortOnName, /* how */
1621 * Reorganized TREEVIEW_ITEM structures.
1622 * Note that we know we have at least two elements.
1625 /* Get the first item and get ready to start... */
1626 item = DPA_GetPtr(sortList, count++);
1627 while ( (nextItem = DPA_GetPtr(sortList, count++)) != NULL )
1629 /* link the two current item toghether */
1630 ((TREEVIEW_ITEM*)item)->sibling = ((TREEVIEW_ITEM*)nextItem)->hItem;
1631 ((TREEVIEW_ITEM*)nextItem)->upsibling = ((TREEVIEW_ITEM*)item)->hItem;
1633 if (prevItem == NULL) /* this is the first item, update the parent */
1635 sortMe->firstChild = ((TREEVIEW_ITEM*)item)->hItem;
1636 ((TREEVIEW_ITEM*)item)->upsibling = NULL;
1638 else /* fix the back chaining */
1640 ((TREEVIEW_ITEM*)item)->upsibling = ((TREEVIEW_ITEM*)prevItem)->hItem;
1643 /* get ready for the next one */
1648 /* the last item is pointed to by item and never has a sibling */
1649 ((TREEVIEW_ITEM*)item)->sibling = NULL;
1651 DPA_Destroy(sortList);
1659 /***************************************************************************
1660 * Setup the treeview structure with regards of the sort method
1661 * and sort the children of the TV item specified in lParam
1663 static LRESULT WINAPI TREEVIEW_SortChildrenCB(
1669 LPTVSORTCB pSort=(LPTVSORTCB) lParam;
1671 return TREEVIEW_Sort (hwnd, wParam, pSort->hParent, pSort);
1675 /***************************************************************************
1676 * Sort the children of the TV item specified in lParam.
1678 static LRESULT WINAPI TREEVIEW_SortChildren (
1683 return TREEVIEW_Sort (hwnd, (BOOL) wParam, (HTREEITEM) lParam, NULL);
1688 /* the method used below isn't the most memory-friendly, but it avoids
1689 a lot of memory reallocations */
1691 /* BTW: we waste handle 0; 0 is not an allowed handle. */
1694 TREEVIEW_InsertItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1697 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1698 TVINSERTSTRUCTA *ptdi;
1700 TREEVIEW_ITEM *wineItem, *parentItem, *prevsib, *sibItem;
1701 INT iItem,listItems,i,len;
1703 /* Item to insert */
1704 ptdi = (LPTVINSERTSTRUCTA) lParam;
1706 /* check if memory is available */
1708 if (infoPtr->uNumPtrsAlloced==0) {
1709 infoPtr->items = COMCTL32_Alloc (TVITEM_ALLOC*sizeof (TREEVIEW_ITEM));
1710 infoPtr->freeList= COMCTL32_Alloc ((1+(TVITEM_ALLOC>>5)) * sizeof (INT));
1711 infoPtr->uNumPtrsAlloced=TVITEM_ALLOC;
1712 infoPtr->TopRootItem=(HTREEITEM)1;
1716 * Reallocate contiguous space for items
1718 if (infoPtr->uNumItems == (infoPtr->uNumPtrsAlloced-1) ) {
1719 TREEVIEW_ITEM *oldItems = infoPtr->items;
1720 INT *oldfreeList = infoPtr->freeList;
1722 infoPtr->uNumPtrsAlloced*=2;
1723 infoPtr->items = COMCTL32_Alloc (infoPtr->uNumPtrsAlloced*sizeof (TREEVIEW_ITEM));
1724 infoPtr->freeList= COMCTL32_Alloc ((1+(infoPtr->uNumPtrsAlloced>>5))*sizeof (INT));
1726 memcpy (&infoPtr->items[0], &oldItems[0],
1727 infoPtr->uNumPtrsAlloced/2 * sizeof(TREEVIEW_ITEM));
1728 memcpy (&infoPtr->freeList[0], &oldfreeList[0],
1729 (infoPtr->uNumPtrsAlloced>>6) * sizeof(INT));
1731 COMCTL32_Free (oldItems);
1732 COMCTL32_Free (oldfreeList);
1736 * Reset infoPtr structure with new stat according to current TV picture
1739 infoPtr->uNumItems++;
1740 if ((INT)infoPtr->uMaxHandle==(infoPtr->uNumItems-1)) {
1741 iItem=infoPtr->uNumItems;
1742 infoPtr->uMaxHandle = (HTREEITEM)((INT)infoPtr->uMaxHandle + 1);
1743 } else { /* check freelist */
1744 for (i=0; i<=infoPtr->uNumPtrsAlloced>>5; i++) {
1745 if (infoPtr->freeList[i]) {
1746 iItem=ffs (infoPtr->freeList[i])-1;
1747 tv_clear_bit(iItem,&infoPtr->freeList[i]);
1754 if (TRACE_ON(treeview)) {
1755 for (i=0; i<=infoPtr->uNumPtrsAlloced>>5; i++)
1756 TRACE("%8x\n",infoPtr->freeList[i]);
1759 if (!iItem) ERR("Argh -- can't find free item.\n");
1762 * Find the parent item of the new item
1764 tvItem= & ptdi->DUMMYUNIONNAME.itemex;
1765 wineItem=& infoPtr->items[iItem];
1767 if ((ptdi->hParent==TVI_ROOT) || (ptdi->hParent==0)) {
1769 wineItem->parent = 0;
1770 sibItem = &infoPtr->items [(INT)infoPtr->TopRootItem];
1771 listItems = infoPtr->uNumItems;
1774 parentItem = &infoPtr->items[(INT)ptdi->hParent];
1776 /* Do the insertion here it if it's the only item of this parent */
1777 if (!parentItem->firstChild)
1778 parentItem->firstChild=(HTREEITEM)iItem;
1780 wineItem->parent = ptdi->hParent;
1781 sibItem = &infoPtr->items [(INT)parentItem->firstChild];
1782 listItems = parentItem->cChildren;
1783 parentItem->cChildren++;
1787 /* NOTE: I am moving some setup of the wineItem object that was initialy
1788 * done at the end of the function since some of the values are
1789 * required by the Callback sorting
1792 if (tvItem->mask & TVIF_TEXT)
1795 * Setup the item text stuff here since it's required by the Sort method
1796 * when the insertion are ordered
1798 if (tvItem->pszText!=LPSTR_TEXTCALLBACKA)
1800 TRACE("(%p,%s)\n", &tvItem->pszText, tvItem->pszText);
1801 len = lstrlenA (tvItem->pszText)+1;
1802 wineItem->pszText= COMCTL32_Alloc (len+1);
1803 lstrcpyA (wineItem->pszText, tvItem->pszText);
1804 wineItem->cchTextMax=len;
1808 TRACE("LPSTR_TEXTCALLBACK\n");
1809 wineItem->pszText = LPSTR_TEXTCALLBACKA;
1810 wineItem->cchTextMax = 0;
1814 if (tvItem->mask & TVIF_PARAM)
1815 wineItem->lParam=tvItem->lParam;
1818 wineItem->upsibling=0; /* needed in case we're the first item in a list */
1819 wineItem->sibling=0;
1820 wineItem->firstChild=0;
1821 wineItem->hItem=(HTREEITEM)iItem;
1826 switch ((DWORD) ptdi->hInsertAfter) {
1827 case (DWORD) TVI_FIRST:
1828 if (sibItem==wineItem) break;
1829 if (wineItem->parent) {
1830 wineItem->sibling=parentItem->firstChild;
1831 parentItem->firstChild=(HTREEITEM)iItem;
1833 wineItem->sibling=infoPtr->TopRootItem;
1834 infoPtr->TopRootItem=(HTREEITEM)iItem;
1836 sibItem->upsibling=(HTREEITEM)iItem;
1839 case (DWORD) TVI_SORT:
1840 if (sibItem==wineItem)
1842 * This item is the first child of the level and it
1843 * has already been inserted
1848 TREEVIEW_ITEM *aChild;
1851 TREEVIEW_ITEM *previousChild = NULL;
1852 BOOL bItemInserted = FALSE;
1855 aChild = &infoPtr->items[(INT)parentItem->firstChild];
1857 aChild = &infoPtr->items[(INT)infoPtr->TopRootItem];
1859 /* lookup the text if using LPSTR_TEXTCALLBACKs */
1860 if (wineItem->pszText==LPSTR_TEXTCALLBACKA) {
1861 TREEVIEW_SendDispInfoNotify (hwnd, wineItem, TVN_GETDISPINFOA, TVIF_TEXT);
1864 /* Iterate the parent children to see where we fit in */
1865 while ( aChild != NULL )
1869 /* lookup the text if using LPSTR_TEXTCALLBACKs */
1870 if (aChild->pszText==LPSTR_TEXTCALLBACKA) {
1871 TREEVIEW_SendDispInfoNotify (hwnd, aChild, TVN_GETDISPINFOA, TVIF_TEXT);
1874 comp = strcmp(wineItem->pszText, aChild->pszText);
1875 if ( comp < 0 ) /* we are smaller than the current one */
1877 TREEVIEW_InsertBefore(infoPtr, wineItem, aChild, parentItem);
1878 bItemInserted = TRUE;
1881 else if ( comp > 0 ) /* we are bigger than the current one */
1883 previousChild = aChild;
1884 aChild = (aChild->sibling == 0) /* This will help us to exit */
1885 ? NULL /* if there is no more sibling */
1886 : &infoPtr->items[(INT)aChild->sibling];
1888 /* Look at the next item */
1891 else if ( comp == 0 )
1894 * An item with this name is already existing, therefore,
1895 * we add after the one we found
1897 TREEVIEW_InsertAfter(infoPtr, wineItem, aChild, parentItem);
1898 bItemInserted = TRUE;
1904 * we reach the end of the child list and the item as not
1905 * yet been inserted, therefore, insert it after the last child.
1907 if ( (! bItemInserted ) && (aChild == NULL) )
1908 TREEVIEW_InsertAfter(infoPtr, wineItem, previousChild, parentItem);
1914 case (DWORD) TVI_LAST:
1915 if (sibItem==wineItem) break;
1916 while (sibItem->sibling) {
1918 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1920 sibItem->sibling=(HTREEITEM)iItem;
1921 wineItem->upsibling=sibItem->hItem;
1924 while ((sibItem->sibling) && (sibItem->hItem!=ptdi->hInsertAfter))
1927 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1929 if (sibItem->hItem!=ptdi->hInsertAfter) {
1930 ERR("tried to insert item after nonexisting handle %d.\n",
1931 (INT) ptdi->hInsertAfter);
1935 if (sibItem->sibling) {
1936 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1937 sibItem->upsibling=(HTREEITEM)iItem;
1938 wineItem->sibling=sibItem->hItem;
1940 prevsib->sibling=(HTREEITEM)iItem;
1941 wineItem->upsibling=prevsib->hItem;
1947 /* Fill in info structure */
1949 TRACE("new item %d; parent %d, mask %x\n", iItem,
1950 (INT)wineItem->parent,tvItem->mask);
1952 wineItem->mask=tvItem->mask;
1953 wineItem->iIntegral=1;
1955 if (tvItem->mask & TVIF_CHILDREN) {
1956 wineItem->cChildren=tvItem->cChildren;
1957 if (tvItem->cChildren==I_CHILDRENCALLBACK)
1958 FIXME(" I_CHILDRENCALLBACK not supported\n");
1961 wineItem->expandBox.left = 0; /* Initialize the expandBox */
1962 wineItem->expandBox.top = 0;
1963 wineItem->expandBox.right = 0;
1964 wineItem->expandBox.bottom = 0;
1966 if (tvItem->mask & TVIF_IMAGE)
1967 wineItem->iImage=tvItem->iImage;
1969 /* If the application sets TVIF_INTEGRAL without
1970 supplying a TVITEMEX structure, it's toast */
1972 if (tvItem->mask & TVIF_INTEGRAL)
1973 wineItem->iIntegral=tvItem->iIntegral;
1975 if (tvItem->mask & TVIF_SELECTEDIMAGE)
1976 wineItem->iSelectedImage=tvItem->iSelectedImage;
1978 if (tvItem->mask & TVIF_STATE) {
1979 TRACE("item state: %x ->%x\n", wineItem->state, tvItem->state);
1980 TRACE("statemask: %x ->%x\n", wineItem->stateMask, tvItem->stateMask);
1981 wineItem->state=tvItem->state;
1982 wineItem->stateMask=tvItem->stateMask;
1985 TREEVIEW_QueueRefresh (hwnd);
1987 return (LRESULT) iItem;
1992 TREEVIEW_InsertItemW(HWND hwnd, WPARAM wParam, LPARAM lParam)
1994 TVINSERTSTRUCTW *tvisW;
1995 TVINSERTSTRUCTA tvisA;
1998 tvisW = (LPTVINSERTSTRUCTW)lParam;
2000 tvisA.hParent = tvisW->hParent;
2001 tvisA.hInsertAfter = tvisW->hInsertAfter;
2003 tvisA.DUMMYUNIONNAME.item.mask = tvisW->DUMMYUNIONNAME.item.mask;
2004 tvisA.DUMMYUNIONNAME.item.hItem = tvisW->DUMMYUNIONNAME.item.hItem;
2005 tvisA.DUMMYUNIONNAME.item.state = tvisW->DUMMYUNIONNAME.item.state;
2006 tvisA.DUMMYUNIONNAME.item.stateMask = tvisW->DUMMYUNIONNAME.item.stateMask;
2007 tvisA.DUMMYUNIONNAME.item.cchTextMax = tvisW->DUMMYUNIONNAME.item.cchTextMax;
2009 if(tvisW->DUMMYUNIONNAME.item.pszText)
2011 if (tvisW->DUMMYUNIONNAME.item.pszText!=LPSTR_TEXTCALLBACKW)
2013 int len = lstrlenW (tvisW->DUMMYUNIONNAME.item.pszText)+1;
2014 tvisA.DUMMYUNIONNAME.item.pszText = COMCTL32_Alloc (len);
2015 lstrcpyWtoA (tvisA.DUMMYUNIONNAME.item.pszText,
2016 tvisW->DUMMYUNIONNAME.item.pszText );
2020 tvisA.DUMMYUNIONNAME.item.pszText = LPSTR_TEXTCALLBACKA;
2021 tvisA.DUMMYUNIONNAME.item.cchTextMax = 0;
2025 tvisA.DUMMYUNIONNAME.item.iImage = tvisW->DUMMYUNIONNAME.item.iImage;
2026 tvisA.DUMMYUNIONNAME.item.iSelectedImage = tvisW->DUMMYUNIONNAME.item.iSelectedImage;
2027 tvisA.DUMMYUNIONNAME.item.cChildren = tvisW->DUMMYUNIONNAME.item.cChildren;
2028 tvisA.DUMMYUNIONNAME.item.lParam = tvisW->DUMMYUNIONNAME.item.lParam;
2030 lRes = TREEVIEW_InsertItemA(hwnd,wParam,(LPARAM)&tvisA);
2032 if (tvisA.DUMMYUNIONNAME.item.pszText!=LPSTR_TEXTCALLBACKA)
2034 COMCTL32_Free(tvisA.DUMMYUNIONNAME.item.pszText);
2043 TREEVIEW_DeleteItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
2045 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2047 TREEVIEW_ITEM *wineItem;
2049 TRACE("item = %08lx\n", lParam);
2051 if (lParam == (INT)TVI_ROOT) {
2052 TREEVIEW_RemoveTree (hwnd);
2054 iItem= (INT) lParam;
2055 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
2056 if (!wineItem) return FALSE;
2058 if (wineItem->pszText==LPSTR_TEXTCALLBACKA)
2059 TRACE("LPSTR_TEXTCALLBACK\n");
2061 TRACE("%s\n",wineItem->pszText);
2062 TREEVIEW_RemoveItem (hwnd, wineItem);
2065 TREEVIEW_QueueRefresh (hwnd);
2073 TREEVIEW_GetIndent (HWND hwnd)
2075 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2078 return infoPtr->uIndent;
2082 TREEVIEW_SetIndent (HWND hwnd, WPARAM wParam)
2084 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2088 newIndent=(INT) wParam;
2089 if (newIndent < MINIMUM_INDENT) newIndent=MINIMUM_INDENT;
2090 infoPtr->uIndent=newIndent;
2096 TREEVIEW_GetToolTips (HWND hwnd)
2099 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2102 return infoPtr->hwndToolTip;
2107 TREEVIEW_SetToolTips (HWND hwnd, WPARAM wParam)
2110 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2114 prevToolTip=infoPtr->hwndToolTip;
2115 infoPtr->hwndToolTip= (HWND) wParam;
2121 static LRESULT CALLBACK
2122 TREEVIEW_GetEditControl (HWND hwnd)
2125 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2127 return infoPtr->hwndEdit;
2131 TREEVIEW_Edit_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam,
2139 HDC hdc = (HDC) wParam;
2140 GetClientRect (hwnd, &rc);
2141 Rectangle (hdc, rc.left, rc.top, rc.right, rc.bottom);
2147 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
2151 if (wParam == VK_ESCAPE)
2153 TREEVIEW_EndEditLabelNow(GetParent(hwnd), (WPARAM)TRUE, 0);
2156 else if (wParam == VK_RETURN)
2157 TREEVIEW_EndEditLabelNow(GetParent(hwnd), (WPARAM)FALSE, 0);
2164 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd));
2166 return CallWindowProcA (infoPtr->wpEditOrig, hwnd, uMsg, wParam, lParam);
2177 /* should handle edit control messages here */
2180 TREEVIEW_Command (HWND hwnd, WPARAM wParam, LPARAM lParam)
2183 TRACE("%x %ld\n",wParam, lParam);
2185 switch (HIWORD(wParam))
2190 * Adjust the edit window size
2192 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2193 TREEVIEW_ITEM *editItem = TREEVIEW_ValidItem(infoPtr, infoPtr->editItem);
2194 INT iLength = GetWindowTextLengthA(infoPtr->hwndEdit);
2195 HDC hdc = GetDC(infoPtr->hwndEdit);
2198 if ( GetTextMetricsA(hdc, &tm) )
2200 LONG newWidth = (iLength * tm.tmAveCharWidth) + 15;
2205 editItem->text.left - 2,
2206 editItem->text.top - 1,
2208 editItem->text.bottom - editItem->text.top + 3,
2211 ReleaseDC(hwnd, hdc);
2217 /* TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
2222 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
2229 TREEVIEW_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
2232 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2234 if (infoPtr->bAutoSize)
2236 infoPtr->bAutoSize = FALSE;
2239 infoPtr->bAutoSize = TRUE;
2241 if (wParam == SIZE_RESTORED)
2243 infoPtr->uTotalWidth = LOWORD (lParam);
2244 infoPtr->uTotalHeight = HIWORD (lParam);
2246 FIXME("WM_SIZE flag %x %lx not handled\n", wParam, lParam);
2249 TREEVIEW_QueueRefresh (hwnd);
2256 TREEVIEW_StyleChanged (HWND hwnd, WPARAM wParam, LPARAM lParam)
2260 TRACE("(%x %lx)\n",wParam,lParam);
2262 TREEVIEW_Refresh (hwnd, hdc);
2263 ReleaseDC(hwnd,hdc);
2269 TREEVIEW_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
2271 TREEVIEW_INFO *infoPtr;
2272 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
2277 TRACE("wnd %x, style %lx\n",hwnd,dwStyle);
2278 /* allocate memory for info structure */
2279 infoPtr = (TREEVIEW_INFO *) COMCTL32_Alloc (sizeof(TREEVIEW_INFO));
2281 SetWindowLongA( hwnd, 0, (DWORD)infoPtr);
2283 if (infoPtr == NULL) {
2284 ERR("could not allocate info memory!\n");
2288 if ((TREEVIEW_INFO*) GetWindowLongA( hwnd, 0) != infoPtr) {
2289 ERR("pointer assignment error!\n");
2295 /* set default settings */
2296 infoPtr->uInternalStatus=0;
2297 infoPtr->uNumItems=0;
2298 infoPtr->clrBk = GetSysColor (COLOR_WINDOW);
2299 infoPtr->clrText = GetSysColor (COLOR_WINDOWTEXT);
2300 infoPtr->clrLine = GetSysColor (COLOR_WINDOWTEXT);
2301 infoPtr->clrInsertMark = GetSysColor (COLOR_BTNTEXT);
2304 infoPtr->uIndent = 15;
2305 infoPtr->himlNormal = NULL;
2306 infoPtr->himlState = NULL;
2307 infoPtr->uItemHeight = -1;
2308 GetTextMetricsA (hdc, &tm);
2309 infoPtr->hFont = GetStockObject (DEFAULT_GUI_FONT);
2310 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
2311 logFont.lfWeight=FW_BOLD;
2312 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
2314 infoPtr->items = NULL;
2315 infoPtr->selectedItem=0;
2316 infoPtr->clrText=-1; /* use system color */
2317 infoPtr->dropItem=0;
2318 infoPtr->insertMarkItem=0;
2319 infoPtr->insertBeforeorAfter=0;
2320 infoPtr->pCallBackSort=NULL;
2321 infoPtr->uScrollTime = 300; /* milliseconds */
2322 infoPtr->wpEditOrig = NULL; /* we haven't subclassed anything yet */
2324 infoPtr->hwndToolTip=0;
2325 if (!(dwStyle & TVS_NOTOOLTIPS)) { /* Create tooltip control */
2328 infoPtr->hwndToolTip =
2329 CreateWindowExA (0, TOOLTIPS_CLASSA, NULL, 0,
2330 CW_USEDEFAULT, CW_USEDEFAULT,
2331 CW_USEDEFAULT, CW_USEDEFAULT,
2334 /* Send NM_TOOLTIPSCREATED notification */
2335 if (infoPtr->hwndToolTip) {
2336 NMTOOLTIPSCREATED nmttc;
2338 nmttc.hdr.hwndFrom = hwnd;
2339 nmttc.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2340 nmttc.hdr.code = NM_TOOLTIPSCREATED;
2341 nmttc.hwndToolTips = infoPtr->hwndToolTip;
2343 SendMessageA (GetParent (hwnd), WM_NOTIFY,
2344 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmttc);
2347 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
2348 ti.cbSize = sizeof(TTTOOLINFOA);
2349 ti.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_TRANSPARENT ;
2352 ti.lpszText = "Test"; /* LPSTR_TEXTCALLBACK; */
2353 SetRectEmpty (&ti.rect);
2355 SendMessageA (infoPtr->hwndToolTip, TTM_ADDTOOLA, 0, (LPARAM)&ti);
2358 infoPtr->hwndEdit = CreateWindowExA (
2362 WS_CHILD | WS_BORDER | ES_AUTOHSCROLL |
2363 ES_WANTRETURN | ES_LEFT,
2366 0,0,0); /* FIXME: (HMENU)IDTVEDIT,pcs->hInstance,0);*/
2368 SendMessageA ( infoPtr->hwndEdit, WM_SETFONT, infoPtr->hFont, FALSE);
2369 infoPtr->wpEditOrig = (WNDPROC)SetWindowLongA (
2372 (LONG) TREEVIEW_Edit_SubclassProc);
2374 if (dwStyle & TVS_CHECKBOXES) {
2378 infoPtr->himlState =
2379 ImageList_Create (16, 16,ILC_COLOR|ILC_MASK, 15, 1);
2381 hbmLoad = LoadBitmapA (COMCTL32_hModule, MAKEINTRESOURCEA(IDT_CHECK));
2382 TRACE ("%x\n",hbmLoad);
2383 nIndex = ImageList_AddMasked (infoPtr->himlState, hbmLoad, CLR_DEFAULT);
2384 TRACE ("%d\n",nIndex);
2385 DeleteObject (hbmLoad);
2387 ReleaseDC (hwnd, hdc);
2394 TREEVIEW_Destroy (HWND hwnd)
2396 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2399 TREEVIEW_RemoveTree (hwnd);
2400 SetWindowLongA (hwnd, 0, (DWORD)NULL);
2402 if (infoPtr->Timer & TV_REFRESH_TIMER_SET)
2403 KillTimer (hwnd, TV_REFRESH_TIMER);
2404 if (infoPtr->hwndToolTip)
2405 DestroyWindow (infoPtr->hwndToolTip);
2407 COMCTL32_Free (infoPtr);
2413 TREEVIEW_Paint (HWND hwnd, WPARAM wParam, LPARAM lParam)
2419 hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
2420 TREEVIEW_Refresh (hwnd, hdc);
2421 if(!wParam) EndPaint (hwnd, &ps);
2424 return DefWindowProcA (hwnd, WM_PAINT, wParam, lParam);
2428 TREEVIEW_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2430 TREEVIEW_SendSimpleNotify (hwnd, NM_SETFOCUS);
2431 InvalidateRect(hwnd, NULL, FALSE);
2436 TREEVIEW_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2438 TREEVIEW_SendSimpleNotify (hwnd, NM_KILLFOCUS);
2439 InvalidateRect(hwnd, NULL, FALSE);
2444 TREEVIEW_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
2446 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2447 HBRUSH hBrush = CreateSolidBrush (infoPtr->clrBk);
2451 GetClientRect (hwnd, &rect);
2452 FillRect ((HDC)wParam, &rect, hBrush);
2453 DeleteObject (hBrush);
2469 TREEVIEW_SendSimpleNotify (HWND hwnd, UINT code)
2474 nmhdr.hwndFrom = hwnd;
2475 nmhdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2478 return (BOOL) SendMessageA (GetParent (hwnd), WM_NOTIFY,
2479 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
2485 TREEVIEW_SendTreeviewNotify (HWND hwnd, UINT code, UINT action,
2486 HTREEITEM oldItem, HTREEITEM newItem)
2489 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2491 TREEVIEW_ITEM *wineItem;
2493 TRACE("code:%x action:%x olditem:%x newitem:%x\n",
2494 code,action,(INT)oldItem,(INT)newItem);
2495 nmhdr.hdr.hwndFrom = hwnd;
2496 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2497 nmhdr.hdr.code = code;
2498 nmhdr.action = action;
2500 wineItem=& infoPtr->items[(INT)oldItem];
2501 nmhdr.itemOld.mask = wineItem->mask;
2502 nmhdr.itemOld.hItem = wineItem->hItem;
2503 nmhdr.itemOld.state = wineItem->state;
2504 nmhdr.itemOld.stateMask = wineItem->stateMask;
2505 nmhdr.itemOld.iImage = wineItem->iImage;
2506 nmhdr.itemOld.pszText = wineItem->pszText;
2507 nmhdr.itemOld.cchTextMax= wineItem->cchTextMax;
2508 nmhdr.itemOld.iImage = wineItem->iImage;
2509 nmhdr.itemOld.iSelectedImage = wineItem->iSelectedImage;
2510 nmhdr.itemOld.cChildren = wineItem->cChildren;
2511 nmhdr.itemOld.lParam = wineItem->lParam;
2515 wineItem=& infoPtr->items[(INT)newItem];
2516 nmhdr.itemNew.mask = wineItem->mask;
2517 nmhdr.itemNew.hItem = wineItem->hItem;
2518 nmhdr.itemNew.state = wineItem->state;
2519 nmhdr.itemNew.stateMask = wineItem->stateMask;
2520 nmhdr.itemNew.iImage = wineItem->iImage;
2521 nmhdr.itemNew.pszText = wineItem->pszText;
2522 nmhdr.itemNew.cchTextMax= wineItem->cchTextMax;
2523 nmhdr.itemNew.iImage = wineItem->iImage;
2524 nmhdr.itemNew.iSelectedImage = wineItem->iSelectedImage;
2525 nmhdr.itemNew.cChildren = wineItem->cChildren;
2526 nmhdr.itemNew.lParam = wineItem->lParam;
2532 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2533 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2538 TREEVIEW_SendTreeviewDnDNotify (HWND hwnd, UINT code, HTREEITEM dragItem,
2541 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2543 TREEVIEW_ITEM *wineItem;
2545 TRACE("code:%x dragitem:%x\n", code,(INT)dragItem);
2547 nmhdr.hdr.hwndFrom = hwnd;
2548 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2549 nmhdr.hdr.code = code;
2551 wineItem=& infoPtr->items[(INT)dragItem];
2552 nmhdr.itemNew.mask = wineItem->mask;
2553 nmhdr.itemNew.hItem = wineItem->hItem;
2554 nmhdr.itemNew.state = wineItem->state;
2555 nmhdr.itemNew.lParam = wineItem->lParam;
2557 nmhdr.ptDrag.x = pt.x;
2558 nmhdr.ptDrag.y = pt.y;
2560 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2561 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2568 TREEVIEW_SendDispInfoNotify (HWND hwnd, TREEVIEW_ITEM *wineItem,
2569 UINT code, UINT what)
2575 TRACE("item %d, action %x, state %d\n",
2576 (INT)wineItem->hItem,
2578 (INT)wineItem->state);
2580 tvdi.hdr.hwndFrom = hwnd;
2581 tvdi.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2582 tvdi.hdr.code = code;
2583 tvdi.item.mask = what;
2584 tvdi.item.hItem = wineItem->hItem;
2585 tvdi.item.state = wineItem->state;
2586 tvdi.item.lParam = wineItem->lParam;
2587 tvdi.item.pszText = COMCTL32_Alloc (128*sizeof(char));
2588 tvdi.item.cchTextMax = 128;
2589 buf = tvdi.item.pszText;
2591 retval=(BOOL)SendMessageA (
2594 (WPARAM)tvdi.hdr.idFrom,
2597 if (what & TVIF_TEXT) {
2598 wineItem->pszText = tvdi.item.pszText;
2599 if (buf==tvdi.item.pszText) {
2600 wineItem->cchTextMax = 128;
2602 TRACE("user-supplied buffer\n");
2603 COMCTL32_Free (buf);
2604 wineItem->cchTextMax = 0;
2607 if (what & TVIF_SELECTEDIMAGE)
2608 wineItem->iSelectedImage = tvdi.item.iSelectedImage;
2609 if (what & TVIF_IMAGE)
2610 wineItem->iImage = tvdi.item.iImage;
2611 if (what & TVIF_CHILDREN)
2612 wineItem->cChildren = tvdi.item.cChildren;
2620 TREEVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
2623 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2624 NMTVCUSTOMDRAW nmcdhdr;
2625 LPNMCUSTOMDRAW nmcd;
2627 TRACE("drawstage:%lx hdc:%x\n", dwDrawStage, hdc);
2629 nmcd= & nmcdhdr.nmcd;
2630 nmcd->hdr.hwndFrom = hwnd;
2631 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2632 nmcd->hdr.code = NM_CUSTOMDRAW;
2633 nmcd->dwDrawStage= dwDrawStage;
2635 nmcd->rc.left = rc.left;
2636 nmcd->rc.right = rc.right;
2637 nmcd->rc.bottom = rc.bottom;
2638 nmcd->rc.top = rc.top;
2639 nmcd->dwItemSpec = 0;
2640 nmcd->uItemState = 0;
2641 nmcd->lItemlParam= 0;
2642 nmcdhdr.clrText = infoPtr->clrText;
2643 nmcdhdr.clrTextBk= infoPtr->clrBk;
2646 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2647 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2653 /* FIXME: need to find out when the flags in uItemState need to be set */
2656 TREEVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
2657 TREEVIEW_ITEM *wineItem, UINT uItemDrawState)
2659 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2660 NMTVCUSTOMDRAW nmcdhdr;
2661 LPNMCUSTOMDRAW nmcd;
2662 DWORD dwDrawStage,dwItemSpec;
2666 dwDrawStage=CDDS_ITEM | uItemDrawState;
2667 dwItemSpec=(DWORD)wineItem->hItem;
2669 if (wineItem->hItem==infoPtr->selectedItem) uItemState|=CDIS_SELECTED;
2670 if (wineItem->hItem==infoPtr->focusItem) uItemState|=CDIS_FOCUS;
2671 if (wineItem->hItem==infoPtr->hotItem) uItemState|=CDIS_HOT;
2673 nmcd= & nmcdhdr.nmcd;
2674 nmcd->hdr.hwndFrom = hwnd;
2675 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2676 nmcd->hdr.code = NM_CUSTOMDRAW;
2677 nmcd->dwDrawStage= dwDrawStage;
2679 nmcd->rc.left = wineItem->rect.left;
2680 nmcd->rc.right = wineItem->rect.right;
2681 nmcd->rc.bottom = wineItem->rect.bottom;
2682 nmcd->rc.top = wineItem->rect.top;
2683 nmcd->dwItemSpec = dwItemSpec;
2684 nmcd->uItemState = uItemState;
2685 nmcd->lItemlParam= wineItem->lParam;
2686 nmcdhdr.clrText = infoPtr->clrText;
2687 nmcdhdr.clrTextBk= infoPtr->clrBk;
2688 nmcdhdr.iLevel = wineItem->iLevel;
2690 TRACE("drawstage:%lx hdc:%x item:%lx, itemstate:%x, lItemlParam:%lx\n",
2691 nmcd->dwDrawStage, nmcd->hdc, nmcd->dwItemSpec,
2692 nmcd->uItemState, nmcd->lItemlParam);
2694 retval=SendMessageA (GetParent (hwnd), WM_NOTIFY,
2695 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2697 infoPtr->clrText=nmcdhdr.clrText;
2698 infoPtr->clrBk =nmcdhdr.clrTextBk;
2699 return (BOOL) retval;
2704 /* Note:If the specified item is the child of a collapsed parent item,
2705 the parent's list of child items is (recursively) expanded to reveal the
2706 specified item. This is mentioned for TREEVIEW_SelectItem; don't
2707 know if it also applies here.
2711 TREEVIEW_Expand (HWND hwnd, WPARAM wParam, LPARAM lParam)
2713 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2714 TREEVIEW_ITEM *wineItem;
2718 flag = (UINT) wParam;
2719 expand = (INT) lParam;
2721 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2725 if (!wineItem->cChildren)
2728 if (wineItem->pszText==LPSTR_TEXTCALLBACKA)
2729 TRACE ("For item %d, flags %d, state %d\n",
2730 expand, flag, wineItem->state);
2732 TRACE("For (%s) item:%d, flags %x, state:%d\n",
2733 wineItem->pszText, flag, expand, wineItem->state);
2735 if (wineItem->cChildren==I_CHILDRENCALLBACK) {
2736 FIXME("we don't handle I_CHILDRENCALLBACK yet\n");
2740 if (flag == TVE_TOGGLE) { /* FIXME: check exact behaviour here */
2741 flag &= ~TVE_TOGGLE; /* ie: bitwise ops or 'case' ops */
2742 if (wineItem->state & TVIS_EXPANDED)
2743 flag |= TVE_COLLAPSE;
2750 case TVE_COLLAPSERESET:
2751 TRACE(" case TVE_COLLAPSERESET\n");
2752 if (!wineItem->state & TVIS_EXPANDED)
2755 wineItem->state &= ~(TVIS_EXPANDEDONCE | TVIS_EXPANDED);
2756 TREEVIEW_RemoveAllChildren (hwnd, wineItem);
2760 TRACE(" case TVE_COLLAPSE\n");
2761 if (!wineItem->state & TVIS_EXPANDED)
2764 wineItem->state &= ~TVIS_EXPANDED;
2768 TRACE(" case TVE_EXPAND\n");
2769 if (wineItem->state & TVIS_EXPANDED)
2772 TRACE(" is not expanded...\n");
2774 if (!(wineItem->state & TVIS_EXPANDEDONCE))
2776 TRACE(" and has never been expanded...\n");
2777 wineItem->state |= TVIS_EXPANDED;
2779 /* this item has never been expanded */
2780 if (TREEVIEW_SendTreeviewNotify (
2787 TRACE(" TVN_ITEMEXPANDINGA returned TRUE, exiting...\n");
2792 * Since the TVN_ITEMEXPANDINGA message may has caused the parent to
2793 * insert new items which in turn may have cause items placeholder
2794 * reallocation, I reassign the current item pointer so we have
2795 * something valid to work with...
2796 * However, this should not be necessary,
2797 * investigation required in TREEVIEW_InsertItemA
2799 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2803 "Catastropic situation, cannot retreive item #%d\n",
2808 wineItem->state |= TVIS_EXPANDEDONCE;
2809 TRACE(" TVN_ITEMEXPANDINGA sent...\n");
2811 TREEVIEW_SendTreeviewNotify (
2818 TRACE(" TVN_ITEMEXPANDEDA sent...\n");
2823 /* this item has already been expanded */
2824 wineItem->state |= TVIS_EXPANDED;
2828 case TVE_EXPANDPARTIAL:
2829 TRACE(" case TVE_EXPANDPARTIAL\n");
2830 FIXME("TVE_EXPANDPARTIAL not implemented\n");
2831 wineItem->state ^=TVIS_EXPANDED;
2832 wineItem->state |=TVIS_EXPANDEDONCE;
2836 TRACE("Exiting, Item %d state is now %d...\n",
2840 TREEVIEW_QueueRefresh (hwnd);
2846 static TREEVIEW_ITEM *
2847 TREEVIEW_HitTestPoint (HWND hwnd, POINT pt)
2849 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2850 TREEVIEW_ITEM *wineItem;
2853 GetClientRect (hwnd, &rect);
2855 if (!infoPtr->firstVisible) return NULL;
2857 wineItem=&infoPtr->items [(INT)infoPtr->firstVisible];
2859 while ((wineItem!=NULL) && (pt.y > wineItem->rect.bottom))
2860 wineItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
2872 TREEVIEW_HitTest (HWND hwnd, LPARAM lParam)
2874 LPTVHITTESTINFO lpht=(LPTVHITTESTINFO) lParam;
2875 TREEVIEW_ITEM *wineItem;
2879 GetClientRect (hwnd, &rect);
2883 if (x < rect.left) status|=TVHT_TOLEFT;
2884 if (x > rect.right) status|=TVHT_TORIGHT;
2885 if (y < rect.top ) status|=TVHT_ABOVE;
2886 if (y > rect.bottom) status|=TVHT_BELOW;
2893 wineItem=TREEVIEW_HitTestPoint (hwnd, lpht->pt);
2895 lpht->flags=TVHT_NOWHERE;
2901 if (x < wineItem->expandBox.left) {
2902 lpht->flags |= TVHT_ONITEMINDENT;
2905 if ( PtInRect ( &wineItem->expandBox, lpht->pt)) {
2906 lpht->flags |= TVHT_ONITEMBUTTON;
2909 if ( PtInRect ( &wineItem->bitmap, lpht->pt)) {
2910 lpht->flags |= TVHT_ONITEMICON;
2913 if ( PtInRect ( &wineItem->statebitmap, lpht->pt)) {
2914 lpht->flags |= TVHT_ONITEMSTATEICON;
2917 if ( PtInRect ( &wineItem->text, lpht->pt)) {
2918 lpht->flags |= TVHT_ONITEMLABEL;
2922 lpht->flags|=TVHT_ONITEMRIGHT;
2926 lpht->hItem=wineItem->hItem;
2927 TRACE ("(%ld,%ld):result %x\n",lpht->pt.x,lpht->pt.y,lpht->flags);
2929 return (LRESULT) wineItem->hItem;
2933 TREEVIEW_EditLabelA (HWND hwnd, WPARAM wParam, LPARAM lParam)
2935 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2936 TREEVIEW_ITEM *wineItem;
2939 * If the style allow editing...
2941 if ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_EDITLABELS )
2944 if ( infoPtr->editItem == 0 ) /* If we are not curently editing */
2946 wineItem = TREEVIEW_ValidItem(infoPtr,(HTREEITEM) lParam);
2947 if ( wineItem == NULL )
2949 ERR("Cannot get valid TREEVIEW_ITEM for lParam\n");
2953 TRACE("Edit started for %s.\n", wineItem->pszText);
2954 infoPtr->editItem = wineItem->hItem;
2958 * It is common practice for a windows program to get this
2959 * edit control and then subclass it. It is assumed that a
2960 * new edit control is given every time.
2962 * As a result some programs really mess up the edit control
2963 * so we need to destory our old edit control and create a new
2964 * one. Recycling would be nice but we would need to reset
2965 * everything. So recreating may just be easyier
2968 DestroyWindow(infoPtr->hwndEdit);
2969 infoPtr->hwndEdit = CreateWindowExA (
2973 WS_CHILD | WS_BORDER | ES_AUTOHSCROLL |
2974 ES_WANTRETURN | ES_LEFT,
2977 0,0,0); /* FIXME: (HMENU)IDTVEDIT,pcs->hInstance,0);*/
2982 (LONG) TREEVIEW_Edit_SubclassProc);
2985 SendMessageA ( infoPtr->hwndEdit, WM_SETFONT, infoPtr->hFont, FALSE);
2987 SetWindowTextA( infoPtr->hwndEdit, wineItem->pszText );
2988 SendMessageA ( infoPtr->hwndEdit, EM_SETSEL, 0, -1 );
2991 ** NOTE: this must be after the edit control is created
2992 ** (according to TVN_BEGINLABELEDITA docs), before position is set.
2994 if ( TREEVIEW_SendDispInfoNotify( /* Return true to cancel edition */
2997 TVN_BEGINLABELEDITA,
3001 ** FIXME: Is this right, should we return a handle even though edit was cancelled?
3003 TRACE("Edit cancelled by TVN_BEGINLABELEDITA for %s.\n", wineItem->pszText);
3005 TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)TRUE, 0);
3013 wineItem->text.left - 2,
3014 wineItem->text.top - 1,
3015 wineItem->text.right - wineItem->text.left + 20 ,
3016 wineItem->text.bottom - wineItem->text.top + 3,
3019 SetFocus ( infoPtr->hwndEdit);
3020 ShowWindow ( infoPtr->hwndEdit, SW_SHOW);
3026 ** return NULL since we cannot edit this.
3032 return infoPtr->hwndEdit;
3036 TREEVIEW_EndEditLabelNow (HWND hwnd, WPARAM wParam, LPARAM lParam)
3038 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3039 TREEVIEW_ITEM *editedItem = TREEVIEW_ValidItem (infoPtr, infoPtr->editItem);
3040 BOOL bRevert = (BOOL)wParam;
3048 ** NOTE: we have to get the new text before calling TVN_ENDLABELEDITA
3049 ** since some apps(eg regedit, win98) validate the text in TVN_ENDLABELEDITA.
3052 oldText = editedItem->pszText;
3054 if ( !bRevert ) /* wParam is set to true to cancel the edition */
3057 iLength = GetWindowTextLengthA( infoPtr->hwndEdit );
3060 WARN("Zero length string for new label(not changing).");
3064 newText = COMCTL32_Alloc( iLength+1 );
3065 if( newText == NULL )
3067 ERR("OutOfMemory, cannot allocate space for label");
3070 GetWindowTextA( infoPtr->hwndEdit, newText, iLength+1);
3079 * notify our parent with the new string(or NULL if wParam==TRUE)
3081 tvdi.hdr.hwndFrom = hwnd;
3082 tvdi.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
3083 tvdi.hdr.code = TVN_ENDLABELEDITA;
3084 tvdi.item.hItem = editedItem->hItem;
3085 tvdi.item.lParam = editedItem->lParam;
3086 tvdi.item.mask = TVIF_TEXT|TVIF_HANDLE|TVIF_PARAM;
3087 tvdi.item.pszText = newText;
3089 if(!SendMessageA ( /* return false to cancel edition */
3092 (WPARAM)tvdi.hdr.idFrom,
3095 if( newText == NULL ) /*we are supposed to ignore the return if (and pszText==NULL), MSDOCs */
3099 if (oldText != LPSTR_TEXTCALLBACKA)
3104 if( newText != NULL )
3105 COMCTL32_Free(newText);
3107 editedItem->pszText=oldText; /* revert back to the old label */
3111 COMCTL32_Free(oldText);
3113 editedItem->pszText=newText; /* use the new label */
3116 else if( newText!=NULL )
3119 ** Is really this necasery? shouldnt an app update its internal data in TVN_ENDLABELEDITA?
3124 * This is a callback string so we need
3125 * to inform the parent that the string
3129 tvdi.hdr.hwndFrom = hwnd;
3130 tvdi.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
3131 tvdi.hdr.code = TVN_SETDISPINFOA;
3132 tvdi.item.mask = TVIF_TEXT;
3133 tvdi.item.pszText = newText;
3138 (WPARAM)tvdi.hdr.idFrom,
3143 COMCTL32_Free(newText);
3147 ShowWindow(infoPtr->hwndEdit, SW_HIDE);
3148 EnableWindow(infoPtr->hwndEdit, FALSE);
3150 /* update the window to eliminate fragments and the like */
3151 TreeView_GetItemRect(hwnd,infoPtr->editItem,&itemRect,FALSE);
3152 RedrawWindow(hwnd,&itemRect,NULL,RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW);
3154 infoPtr->editItem = 0;
3156 return !bRevert; /* return true if label edit succesful, otherwise false */
3162 TREEVIEW_LButtonDoubleClick (HWND hwnd, WPARAM wParam, LPARAM lParam)
3164 TREEVIEW_ITEM *wineItem;
3168 pt.x = (INT)LOWORD(lParam);
3169 pt.y = (INT)HIWORD(lParam);
3172 wineItem=TREEVIEW_HitTestPoint (hwnd, pt);
3173 if (!wineItem) return 0;
3174 TRACE("item %d \n",(INT)wineItem->hItem);
3176 if (TREEVIEW_SendSimpleNotify (hwnd, NM_DBLCLK)!=TRUE) { /* FIXME!*/
3177 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) wineItem->hItem);
3184 TREEVIEW_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
3186 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3190 ht.pt.x = (INT)LOWORD(lParam);
3191 ht.pt.y = (INT)HIWORD(lParam);
3194 iItem=TREEVIEW_HitTest (hwnd, (LPARAM) &ht);
3195 TRACE("item %d \n",iItem);
3197 if (ht.flags & TVHT_ONITEMBUTTON) {
3198 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) iItem);
3202 infoPtr->uInternalStatus|=TV_LDRAG;
3209 TREEVIEW_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
3211 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3213 TREEVIEW_ITEM *wineItem;
3215 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
3217 ht.pt.x = (INT)LOWORD(lParam);
3218 ht.pt.y = (INT)HIWORD(lParam);
3222 /* Return true to cancel default behaviour */
3223 if ( TREEVIEW_SendSimpleNotify (hwnd, NM_CLICK) )
3227 iItem = TREEVIEW_HitTest (hwnd, (LPARAM) &ht);
3228 TRACE ("%d\n",iItem);
3232 wineItem = TREEVIEW_ValidItem(infoPtr, (HTREEITEM)iItem);
3235 * if we are TVS_SINGLEEXPAND then we want this single click to
3236 * do a bunch of things.
3238 if ((dwStyle & TVS_SINGLEEXPAND)&&
3239 ( ht.flags & (TVHT_ONITEMLABEL | TVHT_ONITEMICON))&&
3240 ( infoPtr->editItem == 0 ))
3242 TREEVIEW_ITEM *SelItem;
3244 * Send the notification
3246 TREEVIEW_SendTreeviewNotify (hwnd,TVN_SINGLEEXPAND,0,
3247 (HTREEITEM)iItem,0);
3249 * Close the previous selection all the way to the root
3250 * as long as the new selection is not a child
3253 if ((infoPtr->selectedItem)&&(infoPtr->selectedItem != (HTREEITEM)iItem))
3255 BOOL closeit = TRUE;
3258 while (closeit && SelItem)
3260 closeit = (SelItem->hItem != infoPtr->selectedItem);
3261 SelItem = TREEVIEW_ValidItem(infoPtr,SelItem->parent);
3266 SelItem = TREEVIEW_ValidItem(infoPtr,infoPtr->selectedItem);
3267 while ((SelItem)&&(SelItem->hItem != wineItem->hItem))
3269 TREEVIEW_Expand (hwnd,(WPARAM)TVE_COLLAPSE,(LPARAM)SelItem->hItem);
3270 SelItem = TREEVIEW_ValidItem(infoPtr,SelItem->parent);
3276 * Expand the current item
3278 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) wineItem->hItem);
3281 infoPtr->uInternalStatus &= ~(TV_LDRAG | TV_LDRAGGING);
3284 * If the style allow editing and the node is already selected
3285 * and the click occured on the item label...
3287 if ( ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_EDITLABELS ) &&
3288 ( wineItem->state & TVIS_SELECTED ) &&
3289 ( ht.flags & TVHT_ONITEMLABEL ))
3291 if ( infoPtr->editItem == 0 ) /* If we are not curently editing */
3293 if( SendMessageA(hwnd, TVM_EDITLABELA, 0, (LPARAM)iItem) == NULL)
3297 else if ( infoPtr->editItem != 0 ) /* If we are curently editing */
3299 TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
3301 else if ( ht.flags & (TVHT_ONITEMLABEL | TVHT_ONITEMICON))
3303 TREEVIEW_DoSelectItem ( hwnd, TVGN_CARET, (HTREEITEM)iItem, TVC_BYMOUSE);
3306 if (ht.flags & TVHT_ONITEMSTATEICON) {
3309 if (dwStyle & TVS_CHECKBOXES) { /* TVS_CHECKBOXES requires _us_ */
3310 int state; /* to toggle the current state */
3311 state=1-(wineItem->state>>12);
3312 TRACE ("state:%x\n", state);
3313 wineItem->state&= ~TVIS_STATEIMAGEMASK;
3314 wineItem->state|=state<<12;
3315 TRACE ("state:%x\n", wineItem->state);
3316 TREEVIEW_QueueRefresh (hwnd);
3324 TREEVIEW_RButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
3326 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3329 infoPtr->uInternalStatus|=TV_RDRAG;
3334 TREEVIEW_RButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
3336 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3339 if (TREEVIEW_SendSimpleNotify (hwnd, NM_RCLICK)) return 0;
3340 infoPtr->uInternalStatus&= ~(TV_RDRAG | TV_RDRAGGING);
3346 TREEVIEW_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
3348 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3349 TREEVIEW_ITEM *hotItem;
3352 pt.x=(INT) LOWORD (lParam);
3353 pt.y=(INT) HIWORD (lParam);
3354 hotItem=TREEVIEW_HitTestPoint (hwnd, pt);
3355 if (!hotItem) return 0;
3356 infoPtr->focusItem=hotItem->hItem;
3358 if ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_DISABLEDRAGDROP) return 0;
3360 if (infoPtr->uInternalStatus & TV_LDRAG) {
3361 TREEVIEW_SendTreeviewDnDNotify (hwnd, TVN_BEGINDRAGA, hotItem->hItem, pt);
3362 infoPtr->uInternalStatus &= ~TV_LDRAG;
3363 infoPtr->uInternalStatus |= TV_LDRAGGING;
3364 infoPtr->dropItem=hotItem->hItem;
3368 if (infoPtr->uInternalStatus & TV_RDRAG) {
3369 TREEVIEW_SendTreeviewDnDNotify (hwnd, TVN_BEGINRDRAGA, hotItem->hItem, pt);
3370 infoPtr->uInternalStatus &= ~TV_RDRAG;
3371 infoPtr->uInternalStatus |= TV_RDRAGGING;
3372 infoPtr->dropItem=hotItem->hItem;
3381 TREEVIEW_CreateDragImage (HWND hwnd, WPARAM wParam, LPARAM lParam)
3383 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3384 TREEVIEW_ITEM *dragItem;
3388 HBITMAP hbmp,hOldbmp;
3395 if (!(infoPtr->himlNormal)) return 0;
3396 dragItem=TREEVIEW_ValidItem (infoPtr, (HTREEITEM) lParam);
3398 if (!dragItem) return 0;
3400 if (dragItem->pszText==LPSTR_TEXTCALLBACKA) {
3401 TREEVIEW_SendDispInfoNotify (hwnd, dragItem, TVN_GETDISPINFOA, TVIF_TEXT);
3403 itemtxt=dragItem->pszText;
3405 hwtop=GetDesktopWindow ();
3406 htopdc= GetDC (hwtop);
3407 hdc=CreateCompatibleDC (htopdc);
3409 hOldFont=SelectObject (hdc, infoPtr->hFont);
3410 GetTextExtentPoint32A (hdc, itemtxt, lstrlenA (itemtxt), &size);
3411 TRACE("%d %d %s %d\n",size.cx,size.cy,itemtxt,lstrlenA(itemtxt));
3412 hbmp=CreateCompatibleBitmap (htopdc, size.cx, size.cy);
3413 hOldbmp=SelectObject (hdc, hbmp);
3415 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &cy);
3417 if (cy>size.cy) size.cy=cy;
3419 infoPtr->dragList=ImageList_Create (size.cx, size.cy, ILC_COLOR, 10, 10);
3420 ImageList_Draw (infoPtr->himlNormal, dragItem->iImage, hdc, 0, 0, ILD_NORMAL);
3423 ImageList_GetImageInfo (infoPtr->himlNormal, dragItem->hItem, &iminfo);
3424 ImageList_AddMasked (infoPtr->dragList, iminfo.hbmImage, CLR_DEFAULT);
3427 /* draw item text */
3429 SetRect (&rc, cx, 0, size.cx,size.cy);
3430 DrawTextA (hdc, itemtxt, lstrlenA (itemtxt), &rc, DT_LEFT);
3431 SelectObject (hdc, hOldFont);
3432 SelectObject (hdc, hOldbmp);
3434 ImageList_Add (infoPtr->dragList, hbmp, 0);
3437 DeleteObject (hbmp);
3438 ReleaseDC (hwtop, htopdc);
3440 return (LRESULT)infoPtr->dragList;
3445 TREEVIEW_DoSelectItem (HWND hwnd, INT action, HTREEITEM newSelect, INT cause)
3448 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3449 TREEVIEW_ITEM *prevItem,*wineItem;
3452 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)newSelect);
3454 TRACE("Entering item %d, flag %x, cause %x, state %d\n",
3460 if ( (wineItem) && (wineItem->parent))
3463 * If the item has a collapse parent expand the parent so he
3464 * can expose the item
3466 TREEVIEW_ITEM *parentItem = TREEVIEW_ValidItem (infoPtr, wineItem->parent);
3467 if ( !(parentItem->state & TVIS_EXPANDED))
3468 TREEVIEW_Expand (hwnd, TVE_EXPAND, (LPARAM) wineItem->parent);
3474 prevSelect=(INT)infoPtr->selectedItem;
3476 if ((HTREEITEM)prevSelect==newSelect)
3479 prevItem= TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect);
3482 if (TREEVIEW_SendTreeviewNotify(
3486 (HTREEITEM)prevSelect,
3487 (HTREEITEM)newSelect))
3488 return FALSE; /* FIXME: OK? */
3491 prevItem->state &= ~TVIS_SELECTED;
3493 wineItem->state |= TVIS_SELECTED;
3495 infoPtr->selectedItem=(HTREEITEM)newSelect;
3497 TREEVIEW_SendTreeviewNotify(
3501 (HTREEITEM)prevSelect,
3502 (HTREEITEM)newSelect);
3506 case TVGN_DROPHILITE:
3507 prevItem= TREEVIEW_ValidItem (infoPtr, infoPtr->dropItem);
3510 prevItem->state &= ~TVIS_DROPHILITED;
3512 infoPtr->dropItem=(HTREEITEM)newSelect;
3515 wineItem->state |=TVIS_DROPHILITED;
3519 case TVGN_FIRSTVISIBLE:
3520 FIXME("FIRSTVISIBLE not implemented\n");
3524 TREEVIEW_QueueRefresh (hwnd);
3526 TRACE("Leaving state %d\n", wineItem->state);
3530 /* FIXME: handle NM_KILLFocus etc */
3532 TREEVIEW_SelectItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
3535 return TREEVIEW_DoSelectItem (hwnd, wParam, (HTREEITEM) lParam, TVC_UNKNOWN);
3542 TREEVIEW_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
3545 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3547 TRACE("%x\n",infoPtr->hFont);
3548 return infoPtr->hFont;
3552 TREEVIEW_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
3555 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3558 HFONT hFont, hOldFont;
3562 TRACE("%x %lx\n",wParam, lParam);
3564 infoPtr->hFont = (HFONT)wParam;
3566 hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
3568 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
3569 logFont.lfWeight=FW_BOLD;
3570 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
3573 hOldFont = SelectObject (hdc, hFont);
3574 GetTextMetricsA (hdc, &tm);
3575 height= tm.tmHeight + tm.tmExternalLeading;
3576 if (height>infoPtr->uRealItemHeight)
3577 infoPtr->uRealItemHeight=height;
3578 SelectObject (hdc, hOldFont);
3582 TREEVIEW_QueueRefresh (hwnd);
3590 TREEVIEW_VScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
3593 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3596 TRACE("wp %x, lp %lx\n", wParam, lParam);
3597 if (!infoPtr->uInternalStatus & TV_VSCROLL) return FALSE;
3599 switch (LOWORD (wParam)) {
3601 if (!infoPtr->cy) return FALSE;
3602 infoPtr->cy -= infoPtr->uRealItemHeight;
3603 if (infoPtr->cy < 0) infoPtr->cy=0;
3606 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3607 if (infoPtr->cy == maxHeight) return FALSE;
3608 infoPtr->cy += infoPtr->uRealItemHeight;
3609 if (infoPtr->cy > maxHeight)
3610 infoPtr->cy = maxHeight;
3613 if (!infoPtr->cy) return FALSE;
3614 infoPtr->cy -= infoPtr->uVisibleHeight;
3615 if (infoPtr->cy < 0) infoPtr->cy=0;
3618 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3619 if (infoPtr->cy == maxHeight) return FALSE;
3620 infoPtr->cy += infoPtr->uVisibleHeight;
3621 if (infoPtr->cy > maxHeight)
3622 infoPtr->cy = maxHeight;
3625 infoPtr->cy = HIWORD (wParam);
3630 TREEVIEW_QueueRefresh (hwnd);
3635 TREEVIEW_HScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
3637 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3640 TRACE("wp %lx, lp %x\n", lParam, wParam);
3642 if (!infoPtr->uInternalStatus & TV_HSCROLL) return FALSE;
3644 switch (LOWORD (wParam)) {
3646 if (!infoPtr->cx) return FALSE;
3647 infoPtr->cx -= infoPtr->uRealItemHeight;
3648 if (infoPtr->cx < 0) infoPtr->cx=0;
3651 maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
3652 if (infoPtr->cx == maxWidth) return FALSE;
3653 infoPtr->cx += infoPtr->uRealItemHeight; /*FIXME */
3654 if (infoPtr->cx > maxWidth)
3655 infoPtr->cx = maxWidth;
3658 if (!infoPtr->cx) return FALSE;
3659 infoPtr->cx -= infoPtr->uVisibleWidth;
3660 if (infoPtr->cx < 0) infoPtr->cx=0;
3663 maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
3664 if (infoPtr->cx == maxWidth) return FALSE;
3665 infoPtr->cx += infoPtr->uVisibleWidth;
3666 if (infoPtr->cx > maxWidth)
3667 infoPtr->cx = maxWidth;
3670 infoPtr->cx = HIWORD (wParam);
3675 TREEVIEW_QueueRefresh (hwnd);
3679 static LRESULT TREEVIEW_MouseWheel (HWND hwnd, WPARAM wParam, LPARAM lParam)
3682 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3683 short gcWheelDelta = 0;
3684 UINT pulScrollLines = 3;
3686 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
3688 gcWheelDelta -= (short) HIWORD(wParam);
3689 pulScrollLines *= (gcWheelDelta / WHEEL_DELTA);
3691 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
3693 int wheelDy = pulScrollLines * infoPtr->uRealItemHeight;
3694 int newDy = infoPtr->cy + wheelDy;
3695 int maxDy = infoPtr->uTotalHeight - infoPtr->uVisibleHeight;
3697 if (newDy > maxDy) newDy = maxDy;
3698 if (newDy < 0) newDy = 0;
3700 if (newDy == infoPtr->cy) return TRUE;
3702 TREEVIEW_VScroll(hwnd, MAKEWPARAM(SB_THUMBTRACK,newDy),0);
3708 TREEVIEW_KeyDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
3710 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3711 HTREEITEM hNewSelection = 0;
3712 INT scrollNeeds = -1;
3713 INT cyChangeNeeds = -1;
3714 INT prevSelect = (INT)infoPtr->selectedItem;
3716 TREEVIEW_ITEM *prevItem =
3717 (prevSelect != 0 ) ?
3718 TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect) :
3721 TREEVIEW_ITEM *newItem = NULL;
3723 TRACE("%x %lx\n",wParam, lParam);
3725 if (prevSelect == 0)
3730 newItem=TREEVIEW_GetPrevListItem (infoPtr, prevItem);
3733 newItem=& infoPtr->items[(INT)infoPtr->TopRootItem];
3735 hNewSelection = newItem->hItem;
3737 if (! newItem->visible)
3738 scrollNeeds = SB_LINEUP;
3742 newItem=TREEVIEW_GetNextListItem (infoPtr, prevItem);
3747 hNewSelection = newItem->hItem;
3749 if (! newItem->visible)
3750 scrollNeeds = SB_LINEDOWN;
3755 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem];
3756 hNewSelection = newItem->hItem;
3761 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem];
3762 newItem = TREEVIEW_GetLastListItem (infoPtr, newItem);
3763 hNewSelection = newItem->hItem;
3765 if (! newItem->visible)
3766 cyChangeNeeds = infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3771 if ( (prevItem->cChildren > 0) && (prevItem->state & TVIS_EXPANDED) )
3773 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect );
3775 else if ((INT)prevItem->parent)
3777 newItem = (& infoPtr->items[(INT)prevItem->parent]);
3778 if (! newItem->visible)
3779 /* FIXME find a way to make this item the first visible... */
3782 hNewSelection = newItem->hItem;
3788 if ( ( prevItem->cChildren > 0) ||
3789 ( prevItem->cChildren == I_CHILDRENCALLBACK))
3791 if (! (prevItem->state & TVIS_EXPANDED))
3792 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect );
3795 newItem = (& infoPtr->items[(INT)prevItem->firstChild]);
3796 hNewSelection = newItem->hItem;
3803 if (! (prevItem->state & TVIS_EXPANDED))
3804 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect );
3808 if (prevItem->state & TVIS_EXPANDED)
3809 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect );
3814 newItem=TREEVIEW_GetListItem(
3817 -1*(TREEVIEW_GetVisibleCount(hwnd,0,0)-3));
3821 hNewSelection = newItem->hItem;
3823 if (! newItem->visible)
3824 scrollNeeds = SB_PAGEUP;
3829 newItem=TREEVIEW_GetListItem(
3832 TREEVIEW_GetVisibleCount(hwnd,0,0)-3);
3837 hNewSelection = newItem->hItem;
3839 if (! newItem->visible)
3840 scrollNeeds = SB_PAGEDOWN;
3849 FIXME("%x not implemented\n", wParam);
3856 This works but does not send notification...
3858 prevItem->state &= ~TVIS_SELECTED;
3859 newItem->state |= TVIS_SELECTED;
3860 infoPtr->selectedItem = hNewSelection;
3861 TREEVIEW_QueueRefresh (hwnd);
3864 if ( TREEVIEW_DoSelectItem(
3867 (HTREEITEM)hNewSelection,
3870 /* If selection change is allowed for the new item, perform scrolling */
3871 if (scrollNeeds != -1)
3872 TREEVIEW_VScroll(hwnd, scrollNeeds, 0);
3874 if (cyChangeNeeds != -1)
3875 infoPtr->cy = cyChangeNeeds;
3877 /* FIXME: Something happen in the load the in the two weeks before
3878 april 1st 1999 which makes this SetFocus mandatory otherwise, the focus
3879 is lost... However the SetFocus should not be required...*/
3890 TREEVIEW_GetScrollTime (HWND hwnd)
3892 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3894 return infoPtr->uScrollTime;
3899 TREEVIEW_SetScrollTime (HWND hwnd, UINT uScrollTime)
3901 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3902 UINT uOldScrollTime = infoPtr->uScrollTime;
3904 infoPtr->uScrollTime = min (uScrollTime, 100);
3906 return uOldScrollTime;
3910 static LRESULT WINAPI
3911 TREEVIEW_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3913 if (uMsg==WM_CREATE)
3914 return TREEVIEW_Create (hwnd, wParam, lParam);
3916 if (!TREEVIEW_GetInfoPtr(hwnd))
3917 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
3921 case TVM_INSERTITEMA:
3922 return TREEVIEW_InsertItemA (hwnd, wParam, lParam);
3924 case TVM_INSERTITEMW:
3925 return TREEVIEW_InsertItemW(hwnd,wParam,lParam);;
3927 case TVM_DELETEITEM:
3928 return TREEVIEW_DeleteItem (hwnd, wParam, lParam);
3931 return TREEVIEW_Expand (hwnd, wParam, lParam);
3933 case TVM_GETITEMRECT:
3934 return TREEVIEW_GetItemRect (hwnd, wParam, lParam);
3937 return TREEVIEW_GetCount (hwnd, wParam, lParam);
3940 return TREEVIEW_GetIndent (hwnd);
3943 return TREEVIEW_SetIndent (hwnd, wParam);
3945 case TVM_GETIMAGELIST:
3946 return TREEVIEW_GetImageList (hwnd, wParam, lParam);
3948 case TVM_SETIMAGELIST:
3949 return TREEVIEW_SetImageList (hwnd, wParam, lParam);
3951 case TVM_GETNEXTITEM:
3952 return TREEVIEW_GetNextItem (hwnd, wParam, lParam);
3954 case TVM_SELECTITEM:
3955 return TREEVIEW_SelectItem (hwnd, wParam, lParam);
3958 return TREEVIEW_GetItemA (hwnd, wParam, lParam);
3961 FIXME("Unimplemented msg TVM_GETITEMW\n");
3965 return TREEVIEW_SetItemA (hwnd, wParam, lParam);
3968 FIXME("Unimplemented msg TVM_SETITEMW\n");
3971 case TVM_EDITLABELA:
3972 return TREEVIEW_EditLabelA(hwnd, wParam, lParam);
3974 case TVM_EDITLABELW:
3975 FIXME("Unimplemented msg TVM_EDITLABELW \n");
3978 case TVM_GETEDITCONTROL:
3979 return TREEVIEW_GetEditControl (hwnd);
3981 case TVM_GETVISIBLECOUNT:
3982 return TREEVIEW_GetVisibleCount (hwnd, wParam, lParam);
3985 return TREEVIEW_HitTest (hwnd, lParam);
3987 case TVM_CREATEDRAGIMAGE:
3988 return TREEVIEW_CreateDragImage (hwnd, wParam, lParam);
3990 case TVM_SORTCHILDREN:
3991 return TREEVIEW_SortChildren (hwnd, wParam, lParam);
3993 case TVM_ENSUREVISIBLE:
3994 FIXME("Unimplemented msg TVM_ENSUREVISIBLE\n");
3997 case TVM_SORTCHILDRENCB:
3998 return TREEVIEW_SortChildrenCB(hwnd, wParam, lParam);
4000 case TVM_ENDEDITLABELNOW:
4001 return TREEVIEW_EndEditLabelNow (hwnd, wParam, lParam);
4003 case TVM_GETISEARCHSTRINGA:
4004 FIXME("Unimplemented msg TVM_GETISEARCHSTRINGA\n");
4007 case TVM_GETISEARCHSTRINGW:
4008 FIXME("Unimplemented msg TVM_GETISEARCHSTRINGW\n");
4011 case TVM_GETTOOLTIPS:
4012 return TREEVIEW_GetToolTips (hwnd);
4014 case TVM_SETTOOLTIPS:
4015 return TREEVIEW_SetToolTips (hwnd, wParam);
4017 case TVM_SETINSERTMARK:
4018 return TREEVIEW_SetInsertMark (hwnd,wParam, lParam);
4020 case TVM_SETITEMHEIGHT:
4021 return TREEVIEW_SetItemHeight (hwnd, wParam);
4023 case TVM_GETITEMHEIGHT:
4024 return TREEVIEW_GetItemHeight (hwnd);
4026 case TVM_SETBKCOLOR:
4027 return TREEVIEW_SetBkColor (hwnd, wParam, lParam);
4029 case TVM_SETTEXTCOLOR:
4030 return TREEVIEW_SetTextColor (hwnd, wParam, lParam);
4032 case TVM_GETBKCOLOR:
4033 return TREEVIEW_GetBkColor (hwnd);
4035 case TVM_GETTEXTCOLOR:
4036 return TREEVIEW_GetTextColor (hwnd);
4038 case TVM_SETSCROLLTIME:
4039 return TREEVIEW_SetScrollTime (hwnd, (UINT)wParam);
4041 case TVM_GETSCROLLTIME:
4042 return TREEVIEW_GetScrollTime (hwnd);
4044 case TVM_GETITEMSTATE:
4045 return TREEVIEW_GetItemState (hwnd,wParam, lParam);
4047 case TVM_GETLINECOLOR:
4048 return TREEVIEW_GetLineColor (hwnd,wParam, lParam);
4050 case TVM_SETLINECOLOR:
4051 return TREEVIEW_SetLineColor (hwnd,wParam, lParam);
4053 case TVM_SETINSERTMARKCOLOR:
4054 return TREEVIEW_SetInsertMarkColor (hwnd,wParam, lParam);
4056 case TVM_GETINSERTMARKCOLOR:
4057 return TREEVIEW_GetInsertMarkColor (hwnd,wParam, lParam);
4059 case TVM_SETUNICODEFORMAT:
4060 FIXME("Unimplemented msg TVM_SETUNICODEFORMAT\n");
4063 case TVM_GETUNICODEFORMAT:
4064 FIXME("Unimplemented msg TVM_GETUNICODEFORMAT\n");
4068 return TREEVIEW_Command (hwnd, wParam, lParam);
4071 return TREEVIEW_Destroy (hwnd);
4073 /* case WM_ENABLE: */
4076 return TREEVIEW_EraseBackground (hwnd, wParam, lParam);
4079 return DLGC_WANTARROWS | DLGC_WANTCHARS;
4082 return TREEVIEW_Paint (hwnd, wParam, lParam);
4085 return TREEVIEW_GetFont (hwnd, wParam, lParam);
4088 return TREEVIEW_SetFont (hwnd, wParam, lParam);
4091 return TREEVIEW_KeyDown (hwnd, wParam, lParam);
4094 return TREEVIEW_SetFocus (hwnd, wParam, lParam);
4097 return TREEVIEW_KillFocus (hwnd, wParam, lParam);
4099 case WM_LBUTTONDOWN:
4100 return TREEVIEW_LButtonDown (hwnd, wParam, lParam);
4103 return TREEVIEW_LButtonUp (hwnd, wParam, lParam);
4105 case WM_LBUTTONDBLCLK:
4106 return TREEVIEW_LButtonDoubleClick (hwnd, wParam, lParam);
4108 case WM_RBUTTONDOWN:
4109 return TREEVIEW_RButtonDown (hwnd, wParam, lParam);
4112 return TREEVIEW_RButtonUp (hwnd, wParam, lParam);
4115 return TREEVIEW_MouseMove (hwnd, wParam, lParam);
4117 case WM_STYLECHANGED:
4118 return TREEVIEW_StyleChanged (hwnd, wParam, lParam);
4120 /* case WM_SYSCOLORCHANGE: */
4121 /* case WM_SETREDRAW: */
4124 return TREEVIEW_HandleTimer (hwnd, wParam, lParam);
4127 return TREEVIEW_Size (hwnd, wParam,lParam);
4130 return TREEVIEW_HScroll (hwnd, wParam, lParam);
4132 return TREEVIEW_VScroll (hwnd, wParam, lParam);
4135 if (wParam & (MK_SHIFT | MK_CONTROL))
4136 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
4137 return TREEVIEW_MouseWheel (hwnd, wParam, lParam);
4140 TRACE ("drawItem\n");
4141 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
4144 if (uMsg >= WM_USER)
4145 FIXME("Unknown msg %04x wp=%08x lp=%08lx\n",
4146 uMsg, wParam, lParam);
4147 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
4154 TREEVIEW_Register (void)
4160 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
4161 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
4162 wndClass.lpfnWndProc = (WNDPROC)TREEVIEW_WindowProc;
4163 wndClass.cbClsExtra = 0;
4164 wndClass.cbWndExtra = sizeof(TREEVIEW_INFO *);
4165 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
4166 wndClass.hbrBackground = 0;
4167 wndClass.lpszClassName = WC_TREEVIEWA;
4169 RegisterClassA (&wndClass);
4174 TREEVIEW_Unregister (void)
4176 UnregisterClassA (WC_TREEVIEWA, (HINSTANCE)NULL);