3 * Copyright 1998 Eric Kohl <ekohl@abo.rhein-zeitung.de>
4 * Copyright 1998,1999 Alex Priem <alexp@sci.kun.nl>
5 * Copyright 1999 Sylvain St-Germain
9 * Using DPA to store the item ptr would be good.
10 * Node label edition is implemented but something appened in wine in the
11 * two last weeks of march 99 that broke it.
13 -small array containing info about positions.
14 -better implementation of RefreshItem:
15 1) draw lines between parents
17 3) draw lines from parent<->items.
18 -implement partial drawing?
19 * -drag&drop: TVM_CREATEDRAGIMAGE should create drag bitmap.
20 * -scrollbars: horizontal scrollbar doesn't work.
24 * FIXME: check fontsize. (uRealItemHeight)
25 * test focusItem (redraw in different color)
28 better implementation.
29 * WM_HSCROLL is broken.
30 * use separate routine to get item text/image.
32 * Separate drawing/calculation.
34 * FIXMEs (for personal use)
35 Expand: -ctlmacro expands twice ->toggle.
36 -DblClick: ctlmacro.exe's NM_DBLCLK seems to go wrong (returns FALSE).
37 -treehelper: stack corruption makes big window.
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_EndEditLabelNow (HWND hwnd, WPARAM wParam, LPARAM lParam);
97 /* helper functions. Work with the assumption that validity of operands
98 is checked beforehand, and that tree state is valid. */
100 /* FIXME: MS documentation says `GetNextVisibleItem' returns NULL
101 if not successfull. Probably only applies to dereferencing infoPtr
102 (i.e. we are offered a valid treeview structure)
103 and not whether there is a next `visible' child.
104 FIXME: check other failures.
107 /***************************************************************************
108 * This method returns the TREEVIEW_ITEM object given the handle
110 static TREEVIEW_ITEM* TREEVIEW_ValidItem(
111 TREEVIEW_INFO *infoPtr,
114 if ((!handle) || (handle>infoPtr->uMaxHandle))
117 if (tv_test_bit ((INT)handle, infoPtr->freeList))
120 return &infoPtr->items[(INT)handle];
123 /***************************************************************************
124 * This method returns the last expanded child item of a tree node
126 static TREEVIEW_ITEM *TREEVIEW_GetLastListItem(
127 TREEVIEW_INFO *infoPtr,
128 TREEVIEW_ITEM *tvItem)
130 TREEVIEW_ITEM *wineItem = tvItem;
133 * Get this item last sibling
135 while (wineItem->sibling)
136 wineItem=& infoPtr->items [(INT)wineItem->sibling];
139 * If the last sibling has expanded children, restart.
141 if ( ( wineItem->cChildren > 0 ) && ( wineItem->state & TVIS_EXPANDED) )
142 return TREEVIEW_GetLastListItem(
144 &(infoPtr->items[(INT)wineItem->firstChild]));
149 /***************************************************************************
150 * This method returns the previous physical item in the list not
151 * considering the tree hierarchy.
153 static TREEVIEW_ITEM *TREEVIEW_GetPrevListItem(
154 TREEVIEW_INFO *infoPtr,
155 TREEVIEW_ITEM *tvItem)
157 if (tvItem->upsibling)
160 * This item has a upsibling, get the last item. Since, GetLastListItem
161 * first looks at siblings, we must feed it with the first child.
163 TREEVIEW_ITEM *upItem = &infoPtr->items[(INT)tvItem->upsibling];
165 if ( ( upItem->cChildren > 0 ) && ( upItem->state & TVIS_EXPANDED) )
166 return TREEVIEW_GetLastListItem(
168 &infoPtr->items[(INT)upItem->firstChild]);
175 * this item does not have a upsibling, get the parent
178 return &infoPtr->items[(INT)tvItem->parent];
185 /***************************************************************************
186 * This method returns the next physical item in the treeview not
187 * considering the tree hierarchy.
189 static TREEVIEW_ITEM *TREEVIEW_GetNextListItem(
190 TREEVIEW_INFO *infoPtr,
191 TREEVIEW_ITEM *tvItem)
193 TREEVIEW_ITEM *wineItem = NULL;
196 * If this item has children and is expanded, return the first child
198 if ((tvItem->firstChild) && (tvItem->state & TVIS_EXPANDED))
199 return (& infoPtr->items[(INT)tvItem->firstChild]);
203 * try to get the sibling
206 return (& infoPtr->items[(INT)tvItem->sibling]);
209 * Otherwise, get the parent's sibling.
212 while (wineItem->parent) {
213 wineItem=& infoPtr->items [(INT)wineItem->parent];
214 if (wineItem->sibling)
215 return (& infoPtr->items [(INT)wineItem->sibling]);
221 /***************************************************************************
222 * This method returns the nth item starting at the given item. It returns
223 * the last item (or first) we we run out of items.
225 * Will scroll backward if count is <0.
226 * forward if count is >0.
228 static TREEVIEW_ITEM *TREEVIEW_GetListItem(
229 TREEVIEW_INFO *infoPtr,
230 TREEVIEW_ITEM *tvItem,
233 TREEVIEW_ITEM *previousItem = NULL;
234 TREEVIEW_ITEM *wineItem = tvItem;
239 /* Find count item downward */
240 while ((iter++ < count) && (wineItem != NULL))
242 /* Keep a pointer to the previous in case we ask for more than we got */
243 previousItem = wineItem;
244 wineItem = TREEVIEW_GetNextListItem(infoPtr, wineItem);
247 if (wineItem == NULL)
248 wineItem = previousItem;
252 /* Find count item upward */
253 while ((iter-- > count) && (wineItem != NULL))
255 /* Keep a pointer to the previous in case we ask for more than we got */
256 previousItem = wineItem;
257 wineItem = TREEVIEW_GetPrevListItem(infoPtr, wineItem);
260 if (wineItem == NULL)
261 wineItem = previousItem;
270 /***************************************************************************
273 static void TREEVIEW_RemoveAllChildren(
275 TREEVIEW_ITEM *parentItem)
277 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
278 TREEVIEW_ITEM *killItem;
281 kill=(INT)parentItem->firstChild;
283 tv_set_bit ( kill, infoPtr->freeList);
284 killItem=& infoPtr->items[kill];
285 if (killItem->pszText!=LPSTR_TEXTCALLBACKA)
286 COMCTL32_Free (killItem->pszText);
287 TREEVIEW_SendTreeviewNotify (hwnd, TVN_DELETEITEMA, 0, (HTREEITEM)kill, 0);
288 if (killItem->firstChild)
289 TREEVIEW_RemoveAllChildren (hwnd, killItem);
290 kill=(INT)killItem->sibling;
293 if (parentItem->cChildren>0) {
294 infoPtr->uNumItems -= parentItem->cChildren;
295 parentItem->firstChild = 0;
296 parentItem->cChildren = 0;
303 TREEVIEW_RemoveItem (HWND hwnd, TREEVIEW_ITEM *wineItem)
306 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
307 TREEVIEW_ITEM *parentItem, *upsiblingItem, *siblingItem;
310 iItem=(INT)wineItem->hItem;
311 tv_set_bit(iItem,infoPtr->freeList);
312 infoPtr->uNumItems--;
314 if (wineItem->pszText!=LPSTR_TEXTCALLBACKA)
315 COMCTL32_Free (wineItem->pszText);
317 TREEVIEW_SendTreeviewNotify (hwnd, TVN_DELETEITEMA, 0, (HTREEITEM)iItem, 0);
319 if (wineItem->firstChild)
320 TREEVIEW_RemoveAllChildren (hwnd,wineItem);
322 if (wineItem->parent) {
323 parentItem=& infoPtr->items [(INT)wineItem->parent];
324 switch (parentItem->cChildren) {
325 case I_CHILDRENCALLBACK:
326 FIXME("we don't handle I_CHILDRENCALLBACK yet\n");
329 parentItem->cChildren=0;
330 parentItem->firstChild=0;
333 parentItem->cChildren--;
334 if ((INT)parentItem->firstChild==iItem)
335 parentItem->firstChild=wineItem->sibling;
339 if (iItem==(INT)infoPtr->TopRootItem)
340 infoPtr->TopRootItem=(HTREEITEM)wineItem->sibling;
341 if (wineItem->upsibling) {
342 upsiblingItem=& infoPtr->items [(INT)wineItem->upsibling];
343 upsiblingItem->sibling=wineItem->sibling;
345 if (wineItem->sibling) {
346 siblingItem=& infoPtr->items [(INT)wineItem->sibling];
347 siblingItem->upsibling=wineItem->upsibling;
355 /* Note:TREEVIEW_RemoveTree doesn't remove infoPtr itself */
357 static void TREEVIEW_RemoveTree (HWND hwnd)
360 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
361 TREEVIEW_ITEM *killItem;
364 for (i = 1; i <= (INT)infoPtr->uMaxHandle; i++)
365 if (!tv_test_bit (i, infoPtr->freeList)) {
366 killItem = &infoPtr->items[i];
367 if (killItem->pszText != LPSTR_TEXTCALLBACKA)
368 COMCTL32_Free (killItem->pszText);
369 TREEVIEW_SendTreeviewNotify(hwnd, TVN_DELETEITEMA, 0,
372 if (infoPtr->uNumPtrsAlloced) {
373 COMCTL32_Free (infoPtr->items);
374 COMCTL32_Free (infoPtr->freeList);
375 infoPtr->uNumItems = 0;
376 infoPtr->uNumPtrsAlloced = 0;
377 infoPtr->uMaxHandle = 0;
378 infoPtr->TopRootItem = 0;
389 TREEVIEW_GetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
391 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
395 if ((INT)wParam == TVSIL_NORMAL)
396 return (LRESULT) infoPtr->himlNormal;
397 if ((INT)wParam == TVSIL_STATE)
398 return (LRESULT) infoPtr->himlState;
404 TREEVIEW_SetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
406 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
409 TRACE("%x,%lx\n", wParam, lParam);
410 switch ((INT)wParam) {
412 himlTemp = infoPtr->himlNormal;
413 infoPtr->himlNormal = (HIMAGELIST)lParam;
414 return (LRESULT)himlTemp;
417 himlTemp = infoPtr->himlState;
418 infoPtr->himlState = (HIMAGELIST)lParam;
419 return (LRESULT)himlTemp;
422 return (LRESULT)NULL;
428 TREEVIEW_SetItemHeight (HWND hwnd, WPARAM wParam)
430 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
431 INT cx,cy,prevHeight=infoPtr->uItemHeight;
435 infoPtr->uItemHeight=-1;
439 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &cy);
441 if (wParam>cy) cy=wParam;
442 infoPtr->uItemHeight=cy;
444 if (!( GetWindowLongA( hwnd, GWL_STYLE) & TVS_NONEVENHEIGHT))
445 infoPtr->uItemHeight = (INT) wParam & 0xfffffffe;
450 TREEVIEW_GetItemHeight (HWND hwnd)
452 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
455 return infoPtr->uItemHeight;
459 TREEVIEW_GetLineColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
461 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
464 return (LRESULT) infoPtr->clrLine;
468 TREEVIEW_SetLineColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
470 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
471 COLORREF prevColor=infoPtr->clrLine;
474 infoPtr->clrLine=(COLORREF) lParam;
475 return (LRESULT) prevColor;
479 TREEVIEW_GetInsertMarkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
481 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
484 return (LRESULT) infoPtr->clrInsertMark;
488 TREEVIEW_SetInsertMarkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
490 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
491 COLORREF prevColor=infoPtr->clrInsertMark;
493 TRACE("%d %ld\n",wParam,lParam);
494 infoPtr->clrInsertMark=(COLORREF) lParam;
495 return (LRESULT) prevColor;
499 TREEVIEW_SetInsertMark (HWND hwnd, WPARAM wParam, LPARAM lParam)
501 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
504 FIXME("%d %ld\n",wParam,lParam);
505 if (!TREEVIEW_ValidItem (infoPtr, (HTREEITEM)lParam)) return 0;
506 FIXME("%d %ld\n",wParam,lParam);
508 infoPtr->insertBeforeorAfter=(BOOL) wParam;
509 infoPtr->insertMarkItem=(HTREEITEM) lParam;
512 TREEVIEW_Refresh (hwnd, hdc);
519 TREEVIEW_SetTextColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
521 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
522 COLORREF prevColor=infoPtr->clrText;
525 infoPtr->clrText=(COLORREF) lParam;
526 return (LRESULT) prevColor;
530 TREEVIEW_GetBkColor (HWND hwnd)
532 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
535 return (LRESULT) infoPtr->clrBk;
539 TREEVIEW_SetBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
541 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
542 COLORREF prevColor=infoPtr->clrBk;
545 infoPtr->clrBk=(COLORREF) lParam;
546 return (LRESULT) prevColor;
550 TREEVIEW_GetTextColor (HWND hwnd)
552 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
555 return (LRESULT) infoPtr->clrText;
559 /* cdmode: custom draw mode as received from app. in first NMCUSTOMDRAW
562 #define TREEVIEW_LEFT_MARGIN 8
566 TREEVIEW_DrawItem (HWND hwnd, HDC hdc, TREEVIEW_ITEM *wineItem)
568 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
569 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
570 INT center,xpos,cx,cy, cditem;
572 UINT uTextJustify = DT_LEFT;
576 if (wineItem->state & TVIS_BOLD)
577 hOldFont = SelectObject (hdc, infoPtr->hBoldFont);
579 hOldFont = SelectObject (hdc, infoPtr->hFont);
582 TRACE ("cdmode:%x\n",infoPtr->cdmode);
583 if (infoPtr->cdmode & CDRF_NOTIFYITEMDRAW) {
584 cditem=TREEVIEW_SendCustomDrawItemNotify
585 (hwnd, hdc, wineItem, CDDS_ITEMPREPAINT);
586 TRACE("prepaint:cditem-app returns 0x%x\n",cditem);
588 if (cditem & CDRF_SKIPDEFAULT)
593 * Set drawing starting points
595 r = wineItem->rect; /* this item rectangle */
596 center = (r.top+r.bottom)/2; /* this item vertical center */
597 xpos = r.left + TREEVIEW_LEFT_MARGIN;/* horizontal starting point */
600 * Display the tree hierarchy
602 if ( dwStyle & TVS_HASLINES)
605 * Write links to parent node
606 * we draw the L starting from the child to the parent
608 * points[0] is attached to the current item
609 * points[1] is the L corner
610 * points[2] is attached to the parent or the up sibling
612 if ( dwStyle & TVS_LINESATROOT)
614 TREEVIEW_ITEM *upNode = NULL;
615 BOOL hasParentOrSibling = TRUE;
616 RECT upRect = {0,0,0,0};
617 HPEN hOldPen, hNewPen;
620 * determine the target location of the line at root, either be linked
621 * to the up sibling or to the parent node.
623 if (wineItem->upsibling)
624 upNode = TREEVIEW_ValidItem (infoPtr, wineItem->upsibling);
625 else if (wineItem->parent)
626 upNode = TREEVIEW_ValidItem (infoPtr, wineItem->parent);
628 hasParentOrSibling = FALSE;
631 upRect = upNode->rect;
633 if ( wineItem->iLevel == 0 )
635 points[2].x = points[1].x = upRect.left+8;
636 points[0].x = points[2].x + 10;
637 points[2].y = upRect.bottom-3;
638 points[1].y = points[0].y = center;
642 points[2].x = points[1].x = 8 + (20*wineItem->iLevel);
643 points[2].y = ( upNode->cChildren == 0) ?
644 upRect.top : /* is linked to the "L" above */
645 ( wineItem->upsibling != NULL) ?
646 upRect.bottom-3: /* is linked to an icon */
647 upRect.bottom+1; /* is linked to a +/- box */
648 points[1].y = points[0].y = center;
649 points[0].x = points[1].x + 10;
655 hNewPen = CreatePen(PS_DOT, 0, infoPtr->clrLine);
656 hOldPen = SelectObject( hdc, hNewPen );
658 if (hasParentOrSibling)
659 Polyline (hdc,points,3);
661 Polyline (hdc,points,2);
663 DeleteObject(hNewPen);
664 SelectObject(hdc, hOldPen);
669 * Display the (+/-) signs
671 if (wineItem->iLevel != 0)/* update position only for non root node */
672 xpos+=(5*wineItem->iLevel);
674 if (( dwStyle & TVS_HASBUTTONS) && ( dwStyle & TVS_HASLINES))
676 if ( (wineItem->cChildren) ||
677 (wineItem->cChildren == I_CHILDRENCALLBACK))
679 /* Setup expand box coordinate to facilitate the LMBClick handling */
680 wineItem->expandBox.left = xpos-4;
681 wineItem->expandBox.top = center-4;
682 wineItem->expandBox.right = xpos+5;
683 wineItem->expandBox.bottom = center+5;
687 wineItem->expandBox.left,
688 wineItem->expandBox.top ,
689 wineItem->expandBox.right,
690 wineItem->expandBox.bottom);
692 MoveToEx (hdc, xpos-2, center, NULL);
693 LineTo (hdc, xpos+3, center);
695 if (!(wineItem->state & TVIS_EXPANDED)) {
696 MoveToEx (hdc, xpos, center-2, NULL);
697 LineTo (hdc, xpos, center+3);
703 * Display the image associated with this item
705 xpos += 13; /* update position */
706 if (wineItem->mask & (TVIF_IMAGE|TVIF_SELECTEDIMAGE)) {
708 HIMAGELIST *himlp = NULL;
710 /* State images are displayed to the left of the Normal image
711 * image number is in state; zero should be `display no image'.
712 * FIXME: that last sentence looks like it needs some checking.
714 if (infoPtr->himlState)
715 himlp=&infoPtr->himlState;
716 imageIndex=wineItem->state>>12;
717 imageIndex++; /* yeah, right */
718 TRACE ("imindex:%d\n",imageIndex);
719 if ((himlp) && (imageIndex))
721 imageIndex--; /* see FIXME */
722 ImageList_Draw ( *himlp, imageIndex, hdc, xpos-2, r.top+1, ILD_NORMAL);
723 ImageList_GetIconSize (*himlp, &cx, &cy);
724 wineItem->statebitmap.left=xpos-2;
725 wineItem->statebitmap.right=xpos-2+cx;
726 wineItem->statebitmap.top=r.top+1;
727 wineItem->statebitmap.bottom=r.top+1+cy;
731 /* Now, draw the normal image; can be either selected or
732 * non-selected image.
736 if (infoPtr->himlNormal)
737 himlp=&infoPtr->himlNormal; /* get the image list */
739 imageIndex = wineItem->iImage;
740 if ( (wineItem->state & TVIS_SELECTED) &&
741 (wineItem->iSelectedImage)) {
743 /* The item is curently selected */
744 if (wineItem->iSelectedImage == I_IMAGECALLBACK)
745 TREEVIEW_SendDispInfoNotify
746 (hwnd, wineItem, TVN_GETDISPINFOA, TVIF_SELECTEDIMAGE);
748 imageIndex = wineItem->iSelectedImage;
750 /* The item is not selected */
751 if (wineItem->iImage == I_IMAGECALLBACK)
752 TREEVIEW_SendDispInfoNotify
753 (hwnd, wineItem, TVN_GETDISPINFOA, TVIF_IMAGE);
755 imageIndex = wineItem->iImage;
762 if(wineItem->stateMask & TVIS_OVERLAYMASK)
763 ovlIdx = wineItem->state & TVIS_OVERLAYMASK;
765 ImageList_Draw ( *himlp, imageIndex, hdc, xpos-2, r.top+1, ILD_NORMAL|ovlIdx);
766 ImageList_GetIconSize (*himlp, &cx, &cy);
767 wineItem->bitmap.left=xpos-2;
768 wineItem->bitmap.right=xpos-2+cx;
769 wineItem->bitmap.top=r.top+1;
770 wineItem->bitmap.bottom=r.top+1+cy;
777 * Display the text associated with this item
780 if ((wineItem->mask & TVIF_TEXT) && (wineItem->pszText))
782 COLORREF oldBkColor = 0;
783 COLORREF oldTextColor = 0;
789 wineItem->text.left = r.left;
790 wineItem->text.right = r.right;
791 wineItem->text.top = r.top;
792 wineItem->text.bottom= r.bottom;
794 if (wineItem->pszText== LPSTR_TEXTCALLBACKA) {
795 TRACE("LPSTR_TEXTCALLBACK\n");
796 TREEVIEW_SendDispInfoNotify (hwnd, wineItem, TVN_GETDISPINFOA, TVIF_TEXT);
799 /* Yep, there are some things that need to be straightened out here.
800 Removing the comments around the setTextColor does not give the right
801 results. Dito FillRect.
805 /* GetTextExtentPoint32A (hdc, wineItem->pszText,
806 strlen (wineItem->pszText), &size); */
808 /* FillRect ( hdc, &wineItem->text, GetSysColorBrush (infoPtr->clrBk));
812 if (!(cditem & CDRF_NOTIFYPOSTPAINT) &&
813 (wineItem->state & (TVIS_SELECTED | TVIS_DROPHILITED)) ) {
814 oldBkMode = SetBkMode (hdc, OPAQUE);
815 oldBkColor = SetBkColor (hdc, GetSysColor( COLOR_HIGHLIGHT));
816 oldTextColor = SetTextColor(hdc, GetSysColor( COLOR_HIGHLIGHTTEXT));
818 oldBkMode = SetBkMode (hdc, TRANSPARENT);
819 oldBkColor = SetBkColor (hdc, infoPtr->clrBk);
820 /* oldTextColor = SetTextColor(hdc, infoPtr->clrText); */
828 lstrlenA(wineItem->pszText),
830 uTextJustify | DT_VCENTER | DT_SINGLELINE );
832 /* Obtain the text coordinate */
836 lstrlenA(wineItem->pszText),
838 uTextJustify | DT_VCENTER | DT_SINGLELINE | DT_CALCRECT);
840 /* Restore the hdc state */
841 SetTextColor( hdc, oldTextColor);
843 if (oldBkMode != TRANSPARENT)
844 SetBkMode(hdc, oldBkMode);
845 if (wineItem->state & (TVIS_SELECTED | TVIS_DROPHILITED))
846 SetBkColor (hdc, oldBkColor);
848 /* Draw the box arround the selected item */
849 if (wineItem->state & TVIS_SELECTED )
851 HPEN hNewPen = CreatePen(PS_DOT, 0, GetSysColor(COLOR_WINDOWTEXT) );
852 HPEN hOldPen = SelectObject( hdc, hNewPen );
855 points[0].x = wineItem->text.left-1;
856 points[0].y = wineItem->text.top+1;
857 points[1].x = wineItem->text.right;
858 points[1].y = wineItem->text.top+1;
859 points[2].x = wineItem->text.right;
860 points[2].y = wineItem->text.bottom;
861 points[3].x = wineItem->text.left-1;
862 points[3].y = wineItem->text.bottom;
864 Polyline (hdc,points,4);
866 DeleteObject(hNewPen);
867 SelectObject(hdc, hOldPen);
871 /* Draw insertion mark if necessary */
873 if (infoPtr->insertMarkItem)
874 TRACE ("item:%d,mark:%d\n", (int)wineItem->hItem,
875 (int) infoPtr->insertMarkItem);
876 if (wineItem->hItem==infoPtr->insertMarkItem) {
877 HPEN hNewPen, hOldPen;
880 hNewPen = CreatePen(PS_SOLID, 2, infoPtr->clrInsertMark);
881 hOldPen = SelectObject( hdc, hNewPen );
883 if (infoPtr->insertBeforeorAfter)
884 offset=wineItem->text.top+1;
886 offset=wineItem->text.bottom-1;
888 MoveToEx (hdc, wineItem->text.left, offset-3, NULL);
889 LineTo (hdc, wineItem->text.left, offset+3);
891 MoveToEx (hdc, wineItem->text.left, offset, NULL);
892 LineTo (hdc, r.right-2, offset);
894 MoveToEx (hdc, r.right-2, offset+3, NULL);
895 LineTo (hdc, r.right-2, offset-3);
897 DeleteObject(hNewPen);
899 SelectObject(hdc, hOldPen);
902 if (cditem & CDRF_NOTIFYPOSTPAINT) {
903 cditem=TREEVIEW_SendCustomDrawItemNotify
904 (hwnd, hdc, wineItem, CDDS_ITEMPOSTPAINT);
905 TRACE("postpaint:cditem-app returns 0x%x\n",cditem);
908 SelectObject (hdc, hOldFont);
912 TREEVIEW_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
914 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
915 TREEVIEW_ITEM *wineItem;
917 LPRECT lpRect = (LPRECT)lParam;
922 * validate parameters
927 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
929 TREEVIEW_Refresh (hwnd, hdc); /* we want a rect for the current view */
935 * retrieve the item ptr
937 iItem = (HTREEITEM *) lParam;
938 wineItem = TREEVIEW_ValidItem (infoPtr, *iItem);
939 if ((!wineItem) || (!wineItem->visible))
943 * If wParam is TRUE return the text size otherwise return
944 * the whole item size
947 lpRect->left = wineItem->text.left;
948 lpRect->right = wineItem->text.right;
949 lpRect->bottom = wineItem->text.bottom;
950 lpRect->top = wineItem->text.top;
952 lpRect->left = wineItem->rect.left;
953 lpRect->right = wineItem->rect.right;
954 lpRect->bottom = wineItem->rect.bottom;
955 lpRect->top = wineItem->rect.top;
958 TRACE("[L:%d R:%d T:%d B:%d]\n",
959 lpRect->left,lpRect->right,
960 lpRect->top,lpRect->bottom);
966 TREEVIEW_GetVisibleCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
969 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
971 return (LRESULT) infoPtr->uVisibleHeight / infoPtr->uRealItemHeight;
977 TREEVIEW_SetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
979 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
980 TREEVIEW_ITEM *wineItem;
984 tvItem=(LPTVITEMEXA) lParam;
985 iItem=(INT)tvItem->hItem;
986 TRACE("item %d,mask %x\n",iItem,tvItem->mask);
988 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
989 if (!wineItem) return FALSE;
991 if (tvItem->mask & TVIF_CHILDREN) {
992 wineItem->cChildren=tvItem->cChildren;
995 if (tvItem->mask & TVIF_IMAGE) {
996 wineItem->iImage=tvItem->iImage;
999 if (tvItem->mask & TVIF_INTEGRAL) {
1000 wineItem->iIntegral=tvItem->iIntegral;
1003 if (tvItem->mask & TVIF_PARAM) {
1004 wineItem->lParam=tvItem->lParam;
1007 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
1008 wineItem->iSelectedImage=tvItem->iSelectedImage;
1011 if (tvItem->mask & TVIF_STATE) {
1012 TRACE ("prevstate,state,mask:%x,%x,%x\n",wineItem->state,tvItem->state,
1014 wineItem->state&= ~tvItem->stateMask;
1015 wineItem->state|= (tvItem->state & tvItem->stateMask);
1016 wineItem->stateMask|= tvItem->stateMask;
1019 if (tvItem->mask & TVIF_TEXT) {
1020 if (tvItem->pszText!=LPSTR_TEXTCALLBACKA) {
1021 len=lstrlenA (tvItem->pszText);
1022 if (len>wineItem->cchTextMax)
1023 wineItem->pszText= COMCTL32_ReAlloc (wineItem->pszText, len+1);
1024 lstrcpynA (wineItem->pszText, tvItem->pszText,len+1);
1026 if (wineItem->cchTextMax) {
1027 COMCTL32_Free (wineItem->pszText);
1028 wineItem->cchTextMax=0;
1030 wineItem->pszText=LPSTR_TEXTCALLBACKA;
1034 wineItem->mask |= tvItem->mask;
1040 TREEVIEW_GetItemState (HWND hwnd, WPARAM wParam, LPARAM lParam)
1043 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1044 TREEVIEW_ITEM *wineItem;
1047 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)wParam);
1048 if (!wineItem) return 0;
1050 return (wineItem->state & lParam);
1057 TREEVIEW_Refresh (HWND hwnd, HDC hdc)
1059 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1063 INT iItem, indent, x, y, height, itemHeight;
1064 INT viewtop,viewbottom,viewleft,viewright;
1065 TREEVIEW_ITEM *wineItem, *prevItem;
1070 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
1071 KillTimer (hwnd, TV_REFRESH_TIMER);
1072 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
1076 GetClientRect (hwnd, &rect);
1077 if ((rect.left-rect.right ==0) || (rect.top-rect.bottom==0)) return;
1079 infoPtr->cdmode=TREEVIEW_SendCustomDrawNotify(hwnd,CDDS_PREPAINT,hdc,rect);
1081 if (infoPtr->cdmode==CDRF_SKIPDEFAULT) return;
1083 infoPtr->uVisibleHeight= rect.bottom-rect.top;
1084 infoPtr->uVisibleWidth= rect.right-rect.left;
1086 viewtop=infoPtr->cy;
1087 viewbottom=infoPtr->cy + rect.bottom-rect.top;
1088 viewleft=infoPtr->cx;
1089 viewright=infoPtr->cx + rect.right-rect.left;
1091 TRACE("[%d %d %d %d]\n",viewtop,viewbottom,viewleft,viewright);
1093 /* draw background */
1095 hbrBk = CreateSolidBrush (infoPtr->clrBk);
1096 FillRect(hdc, &rect, hbrBk);
1097 DeleteObject(hbrBk);
1099 ImageList_GetIconSize (infoPtr->himlNormal, &x, &itemHeight);
1100 if (infoPtr->uItemHeight>itemHeight)
1101 itemHeight=infoPtr->uItemHeight;
1103 GetTextMetricsA (hdc, &tm);
1104 if ((tm.tmHeight + tm.tmExternalLeading) > itemHeight)
1105 itemHeight=tm.tmHeight + tm.tmExternalLeading;
1107 infoPtr->uRealItemHeight=itemHeight;
1109 iItem=(INT)infoPtr->TopRootItem;
1110 infoPtr->firstVisible=0;
1117 wineItem= & infoPtr->items[iItem];
1118 wineItem->iLevel=indent;
1120 /* FIXME: remove this in later stage */
1122 if (wineItem->pszText!=LPSTR_TEXTCALLBACK32A)
1123 TRACE (treeview, "%d %d [%d %d %d %d] (%s)\n",y,x,
1124 wineItem->rect.top, wineItem->rect.bottom,
1125 wineItem->rect.left, wineItem->rect.right,
1128 TRACE (treeview, "%d [%d %d %d %d] (CALLBACK)\n",
1130 wineItem->rect.top, wineItem->rect.bottom,
1131 wineItem->rect.left, wineItem->rect.right);
1134 height=itemHeight * wineItem->iIntegral +1;
1135 if ((y >= viewtop) && (y <= viewbottom) &&
1136 (x >= viewleft ) && (x <= viewright)) {
1137 wineItem->visible = TRUE;
1138 wineItem->rect.top = y - infoPtr->cy + rect.top;
1139 wineItem->rect.bottom = wineItem->rect.top + height ;
1140 wineItem->rect.left = x - infoPtr->cx + rect.left;
1141 wineItem->rect.right = rect.right;
1142 if (!infoPtr->firstVisible)
1143 infoPtr->firstVisible=wineItem->hItem;
1144 TREEVIEW_DrawItem (hwnd, hdc, wineItem);
1147 wineItem->visible = FALSE;
1148 wineItem->rect.left = wineItem->rect.top = 0;
1149 wineItem->rect.right= wineItem->rect.bottom = 0;
1150 wineItem->text.left = wineItem->text.top = 0;
1151 wineItem->text.right= wineItem->text.bottom = 0;
1154 /* look up next item */
1156 if ((wineItem->firstChild) && (wineItem->state & TVIS_EXPANDED)) {
1157 iItem=(INT)wineItem->firstChild;
1159 x+=infoPtr->uIndent;
1160 if (x>infoPtr->uTotalWidth)
1161 infoPtr->uTotalWidth=x;
1164 iItem=(INT)wineItem->sibling;
1165 while ((!iItem) && (indent>0)) {
1167 x-=infoPtr->uIndent;
1168 wineItem=&infoPtr->items[(INT)wineItem->parent];
1169 iItem=(INT)wineItem->sibling;
1175 /* FIXME: infoPtr->uTotalWidth should also take item label into account */
1176 /* FIXME: or should query item sizes (ie check CDRF_NEWFONT) */
1178 infoPtr->uTotalHeight=y;
1179 if (y >= (viewbottom-viewtop)) {
1180 if (!(infoPtr->uInternalStatus & TV_VSCROLL))
1181 ShowScrollBar (hwnd, SB_VERT, TRUE);
1182 infoPtr->uInternalStatus |=TV_VSCROLL;
1183 SetScrollRange (hwnd, SB_VERT, 0,
1184 y - infoPtr->uVisibleHeight, FALSE);
1185 SetScrollPos (hwnd, SB_VERT, infoPtr->cy, TRUE);
1188 if (infoPtr->uInternalStatus & TV_VSCROLL)
1189 ShowScrollBar (hwnd, SB_VERT, FALSE);
1190 infoPtr->uInternalStatus &= ~TV_VSCROLL;
1194 if (infoPtr->cdmode & CDRF_NOTIFYPOSTPAINT)
1195 infoPtr->cdmode=TREEVIEW_SendCustomDrawNotify
1196 (hwnd, CDDS_POSTPAINT, hdc, rect);
1203 TREEVIEW_HandleTimer (HWND hwnd, WPARAM wParam, LPARAM lParam)
1205 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1207 TRACE(" %d\n",wParam);
1210 case TV_REFRESH_TIMER:
1211 KillTimer (hwnd, TV_REFRESH_TIMER);
1212 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
1213 InvalidateRect(hwnd, NULL, FALSE);
1216 KillTimer (hwnd, TV_EDIT_TIMER);
1217 infoPtr->Timer &= ~TV_EDIT_TIMER_SET;
1220 ERR("got unknown timer\n");
1228 TREEVIEW_QueueRefresh (HWND hwnd)
1231 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1234 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
1235 KillTimer (hwnd, TV_REFRESH_TIMER);
1238 SetTimer (hwnd, TV_REFRESH_TIMER, TV_REFRESH_DELAY, 0);
1239 infoPtr->Timer|=TV_REFRESH_TIMER_SET;
1245 TREEVIEW_GetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1247 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1249 TREEVIEW_ITEM *wineItem;
1252 tvItem=(LPTVITEMEXA) lParam;
1253 iItem=(INT)tvItem->hItem;
1255 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1256 if (!wineItem) return FALSE;
1258 if (tvItem->mask & TVIF_CHILDREN) {
1259 if (TVIF_CHILDREN==I_CHILDRENCALLBACK)
1260 FIXME("I_CHILDRENCALLBACK not supported\n");
1261 tvItem->cChildren=wineItem->cChildren;
1264 if (tvItem->mask & TVIF_HANDLE) {
1265 tvItem->hItem=wineItem->hItem;
1268 if (tvItem->mask & TVIF_IMAGE) {
1269 tvItem->iImage=wineItem->iImage;
1272 if (tvItem->mask & TVIF_INTEGRAL) {
1273 tvItem->iIntegral=wineItem->iIntegral;
1276 /* undocumented: windows ignores TVIF_PARAM and
1277 * always sets lParam
1279 tvItem->lParam=wineItem->lParam;
1281 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
1282 tvItem->iSelectedImage=wineItem->iSelectedImage;
1285 if (tvItem->mask & TVIF_STATE) {
1286 tvItem->state=wineItem->state & tvItem->stateMask;
1289 if (tvItem->mask & TVIF_TEXT) {
1290 if (wineItem->pszText == LPSTR_TEXTCALLBACKA) {
1291 tvItem->pszText = LPSTR_TEXTCALLBACKA; /* FIXME:send notification? */
1292 ERR(" GetItem called with LPSTR_TEXTCALLBACK\n");
1294 else if (wineItem->pszText) {
1295 lstrcpynA (tvItem->pszText, wineItem->pszText, tvItem->cchTextMax);
1299 TRACE("item %d<%p>, txt %p, img %p, action %x\n",
1300 iItem, tvItem, tvItem->pszText, &tvItem->iImage, tvItem->mask);
1307 /* FIXME: check implementation of TVGN_NEXT/TVGN_NEXTVISIBLE */
1310 TREEVIEW_GetNextItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
1313 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1314 TREEVIEW_ITEM *wineItem, *returnItem;
1315 INT iItem = (INT)lParam, retval = 0, flag = (INT)wParam;
1320 retval = (INT)infoPtr->TopRootItem;
1324 retval = (INT)infoPtr->selectedItem;
1327 case TVGN_FIRSTVISIBLE: /* FIXME:we should only recalculate, not redraw */
1329 TREEVIEW_Refresh (hwnd, hdc);
1330 ReleaseDC(hwnd,hdc);
1331 retval = (INT)infoPtr->firstVisible;
1334 case TVGN_DROPHILITE:
1335 retval = (INT)infoPtr->dropItem;
1339 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1340 retval = wineItem ? (INT)wineItem->sibling : 0;
1344 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1345 retval = wineItem ? (INT)wineItem->upsibling : 0;
1349 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1350 retval = wineItem ? (INT)wineItem->parent : 0;
1354 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1355 retval = wineItem ? (INT)wineItem->firstChild : 0;
1358 case TVGN_LASTVISIBLE:
1359 if((wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem))) {
1360 returnItem = TREEVIEW_GetLastListItem (infoPtr,wineItem);
1361 retval = returnItem ? (INT)returnItem->hItem : 0;
1365 case TVGN_NEXTVISIBLE:
1366 if((wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem))) {
1367 returnItem = TREEVIEW_GetNextListItem (infoPtr,wineItem);
1368 retval = returnItem ? (INT)returnItem->hItem : 0;
1372 case TVGN_PREVIOUSVISIBLE:
1373 if((wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem))) {
1374 returnItem = TREEVIEW_GetPrevListItem (infoPtr, wineItem);
1375 retval = returnItem ? (INT)returnItem->hItem : 0;
1380 FIXME("Unknown msg %x,item %x\n", flag,iItem);
1384 TRACE("flags %x, item %d returns %d\n", flag, iItem, retval);
1390 TREEVIEW_GetCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
1392 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1394 TRACE(" %d\n",infoPtr->uNumItems);
1395 return (LRESULT) infoPtr->uNumItems;
1398 /***************************************************************************
1399 * This method does the chaining of the insertion of a treeview item
1401 * If parent is NULL, we're inserting at the root of the list.
1403 static void TREEVIEW_InsertBefore(
1404 TREEVIEW_INFO *infoPtr,
1405 TREEVIEW_ITEM *newItem,
1406 TREEVIEW_ITEM *sibling,
1407 TREEVIEW_ITEM *parent)
1409 HTREEITEM siblingHandle = 0;
1410 HTREEITEM upSiblingHandle = 0;
1411 TREEVIEW_ITEM *upSibling = NULL;
1413 if (newItem == NULL)
1414 ERR("NULL newItem, impossible condition\n");
1416 if (sibling != NULL) /* Insert before this sibling for this parent */
1418 /* Store the new item sibling up sibling and sibling tem handle */
1419 siblingHandle = sibling->hItem;
1420 upSiblingHandle = sibling->upsibling;
1421 /* As well as a pointer to the upsibling sibling object */
1422 if ( (INT)sibling->upsibling != 0 )
1423 upSibling = &infoPtr->items[(INT)sibling->upsibling];
1425 /* Adjust the sibling pointer */
1426 sibling->upsibling = newItem->hItem;
1428 /* Adjust the new item pointers */
1429 newItem->upsibling = upSiblingHandle;
1430 newItem->sibling = siblingHandle;
1432 /* Adjust the up sibling pointer */
1433 if ( upSibling != NULL )
1434 upSibling->sibling = newItem->hItem;
1436 /* this item is the first child of this parent, adjust parent pointers */
1438 parent->firstChild = newItem->hItem;
1440 infoPtr->TopRootItem= newItem->hItem;
1442 else /* Insert as first child of this parent */
1444 parent->firstChild = newItem->hItem;
1447 /***************************************************************************
1448 * This method does the chaining of the insertion of a treeview item
1450 * If parent is NULL, we're inserting at the root of the list.
1452 static void TREEVIEW_InsertAfter(
1453 TREEVIEW_INFO *infoPtr,
1454 TREEVIEW_ITEM *newItem,
1455 TREEVIEW_ITEM *upSibling,
1456 TREEVIEW_ITEM *parent)
1458 HTREEITEM upSiblingHandle = 0;
1459 HTREEITEM siblingHandle = 0;
1460 TREEVIEW_ITEM *sibling = NULL;
1463 if (newItem == NULL)
1464 ERR("NULL newItem, impossible condition\n");
1466 if (upSibling != NULL) /* Insert after this upsibling for this parent */
1468 /* Store the new item up sibling and sibling item handle */
1469 upSiblingHandle = upSibling->hItem;
1470 siblingHandle = upSibling->sibling;
1471 /* As well as a pointer to the upsibling sibling object */
1472 if ( (INT)upSibling->sibling != 0 )
1473 sibling = &infoPtr->items[(INT)upSibling->sibling];
1475 /* Adjust the up sibling pointer */
1476 upSibling->sibling = newItem->hItem;
1478 /* Adjust the new item pointers */
1479 newItem->upsibling = upSiblingHandle;
1480 newItem->sibling = siblingHandle;
1482 /* Adjust the sibling pointer */
1483 if ( sibling != NULL )
1484 sibling->upsibling = newItem->hItem;
1487 newItem is the last of the level, nothing else to do
1490 else /* Insert as first child of this parent */
1492 parent->firstChild = newItem->hItem;
1495 /***************************************************************************
1496 * Forward the DPA local callback to the treeview owner callback
1498 static INT WINAPI TREEVIEW_CallBackCompare(
1503 /* Forward the call to the client define callback */
1504 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr((HWND)tvInfoPtr);
1505 return (infoPtr->pCallBackSort->lpfnCompare)(
1506 ((TREEVIEW_ITEM*)first)->lParam,
1507 ((TREEVIEW_ITEM*)second)->lParam,
1508 infoPtr->pCallBackSort->lParam);
1511 /***************************************************************************
1512 * Treeview native sort routine: sort on item text.
1514 static INT WINAPI TREEVIEW_SortOnName (
1519 HWND hwnd=(HWND) tvInfoPtr;
1521 TREEVIEW_ITEM *item;
1524 item=(TREEVIEW_ITEM *) first;
1525 if (item->pszText==LPSTR_TEXTCALLBACKA) {
1526 TREEVIEW_SendDispInfoNotify (hwnd, item, TVN_GETDISPINFOA, TVIF_TEXT);
1530 item=(TREEVIEW_ITEM *) second;
1531 if (item->pszText==LPSTR_TEXTCALLBACKA) {
1532 TREEVIEW_SendDispInfoNotify (hwnd, item, TVN_GETDISPINFOA, TVIF_TEXT);
1536 return -strcmp (txt1,txt2);
1539 /***************************************************************************
1540 * Setup the treeview structure with regards of the sort method
1541 * and sort the children of the TV item specified in lParam
1542 * fRecurse: currently unused. Should be zero.
1543 * parent: if pSort!=NULL, should equal pSort->hParent.
1544 * otherwise, item which child items are to be sorted.
1545 * pSort: sort method info. if NULL, sort on item text.
1546 * if non-NULL, sort on item's lParam content, and let the
1547 * application decide what that means. See also TVM_SORTCHILDRENCB.
1550 static LRESULT WINAPI TREEVIEW_Sort (
1557 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1558 TREEVIEW_ITEM *sortMe = NULL; /* Node for which we sort the children */
1560 /* Obtain the TVSORTBC struct */
1561 infoPtr->pCallBackSort = pSort;
1563 /* undocumented feature: TVI_ROOT means `sort the whole tree' */
1565 if (parent==TVI_ROOT)
1566 parent=infoPtr->TopRootItem;
1568 /* Check for a valid handle to the parent item */
1569 if (!TREEVIEW_ValidItem(infoPtr, parent))
1571 ERR ("invalid item hParent=%x\n", (INT)parent);
1575 /* Obtain the parent node to sort */
1576 sortMe = &infoPtr->items[ (INT)parent ];
1578 /* Make sure there is something to sort */
1579 if ( sortMe->cChildren > 1 )
1581 /* pointer organization */
1582 HDPA sortList = DPA_Create(sortMe->cChildren);
1583 HTREEITEM itemHandle = sortMe->firstChild;
1584 TREEVIEW_ITEM *itemPtr = & infoPtr->items[ (INT)itemHandle ];
1586 /* TREEVIEW_ITEM rechaining */
1592 /* Build the list of item to sort */
1596 sortList, /* the list */
1597 sortMe->cChildren+1, /* force the insertion to be an append */
1598 itemPtr); /* the ptr to store */
1600 /* Get the next sibling */
1601 itemHandle = itemPtr->sibling;
1602 itemPtr = & infoPtr->items[ (INT)itemHandle ];
1603 } while ( itemHandle != NULL );
1605 /* let DPA perform the sort activity */
1608 sortList, /* what */
1609 TREEVIEW_CallBackCompare, /* how */
1613 sortList, /* what */
1614 TREEVIEW_SortOnName, /* how */
1618 * Reorganized TREEVIEW_ITEM structures.
1619 * Note that we know we have at least two elements.
1622 /* Get the first item and get ready to start... */
1623 item = DPA_GetPtr(sortList, count++);
1624 while ( (nextItem = DPA_GetPtr(sortList, count++)) != NULL )
1626 /* link the two current item toghether */
1627 ((TREEVIEW_ITEM*)item)->sibling = ((TREEVIEW_ITEM*)nextItem)->hItem;
1628 ((TREEVIEW_ITEM*)nextItem)->upsibling = ((TREEVIEW_ITEM*)item)->hItem;
1630 if (prevItem == NULL) /* this is the first item, update the parent */
1632 sortMe->firstChild = ((TREEVIEW_ITEM*)item)->hItem;
1633 ((TREEVIEW_ITEM*)item)->upsibling = NULL;
1635 else /* fix the back chaining */
1637 ((TREEVIEW_ITEM*)item)->upsibling = ((TREEVIEW_ITEM*)prevItem)->hItem;
1640 /* get ready for the next one */
1645 /* the last item is pointed to by item and never has a sibling */
1646 ((TREEVIEW_ITEM*)item)->sibling = NULL;
1648 DPA_Destroy(sortList);
1656 /***************************************************************************
1657 * Setup the treeview structure with regards of the sort method
1658 * and sort the children of the TV item specified in lParam
1660 static LRESULT WINAPI TREEVIEW_SortChildrenCB(
1666 LPTVSORTCB pSort=(LPTVSORTCB) lParam;
1668 return TREEVIEW_Sort (hwnd, wParam, pSort->hParent, pSort);
1672 /***************************************************************************
1673 * Sort the children of the TV item specified in lParam.
1675 static LRESULT WINAPI TREEVIEW_SortChildren (
1680 return TREEVIEW_Sort (hwnd, (BOOL) wParam, (HTREEITEM) lParam, NULL);
1685 /* the method used below isn't the most memory-friendly, but it avoids
1686 a lot of memory reallocations */
1688 /* BTW: we waste handle 0; 0 is not an allowed handle. */
1691 TREEVIEW_InsertItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1694 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1695 TVINSERTSTRUCTA *ptdi;
1697 TREEVIEW_ITEM *wineItem, *parentItem, *prevsib, *sibItem;
1698 INT iItem,listItems,i,len;
1700 /* Item to insert */
1701 ptdi = (LPTVINSERTSTRUCTA) lParam;
1703 /* check if memory is available */
1705 if (infoPtr->uNumPtrsAlloced==0) {
1706 infoPtr->items = COMCTL32_Alloc (TVITEM_ALLOC*sizeof (TREEVIEW_ITEM));
1707 infoPtr->freeList= COMCTL32_Alloc ((1+(TVITEM_ALLOC>>5)) * sizeof (INT));
1708 infoPtr->uNumPtrsAlloced=TVITEM_ALLOC;
1709 infoPtr->TopRootItem=(HTREEITEM)1;
1713 * Reallocate contiguous space for items
1715 if (infoPtr->uNumItems == (infoPtr->uNumPtrsAlloced-1) ) {
1716 TREEVIEW_ITEM *oldItems = infoPtr->items;
1717 INT *oldfreeList = infoPtr->freeList;
1719 infoPtr->uNumPtrsAlloced*=2;
1720 infoPtr->items = COMCTL32_Alloc (infoPtr->uNumPtrsAlloced*sizeof (TREEVIEW_ITEM));
1721 infoPtr->freeList= COMCTL32_Alloc ((1+(infoPtr->uNumPtrsAlloced>>5))*sizeof (INT));
1723 memcpy (&infoPtr->items[0], &oldItems[0],
1724 infoPtr->uNumPtrsAlloced/2 * sizeof(TREEVIEW_ITEM));
1725 memcpy (&infoPtr->freeList[0], &oldfreeList[0],
1726 (infoPtr->uNumPtrsAlloced>>6) * sizeof(INT));
1728 COMCTL32_Free (oldItems);
1729 COMCTL32_Free (oldfreeList);
1733 * Reset infoPtr structure with new stat according to current TV picture
1736 infoPtr->uNumItems++;
1737 if ((INT)infoPtr->uMaxHandle==(infoPtr->uNumItems-1)) {
1738 iItem=infoPtr->uNumItems;
1739 infoPtr->uMaxHandle = (HTREEITEM)((INT)infoPtr->uMaxHandle + 1);
1740 } else { /* check freelist */
1741 for (i=0; i<=infoPtr->uNumPtrsAlloced>>5; i++) {
1742 if (infoPtr->freeList[i]) {
1743 iItem=ffs (infoPtr->freeList[i])-1;
1744 tv_clear_bit(iItem,&infoPtr->freeList[i]);
1751 if (TRACE_ON(treeview)) {
1752 for (i=0; i<=infoPtr->uNumPtrsAlloced>>5; i++)
1753 TRACE("%8x\n",infoPtr->freeList[i]);
1756 if (!iItem) ERR("Argh -- can't find free item.\n");
1759 * Find the parent item of the new item
1761 tvItem= & ptdi->DUMMYUNIONNAME.itemex;
1762 wineItem=& infoPtr->items[iItem];
1764 if ((ptdi->hParent==TVI_ROOT) || (ptdi->hParent==0)) {
1766 wineItem->parent = 0;
1767 sibItem = &infoPtr->items [(INT)infoPtr->TopRootItem];
1768 listItems = infoPtr->uNumItems;
1771 parentItem = &infoPtr->items[(INT)ptdi->hParent];
1773 /* Do the insertion here it if it's the only item of this parent */
1774 if (!parentItem->firstChild)
1775 parentItem->firstChild=(HTREEITEM)iItem;
1777 wineItem->parent = ptdi->hParent;
1778 sibItem = &infoPtr->items [(INT)parentItem->firstChild];
1779 listItems = parentItem->cChildren;
1780 parentItem->cChildren++;
1784 /* NOTE: I am moving some setup of the wineItem object that was initialy
1785 * done at the end of the function since some of the values are
1786 * required by the Callback sorting
1789 if (tvItem->mask & TVIF_TEXT)
1792 * Setup the item text stuff here since it's required by the Sort method
1793 * when the insertion are ordered
1795 if (tvItem->pszText!=LPSTR_TEXTCALLBACKA)
1797 TRACE("(%p,%s)\n", &tvItem->pszText, tvItem->pszText);
1798 len = lstrlenA (tvItem->pszText)+1;
1799 wineItem->pszText= COMCTL32_Alloc (len+1);
1800 lstrcpyA (wineItem->pszText, tvItem->pszText);
1801 wineItem->cchTextMax=len;
1805 TRACE("LPSTR_TEXTCALLBACK\n");
1806 wineItem->pszText = LPSTR_TEXTCALLBACKA;
1807 wineItem->cchTextMax = 0;
1811 if (tvItem->mask & TVIF_PARAM)
1812 wineItem->lParam=tvItem->lParam;
1815 wineItem->upsibling=0; /* needed in case we're the first item in a list */
1816 wineItem->sibling=0;
1817 wineItem->firstChild=0;
1818 wineItem->hItem=(HTREEITEM)iItem;
1823 switch ((DWORD) ptdi->hInsertAfter) {
1824 case (DWORD) TVI_FIRST:
1825 if (sibItem==wineItem) break;
1826 if (wineItem->parent) {
1827 wineItem->sibling=parentItem->firstChild;
1828 parentItem->firstChild=(HTREEITEM)iItem;
1830 wineItem->sibling=infoPtr->TopRootItem;
1831 infoPtr->TopRootItem=(HTREEITEM)iItem;
1833 sibItem->upsibling=(HTREEITEM)iItem;
1836 case (DWORD) TVI_SORT:
1837 if (sibItem==wineItem)
1839 * This item is the first child of the level and it
1840 * has already been inserted
1845 TREEVIEW_ITEM *aChild;
1848 TREEVIEW_ITEM *previousChild = NULL;
1849 BOOL bItemInserted = FALSE;
1852 aChild = &infoPtr->items[(INT)parentItem->firstChild];
1854 aChild = &infoPtr->items[(INT)infoPtr->TopRootItem];
1856 /* lookup the text if using LPSTR_TEXTCALLBACKs */
1857 if (wineItem->pszText==LPSTR_TEXTCALLBACKA) {
1858 TREEVIEW_SendDispInfoNotify (hwnd, wineItem, TVN_GETDISPINFOA, TVIF_TEXT);
1861 /* Iterate the parent children to see where we fit in */
1862 while ( aChild != NULL )
1866 /* lookup the text if using LPSTR_TEXTCALLBACKs */
1867 if (aChild->pszText==LPSTR_TEXTCALLBACKA) {
1868 TREEVIEW_SendDispInfoNotify (hwnd, aChild, TVN_GETDISPINFOA, TVIF_TEXT);
1871 comp = strcmp(wineItem->pszText, aChild->pszText);
1872 if ( comp < 0 ) /* we are smaller than the current one */
1874 TREEVIEW_InsertBefore(infoPtr, wineItem, aChild, parentItem);
1875 bItemInserted = TRUE;
1878 else if ( comp > 0 ) /* we are bigger than the current one */
1880 previousChild = aChild;
1881 aChild = (aChild->sibling == 0) /* This will help us to exit */
1882 ? NULL /* if there is no more sibling */
1883 : &infoPtr->items[(INT)aChild->sibling];
1885 /* Look at the next item */
1888 else if ( comp == 0 )
1891 * An item with this name is already existing, therefore,
1892 * we add after the one we found
1894 TREEVIEW_InsertAfter(infoPtr, wineItem, aChild, parentItem);
1895 bItemInserted = TRUE;
1901 * we reach the end of the child list and the item as not
1902 * yet been inserted, therefore, insert it after the last child.
1904 if ( (! bItemInserted ) && (aChild == NULL) )
1905 TREEVIEW_InsertAfter(infoPtr, wineItem, previousChild, parentItem);
1911 case (DWORD) TVI_LAST:
1912 if (sibItem==wineItem) break;
1913 while (sibItem->sibling) {
1915 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1917 sibItem->sibling=(HTREEITEM)iItem;
1918 wineItem->upsibling=sibItem->hItem;
1921 while ((sibItem->sibling) && (sibItem->hItem!=ptdi->hInsertAfter))
1924 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1926 if (sibItem->hItem!=ptdi->hInsertAfter) {
1927 ERR("tried to insert item after nonexisting handle %d.\n",
1928 (INT) ptdi->hInsertAfter);
1932 if (sibItem->sibling) {
1933 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1934 sibItem->upsibling=(HTREEITEM)iItem;
1935 wineItem->sibling=sibItem->hItem;
1937 prevsib->sibling=(HTREEITEM)iItem;
1938 wineItem->upsibling=prevsib->hItem;
1944 /* Fill in info structure */
1946 TRACE("new item %d; parent %d, mask %x\n", iItem,
1947 (INT)wineItem->parent,tvItem->mask);
1949 wineItem->mask=tvItem->mask;
1950 wineItem->iIntegral=1;
1952 if (tvItem->mask & TVIF_CHILDREN) {
1953 wineItem->cChildren=tvItem->cChildren;
1954 if (tvItem->cChildren==I_CHILDRENCALLBACK)
1955 FIXME(" I_CHILDRENCALLBACK not supported\n");
1958 wineItem->expandBox.left = 0; /* Initialize the expandBox */
1959 wineItem->expandBox.top = 0;
1960 wineItem->expandBox.right = 0;
1961 wineItem->expandBox.bottom = 0;
1963 if (tvItem->mask & TVIF_IMAGE)
1964 wineItem->iImage=tvItem->iImage;
1966 /* If the application sets TVIF_INTEGRAL without
1967 supplying a TVITEMEX structure, it's toast */
1969 if (tvItem->mask & TVIF_INTEGRAL)
1970 wineItem->iIntegral=tvItem->iIntegral;
1972 if (tvItem->mask & TVIF_SELECTEDIMAGE)
1973 wineItem->iSelectedImage=tvItem->iSelectedImage;
1975 if (tvItem->mask & TVIF_STATE) {
1976 TRACE("item state: %x ->%x\n", wineItem->state, tvItem->state);
1977 TRACE("statemask: %x ->%x\n", wineItem->stateMask, tvItem->stateMask);
1978 wineItem->state=tvItem->state;
1979 wineItem->stateMask=tvItem->stateMask;
1982 TREEVIEW_QueueRefresh (hwnd);
1984 return (LRESULT) iItem;
1989 TREEVIEW_InsertItemW(HWND hwnd, WPARAM wParam, LPARAM lParam)
1991 TVINSERTSTRUCTW *tvisW;
1992 TVINSERTSTRUCTA tvisA;
1995 tvisW = (LPTVINSERTSTRUCTW)lParam;
1997 tvisA.hParent = tvisW->hParent;
1998 tvisA.hInsertAfter = tvisW->hInsertAfter;
2000 tvisA.DUMMYUNIONNAME.item.mask = tvisW->DUMMYUNIONNAME.item.mask;
2001 tvisA.DUMMYUNIONNAME.item.hItem = tvisW->DUMMYUNIONNAME.item.hItem;
2002 tvisA.DUMMYUNIONNAME.item.state = tvisW->DUMMYUNIONNAME.item.state;
2003 tvisA.DUMMYUNIONNAME.item.stateMask = tvisW->DUMMYUNIONNAME.item.stateMask;
2004 tvisA.DUMMYUNIONNAME.item.cchTextMax = tvisW->DUMMYUNIONNAME.item.cchTextMax;
2006 if(tvisW->DUMMYUNIONNAME.item.pszText)
2008 if (tvisW->DUMMYUNIONNAME.item.pszText!=LPSTR_TEXTCALLBACKW)
2010 int len = lstrlenW (tvisW->DUMMYUNIONNAME.item.pszText)+1;
2011 tvisA.DUMMYUNIONNAME.item.pszText = COMCTL32_Alloc (len);
2012 lstrcpyWtoA (tvisA.DUMMYUNIONNAME.item.pszText,
2013 tvisW->DUMMYUNIONNAME.item.pszText );
2017 tvisA.DUMMYUNIONNAME.item.pszText = LPSTR_TEXTCALLBACKA;
2018 tvisA.DUMMYUNIONNAME.item.cchTextMax = 0;
2022 tvisA.DUMMYUNIONNAME.item.iImage = tvisW->DUMMYUNIONNAME.item.iImage;
2023 tvisA.DUMMYUNIONNAME.item.iSelectedImage = tvisW->DUMMYUNIONNAME.item.iSelectedImage;
2024 tvisA.DUMMYUNIONNAME.item.cChildren = tvisW->DUMMYUNIONNAME.item.cChildren;
2025 tvisA.DUMMYUNIONNAME.item.lParam = tvisW->DUMMYUNIONNAME.item.lParam;
2027 lRes = TREEVIEW_InsertItemA(hwnd,wParam,(LPARAM)&tvisA);
2029 if (tvisA.DUMMYUNIONNAME.item.pszText!=LPSTR_TEXTCALLBACKA)
2031 COMCTL32_Free(tvisA.DUMMYUNIONNAME.item.pszText);
2040 TREEVIEW_DeleteItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
2042 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2044 TREEVIEW_ITEM *wineItem;
2046 TRACE("item = %08lx\n", lParam);
2048 if (lParam == (INT)TVI_ROOT) {
2049 TREEVIEW_RemoveTree (hwnd);
2051 iItem= (INT) lParam;
2052 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
2053 if (!wineItem) return FALSE;
2055 if (wineItem->pszText==LPSTR_TEXTCALLBACKA)
2056 TRACE("LPSTR_TEXTCALLBACK\n");
2058 TRACE("%s\n",wineItem->pszText);
2059 TREEVIEW_RemoveItem (hwnd, wineItem);
2062 TREEVIEW_QueueRefresh (hwnd);
2070 TREEVIEW_GetIndent (HWND hwnd)
2072 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2075 return infoPtr->uIndent;
2079 TREEVIEW_SetIndent (HWND hwnd, WPARAM wParam)
2081 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2085 newIndent=(INT) wParam;
2086 if (newIndent < MINIMUM_INDENT) newIndent=MINIMUM_INDENT;
2087 infoPtr->uIndent=newIndent;
2093 TREEVIEW_GetToolTips (HWND hwnd)
2096 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2099 return infoPtr->hwndToolTip;
2104 TREEVIEW_SetToolTips (HWND hwnd, WPARAM wParam)
2107 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2111 prevToolTip=infoPtr->hwndToolTip;
2112 infoPtr->hwndToolTip= (HWND) wParam;
2118 static LRESULT CALLBACK
2119 TREEVIEW_GetEditControl (HWND hwnd)
2122 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2124 return infoPtr->hwndEdit;
2128 TREEVIEW_Edit_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam,
2136 HDC hdc = (HDC) wParam;
2137 GetClientRect (hwnd, &rc);
2138 Rectangle (hdc, rc.left, rc.top, rc.right, rc.bottom);
2144 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
2148 if (wParam == VK_ESCAPE)
2150 TREEVIEW_EndEditLabelNow(GetParent(hwnd), (WPARAM)TRUE, 0);
2153 else if (wParam == VK_RETURN)
2154 TREEVIEW_EndEditLabelNow(GetParent(hwnd), (WPARAM)FALSE, 0);
2161 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd));
2163 return CallWindowProcA (infoPtr->wpEditOrig, hwnd, uMsg, wParam, lParam);
2174 /* should handle edit control messages here */
2177 TREEVIEW_Command (HWND hwnd, WPARAM wParam, LPARAM lParam)
2180 TRACE("%x %ld\n",wParam, lParam);
2182 switch (HIWORD(wParam))
2187 * Adjust the edit window size
2189 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2190 TREEVIEW_ITEM *editItem = TREEVIEW_ValidItem(infoPtr, infoPtr->editItem);
2191 INT iLength = GetWindowTextLengthA(infoPtr->hwndEdit);
2192 HDC hdc = GetDC(infoPtr->hwndEdit);
2195 if ( GetTextMetricsA(hdc, &tm) )
2197 LONG newWidth = (iLength * tm.tmAveCharWidth) + 15;
2202 editItem->text.left - 2,
2203 editItem->text.top - 1,
2205 editItem->text.bottom - editItem->text.top + 3,
2208 ReleaseDC(hwnd, hdc);
2214 /* TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
2219 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
2226 TREEVIEW_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
2229 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2231 if (infoPtr->bAutoSize)
2233 infoPtr->bAutoSize = FALSE;
2236 infoPtr->bAutoSize = TRUE;
2238 if (wParam == SIZE_RESTORED)
2240 infoPtr->uTotalWidth = LOWORD (lParam);
2241 infoPtr->uTotalHeight = HIWORD (lParam);
2243 FIXME("WM_SIZE flag %x %lx not handled\n", wParam, lParam);
2246 TREEVIEW_QueueRefresh (hwnd);
2253 TREEVIEW_StyleChanged (HWND hwnd, WPARAM wParam, LPARAM lParam)
2257 TRACE("(%x %lx)\n",wParam,lParam);
2259 TREEVIEW_Refresh (hwnd, hdc);
2260 ReleaseDC(hwnd,hdc);
2266 TREEVIEW_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
2268 TREEVIEW_INFO *infoPtr;
2269 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
2274 TRACE("wnd %x, style %lx\n",hwnd,dwStyle);
2275 /* allocate memory for info structure */
2276 infoPtr = (TREEVIEW_INFO *) COMCTL32_Alloc (sizeof(TREEVIEW_INFO));
2278 SetWindowLongA( hwnd, 0, (DWORD)infoPtr);
2280 if (infoPtr == NULL) {
2281 ERR("could not allocate info memory!\n");
2285 if ((TREEVIEW_INFO*) GetWindowLongA( hwnd, 0) != infoPtr) {
2286 ERR("pointer assignment error!\n");
2292 /* set default settings */
2293 infoPtr->uInternalStatus=0;
2294 infoPtr->uNumItems=0;
2295 infoPtr->clrBk = GetSysColor (COLOR_WINDOW);
2296 infoPtr->clrText = GetSysColor (COLOR_WINDOWTEXT);
2297 infoPtr->clrLine = GetSysColor (COLOR_WINDOWTEXT);
2298 infoPtr->clrInsertMark = GetSysColor (COLOR_BTNTEXT);
2301 infoPtr->uIndent = 15;
2302 infoPtr->himlNormal = NULL;
2303 infoPtr->himlState = NULL;
2304 infoPtr->uItemHeight = -1;
2305 GetTextMetricsA (hdc, &tm);
2306 infoPtr->hFont = GetStockObject (DEFAULT_GUI_FONT);
2307 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
2308 logFont.lfWeight=FW_BOLD;
2309 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
2311 infoPtr->items = NULL;
2312 infoPtr->selectedItem=0;
2313 infoPtr->clrText=-1; /* use system color */
2314 infoPtr->dropItem=0;
2315 infoPtr->insertMarkItem=0;
2316 infoPtr->insertBeforeorAfter=0;
2317 infoPtr->pCallBackSort=NULL;
2318 infoPtr->uScrollTime = 300; /* milliseconds */
2319 infoPtr->wpEditOrig = NULL; /* we haven't subclassed anything yet */
2321 infoPtr->hwndToolTip=0;
2322 if (!(dwStyle & TVS_NOTOOLTIPS)) { /* Create tooltip control */
2325 infoPtr->hwndToolTip =
2326 CreateWindowExA (0, TOOLTIPS_CLASSA, NULL, 0,
2327 CW_USEDEFAULT, CW_USEDEFAULT,
2328 CW_USEDEFAULT, CW_USEDEFAULT,
2331 /* Send NM_TOOLTIPSCREATED notification */
2332 if (infoPtr->hwndToolTip) {
2333 NMTOOLTIPSCREATED nmttc;
2335 nmttc.hdr.hwndFrom = hwnd;
2336 nmttc.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2337 nmttc.hdr.code = NM_TOOLTIPSCREATED;
2338 nmttc.hwndToolTips = infoPtr->hwndToolTip;
2340 SendMessageA (GetParent (hwnd), WM_NOTIFY,
2341 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmttc);
2344 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
2345 ti.cbSize = sizeof(TTTOOLINFOA);
2346 ti.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_TRANSPARENT ;
2349 ti.lpszText = "Test"; /* LPSTR_TEXTCALLBACK; */
2350 SetRectEmpty (&ti.rect);
2352 SendMessageA (infoPtr->hwndToolTip, TTM_ADDTOOLA, 0, (LPARAM)&ti);
2355 infoPtr->hwndEdit = CreateWindowExA (
2359 WS_CHILD | WS_BORDER | ES_AUTOHSCROLL |
2360 ES_WANTRETURN | ES_LEFT,
2363 0,0,0); /* FIXME: (HMENU)IDTVEDIT,pcs->hInstance,0);*/
2365 SendMessageA ( infoPtr->hwndEdit, WM_SETFONT, infoPtr->hFont, FALSE);
2366 infoPtr->wpEditOrig = (WNDPROC)SetWindowLongA (
2369 (LONG) TREEVIEW_Edit_SubclassProc);
2371 if (dwStyle & TVS_CHECKBOXES) {
2375 infoPtr->himlState =
2376 ImageList_Create (16, 16,ILC_COLOR|ILC_MASK, 15, 1);
2378 hbmLoad = LoadBitmapA (COMCTL32_hModule, MAKEINTRESOURCEA(IDT_CHECK));
2379 TRACE ("%x\n",hbmLoad);
2380 nIndex = ImageList_AddMasked (infoPtr->himlState, hbmLoad, CLR_DEFAULT);
2381 TRACE ("%d\n",nIndex);
2382 DeleteObject (hbmLoad);
2384 ReleaseDC (hwnd, hdc);
2391 TREEVIEW_Destroy (HWND hwnd)
2393 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2396 TREEVIEW_RemoveTree (hwnd);
2397 SetWindowLongA (hwnd, 0, (DWORD)NULL);
2399 if (infoPtr->Timer & TV_REFRESH_TIMER_SET)
2400 KillTimer (hwnd, TV_REFRESH_TIMER);
2401 if (infoPtr->hwndToolTip)
2402 DestroyWindow (infoPtr->hwndToolTip);
2404 COMCTL32_Free (infoPtr);
2410 TREEVIEW_Paint (HWND hwnd, WPARAM wParam, LPARAM lParam)
2416 hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
2417 TREEVIEW_Refresh (hwnd, hdc);
2418 if(!wParam) EndPaint (hwnd, &ps);
2421 return DefWindowProcA (hwnd, WM_PAINT, wParam, lParam);
2425 TREEVIEW_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2427 TREEVIEW_SendSimpleNotify (hwnd, NM_SETFOCUS);
2428 InvalidateRect(hwnd, NULL, FALSE);
2433 TREEVIEW_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2435 TREEVIEW_SendSimpleNotify (hwnd, NM_KILLFOCUS);
2436 InvalidateRect(hwnd, NULL, FALSE);
2441 TREEVIEW_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
2443 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2444 HBRUSH hBrush = CreateSolidBrush (infoPtr->clrBk);
2448 GetClientRect (hwnd, &rect);
2449 FillRect ((HDC)wParam, &rect, hBrush);
2450 DeleteObject (hBrush);
2466 TREEVIEW_SendSimpleNotify (HWND hwnd, UINT code)
2471 nmhdr.hwndFrom = hwnd;
2472 nmhdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2475 return (BOOL) SendMessageA (GetParent (hwnd), WM_NOTIFY,
2476 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
2482 TREEVIEW_SendTreeviewNotify (HWND hwnd, UINT code, UINT action,
2483 HTREEITEM oldItem, HTREEITEM newItem)
2486 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2488 TREEVIEW_ITEM *wineItem;
2490 TRACE("code:%x action:%x olditem:%x newitem:%x\n",
2491 code,action,(INT)oldItem,(INT)newItem);
2492 nmhdr.hdr.hwndFrom = hwnd;
2493 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2494 nmhdr.hdr.code = code;
2495 nmhdr.action = action;
2497 wineItem=& infoPtr->items[(INT)oldItem];
2498 nmhdr.itemOld.mask = wineItem->mask;
2499 nmhdr.itemOld.hItem = wineItem->hItem;
2500 nmhdr.itemOld.state = wineItem->state;
2501 nmhdr.itemOld.stateMask = wineItem->stateMask;
2502 nmhdr.itemOld.iImage = wineItem->iImage;
2503 nmhdr.itemOld.pszText = wineItem->pszText;
2504 nmhdr.itemOld.cchTextMax= wineItem->cchTextMax;
2505 nmhdr.itemOld.iImage = wineItem->iImage;
2506 nmhdr.itemOld.iSelectedImage = wineItem->iSelectedImage;
2507 nmhdr.itemOld.cChildren = wineItem->cChildren;
2508 nmhdr.itemOld.lParam = wineItem->lParam;
2512 wineItem=& infoPtr->items[(INT)newItem];
2513 nmhdr.itemNew.mask = wineItem->mask;
2514 nmhdr.itemNew.hItem = wineItem->hItem;
2515 nmhdr.itemNew.state = wineItem->state;
2516 nmhdr.itemNew.stateMask = wineItem->stateMask;
2517 nmhdr.itemNew.iImage = wineItem->iImage;
2518 nmhdr.itemNew.pszText = wineItem->pszText;
2519 nmhdr.itemNew.cchTextMax= wineItem->cchTextMax;
2520 nmhdr.itemNew.iImage = wineItem->iImage;
2521 nmhdr.itemNew.iSelectedImage = wineItem->iSelectedImage;
2522 nmhdr.itemNew.cChildren = wineItem->cChildren;
2523 nmhdr.itemNew.lParam = wineItem->lParam;
2529 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2530 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2535 TREEVIEW_SendTreeviewDnDNotify (HWND hwnd, UINT code, HTREEITEM dragItem,
2538 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2540 TREEVIEW_ITEM *wineItem;
2542 TRACE("code:%x dragitem:%x\n", code,(INT)dragItem);
2544 nmhdr.hdr.hwndFrom = hwnd;
2545 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2546 nmhdr.hdr.code = code;
2548 wineItem=& infoPtr->items[(INT)dragItem];
2549 nmhdr.itemNew.mask = wineItem->mask;
2550 nmhdr.itemNew.hItem = wineItem->hItem;
2551 nmhdr.itemNew.state = wineItem->state;
2552 nmhdr.itemNew.lParam = wineItem->lParam;
2554 nmhdr.ptDrag.x = pt.x;
2555 nmhdr.ptDrag.y = pt.y;
2557 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2558 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2565 TREEVIEW_SendDispInfoNotify (HWND hwnd, TREEVIEW_ITEM *wineItem,
2566 UINT code, UINT what)
2572 TRACE("item %d, action %x, state %d\n",
2573 (INT)wineItem->hItem,
2575 (INT)wineItem->state);
2577 tvdi.hdr.hwndFrom = hwnd;
2578 tvdi.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2579 tvdi.hdr.code = code;
2580 tvdi.item.mask = what;
2581 tvdi.item.hItem = wineItem->hItem;
2582 tvdi.item.state = wineItem->state;
2583 tvdi.item.lParam = wineItem->lParam;
2584 tvdi.item.pszText = COMCTL32_Alloc (128*sizeof(char));
2585 tvdi.item.cchTextMax = 128;
2586 buf = tvdi.item.pszText;
2588 retval=(BOOL)SendMessageA (
2591 (WPARAM)tvdi.hdr.idFrom,
2594 if (what & TVIF_TEXT) {
2595 wineItem->pszText = tvdi.item.pszText;
2596 if (buf==tvdi.item.pszText) {
2597 wineItem->cchTextMax = 128;
2599 TRACE("user-supplied buffer\n");
2600 COMCTL32_Free (buf);
2601 wineItem->cchTextMax = 0;
2604 if (what & TVIF_SELECTEDIMAGE)
2605 wineItem->iSelectedImage = tvdi.item.iSelectedImage;
2606 if (what & TVIF_IMAGE)
2607 wineItem->iImage = tvdi.item.iImage;
2608 if (what & TVIF_CHILDREN)
2609 wineItem->cChildren = tvdi.item.cChildren;
2617 TREEVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
2620 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2621 NMTVCUSTOMDRAW nmcdhdr;
2622 LPNMCUSTOMDRAW nmcd;
2624 TRACE("drawstage:%lx hdc:%x\n", dwDrawStage, hdc);
2626 nmcd= & nmcdhdr.nmcd;
2627 nmcd->hdr.hwndFrom = hwnd;
2628 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2629 nmcd->hdr.code = NM_CUSTOMDRAW;
2630 nmcd->dwDrawStage= dwDrawStage;
2632 nmcd->rc.left = rc.left;
2633 nmcd->rc.right = rc.right;
2634 nmcd->rc.bottom = rc.bottom;
2635 nmcd->rc.top = rc.top;
2636 nmcd->dwItemSpec = 0;
2637 nmcd->uItemState = 0;
2638 nmcd->lItemlParam= 0;
2639 nmcdhdr.clrText = infoPtr->clrText;
2640 nmcdhdr.clrTextBk= infoPtr->clrBk;
2643 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2644 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2650 /* FIXME: need to find out when the flags in uItemState need to be set */
2653 TREEVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
2654 TREEVIEW_ITEM *wineItem, UINT uItemDrawState)
2656 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2657 NMTVCUSTOMDRAW nmcdhdr;
2658 LPNMCUSTOMDRAW nmcd;
2659 DWORD dwDrawStage,dwItemSpec;
2663 dwDrawStage=CDDS_ITEM | uItemDrawState;
2664 dwItemSpec=(DWORD)wineItem->hItem;
2666 if (wineItem->hItem==infoPtr->selectedItem) uItemState|=CDIS_SELECTED;
2667 if (wineItem->hItem==infoPtr->focusItem) uItemState|=CDIS_FOCUS;
2668 if (wineItem->hItem==infoPtr->hotItem) uItemState|=CDIS_HOT;
2670 nmcd= & nmcdhdr.nmcd;
2671 nmcd->hdr.hwndFrom = hwnd;
2672 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2673 nmcd->hdr.code = NM_CUSTOMDRAW;
2674 nmcd->dwDrawStage= dwDrawStage;
2676 nmcd->rc.left = wineItem->rect.left;
2677 nmcd->rc.right = wineItem->rect.right;
2678 nmcd->rc.bottom = wineItem->rect.bottom;
2679 nmcd->rc.top = wineItem->rect.top;
2680 nmcd->dwItemSpec = dwItemSpec;
2681 nmcd->uItemState = uItemState;
2682 nmcd->lItemlParam= wineItem->lParam;
2683 nmcdhdr.clrText = infoPtr->clrText;
2684 nmcdhdr.clrTextBk= infoPtr->clrBk;
2685 nmcdhdr.iLevel = wineItem->iLevel;
2687 TRACE("drawstage:%lx hdc:%x item:%lx, itemstate:%x, lItemlParam:%lx\n",
2688 nmcd->dwDrawStage, nmcd->hdc, nmcd->dwItemSpec,
2689 nmcd->uItemState, nmcd->lItemlParam);
2691 retval=SendMessageA (GetParent (hwnd), WM_NOTIFY,
2692 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2694 infoPtr->clrText=nmcdhdr.clrText;
2695 infoPtr->clrBk =nmcdhdr.clrTextBk;
2696 return (BOOL) retval;
2701 /* Note:If the specified item is the child of a collapsed parent item,
2702 the parent's list of child items is (recursively) expanded to reveal the
2703 specified item. This is mentioned for TREEVIEW_SelectItem; don't
2704 know if it also applies here.
2708 TREEVIEW_Expand (HWND hwnd, WPARAM wParam, LPARAM lParam)
2710 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2711 TREEVIEW_ITEM *wineItem;
2715 flag = (UINT) wParam;
2716 expand = (INT) lParam;
2718 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2722 if (!wineItem->cChildren)
2725 if (wineItem->pszText==LPSTR_TEXTCALLBACKA)
2726 TRACE ("For item %d, flags %d, state %d\n",
2727 expand, flag, wineItem->state);
2729 TRACE("For (%s) item:%d, flags %x, state:%d\n",
2730 wineItem->pszText, flag, expand, wineItem->state);
2732 if (wineItem->cChildren==I_CHILDRENCALLBACK) {
2733 FIXME("we don't handle I_CHILDRENCALLBACK yet\n");
2737 if (flag == TVE_TOGGLE) { /* FIXME: check exact behaviour here */
2738 flag &= ~TVE_TOGGLE; /* ie: bitwise ops or 'case' ops */
2739 if (wineItem->state & TVIS_EXPANDED)
2740 flag |= TVE_COLLAPSE;
2747 case TVE_COLLAPSERESET:
2748 TRACE(" case TVE_COLLAPSERESET\n");
2749 if (!wineItem->state & TVIS_EXPANDED)
2752 wineItem->state &= ~(TVIS_EXPANDEDONCE | TVIS_EXPANDED);
2753 TREEVIEW_RemoveAllChildren (hwnd, wineItem);
2757 TRACE(" case TVE_COLLAPSE\n");
2758 if (!wineItem->state & TVIS_EXPANDED)
2761 wineItem->state &= ~TVIS_EXPANDED;
2765 TRACE(" case TVE_EXPAND\n");
2766 if (wineItem->state & TVIS_EXPANDED)
2769 TRACE(" is not expanded...\n");
2771 if (!(wineItem->state & TVIS_EXPANDEDONCE))
2773 TRACE(" and has never been expanded...\n");
2774 wineItem->state |= TVIS_EXPANDED;
2776 /* this item has never been expanded */
2777 if (TREEVIEW_SendTreeviewNotify (
2784 TRACE(" TVN_ITEMEXPANDINGA returned TRUE, exiting...\n");
2789 * Since the TVN_ITEMEXPANDINGA message may has caused the parent to
2790 * insert new items which in turn may have cause items placeholder
2791 * reallocation, I reassign the current item pointer so we have
2792 * something valid to work with...
2793 * However, this should not be necessary,
2794 * investigation required in TREEVIEW_InsertItemA
2796 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2800 "Catastropic situation, cannot retreive item #%d\n",
2805 wineItem->state |= TVIS_EXPANDEDONCE;
2806 TRACE(" TVN_ITEMEXPANDINGA sent...\n");
2808 TREEVIEW_SendTreeviewNotify (
2815 TRACE(" TVN_ITEMEXPANDEDA sent...\n");
2820 /* this item has already been expanded */
2821 wineItem->state |= TVIS_EXPANDED;
2825 case TVE_EXPANDPARTIAL:
2826 TRACE(" case TVE_EXPANDPARTIAL\n");
2827 FIXME("TVE_EXPANDPARTIAL not implemented\n");
2828 wineItem->state ^=TVIS_EXPANDED;
2829 wineItem->state |=TVIS_EXPANDEDONCE;
2833 TRACE("Exiting, Item %d state is now %d...\n",
2837 TREEVIEW_QueueRefresh (hwnd);
2843 static TREEVIEW_ITEM *
2844 TREEVIEW_HitTestPoint (HWND hwnd, POINT pt)
2846 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2847 TREEVIEW_ITEM *wineItem;
2850 GetClientRect (hwnd, &rect);
2852 if (!infoPtr->firstVisible) return NULL;
2854 wineItem=&infoPtr->items [(INT)infoPtr->firstVisible];
2856 while ((wineItem!=NULL) && (pt.y > wineItem->rect.bottom))
2857 wineItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
2869 TREEVIEW_HitTest (HWND hwnd, LPARAM lParam)
2871 LPTVHITTESTINFO lpht=(LPTVHITTESTINFO) lParam;
2872 TREEVIEW_ITEM *wineItem;
2876 GetClientRect (hwnd, &rect);
2880 if (x < rect.left) status|=TVHT_TOLEFT;
2881 if (x > rect.right) status|=TVHT_TORIGHT;
2882 if (y < rect.top ) status|=TVHT_ABOVE;
2883 if (y > rect.bottom) status|=TVHT_BELOW;
2890 wineItem=TREEVIEW_HitTestPoint (hwnd, lpht->pt);
2892 lpht->flags=TVHT_NOWHERE;
2898 if (x < wineItem->expandBox.left) {
2899 lpht->flags |= TVHT_ONITEMINDENT;
2902 if ( PtInRect ( &wineItem->expandBox, lpht->pt)) {
2903 lpht->flags |= TVHT_ONITEMBUTTON;
2906 if ( PtInRect ( &wineItem->bitmap, lpht->pt)) {
2907 lpht->flags |= TVHT_ONITEMICON;
2910 if ( PtInRect ( &wineItem->statebitmap, lpht->pt)) {
2911 lpht->flags |= TVHT_ONITEMSTATEICON;
2914 if ( PtInRect ( &wineItem->text, lpht->pt)) {
2915 lpht->flags |= TVHT_ONITEMLABEL;
2919 lpht->flags|=TVHT_ONITEMRIGHT;
2923 lpht->hItem=wineItem->hItem;
2924 TRACE ("(%ld,%ld):result %x\n",lpht->pt.x,lpht->pt.y,lpht->flags);
2926 return (LRESULT) wineItem->hItem;
2930 TREEVIEW_EndEditLabelNow (HWND hwnd, WPARAM wParam, LPARAM lParam)
2932 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2933 TREEVIEW_ITEM *editedItem = TREEVIEW_ValidItem (infoPtr, infoPtr->editItem);
2934 BOOL bRevert = (BOOL)wParam;
2935 BOOL bReturn = ! bRevert;
2940 if ( ! (BOOL)wParam ) /* wParam is set to true to cancel the edition */
2942 if ( TREEVIEW_SendDispInfoNotify( /* return true to cancel edition */
2953 if (bRevert == FALSE) /* Apply the changes */
2956 int iLength = GetWindowTextA(infoPtr->hwndEdit, tmpText, 1023);
2961 ERR("Problem retreiving new item label.");
2963 else if (iLength >= 1023)
2966 "Insuficient space to retrieve new item label, new label ignored.");
2971 * notify our parent with the new string
2973 tvdi.hdr.hwndFrom = hwnd;
2974 tvdi.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2975 tvdi.hdr.code = TVN_ENDLABELEDITA;
2976 tvdi.item.hItem = editedItem->hItem;
2977 tvdi.item.lParam = editedItem->lParam;
2978 tvdi.item.mask = TVIF_TEXT|TVIF_HANDLE|TVIF_PARAM;
2979 tvdi.item.pszText = tmpText;
2984 (WPARAM)tvdi.hdr.idFrom,
2987 if (editedItem->pszText != LPSTR_TEXTCALLBACKA)
2989 if (strcmp( tmpText, editedItem->pszText ) == 0)
2990 /* Do nothing if the label has not changed */
2994 LPSTR tmpLabel = COMCTL32_Alloc( iLength+1 );
2996 if ( tmpLabel == NULL )
2998 "OutOfMemory, cannot allocate space for label");
3001 COMCTL32_Free(editedItem->pszText);
3002 editedItem->pszText = tmpLabel;
3003 lstrcpyA( editedItem->pszText, tmpText);
3011 * This is a callback string so we need
3012 * to inform the parent that the string
3016 tvdi.hdr.hwndFrom = hwnd;
3017 tvdi.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
3018 tvdi.hdr.code = TVN_SETDISPINFOA;
3019 tvdi.item.mask = TVIF_TEXT;
3020 tvdi.item.pszText = tmpText;
3025 (WPARAM)tvdi.hdr.idFrom,
3031 ShowWindow(infoPtr->hwndEdit, SW_HIDE);
3032 EnableWindow(infoPtr->hwndEdit, FALSE);
3034 /* update the window to eliminate fragments and the like */
3035 TreeView_GetItemRect(hwnd,infoPtr->editItem,&itemRect,FALSE);
3036 RedrawWindow(hwnd,&itemRect,NULL,RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW);
3038 infoPtr->editItem = 0;
3046 TREEVIEW_LButtonDoubleClick (HWND hwnd, WPARAM wParam, LPARAM lParam)
3048 TREEVIEW_ITEM *wineItem;
3052 pt.x = (INT)LOWORD(lParam);
3053 pt.y = (INT)HIWORD(lParam);
3056 wineItem=TREEVIEW_HitTestPoint (hwnd, pt);
3057 if (!wineItem) return 0;
3058 TRACE("item %d \n",(INT)wineItem->hItem);
3060 if (TREEVIEW_SendSimpleNotify (hwnd, NM_DBLCLK)!=TRUE) { /* FIXME!*/
3061 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) wineItem->hItem);
3068 TREEVIEW_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
3070 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3074 ht.pt.x = (INT)LOWORD(lParam);
3075 ht.pt.y = (INT)HIWORD(lParam);
3078 iItem=TREEVIEW_HitTest (hwnd, (LPARAM) &ht);
3079 TRACE("item %d \n",iItem);
3081 if (ht.flags & TVHT_ONITEMBUTTON) {
3082 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) iItem);
3086 infoPtr->uInternalStatus|=TV_LDRAG;
3093 TREEVIEW_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
3095 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3097 TREEVIEW_ITEM *wineItem;
3100 ht.pt.x = (INT)LOWORD(lParam);
3101 ht.pt.y = (INT)HIWORD(lParam);
3105 /* Return true to cancel default behaviour */
3106 if ( TREEVIEW_SendSimpleNotify (hwnd, NM_CLICK) )
3110 iItem = TREEVIEW_HitTest (hwnd, (LPARAM) &ht);
3111 TRACE ("%d\n",iItem);
3115 wineItem = TREEVIEW_ValidItem(infoPtr, (HTREEITEM)iItem);
3117 infoPtr->uInternalStatus &= ~(TV_LDRAG | TV_LDRAGGING);
3120 * If the style allow editing and the node is already selected
3121 * and the click occured on the item label...
3123 if ( ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_EDITLABELS ) &&
3124 ( wineItem->state & TVIS_SELECTED ) &&
3125 ( ht.flags & TVHT_ONITEMLABEL ))
3127 if ( infoPtr->editItem == 0 ) /* If we are not curently editing */
3129 if ( TREEVIEW_SendDispInfoNotify( /* Return true to cancel edition */
3132 TVN_BEGINLABELEDITA,
3138 TRACE("Edit started for %s.\n", wineItem->pszText);
3139 infoPtr->editItem = wineItem->hItem;
3142 * It is common practice for a windows program to get this
3143 * edit control and then subclass it. It is assumed that a
3144 * new edit control is given every time.
3146 * As a result some programs really mess up the edit control
3147 * so we need to destory our old edit control and create a new
3148 * one. Recycling would be nice but we would need to reset
3149 * everything. So recreating may just be easyier
3152 DestroyWindow(infoPtr->hwndEdit);
3153 infoPtr->hwndEdit = CreateWindowExA (
3157 WS_CHILD | WS_BORDER | ES_AUTOHSCROLL |
3158 ES_WANTRETURN | ES_LEFT,
3161 0,0,0); /* FIXME: (HMENU)IDTVEDIT,pcs->hInstance,0);*/
3166 (LONG) TREEVIEW_Edit_SubclassProc);
3169 SendMessageA ( infoPtr->hwndEdit, WM_SETFONT, infoPtr->hFont, FALSE);
3174 wineItem->text.left - 2,
3175 wineItem->text.top - 1,
3176 wineItem->text.right - wineItem->text.left + 20 ,
3177 wineItem->text.bottom - wineItem->text.top + 3,
3180 SetWindowTextA( infoPtr->hwndEdit, wineItem->pszText );
3181 SendMessageA ( infoPtr->hwndEdit, EM_SETSEL, 0, -1 );
3182 SetFocus ( infoPtr->hwndEdit);
3183 ShowWindow ( infoPtr->hwndEdit, SW_SHOW);
3186 else if ( infoPtr->editItem != 0 ) /* If we are curently editing */
3188 TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
3190 else if ( ht.flags & (TVHT_ONITEMLABEL | TVHT_ONITEMICON))
3192 TREEVIEW_DoSelectItem ( hwnd, TVGN_CARET, (HTREEITEM)iItem, TVC_BYMOUSE);
3195 if (ht.flags & TVHT_ONITEMSTATEICON) {
3196 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
3199 if (dwStyle & TVS_CHECKBOXES) { /* TVS_CHECKBOXES requires _us_ */
3200 int state; /* to toggle the current state */
3201 state=1-(wineItem->state>>12);
3202 TRACE ("state:%x\n", state);
3203 wineItem->state&= ~TVIS_STATEIMAGEMASK;
3204 wineItem->state|=state<<12;
3205 TRACE ("state:%x\n", wineItem->state);
3206 TREEVIEW_QueueRefresh (hwnd);
3214 TREEVIEW_RButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
3216 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3219 infoPtr->uInternalStatus|=TV_RDRAG;
3224 TREEVIEW_RButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
3226 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3229 if (TREEVIEW_SendSimpleNotify (hwnd, NM_RCLICK)) return 0;
3230 infoPtr->uInternalStatus&= ~(TV_RDRAG | TV_RDRAGGING);
3236 TREEVIEW_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
3238 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3239 TREEVIEW_ITEM *hotItem;
3242 pt.x=(INT) LOWORD (lParam);
3243 pt.y=(INT) HIWORD (lParam);
3244 hotItem=TREEVIEW_HitTestPoint (hwnd, pt);
3245 if (!hotItem) return 0;
3246 infoPtr->focusItem=hotItem->hItem;
3248 if ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_DISABLEDRAGDROP) return 0;
3250 if (infoPtr->uInternalStatus & TV_LDRAG) {
3251 TREEVIEW_SendTreeviewDnDNotify (hwnd, TVN_BEGINDRAGA, hotItem->hItem, pt);
3252 infoPtr->uInternalStatus &= ~TV_LDRAG;
3253 infoPtr->uInternalStatus |= TV_LDRAGGING;
3254 infoPtr->dropItem=hotItem->hItem;
3258 if (infoPtr->uInternalStatus & TV_RDRAG) {
3259 TREEVIEW_SendTreeviewDnDNotify (hwnd, TVN_BEGINRDRAGA, hotItem->hItem, pt);
3260 infoPtr->uInternalStatus &= ~TV_RDRAG;
3261 infoPtr->uInternalStatus |= TV_RDRAGGING;
3262 infoPtr->dropItem=hotItem->hItem;
3271 TREEVIEW_CreateDragImage (HWND hwnd, WPARAM wParam, LPARAM lParam)
3273 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3274 TREEVIEW_ITEM *dragItem;
3278 HBITMAP hbmp,hOldbmp;
3285 if (!(infoPtr->himlNormal)) return 0;
3286 dragItem=TREEVIEW_ValidItem (infoPtr, (HTREEITEM) lParam);
3288 if (!dragItem) return 0;
3290 if (dragItem->pszText==LPSTR_TEXTCALLBACKA) {
3291 TREEVIEW_SendDispInfoNotify (hwnd, dragItem, TVN_GETDISPINFOA, TVIF_TEXT);
3293 itemtxt=dragItem->pszText;
3295 hwtop=GetDesktopWindow ();
3296 htopdc= GetDC (hwtop);
3297 hdc=CreateCompatibleDC (htopdc);
3299 hOldFont=SelectObject (hdc, infoPtr->hFont);
3300 GetTextExtentPoint32A (hdc, itemtxt, lstrlenA (itemtxt), &size);
3301 TRACE("%d %d %s %d\n",size.cx,size.cy,itemtxt,lstrlenA(itemtxt));
3302 hbmp=CreateCompatibleBitmap (htopdc, size.cx, size.cy);
3303 hOldbmp=SelectObject (hdc, hbmp);
3305 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &cy);
3307 if (cy>size.cy) size.cy=cy;
3309 infoPtr->dragList=ImageList_Create (size.cx, size.cy, ILC_COLOR, 10, 10);
3310 ImageList_Draw (infoPtr->himlNormal, dragItem->iImage, hdc, 0, 0, ILD_NORMAL);
3313 ImageList_GetImageInfo (infoPtr->himlNormal, dragItem->hItem, &iminfo);
3314 ImageList_AddMasked (infoPtr->dragList, iminfo.hbmImage, CLR_DEFAULT);
3317 /* draw item text */
3319 SetRect (&rc, cx, 0, size.cx,size.cy);
3320 DrawTextA (hdc, itemtxt, lstrlenA (itemtxt), &rc, DT_LEFT);
3321 SelectObject (hdc, hOldFont);
3322 SelectObject (hdc, hOldbmp);
3324 ImageList_Add (infoPtr->dragList, hbmp, 0);
3327 DeleteObject (hbmp);
3328 ReleaseDC (hwtop, htopdc);
3330 return (LRESULT)infoPtr->dragList;
3335 TREEVIEW_DoSelectItem (HWND hwnd, INT action, HTREEITEM newSelect, INT cause)
3338 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3339 TREEVIEW_ITEM *prevItem,*wineItem;
3342 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)newSelect);
3344 TRACE("Entering item %d, flag %x, cause %x, state %d\n",
3350 if ( (wineItem) && (wineItem->parent))
3353 * If the item has a collapse parent expand the parent so he
3354 * can expose the item
3356 TREEVIEW_ITEM *parentItem = TREEVIEW_ValidItem (infoPtr, wineItem->parent);
3357 if ( !(parentItem->state & TVIS_EXPANDED))
3358 TREEVIEW_Expand (hwnd, TVE_EXPAND, (LPARAM) wineItem->parent);
3364 prevSelect=(INT)infoPtr->selectedItem;
3366 if ((HTREEITEM)prevSelect==newSelect)
3369 prevItem= TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect);
3372 if (TREEVIEW_SendTreeviewNotify(
3376 (HTREEITEM)prevSelect,
3377 (HTREEITEM)newSelect))
3378 return FALSE; /* FIXME: OK? */
3381 prevItem->state &= ~TVIS_SELECTED;
3383 wineItem->state |= TVIS_SELECTED;
3385 infoPtr->selectedItem=(HTREEITEM)newSelect;
3387 TREEVIEW_SendTreeviewNotify(
3391 (HTREEITEM)prevSelect,
3392 (HTREEITEM)newSelect);
3396 case TVGN_DROPHILITE:
3397 prevItem= TREEVIEW_ValidItem (infoPtr, infoPtr->dropItem);
3400 prevItem->state &= ~TVIS_DROPHILITED;
3402 infoPtr->dropItem=(HTREEITEM)newSelect;
3405 wineItem->state |=TVIS_DROPHILITED;
3409 case TVGN_FIRSTVISIBLE:
3410 FIXME("FIRSTVISIBLE not implemented\n");
3414 TREEVIEW_QueueRefresh (hwnd);
3416 TRACE("Leaving state %d\n", wineItem->state);
3420 /* FIXME: handle NM_KILLFocus etc */
3422 TREEVIEW_SelectItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
3425 return TREEVIEW_DoSelectItem (hwnd, wParam, (HTREEITEM) lParam, TVC_UNKNOWN);
3432 TREEVIEW_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
3435 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3437 TRACE("%x\n",infoPtr->hFont);
3438 return infoPtr->hFont;
3442 TREEVIEW_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
3445 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3448 HFONT hFont, hOldFont;
3452 TRACE("%x %lx\n",wParam, lParam);
3454 infoPtr->hFont = (HFONT)wParam;
3456 hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
3458 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
3459 logFont.lfWeight=FW_BOLD;
3460 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
3463 hOldFont = SelectObject (hdc, hFont);
3464 GetTextMetricsA (hdc, &tm);
3465 height= tm.tmHeight + tm.tmExternalLeading;
3466 if (height>infoPtr->uRealItemHeight)
3467 infoPtr->uRealItemHeight=height;
3468 SelectObject (hdc, hOldFont);
3472 TREEVIEW_QueueRefresh (hwnd);
3480 TREEVIEW_VScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
3483 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3486 TRACE("wp %x, lp %lx\n", wParam, lParam);
3487 if (!infoPtr->uInternalStatus & TV_VSCROLL) return FALSE;
3489 switch (LOWORD (wParam)) {
3491 if (!infoPtr->cy) return FALSE;
3492 infoPtr->cy -= infoPtr->uRealItemHeight;
3493 if (infoPtr->cy < 0) infoPtr->cy=0;
3496 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3497 if (infoPtr->cy == maxHeight) return FALSE;
3498 infoPtr->cy += infoPtr->uRealItemHeight;
3499 if (infoPtr->cy > maxHeight)
3500 infoPtr->cy = maxHeight;
3503 if (!infoPtr->cy) return FALSE;
3504 infoPtr->cy -= infoPtr->uVisibleHeight;
3505 if (infoPtr->cy < 0) infoPtr->cy=0;
3508 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3509 if (infoPtr->cy == maxHeight) return FALSE;
3510 infoPtr->cy += infoPtr->uVisibleHeight;
3511 if (infoPtr->cy > maxHeight)
3512 infoPtr->cy = maxHeight;
3515 infoPtr->cy = HIWORD (wParam);
3520 TREEVIEW_QueueRefresh (hwnd);
3525 TREEVIEW_HScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
3527 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3530 TRACE("wp %lx, lp %x\n", lParam, wParam);
3532 if (!infoPtr->uInternalStatus & TV_HSCROLL) return FALSE;
3534 switch (LOWORD (wParam)) {
3536 if (!infoPtr->cx) return FALSE;
3537 infoPtr->cx -= infoPtr->uRealItemHeight;
3538 if (infoPtr->cx < 0) infoPtr->cx=0;
3541 maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
3542 if (infoPtr->cx == maxWidth) return FALSE;
3543 infoPtr->cx += infoPtr->uRealItemHeight; /*FIXME */
3544 if (infoPtr->cx > maxWidth)
3545 infoPtr->cx = maxWidth;
3548 if (!infoPtr->cx) return FALSE;
3549 infoPtr->cx -= infoPtr->uVisibleWidth;
3550 if (infoPtr->cx < 0) infoPtr->cx=0;
3553 maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
3554 if (infoPtr->cx == maxWidth) return FALSE;
3555 infoPtr->cx += infoPtr->uVisibleWidth;
3556 if (infoPtr->cx > maxWidth)
3557 infoPtr->cx = maxWidth;
3560 infoPtr->cx = HIWORD (wParam);
3565 TREEVIEW_QueueRefresh (hwnd);
3569 static LRESULT TREEVIEW_MouseWheel (HWND hwnd, WPARAM wParam, LPARAM lParam)
3572 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3573 short gcWheelDelta = 0;
3574 UINT pulScrollLines = 3;
3576 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
3578 gcWheelDelta -= (short) HIWORD(wParam);
3579 pulScrollLines *= (gcWheelDelta / WHEEL_DELTA);
3581 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
3583 int wheelDy = pulScrollLines * infoPtr->uRealItemHeight;
3584 int newDy = infoPtr->cy + wheelDy;
3585 int maxDy = infoPtr->uTotalHeight - infoPtr->uVisibleHeight;
3587 if (newDy > maxDy) newDy = maxDy;
3588 if (newDy < 0) newDy = 0;
3590 if (newDy == infoPtr->cy) return TRUE;
3592 TREEVIEW_VScroll(hwnd, MAKEWPARAM(SB_THUMBTRACK,newDy),0);
3598 TREEVIEW_KeyDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
3600 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3601 HTREEITEM hNewSelection = 0;
3602 INT scrollNeeds = -1;
3603 INT cyChangeNeeds = -1;
3604 INT prevSelect = (INT)infoPtr->selectedItem;
3606 TREEVIEW_ITEM *prevItem =
3607 (prevSelect != 0 ) ?
3608 TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect) :
3611 TREEVIEW_ITEM *newItem = NULL;
3613 TRACE("%x %lx\n",wParam, lParam);
3615 if (prevSelect == 0)
3620 newItem=TREEVIEW_GetPrevListItem (infoPtr, prevItem);
3623 newItem=& infoPtr->items[(INT)infoPtr->TopRootItem];
3625 hNewSelection = newItem->hItem;
3627 if (! newItem->visible)
3628 scrollNeeds = SB_LINEUP;
3632 newItem=TREEVIEW_GetNextListItem (infoPtr, prevItem);
3637 hNewSelection = newItem->hItem;
3639 if (! newItem->visible)
3640 scrollNeeds = SB_LINEDOWN;
3645 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem];
3646 hNewSelection = newItem->hItem;
3651 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem];
3652 newItem = TREEVIEW_GetLastListItem (infoPtr, newItem);
3653 hNewSelection = newItem->hItem;
3655 if (! newItem->visible)
3656 cyChangeNeeds = infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3661 if ( (prevItem->cChildren > 0) && (prevItem->state & TVIS_EXPANDED) )
3663 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect );
3665 else if ((INT)prevItem->parent)
3667 newItem = (& infoPtr->items[(INT)prevItem->parent]);
3668 if (! newItem->visible)
3669 /* FIXME find a way to make this item the first visible... */
3672 hNewSelection = newItem->hItem;
3678 if ( ( prevItem->cChildren > 0) ||
3679 ( prevItem->cChildren == I_CHILDRENCALLBACK))
3681 if (! (prevItem->state & TVIS_EXPANDED))
3682 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect );
3685 newItem = (& infoPtr->items[(INT)prevItem->firstChild]);
3686 hNewSelection = newItem->hItem;
3693 if (! (prevItem->state & TVIS_EXPANDED))
3694 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect );
3698 if (prevItem->state & TVIS_EXPANDED)
3699 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect );
3704 newItem=TREEVIEW_GetListItem(
3707 -1*(TREEVIEW_GetVisibleCount(hwnd,0,0)-3));
3711 hNewSelection = newItem->hItem;
3713 if (! newItem->visible)
3714 scrollNeeds = SB_PAGEUP;
3719 newItem=TREEVIEW_GetListItem(
3722 TREEVIEW_GetVisibleCount(hwnd,0,0)-3);
3727 hNewSelection = newItem->hItem;
3729 if (! newItem->visible)
3730 scrollNeeds = SB_PAGEDOWN;
3739 FIXME("%x not implemented\n", wParam);
3746 This works but does not send notification...
3748 prevItem->state &= ~TVIS_SELECTED;
3749 newItem->state |= TVIS_SELECTED;
3750 infoPtr->selectedItem = hNewSelection;
3751 TREEVIEW_QueueRefresh (hwnd);
3754 if ( TREEVIEW_DoSelectItem(
3757 (HTREEITEM)hNewSelection,
3760 /* If selection change is allowed for the new item, perform scrolling */
3761 if (scrollNeeds != -1)
3762 TREEVIEW_VScroll(hwnd, scrollNeeds, 0);
3764 if (cyChangeNeeds != -1)
3765 infoPtr->cy = cyChangeNeeds;
3767 /* FIXME: Something happen in the load the in the two weeks before
3768 april 1st 1999 which makes this SetFocus mandatory otherwise, the focus
3769 is lost... However the SetFocus should not be required...*/
3780 TREEVIEW_GetScrollTime (HWND hwnd)
3782 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3784 return infoPtr->uScrollTime;
3789 TREEVIEW_SetScrollTime (HWND hwnd, UINT uScrollTime)
3791 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3792 UINT uOldScrollTime = infoPtr->uScrollTime;
3794 infoPtr->uScrollTime = min (uScrollTime, 100);
3796 return uOldScrollTime;
3800 static LRESULT WINAPI
3801 TREEVIEW_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3803 if (uMsg==WM_CREATE)
3804 return TREEVIEW_Create (hwnd, wParam, lParam);
3806 if (!TREEVIEW_GetInfoPtr(hwnd))
3807 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
3811 case TVM_INSERTITEMA:
3812 return TREEVIEW_InsertItemA (hwnd, wParam, lParam);
3814 case TVM_INSERTITEMW:
3815 return TREEVIEW_InsertItemW(hwnd,wParam,lParam);;
3817 case TVM_DELETEITEM:
3818 return TREEVIEW_DeleteItem (hwnd, wParam, lParam);
3821 return TREEVIEW_Expand (hwnd, wParam, lParam);
3823 case TVM_GETITEMRECT:
3824 return TREEVIEW_GetItemRect (hwnd, wParam, lParam);
3827 return TREEVIEW_GetCount (hwnd, wParam, lParam);
3830 return TREEVIEW_GetIndent (hwnd);
3833 return TREEVIEW_SetIndent (hwnd, wParam);
3835 case TVM_GETIMAGELIST:
3836 return TREEVIEW_GetImageList (hwnd, wParam, lParam);
3838 case TVM_SETIMAGELIST:
3839 return TREEVIEW_SetImageList (hwnd, wParam, lParam);
3841 case TVM_GETNEXTITEM:
3842 return TREEVIEW_GetNextItem (hwnd, wParam, lParam);
3844 case TVM_SELECTITEM:
3845 return TREEVIEW_SelectItem (hwnd, wParam, lParam);
3848 return TREEVIEW_GetItemA (hwnd, wParam, lParam);
3851 FIXME("Unimplemented msg TVM_GETITEMW\n");
3855 return TREEVIEW_SetItemA (hwnd, wParam, lParam);
3858 FIXME("Unimplemented msg TVM_SETITEMW\n");
3861 case TVM_EDITLABELA:
3862 FIXME("Unimplemented msg TVM_EDITLABELA \n");
3865 case TVM_EDITLABELW:
3866 FIXME("Unimplemented msg TVM_EDITLABELW \n");
3869 case TVM_GETEDITCONTROL:
3870 return TREEVIEW_GetEditControl (hwnd);
3872 case TVM_GETVISIBLECOUNT:
3873 return TREEVIEW_GetVisibleCount (hwnd, wParam, lParam);
3876 return TREEVIEW_HitTest (hwnd, lParam);
3878 case TVM_CREATEDRAGIMAGE:
3879 return TREEVIEW_CreateDragImage (hwnd, wParam, lParam);
3881 case TVM_SORTCHILDREN:
3882 return TREEVIEW_SortChildren (hwnd, wParam, lParam);
3884 case TVM_ENSUREVISIBLE:
3885 FIXME("Unimplemented msg TVM_ENSUREVISIBLE\n");
3888 case TVM_SORTCHILDRENCB:
3889 return TREEVIEW_SortChildrenCB(hwnd, wParam, lParam);
3891 case TVM_ENDEDITLABELNOW:
3892 return TREEVIEW_EndEditLabelNow (hwnd, wParam, lParam);
3894 case TVM_GETISEARCHSTRINGA:
3895 FIXME("Unimplemented msg TVM_GETISEARCHSTRINGA\n");
3898 case TVM_GETISEARCHSTRINGW:
3899 FIXME("Unimplemented msg TVM_GETISEARCHSTRINGW\n");
3902 case TVM_GETTOOLTIPS:
3903 return TREEVIEW_GetToolTips (hwnd);
3905 case TVM_SETTOOLTIPS:
3906 return TREEVIEW_SetToolTips (hwnd, wParam);
3908 case TVM_SETINSERTMARK:
3909 return TREEVIEW_SetInsertMark (hwnd,wParam, lParam);
3911 case TVM_SETITEMHEIGHT:
3912 return TREEVIEW_SetItemHeight (hwnd, wParam);
3914 case TVM_GETITEMHEIGHT:
3915 return TREEVIEW_GetItemHeight (hwnd);
3917 case TVM_SETBKCOLOR:
3918 return TREEVIEW_SetBkColor (hwnd, wParam, lParam);
3920 case TVM_SETTEXTCOLOR:
3921 return TREEVIEW_SetTextColor (hwnd, wParam, lParam);
3923 case TVM_GETBKCOLOR:
3924 return TREEVIEW_GetBkColor (hwnd);
3926 case TVM_GETTEXTCOLOR:
3927 return TREEVIEW_GetTextColor (hwnd);
3929 case TVM_SETSCROLLTIME:
3930 return TREEVIEW_SetScrollTime (hwnd, (UINT)wParam);
3932 case TVM_GETSCROLLTIME:
3933 return TREEVIEW_GetScrollTime (hwnd);
3935 case TVM_GETITEMSTATE:
3936 return TREEVIEW_GetItemState (hwnd,wParam, lParam);
3938 case TVM_GETLINECOLOR:
3939 return TREEVIEW_GetLineColor (hwnd,wParam, lParam);
3941 case TVM_SETLINECOLOR:
3942 return TREEVIEW_SetLineColor (hwnd,wParam, lParam);
3944 case TVM_SETINSERTMARKCOLOR:
3945 return TREEVIEW_SetInsertMarkColor (hwnd,wParam, lParam);
3947 case TVM_GETINSERTMARKCOLOR:
3948 return TREEVIEW_GetInsertMarkColor (hwnd,wParam, lParam);
3950 case TVM_SETUNICODEFORMAT:
3951 FIXME("Unimplemented msg TVM_SETUNICODEFORMAT\n");
3954 case TVM_GETUNICODEFORMAT:
3955 FIXME("Unimplemented msg TVM_GETUNICODEFORMAT\n");
3959 return TREEVIEW_Command (hwnd, wParam, lParam);
3962 return TREEVIEW_Destroy (hwnd);
3964 /* case WM_ENABLE: */
3967 return TREEVIEW_EraseBackground (hwnd, wParam, lParam);
3970 return DLGC_WANTARROWS | DLGC_WANTCHARS;
3973 return TREEVIEW_Paint (hwnd, wParam, lParam);
3976 return TREEVIEW_GetFont (hwnd, wParam, lParam);
3979 return TREEVIEW_SetFont (hwnd, wParam, lParam);
3982 return TREEVIEW_KeyDown (hwnd, wParam, lParam);
3985 return TREEVIEW_SetFocus (hwnd, wParam, lParam);
3988 return TREEVIEW_KillFocus (hwnd, wParam, lParam);
3990 case WM_LBUTTONDOWN:
3991 return TREEVIEW_LButtonDown (hwnd, wParam, lParam);
3994 return TREEVIEW_LButtonUp (hwnd, wParam, lParam);
3996 case WM_LBUTTONDBLCLK:
3997 return TREEVIEW_LButtonDoubleClick (hwnd, wParam, lParam);
3999 case WM_RBUTTONDOWN:
4000 return TREEVIEW_RButtonDown (hwnd, wParam, lParam);
4003 return TREEVIEW_RButtonUp (hwnd, wParam, lParam);
4006 return TREEVIEW_MouseMove (hwnd, wParam, lParam);
4008 case WM_STYLECHANGED:
4009 return TREEVIEW_StyleChanged (hwnd, wParam, lParam);
4011 /* case WM_SYSCOLORCHANGE: */
4012 /* case WM_SETREDRAW: */
4015 return TREEVIEW_HandleTimer (hwnd, wParam, lParam);
4018 return TREEVIEW_Size (hwnd, wParam,lParam);
4021 return TREEVIEW_HScroll (hwnd, wParam, lParam);
4023 return TREEVIEW_VScroll (hwnd, wParam, lParam);
4026 if (wParam & (MK_SHIFT | MK_CONTROL))
4027 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
4028 return TREEVIEW_MouseWheel (hwnd, wParam, lParam);
4031 TRACE ("drawItem\n");
4032 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
4035 if (uMsg >= WM_USER)
4036 FIXME("Unknown msg %04x wp=%08x lp=%08lx\n",
4037 uMsg, wParam, lParam);
4038 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
4045 TREEVIEW_Register (void)
4051 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
4052 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
4053 wndClass.lpfnWndProc = (WNDPROC)TREEVIEW_WindowProc;
4054 wndClass.cbClsExtra = 0;
4055 wndClass.cbWndExtra = sizeof(TREEVIEW_INFO *);
4056 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
4057 wndClass.hbrBackground = 0;
4058 wndClass.lpszClassName = WC_TREEVIEWA;
4060 RegisterClassA (&wndClass);
4065 TREEVIEW_Unregister (void)
4067 UnregisterClassA (WC_TREEVIEWA, (HINSTANCE)NULL);