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;
760 ImageList_Draw ( *himlp, imageIndex, hdc, xpos-2, r.top+1, ILD_NORMAL);
761 ImageList_GetIconSize (*himlp, &cx, &cy);
762 wineItem->bitmap.left=xpos-2;
763 wineItem->bitmap.right=xpos-2+cx;
764 wineItem->bitmap.top=r.top+1;
765 wineItem->bitmap.bottom=r.top+1+cy;
772 * Display the text associated with this item
775 if ((wineItem->mask & TVIF_TEXT) && (wineItem->pszText))
777 COLORREF oldBkColor = 0;
778 COLORREF oldTextColor = 0;
784 wineItem->text.left = r.left;
785 wineItem->text.right = r.right;
786 wineItem->text.top = r.top;
787 wineItem->text.bottom= r.bottom;
789 if (wineItem->pszText== LPSTR_TEXTCALLBACKA) {
790 TRACE("LPSTR_TEXTCALLBACK\n");
791 TREEVIEW_SendDispInfoNotify (hwnd, wineItem, TVN_GETDISPINFOA, TVIF_TEXT);
794 /* Yep, there are some things that need to be straightened out here.
795 Removing the comments around the setTextColor does not give the right
796 results. Dito FillRect.
800 /* GetTextExtentPoint32A (hdc, wineItem->pszText,
801 strlen (wineItem->pszText), &size); */
803 /* FillRect ( hdc, &wineItem->text, GetSysColorBrush (infoPtr->clrBk));
807 if (!(cditem & CDRF_NOTIFYPOSTPAINT) &&
808 (wineItem->state & (TVIS_SELECTED | TVIS_DROPHILITED)) ) {
809 oldBkMode = SetBkMode (hdc, OPAQUE);
810 oldBkColor = SetBkColor (hdc, GetSysColor( COLOR_HIGHLIGHT));
811 oldTextColor = SetTextColor(hdc, GetSysColor( COLOR_HIGHLIGHTTEXT));
813 oldBkMode = SetBkMode (hdc, TRANSPARENT);
814 oldBkColor = SetBkColor (hdc, infoPtr->clrBk);
815 /* oldTextColor = SetTextColor(hdc, infoPtr->clrText); */
823 lstrlenA(wineItem->pszText),
825 uTextJustify | DT_VCENTER | DT_SINGLELINE );
827 /* Obtain the text coordinate */
831 lstrlenA(wineItem->pszText),
833 uTextJustify | DT_VCENTER | DT_SINGLELINE | DT_CALCRECT);
835 /* Restore the hdc state */
836 SetTextColor( hdc, oldTextColor);
838 if (oldBkMode != TRANSPARENT)
839 SetBkMode(hdc, oldBkMode);
840 if (wineItem->state & (TVIS_SELECTED | TVIS_DROPHILITED))
841 SetBkColor (hdc, oldBkColor);
843 /* Draw the box arround the selected item */
844 if (wineItem->state & TVIS_SELECTED )
846 HPEN hNewPen = CreatePen(PS_DOT, 0, GetSysColor(COLOR_WINDOWTEXT) );
847 HPEN hOldPen = SelectObject( hdc, hNewPen );
850 points[0].x = wineItem->text.left-1;
851 points[0].y = wineItem->text.top+1;
852 points[1].x = wineItem->text.right;
853 points[1].y = wineItem->text.top+1;
854 points[2].x = wineItem->text.right;
855 points[2].y = wineItem->text.bottom;
856 points[3].x = wineItem->text.left-1;
857 points[3].y = wineItem->text.bottom;
859 Polyline (hdc,points,4);
861 DeleteObject(hNewPen);
862 SelectObject(hdc, hOldPen);
866 /* Draw insertion mark if necessary */
868 if (infoPtr->insertMarkItem)
869 TRACE ("item:%d,mark:%d\n", (int)wineItem->hItem,
870 (int) infoPtr->insertMarkItem);
871 if (wineItem->hItem==infoPtr->insertMarkItem) {
872 HPEN hNewPen, hOldPen;
875 hNewPen = CreatePen(PS_SOLID, 2, infoPtr->clrInsertMark);
876 hOldPen = SelectObject( hdc, hNewPen );
878 if (infoPtr->insertBeforeorAfter)
879 offset=wineItem->text.top+1;
881 offset=wineItem->text.bottom-1;
883 MoveToEx (hdc, wineItem->text.left, offset-3, NULL);
884 LineTo (hdc, wineItem->text.left, offset+3);
886 MoveToEx (hdc, wineItem->text.left, offset, NULL);
887 LineTo (hdc, r.right-2, offset);
889 MoveToEx (hdc, r.right-2, offset+3, NULL);
890 LineTo (hdc, r.right-2, offset-3);
892 DeleteObject(hNewPen);
894 SelectObject(hdc, hOldPen);
897 if (cditem & CDRF_NOTIFYPOSTPAINT) {
898 cditem=TREEVIEW_SendCustomDrawItemNotify
899 (hwnd, hdc, wineItem, CDDS_ITEMPOSTPAINT);
900 TRACE("postpaint:cditem-app returns 0x%x\n",cditem);
903 SelectObject (hdc, hOldFont);
907 TREEVIEW_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
909 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
910 TREEVIEW_ITEM *wineItem;
912 LPRECT lpRect = (LPRECT)lParam;
917 * validate parameters
922 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
924 TREEVIEW_Refresh (hwnd, hdc); /* we want a rect for the current view */
930 * retrieve the item ptr
932 iItem = (HTREEITEM *) lParam;
933 wineItem = TREEVIEW_ValidItem (infoPtr, *iItem);
934 if ((!wineItem) || (!wineItem->visible))
938 * If wParam is TRUE return the text size otherwise return
939 * the whole item size
942 lpRect->left = wineItem->text.left;
943 lpRect->right = wineItem->text.right;
944 lpRect->bottom = wineItem->text.bottom;
945 lpRect->top = wineItem->text.top;
947 lpRect->left = wineItem->rect.left;
948 lpRect->right = wineItem->rect.right;
949 lpRect->bottom = wineItem->rect.bottom;
950 lpRect->top = wineItem->rect.top;
953 TRACE("[L:%d R:%d T:%d B:%d]\n",
954 lpRect->left,lpRect->right,
955 lpRect->top,lpRect->bottom);
961 TREEVIEW_GetVisibleCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
964 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
966 return (LRESULT) infoPtr->uVisibleHeight / infoPtr->uRealItemHeight;
972 TREEVIEW_SetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
974 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
975 TREEVIEW_ITEM *wineItem;
979 tvItem=(LPTVITEMEXA) lParam;
980 iItem=(INT)tvItem->hItem;
981 TRACE("item %d,mask %x\n",iItem,tvItem->mask);
983 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
984 if (!wineItem) return FALSE;
986 if (tvItem->mask & TVIF_CHILDREN) {
987 wineItem->cChildren=tvItem->cChildren;
990 if (tvItem->mask & TVIF_IMAGE) {
991 wineItem->iImage=tvItem->iImage;
994 if (tvItem->mask & TVIF_INTEGRAL) {
995 wineItem->iIntegral=tvItem->iIntegral;
998 if (tvItem->mask & TVIF_PARAM) {
999 wineItem->lParam=tvItem->lParam;
1002 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
1003 wineItem->iSelectedImage=tvItem->iSelectedImage;
1006 if (tvItem->mask & TVIF_STATE) {
1007 TRACE ("prevstate,state,mask:%x,%x,%x\n",wineItem->state,tvItem->state,
1009 wineItem->state&= ~tvItem->stateMask;
1010 wineItem->state|= (tvItem->state & tvItem->stateMask);
1011 wineItem->stateMask|= tvItem->stateMask;
1014 if (tvItem->mask & TVIF_TEXT) {
1015 if (tvItem->pszText!=LPSTR_TEXTCALLBACKA) {
1016 len=lstrlenA (tvItem->pszText);
1017 if (len>wineItem->cchTextMax)
1018 wineItem->pszText= COMCTL32_ReAlloc (wineItem->pszText, len+1);
1019 lstrcpynA (wineItem->pszText, tvItem->pszText,len+1);
1021 if (wineItem->cchTextMax) {
1022 COMCTL32_Free (wineItem->pszText);
1023 wineItem->cchTextMax=0;
1025 wineItem->pszText=LPSTR_TEXTCALLBACKA;
1029 wineItem->mask |= tvItem->mask;
1035 TREEVIEW_GetItemState (HWND hwnd, WPARAM wParam, LPARAM lParam)
1038 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1039 TREEVIEW_ITEM *wineItem;
1042 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)wParam);
1043 if (!wineItem) return 0;
1045 return (wineItem->state & lParam);
1052 TREEVIEW_Refresh (HWND hwnd, HDC hdc)
1054 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1058 INT iItem, indent, x, y, height, itemHeight;
1059 INT viewtop,viewbottom,viewleft,viewright;
1060 TREEVIEW_ITEM *wineItem, *prevItem;
1065 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
1066 KillTimer (hwnd, TV_REFRESH_TIMER);
1067 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
1071 GetClientRect (hwnd, &rect);
1072 if ((rect.left-rect.right ==0) || (rect.top-rect.bottom==0)) return;
1076 infoPtr->cdmode=TREEVIEW_SendCustomDrawNotify(hwnd,CDDS_PREPAINT,hdc,rect);
1078 if (infoPtr->cdmode==CDRF_SKIPDEFAULT) return;
1080 infoPtr->uVisibleHeight= rect.bottom-rect.top;
1081 infoPtr->uVisibleWidth= rect.right-rect.left;
1083 viewtop=infoPtr->cy;
1084 viewbottom=infoPtr->cy + rect.bottom-rect.top;
1085 viewleft=infoPtr->cx;
1086 viewright=infoPtr->cx + rect.right-rect.left;
1088 TRACE("[%d %d %d %d]\n",viewtop,viewbottom,viewleft,viewright);
1090 /* draw background */
1092 hbrBk = CreateSolidBrush (infoPtr->clrBk);
1093 FillRect(hdc, &rect, hbrBk);
1094 DeleteObject(hbrBk);
1096 ImageList_GetIconSize (infoPtr->himlNormal, &x, &itemHeight);
1097 if (infoPtr->uItemHeight>itemHeight)
1098 itemHeight=infoPtr->uItemHeight;
1100 GetTextMetricsA (hdc, &tm);
1101 if ((tm.tmHeight + tm.tmExternalLeading) > itemHeight)
1102 itemHeight=tm.tmHeight + tm.tmExternalLeading;
1104 infoPtr->uRealItemHeight=itemHeight;
1106 iItem=(INT)infoPtr->TopRootItem;
1107 infoPtr->firstVisible=0;
1114 wineItem= & infoPtr->items[iItem];
1115 wineItem->iLevel=indent;
1117 /* FIXME: remove this in later stage */
1119 if (wineItem->pszText!=LPSTR_TEXTCALLBACK32A)
1120 TRACE (treeview, "%d %d [%d %d %d %d] (%s)\n",y,x,
1121 wineItem->rect.top, wineItem->rect.bottom,
1122 wineItem->rect.left, wineItem->rect.right,
1125 TRACE (treeview, "%d [%d %d %d %d] (CALLBACK)\n",
1127 wineItem->rect.top, wineItem->rect.bottom,
1128 wineItem->rect.left, wineItem->rect.right);
1131 height=itemHeight * wineItem->iIntegral +1;
1132 if ((y >= viewtop) && (y <= viewbottom) &&
1133 (x >= viewleft ) && (x <= viewright)) {
1134 wineItem->visible = TRUE;
1135 wineItem->rect.top = y - infoPtr->cy + rect.top;
1136 wineItem->rect.bottom = wineItem->rect.top + height ;
1137 wineItem->rect.left = x - infoPtr->cx + rect.left;
1138 wineItem->rect.right = rect.right;
1139 if (!infoPtr->firstVisible)
1140 infoPtr->firstVisible=wineItem->hItem;
1141 TREEVIEW_DrawItem (hwnd, hdc, wineItem);
1144 wineItem->visible = FALSE;
1145 wineItem->rect.left = wineItem->rect.top = 0;
1146 wineItem->rect.right= wineItem->rect.bottom = 0;
1147 wineItem->text.left = wineItem->text.top = 0;
1148 wineItem->text.right= wineItem->text.bottom = 0;
1151 /* look up next item */
1153 if ((wineItem->firstChild) && (wineItem->state & TVIS_EXPANDED)) {
1154 iItem=(INT)wineItem->firstChild;
1156 x+=infoPtr->uIndent;
1157 if (x>infoPtr->uTotalWidth)
1158 infoPtr->uTotalWidth=x;
1161 iItem=(INT)wineItem->sibling;
1162 while ((!iItem) && (indent>0)) {
1164 x-=infoPtr->uIndent;
1165 wineItem=&infoPtr->items[(INT)wineItem->parent];
1166 iItem=(INT)wineItem->sibling;
1172 /* FIXME: infoPtr->uTotalWidth should also take item label into account */
1173 /* FIXME: or should query item sizes (ie check CDRF_NEWFONT) */
1175 infoPtr->uTotalHeight=y;
1176 if (y >= (viewbottom-viewtop)) {
1177 if (!(infoPtr->uInternalStatus & TV_VSCROLL))
1178 ShowScrollBar (hwnd, SB_VERT, TRUE);
1179 infoPtr->uInternalStatus |=TV_VSCROLL;
1180 SetScrollRange (hwnd, SB_VERT, 0,
1181 y - infoPtr->uVisibleHeight, FALSE);
1182 SetScrollPos (hwnd, SB_VERT, infoPtr->cy, TRUE);
1185 if (infoPtr->uInternalStatus & TV_VSCROLL)
1186 ShowScrollBar (hwnd, SB_VERT, FALSE);
1187 infoPtr->uInternalStatus &= ~TV_VSCROLL;
1191 if (infoPtr->cdmode & CDRF_NOTIFYPOSTPAINT)
1192 infoPtr->cdmode=TREEVIEW_SendCustomDrawNotify
1193 (hwnd, CDDS_POSTPAINT, hdc, rect);
1200 TREEVIEW_HandleTimer (HWND hwnd, WPARAM wParam, LPARAM lParam)
1202 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1204 TRACE(" %d\n",wParam);
1207 case TV_REFRESH_TIMER:
1208 KillTimer (hwnd, TV_REFRESH_TIMER);
1209 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
1210 InvalidateRect(hwnd, NULL, FALSE);
1213 KillTimer (hwnd, TV_EDIT_TIMER);
1214 infoPtr->Timer &= ~TV_EDIT_TIMER_SET;
1217 ERR("got unknown timer\n");
1225 TREEVIEW_QueueRefresh (HWND hwnd)
1228 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1231 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
1232 KillTimer (hwnd, TV_REFRESH_TIMER);
1235 SetTimer (hwnd, TV_REFRESH_TIMER, TV_REFRESH_DELAY, 0);
1236 infoPtr->Timer|=TV_REFRESH_TIMER_SET;
1242 TREEVIEW_GetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1244 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1246 TREEVIEW_ITEM *wineItem;
1249 tvItem=(LPTVITEMEXA) lParam;
1250 iItem=(INT)tvItem->hItem;
1252 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1253 if (!wineItem) return FALSE;
1255 if (tvItem->mask & TVIF_CHILDREN) {
1256 if (TVIF_CHILDREN==I_CHILDRENCALLBACK)
1257 FIXME("I_CHILDRENCALLBACK not supported\n");
1258 tvItem->cChildren=wineItem->cChildren;
1261 if (tvItem->mask & TVIF_HANDLE) {
1262 tvItem->hItem=wineItem->hItem;
1265 if (tvItem->mask & TVIF_IMAGE) {
1266 tvItem->iImage=wineItem->iImage;
1269 if (tvItem->mask & TVIF_INTEGRAL) {
1270 tvItem->iIntegral=wineItem->iIntegral;
1273 /* undocumented: windows ignores TVIF_PARAM and
1274 * always sets lParam
1276 tvItem->lParam=wineItem->lParam;
1278 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
1279 tvItem->iSelectedImage=wineItem->iSelectedImage;
1282 if (tvItem->mask & TVIF_STATE) {
1283 tvItem->state=wineItem->state & tvItem->stateMask;
1286 if (tvItem->mask & TVIF_TEXT) {
1287 if (wineItem->pszText == LPSTR_TEXTCALLBACKA) {
1288 tvItem->pszText = LPSTR_TEXTCALLBACKA; /* FIXME:send notification? */
1289 ERR(" GetItem called with LPSTR_TEXTCALLBACK\n");
1291 else if (wineItem->pszText) {
1292 lstrcpynA (tvItem->pszText, wineItem->pszText, tvItem->cchTextMax);
1296 TRACE("item %d<%p>, txt %p, img %p, action %x\n",
1297 iItem, tvItem, tvItem->pszText, &tvItem->iImage, tvItem->mask);
1304 /* FIXME: check implementation of TVGN_NEXT/TVGN_NEXTVISIBLE */
1307 TREEVIEW_GetNextItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
1310 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1311 TREEVIEW_ITEM *wineItem, *returnItem;
1312 INT iItem = (INT)lParam, retval = 0, flag = (INT)wParam;
1317 retval = (INT)infoPtr->TopRootItem;
1321 retval = (INT)infoPtr->selectedItem;
1324 case TVGN_FIRSTVISIBLE: /* FIXME:we should only recalculate, not redraw */
1326 TREEVIEW_Refresh (hwnd, hdc);
1327 ReleaseDC(hwnd,hdc);
1328 retval = (INT)infoPtr->firstVisible;
1331 case TVGN_DROPHILITE:
1332 retval = (INT)infoPtr->dropItem;
1336 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1337 retval = wineItem ? (INT)wineItem->sibling : 0;
1341 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1342 retval = wineItem ? (INT)wineItem->upsibling : 0;
1346 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1347 retval = wineItem ? (INT)wineItem->parent : 0;
1351 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1352 retval = wineItem ? (INT)wineItem->firstChild : 0;
1355 case TVGN_LASTVISIBLE:
1356 if((wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem))) {
1357 returnItem = TREEVIEW_GetLastListItem (infoPtr,wineItem);
1358 retval = returnItem ? (INT)returnItem->hItem : 0;
1362 case TVGN_NEXTVISIBLE:
1363 if((wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem))) {
1364 returnItem = TREEVIEW_GetNextListItem (infoPtr,wineItem);
1365 retval = returnItem ? (INT)returnItem->hItem : 0;
1369 case TVGN_PREVIOUSVISIBLE:
1370 if((wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem))) {
1371 returnItem = TREEVIEW_GetPrevListItem (infoPtr, wineItem);
1372 retval = returnItem ? (INT)returnItem->hItem : 0;
1377 FIXME("Unknown msg %x,item %x\n", flag,iItem);
1381 TRACE("flags %x, item %d returns %d\n", flag, iItem, retval);
1387 TREEVIEW_GetCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
1389 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1391 TRACE(" %d\n",infoPtr->uNumItems);
1392 return (LRESULT) infoPtr->uNumItems;
1395 /***************************************************************************
1396 * This method does the chaining of the insertion of a treeview item
1398 * If parent is NULL, we're inserting at the root of the list.
1400 static void TREEVIEW_InsertBefore(
1401 TREEVIEW_INFO *infoPtr,
1402 TREEVIEW_ITEM *newItem,
1403 TREEVIEW_ITEM *sibling,
1404 TREEVIEW_ITEM *parent)
1406 HTREEITEM siblingHandle = 0;
1407 HTREEITEM upSiblingHandle = 0;
1408 TREEVIEW_ITEM *upSibling = NULL;
1410 if (newItem == NULL)
1411 ERR("NULL newItem, impossible condition\n");
1413 if (sibling != NULL) /* Insert before this sibling for this parent */
1415 /* Store the new item sibling up sibling and sibling tem handle */
1416 siblingHandle = sibling->hItem;
1417 upSiblingHandle = sibling->upsibling;
1418 /* As well as a pointer to the upsibling sibling object */
1419 if ( (INT)sibling->upsibling != 0 )
1420 upSibling = &infoPtr->items[(INT)sibling->upsibling];
1422 /* Adjust the sibling pointer */
1423 sibling->upsibling = newItem->hItem;
1425 /* Adjust the new item pointers */
1426 newItem->upsibling = upSiblingHandle;
1427 newItem->sibling = siblingHandle;
1429 /* Adjust the up sibling pointer */
1430 if ( upSibling != NULL )
1431 upSibling->sibling = newItem->hItem;
1433 /* this item is the first child of this parent, adjust parent pointers */
1435 parent->firstChild = newItem->hItem;
1437 infoPtr->TopRootItem= newItem->hItem;
1439 else /* Insert as first child of this parent */
1441 parent->firstChild = newItem->hItem;
1444 /***************************************************************************
1445 * This method does the chaining of the insertion of a treeview item
1447 * If parent is NULL, we're inserting at the root of the list.
1449 static void TREEVIEW_InsertAfter(
1450 TREEVIEW_INFO *infoPtr,
1451 TREEVIEW_ITEM *newItem,
1452 TREEVIEW_ITEM *upSibling,
1453 TREEVIEW_ITEM *parent)
1455 HTREEITEM upSiblingHandle = 0;
1456 HTREEITEM siblingHandle = 0;
1457 TREEVIEW_ITEM *sibling = NULL;
1460 if (newItem == NULL)
1461 ERR("NULL newItem, impossible condition\n");
1463 if (upSibling != NULL) /* Insert after this upsibling for this parent */
1465 /* Store the new item up sibling and sibling item handle */
1466 upSiblingHandle = upSibling->hItem;
1467 siblingHandle = upSibling->sibling;
1468 /* As well as a pointer to the upsibling sibling object */
1469 if ( (INT)upSibling->sibling != 0 )
1470 sibling = &infoPtr->items[(INT)upSibling->sibling];
1472 /* Adjust the up sibling pointer */
1473 upSibling->sibling = newItem->hItem;
1475 /* Adjust the new item pointers */
1476 newItem->upsibling = upSiblingHandle;
1477 newItem->sibling = siblingHandle;
1479 /* Adjust the sibling pointer */
1480 if ( sibling != NULL )
1481 sibling->upsibling = newItem->hItem;
1484 newItem is the last of the level, nothing else to do
1487 else /* Insert as first child of this parent */
1489 parent->firstChild = newItem->hItem;
1492 /***************************************************************************
1493 * Forward the DPA local callback to the treeview owner callback
1495 static INT WINAPI TREEVIEW_CallBackCompare(
1500 /* Forward the call to the client define callback */
1501 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr((HWND)tvInfoPtr);
1502 return (infoPtr->pCallBackSort->lpfnCompare)(
1503 ((TREEVIEW_ITEM*)first)->lParam,
1504 ((TREEVIEW_ITEM*)second)->lParam,
1505 infoPtr->pCallBackSort->lParam);
1508 /***************************************************************************
1509 * Treeview native sort routine: sort on item text.
1511 static INT WINAPI TREEVIEW_SortOnName (
1516 HWND hwnd=(HWND) tvInfoPtr;
1518 TREEVIEW_ITEM *item;
1521 item=(TREEVIEW_ITEM *) first;
1522 if (item->pszText==LPSTR_TEXTCALLBACKA) {
1523 TREEVIEW_SendDispInfoNotify (hwnd, item, TVN_GETDISPINFOA, TVIF_TEXT);
1527 item=(TREEVIEW_ITEM *) second;
1528 if (item->pszText==LPSTR_TEXTCALLBACKA) {
1529 TREEVIEW_SendDispInfoNotify (hwnd, item, TVN_GETDISPINFOA, TVIF_TEXT);
1533 return -strcmp (txt1,txt2);
1536 /***************************************************************************
1537 * Setup the treeview structure with regards of the sort method
1538 * and sort the children of the TV item specified in lParam
1539 * fRecurse: currently unused. Should be zero.
1540 * parent: if pSort!=NULL, should equal pSort->hParent.
1541 * otherwise, item which child items are to be sorted.
1542 * pSort: sort method info. if NULL, sort on item text.
1543 * if non-NULL, sort on item's lParam content, and let the
1544 * application decide what that means. See also TVM_SORTCHILDRENCB.
1547 static LRESULT WINAPI TREEVIEW_Sort (
1554 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1555 TREEVIEW_ITEM *sortMe = NULL; /* Node for which we sort the children */
1557 /* Obtain the TVSORTBC struct */
1558 infoPtr->pCallBackSort = pSort;
1560 /* undocumented feature: TVI_ROOT means `sort the whole tree' */
1562 if (parent==TVI_ROOT)
1563 parent=infoPtr->TopRootItem;
1565 /* Check for a valid handle to the parent item */
1566 if (!TREEVIEW_ValidItem(infoPtr, parent))
1568 ERR ("invalid item hParent=%x\n", (INT)parent);
1572 /* Obtain the parent node to sort */
1573 sortMe = &infoPtr->items[ (INT)parent ];
1575 /* Make sure there is something to sort */
1576 if ( sortMe->cChildren > 1 )
1578 /* pointer organization */
1579 HDPA sortList = DPA_Create(sortMe->cChildren);
1580 HTREEITEM itemHandle = sortMe->firstChild;
1581 TREEVIEW_ITEM *itemPtr = & infoPtr->items[ (INT)itemHandle ];
1583 /* TREEVIEW_ITEM rechaining */
1589 /* Build the list of item to sort */
1593 sortList, /* the list */
1594 sortMe->cChildren+1, /* force the insertion to be an append */
1595 itemPtr); /* the ptr to store */
1597 /* Get the next sibling */
1598 itemHandle = itemPtr->sibling;
1599 itemPtr = & infoPtr->items[ (INT)itemHandle ];
1600 } while ( itemHandle != NULL );
1602 /* let DPA perform the sort activity */
1605 sortList, /* what */
1606 TREEVIEW_CallBackCompare, /* how */
1610 sortList, /* what */
1611 TREEVIEW_SortOnName, /* how */
1615 * Reorganized TREEVIEW_ITEM structures.
1616 * Note that we know we have at least two elements.
1619 /* Get the first item and get ready to start... */
1620 item = DPA_GetPtr(sortList, count++);
1621 while ( (nextItem = DPA_GetPtr(sortList, count++)) != NULL )
1623 /* link the two current item toghether */
1624 ((TREEVIEW_ITEM*)item)->sibling = ((TREEVIEW_ITEM*)nextItem)->hItem;
1625 ((TREEVIEW_ITEM*)nextItem)->upsibling = ((TREEVIEW_ITEM*)item)->hItem;
1627 if (prevItem == NULL) /* this is the first item, update the parent */
1629 sortMe->firstChild = ((TREEVIEW_ITEM*)item)->hItem;
1630 ((TREEVIEW_ITEM*)item)->upsibling = NULL;
1632 else /* fix the back chaining */
1634 ((TREEVIEW_ITEM*)item)->upsibling = ((TREEVIEW_ITEM*)prevItem)->hItem;
1637 /* get ready for the next one */
1642 /* the last item is pointed to by item and never has a sibling */
1643 ((TREEVIEW_ITEM*)item)->sibling = NULL;
1645 DPA_Destroy(sortList);
1653 /***************************************************************************
1654 * Setup the treeview structure with regards of the sort method
1655 * and sort the children of the TV item specified in lParam
1657 static LRESULT WINAPI TREEVIEW_SortChildrenCB(
1663 LPTVSORTCB pSort=(LPTVSORTCB) lParam;
1665 return TREEVIEW_Sort (hwnd, wParam, pSort->hParent, pSort);
1669 /***************************************************************************
1670 * Sort the children of the TV item specified in lParam.
1672 static LRESULT WINAPI TREEVIEW_SortChildren (
1677 return TREEVIEW_Sort (hwnd, (BOOL) wParam, (HTREEITEM) lParam, NULL);
1682 /* the method used below isn't the most memory-friendly, but it avoids
1683 a lot of memory reallocations */
1685 /* BTW: we waste handle 0; 0 is not an allowed handle. */
1688 TREEVIEW_InsertItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1691 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1692 TVINSERTSTRUCTA *ptdi;
1694 TREEVIEW_ITEM *wineItem, *parentItem, *prevsib, *sibItem;
1695 INT iItem,listItems,i,len;
1697 /* Item to insert */
1698 ptdi = (LPTVINSERTSTRUCTA) lParam;
1700 /* check if memory is available */
1702 if (infoPtr->uNumPtrsAlloced==0) {
1703 infoPtr->items = COMCTL32_Alloc (TVITEM_ALLOC*sizeof (TREEVIEW_ITEM));
1704 infoPtr->freeList= COMCTL32_Alloc ((1+(TVITEM_ALLOC>>5)) * sizeof (INT));
1705 infoPtr->uNumPtrsAlloced=TVITEM_ALLOC;
1706 infoPtr->TopRootItem=(HTREEITEM)1;
1710 * Reallocate contiguous space for items
1712 if (infoPtr->uNumItems == (infoPtr->uNumPtrsAlloced-1) ) {
1713 TREEVIEW_ITEM *oldItems = infoPtr->items;
1714 INT *oldfreeList = infoPtr->freeList;
1716 infoPtr->uNumPtrsAlloced*=2;
1717 infoPtr->items = COMCTL32_Alloc (infoPtr->uNumPtrsAlloced*sizeof (TREEVIEW_ITEM));
1718 infoPtr->freeList= COMCTL32_Alloc ((1+(infoPtr->uNumPtrsAlloced>>5))*sizeof (INT));
1720 memcpy (&infoPtr->items[0], &oldItems[0],
1721 infoPtr->uNumPtrsAlloced/2 * sizeof(TREEVIEW_ITEM));
1722 memcpy (&infoPtr->freeList[0], &oldfreeList[0],
1723 (infoPtr->uNumPtrsAlloced>>6) * sizeof(INT));
1725 COMCTL32_Free (oldItems);
1726 COMCTL32_Free (oldfreeList);
1730 * Reset infoPtr structure with new stat according to current TV picture
1733 infoPtr->uNumItems++;
1734 if ((INT)infoPtr->uMaxHandle==(infoPtr->uNumItems-1)) {
1735 iItem=infoPtr->uNumItems;
1736 infoPtr->uMaxHandle = (HTREEITEM)((INT)infoPtr->uMaxHandle + 1);
1737 } else { /* check freelist */
1738 for (i=0; i<=infoPtr->uNumPtrsAlloced>>5; i++) {
1739 if (infoPtr->freeList[i]) {
1740 iItem=ffs (infoPtr->freeList[i])-1;
1741 tv_clear_bit(iItem,&infoPtr->freeList[i]);
1748 if (TRACE_ON(treeview)) {
1749 for (i=0; i<=infoPtr->uNumPtrsAlloced>>5; i++)
1750 TRACE("%8x\n",infoPtr->freeList[i]);
1753 if (!iItem) ERR("Argh -- can't find free item.\n");
1756 * Find the parent item of the new item
1758 tvItem= & ptdi->DUMMYUNIONNAME.itemex;
1759 wineItem=& infoPtr->items[iItem];
1761 if ((ptdi->hParent==TVI_ROOT) || (ptdi->hParent==0)) {
1763 wineItem->parent = 0;
1764 sibItem = &infoPtr->items [(INT)infoPtr->TopRootItem];
1765 listItems = infoPtr->uNumItems;
1768 parentItem = &infoPtr->items[(INT)ptdi->hParent];
1770 /* Do the insertion here it if it's the only item of this parent */
1771 if (!parentItem->firstChild)
1772 parentItem->firstChild=(HTREEITEM)iItem;
1774 wineItem->parent = ptdi->hParent;
1775 sibItem = &infoPtr->items [(INT)parentItem->firstChild];
1776 parentItem->cChildren++;
1777 listItems = parentItem->cChildren;
1781 /* NOTE: I am moving some setup of the wineItem object that was initialy
1782 * done at the end of the function since some of the values are
1783 * required by the Callback sorting
1786 if (tvItem->mask & TVIF_TEXT)
1789 * Setup the item text stuff here since it's required by the Sort method
1790 * when the insertion are ordered
1792 if (tvItem->pszText!=LPSTR_TEXTCALLBACKA)
1794 TRACE("(%p,%s)\n", &tvItem->pszText, tvItem->pszText);
1795 len = lstrlenA (tvItem->pszText)+1;
1796 wineItem->pszText= COMCTL32_Alloc (len+1);
1797 lstrcpyA (wineItem->pszText, tvItem->pszText);
1798 wineItem->cchTextMax=len;
1802 TRACE("LPSTR_TEXTCALLBACK\n");
1803 wineItem->pszText = LPSTR_TEXTCALLBACKA;
1804 wineItem->cchTextMax = 0;
1808 if (tvItem->mask & TVIF_PARAM)
1809 wineItem->lParam=tvItem->lParam;
1812 wineItem->upsibling=0; /* needed in case we're the first item in a list */
1813 wineItem->sibling=0;
1814 wineItem->firstChild=0;
1815 wineItem->hItem=(HTREEITEM)iItem;
1820 switch ((DWORD) ptdi->hInsertAfter) {
1821 case (DWORD) TVI_FIRST:
1822 if (sibItem==wineItem) break;
1823 if (wineItem->parent) {
1824 wineItem->sibling=parentItem->firstChild;
1825 parentItem->firstChild=(HTREEITEM)iItem;
1827 wineItem->sibling=infoPtr->TopRootItem;
1828 infoPtr->TopRootItem=(HTREEITEM)iItem;
1830 sibItem->upsibling=(HTREEITEM)iItem;
1833 case (DWORD) TVI_SORT:
1834 if (sibItem==wineItem)
1836 * This item is the first child of the level and it
1837 * has already been inserted
1842 TREEVIEW_ITEM *aChild;
1845 TREEVIEW_ITEM *previousChild = NULL;
1846 BOOL bItemInserted = FALSE;
1849 aChild = &infoPtr->items[(INT)parentItem->firstChild];
1851 aChild = &infoPtr->items[(INT)infoPtr->TopRootItem];
1853 /* lookup the text if using LPSTR_TEXTCALLBACKs */
1854 if (wineItem->pszText==LPSTR_TEXTCALLBACKA) {
1855 TREEVIEW_SendDispInfoNotify (hwnd, wineItem, TVN_GETDISPINFOA, TVIF_TEXT);
1858 /* Iterate the parent children to see where we fit in */
1859 while ( aChild != NULL )
1863 /* lookup the text if using LPSTR_TEXTCALLBACKs */
1864 if (aChild->pszText==LPSTR_TEXTCALLBACKA) {
1865 TREEVIEW_SendDispInfoNotify (hwnd, aChild, TVN_GETDISPINFOA, TVIF_TEXT);
1868 comp = strcmp(wineItem->pszText, aChild->pszText);
1869 if ( comp < 0 ) /* we are smaller than the current one */
1871 TREEVIEW_InsertBefore(infoPtr, wineItem, aChild, parentItem);
1872 bItemInserted = TRUE;
1875 else if ( comp > 0 ) /* we are bigger than the current one */
1877 previousChild = aChild;
1878 aChild = (aChild->sibling == 0) /* This will help us to exit */
1879 ? NULL /* if there is no more sibling */
1880 : &infoPtr->items[(INT)aChild->sibling];
1882 /* Look at the next item */
1885 else if ( comp == 0 )
1888 * An item with this name is already existing, therefore,
1889 * we add after the one we found
1891 TREEVIEW_InsertAfter(infoPtr, wineItem, aChild, parentItem);
1892 bItemInserted = TRUE;
1898 * we reach the end of the child list and the item as not
1899 * yet been inserted, therefore, insert it after the last child.
1901 if ( (! bItemInserted ) && (aChild == NULL) )
1902 TREEVIEW_InsertAfter(infoPtr, wineItem, previousChild, parentItem);
1908 case (DWORD) TVI_LAST:
1909 if (sibItem==wineItem) break;
1910 while (sibItem->sibling) {
1912 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1914 sibItem->sibling=(HTREEITEM)iItem;
1915 wineItem->upsibling=sibItem->hItem;
1918 while ((sibItem->sibling) && (sibItem->hItem!=ptdi->hInsertAfter))
1921 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1923 if (sibItem->hItem!=ptdi->hInsertAfter) {
1924 ERR("tried to insert item after nonexisting handle %d.\n",
1925 (INT) ptdi->hInsertAfter);
1929 if (sibItem->sibling) {
1930 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1931 sibItem->upsibling=(HTREEITEM)iItem;
1932 wineItem->sibling=sibItem->hItem;
1934 prevsib->sibling=(HTREEITEM)iItem;
1935 wineItem->upsibling=prevsib->hItem;
1941 /* Fill in info structure */
1943 TRACE("new item %d; parent %d, mask %x\n", iItem,
1944 (INT)wineItem->parent,tvItem->mask);
1946 wineItem->mask=tvItem->mask;
1947 wineItem->iIntegral=1;
1949 if (tvItem->mask & TVIF_CHILDREN) {
1950 wineItem->cChildren=tvItem->cChildren;
1951 if (tvItem->cChildren==I_CHILDRENCALLBACK)
1952 FIXME(" I_CHILDRENCALLBACK not supported\n");
1955 wineItem->expandBox.left = 0; /* Initialize the expandBox */
1956 wineItem->expandBox.top = 0;
1957 wineItem->expandBox.right = 0;
1958 wineItem->expandBox.bottom = 0;
1960 if (tvItem->mask & TVIF_IMAGE)
1961 wineItem->iImage=tvItem->iImage;
1963 /* If the application sets TVIF_INTEGRAL without
1964 supplying a TVITEMEX structure, it's toast */
1966 if (tvItem->mask & TVIF_INTEGRAL)
1967 wineItem->iIntegral=tvItem->iIntegral;
1969 if (tvItem->mask & TVIF_SELECTEDIMAGE)
1970 wineItem->iSelectedImage=tvItem->iSelectedImage;
1972 if (tvItem->mask & TVIF_STATE) {
1973 TRACE("item state: %x ->%x\n", wineItem->state, tvItem->state);
1974 TRACE("statemask: %x ->%x\n", wineItem->stateMask, tvItem->stateMask);
1975 wineItem->state=tvItem->state;
1976 wineItem->stateMask=tvItem->stateMask;
1979 TREEVIEW_QueueRefresh (hwnd);
1981 return (LRESULT) iItem;
1986 TREEVIEW_InsertItemW(HWND hwnd, WPARAM wParam, LPARAM lParam)
1988 TVINSERTSTRUCTW *tvisW;
1989 TVINSERTSTRUCTA tvisA;
1992 tvisW = (LPTVINSERTSTRUCTW)lParam;
1994 tvisA.hParent = tvisW->hParent;
1995 tvisA.hInsertAfter = tvisW->hInsertAfter;
1997 tvisA.DUMMYUNIONNAME.item.mask = tvisW->DUMMYUNIONNAME.item.mask;
1998 tvisA.DUMMYUNIONNAME.item.hItem = tvisW->DUMMYUNIONNAME.item.hItem;
1999 tvisA.DUMMYUNIONNAME.item.state = tvisW->DUMMYUNIONNAME.item.state;
2000 tvisA.DUMMYUNIONNAME.item.stateMask = tvisW->DUMMYUNIONNAME.item.stateMask;
2001 tvisA.DUMMYUNIONNAME.item.cchTextMax = tvisW->DUMMYUNIONNAME.item.cchTextMax;
2003 if(tvisW->DUMMYUNIONNAME.item.pszText)
2005 if (tvisW->DUMMYUNIONNAME.item.pszText!=LPSTR_TEXTCALLBACKW)
2007 int len = lstrlenW (tvisW->DUMMYUNIONNAME.item.pszText)+1;
2008 tvisA.DUMMYUNIONNAME.item.pszText = COMCTL32_Alloc (len);
2009 lstrcpyWtoA (tvisA.DUMMYUNIONNAME.item.pszText,
2010 tvisW->DUMMYUNIONNAME.item.pszText );
2014 tvisA.DUMMYUNIONNAME.item.pszText = LPSTR_TEXTCALLBACKA;
2015 tvisA.DUMMYUNIONNAME.item.cchTextMax = 0;
2019 tvisA.DUMMYUNIONNAME.item.iImage = tvisW->DUMMYUNIONNAME.item.iImage;
2020 tvisA.DUMMYUNIONNAME.item.iSelectedImage = tvisW->DUMMYUNIONNAME.item.iSelectedImage;
2021 tvisA.DUMMYUNIONNAME.item.cChildren = tvisW->DUMMYUNIONNAME.item.cChildren;
2022 tvisA.DUMMYUNIONNAME.item.lParam = tvisW->DUMMYUNIONNAME.item.lParam;
2024 lRes = TREEVIEW_InsertItemA(hwnd,wParam,(LPARAM)&tvisA);
2026 if (tvisA.DUMMYUNIONNAME.item.pszText!=LPSTR_TEXTCALLBACKA)
2028 COMCTL32_Free(tvisA.DUMMYUNIONNAME.item.pszText);
2037 TREEVIEW_DeleteItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
2039 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2041 TREEVIEW_ITEM *wineItem;
2043 TRACE("item = %08lx\n", lParam);
2045 if (lParam == (INT)TVI_ROOT) {
2046 TREEVIEW_RemoveTree (hwnd);
2048 iItem= (INT) lParam;
2049 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
2050 if (!wineItem) return FALSE;
2052 if (wineItem->pszText==LPSTR_TEXTCALLBACKA)
2053 TRACE("LPSTR_TEXTCALLBACK\n");
2055 TRACE("%s\n",wineItem->pszText);
2056 TREEVIEW_RemoveItem (hwnd, wineItem);
2059 TREEVIEW_QueueRefresh (hwnd);
2067 TREEVIEW_GetIndent (HWND hwnd)
2069 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2072 return infoPtr->uIndent;
2076 TREEVIEW_SetIndent (HWND hwnd, WPARAM wParam)
2078 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2082 newIndent=(INT) wParam;
2083 if (newIndent < MINIMUM_INDENT) newIndent=MINIMUM_INDENT;
2084 infoPtr->uIndent=newIndent;
2090 TREEVIEW_GetToolTips (HWND hwnd)
2093 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2096 return infoPtr->hwndToolTip;
2101 TREEVIEW_SetToolTips (HWND hwnd, WPARAM wParam)
2104 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2108 prevToolTip=infoPtr->hwndToolTip;
2109 infoPtr->hwndToolTip= (HWND) wParam;
2115 static LRESULT CALLBACK
2116 TREEVIEW_GetEditControl (HWND hwnd)
2119 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2121 return infoPtr->hwndEdit;
2125 TREEVIEW_Edit_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam,
2133 HDC hdc = (HDC) wParam;
2134 GetClientRect (hwnd, &rc);
2135 Rectangle (hdc, rc.left, rc.top, rc.right, rc.bottom);
2141 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
2146 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd));
2148 return CallWindowProcA (infoPtr->wpEditOrig, hwnd, uMsg, wParam, lParam);
2159 /* should handle edit control messages here */
2162 TREEVIEW_Command (HWND hwnd, WPARAM wParam, LPARAM lParam)
2165 TRACE("%x %ld\n",wParam, lParam);
2167 switch (HIWORD(wParam))
2172 * Adjust the edit window size
2174 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2175 TREEVIEW_ITEM *editItem = TREEVIEW_ValidItem(infoPtr, infoPtr->editItem);
2176 INT iLength = GetWindowTextLengthA(infoPtr->hwndEdit);
2177 HDC hdc = GetDC(infoPtr->hwndEdit);
2180 if ( GetTextMetricsA(hdc, &tm) )
2182 LONG newWidth = (iLength * tm.tmAveCharWidth) + 15;
2187 editItem->text.left - 2,
2188 editItem->text.top - 1,
2190 editItem->text.bottom - editItem->text.top + 3,
2193 ReleaseDC(hwnd, hdc);
2199 /* TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
2204 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
2211 TREEVIEW_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
2214 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2216 if (infoPtr->bAutoSize)
2218 infoPtr->bAutoSize = FALSE;
2221 infoPtr->bAutoSize = TRUE;
2223 if (wParam == SIZE_RESTORED)
2225 infoPtr->uTotalWidth = LOWORD (lParam);
2226 infoPtr->uTotalHeight = HIWORD (lParam);
2228 FIXME("WM_SIZE flag %x %lx not handled\n", wParam, lParam);
2231 TREEVIEW_QueueRefresh (hwnd);
2238 TREEVIEW_StyleChanged (HWND hwnd, WPARAM wParam, LPARAM lParam)
2242 TRACE("(%x %lx)\n",wParam,lParam);
2244 TREEVIEW_Refresh (hwnd, hdc);
2245 ReleaseDC(hwnd,hdc);
2251 TREEVIEW_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
2253 TREEVIEW_INFO *infoPtr;
2254 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
2259 TRACE("wnd %x, style %lx\n",hwnd,dwStyle);
2260 /* allocate memory for info structure */
2261 infoPtr = (TREEVIEW_INFO *) COMCTL32_Alloc (sizeof(TREEVIEW_INFO));
2263 SetWindowLongA( hwnd, 0, (DWORD)infoPtr);
2265 if (infoPtr == NULL) {
2266 ERR("could not allocate info memory!\n");
2270 if ((TREEVIEW_INFO*) GetWindowLongA( hwnd, 0) != infoPtr) {
2271 ERR("pointer assignment error!\n");
2277 /* set default settings */
2278 infoPtr->uInternalStatus=0;
2279 infoPtr->uNumItems=0;
2280 infoPtr->clrBk = GetSysColor (COLOR_WINDOW);
2281 infoPtr->clrText = GetSysColor (COLOR_WINDOWTEXT);
2282 infoPtr->clrLine = GetSysColor (COLOR_WINDOWTEXT);
2283 infoPtr->clrInsertMark = GetSysColor (COLOR_BTNTEXT);
2286 infoPtr->uIndent = 15;
2287 infoPtr->himlNormal = NULL;
2288 infoPtr->himlState = NULL;
2289 infoPtr->uItemHeight = -1;
2290 GetTextMetricsA (hdc, &tm);
2291 infoPtr->hFont = GetStockObject (DEFAULT_GUI_FONT);
2292 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
2293 logFont.lfWeight=FW_BOLD;
2294 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
2296 infoPtr->items = NULL;
2297 infoPtr->selectedItem=0;
2298 infoPtr->clrText=-1; /* use system color */
2299 infoPtr->dropItem=0;
2300 infoPtr->insertMarkItem=0;
2301 infoPtr->insertBeforeorAfter=0;
2302 infoPtr->pCallBackSort=NULL;
2303 infoPtr->uScrollTime = 300; /* milliseconds */
2304 infoPtr->wpEditOrig = NULL; /* we haven't subclassed anything yet */
2306 infoPtr->hwndToolTip=0;
2307 if (!(dwStyle & TVS_NOTOOLTIPS)) { /* Create tooltip control */
2310 infoPtr->hwndToolTip =
2311 CreateWindowExA (0, TOOLTIPS_CLASSA, NULL, 0,
2312 CW_USEDEFAULT, CW_USEDEFAULT,
2313 CW_USEDEFAULT, CW_USEDEFAULT,
2316 /* Send NM_TOOLTIPSCREATED notification */
2317 if (infoPtr->hwndToolTip) {
2318 NMTOOLTIPSCREATED nmttc;
2320 nmttc.hdr.hwndFrom = hwnd;
2321 nmttc.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2322 nmttc.hdr.code = NM_TOOLTIPSCREATED;
2323 nmttc.hwndToolTips = infoPtr->hwndToolTip;
2325 SendMessageA (GetParent (hwnd), WM_NOTIFY,
2326 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmttc);
2329 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
2330 ti.cbSize = sizeof(TTTOOLINFOA);
2331 ti.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_TRANSPARENT ;
2334 ti.lpszText = "Test"; /* LPSTR_TEXTCALLBACK; */
2335 SetRectEmpty (&ti.rect);
2337 SendMessageA (infoPtr->hwndToolTip, TTM_ADDTOOLA, 0, (LPARAM)&ti);
2340 infoPtr->hwndEdit = CreateWindowExA (
2344 WS_CHILD | WS_BORDER | ES_AUTOHSCROLL |
2345 ES_WANTRETURN | ES_LEFT,
2348 0,0,0); /* FIXME: (HMENU)IDTVEDIT,pcs->hInstance,0);*/
2350 SendMessageA ( infoPtr->hwndEdit, WM_SETFONT, infoPtr->hFont, FALSE);
2351 infoPtr->wpEditOrig = (WNDPROC)SetWindowLongA (
2354 (LONG) TREEVIEW_Edit_SubclassProc);
2356 if (dwStyle & TVS_CHECKBOXES) {
2360 infoPtr->himlState =
2361 ImageList_Create (16, 16,ILC_COLOR|ILC_MASK, 15, 1);
2363 hbmLoad = LoadBitmapA (COMCTL32_hModule, MAKEINTRESOURCEA(IDT_CHECK));
2364 TRACE ("%x\n",hbmLoad);
2365 nIndex = ImageList_AddMasked (infoPtr->himlState, hbmLoad, CLR_DEFAULT);
2366 TRACE ("%d\n",nIndex);
2367 DeleteObject (hbmLoad);
2369 ReleaseDC (hwnd, hdc);
2376 TREEVIEW_Destroy (HWND hwnd)
2378 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2381 TREEVIEW_RemoveTree (hwnd);
2382 SetWindowLongA (hwnd, 0, (DWORD)NULL);
2384 if (infoPtr->Timer & TV_REFRESH_TIMER_SET)
2385 KillTimer (hwnd, TV_REFRESH_TIMER);
2386 if (infoPtr->hwndToolTip)
2387 DestroyWindow (infoPtr->hwndToolTip);
2389 COMCTL32_Free (infoPtr);
2395 TREEVIEW_Paint (HWND hwnd, WPARAM wParam, LPARAM lParam)
2401 hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
2402 TREEVIEW_Refresh (hwnd, hdc);
2403 ReleaseDC(hwnd,hdc);
2404 if(!wParam) EndPaint (hwnd, &ps);
2407 return DefWindowProcA (hwnd, WM_PAINT, wParam, lParam);
2411 TREEVIEW_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2413 TREEVIEW_SendSimpleNotify (hwnd, NM_SETFOCUS);
2414 InvalidateRect(hwnd, NULL, FALSE);
2419 TREEVIEW_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2421 TREEVIEW_SendSimpleNotify (hwnd, NM_KILLFOCUS);
2422 InvalidateRect(hwnd, NULL, FALSE);
2427 TREEVIEW_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
2429 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2430 HBRUSH hBrush = CreateSolidBrush (infoPtr->clrBk);
2434 GetClientRect (hwnd, &rect);
2435 FillRect ((HDC)wParam, &rect, hBrush);
2436 DeleteObject (hBrush);
2452 TREEVIEW_SendSimpleNotify (HWND hwnd, UINT code)
2457 nmhdr.hwndFrom = hwnd;
2458 nmhdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2461 return (BOOL) SendMessageA (GetParent (hwnd), WM_NOTIFY,
2462 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
2468 TREEVIEW_SendTreeviewNotify (HWND hwnd, UINT code, UINT action,
2469 HTREEITEM oldItem, HTREEITEM newItem)
2472 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2474 TREEVIEW_ITEM *wineItem;
2476 TRACE("code:%x action:%x olditem:%x newitem:%x\n",
2477 code,action,(INT)oldItem,(INT)newItem);
2478 nmhdr.hdr.hwndFrom = hwnd;
2479 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2480 nmhdr.hdr.code = code;
2481 nmhdr.action = action;
2483 wineItem=& infoPtr->items[(INT)oldItem];
2484 nmhdr.itemOld.mask = wineItem->mask;
2485 nmhdr.itemOld.hItem = wineItem->hItem;
2486 nmhdr.itemOld.state = wineItem->state;
2487 nmhdr.itemOld.stateMask = wineItem->stateMask;
2488 nmhdr.itemOld.iImage = wineItem->iImage;
2489 nmhdr.itemOld.pszText = wineItem->pszText;
2490 nmhdr.itemOld.cchTextMax= wineItem->cchTextMax;
2491 nmhdr.itemOld.iImage = wineItem->iImage;
2492 nmhdr.itemOld.iSelectedImage = wineItem->iSelectedImage;
2493 nmhdr.itemOld.cChildren = wineItem->cChildren;
2494 nmhdr.itemOld.lParam = wineItem->lParam;
2498 wineItem=& infoPtr->items[(INT)newItem];
2499 nmhdr.itemNew.mask = wineItem->mask;
2500 nmhdr.itemNew.hItem = wineItem->hItem;
2501 nmhdr.itemNew.state = wineItem->state;
2502 nmhdr.itemNew.stateMask = wineItem->stateMask;
2503 nmhdr.itemNew.iImage = wineItem->iImage;
2504 nmhdr.itemNew.pszText = wineItem->pszText;
2505 nmhdr.itemNew.cchTextMax= wineItem->cchTextMax;
2506 nmhdr.itemNew.iImage = wineItem->iImage;
2507 nmhdr.itemNew.iSelectedImage = wineItem->iSelectedImage;
2508 nmhdr.itemNew.cChildren = wineItem->cChildren;
2509 nmhdr.itemNew.lParam = wineItem->lParam;
2515 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2516 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2521 TREEVIEW_SendTreeviewDnDNotify (HWND hwnd, UINT code, HTREEITEM dragItem,
2524 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2526 TREEVIEW_ITEM *wineItem;
2528 TRACE("code:%x dragitem:%x\n", code,(INT)dragItem);
2530 nmhdr.hdr.hwndFrom = hwnd;
2531 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2532 nmhdr.hdr.code = code;
2534 wineItem=& infoPtr->items[(INT)dragItem];
2535 nmhdr.itemNew.mask = wineItem->mask;
2536 nmhdr.itemNew.hItem = wineItem->hItem;
2537 nmhdr.itemNew.state = wineItem->state;
2538 nmhdr.itemNew.lParam = wineItem->lParam;
2540 nmhdr.ptDrag.x = pt.x;
2541 nmhdr.ptDrag.y = pt.y;
2543 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2544 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2551 TREEVIEW_SendDispInfoNotify (HWND hwnd, TREEVIEW_ITEM *wineItem,
2552 UINT code, UINT what)
2558 TRACE("item %d, action %x, state %d\n",
2559 (INT)wineItem->hItem,
2561 (INT)wineItem->state);
2563 tvdi.hdr.hwndFrom = hwnd;
2564 tvdi.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2565 tvdi.hdr.code = code;
2566 tvdi.item.mask = what;
2567 tvdi.item.hItem = wineItem->hItem;
2568 tvdi.item.state = wineItem->state;
2569 tvdi.item.lParam = wineItem->lParam;
2570 tvdi.item.pszText = COMCTL32_Alloc (128*sizeof(char));
2571 tvdi.item.cchTextMax = 128;
2572 buf = tvdi.item.pszText;
2574 retval=(BOOL)SendMessageA (
2577 (WPARAM)tvdi.hdr.idFrom,
2580 if (what & TVIF_TEXT) {
2581 wineItem->pszText = tvdi.item.pszText;
2582 if (buf==tvdi.item.pszText) {
2583 wineItem->cchTextMax = 128;
2585 TRACE("user-supplied buffer\n");
2586 COMCTL32_Free (buf);
2587 wineItem->cchTextMax = 0;
2590 if (what & TVIF_SELECTEDIMAGE)
2591 wineItem->iSelectedImage = tvdi.item.iSelectedImage;
2592 if (what & TVIF_IMAGE)
2593 wineItem->iImage = tvdi.item.iImage;
2594 if (what & TVIF_CHILDREN)
2595 wineItem->cChildren = tvdi.item.cChildren;
2603 TREEVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
2606 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2607 NMTVCUSTOMDRAW nmcdhdr;
2608 LPNMCUSTOMDRAW nmcd;
2610 TRACE("drawstage:%lx hdc:%x\n", dwDrawStage, hdc);
2612 nmcd= & nmcdhdr.nmcd;
2613 nmcd->hdr.hwndFrom = hwnd;
2614 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2615 nmcd->hdr.code = NM_CUSTOMDRAW;
2616 nmcd->dwDrawStage= dwDrawStage;
2618 nmcd->rc.left = rc.left;
2619 nmcd->rc.right = rc.right;
2620 nmcd->rc.bottom = rc.bottom;
2621 nmcd->rc.top = rc.top;
2622 nmcd->dwItemSpec = 0;
2623 nmcd->uItemState = 0;
2624 nmcd->lItemlParam= 0;
2625 nmcdhdr.clrText = infoPtr->clrText;
2626 nmcdhdr.clrTextBk= infoPtr->clrBk;
2629 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2630 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2636 /* FIXME: need to find out when the flags in uItemState need to be set */
2639 TREEVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
2640 TREEVIEW_ITEM *wineItem, UINT uItemDrawState)
2642 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2643 NMTVCUSTOMDRAW nmcdhdr;
2644 LPNMCUSTOMDRAW nmcd;
2645 DWORD dwDrawStage,dwItemSpec;
2649 dwDrawStage=CDDS_ITEM | uItemDrawState;
2650 dwItemSpec=(DWORD)wineItem->hItem;
2652 if (wineItem->hItem==infoPtr->selectedItem) uItemState|=CDIS_SELECTED;
2653 if (wineItem->hItem==infoPtr->focusItem) uItemState|=CDIS_FOCUS;
2654 if (wineItem->hItem==infoPtr->hotItem) uItemState|=CDIS_HOT;
2656 nmcd= & nmcdhdr.nmcd;
2657 nmcd->hdr.hwndFrom = hwnd;
2658 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2659 nmcd->hdr.code = NM_CUSTOMDRAW;
2660 nmcd->dwDrawStage= dwDrawStage;
2662 nmcd->rc.left = wineItem->rect.left;
2663 nmcd->rc.right = wineItem->rect.right;
2664 nmcd->rc.bottom = wineItem->rect.bottom;
2665 nmcd->rc.top = wineItem->rect.top;
2666 nmcd->dwItemSpec = dwItemSpec;
2667 nmcd->uItemState = uItemState;
2668 nmcd->lItemlParam= wineItem->lParam;
2669 nmcdhdr.clrText = infoPtr->clrText;
2670 nmcdhdr.clrTextBk= infoPtr->clrBk;
2671 nmcdhdr.iLevel = wineItem->iLevel;
2673 TRACE("drawstage:%lx hdc:%x item:%lx, itemstate:%x, lItemlParam:%lx\n",
2674 nmcd->dwDrawStage, nmcd->hdc, nmcd->dwItemSpec,
2675 nmcd->uItemState, nmcd->lItemlParam);
2677 retval=SendMessageA (GetParent (hwnd), WM_NOTIFY,
2678 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2680 infoPtr->clrText=nmcdhdr.clrText;
2681 infoPtr->clrBk =nmcdhdr.clrTextBk;
2682 return (BOOL) retval;
2687 /* Note:If the specified item is the child of a collapsed parent item,
2688 the parent's list of child items is (recursively) expanded to reveal the
2689 specified item. This is mentioned for TREEVIEW_SelectItem; don't
2690 know if it also applies here.
2694 TREEVIEW_Expand (HWND hwnd, WPARAM wParam, LPARAM lParam)
2696 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2697 TREEVIEW_ITEM *wineItem;
2701 flag = (UINT) wParam;
2702 expand = (INT) lParam;
2704 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2708 if (!wineItem->cChildren)
2711 if (wineItem->pszText==LPSTR_TEXTCALLBACKA)
2712 TRACE ("For item %d, flags %d, state %d\n",
2713 expand, flag, wineItem->state);
2715 TRACE("For (%s) item:%d, flags %x, state:%d\n",
2716 wineItem->pszText, flag, expand, wineItem->state);
2718 if (wineItem->cChildren==I_CHILDRENCALLBACK) {
2719 FIXME("we don't handle I_CHILDRENCALLBACK yet\n");
2723 if (flag == TVE_TOGGLE) { /* FIXME: check exact behaviour here */
2724 flag &= ~TVE_TOGGLE; /* ie: bitwise ops or 'case' ops */
2725 if (wineItem->state & TVIS_EXPANDED)
2726 flag |= TVE_COLLAPSE;
2733 case TVE_COLLAPSERESET:
2734 TRACE(" case TVE_COLLAPSERESET\n");
2735 if (!wineItem->state & TVIS_EXPANDED)
2738 wineItem->state &= ~(TVIS_EXPANDEDONCE | TVIS_EXPANDED);
2739 TREEVIEW_RemoveAllChildren (hwnd, wineItem);
2743 TRACE(" case TVE_COLLAPSE\n");
2744 if (!wineItem->state & TVIS_EXPANDED)
2747 wineItem->state &= ~TVIS_EXPANDED;
2751 TRACE(" case TVE_EXPAND\n");
2752 if (wineItem->state & TVIS_EXPANDED)
2755 TRACE(" is not expanded...\n");
2757 if (!(wineItem->state & TVIS_EXPANDEDONCE))
2759 TRACE(" and has never been expanded...\n");
2760 wineItem->state |= TVIS_EXPANDED;
2762 /* this item has never been expanded */
2763 if (TREEVIEW_SendTreeviewNotify (
2770 TRACE(" TVN_ITEMEXPANDINGA returned TRUE, exiting...\n");
2775 * Since the TVN_ITEMEXPANDINGA message may has caused the parent to
2776 * insert new items which in turn may have cause items placeholder
2777 * reallocation, I reassign the current item pointer so we have
2778 * something valid to work with...
2779 * However, this should not be necessary,
2780 * investigation required in TREEVIEW_InsertItemA
2782 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2786 "Catastropic situation, cannot retreive item #%d\n",
2791 wineItem->state |= TVIS_EXPANDEDONCE;
2792 TRACE(" TVN_ITEMEXPANDINGA sent...\n");
2794 TREEVIEW_SendTreeviewNotify (
2801 TRACE(" TVN_ITEMEXPANDEDA sent...\n");
2806 /* this item has already been expanded */
2807 wineItem->state |= TVIS_EXPANDED;
2811 case TVE_EXPANDPARTIAL:
2812 TRACE(" case TVE_EXPANDPARTIAL\n");
2813 FIXME("TVE_EXPANDPARTIAL not implemented\n");
2814 wineItem->state ^=TVIS_EXPANDED;
2815 wineItem->state |=TVIS_EXPANDEDONCE;
2819 TRACE("Exiting, Item %d state is now %d...\n",
2823 TREEVIEW_QueueRefresh (hwnd);
2829 static TREEVIEW_ITEM *
2830 TREEVIEW_HitTestPoint (HWND hwnd, POINT pt)
2832 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2833 TREEVIEW_ITEM *wineItem;
2836 GetClientRect (hwnd, &rect);
2838 if (!infoPtr->firstVisible) return NULL;
2840 wineItem=&infoPtr->items [(INT)infoPtr->firstVisible];
2842 while ((wineItem!=NULL) && (pt.y > wineItem->rect.bottom))
2843 wineItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
2855 TREEVIEW_HitTest (HWND hwnd, LPARAM lParam)
2857 LPTVHITTESTINFO lpht=(LPTVHITTESTINFO) lParam;
2858 TREEVIEW_ITEM *wineItem;
2862 GetClientRect (hwnd, &rect);
2866 if (x < rect.left) status|=TVHT_TOLEFT;
2867 if (x > rect.right) status|=TVHT_TORIGHT;
2868 if (y < rect.top ) status|=TVHT_ABOVE;
2869 if (y > rect.bottom) status|=TVHT_BELOW;
2876 wineItem=TREEVIEW_HitTestPoint (hwnd, lpht->pt);
2878 lpht->flags=TVHT_NOWHERE;
2884 if (x < wineItem->expandBox.left) {
2885 lpht->flags |= TVHT_ONITEMINDENT;
2888 if ( PtInRect ( &wineItem->expandBox, lpht->pt)) {
2889 lpht->flags |= TVHT_ONITEMBUTTON;
2892 if ( PtInRect ( &wineItem->bitmap, lpht->pt)) {
2893 lpht->flags |= TVHT_ONITEMICON;
2896 if ( PtInRect ( &wineItem->statebitmap, lpht->pt)) {
2897 lpht->flags |= TVHT_ONITEMSTATEICON;
2900 if ( PtInRect ( &wineItem->text, lpht->pt)) {
2901 lpht->flags |= TVHT_ONITEMLABEL;
2905 lpht->flags|=TVHT_ONITEMRIGHT;
2909 lpht->hItem=wineItem->hItem;
2910 TRACE ("(%ld,%ld):result %x\n",lpht->pt.x,lpht->pt.y,lpht->flags);
2912 return (LRESULT) wineItem->hItem;
2916 TREEVIEW_EndEditLabelNow (HWND hwnd, WPARAM wParam, LPARAM lParam)
2918 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2919 TREEVIEW_ITEM *editedItem = TREEVIEW_ValidItem (infoPtr, infoPtr->editItem);
2920 BOOL bRevert = (BOOL)wParam;
2921 BOOL bReturn = ! bRevert;
2923 if ( ! (BOOL)wParam ) /* wParam is set to true to cancel the edition */
2925 if ( TREEVIEW_SendDispInfoNotify( /* return true to cancel edition */
2936 if (bRevert == FALSE) /* Apply the changes */
2939 int iLength = GetWindowTextA(infoPtr->hwndEdit, tmpText, 1023);
2944 ERR("Problem retreiving new item label.");
2946 else if (iLength >= 1023)
2949 "Insuficient space to retrieve new item label, new label ignored.");
2953 if (strcmp( tmpText, editedItem->pszText ) == 0)
2954 /* Do nothing if the label has not changed */
2958 LPSTR tmpLabel = COMCTL32_Alloc( iLength+1 );
2960 if ( tmpLabel == NULL )
2962 "OutOfMemory, cannot allocate space for label");
2965 COMCTL32_Free(editedItem->pszText);
2966 editedItem->pszText = tmpLabel;
2967 lstrcpyA( editedItem->pszText, tmpText);
2973 ShowWindow(infoPtr->hwndEdit, SW_HIDE);
2974 EnableWindow(infoPtr->hwndEdit, FALSE);
2975 infoPtr->editItem = 0;
2984 TREEVIEW_LButtonDoubleClick (HWND hwnd, WPARAM wParam, LPARAM lParam)
2986 TREEVIEW_ITEM *wineItem;
2990 pt.x = (INT)LOWORD(lParam);
2991 pt.y = (INT)HIWORD(lParam);
2994 wineItem=TREEVIEW_HitTestPoint (hwnd, pt);
2995 if (!wineItem) return 0;
2996 TRACE("item %d \n",(INT)wineItem->hItem);
2998 if (TREEVIEW_SendSimpleNotify (hwnd, NM_DBLCLK)!=TRUE) { /* FIXME!*/
2999 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) wineItem->hItem);
3006 TREEVIEW_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
3008 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3012 ht.pt.x = (INT)LOWORD(lParam);
3013 ht.pt.y = (INT)HIWORD(lParam);
3016 iItem=TREEVIEW_HitTest (hwnd, (LPARAM) &ht);
3017 TRACE("item %d \n",iItem);
3019 if (ht.flags & TVHT_ONITEMBUTTON) {
3020 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) iItem);
3024 infoPtr->uInternalStatus|=TV_LDRAG;
3031 TREEVIEW_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
3033 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3035 TREEVIEW_ITEM *wineItem;
3038 ht.pt.x = (INT)LOWORD(lParam);
3039 ht.pt.y = (INT)HIWORD(lParam);
3043 /* Return true to cancel default behaviour */
3044 if ( TREEVIEW_SendSimpleNotify (hwnd, NM_CLICK) )
3048 iItem = TREEVIEW_HitTest (hwnd, (LPARAM) &ht);
3049 TRACE ("%d\n",iItem);
3053 wineItem = TREEVIEW_ValidItem(infoPtr, (HTREEITEM)iItem);
3055 infoPtr->uInternalStatus &= ~(TV_LDRAG | TV_LDRAGGING);
3058 * If the style allow editing and the node is already selected
3059 * and the click occured on the item label...
3061 if ( ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_EDITLABELS ) &&
3062 ( wineItem->state & TVIS_SELECTED ) &&
3063 ( ht.flags & TVHT_ONITEMLABEL ))
3065 if ( infoPtr->editItem == 0 ) /* If we are not curently editing */
3067 if ( TREEVIEW_SendDispInfoNotify( /* Return true to cancel edition */
3070 TVN_BEGINLABELEDITA,
3076 TRACE("Edit started for %s.\n", wineItem->pszText);
3077 infoPtr->editItem = wineItem->hItem;
3082 wineItem->text.left - 2,
3083 wineItem->text.top - 1,
3084 wineItem->text.right - wineItem->text.left + 20 ,
3085 wineItem->text.bottom - wineItem->text.top + 3,
3088 SetWindowTextA( infoPtr->hwndEdit, wineItem->pszText );
3089 SendMessageA ( infoPtr->hwndEdit, EM_SETSEL, 0, -1 );
3090 SetFocus ( infoPtr->hwndEdit);
3091 ShowWindow ( infoPtr->hwndEdit, SW_SHOW);
3094 else if ( infoPtr->editItem != 0 ) /* If we are curently editing */
3096 TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
3098 else if ( ht.flags & (TVHT_ONITEMLABEL | TVHT_ONITEMICON))
3100 TREEVIEW_DoSelectItem ( hwnd, TVGN_CARET, (HTREEITEM)iItem, TVC_BYMOUSE);
3103 if (ht.flags & TVHT_ONITEMSTATEICON) {
3104 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
3107 if (dwStyle & TVS_CHECKBOXES) { /* TVS_CHECKBOXES requires _us_ */
3108 int state; /* to toggle the current state */
3109 state=1-(wineItem->state>>12);
3110 TRACE ("state:%x\n", state);
3111 wineItem->state&= ~TVIS_STATEIMAGEMASK;
3112 wineItem->state|=state<<12;
3113 TRACE ("state:%x\n", wineItem->state);
3114 TREEVIEW_QueueRefresh (hwnd);
3122 TREEVIEW_RButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
3124 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3127 infoPtr->uInternalStatus|=TV_RDRAG;
3132 TREEVIEW_RButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
3134 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3137 if (TREEVIEW_SendSimpleNotify (hwnd, NM_RCLICK)) return 0;
3138 infoPtr->uInternalStatus&= ~(TV_RDRAG | TV_RDRAGGING);
3144 TREEVIEW_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
3146 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3147 TREEVIEW_ITEM *hotItem;
3150 pt.x=(INT) LOWORD (lParam);
3151 pt.y=(INT) HIWORD (lParam);
3152 hotItem=TREEVIEW_HitTestPoint (hwnd, pt);
3153 if (!hotItem) return 0;
3154 infoPtr->focusItem=hotItem->hItem;
3156 if ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_DISABLEDRAGDROP) return 0;
3158 if (infoPtr->uInternalStatus & TV_LDRAG) {
3159 TREEVIEW_SendTreeviewDnDNotify (hwnd, TVN_BEGINDRAGA, hotItem->hItem, pt);
3160 infoPtr->uInternalStatus &= ~TV_LDRAG;
3161 infoPtr->uInternalStatus |= TV_LDRAGGING;
3162 infoPtr->dropItem=hotItem->hItem;
3166 if (infoPtr->uInternalStatus & TV_RDRAG) {
3167 TREEVIEW_SendTreeviewDnDNotify (hwnd, TVN_BEGINRDRAGA, hotItem->hItem, pt);
3168 infoPtr->uInternalStatus &= ~TV_RDRAG;
3169 infoPtr->uInternalStatus |= TV_RDRAGGING;
3170 infoPtr->dropItem=hotItem->hItem;
3179 TREEVIEW_CreateDragImage (HWND hwnd, WPARAM wParam, LPARAM lParam)
3181 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3182 TREEVIEW_ITEM *dragItem;
3186 HBITMAP hbmp,hOldbmp;
3193 if (!(infoPtr->himlNormal)) return 0;
3194 dragItem=TREEVIEW_ValidItem (infoPtr, (HTREEITEM) lParam);
3196 if (!dragItem) return 0;
3198 if (dragItem->pszText==LPSTR_TEXTCALLBACKA) {
3199 TREEVIEW_SendDispInfoNotify (hwnd, dragItem, TVN_GETDISPINFOA, TVIF_TEXT);
3201 itemtxt=dragItem->pszText;
3203 hwtop=GetDesktopWindow ();
3204 htopdc= GetDC (hwtop);
3205 hdc=CreateCompatibleDC (htopdc);
3207 hOldFont=SelectObject (hdc, infoPtr->hFont);
3208 GetTextExtentPoint32A (hdc, itemtxt, lstrlenA (itemtxt), &size);
3209 TRACE("%d %d %s %d\n",size.cx,size.cy,itemtxt,lstrlenA(itemtxt));
3210 hbmp=CreateCompatibleBitmap (htopdc, size.cx, size.cy);
3211 hOldbmp=SelectObject (hdc, hbmp);
3213 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &cy);
3215 if (cy>size.cy) size.cy=cy;
3217 infoPtr->dragList=ImageList_Create (size.cx, size.cy, ILC_COLOR, 10, 10);
3218 ImageList_Draw (infoPtr->himlNormal, dragItem->iImage, hdc, 0, 0, ILD_NORMAL);
3221 ImageList_GetImageInfo (infoPtr->himlNormal, dragItem->hItem, &iminfo);
3222 ImageList_AddMasked (infoPtr->dragList, iminfo.hbmImage, CLR_DEFAULT);
3225 /* draw item text */
3227 SetRect (&rc, cx, 0, size.cx,size.cy);
3228 DrawTextA (hdc, itemtxt, lstrlenA (itemtxt), &rc, DT_LEFT);
3229 SelectObject (hdc, hOldFont);
3230 SelectObject (hdc, hOldbmp);
3232 ImageList_Add (infoPtr->dragList, hbmp, 0);
3235 DeleteObject (hbmp);
3236 ReleaseDC (hwtop, htopdc);
3238 return (LRESULT)infoPtr->dragList;
3243 TREEVIEW_DoSelectItem (HWND hwnd, INT action, HTREEITEM newSelect, INT cause)
3246 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3247 TREEVIEW_ITEM *prevItem,*wineItem;
3250 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)newSelect);
3252 TRACE("Entering item %d, flag %x, cause %x, state %d\n",
3258 if ( (wineItem) && (wineItem->parent))
3261 * If the item has a collapse parent expand the parent so he
3262 * can expose the item
3264 TREEVIEW_ITEM *parentItem = TREEVIEW_ValidItem (infoPtr, wineItem->parent);
3265 if ( !(parentItem->state & TVIS_EXPANDED))
3266 TREEVIEW_Expand (hwnd, TVE_EXPAND, (LPARAM) wineItem->parent);
3272 prevSelect=(INT)infoPtr->selectedItem;
3274 if ((HTREEITEM)prevSelect==newSelect)
3277 prevItem= TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect);
3280 if (TREEVIEW_SendTreeviewNotify(
3284 (HTREEITEM)prevSelect,
3285 (HTREEITEM)newSelect))
3286 return FALSE; /* FIXME: OK? */
3289 prevItem->state &= ~TVIS_SELECTED;
3291 wineItem->state |= TVIS_SELECTED;
3293 infoPtr->selectedItem=(HTREEITEM)newSelect;
3295 TREEVIEW_SendTreeviewNotify(
3299 (HTREEITEM)prevSelect,
3300 (HTREEITEM)newSelect);
3304 case TVGN_DROPHILITE:
3305 prevItem= TREEVIEW_ValidItem (infoPtr, infoPtr->dropItem);
3308 prevItem->state &= ~TVIS_DROPHILITED;
3310 infoPtr->dropItem=(HTREEITEM)newSelect;
3313 wineItem->state |=TVIS_DROPHILITED;
3317 case TVGN_FIRSTVISIBLE:
3318 FIXME("FIRSTVISIBLE not implemented\n");
3322 TREEVIEW_QueueRefresh (hwnd);
3324 TRACE("Leaving state %d\n", wineItem->state);
3328 /* FIXME: handle NM_KILLFocus etc */
3330 TREEVIEW_SelectItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
3333 return TREEVIEW_DoSelectItem (hwnd, wParam, (HTREEITEM) lParam, TVC_UNKNOWN);
3340 TREEVIEW_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
3343 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3345 TRACE("%x\n",infoPtr->hFont);
3346 return infoPtr->hFont;
3350 TREEVIEW_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
3353 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3356 HFONT hFont, hOldFont;
3360 TRACE("%x %lx\n",wParam, lParam);
3362 infoPtr->hFont = (HFONT)wParam;
3364 hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
3366 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
3367 logFont.lfWeight=FW_BOLD;
3368 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
3371 hOldFont = SelectObject (hdc, hFont);
3372 GetTextMetricsA (hdc, &tm);
3373 height= tm.tmHeight + tm.tmExternalLeading;
3374 if (height>infoPtr->uRealItemHeight)
3375 infoPtr->uRealItemHeight=height;
3376 SelectObject (hdc, hOldFont);
3380 TREEVIEW_QueueRefresh (hwnd);
3388 TREEVIEW_VScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
3391 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3394 TRACE("wp %x, lp %lx\n", wParam, lParam);
3395 if (!infoPtr->uInternalStatus & TV_VSCROLL) return FALSE;
3397 switch (LOWORD (wParam)) {
3399 if (!infoPtr->cy) return FALSE;
3400 infoPtr->cy -= infoPtr->uRealItemHeight;
3401 if (infoPtr->cy < 0) infoPtr->cy=0;
3404 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3405 if (infoPtr->cy == maxHeight) return FALSE;
3406 infoPtr->cy += infoPtr->uRealItemHeight;
3407 if (infoPtr->cy > maxHeight)
3408 infoPtr->cy = maxHeight;
3411 if (!infoPtr->cy) return FALSE;
3412 infoPtr->cy -= infoPtr->uVisibleHeight;
3413 if (infoPtr->cy < 0) infoPtr->cy=0;
3416 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3417 if (infoPtr->cy == maxHeight) return FALSE;
3418 infoPtr->cy += infoPtr->uVisibleHeight;
3419 if (infoPtr->cy > maxHeight)
3420 infoPtr->cy = maxHeight;
3423 infoPtr->cy = HIWORD (wParam);
3428 TREEVIEW_QueueRefresh (hwnd);
3433 TREEVIEW_HScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
3435 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3438 TRACE("wp %lx, lp %x\n", lParam, wParam);
3440 if (!infoPtr->uInternalStatus & TV_HSCROLL) return FALSE;
3442 switch (LOWORD (wParam)) {
3444 if (!infoPtr->cx) return FALSE;
3445 infoPtr->cx -= infoPtr->uRealItemHeight;
3446 if (infoPtr->cx < 0) infoPtr->cx=0;
3449 maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
3450 if (infoPtr->cx == maxWidth) return FALSE;
3451 infoPtr->cx += infoPtr->uRealItemHeight; /*FIXME */
3452 if (infoPtr->cx > maxWidth)
3453 infoPtr->cx = maxWidth;
3456 if (!infoPtr->cx) return FALSE;
3457 infoPtr->cx -= infoPtr->uVisibleWidth;
3458 if (infoPtr->cx < 0) infoPtr->cx=0;
3461 maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
3462 if (infoPtr->cx == maxWidth) return FALSE;
3463 infoPtr->cx += infoPtr->uVisibleWidth;
3464 if (infoPtr->cx > maxWidth)
3465 infoPtr->cx = maxWidth;
3468 infoPtr->cx = HIWORD (wParam);
3473 TREEVIEW_QueueRefresh (hwnd);
3479 TREEVIEW_KeyDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
3481 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3482 HTREEITEM hNewSelection = 0;
3483 INT scrollNeeds = -1;
3484 INT cyChangeNeeds = -1;
3485 INT prevSelect = (INT)infoPtr->selectedItem;
3487 TREEVIEW_ITEM *prevItem =
3488 (prevSelect != 0 ) ?
3489 TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect) :
3492 TREEVIEW_ITEM *newItem = NULL;
3494 TRACE("%x %lx\n",wParam, lParam);
3496 if (prevSelect == 0)
3501 newItem=TREEVIEW_GetPrevListItem (infoPtr, prevItem);
3504 newItem=& infoPtr->items[(INT)infoPtr->TopRootItem];
3506 hNewSelection = newItem->hItem;
3508 if (! newItem->visible)
3509 scrollNeeds = SB_LINEUP;
3513 newItem=TREEVIEW_GetNextListItem (infoPtr, prevItem);
3518 hNewSelection = newItem->hItem;
3520 if (! newItem->visible)
3521 scrollNeeds = SB_LINEDOWN;
3526 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem];
3527 hNewSelection = newItem->hItem;
3532 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem];
3533 newItem = TREEVIEW_GetLastListItem (infoPtr, newItem);
3534 hNewSelection = newItem->hItem;
3536 if (! newItem->visible)
3537 cyChangeNeeds = infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3542 if ( (prevItem->cChildren > 0) && (prevItem->state & TVIS_EXPANDED) )
3544 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect );
3546 else if ((INT)prevItem->parent)
3548 newItem = (& infoPtr->items[(INT)prevItem->parent]);
3549 if (! newItem->visible)
3550 /* FIXME find a way to make this item the first visible... */
3553 hNewSelection = newItem->hItem;
3559 if ( ( prevItem->cChildren > 0) ||
3560 ( prevItem->cChildren == I_CHILDRENCALLBACK))
3562 if (! (prevItem->state & TVIS_EXPANDED))
3563 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect );
3566 newItem = (& infoPtr->items[(INT)prevItem->firstChild]);
3567 hNewSelection = newItem->hItem;
3574 if (! (prevItem->state & TVIS_EXPANDED))
3575 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect );
3579 if (prevItem->state & TVIS_EXPANDED)
3580 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect );
3585 newItem=TREEVIEW_GetListItem(
3588 -1*(TREEVIEW_GetVisibleCount(hwnd,0,0)-3));
3592 hNewSelection = newItem->hItem;
3594 if (! newItem->visible)
3595 scrollNeeds = SB_PAGEUP;
3600 newItem=TREEVIEW_GetListItem(
3603 TREEVIEW_GetVisibleCount(hwnd,0,0)-3);
3608 hNewSelection = newItem->hItem;
3610 if (! newItem->visible)
3611 scrollNeeds = SB_PAGEDOWN;
3620 FIXME("%x not implemented\n", wParam);
3627 This works but does not send notification...
3629 prevItem->state &= ~TVIS_SELECTED;
3630 newItem->state |= TVIS_SELECTED;
3631 infoPtr->selectedItem = hNewSelection;
3632 TREEVIEW_QueueRefresh (hwnd);
3635 if ( TREEVIEW_DoSelectItem(
3638 (HTREEITEM)hNewSelection,
3641 /* If selection change is allowed for the new item, perform scrolling */
3642 if (scrollNeeds != -1)
3643 TREEVIEW_VScroll(hwnd, scrollNeeds, 0);
3645 if (cyChangeNeeds != -1)
3646 infoPtr->cy = cyChangeNeeds;
3648 /* FIXME: Something happen in the load the in the two weeks before
3649 april 1st 1999 which makes this SetFocus mandatory otherwise, the focus
3650 is lost... However the SetFocus should not be required...*/
3661 TREEVIEW_GetScrollTime (HWND hwnd)
3663 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3665 return infoPtr->uScrollTime;
3670 TREEVIEW_SetScrollTime (HWND hwnd, UINT uScrollTime)
3672 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3673 UINT uOldScrollTime = infoPtr->uScrollTime;
3675 infoPtr->uScrollTime = min (uScrollTime, 100);
3677 return uOldScrollTime;
3681 static LRESULT WINAPI
3682 TREEVIEW_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3684 if (uMsg==WM_CREATE)
3685 return TREEVIEW_Create (hwnd, wParam, lParam);
3687 if (!TREEVIEW_GetInfoPtr(hwnd))
3688 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
3692 case TVM_INSERTITEMA:
3693 return TREEVIEW_InsertItemA (hwnd, wParam, lParam);
3695 case TVM_INSERTITEMW:
3696 return TREEVIEW_InsertItemW(hwnd,wParam,lParam);;
3698 case TVM_DELETEITEM:
3699 return TREEVIEW_DeleteItem (hwnd, wParam, lParam);
3702 return TREEVIEW_Expand (hwnd, wParam, lParam);
3704 case TVM_GETITEMRECT:
3705 return TREEVIEW_GetItemRect (hwnd, wParam, lParam);
3708 return TREEVIEW_GetCount (hwnd, wParam, lParam);
3711 return TREEVIEW_GetIndent (hwnd);
3714 return TREEVIEW_SetIndent (hwnd, wParam);
3716 case TVM_GETIMAGELIST:
3717 return TREEVIEW_GetImageList (hwnd, wParam, lParam);
3719 case TVM_SETIMAGELIST:
3720 return TREEVIEW_SetImageList (hwnd, wParam, lParam);
3722 case TVM_GETNEXTITEM:
3723 return TREEVIEW_GetNextItem (hwnd, wParam, lParam);
3725 case TVM_SELECTITEM:
3726 return TREEVIEW_SelectItem (hwnd, wParam, lParam);
3729 return TREEVIEW_GetItemA (hwnd, wParam, lParam);
3732 FIXME("Unimplemented msg TVM_GETITEMW\n");
3736 return TREEVIEW_SetItemA (hwnd, wParam, lParam);
3739 FIXME("Unimplemented msg TVM_SETITEMW\n");
3742 case TVM_EDITLABELA:
3743 FIXME("Unimplemented msg TVM_EDITLABELA \n");
3746 case TVM_EDITLABELW:
3747 FIXME("Unimplemented msg TVM_EDITLABELW \n");
3750 case TVM_GETEDITCONTROL:
3751 return TREEVIEW_GetEditControl (hwnd);
3753 case TVM_GETVISIBLECOUNT:
3754 return TREEVIEW_GetVisibleCount (hwnd, wParam, lParam);
3757 return TREEVIEW_HitTest (hwnd, lParam);
3759 case TVM_CREATEDRAGIMAGE:
3760 return TREEVIEW_CreateDragImage (hwnd, wParam, lParam);
3762 case TVM_SORTCHILDREN:
3763 return TREEVIEW_SortChildren (hwnd, wParam, lParam);
3765 case TVM_ENSUREVISIBLE:
3766 FIXME("Unimplemented msg TVM_ENSUREVISIBLE\n");
3769 case TVM_SORTCHILDRENCB:
3770 return TREEVIEW_SortChildrenCB(hwnd, wParam, lParam);
3772 case TVM_ENDEDITLABELNOW:
3773 return TREEVIEW_EndEditLabelNow (hwnd, wParam, lParam);
3775 case TVM_GETISEARCHSTRINGA:
3776 FIXME("Unimplemented msg TVM_GETISEARCHSTRINGA\n");
3779 case TVM_GETISEARCHSTRINGW:
3780 FIXME("Unimplemented msg TVM_GETISEARCHSTRINGW\n");
3783 case TVM_GETTOOLTIPS:
3784 return TREEVIEW_GetToolTips (hwnd);
3786 case TVM_SETTOOLTIPS:
3787 return TREEVIEW_SetToolTips (hwnd, wParam);
3789 case TVM_SETINSERTMARK:
3790 return TREEVIEW_SetInsertMark (hwnd,wParam, lParam);
3792 case TVM_SETITEMHEIGHT:
3793 return TREEVIEW_SetItemHeight (hwnd, wParam);
3795 case TVM_GETITEMHEIGHT:
3796 return TREEVIEW_GetItemHeight (hwnd);
3798 case TVM_SETBKCOLOR:
3799 return TREEVIEW_SetBkColor (hwnd, wParam, lParam);
3801 case TVM_SETTEXTCOLOR:
3802 return TREEVIEW_SetTextColor (hwnd, wParam, lParam);
3804 case TVM_GETBKCOLOR:
3805 return TREEVIEW_GetBkColor (hwnd);
3807 case TVM_GETTEXTCOLOR:
3808 return TREEVIEW_GetTextColor (hwnd);
3810 case TVM_SETSCROLLTIME:
3811 return TREEVIEW_SetScrollTime (hwnd, (UINT)wParam);
3813 case TVM_GETSCROLLTIME:
3814 return TREEVIEW_GetScrollTime (hwnd);
3816 case TVM_GETITEMSTATE:
3817 return TREEVIEW_GetItemState (hwnd,wParam, lParam);
3819 case TVM_GETLINECOLOR:
3820 return TREEVIEW_GetLineColor (hwnd,wParam, lParam);
3822 case TVM_SETLINECOLOR:
3823 return TREEVIEW_SetLineColor (hwnd,wParam, lParam);
3825 case TVM_SETINSERTMARKCOLOR:
3826 return TREEVIEW_SetInsertMarkColor (hwnd,wParam, lParam);
3828 case TVM_GETINSERTMARKCOLOR:
3829 return TREEVIEW_GetInsertMarkColor (hwnd,wParam, lParam);
3831 case TVM_SETUNICODEFORMAT:
3832 FIXME("Unimplemented msg TVM_SETUNICODEFORMAT\n");
3835 case TVM_GETUNICODEFORMAT:
3836 FIXME("Unimplemented msg TVM_GETUNICODEFORMAT\n");
3840 return TREEVIEW_Command (hwnd, wParam, lParam);
3843 return TREEVIEW_Destroy (hwnd);
3845 /* case WM_ENABLE: */
3848 return TREEVIEW_EraseBackground (hwnd, wParam, lParam);
3851 return DLGC_WANTARROWS | DLGC_WANTCHARS;
3854 return TREEVIEW_Paint (hwnd, wParam, lParam);
3857 return TREEVIEW_GetFont (hwnd, wParam, lParam);
3860 return TREEVIEW_SetFont (hwnd, wParam, lParam);
3863 return TREEVIEW_KeyDown (hwnd, wParam, lParam);
3866 return TREEVIEW_SetFocus (hwnd, wParam, lParam);
3869 return TREEVIEW_KillFocus (hwnd, wParam, lParam);
3871 case WM_LBUTTONDOWN:
3872 return TREEVIEW_LButtonDown (hwnd, wParam, lParam);
3875 return TREEVIEW_LButtonUp (hwnd, wParam, lParam);
3877 case WM_LBUTTONDBLCLK:
3878 return TREEVIEW_LButtonDoubleClick (hwnd, wParam, lParam);
3880 case WM_RBUTTONDOWN:
3881 return TREEVIEW_RButtonDown (hwnd, wParam, lParam);
3884 return TREEVIEW_RButtonUp (hwnd, wParam, lParam);
3887 return TREEVIEW_MouseMove (hwnd, wParam, lParam);
3889 case WM_STYLECHANGED:
3890 return TREEVIEW_StyleChanged (hwnd, wParam, lParam);
3892 /* case WM_SYSCOLORCHANGE: */
3893 /* case WM_SETREDRAW: */
3896 return TREEVIEW_HandleTimer (hwnd, wParam, lParam);
3899 return TREEVIEW_Size (hwnd, wParam,lParam);
3902 return TREEVIEW_HScroll (hwnd, wParam, lParam);
3904 return TREEVIEW_VScroll (hwnd, wParam, lParam);
3907 TRACE ("drawItem\n");
3908 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
3911 if (uMsg >= WM_USER)
3912 FIXME("Unknown msg %04x wp=%08x lp=%08lx\n",
3913 uMsg, wParam, lParam);
3914 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
3921 TREEVIEW_Register (void)
3927 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
3928 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
3929 wndClass.lpfnWndProc = (WNDPROC)TREEVIEW_WindowProc;
3930 wndClass.cbClsExtra = 0;
3931 wndClass.cbWndExtra = sizeof(TREEVIEW_INFO *);
3932 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
3933 wndClass.hbrBackground = 0;
3934 wndClass.lpszClassName = WC_TREEVIEWA;
3936 RegisterClassA (&wndClass);
3941 TREEVIEW_Unregister (void)
3943 UnregisterClassA (WC_TREEVIEWA, (HINSTANCE)NULL);