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->clrBk;
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->clrText;
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;
989 /* draw background */
991 hbrBk = CreateSolidBrush (infoPtr->clrBk);
992 FillRect(hdc, &rect, hbrBk);
995 iItem=(INT)infoPtr->TopRootItem;
996 infoPtr->firstVisible=0;
1000 TRACE("[%d %d %d %d]\n",viewtop,viewbottom,viewleft,viewright);
1004 wineItem= & infoPtr->items[iItem];
1005 wineItem->iLevel=indent;
1007 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &itemHeight);
1008 if (infoPtr->uItemHeight>itemHeight)
1009 itemHeight=infoPtr->uItemHeight;
1011 GetTextMetricsA (hdc, &tm);
1012 if ((tm.tmHeight + tm.tmExternalLeading) > itemHeight)
1013 itemHeight=tm.tmHeight + tm.tmExternalLeading;
1015 infoPtr->uRealItemHeight=itemHeight;
1018 /* FIXME: remove this in later stage */
1020 if (wineItem->pszText!=LPSTR_TEXTCALLBACK32A)
1021 TRACE (treeview, "%d %d [%d %d %d %d] (%s)\n",y,x,
1022 wineItem->rect.top, wineItem->rect.bottom,
1023 wineItem->rect.left, wineItem->rect.right,
1026 TRACE (treeview, "%d [%d %d %d %d] (CALLBACK)\n",
1028 wineItem->rect.top, wineItem->rect.bottom,
1029 wineItem->rect.left, wineItem->rect.right);
1032 height=itemHeight * wineItem->iIntegral +1;
1033 if ((y >= viewtop) && (y <= viewbottom) &&
1034 (x >= viewleft ) && (x <= viewright)) {
1035 wineItem->visible = TRUE;
1036 wineItem->rect.top = y - infoPtr->cy + rect.top;
1037 wineItem->rect.bottom = wineItem->rect.top + height ;
1038 wineItem->rect.left = x - infoPtr->cx + rect.left;
1039 wineItem->rect.right = rect.right;
1040 if (!infoPtr->firstVisible)
1041 infoPtr->firstVisible=wineItem->hItem;
1042 TREEVIEW_DrawItem (hwnd, hdc, wineItem);
1045 wineItem->visible = FALSE;
1046 wineItem->rect.left = wineItem->rect.top = 0;
1047 wineItem->rect.right= wineItem->rect.bottom = 0;
1048 wineItem->text.left = wineItem->text.top = 0;
1049 wineItem->text.right= wineItem->text.bottom = 0;
1052 /* look up next item */
1054 if ((wineItem->firstChild) && (wineItem->state & TVIS_EXPANDED)) {
1055 iItem=(INT)wineItem->firstChild;
1057 x+=infoPtr->uIndent;
1058 if (x>infoPtr->uTotalWidth)
1059 infoPtr->uTotalWidth=x;
1062 iItem=(INT)wineItem->sibling;
1063 while ((!iItem) && (indent>0)) {
1065 x-=infoPtr->uIndent;
1067 wineItem=&infoPtr->items[(INT)wineItem->parent];
1068 iItem=(INT)wineItem->sibling;
1074 /* FIXME: infoPtr->uTotalWidth should also take item label into account */
1075 /* FIXME: or should query item sizes (ie check CDRF_NEWFONT) */
1077 infoPtr->uTotalHeight=y;
1078 if (y >= (viewbottom-viewtop)) {
1079 if (!(infoPtr->uInternalStatus & TV_VSCROLL))
1080 ShowScrollBar (hwnd, SB_VERT, TRUE);
1081 infoPtr->uInternalStatus |=TV_VSCROLL;
1082 SetScrollRange (hwnd, SB_VERT, 0,
1083 y - infoPtr->uVisibleHeight, FALSE);
1084 SetScrollPos (hwnd, SB_VERT, infoPtr->cy, TRUE);
1087 if (infoPtr->uInternalStatus & TV_VSCROLL)
1088 ShowScrollBar (hwnd, SB_VERT, FALSE);
1089 infoPtr->uInternalStatus &= ~TV_VSCROLL;
1093 if (infoPtr->cdmode & CDRF_NOTIFYPOSTPAINT)
1094 infoPtr->cdmode=TREEVIEW_SendCustomDrawNotify
1095 (hwnd, CDDS_POSTPAINT, hdc, rect);
1097 ReleaseDC (hwnd, hdc);
1103 TREEVIEW_HandleTimer (HWND hwnd, WPARAM wParam, LPARAM lParam)
1105 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1107 TRACE(" %d\n",wParam);
1108 if (!infoPtr) return FALSE;
1111 case TV_REFRESH_TIMER:
1112 KillTimer (hwnd, TV_REFRESH_TIMER);
1113 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
1114 InvalidateRect(hwnd, NULL, FALSE);
1117 KillTimer (hwnd, TV_EDIT_TIMER);
1118 infoPtr->Timer &= ~TV_EDIT_TIMER_SET;
1121 ERR("got unknown timer\n");
1129 TREEVIEW_QueueRefresh (HWND hwnd)
1132 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1135 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
1136 KillTimer (hwnd, TV_REFRESH_TIMER);
1139 SetTimer (hwnd, TV_REFRESH_TIMER, TV_REFRESH_DELAY, 0);
1140 infoPtr->Timer|=TV_REFRESH_TIMER_SET;
1146 TREEVIEW_GetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1148 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1150 TREEVIEW_ITEM *wineItem;
1153 tvItem=(LPTVITEMEXA) lParam;
1154 iItem=(INT)tvItem->hItem;
1156 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1157 if (!wineItem) return FALSE;
1159 if (tvItem->mask & TVIF_CHILDREN) {
1160 if (TVIF_CHILDREN==I_CHILDRENCALLBACK)
1161 FIXME("I_CHILDRENCALLBACK not supported\n");
1162 tvItem->cChildren=wineItem->cChildren;
1165 if (tvItem->mask & TVIF_HANDLE) {
1166 tvItem->hItem=wineItem->hItem;
1169 if (tvItem->mask & TVIF_IMAGE) {
1170 tvItem->iImage=wineItem->iImage;
1173 if (tvItem->mask & TVIF_INTEGRAL) {
1174 tvItem->iIntegral=wineItem->iIntegral;
1177 /* undocumented: windows ignores TVIF_PARAM and
1178 * always sets lParam
1180 tvItem->lParam=wineItem->lParam;
1182 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
1183 tvItem->iSelectedImage=wineItem->iSelectedImage;
1186 if (tvItem->mask & TVIF_STATE) {
1187 tvItem->state=wineItem->state & tvItem->stateMask;
1190 if (tvItem->mask & TVIF_TEXT) {
1191 if (wineItem->pszText == LPSTR_TEXTCALLBACKA) {
1192 tvItem->pszText = LPSTR_TEXTCALLBACKA; /* FIXME:send notification? */
1193 ERR(" GetItem called with LPSTR_TEXTCALLBACK\n");
1195 else if (wineItem->pszText) {
1196 lstrcpynA (tvItem->pszText, wineItem->pszText, tvItem->cchTextMax);
1200 TRACE("item %d<%p>, txt %p, img %p, action %x\n",
1212 /* FIXME: check implementation of TVGN_NEXT/TVGN_NEXTVISIBLE */
1215 TREEVIEW_GetNextItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
1218 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1219 TREEVIEW_ITEM *wineItem, *returnItem;
1220 INT iItem, retval, flag;
1223 if (!infoPtr) return FALSE;
1224 flag = (INT) wParam;
1225 iItem = (INT) lParam;
1228 case TVGN_ROOT: retval=(INT)infoPtr->TopRootItem;
1230 case TVGN_CARET:retval=(INT)infoPtr->selectedItem;
1232 case TVGN_FIRSTVISIBLE:
1233 TREEVIEW_Refresh (hwnd);
1234 /* FIXME:we should only recalculate, not redraw */
1235 retval=(INT)infoPtr->firstVisible;
1237 case TVGN_DROPHILITE:
1238 retval=(INT)infoPtr->dropItem;
1242 TRACE("flags:%x, returns %u\n", flag, retval);
1246 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1248 if (!wineItem) return FALSE;
1251 case TVGN_NEXT: retval=(INT)wineItem->sibling;
1254 retval=(INT)wineItem->upsibling;
1257 retval=(INT)wineItem->parent;
1260 retval=(INT)wineItem->firstChild;
1262 case TVGN_LASTVISIBLE:
1263 returnItem=TREEVIEW_GetLastListItem (infoPtr,wineItem);
1265 case TVGN_NEXTVISIBLE:
1266 returnItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
1268 case TVGN_PREVIOUSVISIBLE:
1269 returnItem=TREEVIEW_GetPrevListItem (infoPtr, wineItem);
1271 default: FIXME("Unknown msg %x,item %x\n", flag,iItem);
1276 TRACE("flags:%x, item %d;returns %d\n", flag, iItem,
1277 (INT)returnItem->hItem);
1278 return (INT)returnItem->hItem;
1281 TRACE("flags:%x, item %d;returns %d\n", flag, iItem,retval);
1287 TREEVIEW_GetCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
1289 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1291 TRACE(" %d\n",infoPtr->uNumItems);
1292 return (LRESULT) infoPtr->uNumItems;
1295 /***************************************************************************
1296 * This method does the chaining of the insertion of a treeview item
1298 * If parent is NULL, we're inserting at the root of the list.
1300 static void TREEVIEW_InsertBefore(
1301 TREEVIEW_INFO *infoPtr,
1302 TREEVIEW_ITEM *newItem,
1303 TREEVIEW_ITEM *sibling,
1304 TREEVIEW_ITEM *parent)
1306 HTREEITEM siblingHandle = 0;
1307 HTREEITEM upSiblingHandle = 0;
1308 TREEVIEW_ITEM *upSibling = NULL;
1310 if (newItem == NULL)
1311 ERR("NULL newItem, impossible condition\n");
1313 if (sibling != NULL) /* Insert before this sibling for this parent */
1315 /* Store the new item sibling up sibling and sibling tem handle */
1316 siblingHandle = sibling->hItem;
1317 upSiblingHandle = sibling->upsibling;
1318 /* As well as a pointer to the upsibling sibling object */
1319 if ( (INT)sibling->upsibling != 0 )
1320 upSibling = &infoPtr->items[(INT)sibling->upsibling];
1322 /* Adjust the sibling pointer */
1323 sibling->upsibling = newItem->hItem;
1325 /* Adjust the new item pointers */
1326 newItem->upsibling = upSiblingHandle;
1327 newItem->sibling = siblingHandle;
1329 /* Adjust the up sibling pointer */
1330 if ( upSibling != NULL )
1331 upSibling->sibling = newItem->hItem;
1333 /* this item is the first child of this parent, adjust parent pointers */
1335 parent->firstChild = newItem->hItem;
1337 infoPtr->TopRootItem= newItem->hItem;
1339 else /* Insert as first child of this parent */
1341 parent->firstChild = newItem->hItem;
1344 /***************************************************************************
1345 * This method does the chaining of the insertion of a treeview item
1347 * If parent is NULL, we're inserting at the root of the list.
1349 static void TREEVIEW_InsertAfter(
1350 TREEVIEW_INFO *infoPtr,
1351 TREEVIEW_ITEM *newItem,
1352 TREEVIEW_ITEM *upSibling,
1353 TREEVIEW_ITEM *parent)
1355 HTREEITEM upSiblingHandle = 0;
1356 HTREEITEM siblingHandle = 0;
1357 TREEVIEW_ITEM *sibling = NULL;
1360 if (newItem == NULL)
1361 ERR("NULL newItem, impossible condition\n");
1363 if (upSibling != NULL) /* Insert after this upsibling for this parent */
1365 /* Store the new item up sibling and sibling item handle */
1366 upSiblingHandle = upSibling->hItem;
1367 siblingHandle = upSibling->sibling;
1368 /* As well as a pointer to the upsibling sibling object */
1369 if ( (INT)upSibling->sibling != 0 )
1370 sibling = &infoPtr->items[(INT)upSibling->sibling];
1372 /* Adjust the up sibling pointer */
1373 upSibling->sibling = newItem->hItem;
1375 /* Adjust the new item pointers */
1376 newItem->upsibling = upSiblingHandle;
1377 newItem->sibling = siblingHandle;
1379 /* Adjust the sibling pointer */
1380 if ( sibling != NULL )
1381 sibling->upsibling = newItem->hItem;
1384 newItem is the last of the level, nothing else to do
1387 else /* Insert as first child of this parent */
1389 parent->firstChild = newItem->hItem;
1392 /***************************************************************************
1393 * Forward the DPA local callback to the treeview owner callback
1395 static INT WINAPI TREEVIEW_CallBackCompare(
1400 /* Forward the call to the client define callback */
1401 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr((HWND)tvInfoPtr);
1402 return (infoPtr->pCallBackSort->lpfnCompare)(
1403 ((TREEVIEW_ITEM*)first)->lParam,
1404 ((TREEVIEW_ITEM*)second)->lParam,
1405 infoPtr->pCallBackSort->lParam);
1408 /***************************************************************************
1409 * Treeview native sort routine: sort on item text.
1411 static INT WINAPI TREEVIEW_SortOnName (
1416 HWND hwnd=(HWND) tvInfoPtr;
1418 TREEVIEW_ITEM *item;
1421 item=(TREEVIEW_ITEM *) first;
1422 if (item->pszText==LPSTR_TEXTCALLBACKA) {
1423 TREEVIEW_SendDispInfoNotify (hwnd, item, TVN_GETDISPINFO, TVIF_TEXT);
1427 item=(TREEVIEW_ITEM *) second;
1428 if (item->pszText==LPSTR_TEXTCALLBACKA) {
1429 TREEVIEW_SendDispInfoNotify (hwnd, item, TVN_GETDISPINFO, TVIF_TEXT);
1433 return -strcmp (txt1,txt2);
1436 /***************************************************************************
1437 * Setup the treeview structure with regards of the sort method
1438 * and sort the children of the TV item specified in lParam
1439 * fRecurse: currently unused. Should be zero.
1440 * parent: if pSort!=NULL, should equal pSort->hParent.
1441 * otherwise, item which child items are to be sorted.
1442 * pSort: sort method info. if NULL, sort on item text.
1443 * if non-NULL, sort on item's lParam content, and let the
1444 * application decide what that means. See also TVM_SORTCHILDRENCB.
1447 static LRESULT WINAPI TREEVIEW_Sort (
1454 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1455 TREEVIEW_ITEM *sortMe = NULL; /* Node for which we sort the children */
1457 /* Obtain the TVSORTBC struct */
1458 infoPtr->pCallBackSort = pSort;
1460 /* undocumented feature: TVI_ROOT means `sort the whole tree' */
1462 if (parent==TVI_ROOT)
1463 parent=infoPtr->TopRootItem;
1465 /* Check for a valid handle to the parent item */
1466 if (!TREEVIEW_ValidItem(infoPtr, parent))
1468 ERR ("invalid item hParent=%x\n", (INT)parent);
1472 /* Obtain the parent node to sort */
1473 sortMe = &infoPtr->items[ (INT)parent ];
1475 /* Make sure there is something to sort */
1476 if ( sortMe->cChildren > 1 )
1478 /* pointer organization */
1479 HDPA sortList = DPA_Create(sortMe->cChildren);
1480 HTREEITEM itemHandle = sortMe->firstChild;
1481 TREEVIEW_ITEM *itemPtr = & infoPtr->items[ (INT)itemHandle ];
1483 /* TREEVIEW_ITEM rechaining */
1489 /* Build the list of item to sort */
1493 sortList, /* the list */
1494 sortMe->cChildren+1, /* force the insertion to be an append */
1495 itemPtr); /* the ptr to store */
1497 /* Get the next sibling */
1498 itemHandle = itemPtr->sibling;
1499 itemPtr = & infoPtr->items[ (INT)itemHandle ];
1500 } while ( itemHandle != NULL );
1502 /* let DPA perform the sort activity */
1505 sortList, /* what */
1506 TREEVIEW_CallBackCompare, /* how */
1510 sortList, /* what */
1511 TREEVIEW_SortOnName, /* how */
1515 * Reorganized TREEVIEW_ITEM structures.
1516 * Note that we know we have at least two elements.
1519 /* Get the first item and get ready to start... */
1520 item = DPA_GetPtr(sortList, count++);
1521 while ( (nextItem = DPA_GetPtr(sortList, count++)) != NULL )
1523 /* link the two current item toghether */
1524 ((TREEVIEW_ITEM*)item)->sibling = ((TREEVIEW_ITEM*)nextItem)->hItem;
1525 ((TREEVIEW_ITEM*)nextItem)->upsibling = ((TREEVIEW_ITEM*)item)->hItem;
1527 if (prevItem == NULL) /* this is the first item, update the parent */
1529 sortMe->firstChild = ((TREEVIEW_ITEM*)item)->hItem;
1530 ((TREEVIEW_ITEM*)item)->upsibling = NULL;
1532 else /* fix the back chaining */
1534 ((TREEVIEW_ITEM*)item)->upsibling = ((TREEVIEW_ITEM*)prevItem)->hItem;
1537 /* get ready for the next one */
1542 /* the last item is pointed to by item and never has a sibling */
1543 ((TREEVIEW_ITEM*)item)->sibling = NULL;
1545 DPA_Destroy(sortList);
1553 /***************************************************************************
1554 * Setup the treeview structure with regards of the sort method
1555 * and sort the children of the TV item specified in lParam
1557 static LRESULT WINAPI TREEVIEW_SortChildrenCB(
1563 LPTVSORTCB pSort=(LPTVSORTCB) lParam;
1565 return TREEVIEW_Sort (hwnd, wParam, pSort->hParent, pSort);
1569 /***************************************************************************
1570 * Sort the children of the TV item specified in lParam.
1572 static LRESULT WINAPI TREEVIEW_SortChildren (
1577 return TREEVIEW_Sort (hwnd, (BOOL) wParam, (HTREEITEM) lParam, NULL);
1582 /* the method used below isn't the most memory-friendly, but it avoids
1583 a lot of memory reallocations */
1585 /* BTW: we waste handle 0; 0 is not an allowed handle. */
1588 TREEVIEW_InsertItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1591 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1592 TVINSERTSTRUCTA *ptdi;
1594 TREEVIEW_ITEM *wineItem, *parentItem, *prevsib, *sibItem;
1595 INT iItem,listItems,i,len;
1597 /* Item to insert */
1598 ptdi = (LPTVINSERTSTRUCTA) lParam;
1600 /* check if memory is available */
1602 if (infoPtr->uNumPtrsAlloced==0) {
1603 infoPtr->items = COMCTL32_Alloc (TVITEM_ALLOC*sizeof (TREEVIEW_ITEM));
1604 infoPtr->freeList= COMCTL32_Alloc ((1+(TVITEM_ALLOC>>5)) * sizeof (INT));
1605 infoPtr->uNumPtrsAlloced=TVITEM_ALLOC;
1606 infoPtr->TopRootItem=(HTREEITEM)1;
1610 * Reallocate contiguous space for items
1612 if (infoPtr->uNumItems == (infoPtr->uNumPtrsAlloced-1) ) {
1613 TREEVIEW_ITEM *oldItems = infoPtr->items;
1614 INT *oldfreeList = infoPtr->freeList;
1616 infoPtr->uNumPtrsAlloced*=2;
1617 infoPtr->items = COMCTL32_Alloc (infoPtr->uNumPtrsAlloced*sizeof (TREEVIEW_ITEM));
1618 infoPtr->freeList= COMCTL32_Alloc ((1+(infoPtr->uNumPtrsAlloced>>5))*sizeof (INT));
1620 memcpy (&infoPtr->items[0], &oldItems[0],
1621 infoPtr->uNumPtrsAlloced/2 * sizeof(TREEVIEW_ITEM));
1622 memcpy (&infoPtr->freeList[0], &oldfreeList[0],
1623 (infoPtr->uNumPtrsAlloced>>6) * sizeof(INT));
1625 COMCTL32_Free (oldItems);
1626 COMCTL32_Free (oldfreeList);
1630 * Reset infoPtr structure with new stat according to current TV picture
1633 infoPtr->uNumItems++;
1634 if ((INT)infoPtr->uMaxHandle==(infoPtr->uNumItems-1)) {
1635 iItem=infoPtr->uNumItems;
1636 infoPtr->uMaxHandle = (HTREEITEM)((INT)infoPtr->uMaxHandle + 1);
1637 } else { /* check freelist */
1638 for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++) {
1639 if (infoPtr->freeList[i]) {
1640 iItem=ffs (infoPtr->freeList[i])-1;
1641 tv_clear_bit(iItem,&infoPtr->freeList[i]);
1648 if (TRACE_ON(treeview)) {
1649 for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++)
1650 TRACE("%8x\n",infoPtr->freeList[i]);
1653 if (!iItem) ERR("Argh -- can't find free item.\n");
1656 * Find the parent item of the new item
1658 tvItem= & ptdi->DUMMYUNIONNAME.itemex;
1659 wineItem=& infoPtr->items[iItem];
1661 if ((ptdi->hParent==TVI_ROOT) || (ptdi->hParent==0)) {
1663 wineItem->parent = 0;
1664 sibItem = &infoPtr->items [(INT)infoPtr->TopRootItem];
1665 listItems = infoPtr->uNumItems;
1668 parentItem = &infoPtr->items[(INT)ptdi->hParent];
1670 /* Do the insertion here it if it's the only item of this parent */
1671 if (!parentItem->firstChild)
1672 parentItem->firstChild=(HTREEITEM)iItem;
1674 wineItem->parent = ptdi->hParent;
1675 sibItem = &infoPtr->items [(INT)parentItem->firstChild];
1676 parentItem->cChildren++;
1677 listItems = parentItem->cChildren;
1681 /* NOTE: I am moving some setup of the wineItem object that was initialy
1682 * done at the end of the function since some of the values are
1683 * required by the Callback sorting
1686 if (tvItem->mask & TVIF_TEXT)
1689 * Setup the item text stuff here since it's required by the Sort method
1690 * when the insertion are ordered
1692 if (tvItem->pszText!=LPSTR_TEXTCALLBACKA)
1694 TRACE("(%p,%s)\n", &tvItem->pszText, tvItem->pszText);
1695 len = lstrlenA (tvItem->pszText)+1;
1696 wineItem->pszText= COMCTL32_Alloc (len+1);
1697 lstrcpyA (wineItem->pszText, tvItem->pszText);
1698 wineItem->cchTextMax=len;
1702 TRACE("LPSTR_TEXTCALLBACK\n");
1703 wineItem->pszText = LPSTR_TEXTCALLBACKA;
1704 wineItem->cchTextMax = 0;
1708 if (tvItem->mask & TVIF_PARAM)
1709 wineItem->lParam=tvItem->lParam;
1712 wineItem->upsibling=0; /* needed in case we're the first item in a list */
1713 wineItem->sibling=0;
1714 wineItem->firstChild=0;
1715 wineItem->hItem=(HTREEITEM)iItem;
1720 switch ((DWORD) ptdi->hInsertAfter) {
1721 case (DWORD) TVI_FIRST:
1722 if (sibItem==wineItem) break;
1723 if (wineItem->parent) {
1724 wineItem->sibling=parentItem->firstChild;
1725 parentItem->firstChild=(HTREEITEM)iItem;
1727 wineItem->sibling=infoPtr->TopRootItem;
1728 infoPtr->TopRootItem=(HTREEITEM)iItem;
1730 sibItem->upsibling=(HTREEITEM)iItem;
1733 case (DWORD) TVI_SORT:
1734 if (sibItem==wineItem)
1736 * This item is the first child of the level and it
1737 * has already been inserted
1742 TREEVIEW_ITEM *aChild;
1745 TREEVIEW_ITEM *previousChild = NULL;
1746 BOOL bItemInserted = FALSE;
1749 aChild = &infoPtr->items[(INT)parentItem->firstChild];
1751 aChild = &infoPtr->items[(INT)infoPtr->TopRootItem];
1753 /* Iterate the parent children to see where we fit in */
1754 while ( aChild != NULL )
1756 INT comp = strcmp(wineItem->pszText, aChild->pszText);
1757 if ( comp < 0 ) /* we are smaller than the current one */
1759 TREEVIEW_InsertBefore(infoPtr, wineItem, aChild, parentItem);
1760 bItemInserted = TRUE;
1763 else if ( comp > 0 ) /* we are bigger than the current one */
1765 previousChild = aChild;
1766 aChild = (aChild->sibling == 0) /* This will help us to exit */
1767 ? NULL /* if there is no more sibling */
1768 : &infoPtr->items[(INT)aChild->sibling];
1770 /* Look at the next item */
1773 else if ( comp == 0 )
1776 * An item with this name is already existing, therefore,
1777 * we add after the one we found
1779 TREEVIEW_InsertAfter(infoPtr, wineItem, aChild, parentItem);
1780 bItemInserted = TRUE;
1786 * we reach the end of the child list and the item as not
1787 * yet been inserted, therefore, insert it after the last child.
1789 if ( (! bItemInserted ) && (aChild == NULL) )
1790 TREEVIEW_InsertAfter(infoPtr, wineItem, previousChild, parentItem);
1796 case (DWORD) TVI_LAST:
1797 if (sibItem==wineItem) break;
1798 while (sibItem->sibling) {
1800 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1802 sibItem->sibling=(HTREEITEM)iItem;
1803 wineItem->upsibling=sibItem->hItem;
1806 while ((sibItem->sibling) && (sibItem->hItem!=ptdi->hInsertAfter))
1809 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1811 if (sibItem->hItem!=ptdi->hInsertAfter) {
1812 ERR("tried to insert item after nonexisting handle %d.\n",
1813 (INT) ptdi->hInsertAfter);
1817 if (sibItem->sibling) {
1818 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1819 sibItem->upsibling=(HTREEITEM)iItem;
1820 wineItem->sibling=sibItem->hItem;
1822 prevsib->sibling=(HTREEITEM)iItem;
1823 wineItem->upsibling=prevsib->hItem;
1829 /* Fill in info structure */
1831 TRACE("new item %d; parent %d, mask %x\n", iItem,
1832 (INT)wineItem->parent,tvItem->mask);
1834 wineItem->mask=tvItem->mask;
1835 wineItem->iIntegral=1;
1837 if (tvItem->mask & TVIF_CHILDREN) {
1838 wineItem->cChildren=tvItem->cChildren;
1839 if (tvItem->cChildren==I_CHILDRENCALLBACK)
1840 FIXME(" I_CHILDRENCALLBACK not supported\n");
1843 wineItem->expandBox.left = 0; /* Initialize the expandBox */
1844 wineItem->expandBox.top = 0;
1845 wineItem->expandBox.right = 0;
1846 wineItem->expandBox.bottom = 0;
1848 if (tvItem->mask & TVIF_IMAGE)
1849 wineItem->iImage=tvItem->iImage;
1851 /* If the application sets TVIF_INTEGRAL without
1852 supplying a TVITEMEX structure, it's toast */
1854 if (tvItem->mask & TVIF_INTEGRAL)
1855 wineItem->iIntegral=tvItem->iIntegral;
1857 if (tvItem->mask & TVIF_SELECTEDIMAGE)
1858 wineItem->iSelectedImage=tvItem->iSelectedImage;
1860 if (tvItem->mask & TVIF_STATE) {
1861 TRACE("Changing item state from %d to %d\n",
1864 wineItem->state=tvItem->state;
1865 wineItem->stateMask=tvItem->stateMask;
1869 TREEVIEW_QueueRefresh (hwnd);
1871 return (LRESULT) iItem;
1876 TREEVIEW_InsertItemW(HWND hwnd, WPARAM wParam, LPARAM lParam)
1878 TVINSERTSTRUCTW *tvisW;
1879 TVINSERTSTRUCTA tvisA;
1882 tvisW = (LPTVINSERTSTRUCTW)lParam;
1884 tvisA.hParent = tvisW->hParent;
1885 tvisA.hInsertAfter = tvisW->hInsertAfter;
1887 tvisA.DUMMYUNIONNAME.item.mask = tvisW->DUMMYUNIONNAME.item.mask;
1888 tvisA.DUMMYUNIONNAME.item.hItem = tvisW->DUMMYUNIONNAME.item.hItem;
1889 tvisA.DUMMYUNIONNAME.item.state = tvisW->DUMMYUNIONNAME.item.state;
1890 tvisA.DUMMYUNIONNAME.item.stateMask = tvisW->DUMMYUNIONNAME.item.stateMask;
1891 tvisA.DUMMYUNIONNAME.item.cchTextMax = tvisW->DUMMYUNIONNAME.item.cchTextMax;
1893 if(tvisW->DUMMYUNIONNAME.item.pszText)
1895 if (tvisW->DUMMYUNIONNAME.item.pszText!=LPSTR_TEXTCALLBACKW)
1897 int len = lstrlenW (tvisW->DUMMYUNIONNAME.item.pszText)+1;
1898 tvisA.DUMMYUNIONNAME.item.pszText = COMCTL32_Alloc (len);
1899 lstrcpyWtoA (tvisA.DUMMYUNIONNAME.item.pszText,
1900 tvisW->DUMMYUNIONNAME.item.pszText );
1904 tvisA.DUMMYUNIONNAME.item.pszText = LPSTR_TEXTCALLBACKA;
1905 tvisA.DUMMYUNIONNAME.item.cchTextMax = 0;
1909 tvisA.DUMMYUNIONNAME.item.iImage = tvisW->DUMMYUNIONNAME.item.iImage;
1910 tvisA.DUMMYUNIONNAME.item.iSelectedImage = tvisW->DUMMYUNIONNAME.item.iSelectedImage;
1911 tvisA.DUMMYUNIONNAME.item.cChildren = tvisW->DUMMYUNIONNAME.item.cChildren;
1912 tvisA.DUMMYUNIONNAME.item.lParam = tvisW->DUMMYUNIONNAME.item.lParam;
1914 lRes = TREEVIEW_InsertItemA(hwnd,wParam,(LPARAM)&tvisA);
1916 if (tvisA.DUMMYUNIONNAME.item.pszText!=LPSTR_TEXTCALLBACKA)
1918 COMCTL32_Free(tvisA.DUMMYUNIONNAME.item.pszText);
1927 TREEVIEW_DeleteItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
1929 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1931 TREEVIEW_ITEM *wineItem;
1934 if (!infoPtr) return FALSE;
1936 if (lParam == (INT)TVI_ROOT) {
1937 TREEVIEW_RemoveTree (hwnd);
1939 iItem= (INT) lParam;
1940 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1941 if (!wineItem) return FALSE;
1942 TRACE("%s\n",wineItem->pszText);
1943 TREEVIEW_RemoveItem (hwnd, wineItem);
1946 TREEVIEW_QueueRefresh (hwnd);
1954 TREEVIEW_GetIndent (HWND hwnd)
1956 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1959 return infoPtr->uIndent;
1963 TREEVIEW_SetIndent (HWND hwnd, WPARAM wParam)
1965 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1969 newIndent=(INT) wParam;
1970 if (newIndent < MINIMUM_INDENT) newIndent=MINIMUM_INDENT;
1971 infoPtr->uIndent=newIndent;
1977 TREEVIEW_GetToolTips (HWND hwnd)
1980 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1983 return infoPtr->hwndToolTip;
1988 TREEVIEW_SetToolTips (HWND hwnd, WPARAM wParam)
1991 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1995 prevToolTip=infoPtr->hwndToolTip;
1996 infoPtr->hwndToolTip= (HWND) wParam;
2002 static LRESULT CALLBACK
2003 TREEVIEW_GetEditControl (HWND hwnd)
2006 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2008 return infoPtr->hwndEdit;
2012 TREEVIEW_Edit_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam,
2020 HDC hdc = (HDC) wParam;
2021 GetClientRect (hwnd, &rc);
2022 Rectangle (hdc, rc.left, rc.top, rc.right, rc.bottom);
2028 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
2033 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd));
2034 return CallWindowProcA( infoPtr->wpEditOrig, hwnd, uMsg, wParam, lParam);
2042 /* should handle edit control messages here */
2045 TREEVIEW_Command (HWND hwnd, WPARAM wParam, LPARAM lParam)
2048 TRACE("%x %ld\n",wParam, lParam);
2050 switch (HIWORD(wParam))
2055 * Adjust the edit window size
2057 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2058 TREEVIEW_ITEM *editItem = TREEVIEW_ValidItem(infoPtr, infoPtr->editItem);
2059 INT iLength = GetWindowTextLengthA(infoPtr->hwndEdit);
2060 HDC hdc = GetDC(infoPtr->hwndEdit);
2063 if ( GetTextMetricsA(hdc, &tm) )
2065 LONG newWidth = (iLength * tm.tmAveCharWidth) + 15;
2070 editItem->text.left - 2,
2071 editItem->text.top - 1,
2073 editItem->text.bottom - editItem->text.top + 3,
2076 ReleaseDC(hwnd, hdc);
2082 /* TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
2087 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
2094 TREEVIEW_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
2097 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2099 if (infoPtr->bAutoSize)
2101 infoPtr->bAutoSize = FALSE;
2104 infoPtr->bAutoSize = TRUE;
2106 if (wParam == SIZE_RESTORED)
2108 infoPtr->uTotalWidth = LOWORD (lParam);
2109 infoPtr->uTotalHeight = HIWORD (lParam);
2111 FIXME("WM_SIZE flag %x %lx not handled\n", wParam, lParam);
2114 TREEVIEW_QueueRefresh (hwnd);
2121 TREEVIEW_StyleChanged (HWND hwnd, WPARAM wParam, LPARAM lParam)
2123 TRACE("(%x %lx)\n",wParam,lParam);
2125 TREEVIEW_Refresh (hwnd);
2131 TREEVIEW_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
2133 TREEVIEW_INFO *infoPtr;
2138 TRACE("wnd %x\n",hwnd);
2139 /* allocate memory for info structure */
2140 infoPtr = (TREEVIEW_INFO *) COMCTL32_Alloc (sizeof(TREEVIEW_INFO));
2142 SetWindowLongA( hwnd, 0, (DWORD)infoPtr);
2144 if (infoPtr == NULL) {
2145 ERR("could not allocate info memory!\n");
2149 if ((TREEVIEW_INFO*) GetWindowLongA( hwnd, 0) != infoPtr) {
2150 ERR("pointer assignment error!\n");
2156 /* set default settings */
2157 infoPtr->uInternalStatus=0;
2158 infoPtr->uNumItems=0;
2159 infoPtr->clrBk = GetSysColor (COLOR_WINDOW);
2160 infoPtr->clrText = GetSysColor (COLOR_BTNTEXT);
2161 infoPtr->clrLine = GetSysColor (COLOR_WINDOWTEXT);
2164 infoPtr->uIndent = 15;
2165 infoPtr->himlNormal = NULL;
2166 infoPtr->himlState = NULL;
2167 infoPtr->uItemHeight = -1;
2168 GetTextMetricsA (hdc, &tm);
2169 infoPtr->hFont = GetStockObject (DEFAULT_GUI_FONT);
2170 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
2171 logFont.lfWeight=FW_BOLD;
2172 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
2174 infoPtr->items = NULL;
2175 infoPtr->selectedItem=0;
2176 infoPtr->clrText=-1; /* use system color */
2177 infoPtr->dropItem=0;
2178 infoPtr->pCallBackSort=NULL;
2179 infoPtr->uScrollTime = 300; /* milliseconds */
2182 infoPtr->hwndNotify = GetParent32 (hwnd);
2183 infoPtr->bTransparent = ( GetWindowLongA( hwnd, GWL_STYLE) & TBSTYLE_FLAT);
2186 infoPtr->hwndToolTip=0;
2187 if (!( GetWindowLongA( hwnd, GWL_STYLE) & TVS_NOTOOLTIPS)) { /* Create tooltip control */
2190 infoPtr->hwndToolTip =
2191 CreateWindowExA (0, TOOLTIPS_CLASSA, NULL, 0,
2192 CW_USEDEFAULT, CW_USEDEFAULT,
2193 CW_USEDEFAULT, CW_USEDEFAULT,
2196 /* Send NM_TOOLTIPSCREATED notification */
2197 if (infoPtr->hwndToolTip) {
2198 NMTOOLTIPSCREATED nmttc;
2200 nmttc.hdr.hwndFrom = hwnd;
2201 nmttc.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2202 nmttc.hdr.code = NM_TOOLTIPSCREATED;
2203 nmttc.hwndToolTips = infoPtr->hwndToolTip;
2205 SendMessageA (GetParent (hwnd), WM_NOTIFY,
2206 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmttc);
2209 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
2210 ti.cbSize = sizeof(TTTOOLINFOA);
2211 ti.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_TRANSPARENT ;
2214 ti.lpszText = "Test"; /* LPSTR_TEXTCALLBACK; */
2215 SetRectEmpty (&ti.rect);
2217 SendMessageA (infoPtr->hwndToolTip, TTM_ADDTOOLA, 0, (LPARAM)&ti);
2220 infoPtr->hwndEdit = CreateWindowExA (
2224 WS_CHILD | WS_BORDER | ES_AUTOHSCROLL |
2225 ES_WANTRETURN | ES_LEFT,
2228 0,0,0); /* FIXME: (HMENU)IDTVEDIT,pcs->hInstance,0);*/
2230 SendMessageA ( infoPtr->hwndEdit, WM_SETFONT, infoPtr->hFont, FALSE);
2231 infoPtr->wpEditOrig = (WNDPROC)SetWindowLongA (
2234 (LONG) TREEVIEW_Edit_SubclassProc);
2236 ReleaseDC (hwnd, hdc);
2243 TREEVIEW_Destroy (HWND hwnd)
2245 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2248 TREEVIEW_RemoveTree (hwnd);
2249 if (infoPtr->Timer & TV_REFRESH_TIMER_SET)
2250 KillTimer (hwnd, TV_REFRESH_TIMER);
2251 if (infoPtr->hwndToolTip)
2252 DestroyWindow (infoPtr->hwndToolTip);
2254 COMCTL32_Free (infoPtr);
2260 TREEVIEW_Paint (HWND hwnd, WPARAM wParam, LPARAM lParam)
2266 hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
2267 TREEVIEW_Refresh (hwnd);
2269 EndPaint (hwnd, &ps);
2272 return DefWindowProcA (hwnd, WM_PAINT, wParam, lParam);
2276 TREEVIEW_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2278 TREEVIEW_SendSimpleNotify (hwnd, NM_SETFOCUS);
2279 InvalidateRect(hwnd, NULL, FALSE);
2284 TREEVIEW_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2286 TREEVIEW_SendSimpleNotify (hwnd, NM_KILLFOCUS);
2287 InvalidateRect(hwnd, NULL, FALSE);
2292 TREEVIEW_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
2294 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2295 HBRUSH hBrush = CreateSolidBrush (infoPtr->clrBk);
2299 GetClientRect (hwnd, &rect);
2300 FillRect ((HDC)wParam, &rect, hBrush);
2301 DeleteObject (hBrush);
2317 TREEVIEW_SendSimpleNotify (HWND hwnd, UINT code)
2322 nmhdr.hwndFrom = hwnd;
2323 nmhdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2326 return (BOOL) SendMessageA (GetParent (hwnd), WM_NOTIFY,
2327 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
2333 TREEVIEW_SendTreeviewNotify (HWND hwnd, UINT code, UINT action,
2334 HTREEITEM oldItem, HTREEITEM newItem)
2337 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2339 TREEVIEW_ITEM *wineItem;
2341 TRACE("code:%x action:%x olditem:%x newitem:%x\n",
2342 code,action,(INT)oldItem,(INT)newItem);
2343 nmhdr.hdr.hwndFrom = hwnd;
2344 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2345 nmhdr.hdr.code = code;
2346 nmhdr.action = action;
2348 wineItem=& infoPtr->items[(INT)oldItem];
2349 nmhdr.itemOld.mask = wineItem->mask;
2350 nmhdr.itemOld.hItem = wineItem->hItem;
2351 nmhdr.itemOld.state = wineItem->state;
2352 nmhdr.itemOld.stateMask = wineItem->stateMask;
2353 nmhdr.itemOld.iImage = wineItem->iImage;
2354 nmhdr.itemOld.pszText = wineItem->pszText;
2355 nmhdr.itemOld.cchTextMax= wineItem->cchTextMax;
2356 nmhdr.itemOld.iImage = wineItem->iImage;
2357 nmhdr.itemOld.iSelectedImage = wineItem->iSelectedImage;
2358 nmhdr.itemOld.cChildren = wineItem->cChildren;
2359 nmhdr.itemOld.lParam = wineItem->lParam;
2363 wineItem=& infoPtr->items[(INT)newItem];
2364 nmhdr.itemNew.mask = wineItem->mask;
2365 nmhdr.itemNew.hItem = wineItem->hItem;
2366 nmhdr.itemNew.state = wineItem->state;
2367 nmhdr.itemNew.stateMask = wineItem->stateMask;
2368 nmhdr.itemNew.iImage = wineItem->iImage;
2369 nmhdr.itemNew.pszText = wineItem->pszText;
2370 nmhdr.itemNew.cchTextMax= wineItem->cchTextMax;
2371 nmhdr.itemNew.iImage = wineItem->iImage;
2372 nmhdr.itemNew.iSelectedImage = wineItem->iSelectedImage;
2373 nmhdr.itemNew.cChildren = wineItem->cChildren;
2374 nmhdr.itemNew.lParam = wineItem->lParam;
2380 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2381 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2386 TREEVIEW_SendTreeviewDnDNotify (HWND hwnd, UINT code, HTREEITEM dragItem,
2389 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2391 TREEVIEW_ITEM *wineItem;
2393 TRACE("code:%x dragitem:%x\n", code,(INT)dragItem);
2395 nmhdr.hdr.hwndFrom = hwnd;
2396 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2397 nmhdr.hdr.code = code;
2399 wineItem=& infoPtr->items[(INT)dragItem];
2400 nmhdr.itemNew.mask = wineItem->mask;
2401 nmhdr.itemNew.hItem = wineItem->hItem;
2402 nmhdr.itemNew.state = wineItem->state;
2403 nmhdr.itemNew.lParam = wineItem->lParam;
2405 nmhdr.ptDrag.x = pt.x;
2406 nmhdr.ptDrag.y = pt.y;
2408 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2409 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2416 TREEVIEW_SendDispInfoNotify (HWND hwnd, TREEVIEW_ITEM *wineItem,
2417 UINT code, UINT what)
2423 TRACE("item %d, action %x, state %d\n",
2424 (INT)wineItem->hItem,
2426 (INT)wineItem->state);
2428 tvdi.hdr.hwndFrom = hwnd;
2429 tvdi.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2430 tvdi.hdr.code = code;
2431 tvdi.item.mask = what;
2432 tvdi.item.hItem = wineItem->hItem;
2433 tvdi.item.state = wineItem->state;
2434 tvdi.item.lParam = wineItem->lParam;
2435 tvdi.item.pszText = COMCTL32_Alloc (128*sizeof(char));
2436 buf = tvdi.item.pszText;
2438 retval=(BOOL)SendMessageA (
2441 (WPARAM)tvdi.hdr.idFrom,
2444 if (what & TVIF_TEXT) {
2445 wineItem->pszText = tvdi.item.pszText;
2446 if (buf==tvdi.item.pszText) {
2447 wineItem->cchTextMax = 128;
2449 TRACE("user-supplied buffer\n");
2450 COMCTL32_Free (buf);
2451 wineItem->cchTextMax = 0;
2454 if (what & TVIF_SELECTEDIMAGE)
2455 wineItem->iSelectedImage = tvdi.item.iSelectedImage;
2456 if (what & TVIF_IMAGE)
2457 wineItem->iImage = tvdi.item.iImage;
2458 if (what & TVIF_CHILDREN)
2459 wineItem->cChildren = tvdi.item.cChildren;
2467 TREEVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
2470 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2471 NMTVCUSTOMDRAW nmcdhdr;
2472 LPNMCUSTOMDRAW nmcd;
2474 TRACE("drawstage:%lx hdc:%x\n", dwDrawStage, hdc);
2476 nmcd= & nmcdhdr.nmcd;
2477 nmcd->hdr.hwndFrom = hwnd;
2478 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2479 nmcd->hdr.code = NM_CUSTOMDRAW;
2480 nmcd->dwDrawStage= dwDrawStage;
2482 nmcd->rc.left = rc.left;
2483 nmcd->rc.right = rc.right;
2484 nmcd->rc.bottom = rc.bottom;
2485 nmcd->rc.top = rc.top;
2486 nmcd->dwItemSpec = 0;
2487 nmcd->uItemState = 0;
2488 nmcd->lItemlParam= 0;
2489 nmcdhdr.clrText = infoPtr->clrText;
2490 nmcdhdr.clrTextBk= infoPtr->clrBk;
2493 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2494 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2500 /* FIXME: need to find out when the flags in uItemState need to be set */
2503 TREEVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
2504 TREEVIEW_ITEM *wineItem, UINT uItemDrawState)
2506 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2507 NMTVCUSTOMDRAW nmcdhdr;
2508 LPNMCUSTOMDRAW nmcd;
2509 DWORD dwDrawStage,dwItemSpec;
2512 dwDrawStage=CDDS_ITEM | uItemDrawState;
2513 dwItemSpec=(DWORD)wineItem->hItem;
2515 if (wineItem->hItem==infoPtr->selectedItem) uItemState|=CDIS_SELECTED;
2516 if (wineItem->hItem==infoPtr->focusItem) uItemState|=CDIS_FOCUS;
2517 if (wineItem->hItem==infoPtr->hotItem) uItemState|=CDIS_HOT;
2519 nmcd= & nmcdhdr.nmcd;
2520 nmcd->hdr.hwndFrom = hwnd;
2521 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2522 nmcd->hdr.code = NM_CUSTOMDRAW;
2523 nmcd->dwDrawStage= dwDrawStage;
2525 nmcd->rc.left = wineItem->rect.left;
2526 nmcd->rc.right = wineItem->rect.right;
2527 nmcd->rc.bottom = wineItem->rect.bottom;
2528 nmcd->rc.top = wineItem->rect.top;
2529 nmcd->dwItemSpec = dwItemSpec;
2530 nmcd->uItemState = uItemState;
2531 nmcd->lItemlParam= wineItem->lParam;
2533 nmcdhdr.clrText = infoPtr->clrText;
2534 nmcdhdr.clrTextBk= infoPtr->clrBk;
2535 nmcdhdr.iLevel = wineItem->iLevel;
2537 TRACE("drawstage:%lx hdc:%x item:%lx, itemstate:%x\n",
2538 dwDrawStage, hdc, dwItemSpec, uItemState);
2540 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2541 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2546 /* Note:If the specified item is the child of a collapsed parent item,
2547 the parent's list of child items is (recursively) expanded to reveal the
2548 specified item. This is mentioned for TREEVIEW_SelectItem; don't
2549 know if it also applies here.
2553 TREEVIEW_Expand (HWND hwnd, WPARAM wParam, LPARAM lParam)
2555 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2556 TREEVIEW_ITEM *wineItem;
2560 flag = (UINT) wParam;
2561 expand = (INT) lParam;
2563 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2567 if (!wineItem->cChildren)
2570 if (wineItem->pszText==LPSTR_TEXTCALLBACKA)
2571 TRACE ("For item %d, flags %d, state %d\n",
2572 expand, flag, wineItem->state);
2574 TRACE("For (%s) item:%d, flags %x, state:%d\n",
2575 wineItem->pszText, flag, expand, wineItem->state);
2577 if (wineItem->cChildren==I_CHILDRENCALLBACK) {
2578 FIXME("we don't handle I_CHILDRENCALLBACK yet\n");
2582 if (flag == TVE_TOGGLE) { /* FIXME: check exact behaviour here */
2583 flag &= ~TVE_TOGGLE; /* ie: bitwise ops or 'case' ops */
2584 if (wineItem->state & TVIS_EXPANDED)
2585 flag |= TVE_COLLAPSE;
2592 case TVE_COLLAPSERESET:
2593 TRACE(" case TVE_COLLAPSERESET\n");
2594 if (!wineItem->state & TVIS_EXPANDED)
2597 wineItem->state &= ~(TVIS_EXPANDEDONCE | TVIS_EXPANDED);
2598 TREEVIEW_RemoveAllChildren (hwnd, wineItem);
2602 TRACE(" case TVE_COLLAPSE\n");
2603 if (!wineItem->state & TVIS_EXPANDED)
2606 wineItem->state &= ~TVIS_EXPANDED;
2610 TRACE(" case TVE_EXPAND\n");
2611 if (wineItem->state & TVIS_EXPANDED)
2614 TRACE(" is not expanded...\n");
2616 if (!(wineItem->state & TVIS_EXPANDEDONCE))
2618 TRACE(" and has never been expanded...\n");
2619 wineItem->state |= TVIS_EXPANDED;
2621 /* this item has never been expanded */
2622 if (TREEVIEW_SendTreeviewNotify (
2629 TRACE(" TVN_ITEMEXPANDING returned TRUE, exiting...\n");
2634 * Since the TVN_ITEMEXPANDING message may has caused the parent to
2635 * insert new items which in turn may have cause items placeholder
2636 * reallocation, I reassign the current item pointer so we have
2637 * something valid to work with...
2638 * However, this should not be necessary,
2639 * investigation required in TREEVIEW_InsertItemA
2641 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2645 "Catastropic situation, cannot retreive item #%d\n",
2650 wineItem->state |= TVIS_EXPANDEDONCE;
2651 TRACE(" TVN_ITEMEXPANDING sent...\n");
2653 TREEVIEW_SendTreeviewNotify (
2660 TRACE(" TVN_ITEMEXPANDED sent...\n");
2665 /* this item has already been expanded */
2666 wineItem->state |= TVIS_EXPANDED;
2670 case TVE_EXPANDPARTIAL:
2671 TRACE(" case TVE_EXPANDPARTIAL\n");
2672 FIXME("TVE_EXPANDPARTIAL not implemented\n");
2673 wineItem->state ^=TVIS_EXPANDED;
2674 wineItem->state |=TVIS_EXPANDEDONCE;
2678 TRACE("Exiting, Item %d state is now %d...\n",
2682 TREEVIEW_QueueRefresh (hwnd);
2688 static TREEVIEW_ITEM *
2689 TREEVIEW_HitTestPoint (HWND hwnd, POINT pt)
2691 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2692 TREEVIEW_ITEM *wineItem;
2695 GetClientRect (hwnd, &rect);
2697 if (!infoPtr->firstVisible) return NULL;
2699 wineItem=&infoPtr->items [(INT)infoPtr->firstVisible];
2701 while ((wineItem!=NULL) && (pt.y > wineItem->rect.bottom))
2702 wineItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
2714 TREEVIEW_HitTest (HWND hwnd, LPARAM lParam)
2716 LPTVHITTESTINFO lpht=(LPTVHITTESTINFO) lParam;
2717 TREEVIEW_ITEM *wineItem;
2721 GetClientRect (hwnd, &rect);
2725 if (x < rect.left) status|=TVHT_TOLEFT;
2726 if (x > rect.right) status|=TVHT_TORIGHT;
2727 if (y < rect.top ) status|=TVHT_ABOVE;
2728 if (y > rect.bottom) status|=TVHT_BELOW;
2735 wineItem=TREEVIEW_HitTestPoint (hwnd, lpht->pt);
2737 lpht->flags=TVHT_NOWHERE;
2741 /* FIXME: implement other flags
2742 * Assign the appropriate flags depending on the click location
2743 * Intitialize flags before to "|=" it...
2747 if (x < wineItem->expandBox.left)
2749 lpht->flags |= TVHT_ONITEMINDENT;
2751 else if ( ( x >= wineItem->expandBox.left) &&
2752 ( x <= wineItem->expandBox.right))
2754 lpht->flags |= TVHT_ONITEMBUTTON;
2756 else if (x < wineItem->rect.right)
2758 lpht->flags |= TVHT_ONITEMLABEL;
2762 lpht->flags|=TVHT_ONITEMRIGHT;
2765 lpht->hItem=wineItem->hItem;
2767 return (LRESULT) wineItem->hItem;
2771 TREEVIEW_EndEditLabelNow (HWND hwnd, WPARAM wParam, LPARAM lParam)
2773 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2774 TREEVIEW_ITEM *editedItem = TREEVIEW_ValidItem (infoPtr, infoPtr->editItem);
2775 BOOL bRevert = (BOOL)wParam;
2776 BOOL bReturn = ! bRevert;
2778 if ( ! (BOOL)wParam ) /* wParam is set to true to cancel the edition */
2780 if ( TREEVIEW_SendDispInfoNotify( /* return true to cancel edition */
2791 if (bRevert == FALSE) /* Apply the changes */
2794 int iLength = GetWindowTextA(infoPtr->hwndEdit, tmpText, 1023);
2799 ERR("Problem retreiving new item label.");
2801 else if (iLength >= 1023)
2804 "Insuficient space to retrieve new item label, new label ignored.");
2808 if (strcmp( tmpText, editedItem->pszText ) == 0)
2809 /* Do nothing if the label has not changed */
2813 LPSTR tmpLabel = COMCTL32_Alloc( iLength+1 );
2815 if ( tmpLabel == NULL )
2817 "OutOfMemory, cannot allocate space for label");
2820 COMCTL32_Free(editedItem->pszText);
2821 editedItem->pszText = tmpLabel;
2822 lstrcpyA( editedItem->pszText, tmpText);
2828 ShowWindow(infoPtr->hwndEdit, SW_HIDE);
2829 EnableWindow(infoPtr->hwndEdit, FALSE);
2830 infoPtr->editItem = 0;
2839 TREEVIEW_LButtonDoubleClick (HWND hwnd, WPARAM wParam, LPARAM lParam)
2841 TREEVIEW_ITEM *wineItem;
2845 pt.x = (INT)LOWORD(lParam);
2846 pt.y = (INT)HIWORD(lParam);
2849 wineItem=TREEVIEW_HitTestPoint (hwnd, pt);
2850 if (!wineItem) return 0;
2851 TRACE("item %d \n",(INT)wineItem->hItem);
2853 if (TREEVIEW_SendSimpleNotify (hwnd, NM_DBLCLK)!=TRUE) { /* FIXME!*/
2854 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) wineItem->hItem);
2861 TREEVIEW_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
2863 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2867 ht.pt.x = (INT)LOWORD(lParam);
2868 ht.pt.y = (INT)HIWORD(lParam);
2871 iItem=TREEVIEW_HitTest (hwnd, (LPARAM) &ht);
2872 TRACE("item %d \n",iItem);
2874 if (ht.flags & TVHT_ONITEMBUTTON) {
2875 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) iItem);
2879 infoPtr->uInternalStatus|=TV_LDRAG;
2886 TREEVIEW_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
2888 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2890 TREEVIEW_ITEM *editItem;
2893 ht.pt.x = (INT)LOWORD(lParam);
2894 ht.pt.y = (INT)HIWORD(lParam);
2898 /* Return true to cancel default behaviour */
2899 if ( TREEVIEW_SendSimpleNotify (hwnd, NM_CLICK) )
2903 iItem = TREEVIEW_HitTest (hwnd, (LPARAM) &ht);
2907 editItem = TREEVIEW_ValidItem(infoPtr, (HTREEITEM)iItem);
2909 infoPtr->uInternalStatus &= ~(TV_LDRAG | TV_LDRAGGING);
2912 * If the style allow editing and the node is already selected
2913 * and the click occured on the item label...
2915 if ( ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_EDITLABELS ) &&
2916 ( editItem->state & TVIS_SELECTED ) &&
2917 ( ht.flags & TVHT_ONITEMLABEL ))
2919 if ( infoPtr->editItem == 0 ) /* If we are not curently editing */
2921 if ( TREEVIEW_SendDispInfoNotify( /* Return true to cancel edition */
2930 TRACE("Edit started for %s.\n", editItem->pszText);
2931 infoPtr->editItem = editItem->hItem;
2936 editItem->text.left - 2,
2937 editItem->text.top - 1,
2938 editItem->text.right - editItem->text.left + 20 ,
2939 editItem->text.bottom - editItem->text.top + 3,
2942 SetWindowTextA( infoPtr->hwndEdit, editItem->pszText );
2943 SendMessageA ( infoPtr->hwndEdit, EM_SETSEL, 0, -1 );
2944 SetFocus ( infoPtr->hwndEdit);
2945 ShowWindow ( infoPtr->hwndEdit, SW_SHOW);
2948 else if ( infoPtr->editItem != 0 ) /* If we are curently editing */
2950 TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
2952 else if ( ht.flags & (TVHT_ONITEMLABEL | TVHT_ONITEMICON))
2954 TREEVIEW_DoSelectItem (
2966 TREEVIEW_RButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
2968 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2971 infoPtr->uInternalStatus|=TV_RDRAG;
2976 TREEVIEW_RButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
2978 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2981 if (TREEVIEW_SendSimpleNotify (hwnd, NM_RCLICK)) return 0;
2982 infoPtr->uInternalStatus&= ~(TV_RDRAG | TV_RDRAGGING);
2988 TREEVIEW_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
2990 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2991 TREEVIEW_ITEM *hotItem;
2994 pt.x=(INT) LOWORD (lParam);
2995 pt.y=(INT) HIWORD (lParam);
2996 hotItem=TREEVIEW_HitTestPoint (hwnd, pt);
2997 if (!hotItem) return 0;
2998 infoPtr->focusItem=hotItem->hItem;
3000 if ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_DISABLEDRAGDROP) return 0;
3002 if (infoPtr->uInternalStatus & TV_LDRAG) {
3003 TREEVIEW_SendTreeviewDnDNotify (hwnd, TVN_BEGINDRAG, hotItem->hItem, pt);
3004 infoPtr->uInternalStatus &= ~TV_LDRAG;
3005 infoPtr->uInternalStatus |= TV_LDRAGGING;
3006 infoPtr->dropItem=hotItem->hItem;
3010 if (infoPtr->uInternalStatus & TV_RDRAG) {
3011 TREEVIEW_SendTreeviewDnDNotify (hwnd, TVN_BEGINRDRAG, hotItem->hItem, pt);
3012 infoPtr->uInternalStatus &= ~TV_RDRAG;
3013 infoPtr->uInternalStatus |= TV_RDRAGGING;
3014 infoPtr->dropItem=hotItem->hItem;
3023 TREEVIEW_CreateDragImage (HWND hwnd, WPARAM wParam, LPARAM lParam)
3025 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3026 TREEVIEW_ITEM *dragItem;
3030 HBITMAP hbmp,hOldbmp;
3037 if (!(infoPtr->himlNormal)) return 0;
3038 dragItem=TREEVIEW_ValidItem (infoPtr, (HTREEITEM) lParam);
3040 if (!dragItem) return 0;
3041 itemtxt=dragItem->pszText;
3043 hwtop=GetDesktopWindow ();
3044 htopdc= GetDC (hwtop);
3045 hdc=CreateCompatibleDC (htopdc);
3047 hOldFont=SelectObject (hdc, infoPtr->hFont);
3048 GetTextExtentPoint32A (hdc, itemtxt, lstrlenA (itemtxt), &size);
3049 TRACE("%d %d %s %d\n",size.cx,size.cy,itemtxt,lstrlenA(itemtxt));
3050 hbmp=CreateCompatibleBitmap (htopdc, size.cx, size.cy);
3051 hOldbmp=SelectObject (hdc, hbmp);
3053 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &cy);
3055 if (cy>size.cy) size.cy=cy;
3057 infoPtr->dragList=ImageList_Create (size.cx, size.cy, ILC_COLOR, 10, 10);
3058 ImageList_Draw (infoPtr->himlNormal, dragItem->iImage, hdc, 0, 0, ILD_NORMAL);
3061 ImageList_GetImageInfo (infoPtr->himlNormal, dragItem->hItem, &iminfo);
3062 ImageList_AddMasked (infoPtr->dragList, iminfo.hbmImage, CLR_DEFAULT);
3065 /* draw item text */
3067 SetRect (&rc, cx, 0, size.cx,size.cy);
3068 DrawTextA (hdc, itemtxt, lstrlenA (itemtxt), &rc, DT_LEFT);
3069 SelectObject (hdc, hOldFont);
3070 SelectObject (hdc, hOldbmp);
3072 ImageList_Add (infoPtr->dragList, hbmp, 0);
3075 DeleteObject (hbmp);
3076 ReleaseDC (hwtop, htopdc);
3078 return (LRESULT)infoPtr->dragList;
3083 TREEVIEW_DoSelectItem (HWND hwnd, INT action, HTREEITEM newSelect, INT cause)
3086 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3087 TREEVIEW_ITEM *prevItem,*wineItem;
3090 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)newSelect);
3092 TRACE("Entering item %d, flag %x, cause %x, state %d\n",
3098 if ( (wineItem) && (wineItem->parent))
3101 * If the item has a collapse parent expand the parent so he
3102 * can expose the item
3104 TREEVIEW_ITEM *parentItem = TREEVIEW_ValidItem (infoPtr, wineItem->parent);
3105 if ( !(parentItem->state & TVIS_EXPANDED))
3106 TREEVIEW_Expand (hwnd, TVE_EXPAND, (LPARAM) wineItem->parent);
3112 prevSelect=(INT)infoPtr->selectedItem;
3114 if ((HTREEITEM)prevSelect==newSelect)
3117 prevItem= TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect);
3120 if (TREEVIEW_SendTreeviewNotify(
3124 (HTREEITEM)prevSelect,
3125 (HTREEITEM)newSelect))
3126 return FALSE; /* FIXME: OK? */
3129 prevItem->state &= ~TVIS_SELECTED;
3131 wineItem->state |= TVIS_SELECTED;
3133 infoPtr->selectedItem=(HTREEITEM)newSelect;
3135 TREEVIEW_SendTreeviewNotify(
3139 (HTREEITEM)prevSelect,
3140 (HTREEITEM)newSelect);
3144 case TVGN_DROPHILITE:
3145 prevItem= TREEVIEW_ValidItem (infoPtr, infoPtr->dropItem);
3148 prevItem->state &= ~TVIS_DROPHILITED;
3150 infoPtr->dropItem=(HTREEITEM)newSelect;
3153 wineItem->state |=TVIS_DROPHILITED;
3157 case TVGN_FIRSTVISIBLE:
3158 FIXME("FIRSTVISIBLE not implemented\n");
3162 TREEVIEW_QueueRefresh (hwnd);
3164 TRACE("Leaving state %d\n", wineItem->state);
3168 /* FIXME: handle NM_KILLFocus enzo */
3170 TREEVIEW_SelectItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
3173 return TREEVIEW_DoSelectItem (hwnd, wParam, (HTREEITEM) lParam, TVC_UNKNOWN);
3180 TREEVIEW_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
3183 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3185 TRACE("%x\n",infoPtr->hFont);
3186 return infoPtr->hFont;
3190 TREEVIEW_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
3193 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3196 HFONT hFont, hOldFont;
3200 TRACE("%x %lx\n",wParam, lParam);
3202 infoPtr->hFont = (HFONT)wParam;
3204 hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
3206 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
3207 logFont.lfWeight=FW_BOLD;
3208 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
3211 hOldFont = SelectObject (hdc, hFont);
3212 GetTextMetricsA (hdc, &tm);
3213 height= tm.tmHeight + tm.tmExternalLeading;
3214 if (height>infoPtr->uRealItemHeight)
3215 infoPtr->uRealItemHeight=height;
3216 SelectObject (hdc, hOldFont);
3220 TREEVIEW_QueueRefresh (hwnd);
3228 TREEVIEW_VScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
3231 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3234 TRACE("wp %x, lp %lx\n", wParam, lParam);
3235 if (!infoPtr->uInternalStatus & TV_VSCROLL) return FALSE;
3237 switch (LOWORD (wParam)) {
3239 if (!infoPtr->cy) return FALSE;
3240 infoPtr->cy -= infoPtr->uRealItemHeight;
3241 if (infoPtr->cy < 0) infoPtr->cy=0;
3244 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3245 if (infoPtr->cy == maxHeight) return FALSE;
3246 infoPtr->cy += infoPtr->uRealItemHeight;
3247 if (infoPtr->cy > maxHeight)
3248 infoPtr->cy = maxHeight;
3251 if (!infoPtr->cy) return FALSE;
3252 infoPtr->cy -= infoPtr->uVisibleHeight;
3253 if (infoPtr->cy < 0) infoPtr->cy=0;
3256 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3257 if (infoPtr->cy == maxHeight) return FALSE;
3258 infoPtr->cy += infoPtr->uVisibleHeight;
3259 if (infoPtr->cy > maxHeight)
3260 infoPtr->cy = maxHeight;
3263 infoPtr->cy = HIWORD (wParam);
3268 TREEVIEW_QueueRefresh (hwnd);
3273 TREEVIEW_HScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
3275 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3278 TRACE("wp %lx, lp %x\n", lParam, wParam);
3280 if (!infoPtr->uInternalStatus & TV_HSCROLL) return FALSE;
3282 switch (LOWORD (wParam)) {
3284 if (!infoPtr->cx) return FALSE;
3285 infoPtr->cx -= infoPtr->uRealItemHeight;
3286 if (infoPtr->cx < 0) infoPtr->cx=0;
3289 maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
3290 if (infoPtr->cx == maxWidth) return FALSE;
3291 infoPtr->cx += infoPtr->uRealItemHeight; /*FIXME */
3292 if (infoPtr->cx > maxWidth)
3293 infoPtr->cx = maxWidth;
3296 if (!infoPtr->cx) return FALSE;
3297 infoPtr->cx -= infoPtr->uVisibleWidth;
3298 if (infoPtr->cx < 0) infoPtr->cx=0;
3301 maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
3302 if (infoPtr->cx == maxWidth) return FALSE;
3303 infoPtr->cx += infoPtr->uVisibleWidth;
3304 if (infoPtr->cx > maxWidth)
3305 infoPtr->cx = maxWidth;
3308 infoPtr->cx = HIWORD (wParam);
3313 TREEVIEW_QueueRefresh (hwnd);
3319 TREEVIEW_KeyDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
3321 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3322 HTREEITEM hNewSelection = 0;
3323 INT scrollNeeds = -1;
3324 INT cyChangeNeeds = -1;
3325 INT prevSelect = (INT)infoPtr->selectedItem;
3327 TREEVIEW_ITEM *prevItem =
3328 (prevSelect != 0 ) ?
3329 TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect) :
3332 TREEVIEW_ITEM *newItem = NULL;
3334 TRACE("%x %lx\n",wParam, lParam);
3336 if (prevSelect == 0)
3341 newItem=TREEVIEW_GetPrevListItem (infoPtr, prevItem);
3344 newItem=& infoPtr->items[(INT)infoPtr->TopRootItem];
3346 hNewSelection = newItem->hItem;
3348 if (! newItem->visible)
3349 scrollNeeds = SB_LINEUP;
3354 newItem=TREEVIEW_GetNextListItem (infoPtr, prevItem);
3359 hNewSelection = newItem->hItem;
3361 if (! newItem->visible)
3362 scrollNeeds = SB_LINEDOWN;
3367 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem];
3368 hNewSelection = newItem->hItem;
3373 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem];
3374 newItem = TREEVIEW_GetLastListItem (infoPtr, newItem);
3375 hNewSelection = newItem->hItem;
3377 if (! newItem->visible)
3378 cyChangeNeeds = infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3383 if ( (prevItem->cChildren > 0) && (prevItem->state & TVIS_EXPANDED) )
3385 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect );
3387 else if ((INT)prevItem->parent)
3389 newItem = (& infoPtr->items[(INT)prevItem->parent]);
3390 if (! newItem->visible)
3391 /* FIXME find a way to make this item the first visible... */
3394 hNewSelection = newItem->hItem;
3400 if ( ( prevItem->cChildren > 0) ||
3401 ( prevItem->cChildren == I_CHILDRENCALLBACK))
3403 if (! (prevItem->state & TVIS_EXPANDED))
3404 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect );
3407 newItem = (& infoPtr->items[(INT)prevItem->firstChild]);
3408 hNewSelection = newItem->hItem;
3415 if (! (prevItem->state & TVIS_EXPANDED))
3416 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect );
3420 if (prevItem->state & TVIS_EXPANDED)
3421 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect );
3426 newItem=TREEVIEW_GetListItem(
3429 -1*(TREEVIEW_GetVisibleCount(hwnd,0,0)-3));
3433 hNewSelection = newItem->hItem;
3435 if (! newItem->visible)
3436 scrollNeeds = SB_PAGEUP;
3441 newItem=TREEVIEW_GetListItem(
3444 TREEVIEW_GetVisibleCount(hwnd,0,0)-3);
3449 hNewSelection = newItem->hItem;
3451 if (! newItem->visible)
3452 scrollNeeds = SB_PAGEDOWN;
3461 FIXME("%x not implemented\n", wParam);
3468 This works but does not send notification...
3470 prevItem->state &= ~TVIS_SELECTED;
3471 newItem->state |= TVIS_SELECTED;
3472 infoPtr->selectedItem = hNewSelection;
3473 TREEVIEW_QueueRefresh (hwnd);
3476 if ( TREEVIEW_DoSelectItem(
3479 (HTREEITEM)hNewSelection,
3482 /* If selection change is allowed for the new item, perform scrolling */
3483 if (scrollNeeds != -1)
3484 TREEVIEW_VScroll(hwnd, scrollNeeds, 0);
3486 if (cyChangeNeeds != -1)
3487 infoPtr->cy = cyChangeNeeds;
3489 /* FIXME: Something happen in the load the in the two weeks before
3490 april 1st 1999 which makes this SetFocus mandatory otherwise, the focus
3491 is lost... However the SetFocus should not be required...*/
3502 TREEVIEW_GetScrollTime (HWND hwnd)
3504 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3506 return infoPtr->uScrollTime;
3511 TREEVIEW_SetScrollTime (HWND hwnd, UINT uScrollTime)
3513 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3514 UINT uOldScrollTime = infoPtr->uScrollTime;
3516 infoPtr->uScrollTime = min (uScrollTime, 100);
3518 return uOldScrollTime;
3522 static LRESULT WINAPI
3523 TREEVIEW_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3526 case TVM_INSERTITEMA:
3527 return TREEVIEW_InsertItemA (hwnd, wParam, lParam);
3529 case TVM_INSERTITEMW:
3530 return TREEVIEW_InsertItemW(hwnd,wParam,lParam);;
3532 case TVM_DELETEITEM:
3533 return TREEVIEW_DeleteItem (hwnd, wParam, lParam);
3536 return TREEVIEW_Expand (hwnd, wParam, lParam);
3538 case TVM_GETITEMRECT:
3539 return TREEVIEW_GetItemRect (hwnd, wParam, lParam);
3542 return TREEVIEW_GetCount (hwnd, wParam, lParam);
3545 return TREEVIEW_GetIndent (hwnd);
3548 return TREEVIEW_SetIndent (hwnd, wParam);
3550 case TVM_GETIMAGELIST:
3551 return TREEVIEW_GetImageList (hwnd, wParam, lParam);
3553 case TVM_SETIMAGELIST:
3554 return TREEVIEW_SetImageList (hwnd, wParam, lParam);
3556 case TVM_GETNEXTITEM:
3557 return TREEVIEW_GetNextItem (hwnd, wParam, lParam);
3559 case TVM_SELECTITEM:
3560 return TREEVIEW_SelectItem (hwnd, wParam, lParam);
3563 return TREEVIEW_GetItemA (hwnd, wParam, lParam);
3566 FIXME("Unimplemented msg TVM_GETITEMW\n");
3570 return TREEVIEW_SetItemA (hwnd, wParam, lParam);
3573 FIXME("Unimplemented msg TVM_SETITEMW\n");
3576 case TVM_EDITLABELA:
3577 FIXME("Unimplemented msg TVM_EDITLABELA \n");
3580 case TVM_EDITLABELW:
3581 FIXME("Unimplemented msg TVM_EDITLABELW \n");
3584 case TVM_GETEDITCONTROL:
3585 return TREEVIEW_GetEditControl (hwnd);
3587 case TVM_GETVISIBLECOUNT:
3588 return TREEVIEW_GetVisibleCount (hwnd, wParam, lParam);
3591 return TREEVIEW_HitTest (hwnd, lParam);
3593 case TVM_CREATEDRAGIMAGE:
3594 return TREEVIEW_CreateDragImage (hwnd, wParam, lParam);
3596 case TVM_SORTCHILDREN:
3597 return TREEVIEW_SortChildren (hwnd, wParam, lParam);
3599 case TVM_ENSUREVISIBLE:
3600 FIXME("Unimplemented msg TVM_ENSUREVISIBLE\n");
3603 case TVM_SORTCHILDRENCB:
3604 return TREEVIEW_SortChildrenCB(hwnd, wParam, lParam);
3606 case TVM_ENDEDITLABELNOW:
3607 return TREEVIEW_EndEditLabelNow (hwnd, wParam, lParam);
3609 case TVM_GETISEARCHSTRINGA:
3610 FIXME("Unimplemented msg TVM_GETISEARCHSTRINGA\n");
3613 case TVM_GETISEARCHSTRINGW:
3614 FIXME("Unimplemented msg TVM_GETISEARCHSTRINGW\n");
3617 case TVM_GETTOOLTIPS:
3618 return TREEVIEW_GetToolTips (hwnd);
3620 case TVM_SETTOOLTIPS:
3621 return TREEVIEW_SetToolTips (hwnd, wParam);
3623 case TVM_SETINSERTMARK:
3624 FIXME("Unimplemented msg TVM_SETINSERTMARK\n");
3627 case TVM_SETITEMHEIGHT:
3628 return TREEVIEW_SetItemHeight (hwnd, wParam);
3630 case TVM_GETITEMHEIGHT:
3631 return TREEVIEW_GetItemHeight (hwnd);
3633 case TVM_SETBKCOLOR:
3634 return TREEVIEW_SetBkColor (hwnd, wParam, lParam);
3636 case TVM_SETTEXTCOLOR:
3637 return TREEVIEW_SetTextColor (hwnd, wParam, lParam);
3639 case TVM_GETBKCOLOR:
3640 return TREEVIEW_GetBkColor (hwnd);
3642 case TVM_GETTEXTCOLOR:
3643 return TREEVIEW_GetTextColor (hwnd);
3645 case TVM_SETSCROLLTIME:
3646 return TREEVIEW_SetScrollTime (hwnd, (UINT)wParam);
3648 case TVM_GETSCROLLTIME:
3649 return TREEVIEW_GetScrollTime (hwnd);
3651 case TVM_GETITEMSTATE:
3652 return TREEVIEW_GetItemState (hwnd,wParam, lParam);
3654 case TVM_GETLINECOLOR:
3655 return TREEVIEW_GetLineColor (hwnd,wParam, lParam);
3657 case TVM_SETLINECOLOR:
3658 return TREEVIEW_SetLineColor (hwnd,wParam, lParam);
3660 case TVM_SETINSERTMARKCOLOR:
3661 FIXME("Unimplemented msg TVM_SETINSERTMARKCOLOR\n");
3664 case TVM_SETUNICODEFORMAT:
3665 FIXME("Unimplemented msg TVM_SETUNICODEFORMAT\n");
3668 case TVM_GETUNICODEFORMAT:
3669 FIXME("Unimplemented msg TVM_GETUNICODEFORMAT\n");
3673 return TREEVIEW_Command (hwnd, wParam, lParam);
3676 return TREEVIEW_Create (hwnd, wParam, lParam);
3679 return TREEVIEW_Destroy (hwnd);
3681 /* case WM_ENABLE: */
3684 return TREEVIEW_EraseBackground (hwnd, wParam, lParam);
3687 return DLGC_WANTARROWS | DLGC_WANTCHARS;
3690 return TREEVIEW_Paint (hwnd, wParam, lParam);
3693 return TREEVIEW_GetFont (hwnd, wParam, lParam);
3696 return TREEVIEW_SetFont (hwnd, wParam, lParam);
3699 return TREEVIEW_KeyDown (hwnd, wParam, lParam);
3702 return TREEVIEW_SetFocus (hwnd, wParam, lParam);
3705 return TREEVIEW_KillFocus (hwnd, wParam, lParam);
3707 case WM_LBUTTONDOWN:
3708 return TREEVIEW_LButtonDown (hwnd, wParam, lParam);
3711 return TREEVIEW_LButtonUp (hwnd, wParam, lParam);
3713 case WM_LBUTTONDBLCLK:
3714 return TREEVIEW_LButtonDoubleClick (hwnd, wParam, lParam);
3716 case WM_RBUTTONDOWN:
3717 return TREEVIEW_RButtonDown (hwnd, wParam, lParam);
3720 return TREEVIEW_RButtonUp (hwnd, wParam, lParam);
3723 return TREEVIEW_MouseMove (hwnd, wParam, lParam);
3725 case WM_STYLECHANGED:
3726 return TREEVIEW_StyleChanged (hwnd, wParam, lParam);
3728 /* case WM_SYSCOLORCHANGE: */
3729 /* case WM_SETREDRAW: */
3732 return TREEVIEW_HandleTimer (hwnd, wParam, lParam);
3735 return TREEVIEW_Size (hwnd, wParam,lParam);
3738 return TREEVIEW_HScroll (hwnd, wParam, lParam);
3740 return TREEVIEW_VScroll (hwnd, wParam, lParam);
3743 TRACE ("drawItem\n");
3744 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
3747 if (uMsg >= WM_USER)
3748 FIXME("Unknown msg %04x wp=%08x lp=%08lx\n",
3749 uMsg, wParam, lParam);
3750 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
3757 TREEVIEW_Register (void)
3763 if (GlobalFindAtomA (WC_TREEVIEWA)) return;
3765 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
3766 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
3767 wndClass.lpfnWndProc = (WNDPROC)TREEVIEW_WindowProc;
3768 wndClass.cbClsExtra = 0;
3769 wndClass.cbWndExtra = sizeof(TREEVIEW_INFO *);
3770 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
3771 wndClass.hbrBackground = 0;
3772 wndClass.lpszClassName = WC_TREEVIEWA;
3774 RegisterClassA (&wndClass);
3779 TREEVIEW_Unregister (void)
3781 if (GlobalFindAtomA (WC_TREEVIEWA))
3782 UnregisterClassA (WC_TREEVIEWA, (HINSTANCE)NULL);