3 * Copyright 1998 Eric Kohl <ekohl@abo.rhein-zeitung.de>
4 * Copyright 1998,1999 Alex Priem <alexp@sci.kun.nl>
5 * Copyright 1999 Sylvain St-Germain
9 * Using DPA to store the item ptr would be good.
10 * Node label edition is implemented but something appened in wine in the
11 * two last weeks of march 99 that broke it.
13 -small array containing info about positions.
14 -better implementation of RefreshItem:
15 1) draw lines between parents
17 3) draw lines from parent<->items.
18 -implement partial drawing?
19 * -drag&drop: TVM_CREATEDRAGIMAGE should create drag bitmap.
20 * -scrollbars: horizontal scrollbar doesn't work.
24 * FIXME: check fontsize. (uRealItemHeight)
25 * test focusItem (redraw in different color)
28 better implementation.
29 * WM_HSCROLL is broken.
30 * use separate routine to get item text/image.
32 * Separate drawing/calculation.
34 * FIXMEs (for personal use)
35 Expand: -ctlmacro expands twice ->toggle.
36 -DblClick: ctlmacro.exe's NM_DBLCLK seems to go wrong (returns FALSE).
37 -treehelper: stack corruption makes big window.
47 #include "debugtools.h"
49 DEFAULT_DEBUG_CHANNEL(treeview)
51 /* ffs should be in <string.h>. */
53 /* Defines, since they do not need to return previous state, and nr
54 * has no side effects in this file.
56 #define tv_test_bit(nr,bf) (((LPBYTE)bf)[nr>>3]&(1<<(nr&7)))
57 #define tv_set_bit(nr,bf) ((LPBYTE)bf)[nr>>3]|=(1<<(nr&7))
58 #define tv_clear_bit(nr,bf) ((LPBYTE)bf)[nr>>3]&=~(1<<(nr&7))
61 #define TREEVIEW_GetInfoPtr(hwnd) \
62 ((TREEVIEW_INFO *) GetWindowLongA( hwnd, 0))
65 TREEVIEW_SendSimpleNotify (HWND hwnd, UINT code);
67 TREEVIEW_SendTreeviewNotify (HWND hwnd, UINT code, UINT action,
68 HTREEITEM oldItem, HTREEITEM newItem);
70 TREEVIEW_SendTreeviewDnDNotify (HWND hwnd, UINT code, HTREEITEM dragItem,
73 TREEVIEW_SendDispInfoNotify (HWND hwnd, TREEVIEW_ITEM *wineItem,
74 UINT code, UINT what);
76 TREEVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
79 TREEVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
80 TREEVIEW_ITEM *tvItem, UINT uItemDrawState);
82 TREEVIEW_DoSelectItem (HWND hwnd, INT action, HTREEITEM newSelect, INT cause);
84 TREEVIEW_Refresh (HWND hwnd);
86 static LRESULT CALLBACK
87 TREEVIEW_Edit_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam,
91 TREEVIEW_EndEditLabelNow (HWND hwnd, WPARAM wParam, LPARAM lParam);
96 /* helper functions. Work with the assumption that validity of operands
97 is checked beforehand, and that tree state is valid. */
99 /* FIXME: MS documentation says `GetNextVisibleItem' returns NULL
100 if not succesfull'. Probably only applies to derefencing infoPtr
101 (ie we are offered a valid treeview structure)
102 and not whether there is a next `visible' child.
103 FIXME: check other failures.
106 /***************************************************************************
107 * This method returns the TREEVIEW_ITEM object given the handle
109 static TREEVIEW_ITEM* TREEVIEW_ValidItem(
110 TREEVIEW_INFO *infoPtr,
113 if ((!handle) || (handle>infoPtr->uMaxHandle))
116 if (tv_test_bit ((INT)handle, infoPtr->freeList))
119 return &infoPtr->items[(INT)handle];
122 /***************************************************************************
123 * This method returns the last expanded child item of a tree node
125 static TREEVIEW_ITEM *TREEVIEW_GetLastListItem(
126 TREEVIEW_INFO *infoPtr,
127 TREEVIEW_ITEM *tvItem)
130 TREEVIEW_ITEM *wineItem = tvItem;
133 * Get this item last sibling
135 while (wineItem->sibling)
136 wineItem=& infoPtr->items [(INT)wineItem->sibling];
139 * If the last sibling has expanded children, restart.
141 if ( ( wineItem->cChildren > 0 ) && ( wineItem->state & TVIS_EXPANDED) )
142 return TREEVIEW_GetLastListItem(
144 &(infoPtr->items[(INT)wineItem->firstChild]));
149 /***************************************************************************
150 * This method returns the previous physical item in the list not
151 * considering the tree hierarchy.
153 static TREEVIEW_ITEM *TREEVIEW_GetPrevListItem(
154 TREEVIEW_INFO *infoPtr,
155 TREEVIEW_ITEM *tvItem)
157 if (tvItem->upsibling)
160 * This item has a upsibling, get the last item. Since, GetLastListItem
161 * first looks at siblings, we must feed it with the first child.
163 TREEVIEW_ITEM *upItem = &infoPtr->items[(INT)tvItem->upsibling];
165 if ( ( upItem->cChildren > 0 ) && ( upItem->state & TVIS_EXPANDED) )
166 return TREEVIEW_GetLastListItem(
168 &infoPtr->items[(INT)upItem->firstChild]);
175 * this item does not have a upsibling, get the parent
178 return &infoPtr->items[(INT)tvItem->parent];
185 /***************************************************************************
186 * This method returns the next physical item in the treeview not
187 * considering the tree hierarchy.
189 static TREEVIEW_ITEM *TREEVIEW_GetNextListItem(
190 TREEVIEW_INFO *infoPtr,
191 TREEVIEW_ITEM *tvItem)
193 TREEVIEW_ITEM *wineItem = NULL;
196 * If this item has children and is expanded, return the first child
198 if ((tvItem->firstChild) && (tvItem->state & TVIS_EXPANDED))
199 return (& infoPtr->items[(INT)tvItem->firstChild]);
203 * try to get the sibling
206 return (& infoPtr->items[(INT)tvItem->sibling]);
209 * Otherwise, get the parent's sibling.
212 while (wineItem->parent) {
213 wineItem=& infoPtr->items [(INT)wineItem->parent];
214 if (wineItem->sibling)
215 return (& infoPtr->items [(INT)wineItem->sibling]);
221 /***************************************************************************
222 * This method returns the nth item starting at the given item. It returns
223 * the last item (or first) we we run out of items.
225 * Will scroll backward if count is <0.
226 * forward if count is >0.
228 static TREEVIEW_ITEM *TREEVIEW_GetListItem(
229 TREEVIEW_INFO *infoPtr,
230 TREEVIEW_ITEM *tvItem,
233 TREEVIEW_ITEM *previousItem = NULL;
234 TREEVIEW_ITEM *wineItem = tvItem;
239 /* Find count item downward */
240 while ((iter++ < count) && (wineItem != NULL))
242 /* Keep a pointer to the previous in case we ask for more than we got */
243 previousItem = wineItem;
244 wineItem = TREEVIEW_GetNextListItem(infoPtr, wineItem);
247 if (wineItem == NULL)
248 wineItem = previousItem;
252 /* Find count item upward */
253 while ((iter-- > count) && (wineItem != NULL))
255 /* Keep a pointer to the previous in case we ask for more than we got */
256 previousItem = wineItem;
257 wineItem = TREEVIEW_GetPrevListItem(infoPtr, wineItem);
260 if (wineItem == NULL)
261 wineItem = previousItem;
270 /***************************************************************************
273 static void TREEVIEW_RemoveAllChildren(
275 TREEVIEW_ITEM *parentItem)
277 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
278 TREEVIEW_ITEM *killItem;
281 kill=(INT)parentItem->firstChild;
283 tv_set_bit ( kill, infoPtr->freeList);
284 killItem=& infoPtr->items[kill];
285 if (killItem->pszText!=LPSTR_TEXTCALLBACKA)
286 COMCTL32_Free (killItem->pszText);
287 TREEVIEW_SendTreeviewNotify (hwnd, TVN_DELETEITEM, 0, (HTREEITEM)kill, 0);
288 if (killItem->firstChild)
289 TREEVIEW_RemoveAllChildren (hwnd, killItem);
290 kill=(INT)killItem->sibling;
293 if (parentItem->cChildren>0) {
294 infoPtr->uNumItems -= parentItem->cChildren;
295 parentItem->firstChild = 0;
296 parentItem->cChildren = 0;
303 TREEVIEW_RemoveItem (HWND hwnd, TREEVIEW_ITEM *wineItem)
306 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
307 TREEVIEW_ITEM *parentItem, *upsiblingItem, *siblingItem;
310 iItem=(INT)wineItem->hItem;
311 tv_set_bit(iItem,infoPtr->freeList);
312 infoPtr->uNumItems--;
314 if (wineItem->pszText!=LPSTR_TEXTCALLBACKA)
315 COMCTL32_Free (wineItem->pszText);
317 TREEVIEW_SendTreeviewNotify (hwnd, TVN_DELETEITEM, 0, (HTREEITEM)iItem, 0);
319 if (wineItem->firstChild)
320 TREEVIEW_RemoveAllChildren (hwnd,wineItem);
322 if (wineItem->parent) {
323 parentItem=& infoPtr->items [(INT)wineItem->parent];
324 switch (parentItem->cChildren) {
325 case I_CHILDRENCALLBACK:
326 FIXME("we don't handle I_CHILDRENCALLBACK yet\n");
329 parentItem->cChildren=0;
330 parentItem->firstChild=0;
333 parentItem->cChildren--;
334 if ((INT)parentItem->firstChild==iItem)
335 parentItem->firstChild=wineItem->sibling;
339 if (iItem==(INT)infoPtr->TopRootItem)
340 infoPtr->TopRootItem=(HTREEITEM)wineItem->sibling;
341 if (wineItem->upsibling) {
342 upsiblingItem=& infoPtr->items [(INT)wineItem->upsibling];
343 upsiblingItem->sibling=wineItem->sibling;
345 if (wineItem->sibling) {
346 siblingItem=& infoPtr->items [(INT)wineItem->sibling];
347 siblingItem->upsibling=wineItem->upsibling;
355 /* Note:TREEVIEW_RemoveTree doesn't remove infoPtr itself */
357 static void TREEVIEW_RemoveTree (HWND hwnd)
360 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
361 TREEVIEW_ITEM *killItem;
364 for (i=1; i<=(INT)infoPtr->uMaxHandle; i++)
365 if (!tv_test_bit (i, infoPtr->freeList)) {
366 killItem=& infoPtr->items [i];
367 if (killItem->pszText!=LPSTR_TEXTCALLBACKA)
368 COMCTL32_Free (killItem->pszText);
369 TREEVIEW_SendTreeviewNotify
370 (hwnd, TVN_DELETEITEM, 0, killItem->hItem, 0);
373 if (infoPtr->uNumPtrsAlloced) {
374 COMCTL32_Free (infoPtr->items);
375 COMCTL32_Free (infoPtr->freeList);
376 infoPtr->uNumItems=0;
377 infoPtr->uNumPtrsAlloced=0;
378 infoPtr->uMaxHandle=0;
389 TREEVIEW_GetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
391 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
394 if (infoPtr==NULL) return 0;
396 if ((INT)wParam == TVSIL_NORMAL)
397 return (LRESULT) infoPtr->himlNormal;
398 if ((INT)wParam == TVSIL_STATE)
399 return (LRESULT) infoPtr->himlState;
405 TREEVIEW_SetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
407 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
411 switch ((INT)wParam) {
413 himlTemp = infoPtr->himlNormal;
414 infoPtr->himlNormal = (HIMAGELIST)lParam;
415 return (LRESULT)himlTemp;
418 himlTemp = infoPtr->himlState;
419 infoPtr->himlState = (HIMAGELIST)lParam;
420 return (LRESULT)himlTemp;
423 return (LRESULT)NULL;
429 TREEVIEW_SetItemHeight (HWND hwnd, WPARAM wParam)
431 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
432 INT cx,cy,prevHeight=infoPtr->uItemHeight;
438 infoPtr->uItemHeight=-1;
442 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &cy);
444 if (wParam>cy) cy=wParam;
445 infoPtr->uItemHeight=cy;
447 if (!( GetWindowLongA( hwnd, GWL_STYLE) & TVS_NONEVENHEIGHT))
448 infoPtr->uItemHeight = (INT) wParam & 0xfffffffe;
453 TREEVIEW_GetItemHeight (HWND hwnd)
455 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
458 return infoPtr->uItemHeight;
462 TREEVIEW_GetLineColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
464 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
467 return (LRESULT) infoPtr->clrLine;
471 TREEVIEW_SetLineColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
473 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
474 COLORREF prevColor=infoPtr->clrLine;
477 infoPtr->clrLine=(COLORREF) lParam;
478 return (LRESULT) prevColor;
482 TREEVIEW_SetTextColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
484 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
485 COLORREF prevColor=infoPtr->clrText;
488 infoPtr->clrText=(COLORREF) lParam;
489 return (LRESULT) prevColor;
493 TREEVIEW_GetBkColor (HWND hwnd)
495 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
498 return (LRESULT) infoPtr->clrText;
502 TREEVIEW_SetBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
504 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
505 COLORREF prevColor=infoPtr->clrBk;
508 infoPtr->clrBk=(COLORREF) lParam;
509 return (LRESULT) prevColor;
513 TREEVIEW_GetTextColor (HWND hwnd)
515 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
518 return (LRESULT) infoPtr->clrBk;
522 /* cdmode: custom draw mode as received from app. in first NMCUSTOMDRAW
525 #define TREEVIEW_LEFT_MARGIN 8
529 TREEVIEW_DrawItem (HWND hwnd, HDC hdc, TREEVIEW_ITEM *wineItem)
531 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
532 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
533 INT center,xpos,cx,cy, cditem, drawmode;
535 UINT uTextJustify = DT_LEFT;
539 if (wineItem->state & TVIS_BOLD)
540 hOldFont = SelectObject (hdc, infoPtr->hBoldFont);
542 hOldFont = SelectObject (hdc, infoPtr->hFont);
545 TRACE ("cdmode:%x\n",infoPtr->cdmode);
546 if (infoPtr->cdmode & CDRF_NOTIFYITEMDRAW) {
547 drawmode=CDDS_ITEMPREPAINT;
549 if (infoPtr->cdmode & CDRF_NOTIFYSUBITEMDRAW)
550 drawmode|=CDDS_SUBITEM;
552 cditem=TREEVIEW_SendCustomDrawItemNotify (hwnd, hdc, wineItem, drawmode);
554 TRACE("cditem:%d\n",cditem);
556 if (cditem & CDRF_SKIPDEFAULT)
561 * Set drawing starting points
563 r = wineItem->rect; /* this item rectangle */
564 center = (r.top+r.bottom)/2; /* this item vertical center */
565 xpos = r.left + TREEVIEW_LEFT_MARGIN;/* horizontal starting point */
568 * Display the tree hierarchy
570 if ( dwStyle & TVS_HASLINES)
573 * Write links to parent node
574 * we draw the L starting from the child to the parent
576 * points[0] is attached to the current item
577 * points[1] is the L corner
578 * points[2] is attached to the parent or the up sibling
580 if ( dwStyle & TVS_LINESATROOT)
582 TREEVIEW_ITEM *upNode = NULL;
583 BOOL hasParentOrSibling = TRUE;
584 RECT upRect = {0,0,0,0};
585 HPEN hOldPen, hnewPen;
588 * determine the target location of the line at root, either be linked
589 * to the up sibling or to the parent node.
591 if (wineItem->upsibling)
592 upNode = TREEVIEW_ValidItem (infoPtr, wineItem->upsibling);
593 else if (wineItem->parent)
594 upNode = TREEVIEW_ValidItem (infoPtr, wineItem->parent);
596 hasParentOrSibling = FALSE;
599 upRect = upNode->rect;
601 if ( wineItem->iLevel == 0 )
603 points[2].x = points[1].x = upRect.left+8;
604 points[0].x = points[2].x + 10;
605 points[2].y = upRect.bottom-3;
606 points[1].y = points[0].y = center;
610 points[2].x = points[1].x = 8 + (20*wineItem->iLevel);
611 points[2].y = ( upNode->cChildren == 0) ?
612 upRect.top : /* is linked to the "L" above */
613 ( wineItem->upsibling != NULL) ?
614 upRect.bottom-3: /* is linked to an icon */
615 upRect.bottom+1; /* is linked to a +/- box */
616 points[1].y = points[0].y = center;
617 points[0].x = points[1].x + 10;
623 hnewPen = CreatePen(PS_DOT, 0, infoPtr->clrLine);
624 hOldPen = SelectObject( hdc, hnewPen );
626 if (hasParentOrSibling)
627 Polyline (hdc,points,3);
629 Polyline (hdc,points,2);
631 DeleteObject(hnewPen);
632 SelectObject(hdc, hOldPen);
637 * Display the (+/-) signs
639 if (wineItem->iLevel != 0)/* update position only for non root node */
640 xpos+=(5*wineItem->iLevel);
642 if (( dwStyle & TVS_HASBUTTONS) && ( dwStyle & TVS_HASLINES))
644 if ( (wineItem->cChildren) ||
645 (wineItem->cChildren == I_CHILDRENCALLBACK))
647 /* Setup expand box coordinate to facilitate the LMBClick handling */
648 wineItem->expandBox.left = xpos-4;
649 wineItem->expandBox.top = center-4;
650 wineItem->expandBox.right = xpos+5;
651 wineItem->expandBox.bottom = center+5;
655 wineItem->expandBox.left,
656 wineItem->expandBox.top ,
657 wineItem->expandBox.right,
658 wineItem->expandBox.bottom);
660 MoveToEx (hdc, xpos-2, center, NULL);
661 LineTo (hdc, xpos+3, center);
663 if (!(wineItem->state & TVIS_EXPANDED)) {
664 MoveToEx (hdc, xpos, center-2, NULL);
665 LineTo (hdc, xpos, center+3);
671 * Display the image assiciated with this item
673 xpos += 13; /* update position */
674 if (wineItem->mask & (TVIF_IMAGE|TVIF_SELECTEDIMAGE)) {
676 HIMAGELIST *himlp = NULL;
678 if (infoPtr->himlNormal)
679 himlp=&infoPtr->himlNormal; /* get the image list */
681 if ( (wineItem->state & TVIS_SELECTED) &&
682 (wineItem->iSelectedImage)) {
684 /* State images are displayed to the left of the Normal image*/
685 if (infoPtr->himlState)
686 himlp=&infoPtr->himlState;
688 /* The item is curently selected */
689 if (wineItem->iSelectedImage == I_IMAGECALLBACK)
690 TREEVIEW_SendDispInfoNotify (
696 imageIndex = wineItem->iSelectedImage;
699 /* This item is not selected */
700 if (wineItem->iImage == I_IMAGECALLBACK)
701 TREEVIEW_SendDispInfoNotify (
707 imageIndex = wineItem->iImage;
712 /* We found an image to display? Draw it. */
721 ImageList_GetIconSize (*himlp, &cx, &cy);
727 * Display the text assiciated with this item
730 if ((wineItem->mask & TVIF_TEXT) && (wineItem->pszText))
732 COLORREF oldBkColor = 0;
733 COLORREF oldTextColor = 0;
739 wineItem->text.left = r.left;
740 wineItem->text.right = r.right;
741 wineItem->text.top = r.top;
742 wineItem->text.bottom= r.bottom;
744 if (wineItem->state & (TVIS_SELECTED | TVIS_DROPHILITED) ) {
745 oldBkMode = SetBkMode (hdc, OPAQUE);
746 oldBkColor = SetBkColor (hdc, GetSysColor( COLOR_HIGHLIGHT));
747 oldTextColor = SetTextColor(hdc, GetSysColor( COLOR_HIGHLIGHTTEXT));
751 oldBkMode = SetBkMode(hdc, TRANSPARENT);
752 oldTextColor = SetTextColor(hdc, GetSysColor( COLOR_WINDOWTEXT));
755 if (wineItem->pszText== LPSTR_TEXTCALLBACKA) {
756 TRACE("LPSTR_TEXTCALLBACK\n");
757 TREEVIEW_SendDispInfoNotify (hwnd, wineItem, TVN_GETDISPINFO, TVIF_TEXT);
764 lstrlenA(wineItem->pszText),
766 uTextJustify | DT_VCENTER | DT_SINGLELINE );
768 /* Obtain the text coordinate */
772 lstrlenA(wineItem->pszText),
774 uTextJustify | DT_VCENTER | DT_SINGLELINE | DT_CALCRECT);
776 /* Restore the hdc state */
777 SetTextColor( hdc, oldTextColor);
779 if (oldBkMode != TRANSPARENT)
780 SetBkMode(hdc, oldBkMode);
781 if (wineItem->state & (TVIS_SELECTED | TVIS_DROPHILITED))
782 SetBkColor (hdc, oldBkColor);
784 /* Draw the box arround the selected item */
785 if (wineItem->state & TVIS_SELECTED )
787 HPEN hnewPen = CreatePen(PS_DOT, 0, GetSysColor(COLOR_WINDOWTEXT) );
788 HPEN hOldPen = SelectObject( hdc, hnewPen );
791 points[0].x = wineItem->text.left-1;
792 points[0].y = wineItem->text.top+1;
793 points[1].x = wineItem->text.right;
794 points[1].y = wineItem->text.top+1;
795 points[2].x = wineItem->text.right;
796 points[2].y = wineItem->text.bottom;
797 points[3].x = wineItem->text.left-1;
798 points[3].y = wineItem->text.bottom;
800 Polyline (hdc,points,4);
802 DeleteObject(hnewPen);
803 SelectObject(hdc, hOldPen);
807 if (cditem & CDRF_NOTIFYPOSTPAINT)
808 TREEVIEW_SendCustomDrawItemNotify (hwnd, hdc, wineItem, CDDS_ITEMPOSTPAINT);
810 SelectObject (hdc, hOldFont);
814 TREEVIEW_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
816 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
817 TREEVIEW_ITEM *wineItem;
819 LPRECT lpRect = (LPRECT)lParam;
823 * validate parameters
825 if ( (infoPtr==NULL) || (lpRect == NULL) )
828 if (infoPtr->Timer & TV_REFRESH_TIMER_SET)
829 TREEVIEW_Refresh (hwnd); /* we want a rect for the current view */
832 * retrive the item ptr
834 iItem = (HTREEITEM *) lParam;
835 wineItem = TREEVIEW_ValidItem (infoPtr, *iItem);
836 if ((!wineItem) || (!wineItem->visible))
840 * If wParam is TRUE return the text size otherwise return
841 * the whole item size
844 lpRect->left = wineItem->text.left;
845 lpRect->right = wineItem->text.right;
846 lpRect->bottom = wineItem->text.bottom;
847 lpRect->top = wineItem->text.top;
849 lpRect->left = wineItem->rect.left;
850 lpRect->right = wineItem->rect.right;
851 lpRect->bottom = wineItem->rect.bottom;
852 lpRect->top = wineItem->rect.top;
855 TRACE("[L:%d R:%d T:%d B:%d]\n",
856 lpRect->left,lpRect->right,
857 lpRect->top,lpRect->bottom);
863 TREEVIEW_GetVisibleCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
866 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
868 return (LRESULT) infoPtr->uVisibleHeight / infoPtr->uRealItemHeight;
874 TREEVIEW_SetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
876 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
877 TREEVIEW_ITEM *wineItem;
881 tvItem=(LPTVITEMEXA) lParam;
882 iItem=(INT)tvItem->hItem;
883 TRACE("item %d,mask %x\n",iItem,tvItem->mask);
885 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
886 if (!wineItem) return FALSE;
888 if (tvItem->mask & TVIF_CHILDREN) {
889 wineItem->cChildren=tvItem->cChildren;
892 if (tvItem->mask & TVIF_IMAGE) {
893 wineItem->iImage=tvItem->iImage;
896 if (tvItem->mask & TVIF_INTEGRAL) {
897 wineItem->iIntegral=tvItem->iIntegral;
900 if (tvItem->mask & TVIF_PARAM) {
901 wineItem->lParam=tvItem->lParam;
904 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
905 wineItem->iSelectedImage=tvItem->iSelectedImage;
908 if (tvItem->mask & TVIF_STATE) {
909 wineItem->state=tvItem->state & tvItem->stateMask;
912 if (tvItem->mask & TVIF_TEXT) {
913 if (tvItem->pszText!=LPSTR_TEXTCALLBACKA) {
914 len=lstrlenA (tvItem->pszText);
915 if (len>wineItem->cchTextMax)
916 wineItem->pszText= COMCTL32_ReAlloc (wineItem->pszText, len+1);
917 lstrcpynA (wineItem->pszText, tvItem->pszText,len);
919 if (wineItem->cchTextMax) {
920 COMCTL32_Free (wineItem->pszText);
921 wineItem->cchTextMax=0;
923 wineItem->pszText=LPSTR_TEXTCALLBACKA;
931 TREEVIEW_GetItemState (HWND hwnd, WPARAM wParam, LPARAM lParam)
934 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
935 TREEVIEW_ITEM *wineItem;
937 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)wParam);
938 if (!wineItem) return 0;
940 return (wineItem->state & lParam);
948 TREEVIEW_Refresh (HWND hwnd)
951 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
956 INT iItem, indent, x, y, cx, height, itemHeight;
957 INT viewtop,viewbottom,viewleft,viewright;
958 TREEVIEW_ITEM *wineItem, *prevItem;
964 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
965 KillTimer (hwnd, TV_REFRESH_TIMER);
966 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
970 GetClientRect (hwnd, &rect);
971 if ((rect.left-rect.right ==0) || (rect.top-rect.bottom==0)) return;
973 infoPtr->cdmode=TREEVIEW_SendCustomDrawNotify
974 (hwnd, CDDS_PREPAINT, hdc, rect);
976 if (infoPtr->cdmode==CDRF_SKIPDEFAULT) {
977 ReleaseDC (hwnd, hdc);
981 infoPtr->uVisibleHeight= rect.bottom-rect.top;
982 infoPtr->uVisibleWidth= rect.right-rect.left;
985 viewbottom=infoPtr->cy + rect.bottom-rect.top;
986 viewleft=infoPtr->cx;
987 viewright=infoPtr->cx + rect.right-rect.left;
991 /* draw background */
993 hbrBk = GetSysColorBrush (COLOR_WINDOW);
994 FillRect(hdc, &rect, hbrBk);
997 iItem=(INT)infoPtr->TopRootItem;
998 infoPtr->firstVisible=0;
1002 TRACE("[%d %d %d %d]\n",viewtop,viewbottom,viewleft,viewright);
1006 wineItem= & infoPtr->items[iItem];
1007 wineItem->iLevel=indent;
1009 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &itemHeight);
1010 if (infoPtr->uItemHeight>itemHeight)
1011 itemHeight=infoPtr->uItemHeight;
1013 GetTextMetricsA (hdc, &tm);
1014 if ((tm.tmHeight + tm.tmExternalLeading) > itemHeight)
1015 itemHeight=tm.tmHeight + tm.tmExternalLeading;
1017 infoPtr->uRealItemHeight=itemHeight;
1020 /* FIXME: remove this in later stage */
1022 if (wineItem->pszText!=LPSTR_TEXTCALLBACK32A)
1023 TRACE (treeview, "%d %d [%d %d %d %d] (%s)\n",y,x,
1024 wineItem->rect.top, wineItem->rect.bottom,
1025 wineItem->rect.left, wineItem->rect.right,
1028 TRACE (treeview, "%d [%d %d %d %d] (CALLBACK)\n",
1030 wineItem->rect.top, wineItem->rect.bottom,
1031 wineItem->rect.left, wineItem->rect.right);
1034 height=itemHeight * wineItem->iIntegral +1;
1035 if ((y >= viewtop) && (y <= viewbottom) &&
1036 (x >= viewleft ) && (x <= viewright)) {
1037 wineItem->visible = TRUE;
1038 wineItem->rect.top = y - infoPtr->cy + rect.top;
1039 wineItem->rect.bottom = wineItem->rect.top + height ;
1040 wineItem->rect.left = x - infoPtr->cx + rect.left;
1041 wineItem->rect.right = rect.right;
1042 if (!infoPtr->firstVisible)
1043 infoPtr->firstVisible=wineItem->hItem;
1044 TREEVIEW_DrawItem (hwnd, hdc, wineItem);
1047 wineItem->visible = FALSE;
1048 wineItem->rect.left = wineItem->rect.top = 0;
1049 wineItem->rect.right= wineItem->rect.bottom = 0;
1050 wineItem->text.left = wineItem->text.top = 0;
1051 wineItem->text.right= wineItem->text.bottom = 0;
1054 /* look up next item */
1056 if ((wineItem->firstChild) && (wineItem->state & TVIS_EXPANDED)) {
1057 iItem=(INT)wineItem->firstChild;
1059 x+=infoPtr->uIndent;
1060 if (x>infoPtr->uTotalWidth)
1061 infoPtr->uTotalWidth=x;
1064 iItem=(INT)wineItem->sibling;
1065 while ((!iItem) && (indent>0)) {
1067 x-=infoPtr->uIndent;
1069 wineItem=&infoPtr->items[(INT)wineItem->parent];
1070 iItem=(INT)wineItem->sibling;
1076 /* FIXME: infoPtr->uTotalWidth should also take item label into account */
1077 /* FIXME: or should query item sizes (ie check CDRF_NEWFONT) */
1079 infoPtr->uTotalHeight=y;
1080 if (y >= (viewbottom-viewtop)) {
1081 if (!(infoPtr->uInternalStatus & TV_VSCROLL))
1082 ShowScrollBar (hwnd, SB_VERT, TRUE);
1083 infoPtr->uInternalStatus |=TV_VSCROLL;
1084 SetScrollRange (hwnd, SB_VERT, 0,
1085 y - infoPtr->uVisibleHeight, FALSE);
1086 SetScrollPos (hwnd, SB_VERT, infoPtr->cy, TRUE);
1089 if (infoPtr->uInternalStatus & TV_VSCROLL)
1090 ShowScrollBar (hwnd, SB_VERT, FALSE);
1091 infoPtr->uInternalStatus &= ~TV_VSCROLL;
1095 if (infoPtr->cdmode & CDRF_NOTIFYPOSTPAINT)
1096 infoPtr->cdmode=TREEVIEW_SendCustomDrawNotify
1097 (hwnd, CDDS_POSTPAINT, hdc, rect);
1099 ReleaseDC (hwnd, hdc);
1105 TREEVIEW_HandleTimer (HWND hwnd, WPARAM wParam, LPARAM lParam)
1107 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1109 TRACE(" %d\n",wParam);
1110 if (!infoPtr) return FALSE;
1113 case TV_REFRESH_TIMER:
1114 KillTimer (hwnd, TV_REFRESH_TIMER);
1115 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
1116 InvalidateRect(hwnd, NULL, FALSE);
1119 KillTimer (hwnd, TV_EDIT_TIMER);
1120 infoPtr->Timer &= ~TV_EDIT_TIMER_SET;
1123 ERR("got unknown timer\n");
1131 TREEVIEW_QueueRefresh (HWND hwnd)
1134 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1137 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
1138 KillTimer (hwnd, TV_REFRESH_TIMER);
1141 SetTimer (hwnd, TV_REFRESH_TIMER, TV_REFRESH_DELAY, 0);
1142 infoPtr->Timer|=TV_REFRESH_TIMER_SET;
1148 TREEVIEW_GetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1150 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1152 TREEVIEW_ITEM *wineItem;
1155 tvItem=(LPTVITEMEXA) lParam;
1156 iItem=(INT)tvItem->hItem;
1158 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1159 if (!wineItem) return FALSE;
1161 if (tvItem->mask & TVIF_CHILDREN) {
1162 if (TVIF_CHILDREN==I_CHILDRENCALLBACK)
1163 FIXME("I_CHILDRENCALLBACK not supported\n");
1164 tvItem->cChildren=wineItem->cChildren;
1167 if (tvItem->mask & TVIF_HANDLE) {
1168 tvItem->hItem=wineItem->hItem;
1171 if (tvItem->mask & TVIF_IMAGE) {
1172 tvItem->iImage=wineItem->iImage;
1175 if (tvItem->mask & TVIF_INTEGRAL) {
1176 tvItem->iIntegral=wineItem->iIntegral;
1179 /* undocumented: windows ignores TVIF_PARAM and
1180 * always sets lParam
1182 tvItem->lParam=wineItem->lParam;
1184 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
1185 tvItem->iSelectedImage=wineItem->iSelectedImage;
1188 if (tvItem->mask & TVIF_STATE) {
1189 tvItem->state=wineItem->state & tvItem->stateMask;
1192 if (tvItem->mask & TVIF_TEXT) {
1193 if (wineItem->pszText == LPSTR_TEXTCALLBACKA) {
1194 tvItem->pszText = LPSTR_TEXTCALLBACKA; /* FIXME:send notification? */
1195 ERR(" GetItem called with LPSTR_TEXTCALLBACK\n");
1197 else if (wineItem->pszText) {
1198 lstrcpynA (tvItem->pszText, wineItem->pszText, tvItem->cchTextMax);
1202 TRACE("item %d<%p>, txt %p, img %p, action %x\n",
1214 /* FIXME: check implementation of TVGN_NEXT/TVGN_NEXTVISIBLE */
1217 TREEVIEW_GetNextItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
1220 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1221 TREEVIEW_ITEM *wineItem, *returnItem;
1222 INT iItem, retval, flag;
1225 if (!infoPtr) return FALSE;
1226 flag = (INT) wParam;
1227 iItem = (INT) lParam;
1230 case TVGN_ROOT: retval=(INT)infoPtr->TopRootItem;
1232 case TVGN_CARET:retval=(INT)infoPtr->selectedItem;
1234 case TVGN_FIRSTVISIBLE:
1235 TREEVIEW_Refresh (hwnd);
1236 /* FIXME:we should only recalculate, not redraw */
1237 retval=(INT)infoPtr->firstVisible;
1239 case TVGN_DROPHILITE:
1240 retval=(INT)infoPtr->dropItem;
1244 TRACE("flags:%x, returns %u\n", flag, retval);
1248 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1250 if (!wineItem) return FALSE;
1253 case TVGN_NEXT: retval=(INT)wineItem->sibling;
1256 retval=(INT)wineItem->upsibling;
1259 retval=(INT)wineItem->parent;
1262 retval=(INT)wineItem->firstChild;
1264 case TVGN_LASTVISIBLE:
1265 returnItem=TREEVIEW_GetLastListItem (infoPtr,wineItem);
1267 case TVGN_NEXTVISIBLE:
1268 returnItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
1270 case TVGN_PREVIOUSVISIBLE:
1271 returnItem=TREEVIEW_GetPrevListItem (infoPtr, wineItem);
1273 default: FIXME("Unknown msg %x,item %x\n", flag,iItem);
1278 TRACE("flags:%x, item %d;returns %d\n", flag, iItem,
1279 (INT)returnItem->hItem);
1280 return (INT)returnItem->hItem;
1283 TRACE("flags:%x, item %d;returns %d\n", flag, iItem,retval);
1289 TREEVIEW_GetCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
1291 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1293 TRACE(" %d\n",infoPtr->uNumItems);
1294 return (LRESULT) infoPtr->uNumItems;
1297 /***************************************************************************
1298 * This method does the chaining of the insertion of a treeview item
1300 * If parent is NULL, we're inserting at the root of the list.
1302 static void TREEVIEW_InsertBefore(
1303 TREEVIEW_INFO *infoPtr,
1304 TREEVIEW_ITEM *newItem,
1305 TREEVIEW_ITEM *sibling,
1306 TREEVIEW_ITEM *parent)
1308 HTREEITEM siblingHandle = 0;
1309 HTREEITEM upSiblingHandle = 0;
1310 TREEVIEW_ITEM *upSibling = NULL;
1312 if (newItem == NULL)
1313 ERR("NULL newItem, impossible condition\n");
1315 if (sibling != NULL) /* Insert before this sibling for this parent */
1317 /* Store the new item sibling up sibling and sibling tem handle */
1318 siblingHandle = sibling->hItem;
1319 upSiblingHandle = sibling->upsibling;
1320 /* As well as a pointer to the upsibling sibling object */
1321 if ( (INT)sibling->upsibling != 0 )
1322 upSibling = &infoPtr->items[(INT)sibling->upsibling];
1324 /* Adjust the sibling pointer */
1325 sibling->upsibling = newItem->hItem;
1327 /* Adjust the new item pointers */
1328 newItem->upsibling = upSiblingHandle;
1329 newItem->sibling = siblingHandle;
1331 /* Adjust the up sibling pointer */
1332 if ( upSibling != NULL )
1333 upSibling->sibling = newItem->hItem;
1335 /* this item is the first child of this parent, adjust parent pointers */
1337 parent->firstChild = newItem->hItem;
1339 infoPtr->TopRootItem= newItem->hItem;
1341 else /* Insert as first child of this parent */
1343 parent->firstChild = newItem->hItem;
1346 /***************************************************************************
1347 * This method does the chaining of the insertion of a treeview item
1349 * If parent is NULL, we're inserting at the root of the list.
1351 static void TREEVIEW_InsertAfter(
1352 TREEVIEW_INFO *infoPtr,
1353 TREEVIEW_ITEM *newItem,
1354 TREEVIEW_ITEM *upSibling,
1355 TREEVIEW_ITEM *parent)
1357 HTREEITEM upSiblingHandle = 0;
1358 HTREEITEM siblingHandle = 0;
1359 TREEVIEW_ITEM *sibling = NULL;
1362 if (newItem == NULL)
1363 ERR("NULL newItem, impossible condition\n");
1365 if (upSibling != NULL) /* Insert after this upsibling for this parent */
1367 /* Store the new item up sibling and sibling item handle */
1368 upSiblingHandle = upSibling->hItem;
1369 siblingHandle = upSibling->sibling;
1370 /* As well as a pointer to the upsibling sibling object */
1371 if ( (INT)upSibling->sibling != 0 )
1372 sibling = &infoPtr->items[(INT)upSibling->sibling];
1374 /* Adjust the up sibling pointer */
1375 upSibling->sibling = newItem->hItem;
1377 /* Adjust the new item pointers */
1378 newItem->upsibling = upSiblingHandle;
1379 newItem->sibling = siblingHandle;
1381 /* Adjust the sibling pointer */
1382 if ( sibling != NULL )
1383 sibling->upsibling = newItem->hItem;
1386 newItem is the last of the level, nothing else to do
1389 else /* Insert as first child of this parent */
1391 parent->firstChild = newItem->hItem;
1394 /***************************************************************************
1395 * Forward the DPA local callback to the treeview owner callback
1397 static INT WINAPI TREEVIEW_CallBackCompare(
1402 /* Forward the call to the client define callback */
1403 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr((HWND)tvInfoPtr);
1404 return (infoPtr->pCallBackSort->lpfnCompare)(
1405 ((TREEVIEW_ITEM*)first)->lParam,
1406 ((TREEVIEW_ITEM*)second)->lParam,
1407 infoPtr->pCallBackSort->lParam);
1410 /***************************************************************************
1411 * Treeview native sort routine: sort on item text.
1413 static INT WINAPI TREEVIEW_SortOnName (
1418 HWND hwnd=(HWND) tvInfoPtr;
1420 TREEVIEW_ITEM *item;
1423 item=(TREEVIEW_ITEM *) first;
1424 if (item->pszText==LPSTR_TEXTCALLBACKA) {
1425 TREEVIEW_SendDispInfoNotify (hwnd, item, TVN_GETDISPINFO, TVIF_TEXT);
1429 item=(TREEVIEW_ITEM *) second;
1430 if (item->pszText==LPSTR_TEXTCALLBACKA) {
1431 TREEVIEW_SendDispInfoNotify (hwnd, item, TVN_GETDISPINFO, TVIF_TEXT);
1435 return -strcmp (txt1,txt2);
1438 /***************************************************************************
1439 * Setup the treeview structure with regards of the sort method
1440 * and sort the children of the TV item specified in lParam
1441 * fRecurse: currently unused. Should be zero.
1442 * parent: if pSort!=NULL, should equal pSort->hParent.
1443 * otherwise, item which child items are to be sorted.
1444 * pSort: sort method info. if NULL, sort on item text.
1445 * if non-NULL, sort on item's lParam content, and let the
1446 * application decide what that means. See also TVM_SORTCHILDRENCB.
1449 static LRESULT WINAPI TREEVIEW_Sort (
1456 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1457 TREEVIEW_ITEM *sortMe = NULL; /* Node for which we sort the children */
1459 /* Obtain the TVSORTBC struct */
1460 infoPtr->pCallBackSort = pSort;
1462 /* undocumented feature: TVI_ROOT means `sort the whole tree' */
1464 if (parent==TVI_ROOT)
1465 parent=infoPtr->TopRootItem;
1467 /* Check for a valid handle to the parent item */
1468 if (!TREEVIEW_ValidItem(infoPtr, parent))
1470 ERR ("invalid item hParent=%x\n", (INT)parent);
1474 /* Obtain the parent node to sort */
1475 sortMe = &infoPtr->items[ (INT)parent ];
1477 /* Make sure there is something to sort */
1478 if ( sortMe->cChildren > 1 )
1480 /* pointer organization */
1481 HDPA sortList = DPA_Create(sortMe->cChildren);
1482 HTREEITEM itemHandle = sortMe->firstChild;
1483 TREEVIEW_ITEM *itemPtr = & infoPtr->items[ (INT)itemHandle ];
1485 /* TREEVIEW_ITEM rechaining */
1491 /* Build the list of item to sort */
1495 sortList, /* the list */
1496 sortMe->cChildren+1, /* force the insertion to be an append */
1497 itemPtr); /* the ptr to store */
1499 /* Get the next sibling */
1500 itemHandle = itemPtr->sibling;
1501 itemPtr = & infoPtr->items[ (INT)itemHandle ];
1502 } while ( itemHandle != NULL );
1504 /* let DPA perform the sort activity */
1507 sortList, /* what */
1508 TREEVIEW_CallBackCompare, /* how */
1512 sortList, /* what */
1513 TREEVIEW_SortOnName, /* how */
1517 * Reorganized TREEVIEW_ITEM structures.
1518 * Note that we know we have at least two elements.
1521 /* Get the first item and get ready to start... */
1522 item = DPA_GetPtr(sortList, count++);
1523 while ( (nextItem = DPA_GetPtr(sortList, count++)) != NULL )
1525 /* link the two current item toghether */
1526 ((TREEVIEW_ITEM*)item)->sibling = ((TREEVIEW_ITEM*)nextItem)->hItem;
1527 ((TREEVIEW_ITEM*)nextItem)->upsibling = ((TREEVIEW_ITEM*)item)->hItem;
1529 if (prevItem == NULL) /* this is the first item, update the parent */
1531 sortMe->firstChild = ((TREEVIEW_ITEM*)item)->hItem;
1532 ((TREEVIEW_ITEM*)item)->upsibling = NULL;
1534 else /* fix the back chaining */
1536 ((TREEVIEW_ITEM*)item)->upsibling = ((TREEVIEW_ITEM*)prevItem)->hItem;
1539 /* get ready for the next one */
1544 /* the last item is pointed to by item and never has a sibling */
1545 ((TREEVIEW_ITEM*)item)->sibling = NULL;
1547 DPA_Destroy(sortList);
1555 /***************************************************************************
1556 * Setup the treeview structure with regards of the sort method
1557 * and sort the children of the TV item specified in lParam
1559 static LRESULT WINAPI TREEVIEW_SortChildrenCB(
1565 LPTVSORTCB pSort=(LPTVSORTCB) lParam;
1567 return TREEVIEW_Sort (hwnd, wParam, pSort->hParent, pSort);
1571 /***************************************************************************
1572 * Sort the children of the TV item specified in lParam.
1574 static LRESULT WINAPI TREEVIEW_SortChildren (
1579 return TREEVIEW_Sort (hwnd, (BOOL) wParam, (HTREEITEM) lParam, NULL);
1584 /* the method used below isn't the most memory-friendly, but it avoids
1585 a lot of memory reallocations */
1587 /* BTW: we waste handle 0; 0 is not an allowed handle. */
1590 TREEVIEW_InsertItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1593 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1594 TVINSERTSTRUCTA *ptdi;
1596 TREEVIEW_ITEM *wineItem, *parentItem, *prevsib, *sibItem;
1597 INT iItem,listItems,i,len;
1599 /* Item to insert */
1600 ptdi = (LPTVINSERTSTRUCTA) lParam;
1602 /* check if memory is available */
1604 if (infoPtr->uNumPtrsAlloced==0) {
1605 infoPtr->items = COMCTL32_Alloc (TVITEM_ALLOC*sizeof (TREEVIEW_ITEM));
1606 infoPtr->freeList= COMCTL32_Alloc ((1+(TVITEM_ALLOC>>5)) * sizeof (INT));
1607 infoPtr->uNumPtrsAlloced=TVITEM_ALLOC;
1608 infoPtr->TopRootItem=(HTREEITEM)1;
1612 * Reallocate contiguous space for items
1614 if (infoPtr->uNumItems == (infoPtr->uNumPtrsAlloced-1) ) {
1615 TREEVIEW_ITEM *oldItems = infoPtr->items;
1616 INT *oldfreeList = infoPtr->freeList;
1618 infoPtr->uNumPtrsAlloced*=2;
1619 infoPtr->items = COMCTL32_Alloc (infoPtr->uNumPtrsAlloced*sizeof (TREEVIEW_ITEM));
1620 infoPtr->freeList= COMCTL32_Alloc ((1+(infoPtr->uNumPtrsAlloced>>5))*sizeof (INT));
1622 memcpy (&infoPtr->items[0], &oldItems[0],
1623 infoPtr->uNumPtrsAlloced/2 * sizeof(TREEVIEW_ITEM));
1624 memcpy (&infoPtr->freeList[0], &oldfreeList[0],
1625 (infoPtr->uNumPtrsAlloced>>6) * sizeof(INT));
1627 COMCTL32_Free (oldItems);
1628 COMCTL32_Free (oldfreeList);
1632 * Reset infoPtr structure with new stat according to current TV picture
1635 infoPtr->uNumItems++;
1636 if ((INT)infoPtr->uMaxHandle==(infoPtr->uNumItems-1)) {
1637 iItem=infoPtr->uNumItems;
1638 infoPtr->uMaxHandle = (HTREEITEM)((INT)infoPtr->uMaxHandle + 1);
1639 } else { /* check freelist */
1640 for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++) {
1641 if (infoPtr->freeList[i]) {
1642 iItem=ffs (infoPtr->freeList[i])-1;
1643 tv_clear_bit(iItem,&infoPtr->freeList[i]);
1650 if (TRACE_ON(treeview)) {
1651 for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++)
1652 TRACE("%8x\n",infoPtr->freeList[i]);
1655 if (!iItem) ERR("Argh -- can't find free item.\n");
1658 * Find the parent item of the new item
1660 tvItem= & ptdi->DUMMYUNIONNAME.itemex;
1661 wineItem=& infoPtr->items[iItem];
1663 if ((ptdi->hParent==TVI_ROOT) || (ptdi->hParent==0)) {
1665 wineItem->parent = 0;
1666 sibItem = &infoPtr->items [(INT)infoPtr->TopRootItem];
1667 listItems = infoPtr->uNumItems;
1670 parentItem = &infoPtr->items[(INT)ptdi->hParent];
1672 /* Do the insertion here it if it's the only item of this parent */
1673 if (!parentItem->firstChild)
1674 parentItem->firstChild=(HTREEITEM)iItem;
1676 wineItem->parent = ptdi->hParent;
1677 sibItem = &infoPtr->items [(INT)parentItem->firstChild];
1678 parentItem->cChildren++;
1679 listItems = parentItem->cChildren;
1683 /* NOTE: I am moving some setup of the wineItem object that was initialy
1684 * done at the end of the function since some of the values are
1685 * required by the Callback sorting
1688 if (tvItem->mask & TVIF_TEXT)
1691 * Setup the item text stuff here since it's required by the Sort method
1692 * when the insertion are ordered
1694 if (tvItem->pszText!=LPSTR_TEXTCALLBACKA)
1696 TRACE("(%p,%s)\n", &tvItem->pszText, tvItem->pszText);
1697 len = lstrlenA (tvItem->pszText)+1;
1698 wineItem->pszText= COMCTL32_Alloc (len+1);
1699 lstrcpyA (wineItem->pszText, tvItem->pszText);
1700 wineItem->cchTextMax=len;
1704 TRACE("LPSTR_TEXTCALLBACK\n");
1705 wineItem->pszText = LPSTR_TEXTCALLBACKA;
1706 wineItem->cchTextMax = 0;
1710 if (tvItem->mask & TVIF_PARAM)
1711 wineItem->lParam=tvItem->lParam;
1714 wineItem->upsibling=0; /* needed in case we're the first item in a list */
1715 wineItem->sibling=0;
1716 wineItem->firstChild=0;
1717 wineItem->hItem=(HTREEITEM)iItem;
1722 switch ((DWORD) ptdi->hInsertAfter) {
1723 case (DWORD) TVI_FIRST:
1724 if (wineItem->parent) {
1725 wineItem->sibling=parentItem->firstChild;
1726 parentItem->firstChild=(HTREEITEM)iItem;
1728 wineItem->sibling=infoPtr->TopRootItem;
1729 infoPtr->TopRootItem=(HTREEITEM)iItem;
1731 sibItem->upsibling=(HTREEITEM)iItem;
1734 case (DWORD) TVI_SORT:
1735 if (sibItem==wineItem)
1737 * This item is the first child of the level and it
1738 * has already been inserted
1743 TREEVIEW_ITEM *aChild;
1746 TREEVIEW_ITEM *previousChild = NULL;
1747 BOOL bItemInserted = FALSE;
1750 aChild = &infoPtr->items[(INT)parentItem->firstChild];
1752 aChild = &infoPtr->items[(INT)infoPtr->TopRootItem];
1754 /* Iterate the parent children to see where we fit in */
1755 while ( aChild != NULL )
1757 INT comp = strcmp(wineItem->pszText, aChild->pszText);
1758 if ( comp < 0 ) /* we are smaller than the current one */
1760 TREEVIEW_InsertBefore(infoPtr, wineItem, aChild, parentItem);
1761 bItemInserted = TRUE;
1764 else if ( comp > 0 ) /* we are bigger than the current one */
1766 previousChild = aChild;
1767 aChild = (aChild->sibling == 0) /* This will help us to exit */
1768 ? NULL /* if there is no more sibling */
1769 : &infoPtr->items[(INT)aChild->sibling];
1771 /* Look at the next item */
1774 else if ( comp == 0 )
1777 * An item with this name is already existing, therefore,
1778 * we add after the one we found
1780 TREEVIEW_InsertAfter(infoPtr, wineItem, aChild, parentItem);
1781 bItemInserted = TRUE;
1787 * we reach the end of the child list and the item as not
1788 * yet been inserted, therefore, insert it after the last child.
1790 if ( (! bItemInserted ) && (aChild == NULL) )
1791 TREEVIEW_InsertAfter(infoPtr, wineItem, previousChild, parentItem);
1797 case (DWORD) TVI_LAST:
1798 if (sibItem==wineItem) break;
1799 while (sibItem->sibling) {
1801 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1803 sibItem->sibling=(HTREEITEM)iItem;
1804 wineItem->upsibling=sibItem->hItem;
1807 while ((sibItem->sibling) && (sibItem->hItem!=ptdi->hInsertAfter))
1810 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1812 if (sibItem->hItem!=ptdi->hInsertAfter) {
1813 ERR("tried to insert item after nonexisting handle %d.\n",
1814 (INT) ptdi->hInsertAfter);
1818 if (sibItem->sibling) {
1819 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1820 sibItem->upsibling=(HTREEITEM)iItem;
1821 wineItem->sibling=sibItem->hItem;
1823 prevsib->sibling=(HTREEITEM)iItem;
1824 wineItem->upsibling=prevsib->hItem;
1830 /* Fill in info structure */
1832 TRACE("new item %d; parent %d, mask %x\n", iItem,
1833 (INT)wineItem->parent,tvItem->mask);
1835 wineItem->mask=tvItem->mask;
1836 wineItem->iIntegral=1;
1838 if (tvItem->mask & TVIF_CHILDREN) {
1839 wineItem->cChildren=tvItem->cChildren;
1840 if (tvItem->cChildren==I_CHILDRENCALLBACK)
1841 FIXME(" I_CHILDRENCALLBACK not supported\n");
1844 wineItem->expandBox.left = 0; /* Initialize the expandBox */
1845 wineItem->expandBox.top = 0;
1846 wineItem->expandBox.right = 0;
1847 wineItem->expandBox.bottom = 0;
1849 if (tvItem->mask & TVIF_IMAGE)
1850 wineItem->iImage=tvItem->iImage;
1852 /* If the application sets TVIF_INTEGRAL without
1853 supplying a TVITEMEX structure, it's toast */
1855 if (tvItem->mask & TVIF_INTEGRAL)
1856 wineItem->iIntegral=tvItem->iIntegral;
1858 if (tvItem->mask & TVIF_SELECTEDIMAGE)
1859 wineItem->iSelectedImage=tvItem->iSelectedImage;
1861 if (tvItem->mask & TVIF_STATE) {
1862 TRACE("Changing item state from %d to %d\n",
1865 wineItem->state=tvItem->state;
1866 wineItem->stateMask=tvItem->stateMask;
1870 TREEVIEW_QueueRefresh (hwnd);
1872 return (LRESULT) iItem;
1877 TREEVIEW_InsertItemW(HWND hwnd, WPARAM wParam, LPARAM lParam)
1879 TVINSERTSTRUCTW *tvisW;
1880 TVINSERTSTRUCTA tvisA;
1883 tvisW = (LPTVINSERTSTRUCTW)lParam;
1885 tvisA.hParent = tvisW->hParent;
1886 tvisA.hInsertAfter = tvisW->hInsertAfter;
1888 tvisA.DUMMYUNIONNAME.item.mask = tvisW->DUMMYUNIONNAME.item.mask;
1889 tvisA.DUMMYUNIONNAME.item.hItem = tvisW->DUMMYUNIONNAME.item.hItem;
1890 tvisA.DUMMYUNIONNAME.item.state = tvisW->DUMMYUNIONNAME.item.state;
1891 tvisA.DUMMYUNIONNAME.item.stateMask = tvisW->DUMMYUNIONNAME.item.stateMask;
1892 tvisA.DUMMYUNIONNAME.item.cchTextMax = tvisW->DUMMYUNIONNAME.item.cchTextMax;
1894 if(tvisW->DUMMYUNIONNAME.item.pszText)
1896 if (tvisW->DUMMYUNIONNAME.item.pszText!=LPSTR_TEXTCALLBACKW)
1898 int len = lstrlenW (tvisW->DUMMYUNIONNAME.item.pszText)+1;
1899 tvisA.DUMMYUNIONNAME.item.pszText = COMCTL32_Alloc (len);
1900 lstrcpyWtoA (tvisA.DUMMYUNIONNAME.item.pszText,
1901 tvisW->DUMMYUNIONNAME.item.pszText );
1905 tvisA.DUMMYUNIONNAME.item.pszText = LPSTR_TEXTCALLBACKA;
1906 tvisA.DUMMYUNIONNAME.item.cchTextMax = 0;
1910 tvisA.DUMMYUNIONNAME.item.iImage = tvisW->DUMMYUNIONNAME.item.iImage;
1911 tvisA.DUMMYUNIONNAME.item.iSelectedImage = tvisW->DUMMYUNIONNAME.item.iSelectedImage;
1912 tvisA.DUMMYUNIONNAME.item.cChildren = tvisW->DUMMYUNIONNAME.item.cChildren;
1913 tvisA.DUMMYUNIONNAME.item.lParam = tvisW->DUMMYUNIONNAME.item.lParam;
1915 lRes = TREEVIEW_InsertItemA(hwnd,wParam,(LPARAM)&tvisA);
1917 if (tvisA.DUMMYUNIONNAME.item.pszText!=LPSTR_TEXTCALLBACKA)
1919 COMCTL32_Free(tvisA.DUMMYUNIONNAME.item.pszText);
1928 TREEVIEW_DeleteItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
1930 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1932 TREEVIEW_ITEM *wineItem;
1935 if (!infoPtr) return FALSE;
1937 if (lParam == (INT)TVI_ROOT) {
1938 TREEVIEW_RemoveTree (hwnd);
1940 iItem= (INT) lParam;
1941 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1942 if (!wineItem) return FALSE;
1943 TRACE("%s\n",wineItem->pszText);
1944 TREEVIEW_RemoveItem (hwnd, wineItem);
1947 TREEVIEW_QueueRefresh (hwnd);
1955 TREEVIEW_GetIndent (HWND hwnd)
1957 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1960 return infoPtr->uIndent;
1964 TREEVIEW_SetIndent (HWND hwnd, WPARAM wParam)
1966 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1970 newIndent=(INT) wParam;
1971 if (newIndent < MINIMUM_INDENT) newIndent=MINIMUM_INDENT;
1972 infoPtr->uIndent=newIndent;
1978 TREEVIEW_GetToolTips (HWND hwnd)
1981 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1984 return infoPtr->hwndToolTip;
1989 TREEVIEW_SetToolTips (HWND hwnd, WPARAM wParam)
1992 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1996 prevToolTip=infoPtr->hwndToolTip;
1997 infoPtr->hwndToolTip= (HWND) wParam;
2003 static LRESULT CALLBACK
2004 TREEVIEW_GetEditControl (HWND hwnd)
2007 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2009 return infoPtr->hwndEdit;
2013 TREEVIEW_Edit_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam,
2021 HDC hdc = (HDC) wParam;
2022 GetClientRect (hwnd, &rc);
2023 Rectangle (hdc, rc.left, rc.top, rc.right, rc.bottom);
2029 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
2034 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd));
2035 return CallWindowProcA( infoPtr->wpEditOrig, hwnd, uMsg, wParam, lParam);
2043 /* should handle edit control messages here */
2046 TREEVIEW_Command (HWND hwnd, WPARAM wParam, LPARAM lParam)
2049 TRACE("%x %ld\n",wParam, lParam);
2051 switch (HIWORD(wParam))
2056 * Adjust the edit window size
2058 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2059 TREEVIEW_ITEM *editItem = TREEVIEW_ValidItem(infoPtr, infoPtr->editItem);
2060 INT iLength = GetWindowTextLengthA(infoPtr->hwndEdit);
2061 HDC hdc = GetDC(infoPtr->hwndEdit);
2064 if ( GetTextMetricsA(hdc, &tm) )
2066 LONG newWidth = (iLength * tm.tmAveCharWidth) + 15;
2071 editItem->text.left - 2,
2072 editItem->text.top - 1,
2074 editItem->text.bottom - editItem->text.top + 3,
2077 ReleaseDC(hwnd, hdc);
2083 /* TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
2088 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
2095 TREEVIEW_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
2098 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2100 if (infoPtr->bAutoSize)
2102 infoPtr->bAutoSize = FALSE;
2105 infoPtr->bAutoSize = TRUE;
2107 if (wParam == SIZE_RESTORED)
2109 infoPtr->uTotalWidth = LOWORD (lParam);
2110 infoPtr->uTotalHeight = HIWORD (lParam);
2112 FIXME("WM_SIZE flag %x %lx not handled\n", wParam, lParam);
2115 TREEVIEW_QueueRefresh (hwnd);
2122 TREEVIEW_StyleChanged (HWND hwnd, WPARAM wParam, LPARAM lParam)
2124 TRACE("(%x %lx)\n",wParam,lParam);
2126 TREEVIEW_Refresh (hwnd);
2132 TREEVIEW_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
2134 TREEVIEW_INFO *infoPtr;
2139 TRACE("wnd %x\n",hwnd);
2140 /* allocate memory for info structure */
2141 infoPtr = (TREEVIEW_INFO *) COMCTL32_Alloc (sizeof(TREEVIEW_INFO));
2143 SetWindowLongA( hwnd, 0, (DWORD)infoPtr);
2145 if (infoPtr == NULL) {
2146 ERR("could not allocate info memory!\n");
2150 if ((TREEVIEW_INFO*) GetWindowLongA( hwnd, 0) != infoPtr) {
2151 ERR("pointer assignment error!\n");
2157 /* set default settings */
2158 infoPtr->uInternalStatus=0;
2159 infoPtr->uNumItems=0;
2160 infoPtr->clrBk = GetSysColor (COLOR_WINDOW);
2161 infoPtr->clrText = GetSysColor (COLOR_BTNTEXT);
2162 infoPtr->clrLine = GetSysColor (COLOR_WINDOWTEXT);
2165 infoPtr->uIndent = 15;
2166 infoPtr->himlNormal = NULL;
2167 infoPtr->himlState = NULL;
2168 infoPtr->uItemHeight = -1;
2169 GetTextMetricsA (hdc, &tm);
2170 infoPtr->hFont = GetStockObject (DEFAULT_GUI_FONT);
2171 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
2172 logFont.lfWeight=FW_BOLD;
2173 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
2175 infoPtr->items = NULL;
2176 infoPtr->selectedItem=0;
2177 infoPtr->clrText=-1; /* use system color */
2178 infoPtr->dropItem=0;
2179 infoPtr->pCallBackSort=NULL;
2180 infoPtr->uScrollTime = 300; /* milliseconds */
2183 infoPtr->hwndNotify = GetParent32 (hwnd);
2184 infoPtr->bTransparent = ( GetWindowLongA( hwnd, GWL_STYLE) & TBSTYLE_FLAT);
2187 infoPtr->hwndToolTip=0;
2188 if (!( GetWindowLongA( hwnd, GWL_STYLE) & TVS_NOTOOLTIPS)) { /* Create tooltip control */
2191 infoPtr->hwndToolTip =
2192 CreateWindowExA (0, TOOLTIPS_CLASSA, NULL, 0,
2193 CW_USEDEFAULT, CW_USEDEFAULT,
2194 CW_USEDEFAULT, CW_USEDEFAULT,
2197 /* Send NM_TOOLTIPSCREATED notification */
2198 if (infoPtr->hwndToolTip) {
2199 NMTOOLTIPSCREATED nmttc;
2201 nmttc.hdr.hwndFrom = hwnd;
2202 nmttc.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2203 nmttc.hdr.code = NM_TOOLTIPSCREATED;
2204 nmttc.hwndToolTips = infoPtr->hwndToolTip;
2206 SendMessageA (GetParent (hwnd), WM_NOTIFY,
2207 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmttc);
2210 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
2211 ti.cbSize = sizeof(TTTOOLINFOA);
2212 ti.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_TRANSPARENT ;
2215 ti.lpszText = "Test"; /* LPSTR_TEXTCALLBACK; */
2216 SetRectEmpty (&ti.rect);
2218 SendMessageA (infoPtr->hwndToolTip, TTM_ADDTOOLA, 0, (LPARAM)&ti);
2221 infoPtr->hwndEdit = CreateWindowExA (
2225 WS_CHILD | WS_BORDER | ES_AUTOHSCROLL |
2226 ES_WANTRETURN | ES_LEFT,
2229 0,0,0); /* FIXME: (HMENU)IDTVEDIT,pcs->hInstance,0);*/
2231 SendMessageA ( infoPtr->hwndEdit, WM_SETFONT, infoPtr->hFont, FALSE);
2232 infoPtr->wpEditOrig = (WNDPROC)SetWindowLongA (
2235 (LONG) TREEVIEW_Edit_SubclassProc);
2237 ReleaseDC (hwnd, hdc);
2244 TREEVIEW_Destroy (HWND hwnd)
2246 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2249 TREEVIEW_RemoveTree (hwnd);
2250 if (infoPtr->Timer & TV_REFRESH_TIMER_SET)
2251 KillTimer (hwnd, TV_REFRESH_TIMER);
2252 if (infoPtr->hwndToolTip)
2253 DestroyWindow (infoPtr->hwndToolTip);
2255 COMCTL32_Free (infoPtr);
2261 TREEVIEW_Paint (HWND hwnd, WPARAM wParam, LPARAM lParam)
2267 hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
2268 TREEVIEW_Refresh (hwnd);
2270 EndPaint (hwnd, &ps);
2273 return DefWindowProcA (hwnd, WM_PAINT, wParam, lParam);
2277 TREEVIEW_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2279 TREEVIEW_SendSimpleNotify (hwnd, NM_SETFOCUS);
2280 InvalidateRect(hwnd, NULL, FALSE);
2285 TREEVIEW_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2287 TREEVIEW_SendSimpleNotify (hwnd, NM_KILLFOCUS);
2288 InvalidateRect(hwnd, NULL, FALSE);
2293 TREEVIEW_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
2295 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2296 HBRUSH hBrush = CreateSolidBrush (infoPtr->clrBk);
2300 GetClientRect (hwnd, &rect);
2301 FillRect ((HDC)wParam, &rect, hBrush);
2302 DeleteObject (hBrush);
2318 TREEVIEW_SendSimpleNotify (HWND hwnd, UINT code)
2323 nmhdr.hwndFrom = hwnd;
2324 nmhdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2327 return (BOOL) SendMessageA (GetParent (hwnd), WM_NOTIFY,
2328 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
2334 TREEVIEW_SendTreeviewNotify (HWND hwnd, UINT code, UINT action,
2335 HTREEITEM oldItem, HTREEITEM newItem)
2338 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2340 TREEVIEW_ITEM *wineItem;
2342 TRACE("code:%x action:%x olditem:%x newitem:%x\n",
2343 code,action,(INT)oldItem,(INT)newItem);
2344 nmhdr.hdr.hwndFrom = hwnd;
2345 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2346 nmhdr.hdr.code = code;
2347 nmhdr.action = action;
2349 wineItem=& infoPtr->items[(INT)oldItem];
2350 nmhdr.itemOld.mask = wineItem->mask;
2351 nmhdr.itemOld.hItem = wineItem->hItem;
2352 nmhdr.itemOld.state = wineItem->state;
2353 nmhdr.itemOld.stateMask = wineItem->stateMask;
2354 nmhdr.itemOld.iImage = wineItem->iImage;
2355 nmhdr.itemOld.pszText = wineItem->pszText;
2356 nmhdr.itemOld.cchTextMax= wineItem->cchTextMax;
2357 nmhdr.itemOld.iImage = wineItem->iImage;
2358 nmhdr.itemOld.iSelectedImage = wineItem->iSelectedImage;
2359 nmhdr.itemOld.cChildren = wineItem->cChildren;
2360 nmhdr.itemOld.lParam = wineItem->lParam;
2364 wineItem=& infoPtr->items[(INT)newItem];
2365 nmhdr.itemNew.mask = wineItem->mask;
2366 nmhdr.itemNew.hItem = wineItem->hItem;
2367 nmhdr.itemNew.state = wineItem->state;
2368 nmhdr.itemNew.stateMask = wineItem->stateMask;
2369 nmhdr.itemNew.iImage = wineItem->iImage;
2370 nmhdr.itemNew.pszText = wineItem->pszText;
2371 nmhdr.itemNew.cchTextMax= wineItem->cchTextMax;
2372 nmhdr.itemNew.iImage = wineItem->iImage;
2373 nmhdr.itemNew.iSelectedImage = wineItem->iSelectedImage;
2374 nmhdr.itemNew.cChildren = wineItem->cChildren;
2375 nmhdr.itemNew.lParam = wineItem->lParam;
2381 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2382 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2387 TREEVIEW_SendTreeviewDnDNotify (HWND hwnd, UINT code, HTREEITEM dragItem,
2390 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2392 TREEVIEW_ITEM *wineItem;
2394 TRACE("code:%x dragitem:%x\n", code,(INT)dragItem);
2396 nmhdr.hdr.hwndFrom = hwnd;
2397 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2398 nmhdr.hdr.code = code;
2400 wineItem=& infoPtr->items[(INT)dragItem];
2401 nmhdr.itemNew.mask = wineItem->mask;
2402 nmhdr.itemNew.hItem = wineItem->hItem;
2403 nmhdr.itemNew.state = wineItem->state;
2404 nmhdr.itemNew.lParam = wineItem->lParam;
2406 nmhdr.ptDrag.x = pt.x;
2407 nmhdr.ptDrag.y = pt.y;
2409 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2410 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2417 TREEVIEW_SendDispInfoNotify (HWND hwnd, TREEVIEW_ITEM *wineItem,
2418 UINT code, UINT what)
2424 TRACE("item %d, action %x, state %d\n",
2425 (INT)wineItem->hItem,
2427 (INT)wineItem->state);
2429 tvdi.hdr.hwndFrom = hwnd;
2430 tvdi.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2431 tvdi.hdr.code = code;
2432 tvdi.item.mask = what;
2433 tvdi.item.hItem = wineItem->hItem;
2434 tvdi.item.state = wineItem->state;
2435 tvdi.item.lParam = wineItem->lParam;
2436 tvdi.item.pszText = COMCTL32_Alloc (128*sizeof(char));
2437 buf = tvdi.item.pszText;
2439 retval=(BOOL)SendMessageA (
2442 (WPARAM)tvdi.hdr.idFrom,
2445 if (what & TVIF_TEXT) {
2446 wineItem->pszText = tvdi.item.pszText;
2447 if (buf==tvdi.item.pszText) {
2448 wineItem->cchTextMax = 128;
2450 TRACE("user-supplied buffer\n");
2451 COMCTL32_Free (buf);
2452 wineItem->cchTextMax = 0;
2455 if (what & TVIF_SELECTEDIMAGE)
2456 wineItem->iSelectedImage = tvdi.item.iSelectedImage;
2457 if (what & TVIF_IMAGE)
2458 wineItem->iImage = tvdi.item.iImage;
2459 if (what & TVIF_CHILDREN)
2460 wineItem->cChildren = tvdi.item.cChildren;
2468 TREEVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
2471 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2472 NMTVCUSTOMDRAW nmcdhdr;
2473 LPNMCUSTOMDRAW nmcd;
2475 TRACE("drawstage:%lx hdc:%x\n", dwDrawStage, hdc);
2477 nmcd= & nmcdhdr.nmcd;
2478 nmcd->hdr.hwndFrom = hwnd;
2479 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2480 nmcd->hdr.code = NM_CUSTOMDRAW;
2481 nmcd->dwDrawStage= dwDrawStage;
2483 nmcd->rc.left = rc.left;
2484 nmcd->rc.right = rc.right;
2485 nmcd->rc.bottom = rc.bottom;
2486 nmcd->rc.top = rc.top;
2487 nmcd->dwItemSpec = 0;
2488 nmcd->uItemState = 0;
2489 nmcd->lItemlParam= 0;
2490 nmcdhdr.clrText = infoPtr->clrText;
2491 nmcdhdr.clrTextBk= infoPtr->clrBk;
2494 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2495 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2501 /* FIXME: need to find out when the flags in uItemState need to be set */
2504 TREEVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
2505 TREEVIEW_ITEM *wineItem, UINT uItemDrawState)
2507 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2508 NMTVCUSTOMDRAW nmcdhdr;
2509 LPNMCUSTOMDRAW nmcd;
2510 DWORD dwDrawStage,dwItemSpec;
2513 dwDrawStage=CDDS_ITEM | uItemDrawState;
2514 dwItemSpec=(DWORD)wineItem->hItem;
2516 if (wineItem->hItem==infoPtr->selectedItem) uItemState|=CDIS_SELECTED;
2517 if (wineItem->hItem==infoPtr->focusItem) uItemState|=CDIS_FOCUS;
2518 if (wineItem->hItem==infoPtr->hotItem) uItemState|=CDIS_HOT;
2520 nmcd= & nmcdhdr.nmcd;
2521 nmcd->hdr.hwndFrom = hwnd;
2522 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2523 nmcd->hdr.code = NM_CUSTOMDRAW;
2524 nmcd->dwDrawStage= dwDrawStage;
2526 nmcd->rc.left = wineItem->rect.left;
2527 nmcd->rc.right = wineItem->rect.right;
2528 nmcd->rc.bottom = wineItem->rect.bottom;
2529 nmcd->rc.top = wineItem->rect.top;
2530 nmcd->dwItemSpec = dwItemSpec;
2531 nmcd->uItemState = uItemState;
2532 nmcd->lItemlParam= wineItem->lParam;
2534 nmcdhdr.clrText = infoPtr->clrText;
2535 nmcdhdr.clrTextBk= infoPtr->clrBk;
2536 nmcdhdr.iLevel = wineItem->iLevel;
2538 TRACE("drawstage:%lx hdc:%x item:%lx, itemstate:%x\n",
2539 dwDrawStage, hdc, dwItemSpec, uItemState);
2541 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2542 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2547 /* Note:If the specified item is the child of a collapsed parent item,
2548 the parent's list of child items is (recursively) expanded to reveal the
2549 specified item. This is mentioned for TREEVIEW_SelectItem; don't
2550 know if it also applies here.
2554 TREEVIEW_Expand (HWND hwnd, WPARAM wParam, LPARAM lParam)
2556 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2557 TREEVIEW_ITEM *wineItem;
2561 flag = (UINT) wParam;
2562 expand = (INT) lParam;
2564 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2568 if (!wineItem->cChildren)
2571 if (wineItem->pszText==LPSTR_TEXTCALLBACKA)
2572 TRACE ("For item %d, flags %d, state %d\n",
2573 expand, flag, wineItem->state);
2575 TRACE("For (%s) item:%d, flags %x, state:%d\n",
2576 wineItem->pszText, flag, expand, wineItem->state);
2578 if (wineItem->cChildren==I_CHILDRENCALLBACK) {
2579 FIXME("we don't handle I_CHILDRENCALLBACK yet\n");
2583 if (flag == TVE_TOGGLE) { /* FIXME: check exact behaviour here */
2584 flag &= ~TVE_TOGGLE; /* ie: bitwise ops or 'case' ops */
2585 if (wineItem->state & TVIS_EXPANDED)
2586 flag |= TVE_COLLAPSE;
2593 case TVE_COLLAPSERESET:
2594 TRACE(" case TVE_COLLAPSERESET\n");
2595 if (!wineItem->state & TVIS_EXPANDED)
2598 wineItem->state &= ~(TVIS_EXPANDEDONCE | TVIS_EXPANDED);
2599 TREEVIEW_RemoveAllChildren (hwnd, wineItem);
2603 TRACE(" case TVE_COLLAPSE\n");
2604 if (!wineItem->state & TVIS_EXPANDED)
2607 wineItem->state &= ~TVIS_EXPANDED;
2611 TRACE(" case TVE_EXPAND\n");
2612 if (wineItem->state & TVIS_EXPANDED)
2615 TRACE(" is not expanded...\n");
2617 if (!(wineItem->state & TVIS_EXPANDEDONCE))
2619 TRACE(" and has never been expanded...\n");
2620 wineItem->state |= TVIS_EXPANDED;
2622 /* this item has never been expanded */
2623 if (TREEVIEW_SendTreeviewNotify (
2630 TRACE(" TVN_ITEMEXPANDING returned TRUE, exiting...\n");
2635 * Since the TVN_ITEMEXPANDING message may has caused the parent to
2636 * insert new items which in turn may have cause items placeholder
2637 * reallocation, I reassign the current item pointer so we have
2638 * something valid to work with...
2639 * However, this should not be necessary,
2640 * investigation required in TREEVIEW_InsertItemA
2642 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2646 "Catastropic situation, cannot retreive item #%d\n",
2651 wineItem->state |= TVIS_EXPANDEDONCE;
2652 TRACE(" TVN_ITEMEXPANDING sent...\n");
2654 TREEVIEW_SendTreeviewNotify (
2661 TRACE(" TVN_ITEMEXPANDED sent...\n");
2666 /* this item has already been expanded */
2667 wineItem->state |= TVIS_EXPANDED;
2671 case TVE_EXPANDPARTIAL:
2672 TRACE(" case TVE_EXPANDPARTIAL\n");
2673 FIXME("TVE_EXPANDPARTIAL not implemented\n");
2674 wineItem->state ^=TVIS_EXPANDED;
2675 wineItem->state |=TVIS_EXPANDEDONCE;
2679 TRACE("Exiting, Item %d state is now %d...\n",
2683 TREEVIEW_QueueRefresh (hwnd);
2689 static TREEVIEW_ITEM *
2690 TREEVIEW_HitTestPoint (HWND hwnd, POINT pt)
2692 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2693 TREEVIEW_ITEM *wineItem;
2696 GetClientRect (hwnd, &rect);
2698 if (!infoPtr->firstVisible) return NULL;
2700 wineItem=&infoPtr->items [(INT)infoPtr->firstVisible];
2702 while ((wineItem!=NULL) && (pt.y > wineItem->rect.bottom))
2703 wineItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
2715 TREEVIEW_HitTest (HWND hwnd, LPARAM lParam)
2717 LPTVHITTESTINFO lpht=(LPTVHITTESTINFO) lParam;
2718 TREEVIEW_ITEM *wineItem;
2722 GetClientRect (hwnd, &rect);
2726 if (x < rect.left) status|=TVHT_TOLEFT;
2727 if (x > rect.right) status|=TVHT_TORIGHT;
2728 if (y < rect.top ) status|=TVHT_ABOVE;
2729 if (y > rect.bottom) status|=TVHT_BELOW;
2736 wineItem=TREEVIEW_HitTestPoint (hwnd, lpht->pt);
2738 lpht->flags=TVHT_NOWHERE;
2742 /* FIXME: implement other flags
2743 * Assign the appropriate flags depending on the click location
2744 * Intitialize flags before to "|=" it...
2748 if (x < wineItem->expandBox.left)
2750 lpht->flags |= TVHT_ONITEMINDENT;
2752 else if ( ( x >= wineItem->expandBox.left) &&
2753 ( x <= wineItem->expandBox.right))
2755 lpht->flags |= TVHT_ONITEMBUTTON;
2757 else if (x < wineItem->rect.right)
2759 lpht->flags |= TVHT_ONITEMLABEL;
2763 lpht->flags|=TVHT_ONITEMRIGHT;
2766 lpht->hItem=wineItem->hItem;
2768 return (LRESULT) wineItem->hItem;
2772 TREEVIEW_EndEditLabelNow (HWND hwnd, WPARAM wParam, LPARAM lParam)
2774 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2775 TREEVIEW_ITEM *editedItem = TREEVIEW_ValidItem (infoPtr, infoPtr->editItem);
2776 BOOL bRevert = (BOOL)wParam;
2777 BOOL bReturn = ! bRevert;
2779 if ( ! (BOOL)wParam ) /* wParam is set to true to cancel the edition */
2781 if ( TREEVIEW_SendDispInfoNotify( /* return true to cancel edition */
2792 if (bRevert == FALSE) /* Apply the changes */
2795 int iLength = GetWindowTextA(infoPtr->hwndEdit, tmpText, 1023);
2800 ERR("Problem retreiving new item label.");
2802 else if (iLength >= 1023)
2805 "Insuficient space to retrieve new item label, new label ignored.");
2809 if (strcmp( tmpText, editedItem->pszText ) == 0)
2810 /* Do nothing if the label has not changed */
2814 LPSTR tmpLabel = COMCTL32_Alloc( iLength+1 );
2816 if ( tmpLabel == NULL )
2818 "OutOfMemory, cannot allocate space for label");
2821 COMCTL32_Free(editedItem->pszText);
2822 editedItem->pszText = tmpLabel;
2823 lstrcpyA( editedItem->pszText, tmpText);
2829 ShowWindow(infoPtr->hwndEdit, SW_HIDE);
2830 EnableWindow(infoPtr->hwndEdit, FALSE);
2831 infoPtr->editItem = 0;
2840 TREEVIEW_LButtonDoubleClick (HWND hwnd, WPARAM wParam, LPARAM lParam)
2842 TREEVIEW_ITEM *wineItem;
2846 pt.x = (INT)LOWORD(lParam);
2847 pt.y = (INT)HIWORD(lParam);
2850 wineItem=TREEVIEW_HitTestPoint (hwnd, pt);
2851 if (!wineItem) return 0;
2852 TRACE("item %d \n",(INT)wineItem->hItem);
2854 if (TREEVIEW_SendSimpleNotify (hwnd, NM_DBLCLK)!=TRUE) { /* FIXME!*/
2855 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) wineItem->hItem);
2862 TREEVIEW_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
2864 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2868 ht.pt.x = (INT)LOWORD(lParam);
2869 ht.pt.y = (INT)HIWORD(lParam);
2872 iItem=TREEVIEW_HitTest (hwnd, (LPARAM) &ht);
2873 TRACE("item %d \n",iItem);
2875 if (ht.flags & TVHT_ONITEMBUTTON) {
2876 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) iItem);
2880 infoPtr->uInternalStatus|=TV_LDRAG;
2887 TREEVIEW_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
2889 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2891 TREEVIEW_ITEM *editItem;
2894 ht.pt.x = (INT)LOWORD(lParam);
2895 ht.pt.y = (INT)HIWORD(lParam);
2899 /* Return true to cancel default behaviour */
2900 if ( TREEVIEW_SendSimpleNotify (hwnd, NM_CLICK) )
2904 iItem = TREEVIEW_HitTest (hwnd, (LPARAM) &ht);
2908 editItem = TREEVIEW_ValidItem(infoPtr, (HTREEITEM)iItem);
2910 infoPtr->uInternalStatus &= ~(TV_LDRAG | TV_LDRAGGING);
2913 * If the style allow editing and the node is already selected
2914 * and the click occured on the item label...
2916 if ( ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_EDITLABELS ) &&
2917 ( editItem->state & TVIS_SELECTED ) &&
2918 ( ht.flags & TVHT_ONITEMLABEL ))
2920 if ( infoPtr->editItem == 0 ) /* If we are not curently editing */
2922 if ( TREEVIEW_SendDispInfoNotify( /* Return true to cancel edition */
2931 TRACE("Edit started for %s.\n", editItem->pszText);
2932 infoPtr->editItem = editItem->hItem;
2937 editItem->text.left - 2,
2938 editItem->text.top - 1,
2939 editItem->text.right - editItem->text.left + 20 ,
2940 editItem->text.bottom - editItem->text.top + 3,
2943 SetWindowTextA( infoPtr->hwndEdit, editItem->pszText );
2944 SendMessageA ( infoPtr->hwndEdit, EM_SETSEL, 0, -1 );
2945 SetFocus ( infoPtr->hwndEdit);
2946 ShowWindow ( infoPtr->hwndEdit, SW_SHOW);
2949 else if ( infoPtr->editItem != 0 ) /* If we are curently editing */
2951 TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
2953 else if ( ht.flags & (TVHT_ONITEMLABEL | TVHT_ONITEMICON))
2955 TREEVIEW_DoSelectItem (
2967 TREEVIEW_RButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
2969 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2972 infoPtr->uInternalStatus|=TV_RDRAG;
2977 TREEVIEW_RButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
2979 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2982 if (TREEVIEW_SendSimpleNotify (hwnd, NM_RCLICK)) return 0;
2983 infoPtr->uInternalStatus&= ~(TV_RDRAG | TV_RDRAGGING);
2989 TREEVIEW_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
2991 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2992 TREEVIEW_ITEM *hotItem;
2995 pt.x=(INT) LOWORD (lParam);
2996 pt.y=(INT) HIWORD (lParam);
2997 hotItem=TREEVIEW_HitTestPoint (hwnd, pt);
2998 if (!hotItem) return 0;
2999 infoPtr->focusItem=hotItem->hItem;
3001 if ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_DISABLEDRAGDROP) return 0;
3003 if (infoPtr->uInternalStatus & TV_LDRAG) {
3004 TREEVIEW_SendTreeviewDnDNotify (hwnd, TVN_BEGINDRAG, hotItem->hItem, pt);
3005 infoPtr->uInternalStatus &= ~TV_LDRAG;
3006 infoPtr->uInternalStatus |= TV_LDRAGGING;
3007 infoPtr->dropItem=hotItem->hItem;
3011 if (infoPtr->uInternalStatus & TV_RDRAG) {
3012 TREEVIEW_SendTreeviewDnDNotify (hwnd, TVN_BEGINRDRAG, hotItem->hItem, pt);
3013 infoPtr->uInternalStatus &= ~TV_RDRAG;
3014 infoPtr->uInternalStatus |= TV_RDRAGGING;
3015 infoPtr->dropItem=hotItem->hItem;
3024 TREEVIEW_CreateDragImage (HWND hwnd, WPARAM wParam, LPARAM lParam)
3026 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3027 TREEVIEW_ITEM *dragItem;
3031 HBITMAP hbmp,hOldbmp;
3038 if (!(infoPtr->himlNormal)) return 0;
3039 dragItem=TREEVIEW_ValidItem (infoPtr, (HTREEITEM) lParam);
3041 if (!dragItem) return 0;
3042 itemtxt=dragItem->pszText;
3044 hwtop=GetDesktopWindow ();
3045 htopdc= GetDC (hwtop);
3046 hdc=CreateCompatibleDC (htopdc);
3048 hOldFont=SelectObject (hdc, infoPtr->hFont);
3049 GetTextExtentPoint32A (hdc, itemtxt, lstrlenA (itemtxt), &size);
3050 TRACE("%d %d %s %d\n",size.cx,size.cy,itemtxt,lstrlenA(itemtxt));
3051 hbmp=CreateCompatibleBitmap (htopdc, size.cx, size.cy);
3052 hOldbmp=SelectObject (hdc, hbmp);
3054 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &cy);
3056 if (cy>size.cy) size.cy=cy;
3058 infoPtr->dragList=ImageList_Create (size.cx, size.cy, ILC_COLOR, 10, 10);
3059 ImageList_Draw (infoPtr->himlNormal, dragItem->iImage, hdc, 0, 0, ILD_NORMAL);
3062 ImageList_GetImageInfo (infoPtr->himlNormal, dragItem->hItem, &iminfo);
3063 ImageList_AddMasked (infoPtr->dragList, iminfo.hbmImage, CLR_DEFAULT);
3066 /* draw item text */
3068 SetRect (&rc, cx, 0, size.cx,size.cy);
3069 DrawTextA (hdc, itemtxt, lstrlenA (itemtxt), &rc, DT_LEFT);
3070 SelectObject (hdc, hOldFont);
3071 SelectObject (hdc, hOldbmp);
3073 ImageList_Add (infoPtr->dragList, hbmp, 0);
3076 DeleteObject (hbmp);
3077 ReleaseDC (hwtop, htopdc);
3079 return (LRESULT)infoPtr->dragList;
3084 TREEVIEW_DoSelectItem (HWND hwnd, INT action, HTREEITEM newSelect, INT cause)
3087 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3088 TREEVIEW_ITEM *prevItem,*wineItem;
3091 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)newSelect);
3093 TRACE("Entering item %d, flag %x, cause %x, state %d\n",
3099 if ( (wineItem) && (wineItem->parent))
3102 * If the item has a collapse parent expand the parent so he
3103 * can expose the item
3105 TREEVIEW_ITEM *parentItem = TREEVIEW_ValidItem (infoPtr, wineItem->parent);
3106 if ( !(parentItem->state & TVIS_EXPANDED))
3107 TREEVIEW_Expand (hwnd, TVE_EXPAND, (LPARAM) wineItem->parent);
3113 prevSelect=(INT)infoPtr->selectedItem;
3115 if ((HTREEITEM)prevSelect==newSelect)
3118 prevItem= TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect);
3121 if (TREEVIEW_SendTreeviewNotify(
3125 (HTREEITEM)prevSelect,
3126 (HTREEITEM)newSelect))
3127 return FALSE; /* FIXME: OK? */
3130 prevItem->state &= ~TVIS_SELECTED;
3132 wineItem->state |= TVIS_SELECTED;
3134 infoPtr->selectedItem=(HTREEITEM)newSelect;
3136 TREEVIEW_SendTreeviewNotify(
3140 (HTREEITEM)prevSelect,
3141 (HTREEITEM)newSelect);
3145 case TVGN_DROPHILITE:
3146 prevItem= TREEVIEW_ValidItem (infoPtr, infoPtr->dropItem);
3149 prevItem->state &= ~TVIS_DROPHILITED;
3151 infoPtr->dropItem=(HTREEITEM)newSelect;
3154 wineItem->state |=TVIS_DROPHILITED;
3158 case TVGN_FIRSTVISIBLE:
3159 FIXME("FIRSTVISIBLE not implemented\n");
3163 TREEVIEW_QueueRefresh (hwnd);
3165 TRACE("Leaving state %d\n", wineItem->state);
3169 /* FIXME: handle NM_KILLFocus enzo */
3171 TREEVIEW_SelectItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
3174 return TREEVIEW_DoSelectItem (hwnd, wParam, (HTREEITEM) lParam, TVC_UNKNOWN);
3181 TREEVIEW_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
3184 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3186 TRACE("%x\n",infoPtr->hFont);
3187 return infoPtr->hFont;
3191 TREEVIEW_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
3194 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3197 HFONT hFont, hOldFont;
3201 TRACE("%x %lx\n",wParam, lParam);
3203 infoPtr->hFont = (HFONT)wParam;
3205 hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
3207 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
3208 logFont.lfWeight=FW_BOLD;
3209 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
3212 hOldFont = SelectObject (hdc, hFont);
3213 GetTextMetricsA (hdc, &tm);
3214 height= tm.tmHeight + tm.tmExternalLeading;
3215 if (height>infoPtr->uRealItemHeight)
3216 infoPtr->uRealItemHeight=height;
3217 SelectObject (hdc, hOldFont);
3221 TREEVIEW_QueueRefresh (hwnd);
3229 TREEVIEW_VScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
3232 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3235 TRACE("wp %x, lp %lx\n", wParam, lParam);
3236 if (!infoPtr->uInternalStatus & TV_VSCROLL) return FALSE;
3238 switch (LOWORD (wParam)) {
3240 if (!infoPtr->cy) return FALSE;
3241 infoPtr->cy -= infoPtr->uRealItemHeight;
3242 if (infoPtr->cy < 0) infoPtr->cy=0;
3245 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3246 if (infoPtr->cy == maxHeight) return FALSE;
3247 infoPtr->cy += infoPtr->uRealItemHeight;
3248 if (infoPtr->cy > maxHeight)
3249 infoPtr->cy = maxHeight;
3252 if (!infoPtr->cy) return FALSE;
3253 infoPtr->cy -= infoPtr->uVisibleHeight;
3254 if (infoPtr->cy < 0) infoPtr->cy=0;
3257 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3258 if (infoPtr->cy == maxHeight) return FALSE;
3259 infoPtr->cy += infoPtr->uVisibleHeight;
3260 if (infoPtr->cy > maxHeight)
3261 infoPtr->cy = maxHeight;
3264 infoPtr->cy = HIWORD (wParam);
3269 TREEVIEW_QueueRefresh (hwnd);
3274 TREEVIEW_HScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
3276 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3279 TRACE("wp %lx, lp %x\n", lParam, wParam);
3281 if (!infoPtr->uInternalStatus & TV_HSCROLL) return FALSE;
3283 switch (LOWORD (wParam)) {
3285 if (!infoPtr->cx) return FALSE;
3286 infoPtr->cx -= infoPtr->uRealItemHeight;
3287 if (infoPtr->cx < 0) infoPtr->cx=0;
3290 maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
3291 if (infoPtr->cx == maxWidth) return FALSE;
3292 infoPtr->cx += infoPtr->uRealItemHeight; /*FIXME */
3293 if (infoPtr->cx > maxWidth)
3294 infoPtr->cx = maxWidth;
3297 if (!infoPtr->cx) return FALSE;
3298 infoPtr->cx -= infoPtr->uVisibleWidth;
3299 if (infoPtr->cx < 0) infoPtr->cx=0;
3302 maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
3303 if (infoPtr->cx == maxWidth) return FALSE;
3304 infoPtr->cx += infoPtr->uVisibleWidth;
3305 if (infoPtr->cx > maxWidth)
3306 infoPtr->cx = maxWidth;
3309 infoPtr->cx = HIWORD (wParam);
3314 TREEVIEW_QueueRefresh (hwnd);
3320 TREEVIEW_KeyDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
3322 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3323 HTREEITEM hNewSelection = 0;
3324 INT scrollNeeds = -1;
3325 INT cyChangeNeeds = -1;
3326 INT prevSelect = (INT)infoPtr->selectedItem;
3328 TREEVIEW_ITEM *prevItem =
3329 (prevSelect != 0 ) ?
3330 TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect) :
3333 TREEVIEW_ITEM *newItem = NULL;
3335 TRACE("%x %lx\n",wParam, lParam);
3337 if (prevSelect == 0)
3342 newItem=TREEVIEW_GetPrevListItem (infoPtr, prevItem);
3345 newItem=& infoPtr->items[(INT)infoPtr->TopRootItem];
3347 hNewSelection = newItem->hItem;
3349 if (! newItem->visible)
3350 scrollNeeds = SB_LINEUP;
3355 newItem=TREEVIEW_GetNextListItem (infoPtr, prevItem);
3360 hNewSelection = newItem->hItem;
3362 if (! newItem->visible)
3363 scrollNeeds = SB_LINEDOWN;
3368 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem];
3369 hNewSelection = newItem->hItem;
3374 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem];
3375 newItem = TREEVIEW_GetLastListItem (infoPtr, newItem);
3376 hNewSelection = newItem->hItem;
3378 if (! newItem->visible)
3379 cyChangeNeeds = infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3384 if ( (prevItem->cChildren > 0) && (prevItem->state & TVIS_EXPANDED) )
3386 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect );
3388 else if ((INT)prevItem->parent)
3390 newItem = (& infoPtr->items[(INT)prevItem->parent]);
3391 if (! newItem->visible)
3392 /* FIXME find a way to make this item the first visible... */
3395 hNewSelection = newItem->hItem;
3401 if ( ( prevItem->cChildren > 0) ||
3402 ( prevItem->cChildren == I_CHILDRENCALLBACK))
3404 if (! (prevItem->state & TVIS_EXPANDED))
3405 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect );
3408 newItem = (& infoPtr->items[(INT)prevItem->firstChild]);
3409 hNewSelection = newItem->hItem;
3416 if (! (prevItem->state & TVIS_EXPANDED))
3417 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect );
3421 if (prevItem->state & TVIS_EXPANDED)
3422 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect );
3427 newItem=TREEVIEW_GetListItem(
3430 -1*(TREEVIEW_GetVisibleCount(hwnd,0,0)-3));
3434 hNewSelection = newItem->hItem;
3436 if (! newItem->visible)
3437 scrollNeeds = SB_PAGEUP;
3442 newItem=TREEVIEW_GetListItem(
3445 TREEVIEW_GetVisibleCount(hwnd,0,0)-3);
3450 hNewSelection = newItem->hItem;
3452 if (! newItem->visible)
3453 scrollNeeds = SB_PAGEDOWN;
3462 FIXME("%x not implemented\n", wParam);
3469 This works but does not send notification...
3471 prevItem->state &= ~TVIS_SELECTED;
3472 newItem->state |= TVIS_SELECTED;
3473 infoPtr->selectedItem = hNewSelection;
3474 TREEVIEW_QueueRefresh (hwnd);
3477 if ( TREEVIEW_DoSelectItem(
3480 (HTREEITEM)hNewSelection,
3483 /* If selection change is allowed for the new item, perform scrolling */
3484 if (scrollNeeds != -1)
3485 TREEVIEW_VScroll(hwnd, scrollNeeds, 0);
3487 if (cyChangeNeeds != -1)
3488 infoPtr->cy = cyChangeNeeds;
3490 /* FIXME: Something happen in the load the in the two weeks before
3491 april 1st 1999 which makes this SetFocus mandatory otherwise, the focus
3492 is lost... However the SetFocus should not be required...*/
3503 TREEVIEW_GetScrollTime (HWND hwnd)
3505 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3507 return infoPtr->uScrollTime;
3512 TREEVIEW_SetScrollTime (HWND hwnd, UINT uScrollTime)
3514 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3515 UINT uOldScrollTime = infoPtr->uScrollTime;
3517 infoPtr->uScrollTime = min (uScrollTime, 100);
3519 return uOldScrollTime;
3523 static LRESULT WINAPI
3524 TREEVIEW_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3527 case TVM_INSERTITEMA:
3528 return TREEVIEW_InsertItemA (hwnd, wParam, lParam);
3530 case TVM_INSERTITEMW:
3531 return TREEVIEW_InsertItemW(hwnd,wParam,lParam);;
3533 case TVM_DELETEITEM:
3534 return TREEVIEW_DeleteItem (hwnd, wParam, lParam);
3537 return TREEVIEW_Expand (hwnd, wParam, lParam);
3539 case TVM_GETITEMRECT:
3540 return TREEVIEW_GetItemRect (hwnd, wParam, lParam);
3543 return TREEVIEW_GetCount (hwnd, wParam, lParam);
3546 return TREEVIEW_GetIndent (hwnd);
3549 return TREEVIEW_SetIndent (hwnd, wParam);
3551 case TVM_GETIMAGELIST:
3552 return TREEVIEW_GetImageList (hwnd, wParam, lParam);
3554 case TVM_SETIMAGELIST:
3555 return TREEVIEW_SetImageList (hwnd, wParam, lParam);
3557 case TVM_GETNEXTITEM:
3558 return TREEVIEW_GetNextItem (hwnd, wParam, lParam);
3560 case TVM_SELECTITEM:
3561 return TREEVIEW_SelectItem (hwnd, wParam, lParam);
3564 return TREEVIEW_GetItemA (hwnd, wParam, lParam);
3567 FIXME("Unimplemented msg TVM_GETITEMW\n");
3571 return TREEVIEW_SetItemA (hwnd, wParam, lParam);
3574 FIXME("Unimplemented msg TVM_SETITEMW\n");
3577 case TVM_EDITLABELA:
3578 FIXME("Unimplemented msg TVM_EDITLABELA \n");
3581 case TVM_EDITLABELW:
3582 FIXME("Unimplemented msg TVM_EDITLABELW \n");
3585 case TVM_GETEDITCONTROL:
3586 return TREEVIEW_GetEditControl (hwnd);
3588 case TVM_GETVISIBLECOUNT:
3589 return TREEVIEW_GetVisibleCount (hwnd, wParam, lParam);
3592 return TREEVIEW_HitTest (hwnd, lParam);
3594 case TVM_CREATEDRAGIMAGE:
3595 return TREEVIEW_CreateDragImage (hwnd, wParam, lParam);
3597 case TVM_SORTCHILDREN:
3598 return TREEVIEW_SortChildren (hwnd, wParam, lParam);
3600 case TVM_ENSUREVISIBLE:
3601 FIXME("Unimplemented msg TVM_ENSUREVISIBLE\n");
3604 case TVM_SORTCHILDRENCB:
3605 return TREEVIEW_SortChildrenCB(hwnd, wParam, lParam);
3607 case TVM_ENDEDITLABELNOW:
3608 return TREEVIEW_EndEditLabelNow (hwnd, wParam, lParam);
3610 case TVM_GETISEARCHSTRINGA:
3611 FIXME("Unimplemented msg TVM_GETISEARCHSTRINGA\n");
3614 case TVM_GETISEARCHSTRINGW:
3615 FIXME("Unimplemented msg TVM_GETISEARCHSTRINGW\n");
3618 case TVM_GETTOOLTIPS:
3619 return TREEVIEW_GetToolTips (hwnd);
3621 case TVM_SETTOOLTIPS:
3622 return TREEVIEW_SetToolTips (hwnd, wParam);
3624 case TVM_SETINSERTMARK:
3625 FIXME("Unimplemented msg TVM_SETINSERTMARK\n");
3628 case TVM_SETITEMHEIGHT:
3629 return TREEVIEW_SetItemHeight (hwnd, wParam);
3631 case TVM_GETITEMHEIGHT:
3632 return TREEVIEW_GetItemHeight (hwnd);
3634 case TVM_SETBKCOLOR:
3635 return TREEVIEW_SetBkColor (hwnd, wParam, lParam);
3637 case TVM_SETTEXTCOLOR:
3638 return TREEVIEW_SetTextColor (hwnd, wParam, lParam);
3640 case TVM_GETBKCOLOR:
3641 return TREEVIEW_GetBkColor (hwnd);
3643 case TVM_GETTEXTCOLOR:
3644 return TREEVIEW_GetTextColor (hwnd);
3646 case TVM_SETSCROLLTIME:
3647 return TREEVIEW_SetScrollTime (hwnd, (UINT)wParam);
3649 case TVM_GETSCROLLTIME:
3650 return TREEVIEW_GetScrollTime (hwnd);
3652 case TVM_GETITEMSTATE:
3653 return TREEVIEW_GetItemState (hwnd,wParam, lParam);
3655 case TVM_GETLINECOLOR:
3656 return TREEVIEW_GetLineColor (hwnd,wParam, lParam);
3658 case TVM_SETLINECOLOR:
3659 return TREEVIEW_SetLineColor (hwnd,wParam, lParam);
3661 case TVM_SETINSERTMARKCOLOR:
3662 FIXME("Unimplemented msg TVM_SETINSERTMARKCOLOR\n");
3665 case TVM_SETUNICODEFORMAT:
3666 FIXME("Unimplemented msg TVM_SETUNICODEFORMAT\n");
3669 case TVM_GETUNICODEFORMAT:
3670 FIXME("Unimplemented msg TVM_GETUNICODEFORMAT\n");
3674 return TREEVIEW_Command (hwnd, wParam, lParam);
3677 return TREEVIEW_Create (hwnd, wParam, lParam);
3680 return TREEVIEW_Destroy (hwnd);
3682 /* case WM_ENABLE: */
3685 return TREEVIEW_EraseBackground (hwnd, wParam, lParam);
3688 return DLGC_WANTARROWS | DLGC_WANTCHARS;
3691 return TREEVIEW_Paint (hwnd, wParam, lParam);
3694 return TREEVIEW_GetFont (hwnd, wParam, lParam);
3697 return TREEVIEW_SetFont (hwnd, wParam, lParam);
3700 return TREEVIEW_KeyDown (hwnd, wParam, lParam);
3703 return TREEVIEW_SetFocus (hwnd, wParam, lParam);
3706 return TREEVIEW_KillFocus (hwnd, wParam, lParam);
3708 case WM_LBUTTONDOWN:
3709 return TREEVIEW_LButtonDown (hwnd, wParam, lParam);
3712 return TREEVIEW_LButtonUp (hwnd, wParam, lParam);
3714 case WM_LBUTTONDBLCLK:
3715 return TREEVIEW_LButtonDoubleClick (hwnd, wParam, lParam);
3717 case WM_RBUTTONDOWN:
3718 return TREEVIEW_RButtonDown (hwnd, wParam, lParam);
3721 return TREEVIEW_RButtonUp (hwnd, wParam, lParam);
3724 return TREEVIEW_MouseMove (hwnd, wParam, lParam);
3726 case WM_STYLECHANGED:
3727 return TREEVIEW_StyleChanged (hwnd, wParam, lParam);
3729 /* case WM_SYSCOLORCHANGE: */
3730 /* case WM_SETREDRAW: */
3733 return TREEVIEW_HandleTimer (hwnd, wParam, lParam);
3736 return TREEVIEW_Size (hwnd, wParam,lParam);
3739 return TREEVIEW_HScroll (hwnd, wParam, lParam);
3741 return TREEVIEW_VScroll (hwnd, wParam, lParam);
3744 TRACE ("drawItem\n");
3745 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
3748 if (uMsg >= WM_USER)
3749 FIXME("Unknown msg %04x wp=%08x lp=%08lx\n",
3750 uMsg, wParam, lParam);
3751 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
3758 TREEVIEW_Register (void)
3764 if (GlobalFindAtomA (WC_TREEVIEWA)) return;
3766 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
3767 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
3768 wndClass.lpfnWndProc = (WNDPROC)TREEVIEW_WindowProc;
3769 wndClass.cbClsExtra = 0;
3770 wndClass.cbWndExtra = sizeof(TREEVIEW_INFO *);
3771 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
3772 wndClass.hbrBackground = 0;
3773 wndClass.lpszClassName = WC_TREEVIEWA;
3775 RegisterClassA (&wndClass);
3780 TREEVIEW_Unregister (void)
3782 if (GlobalFindAtomA (WC_TREEVIEWA))
3783 UnregisterClassA (WC_TREEVIEWA, (HINSTANCE)NULL);