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 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) parent=infoPtr->TopRootItem;
1466 /* Check for a valid handle to the parent item */
1467 if (!TREEVIEW_ValidItem(infoPtr, parent))
1469 ERR ("invalid item hParent=%x\n", (INT)parent);
1473 /* Obtain the parent node to sort */
1474 sortMe = &infoPtr->items[ (INT)parent ];
1476 /* Make sure there is something to sort */
1477 if ( sortMe->cChildren > 1 )
1479 /* pointer organization */
1480 HDPA sortList = DPA_Create(sortMe->cChildren);
1481 HTREEITEM itemHandle = sortMe->firstChild;
1482 TREEVIEW_ITEM *itemPtr = & infoPtr->items[ (INT)itemHandle ];
1484 /* TREEVIEW_ITEM rechaining */
1490 /* Build the list of item to sort */
1494 sortList, /* the list */
1495 sortMe->cChildren+1, /* force the insertion to be an append */
1496 itemPtr); /* the ptr to store */
1498 /* Get the next sibling */
1499 itemHandle = itemPtr->sibling;
1500 itemPtr = & infoPtr->items[ (INT)itemHandle ];
1501 } while ( itemHandle != NULL );
1503 /* let DPA perform the sort activity */
1506 sortList, /* what */
1507 TREEVIEW_CallBackCompare, /* how */
1511 sortList, /* what */
1512 TREEVIEW_SortOnName, /* how */
1516 * Reorganized TREEVIEW_ITEM structures.
1517 * Note that we know we have at least two elements.
1520 /* Get the first item and get ready to start... */
1521 item = DPA_GetPtr(sortList, count++);
1522 while ( (nextItem = DPA_GetPtr(sortList, count++)) != NULL )
1524 /* link the two current item toghether */
1525 ((TREEVIEW_ITEM*)item)->sibling = ((TREEVIEW_ITEM*)nextItem)->hItem;
1526 ((TREEVIEW_ITEM*)nextItem)->upsibling = ((TREEVIEW_ITEM*)item)->hItem;
1528 if (prevItem == NULL) /* this is the first item, update the parent */
1530 sortMe->firstChild = ((TREEVIEW_ITEM*)item)->hItem;
1531 ((TREEVIEW_ITEM*)item)->upsibling = NULL;
1533 else /* fix the back chaining */
1535 ((TREEVIEW_ITEM*)item)->upsibling = ((TREEVIEW_ITEM*)prevItem)->hItem;
1538 /* get ready for the next one */
1543 /* the last item is pointed to by item and never has a sibling */
1544 ((TREEVIEW_ITEM*)item)->sibling = NULL;
1546 DPA_Destroy(sortList);
1554 /***************************************************************************
1555 * Setup the treeview structure with regards of the sort method
1556 * and sort the children of the TV item specified in lParam
1558 LRESULT WINAPI TREEVIEW_SortChildrenCB(
1564 LPTVSORTCB pSort=(LPTVSORTCB) lParam;
1566 return TREEVIEW_Sort (hwnd, wParam, pSort->hParent, pSort);
1570 /***************************************************************************
1571 * Sort the children of the TV item specified in lParam.
1573 LRESULT WINAPI TREEVIEW_SortChildren (
1578 return TREEVIEW_Sort (hwnd, (BOOL) wParam, (HTREEITEM) lParam, NULL);
1583 /* the method used below isn't the most memory-friendly, but it avoids
1584 a lot of memory reallocations */
1586 /* BTW: we waste handle 0; 0 is not an allowed handle. */
1589 TREEVIEW_InsertItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1592 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1593 TVINSERTSTRUCTA *ptdi;
1595 TREEVIEW_ITEM *wineItem, *parentItem, *prevsib, *sibItem;
1596 INT iItem,listItems,i,len;
1598 /* Item to insert */
1599 ptdi = (LPTVINSERTSTRUCTA) lParam;
1601 /* check if memory is available */
1603 if (infoPtr->uNumPtrsAlloced==0) {
1604 infoPtr->items = COMCTL32_Alloc (TVITEM_ALLOC*sizeof (TREEVIEW_ITEM));
1605 infoPtr->freeList= COMCTL32_Alloc ((1+(TVITEM_ALLOC>>5)) * sizeof (INT));
1606 infoPtr->uNumPtrsAlloced=TVITEM_ALLOC;
1607 infoPtr->TopRootItem=(HTREEITEM)1;
1611 * Reallocate contiguous space for items
1613 if (infoPtr->uNumItems == (infoPtr->uNumPtrsAlloced-1) ) {
1614 TREEVIEW_ITEM *oldItems = infoPtr->items;
1615 INT *oldfreeList = infoPtr->freeList;
1617 infoPtr->uNumPtrsAlloced*=2;
1618 infoPtr->items = COMCTL32_Alloc (infoPtr->uNumPtrsAlloced*sizeof (TREEVIEW_ITEM));
1619 infoPtr->freeList= COMCTL32_Alloc ((1+(infoPtr->uNumPtrsAlloced>>5))*sizeof (INT));
1621 memcpy (&infoPtr->items[0], &oldItems[0],
1622 infoPtr->uNumPtrsAlloced/2 * sizeof(TREEVIEW_ITEM));
1623 memcpy (&infoPtr->freeList[0], &oldfreeList[0],
1624 (infoPtr->uNumPtrsAlloced>>6) * sizeof(INT));
1626 COMCTL32_Free (oldItems);
1627 COMCTL32_Free (oldfreeList);
1631 * Reset infoPtr structure with new stat according to current TV picture
1634 infoPtr->uNumItems++;
1635 if ((INT)infoPtr->uMaxHandle==(infoPtr->uNumItems-1)) {
1636 iItem=infoPtr->uNumItems;
1637 infoPtr->uMaxHandle = (HTREEITEM)((INT)infoPtr->uMaxHandle + 1);
1638 } else { /* check freelist */
1639 for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++) {
1640 if (infoPtr->freeList[i]) {
1641 iItem=ffs (infoPtr->freeList[i])-1;
1642 tv_clear_bit(iItem,&infoPtr->freeList[i]);
1649 if (TRACE_ON(treeview)) {
1650 for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++)
1651 TRACE("%8x\n",infoPtr->freeList[i]);
1654 if (!iItem) ERR("Argh -- can't find free item.\n");
1657 * Find the parent item of the new item
1659 tvItem= & ptdi->DUMMYUNIONNAME.itemex;
1660 wineItem=& infoPtr->items[iItem];
1662 if ((ptdi->hParent==TVI_ROOT) || (ptdi->hParent==0)) {
1664 wineItem->parent = 0;
1665 sibItem = &infoPtr->items [(INT)infoPtr->TopRootItem];
1666 listItems = infoPtr->uNumItems;
1669 parentItem = &infoPtr->items[(INT)ptdi->hParent];
1671 /* Do the insertion here it if it's the only item of this parent */
1672 if (!parentItem->firstChild)
1673 parentItem->firstChild=(HTREEITEM)iItem;
1675 wineItem->parent = ptdi->hParent;
1676 sibItem = &infoPtr->items [(INT)parentItem->firstChild];
1677 parentItem->cChildren++;
1678 listItems = parentItem->cChildren;
1682 /* NOTE: I am moving some setup of the wineItem object that was initialy
1683 * done at the end of the function since some of the values are
1684 * required by the Callback sorting
1687 if (tvItem->mask & TVIF_TEXT)
1690 * Setup the item text stuff here since it's required by the Sort method
1691 * when the insertion are ordered
1693 if (tvItem->pszText!=LPSTR_TEXTCALLBACKA)
1695 TRACE("(%p,%s)\n", &tvItem->pszText, tvItem->pszText);
1696 len = lstrlenA (tvItem->pszText)+1;
1697 wineItem->pszText= COMCTL32_Alloc (len+1);
1698 lstrcpyA (wineItem->pszText, tvItem->pszText);
1699 wineItem->cchTextMax=len;
1703 TRACE("LPSTR_TEXTCALLBACK\n");
1704 wineItem->pszText = LPSTR_TEXTCALLBACKA;
1705 wineItem->cchTextMax = 0;
1709 if (tvItem->mask & TVIF_PARAM)
1710 wineItem->lParam=tvItem->lParam;
1713 wineItem->upsibling=0; /* needed in case we're the first item in a list */
1714 wineItem->sibling=0;
1715 wineItem->firstChild=0;
1716 wineItem->hItem=(HTREEITEM)iItem;
1721 switch ((DWORD) ptdi->hInsertAfter) {
1722 case (DWORD) TVI_FIRST:
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;
1874 TREEVIEW_InsertItemW(HWND hwnd, WPARAM wParam, LPARAM lParam)
1876 TVINSERTSTRUCTW *tvisW;
1877 TVINSERTSTRUCTA tvisA;
1880 tvisW = (LPTVINSERTSTRUCTW)lParam;
1882 tvisA.hParent = tvisW->hParent;
1883 tvisA.hInsertAfter = tvisW->hInsertAfter;
1885 tvisA.DUMMYUNIONNAME.item.mask = tvisW->DUMMYUNIONNAME.item.mask;
1886 tvisA.DUMMYUNIONNAME.item.hItem = tvisW->DUMMYUNIONNAME.item.hItem;
1887 tvisA.DUMMYUNIONNAME.item.state = tvisW->DUMMYUNIONNAME.item.state;
1888 tvisA.DUMMYUNIONNAME.item.stateMask = tvisW->DUMMYUNIONNAME.item.stateMask;
1889 tvisA.DUMMYUNIONNAME.item.cchTextMax = tvisW->DUMMYUNIONNAME.item.cchTextMax;
1891 if(tvisW->DUMMYUNIONNAME.item.pszText)
1893 if (tvisW->DUMMYUNIONNAME.item.pszText!=LPSTR_TEXTCALLBACKW)
1895 int len = lstrlenW (tvisW->DUMMYUNIONNAME.item.pszText)+1;
1896 tvisA.DUMMYUNIONNAME.item.pszText = COMCTL32_Alloc (len);
1897 lstrcpyWtoA (tvisA.DUMMYUNIONNAME.item.pszText,
1898 tvisW->DUMMYUNIONNAME.item.pszText );
1902 tvisA.DUMMYUNIONNAME.item.pszText = LPSTR_TEXTCALLBACKA;
1903 tvisA.DUMMYUNIONNAME.item.cchTextMax = 0;
1907 tvisA.DUMMYUNIONNAME.item.iImage = tvisW->DUMMYUNIONNAME.item.iImage;
1908 tvisA.DUMMYUNIONNAME.item.iSelectedImage = tvisW->DUMMYUNIONNAME.item.iSelectedImage;
1909 tvisA.DUMMYUNIONNAME.item.cChildren = tvisW->DUMMYUNIONNAME.item.cChildren;
1910 tvisA.DUMMYUNIONNAME.item.lParam = tvisW->DUMMYUNIONNAME.item.lParam;
1912 lRes = TREEVIEW_InsertItemA(hwnd,wParam,(LPARAM)&tvisA);
1914 if (tvisA.DUMMYUNIONNAME.item.pszText!=LPSTR_TEXTCALLBACKA)
1916 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;
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;
2181 infoPtr->hwndNotify = GetParent32 (hwnd);
2182 infoPtr->bTransparent = ( GetWindowLongA( hwnd, GWL_STYLE) & TBSTYLE_FLAT);
2185 infoPtr->hwndToolTip=0;
2186 if (!( GetWindowLongA( hwnd, GWL_STYLE) & TVS_NOTOOLTIPS)) { /* Create tooltip control */
2189 infoPtr->hwndToolTip =
2190 CreateWindowExA (0, TOOLTIPS_CLASSA, NULL, 0,
2191 CW_USEDEFAULT, CW_USEDEFAULT,
2192 CW_USEDEFAULT, CW_USEDEFAULT,
2195 /* Send NM_TOOLTIPSCREATED notification */
2196 if (infoPtr->hwndToolTip) {
2197 NMTOOLTIPSCREATED nmttc;
2199 nmttc.hdr.hwndFrom = hwnd;
2200 nmttc.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2201 nmttc.hdr.code = NM_TOOLTIPSCREATED;
2202 nmttc.hwndToolTips = infoPtr->hwndToolTip;
2204 SendMessageA (GetParent (hwnd), WM_NOTIFY,
2205 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmttc);
2208 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
2209 ti.cbSize = sizeof(TTTOOLINFOA);
2210 ti.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_TRANSPARENT ;
2213 ti.lpszText = "Test"; /* LPSTR_TEXTCALLBACK; */
2214 SetRectEmpty (&ti.rect);
2216 SendMessageA (infoPtr->hwndToolTip, TTM_ADDTOOLA, 0, (LPARAM)&ti);
2219 infoPtr->hwndEdit = CreateWindowExA (
2223 WS_CHILD | WS_BORDER | ES_AUTOHSCROLL |
2224 ES_WANTRETURN | ES_LEFT,
2227 0,0,0); /* FIXME: (HMENU)IDTVEDIT,pcs->hInstance,0);*/
2229 SendMessageA ( infoPtr->hwndEdit, WM_SETFONT, infoPtr->hFont, FALSE);
2230 infoPtr->wpEditOrig = (WNDPROC)SetWindowLongA (
2233 (LONG) TREEVIEW_Edit_SubclassProc);
2235 ReleaseDC (hwnd, hdc);
2242 TREEVIEW_Destroy (HWND hwnd)
2244 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2247 TREEVIEW_RemoveTree (hwnd);
2248 if (infoPtr->Timer & TV_REFRESH_TIMER_SET)
2249 KillTimer (hwnd, TV_REFRESH_TIMER);
2250 if (infoPtr->hwndToolTip)
2251 DestroyWindow (infoPtr->hwndToolTip);
2253 COMCTL32_Free (infoPtr);
2259 TREEVIEW_Paint (HWND hwnd, WPARAM wParam, LPARAM lParam)
2265 hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
2266 TREEVIEW_Refresh (hwnd);
2268 EndPaint (hwnd, &ps);
2271 return DefWindowProcA (hwnd, WM_PAINT, wParam, lParam);
2275 TREEVIEW_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2277 TREEVIEW_SendSimpleNotify (hwnd, NM_SETFOCUS);
2278 InvalidateRect(hwnd, NULL, FALSE);
2283 TREEVIEW_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2285 TREEVIEW_SendSimpleNotify (hwnd, NM_KILLFOCUS);
2286 InvalidateRect(hwnd, NULL, FALSE);
2291 TREEVIEW_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
2293 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2294 HBRUSH hBrush = CreateSolidBrush (infoPtr->clrBk);
2298 GetClientRect (hwnd, &rect);
2299 FillRect ((HDC)wParam, &rect, hBrush);
2300 DeleteObject (hBrush);
2316 TREEVIEW_SendSimpleNotify (HWND hwnd, UINT code)
2321 nmhdr.hwndFrom = hwnd;
2322 nmhdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2325 return (BOOL) SendMessageA (GetParent (hwnd), WM_NOTIFY,
2326 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
2332 TREEVIEW_SendTreeviewNotify (HWND hwnd, UINT code, UINT action,
2333 HTREEITEM oldItem, HTREEITEM newItem)
2336 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2338 TREEVIEW_ITEM *wineItem;
2340 TRACE("code:%x action:%x olditem:%x newitem:%x\n",
2341 code,action,(INT)oldItem,(INT)newItem);
2342 nmhdr.hdr.hwndFrom = hwnd;
2343 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2344 nmhdr.hdr.code = code;
2345 nmhdr.action = action;
2347 wineItem=& infoPtr->items[(INT)oldItem];
2348 nmhdr.itemOld.mask = wineItem->mask;
2349 nmhdr.itemOld.hItem = wineItem->hItem;
2350 nmhdr.itemOld.state = wineItem->state;
2351 nmhdr.itemOld.stateMask = wineItem->stateMask;
2352 nmhdr.itemOld.iImage = wineItem->iImage;
2353 nmhdr.itemOld.pszText = wineItem->pszText;
2354 nmhdr.itemOld.cchTextMax= wineItem->cchTextMax;
2355 nmhdr.itemOld.iImage = wineItem->iImage;
2356 nmhdr.itemOld.iSelectedImage = wineItem->iSelectedImage;
2357 nmhdr.itemOld.cChildren = wineItem->cChildren;
2358 nmhdr.itemOld.lParam = wineItem->lParam;
2362 wineItem=& infoPtr->items[(INT)newItem];
2363 nmhdr.itemNew.mask = wineItem->mask;
2364 nmhdr.itemNew.hItem = wineItem->hItem;
2365 nmhdr.itemNew.state = wineItem->state;
2366 nmhdr.itemNew.stateMask = wineItem->stateMask;
2367 nmhdr.itemNew.iImage = wineItem->iImage;
2368 nmhdr.itemNew.pszText = wineItem->pszText;
2369 nmhdr.itemNew.cchTextMax= wineItem->cchTextMax;
2370 nmhdr.itemNew.iImage = wineItem->iImage;
2371 nmhdr.itemNew.iSelectedImage = wineItem->iSelectedImage;
2372 nmhdr.itemNew.cChildren = wineItem->cChildren;
2373 nmhdr.itemNew.lParam = wineItem->lParam;
2379 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2380 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2385 TREEVIEW_SendTreeviewDnDNotify (HWND hwnd, UINT code, HTREEITEM dragItem,
2388 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2390 TREEVIEW_ITEM *wineItem;
2392 TRACE("code:%x dragitem:%x\n", code,(INT)dragItem);
2394 nmhdr.hdr.hwndFrom = hwnd;
2395 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2396 nmhdr.hdr.code = code;
2398 wineItem=& infoPtr->items[(INT)dragItem];
2399 nmhdr.itemNew.mask = wineItem->mask;
2400 nmhdr.itemNew.hItem = wineItem->hItem;
2401 nmhdr.itemNew.state = wineItem->state;
2402 nmhdr.itemNew.lParam = wineItem->lParam;
2404 nmhdr.ptDrag.x = pt.x;
2405 nmhdr.ptDrag.y = pt.y;
2407 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2408 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2415 TREEVIEW_SendDispInfoNotify (HWND hwnd, TREEVIEW_ITEM *wineItem,
2416 UINT code, UINT what)
2422 TRACE("item %d, action %x, state %d\n",
2423 (INT)wineItem->hItem,
2425 (INT)wineItem->state);
2427 tvdi.hdr.hwndFrom = hwnd;
2428 tvdi.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2429 tvdi.hdr.code = code;
2430 tvdi.item.mask = what;
2431 tvdi.item.hItem = wineItem->hItem;
2432 tvdi.item.state = wineItem->state;
2433 tvdi.item.lParam = wineItem->lParam;
2434 tvdi.item.pszText = COMCTL32_Alloc (128*sizeof(char));
2435 buf = tvdi.item.pszText;
2437 retval=(BOOL)SendMessageA (
2440 (WPARAM)tvdi.hdr.idFrom,
2443 if (what & TVIF_TEXT) {
2444 wineItem->pszText = tvdi.item.pszText;
2445 if (buf==tvdi.item.pszText) {
2446 wineItem->cchTextMax = 128;
2448 TRACE("user-supplied buffer\n");
2449 COMCTL32_Free (buf);
2450 wineItem->cchTextMax = 0;
2453 if (what & TVIF_SELECTEDIMAGE)
2454 wineItem->iSelectedImage = tvdi.item.iSelectedImage;
2455 if (what & TVIF_IMAGE)
2456 wineItem->iImage = tvdi.item.iImage;
2457 if (what & TVIF_CHILDREN)
2458 wineItem->cChildren = tvdi.item.cChildren;
2466 TREEVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
2469 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2470 NMTVCUSTOMDRAW nmcdhdr;
2471 LPNMCUSTOMDRAW nmcd;
2473 TRACE("drawstage:%lx hdc:%x\n", dwDrawStage, hdc);
2475 nmcd= & nmcdhdr.nmcd;
2476 nmcd->hdr.hwndFrom = hwnd;
2477 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2478 nmcd->hdr.code = NM_CUSTOMDRAW;
2479 nmcd->dwDrawStage= dwDrawStage;
2481 nmcd->rc.left = rc.left;
2482 nmcd->rc.right = rc.right;
2483 nmcd->rc.bottom = rc.bottom;
2484 nmcd->rc.top = rc.top;
2485 nmcd->dwItemSpec = 0;
2486 nmcd->uItemState = 0;
2487 nmcd->lItemlParam= 0;
2488 nmcdhdr.clrText = infoPtr->clrText;
2489 nmcdhdr.clrTextBk= infoPtr->clrBk;
2492 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2493 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2499 /* FIXME: need to find out when the flags in uItemState need to be set */
2502 TREEVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
2503 TREEVIEW_ITEM *wineItem, UINT uItemDrawState)
2505 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2506 NMTVCUSTOMDRAW nmcdhdr;
2507 LPNMCUSTOMDRAW nmcd;
2508 DWORD dwDrawStage,dwItemSpec;
2511 dwDrawStage=CDDS_ITEM | uItemDrawState;
2512 dwItemSpec=(DWORD)wineItem->hItem;
2514 if (wineItem->hItem==infoPtr->selectedItem) uItemState|=CDIS_SELECTED;
2515 if (wineItem->hItem==infoPtr->focusItem) uItemState|=CDIS_FOCUS;
2516 if (wineItem->hItem==infoPtr->hotItem) uItemState|=CDIS_HOT;
2518 nmcd= & nmcdhdr.nmcd;
2519 nmcd->hdr.hwndFrom = hwnd;
2520 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2521 nmcd->hdr.code = NM_CUSTOMDRAW;
2522 nmcd->dwDrawStage= dwDrawStage;
2524 nmcd->rc.left = wineItem->rect.left;
2525 nmcd->rc.right = wineItem->rect.right;
2526 nmcd->rc.bottom = wineItem->rect.bottom;
2527 nmcd->rc.top = wineItem->rect.top;
2528 nmcd->dwItemSpec = dwItemSpec;
2529 nmcd->uItemState = uItemState;
2530 nmcd->lItemlParam= wineItem->lParam;
2532 nmcdhdr.clrText = infoPtr->clrText;
2533 nmcdhdr.clrTextBk= infoPtr->clrBk;
2534 nmcdhdr.iLevel = wineItem->iLevel;
2536 TRACE("drawstage:%lx hdc:%x item:%lx, itemstate:%x\n",
2537 dwDrawStage, hdc, dwItemSpec, uItemState);
2539 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2540 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2545 /* Note:If the specified item is the child of a collapsed parent item,
2546 the parent's list of child items is (recursively) expanded to reveal the
2547 specified item. This is mentioned for TREEVIEW_SelectItem; don't
2548 know if it also applies here.
2552 TREEVIEW_Expand (HWND hwnd, WPARAM wParam, LPARAM lParam)
2554 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2555 TREEVIEW_ITEM *wineItem;
2559 flag = (UINT) wParam;
2560 expand = (INT) lParam;
2562 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2566 if (!wineItem->cChildren)
2569 if (wineItem->pszText==LPSTR_TEXTCALLBACKA)
2570 TRACE ("For item %d, flags %d, state %d\n",
2571 expand, flag, wineItem->state);
2573 TRACE("For (%s) item:%d, flags %x, state:%d\n",
2574 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_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3505 case TVM_INSERTITEMA:
3506 return TREEVIEW_InsertItemA (hwnd, wParam, lParam);
3508 case TVM_INSERTITEMW:
3509 return TREEVIEW_InsertItemW(hwnd,wParam,lParam);;
3511 case TVM_DELETEITEM:
3512 return TREEVIEW_DeleteItem (hwnd, wParam, lParam);
3515 return TREEVIEW_Expand (hwnd, wParam, lParam);
3517 case TVM_GETITEMRECT:
3518 return TREEVIEW_GetItemRect (hwnd, wParam, lParam);
3521 return TREEVIEW_GetCount (hwnd, wParam, lParam);
3524 return TREEVIEW_GetIndent (hwnd);
3527 return TREEVIEW_SetIndent (hwnd, wParam);
3529 case TVM_GETIMAGELIST:
3530 return TREEVIEW_GetImageList (hwnd, wParam, lParam);
3532 case TVM_SETIMAGELIST:
3533 return TREEVIEW_SetImageList (hwnd, wParam, lParam);
3535 case TVM_GETNEXTITEM:
3536 return TREEVIEW_GetNextItem (hwnd, wParam, lParam);
3538 case TVM_SELECTITEM:
3539 return TREEVIEW_SelectItem (hwnd, wParam, lParam);
3542 return TREEVIEW_GetItemA (hwnd, wParam, lParam);
3545 FIXME("Unimplemented msg TVM_GETITEM32W\n");
3549 return TREEVIEW_SetItemA (hwnd, wParam, lParam);
3552 FIXME("Unimplemented msg TVM_SETITEMW\n");
3555 case TVM_EDITLABELA:
3556 FIXME("Unimplemented msg TVM_EDITLABEL32A \n");
3559 case TVM_EDITLABELW:
3560 FIXME("Unimplemented msg TVM_EDITLABEL32W \n");
3563 case TVM_GETEDITCONTROL:
3564 return TREEVIEW_GetEditControl (hwnd);
3566 case TVM_GETVISIBLECOUNT:
3567 return TREEVIEW_GetVisibleCount (hwnd, wParam, lParam);
3570 return TREEVIEW_HitTest (hwnd, lParam);
3572 case TVM_CREATEDRAGIMAGE:
3573 return TREEVIEW_CreateDragImage (hwnd, wParam, lParam);
3575 case TVM_SORTCHILDREN:
3576 return TREEVIEW_SortChildren (hwnd, wParam, lParam);
3578 case TVM_ENSUREVISIBLE:
3579 FIXME("Unimplemented msg TVM_ENSUREVISIBLE\n");
3582 case TVM_SORTCHILDRENCB:
3583 return TREEVIEW_SortChildrenCB(hwnd, wParam, lParam);
3585 case TVM_ENDEDITLABELNOW:
3586 return TREEVIEW_EndEditLabelNow (hwnd, wParam, lParam);
3588 case TVM_GETISEARCHSTRINGA:
3589 FIXME("Unimplemented msg TVM_GETISEARCHSTRING32A\n");
3592 case TVM_GETISEARCHSTRINGW:
3593 FIXME("Unimplemented msg TVM_GETISEARCHSTRING32W\n");
3596 case TVM_GETTOOLTIPS:
3597 return TREEVIEW_GetToolTips (hwnd);
3599 case TVM_SETTOOLTIPS:
3600 return TREEVIEW_SetToolTips (hwnd, wParam);
3602 case TVM_SETINSERTMARK:
3603 FIXME("Unimplemented msg TVM_SETINSERTMARK\n");
3606 case TVM_SETITEMHEIGHT:
3607 return TREEVIEW_SetItemHeight (hwnd, wParam);
3609 case TVM_GETITEMHEIGHT:
3610 return TREEVIEW_GetItemHeight (hwnd);
3612 case TVM_SETBKCOLOR:
3613 return TREEVIEW_SetBkColor (hwnd, wParam, lParam);
3615 case TVM_SETTEXTCOLOR:
3616 return TREEVIEW_SetTextColor (hwnd, wParam, lParam);
3618 case TVM_GETBKCOLOR:
3619 return TREEVIEW_GetBkColor (hwnd);
3621 case TVM_GETTEXTCOLOR:
3622 return TREEVIEW_GetTextColor (hwnd);
3624 case TVM_SETSCROLLTIME:
3625 FIXME("Unimplemented msg TVM_SETSCROLLTIME\n");
3628 case TVM_GETSCROLLTIME:
3629 FIXME("Unimplemented msg TVM_GETSCROLLTIME\n");
3632 case TVM_GETITEMSTATE:
3633 return TREEVIEW_GetItemState (hwnd,wParam, lParam);
3635 case TVM_GETLINECOLOR:
3636 return TREEVIEW_GetLineColor (hwnd,wParam, lParam);
3638 case TVM_SETLINECOLOR:
3639 return TREEVIEW_SetLineColor (hwnd,wParam, lParam);
3641 case TVM_SETINSERTMARKCOLOR:
3642 FIXME("Unimplemented msg TVM_SETINSERTMARKCOLOR\n");
3645 case TVM_SETUNICODEFORMAT:
3646 FIXME("Unimplemented msg TVM_SETUNICODEFORMAT\n");
3649 case TVM_GETUNICODEFORMAT:
3650 FIXME("Unimplemented msg TVM_GETUNICODEFORMAT\n");
3654 return TREEVIEW_Command (hwnd, wParam, lParam);
3657 return TREEVIEW_Create (hwnd, wParam, lParam);
3660 return TREEVIEW_Destroy (hwnd);
3662 /* case WM_ENABLE: */
3665 return TREEVIEW_EraseBackground (hwnd, wParam, lParam);
3668 return DLGC_WANTARROWS | DLGC_WANTCHARS;
3671 return TREEVIEW_Paint (hwnd, wParam, lParam);
3674 return TREEVIEW_GetFont (hwnd, wParam, lParam);
3677 return TREEVIEW_SetFont (hwnd, wParam, lParam);
3680 return TREEVIEW_KeyDown (hwnd, wParam, lParam);
3683 return TREEVIEW_SetFocus (hwnd, wParam, lParam);
3686 return TREEVIEW_KillFocus (hwnd, wParam, lParam);
3688 case WM_LBUTTONDOWN:
3689 return TREEVIEW_LButtonDown (hwnd, wParam, lParam);
3692 return TREEVIEW_LButtonUp (hwnd, wParam, lParam);
3694 case WM_LBUTTONDBLCLK:
3695 return TREEVIEW_LButtonDoubleClick (hwnd, wParam, lParam);
3697 case WM_RBUTTONDOWN:
3698 return TREEVIEW_RButtonDown (hwnd, wParam, lParam);
3701 return TREEVIEW_RButtonUp (hwnd, wParam, lParam);
3704 return TREEVIEW_MouseMove (hwnd, wParam, lParam);
3706 case WM_STYLECHANGED:
3707 return TREEVIEW_StyleChanged (hwnd, wParam, lParam);
3709 /* case WM_SYSCOLORCHANGE: */
3710 /* case WM_SETREDRAW: */
3713 return TREEVIEW_HandleTimer (hwnd, wParam, lParam);
3716 return TREEVIEW_Size (hwnd, wParam,lParam);
3719 return TREEVIEW_HScroll (hwnd, wParam, lParam);
3721 return TREEVIEW_VScroll (hwnd, wParam, lParam);
3724 TRACE ("drawItem\n");
3725 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
3728 if (uMsg >= WM_USER)
3729 FIXME("Unknown msg %04x wp=%08x lp=%08lx\n",
3730 uMsg, wParam, lParam);
3731 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
3738 TREEVIEW_Register (void)
3744 if (GlobalFindAtomA (WC_TREEVIEWA)) return;
3746 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
3747 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
3748 wndClass.lpfnWndProc = (WNDPROC)TREEVIEW_WindowProc;
3749 wndClass.cbClsExtra = 0;
3750 wndClass.cbWndExtra = sizeof(TREEVIEW_INFO *);
3751 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
3752 wndClass.hbrBackground = 0;
3753 wndClass.lpszClassName = WC_TREEVIEWA;
3755 RegisterClassA (&wndClass);
3760 TREEVIEW_Unregister (void)
3762 if (GlobalFindAtomA (WC_TREEVIEWA))
3763 UnregisterClassA (WC_TREEVIEWA, (HINSTANCE)NULL);