3 * Copyright 1998 Eric Kohl <ekohl@abo.rhein-zeitung.de>
4 * Copyright 1998,1999 Alex Priem <alexp@sci.kun.nl>
5 * Copyright 1999 Sylvain St-Germain
9 * Using DPA to store the item ptr would be good.
10 * Node label edition is implemented but something appened in wine in the
11 * two last weeks of march 99 that broke it.
13 -small array containing info about positions.
14 -better implementation of RefreshItem:
15 1) draw lines between parents
17 3) draw lines from parent<->items.
18 -implement partial drawing?
19 * -drag&drop: TVM_CREATEDRAGIMAGE should create drag bitmap.
20 * -scrollbars: horizontal scrollbar doesn't work.
24 * FIXME: check fontsize. (uRealItemHeight)
25 * test focusItem (redraw in different color)
28 better implementation.
29 * WM_HSCROLL is broken.
30 * use separate routine to get item text/image.
32 * Separate drawing/calculation.
34 * FIXMEs (for personal use)
35 Expand: -ctlmacro expands twice ->toggle.
36 -DblClick: ctlmacro.exe's NM_DBLCLK seems to go wrong (returns FALSE).
37 -treehelper: stack corruption makes big window.
48 #include "debugtools.h"
50 DEFAULT_DEBUG_CHANNEL(treeview
)
52 /* ffs should be in <string.h>. */
54 /* Defines, since they do not need to return previous state, and nr
55 * has no side effects in this file.
57 #define tv_test_bit(nr,bf) (((LPBYTE)bf)[nr>>3]&(1<<(nr&7)))
58 #define tv_set_bit(nr,bf) ((LPBYTE)bf)[nr>>3]|=(1<<(nr&7))
59 #define tv_clear_bit(nr,bf) ((LPBYTE)bf)[nr>>3]&=~(1<<(nr&7))
62 #define TREEVIEW_GetInfoPtr(hwnd) \
63 ((TREEVIEW_INFO *) GetWindowLongA( hwnd, 0))
66 TREEVIEW_SendSimpleNotify (HWND hwnd
, UINT code
);
68 TREEVIEW_SendTreeviewNotify (HWND hwnd
, UINT code
, UINT action
,
69 HTREEITEM oldItem
, HTREEITEM newItem
);
71 TREEVIEW_SendTreeviewDnDNotify (HWND hwnd
, UINT code
, HTREEITEM dragItem
,
74 TREEVIEW_SendDispInfoNotify (HWND hwnd
, TREEVIEW_ITEM
*wineItem
,
75 UINT code
, UINT what
);
77 TREEVIEW_SendCustomDrawNotify (HWND hwnd
, DWORD dwDrawStage
, HDC hdc
,
80 TREEVIEW_SendCustomDrawItemNotify (HWND hwnd
, HDC hdc
,
81 TREEVIEW_ITEM
*tvItem
, UINT uItemDrawState
);
83 TREEVIEW_DoSelectItem (HWND hwnd
, INT action
, HTREEITEM newSelect
, INT cause
);
85 TREEVIEW_Refresh (HWND hwnd
, HDC hdc
);
87 static LRESULT CALLBACK
88 TREEVIEW_Edit_SubclassProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
,
92 TREEVIEW_EndEditLabelNow (HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
97 /* helper functions. Work with the assumption that validity of operands
98 is checked beforehand, and that tree state is valid. */
100 /* FIXME: MS documentation says `GetNextVisibleItem' returns NULL
101 if not successfull. Probably only applies to dereferencing infoPtr
102 (i.e. we are offered a valid treeview structure)
103 and not whether there is a next `visible' child.
104 FIXME: check other failures.
107 /***************************************************************************
108 * This method returns the TREEVIEW_ITEM object given the handle
110 static TREEVIEW_ITEM
* TREEVIEW_ValidItem(
111 TREEVIEW_INFO
*infoPtr
,
114 if ((!handle
) || (handle
>infoPtr
->uMaxHandle
))
117 if (tv_test_bit ((INT
)handle
, infoPtr
->freeList
))
120 return &infoPtr
->items
[(INT
)handle
];
123 /***************************************************************************
124 * This method returns the last expanded child item of a tree node
126 static TREEVIEW_ITEM
*TREEVIEW_GetLastListItem(
127 TREEVIEW_INFO
*infoPtr
,
128 TREEVIEW_ITEM
*tvItem
)
130 TREEVIEW_ITEM
*wineItem
= tvItem
;
133 * Get this item last sibling
135 while (wineItem
->sibling
)
136 wineItem
=& infoPtr
->items
[(INT
)wineItem
->sibling
];
139 * If the last sibling has expanded children, restart.
141 if ( ( wineItem
->cChildren
> 0 ) && ( wineItem
->state
& TVIS_EXPANDED
) )
142 return TREEVIEW_GetLastListItem(
144 &(infoPtr
->items
[(INT
)wineItem
->firstChild
]));
149 /***************************************************************************
150 * This method returns the previous physical item in the list not
151 * considering the tree hierarchy.
153 static TREEVIEW_ITEM
*TREEVIEW_GetPrevListItem(
154 TREEVIEW_INFO
*infoPtr
,
155 TREEVIEW_ITEM
*tvItem
)
157 if (tvItem
->upsibling
)
160 * This item has a upsibling, get the last item. Since, GetLastListItem
161 * first looks at siblings, we must feed it with the first child.
163 TREEVIEW_ITEM
*upItem
= &infoPtr
->items
[(INT
)tvItem
->upsibling
];
165 if ( ( upItem
->cChildren
> 0 ) && ( upItem
->state
& TVIS_EXPANDED
) )
166 return TREEVIEW_GetLastListItem(
168 &infoPtr
->items
[(INT
)upItem
->firstChild
]);
175 * this item does not have a upsibling, get the parent
178 return &infoPtr
->items
[(INT
)tvItem
->parent
];
185 /***************************************************************************
186 * This method returns the next physical item in the treeview not
187 * considering the tree hierarchy.
189 static TREEVIEW_ITEM
*TREEVIEW_GetNextListItem(
190 TREEVIEW_INFO
*infoPtr
,
191 TREEVIEW_ITEM
*tvItem
)
193 TREEVIEW_ITEM
*wineItem
= NULL
;
196 * If this item has children and is expanded, return the first child
198 if ((tvItem
->firstChild
) && (tvItem
->state
& TVIS_EXPANDED
))
199 return (& infoPtr
->items
[(INT
)tvItem
->firstChild
]);
203 * try to get the sibling
206 return (& infoPtr
->items
[(INT
)tvItem
->sibling
]);
209 * Otherwise, get the parent's sibling.
212 while (wineItem
->parent
) {
213 wineItem
=& infoPtr
->items
[(INT
)wineItem
->parent
];
214 if (wineItem
->sibling
)
215 return (& infoPtr
->items
[(INT
)wineItem
->sibling
]);
221 /***************************************************************************
222 * This method returns the nth item starting at the given item. It returns
223 * the last item (or first) we we run out of items.
225 * Will scroll backward if count is <0.
226 * forward if count is >0.
228 static TREEVIEW_ITEM
*TREEVIEW_GetListItem(
229 TREEVIEW_INFO
*infoPtr
,
230 TREEVIEW_ITEM
*tvItem
,
233 TREEVIEW_ITEM
*previousItem
= NULL
;
234 TREEVIEW_ITEM
*wineItem
= tvItem
;
239 /* Find count item downward */
240 while ((iter
++ < count
) && (wineItem
!= NULL
))
242 /* Keep a pointer to the previous in case we ask for more than we got */
243 previousItem
= wineItem
;
244 wineItem
= TREEVIEW_GetNextListItem(infoPtr
, wineItem
);
247 if (wineItem
== NULL
)
248 wineItem
= previousItem
;
252 /* Find count item upward */
253 while ((iter
-- > count
) && (wineItem
!= NULL
))
255 /* Keep a pointer to the previous in case we ask for more than we got */
256 previousItem
= wineItem
;
257 wineItem
= TREEVIEW_GetPrevListItem(infoPtr
, wineItem
);
260 if (wineItem
== NULL
)
261 wineItem
= previousItem
;
270 /***************************************************************************
273 static void TREEVIEW_RemoveAllChildren(
275 TREEVIEW_ITEM
*parentItem
)
277 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
278 TREEVIEW_ITEM
*killItem
;
281 kill
=(INT
)parentItem
->firstChild
;
283 tv_set_bit ( kill
, infoPtr
->freeList
);
284 killItem
=& infoPtr
->items
[kill
];
285 if (killItem
->pszText
!=LPSTR_TEXTCALLBACKA
)
286 COMCTL32_Free (killItem
->pszText
);
287 TREEVIEW_SendTreeviewNotify (hwnd
, TVN_DELETEITEMA
, 0, (HTREEITEM
)kill
, 0);
288 if (killItem
->firstChild
)
289 TREEVIEW_RemoveAllChildren (hwnd
, killItem
);
290 kill
=(INT
)killItem
->sibling
;
293 if (parentItem
->cChildren
>0) {
294 infoPtr
->uNumItems
-= parentItem
->cChildren
;
295 parentItem
->firstChild
= 0;
296 parentItem
->cChildren
= 0;
303 TREEVIEW_RemoveItem (HWND hwnd
, TREEVIEW_ITEM
*wineItem
)
306 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
307 TREEVIEW_ITEM
*parentItem
, *upsiblingItem
, *siblingItem
;
310 iItem
=(INT
)wineItem
->hItem
;
311 tv_set_bit(iItem
,infoPtr
->freeList
);
312 infoPtr
->uNumItems
--;
314 if (wineItem
->pszText
!=LPSTR_TEXTCALLBACKA
)
315 COMCTL32_Free (wineItem
->pszText
);
317 TREEVIEW_SendTreeviewNotify (hwnd
, TVN_DELETEITEMA
, 0, (HTREEITEM
)iItem
, 0);
319 if (wineItem
->firstChild
)
320 TREEVIEW_RemoveAllChildren (hwnd
,wineItem
);
322 if (wineItem
->parent
) {
323 parentItem
=& infoPtr
->items
[(INT
)wineItem
->parent
];
324 switch (parentItem
->cChildren
) {
325 case I_CHILDRENCALLBACK
:
326 FIXME("we don't handle I_CHILDRENCALLBACK yet\n");
329 parentItem
->cChildren
=0;
330 parentItem
->firstChild
=0;
333 parentItem
->cChildren
--;
334 if ((INT
)parentItem
->firstChild
==iItem
)
335 parentItem
->firstChild
=wineItem
->sibling
;
339 if (iItem
==(INT
)infoPtr
->TopRootItem
)
340 infoPtr
->TopRootItem
=(HTREEITEM
)wineItem
->sibling
;
341 if (wineItem
->upsibling
) {
342 upsiblingItem
=& infoPtr
->items
[(INT
)wineItem
->upsibling
];
343 upsiblingItem
->sibling
=wineItem
->sibling
;
345 if (wineItem
->sibling
) {
346 siblingItem
=& infoPtr
->items
[(INT
)wineItem
->sibling
];
347 siblingItem
->upsibling
=wineItem
->upsibling
;
355 /* Note:TREEVIEW_RemoveTree doesn't remove infoPtr itself */
357 static void TREEVIEW_RemoveTree (HWND hwnd
)
360 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
361 TREEVIEW_ITEM
*killItem
;
364 for (i
= 1; i
<= (INT
)infoPtr
->uMaxHandle
; i
++)
365 if (!tv_test_bit (i
, infoPtr
->freeList
)) {
366 killItem
= &infoPtr
->items
[i
];
367 if (killItem
->pszText
!= LPSTR_TEXTCALLBACKA
)
368 COMCTL32_Free (killItem
->pszText
);
369 TREEVIEW_SendTreeviewNotify(hwnd
, TVN_DELETEITEMA
, 0,
372 if (infoPtr
->uNumPtrsAlloced
) {
373 COMCTL32_Free (infoPtr
->items
);
374 COMCTL32_Free (infoPtr
->freeList
);
375 infoPtr
->uNumItems
= 0;
376 infoPtr
->uNumPtrsAlloced
= 0;
377 infoPtr
->uMaxHandle
= 0;
378 infoPtr
->TopRootItem
= 0;
389 TREEVIEW_GetImageList (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
391 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
395 if ((INT
)wParam
== TVSIL_NORMAL
)
396 return (LRESULT
) infoPtr
->himlNormal
;
397 if ((INT
)wParam
== TVSIL_STATE
)
398 return (LRESULT
) infoPtr
->himlState
;
404 TREEVIEW_SetImageList (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
406 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
409 TRACE("%x,%lx\n", wParam
, lParam
);
410 switch ((INT
)wParam
) {
412 himlTemp
= infoPtr
->himlNormal
;
413 infoPtr
->himlNormal
= (HIMAGELIST
)lParam
;
414 return (LRESULT
)himlTemp
;
417 himlTemp
= infoPtr
->himlState
;
418 infoPtr
->himlState
= (HIMAGELIST
)lParam
;
419 return (LRESULT
)himlTemp
;
422 return (LRESULT
)NULL
;
428 TREEVIEW_SetItemHeight (HWND hwnd
, WPARAM wParam
)
430 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
431 INT cx
,cy
,prevHeight
=infoPtr
->uItemHeight
;
435 infoPtr
->uItemHeight
=-1;
439 ImageList_GetIconSize (infoPtr
->himlNormal
, &cx
, &cy
);
441 if (wParam
>cy
) cy
=wParam
;
442 infoPtr
->uItemHeight
=cy
;
444 if (!( GetWindowLongA( hwnd
, GWL_STYLE
) & TVS_NONEVENHEIGHT
))
445 infoPtr
->uItemHeight
= (INT
) wParam
& 0xfffffffe;
450 TREEVIEW_GetItemHeight (HWND hwnd
)
452 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
455 return infoPtr
->uItemHeight
;
459 TREEVIEW_GetLineColor (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
461 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
464 return (LRESULT
) infoPtr
->clrLine
;
468 TREEVIEW_SetLineColor (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
470 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
471 COLORREF prevColor
=infoPtr
->clrLine
;
474 infoPtr
->clrLine
=(COLORREF
) lParam
;
475 return (LRESULT
) prevColor
;
479 TREEVIEW_GetInsertMarkColor (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
481 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
484 return (LRESULT
) infoPtr
->clrInsertMark
;
488 TREEVIEW_SetInsertMarkColor (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
490 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
491 COLORREF prevColor
=infoPtr
->clrInsertMark
;
493 TRACE("%d %ld\n",wParam
,lParam
);
494 infoPtr
->clrInsertMark
=(COLORREF
) lParam
;
495 return (LRESULT
) prevColor
;
499 TREEVIEW_SetInsertMark (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
501 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
504 FIXME("%d %ld\n",wParam
,lParam
);
505 if (!TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)lParam
)) return 0;
506 FIXME("%d %ld\n",wParam
,lParam
);
508 infoPtr
->insertBeforeorAfter
=(BOOL
) wParam
;
509 infoPtr
->insertMarkItem
=(HTREEITEM
) lParam
;
512 TREEVIEW_Refresh (hwnd
, hdc
);
519 TREEVIEW_SetTextColor (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
521 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
522 COLORREF prevColor
=infoPtr
->clrText
;
525 infoPtr
->clrText
=(COLORREF
) lParam
;
526 return (LRESULT
) prevColor
;
530 TREEVIEW_GetBkColor (HWND hwnd
)
532 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
535 return (LRESULT
) infoPtr
->clrBk
;
539 TREEVIEW_SetBkColor (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
541 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
542 COLORREF prevColor
=infoPtr
->clrBk
;
545 infoPtr
->clrBk
=(COLORREF
) lParam
;
546 return (LRESULT
) prevColor
;
550 TREEVIEW_GetTextColor (HWND hwnd
)
552 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
555 return (LRESULT
) infoPtr
->clrText
;
559 /* cdmode: custom draw mode as received from app. in first NMCUSTOMDRAW
562 #define TREEVIEW_LEFT_MARGIN 8
566 TREEVIEW_DrawItem (HWND hwnd
, HDC hdc
, TREEVIEW_ITEM
*wineItem
)
568 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
569 DWORD dwStyle
= GetWindowLongA (hwnd
, GWL_STYLE
);
570 INT center
,xpos
,cx
,cy
, cditem
;
572 UINT uTextJustify
= DT_LEFT
;
576 if (wineItem
->state
& TVIS_BOLD
)
577 hOldFont
= SelectObject (hdc
, infoPtr
->hBoldFont
);
579 hOldFont
= SelectObject (hdc
, infoPtr
->hFont
);
582 TRACE ("cdmode:%x\n",infoPtr
->cdmode
);
583 if (infoPtr
->cdmode
& CDRF_NOTIFYITEMDRAW
) {
584 cditem
=TREEVIEW_SendCustomDrawItemNotify
585 (hwnd
, hdc
, wineItem
, CDDS_ITEMPREPAINT
);
586 TRACE("prepaint:cditem-app returns 0x%x\n",cditem
);
588 if (cditem
& CDRF_SKIPDEFAULT
)
593 * Set drawing starting points
595 r
= wineItem
->rect
; /* this item rectangle */
596 center
= (r
.top
+r
.bottom
)/2; /* this item vertical center */
597 xpos
= r
.left
+ TREEVIEW_LEFT_MARGIN
;/* horizontal starting point */
600 * Display the tree hierarchy
602 if ( dwStyle
& TVS_HASLINES
)
605 * Write links to parent node
606 * we draw the L starting from the child to the parent
608 * points[0] is attached to the current item
609 * points[1] is the L corner
610 * points[2] is attached to the parent or the up sibling
612 if ( dwStyle
& TVS_LINESATROOT
)
614 TREEVIEW_ITEM
*upNode
= NULL
;
615 BOOL hasParentOrSibling
= TRUE
;
616 RECT upRect
= {0,0,0,0};
617 HPEN hOldPen
, hNewPen
;
620 * determine the target location of the line at root, either be linked
621 * to the up sibling or to the parent node.
623 if (wineItem
->upsibling
)
624 upNode
= TREEVIEW_ValidItem (infoPtr
, wineItem
->upsibling
);
625 else if (wineItem
->parent
)
626 upNode
= TREEVIEW_ValidItem (infoPtr
, wineItem
->parent
);
628 hasParentOrSibling
= FALSE
;
631 upRect
= upNode
->rect
;
633 if ( wineItem
->iLevel
== 0 )
635 points
[2].x
= points
[1].x
= upRect
.left
+8;
636 points
[0].x
= points
[2].x
+ 10;
637 points
[2].y
= upRect
.bottom
-3;
638 points
[1].y
= points
[0].y
= center
;
642 points
[2].x
= points
[1].x
= 8 + (20*wineItem
->iLevel
);
643 points
[2].y
= ( upNode
->cChildren
== 0) ?
644 upRect
.top
: /* is linked to the "L" above */
645 ( wineItem
->upsibling
!= NULL
) ?
646 upRect
.bottom
-3: /* is linked to an icon */
647 upRect
.bottom
+1; /* is linked to a +/- box */
648 points
[1].y
= points
[0].y
= center
;
649 points
[0].x
= points
[1].x
+ 10;
655 hNewPen
= CreatePen(PS_DOT
, 0, infoPtr
->clrLine
);
656 hOldPen
= SelectObject( hdc
, hNewPen
);
658 if (hasParentOrSibling
)
659 Polyline (hdc
,points
,3);
661 Polyline (hdc
,points
,2);
663 DeleteObject(hNewPen
);
664 SelectObject(hdc
, hOldPen
);
669 * Display the (+/-) signs
671 if (wineItem
->iLevel
!= 0)/* update position only for non root node */
672 xpos
+=(5*wineItem
->iLevel
);
674 if (( dwStyle
& TVS_HASBUTTONS
) && ( dwStyle
& TVS_HASLINES
))
676 if ( (wineItem
->cChildren
) ||
677 (wineItem
->cChildren
== I_CHILDRENCALLBACK
))
679 /* Setup expand box coordinate to facilitate the LMBClick handling */
680 wineItem
->expandBox
.left
= xpos
-4;
681 wineItem
->expandBox
.top
= center
-4;
682 wineItem
->expandBox
.right
= xpos
+5;
683 wineItem
->expandBox
.bottom
= center
+5;
687 wineItem
->expandBox
.left
,
688 wineItem
->expandBox
.top
,
689 wineItem
->expandBox
.right
,
690 wineItem
->expandBox
.bottom
);
692 MoveToEx (hdc
, xpos
-2, center
, NULL
);
693 LineTo (hdc
, xpos
+3, center
);
695 if (!(wineItem
->state
& TVIS_EXPANDED
)) {
696 MoveToEx (hdc
, xpos
, center
-2, NULL
);
697 LineTo (hdc
, xpos
, center
+3);
703 * Display the image associated with this item
705 xpos
+= 13; /* update position */
706 if (wineItem
->mask
& (TVIF_IMAGE
|TVIF_SELECTEDIMAGE
)) {
708 HIMAGELIST
*himlp
= NULL
;
710 /* State images are displayed to the left of the Normal image
711 * image number is in state; zero should be `display no image'.
712 * FIXME: that last sentence looks like it needs some checking.
714 if (infoPtr
->himlState
)
715 himlp
=&infoPtr
->himlState
;
716 imageIndex
=wineItem
->state
>>12;
717 imageIndex
++; /* yeah, right */
718 TRACE ("imindex:%d\n",imageIndex
);
719 if ((himlp
) && (imageIndex
))
721 imageIndex
--; /* see FIXME */
722 ImageList_Draw ( *himlp
, imageIndex
, hdc
, xpos
-2, r
.top
+1, ILD_NORMAL
);
723 ImageList_GetIconSize (*himlp
, &cx
, &cy
);
724 wineItem
->statebitmap
.left
=xpos
-2;
725 wineItem
->statebitmap
.right
=xpos
-2+cx
;
726 wineItem
->statebitmap
.top
=r
.top
+1;
727 wineItem
->statebitmap
.bottom
=r
.top
+1+cy
;
731 /* Now, draw the normal image; can be either selected or
732 * non-selected image.
736 if (infoPtr
->himlNormal
)
737 himlp
=&infoPtr
->himlNormal
; /* get the image list */
739 imageIndex
= wineItem
->iImage
;
740 if ( (wineItem
->state
& TVIS_SELECTED
) &&
741 (wineItem
->iSelectedImage
)) {
743 /* The item is curently selected */
744 if (wineItem
->iSelectedImage
== I_IMAGECALLBACK
)
745 TREEVIEW_SendDispInfoNotify
746 (hwnd
, wineItem
, TVN_GETDISPINFOA
, TVIF_SELECTEDIMAGE
);
748 imageIndex
= wineItem
->iSelectedImage
;
750 /* The item is not selected */
751 if (wineItem
->iImage
== I_IMAGECALLBACK
)
752 TREEVIEW_SendDispInfoNotify
753 (hwnd
, wineItem
, TVN_GETDISPINFOA
, TVIF_IMAGE
);
755 imageIndex
= wineItem
->iImage
;
762 if(wineItem
->stateMask
& TVIS_OVERLAYMASK
)
763 ovlIdx
= wineItem
->state
& TVIS_OVERLAYMASK
;
765 ImageList_Draw ( *himlp
, imageIndex
, hdc
, xpos
-2, r
.top
+1, ILD_NORMAL
|ovlIdx
);
766 ImageList_GetIconSize (*himlp
, &cx
, &cy
);
767 wineItem
->bitmap
.left
=xpos
-2;
768 wineItem
->bitmap
.right
=xpos
-2+cx
;
769 wineItem
->bitmap
.top
=r
.top
+1;
770 wineItem
->bitmap
.bottom
=r
.top
+1+cy
;
777 * Display the text associated with this item
780 if ((wineItem
->mask
& TVIF_TEXT
) && (wineItem
->pszText
))
782 COLORREF oldBkColor
= 0;
783 COLORREF oldTextColor
= 0;
789 wineItem
->text
.left
= r
.left
;
790 wineItem
->text
.right
= r
.right
;
791 wineItem
->text
.top
= r
.top
;
792 wineItem
->text
.bottom
= r
.bottom
;
794 if (wineItem
->pszText
== LPSTR_TEXTCALLBACKA
) {
795 TRACE("LPSTR_TEXTCALLBACK\n");
796 TREEVIEW_SendDispInfoNotify (hwnd
, wineItem
, TVN_GETDISPINFOA
, TVIF_TEXT
);
799 /* Yep, there are some things that need to be straightened out here.
800 Removing the comments around the setTextColor does not give the right
801 results. Dito FillRect.
805 /* GetTextExtentPoint32A (hdc, wineItem->pszText,
806 strlen (wineItem->pszText), &size); */
808 /* FillRect ( hdc, &wineItem->text, GetSysColorBrush (infoPtr->clrBk));
812 if (!(cditem
& CDRF_NOTIFYPOSTPAINT
) &&
813 (wineItem
->state
& (TVIS_SELECTED
| TVIS_DROPHILITED
)) ) {
814 oldBkMode
= SetBkMode (hdc
, OPAQUE
);
815 oldBkColor
= SetBkColor (hdc
, GetSysColor( COLOR_HIGHLIGHT
));
816 oldTextColor
= SetTextColor(hdc
, GetSysColor( COLOR_HIGHLIGHTTEXT
));
818 oldBkMode
= SetBkMode (hdc
, TRANSPARENT
);
819 oldBkColor
= SetBkColor (hdc
, infoPtr
->clrBk
);
820 /* oldTextColor = SetTextColor(hdc, infoPtr->clrText); */
828 lstrlenA(wineItem
->pszText
),
830 uTextJustify
| DT_VCENTER
| DT_SINGLELINE
);
832 /* Obtain the text coordinate */
836 lstrlenA(wineItem
->pszText
),
838 uTextJustify
| DT_VCENTER
| DT_SINGLELINE
| DT_CALCRECT
);
840 /* Restore the hdc state */
841 SetTextColor( hdc
, oldTextColor
);
843 if (oldBkMode
!= TRANSPARENT
)
844 SetBkMode(hdc
, oldBkMode
);
845 if (wineItem
->state
& (TVIS_SELECTED
| TVIS_DROPHILITED
))
846 SetBkColor (hdc
, oldBkColor
);
848 /* Draw the box arround the selected item */
849 if (wineItem
->state
& TVIS_SELECTED
)
851 HPEN hNewPen
= CreatePen(PS_DOT
, 0, GetSysColor(COLOR_WINDOWTEXT
) );
852 HPEN hOldPen
= SelectObject( hdc
, hNewPen
);
855 points
[0].x
= wineItem
->text
.left
-1;
856 points
[0].y
= wineItem
->text
.top
+1;
857 points
[1].x
= wineItem
->text
.right
;
858 points
[1].y
= wineItem
->text
.top
+1;
859 points
[2].x
= wineItem
->text
.right
;
860 points
[2].y
= wineItem
->text
.bottom
;
861 points
[3].x
= wineItem
->text
.left
-1;
862 points
[3].y
= wineItem
->text
.bottom
;
864 Polyline (hdc
,points
,4);
866 DeleteObject(hNewPen
);
867 SelectObject(hdc
, hOldPen
);
871 /* Draw insertion mark if necessary */
873 if (infoPtr
->insertMarkItem
)
874 TRACE ("item:%d,mark:%d\n", (int)wineItem
->hItem
,
875 (int) infoPtr
->insertMarkItem
);
876 if (wineItem
->hItem
==infoPtr
->insertMarkItem
) {
877 HPEN hNewPen
, hOldPen
;
880 hNewPen
= CreatePen(PS_SOLID
, 2, infoPtr
->clrInsertMark
);
881 hOldPen
= SelectObject( hdc
, hNewPen
);
883 if (infoPtr
->insertBeforeorAfter
)
884 offset
=wineItem
->text
.top
+1;
886 offset
=wineItem
->text
.bottom
-1;
888 MoveToEx (hdc
, wineItem
->text
.left
, offset
-3, NULL
);
889 LineTo (hdc
, wineItem
->text
.left
, offset
+3);
891 MoveToEx (hdc
, wineItem
->text
.left
, offset
, NULL
);
892 LineTo (hdc
, r
.right
-2, offset
);
894 MoveToEx (hdc
, r
.right
-2, offset
+3, NULL
);
895 LineTo (hdc
, r
.right
-2, offset
-3);
897 DeleteObject(hNewPen
);
899 SelectObject(hdc
, hOldPen
);
902 if (cditem
& CDRF_NOTIFYPOSTPAINT
) {
903 cditem
=TREEVIEW_SendCustomDrawItemNotify
904 (hwnd
, hdc
, wineItem
, CDDS_ITEMPOSTPAINT
);
905 TRACE("postpaint:cditem-app returns 0x%x\n",cditem
);
908 SelectObject (hdc
, hOldFont
);
912 TREEVIEW_GetItemRect (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
914 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
915 TREEVIEW_ITEM
*wineItem
;
917 LPRECT lpRect
= (LPRECT
)lParam
;
922 * validate parameters
927 if (infoPtr
->Timer
& TV_REFRESH_TIMER_SET
) {
929 TREEVIEW_Refresh (hwnd
, hdc
); /* we want a rect for the current view */
935 * retrieve the item ptr
937 iItem
= (HTREEITEM
*) lParam
;
938 wineItem
= TREEVIEW_ValidItem (infoPtr
, *iItem
);
939 if ((!wineItem
) || (!wineItem
->visible
))
943 * If wParam is TRUE return the text size otherwise return
944 * the whole item size
947 lpRect
->left
= wineItem
->text
.left
;
948 lpRect
->right
= wineItem
->text
.right
;
949 lpRect
->bottom
= wineItem
->text
.bottom
;
950 lpRect
->top
= wineItem
->text
.top
;
952 lpRect
->left
= wineItem
->rect
.left
;
953 lpRect
->right
= wineItem
->rect
.right
;
954 lpRect
->bottom
= wineItem
->rect
.bottom
;
955 lpRect
->top
= wineItem
->rect
.top
;
958 TRACE("[L:%d R:%d T:%d B:%d]\n",
959 lpRect
->left
,lpRect
->right
,
960 lpRect
->top
,lpRect
->bottom
);
966 TREEVIEW_GetVisibleCount (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
969 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
971 return (LRESULT
) infoPtr
->uVisibleHeight
/ infoPtr
->uRealItemHeight
;
977 TREEVIEW_SetItemA (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
979 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
980 TREEVIEW_ITEM
*wineItem
;
984 tvItem
=(LPTVITEMEXA
) lParam
;
985 iItem
=(INT
)tvItem
->hItem
;
986 TRACE("item %d,mask %x\n",iItem
,tvItem
->mask
);
988 wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)iItem
);
989 if (!wineItem
) return FALSE
;
991 if (tvItem
->mask
& TVIF_CHILDREN
) {
992 wineItem
->cChildren
=tvItem
->cChildren
;
995 if (tvItem
->mask
& TVIF_IMAGE
) {
996 wineItem
->iImage
=tvItem
->iImage
;
999 if (tvItem
->mask
& TVIF_INTEGRAL
) {
1000 wineItem
->iIntegral
=tvItem
->iIntegral
;
1003 if (tvItem
->mask
& TVIF_PARAM
) {
1004 wineItem
->lParam
=tvItem
->lParam
;
1007 if (tvItem
->mask
& TVIF_SELECTEDIMAGE
) {
1008 wineItem
->iSelectedImage
=tvItem
->iSelectedImage
;
1011 if (tvItem
->mask
& TVIF_STATE
) {
1012 TRACE ("prevstate,state,mask:%x,%x,%x\n",wineItem
->state
,tvItem
->state
,
1014 wineItem
->state
&= ~tvItem
->stateMask
;
1015 wineItem
->state
|= (tvItem
->state
& tvItem
->stateMask
);
1016 wineItem
->stateMask
|= tvItem
->stateMask
;
1019 if (tvItem
->mask
& TVIF_TEXT
) {
1020 if (tvItem
->pszText
!=LPSTR_TEXTCALLBACKA
) {
1021 len
=lstrlenA (tvItem
->pszText
);
1022 if (len
>wineItem
->cchTextMax
)
1023 wineItem
->pszText
= COMCTL32_ReAlloc (wineItem
->pszText
, len
+1);
1024 lstrcpynA (wineItem
->pszText
, tvItem
->pszText
,len
+1);
1026 if (wineItem
->cchTextMax
) {
1027 COMCTL32_Free (wineItem
->pszText
);
1028 wineItem
->cchTextMax
=0;
1030 wineItem
->pszText
=LPSTR_TEXTCALLBACKA
;
1034 wineItem
->mask
|= tvItem
->mask
;
1040 TREEVIEW_GetItemState (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1043 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
1044 TREEVIEW_ITEM
*wineItem
;
1047 wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)wParam
);
1048 if (!wineItem
) return 0;
1050 return (wineItem
->state
& lParam
);
1057 TREEVIEW_Refresh (HWND hwnd
, HDC hdc
)
1059 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
1063 INT iItem
, indent
, x
, y
, height
, itemHeight
;
1064 INT viewtop
,viewbottom
,viewleft
,viewright
;
1065 TREEVIEW_ITEM
*wineItem
, *prevItem
;
1070 if (infoPtr
->Timer
& TV_REFRESH_TIMER_SET
) {
1071 KillTimer (hwnd
, TV_REFRESH_TIMER
);
1072 infoPtr
->Timer
&= ~TV_REFRESH_TIMER_SET
;
1076 GetClientRect (hwnd
, &rect
);
1077 if ((rect
.left
-rect
.right
==0) || (rect
.top
-rect
.bottom
==0)) return;
1081 infoPtr
->cdmode
=TREEVIEW_SendCustomDrawNotify(hwnd
,CDDS_PREPAINT
,hdc
,rect
);
1083 if (infoPtr
->cdmode
==CDRF_SKIPDEFAULT
) return;
1085 infoPtr
->uVisibleHeight
= rect
.bottom
-rect
.top
;
1086 infoPtr
->uVisibleWidth
= rect
.right
-rect
.left
;
1088 viewtop
=infoPtr
->cy
;
1089 viewbottom
=infoPtr
->cy
+ rect
.bottom
-rect
.top
;
1090 viewleft
=infoPtr
->cx
;
1091 viewright
=infoPtr
->cx
+ rect
.right
-rect
.left
;
1093 TRACE("[%d %d %d %d]\n",viewtop
,viewbottom
,viewleft
,viewright
);
1095 /* draw background */
1097 hbrBk
= CreateSolidBrush (infoPtr
->clrBk
);
1098 FillRect(hdc
, &rect
, hbrBk
);
1099 DeleteObject(hbrBk
);
1101 ImageList_GetIconSize (infoPtr
->himlNormal
, &x
, &itemHeight
);
1102 if (infoPtr
->uItemHeight
>itemHeight
)
1103 itemHeight
=infoPtr
->uItemHeight
;
1105 GetTextMetricsA (hdc
, &tm
);
1106 if ((tm
.tmHeight
+ tm
.tmExternalLeading
) > itemHeight
)
1107 itemHeight
=tm
.tmHeight
+ tm
.tmExternalLeading
;
1109 infoPtr
->uRealItemHeight
=itemHeight
;
1111 iItem
=(INT
)infoPtr
->TopRootItem
;
1112 infoPtr
->firstVisible
=0;
1119 wineItem
= & infoPtr
->items
[iItem
];
1120 wineItem
->iLevel
=indent
;
1122 /* FIXME: remove this in later stage */
1124 if (wineItem->pszText!=LPSTR_TEXTCALLBACK32A)
1125 TRACE (treeview, "%d %d [%d %d %d %d] (%s)\n",y,x,
1126 wineItem->rect.top, wineItem->rect.bottom,
1127 wineItem->rect.left, wineItem->rect.right,
1130 TRACE (treeview, "%d [%d %d %d %d] (CALLBACK)\n",
1132 wineItem->rect.top, wineItem->rect.bottom,
1133 wineItem->rect.left, wineItem->rect.right);
1136 height
=itemHeight
* wineItem
->iIntegral
+1;
1137 if ((y
>= viewtop
) && (y
<= viewbottom
) &&
1138 (x
>= viewleft
) && (x
<= viewright
)) {
1139 wineItem
->visible
= TRUE
;
1140 wineItem
->rect
.top
= y
- infoPtr
->cy
+ rect
.top
;
1141 wineItem
->rect
.bottom
= wineItem
->rect
.top
+ height
;
1142 wineItem
->rect
.left
= x
- infoPtr
->cx
+ rect
.left
;
1143 wineItem
->rect
.right
= rect
.right
;
1144 if (!infoPtr
->firstVisible
)
1145 infoPtr
->firstVisible
=wineItem
->hItem
;
1146 TREEVIEW_DrawItem (hwnd
, hdc
, wineItem
);
1149 wineItem
->visible
= FALSE
;
1150 wineItem
->rect
.left
= wineItem
->rect
.top
= 0;
1151 wineItem
->rect
.right
= wineItem
->rect
.bottom
= 0;
1152 wineItem
->text
.left
= wineItem
->text
.top
= 0;
1153 wineItem
->text
.right
= wineItem
->text
.bottom
= 0;
1156 /* look up next item */
1158 if ((wineItem
->firstChild
) && (wineItem
->state
& TVIS_EXPANDED
)) {
1159 iItem
=(INT
)wineItem
->firstChild
;
1161 x
+=infoPtr
->uIndent
;
1162 if (x
>infoPtr
->uTotalWidth
)
1163 infoPtr
->uTotalWidth
=x
;
1166 iItem
=(INT
)wineItem
->sibling
;
1167 while ((!iItem
) && (indent
>0)) {
1169 x
-=infoPtr
->uIndent
;
1170 wineItem
=&infoPtr
->items
[(INT
)wineItem
->parent
];
1171 iItem
=(INT
)wineItem
->sibling
;
1177 /* FIXME: infoPtr->uTotalWidth should also take item label into account */
1178 /* FIXME: or should query item sizes (ie check CDRF_NEWFONT) */
1180 infoPtr
->uTotalHeight
=y
;
1181 if (y
>= (viewbottom
-viewtop
)) {
1182 if (!(infoPtr
->uInternalStatus
& TV_VSCROLL
))
1183 ShowScrollBar (hwnd
, SB_VERT
, TRUE
);
1184 infoPtr
->uInternalStatus
|=TV_VSCROLL
;
1185 SetScrollRange (hwnd
, SB_VERT
, 0,
1186 y
- infoPtr
->uVisibleHeight
, FALSE
);
1187 SetScrollPos (hwnd
, SB_VERT
, infoPtr
->cy
, TRUE
);
1190 if (infoPtr
->uInternalStatus
& TV_VSCROLL
)
1191 ShowScrollBar (hwnd
, SB_VERT
, FALSE
);
1192 infoPtr
->uInternalStatus
&= ~TV_VSCROLL
;
1196 if (infoPtr
->cdmode
& CDRF_NOTIFYPOSTPAINT
)
1197 infoPtr
->cdmode
=TREEVIEW_SendCustomDrawNotify
1198 (hwnd
, CDDS_POSTPAINT
, hdc
, rect
);
1205 TREEVIEW_HandleTimer (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1207 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
1209 TRACE(" %d\n",wParam
);
1212 case TV_REFRESH_TIMER
:
1213 KillTimer (hwnd
, TV_REFRESH_TIMER
);
1214 infoPtr
->Timer
&= ~TV_REFRESH_TIMER_SET
;
1215 InvalidateRect(hwnd
, NULL
, FALSE
);
1218 KillTimer (hwnd
, TV_EDIT_TIMER
);
1219 infoPtr
->Timer
&= ~TV_EDIT_TIMER_SET
;
1222 ERR("got unknown timer\n");
1230 TREEVIEW_QueueRefresh (HWND hwnd
)
1233 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
1236 if (infoPtr
->Timer
& TV_REFRESH_TIMER_SET
) {
1237 KillTimer (hwnd
, TV_REFRESH_TIMER
);
1240 SetTimer (hwnd
, TV_REFRESH_TIMER
, TV_REFRESH_DELAY
, 0);
1241 infoPtr
->Timer
|=TV_REFRESH_TIMER_SET
;
1247 TREEVIEW_GetItemA (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1249 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
1251 TREEVIEW_ITEM
*wineItem
;
1254 tvItem
=(LPTVITEMEXA
) lParam
;
1255 iItem
=(INT
)tvItem
->hItem
;
1257 wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)iItem
);
1258 if (!wineItem
) return FALSE
;
1260 if (tvItem
->mask
& TVIF_CHILDREN
) {
1261 if (TVIF_CHILDREN
==I_CHILDRENCALLBACK
)
1262 FIXME("I_CHILDRENCALLBACK not supported\n");
1263 tvItem
->cChildren
=wineItem
->cChildren
;
1266 if (tvItem
->mask
& TVIF_HANDLE
) {
1267 tvItem
->hItem
=wineItem
->hItem
;
1270 if (tvItem
->mask
& TVIF_IMAGE
) {
1271 tvItem
->iImage
=wineItem
->iImage
;
1274 if (tvItem
->mask
& TVIF_INTEGRAL
) {
1275 tvItem
->iIntegral
=wineItem
->iIntegral
;
1278 /* undocumented: windows ignores TVIF_PARAM and
1279 * always sets lParam
1281 tvItem
->lParam
=wineItem
->lParam
;
1283 if (tvItem
->mask
& TVIF_SELECTEDIMAGE
) {
1284 tvItem
->iSelectedImage
=wineItem
->iSelectedImage
;
1287 if (tvItem
->mask
& TVIF_STATE
) {
1288 tvItem
->state
=wineItem
->state
& tvItem
->stateMask
;
1291 if (tvItem
->mask
& TVIF_TEXT
) {
1292 if (wineItem
->pszText
== LPSTR_TEXTCALLBACKA
) {
1293 tvItem
->pszText
= LPSTR_TEXTCALLBACKA
; /* FIXME:send notification? */
1294 ERR(" GetItem called with LPSTR_TEXTCALLBACK\n");
1296 else if (wineItem
->pszText
) {
1297 lstrcpynA (tvItem
->pszText
, wineItem
->pszText
, tvItem
->cchTextMax
);
1301 TRACE("item %d<%p>, txt %p, img %p, action %x\n",
1302 iItem
, tvItem
, tvItem
->pszText
, &tvItem
->iImage
, tvItem
->mask
);
1309 /* FIXME: check implementation of TVGN_NEXT/TVGN_NEXTVISIBLE */
1312 TREEVIEW_GetNextItem (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1315 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
1316 TREEVIEW_ITEM
*wineItem
, *returnItem
;
1317 INT iItem
= (INT
)lParam
, retval
= 0, flag
= (INT
)wParam
;
1322 retval
= (INT
)infoPtr
->TopRootItem
;
1326 retval
= (INT
)infoPtr
->selectedItem
;
1329 case TVGN_FIRSTVISIBLE
: /* FIXME:we should only recalculate, not redraw */
1331 TREEVIEW_Refresh (hwnd
, hdc
);
1332 ReleaseDC(hwnd
,hdc
);
1333 retval
= (INT
)infoPtr
->firstVisible
;
1336 case TVGN_DROPHILITE
:
1337 retval
= (INT
)infoPtr
->dropItem
;
1341 wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)iItem
);
1342 retval
= wineItem
? (INT
)wineItem
->sibling
: 0;
1346 wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)iItem
);
1347 retval
= wineItem
? (INT
)wineItem
->upsibling
: 0;
1351 wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)iItem
);
1352 retval
= wineItem
? (INT
)wineItem
->parent
: 0;
1356 wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)iItem
);
1357 retval
= wineItem
? (INT
)wineItem
->firstChild
: 0;
1360 case TVGN_LASTVISIBLE
:
1361 if((wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)iItem
))) {
1362 returnItem
= TREEVIEW_GetLastListItem (infoPtr
,wineItem
);
1363 retval
= returnItem
? (INT
)returnItem
->hItem
: 0;
1367 case TVGN_NEXTVISIBLE
:
1368 if((wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)iItem
))) {
1369 returnItem
= TREEVIEW_GetNextListItem (infoPtr
,wineItem
);
1370 retval
= returnItem
? (INT
)returnItem
->hItem
: 0;
1374 case TVGN_PREVIOUSVISIBLE
:
1375 if((wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)iItem
))) {
1376 returnItem
= TREEVIEW_GetPrevListItem (infoPtr
, wineItem
);
1377 retval
= returnItem
? (INT
)returnItem
->hItem
: 0;
1382 FIXME("Unknown msg %x,item %x\n", flag
,iItem
);
1386 TRACE("flags %x, item %d returns %d\n", flag
, iItem
, retval
);
1392 TREEVIEW_GetCount (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1394 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
1396 TRACE(" %d\n",infoPtr
->uNumItems
);
1397 return (LRESULT
) infoPtr
->uNumItems
;
1400 /***************************************************************************
1401 * This method does the chaining of the insertion of a treeview item
1403 * If parent is NULL, we're inserting at the root of the list.
1405 static void TREEVIEW_InsertBefore(
1406 TREEVIEW_INFO
*infoPtr
,
1407 TREEVIEW_ITEM
*newItem
,
1408 TREEVIEW_ITEM
*sibling
,
1409 TREEVIEW_ITEM
*parent
)
1411 HTREEITEM siblingHandle
= 0;
1412 HTREEITEM upSiblingHandle
= 0;
1413 TREEVIEW_ITEM
*upSibling
= NULL
;
1415 if (newItem
== NULL
)
1416 ERR("NULL newItem, impossible condition\n");
1418 if (sibling
!= NULL
) /* Insert before this sibling for this parent */
1420 /* Store the new item sibling up sibling and sibling tem handle */
1421 siblingHandle
= sibling
->hItem
;
1422 upSiblingHandle
= sibling
->upsibling
;
1423 /* As well as a pointer to the upsibling sibling object */
1424 if ( (INT
)sibling
->upsibling
!= 0 )
1425 upSibling
= &infoPtr
->items
[(INT
)sibling
->upsibling
];
1427 /* Adjust the sibling pointer */
1428 sibling
->upsibling
= newItem
->hItem
;
1430 /* Adjust the new item pointers */
1431 newItem
->upsibling
= upSiblingHandle
;
1432 newItem
->sibling
= siblingHandle
;
1434 /* Adjust the up sibling pointer */
1435 if ( upSibling
!= NULL
)
1436 upSibling
->sibling
= newItem
->hItem
;
1438 /* this item is the first child of this parent, adjust parent pointers */
1440 parent
->firstChild
= newItem
->hItem
;
1442 infoPtr
->TopRootItem
= newItem
->hItem
;
1444 else /* Insert as first child of this parent */
1446 parent
->firstChild
= newItem
->hItem
;
1449 /***************************************************************************
1450 * This method does the chaining of the insertion of a treeview item
1452 * If parent is NULL, we're inserting at the root of the list.
1454 static void TREEVIEW_InsertAfter(
1455 TREEVIEW_INFO
*infoPtr
,
1456 TREEVIEW_ITEM
*newItem
,
1457 TREEVIEW_ITEM
*upSibling
,
1458 TREEVIEW_ITEM
*parent
)
1460 HTREEITEM upSiblingHandle
= 0;
1461 HTREEITEM siblingHandle
= 0;
1462 TREEVIEW_ITEM
*sibling
= NULL
;
1465 if (newItem
== NULL
)
1466 ERR("NULL newItem, impossible condition\n");
1468 if (upSibling
!= NULL
) /* Insert after this upsibling for this parent */
1470 /* Store the new item up sibling and sibling item handle */
1471 upSiblingHandle
= upSibling
->hItem
;
1472 siblingHandle
= upSibling
->sibling
;
1473 /* As well as a pointer to the upsibling sibling object */
1474 if ( (INT
)upSibling
->sibling
!= 0 )
1475 sibling
= &infoPtr
->items
[(INT
)upSibling
->sibling
];
1477 /* Adjust the up sibling pointer */
1478 upSibling
->sibling
= newItem
->hItem
;
1480 /* Adjust the new item pointers */
1481 newItem
->upsibling
= upSiblingHandle
;
1482 newItem
->sibling
= siblingHandle
;
1484 /* Adjust the sibling pointer */
1485 if ( sibling
!= NULL
)
1486 sibling
->upsibling
= newItem
->hItem
;
1489 newItem is the last of the level, nothing else to do
1492 else /* Insert as first child of this parent */
1494 parent
->firstChild
= newItem
->hItem
;
1497 /***************************************************************************
1498 * Forward the DPA local callback to the treeview owner callback
1500 static INT WINAPI
TREEVIEW_CallBackCompare(
1505 /* Forward the call to the client define callback */
1506 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr((HWND
)tvInfoPtr
);
1507 return (infoPtr
->pCallBackSort
->lpfnCompare
)(
1508 ((TREEVIEW_ITEM
*)first
)->lParam
,
1509 ((TREEVIEW_ITEM
*)second
)->lParam
,
1510 infoPtr
->pCallBackSort
->lParam
);
1513 /***************************************************************************
1514 * Treeview native sort routine: sort on item text.
1516 static INT WINAPI
TREEVIEW_SortOnName (
1521 HWND hwnd
=(HWND
) tvInfoPtr
;
1523 TREEVIEW_ITEM
*item
;
1526 item
=(TREEVIEW_ITEM
*) first
;
1527 if (item
->pszText
==LPSTR_TEXTCALLBACKA
) {
1528 TREEVIEW_SendDispInfoNotify (hwnd
, item
, TVN_GETDISPINFOA
, TVIF_TEXT
);
1532 item
=(TREEVIEW_ITEM
*) second
;
1533 if (item
->pszText
==LPSTR_TEXTCALLBACKA
) {
1534 TREEVIEW_SendDispInfoNotify (hwnd
, item
, TVN_GETDISPINFOA
, TVIF_TEXT
);
1538 return -strcmp (txt1
,txt2
);
1541 /***************************************************************************
1542 * Setup the treeview structure with regards of the sort method
1543 * and sort the children of the TV item specified in lParam
1544 * fRecurse: currently unused. Should be zero.
1545 * parent: if pSort!=NULL, should equal pSort->hParent.
1546 * otherwise, item which child items are to be sorted.
1547 * pSort: sort method info. if NULL, sort on item text.
1548 * if non-NULL, sort on item's lParam content, and let the
1549 * application decide what that means. See also TVM_SORTCHILDRENCB.
1552 static LRESULT WINAPI
TREEVIEW_Sort (
1559 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
1560 TREEVIEW_ITEM
*sortMe
= NULL
; /* Node for which we sort the children */
1562 /* Obtain the TVSORTBC struct */
1563 infoPtr
->pCallBackSort
= pSort
;
1565 /* undocumented feature: TVI_ROOT means `sort the whole tree' */
1567 if (parent
==TVI_ROOT
)
1568 parent
=infoPtr
->TopRootItem
;
1570 /* Check for a valid handle to the parent item */
1571 if (!TREEVIEW_ValidItem(infoPtr
, parent
))
1573 ERR ("invalid item hParent=%x\n", (INT
)parent
);
1577 /* Obtain the parent node to sort */
1578 sortMe
= &infoPtr
->items
[ (INT
)parent
];
1580 /* Make sure there is something to sort */
1581 if ( sortMe
->cChildren
> 1 )
1583 /* pointer organization */
1584 HDPA sortList
= DPA_Create(sortMe
->cChildren
);
1585 HTREEITEM itemHandle
= sortMe
->firstChild
;
1586 TREEVIEW_ITEM
*itemPtr
= & infoPtr
->items
[ (INT
)itemHandle
];
1588 /* TREEVIEW_ITEM rechaining */
1594 /* Build the list of item to sort */
1598 sortList
, /* the list */
1599 sortMe
->cChildren
+1, /* force the insertion to be an append */
1600 itemPtr
); /* the ptr to store */
1602 /* Get the next sibling */
1603 itemHandle
= itemPtr
->sibling
;
1604 itemPtr
= & infoPtr
->items
[ (INT
)itemHandle
];
1605 } while ( itemHandle
!= NULL
);
1607 /* let DPA perform the sort activity */
1610 sortList
, /* what */
1611 TREEVIEW_CallBackCompare
, /* how */
1615 sortList
, /* what */
1616 TREEVIEW_SortOnName
, /* how */
1620 * Reorganized TREEVIEW_ITEM structures.
1621 * Note that we know we have at least two elements.
1624 /* Get the first item and get ready to start... */
1625 item
= DPA_GetPtr(sortList
, count
++);
1626 while ( (nextItem
= DPA_GetPtr(sortList
, count
++)) != NULL
)
1628 /* link the two current item toghether */
1629 ((TREEVIEW_ITEM
*)item
)->sibling
= ((TREEVIEW_ITEM
*)nextItem
)->hItem
;
1630 ((TREEVIEW_ITEM
*)nextItem
)->upsibling
= ((TREEVIEW_ITEM
*)item
)->hItem
;
1632 if (prevItem
== NULL
) /* this is the first item, update the parent */
1634 sortMe
->firstChild
= ((TREEVIEW_ITEM
*)item
)->hItem
;
1635 ((TREEVIEW_ITEM
*)item
)->upsibling
= NULL
;
1637 else /* fix the back chaining */
1639 ((TREEVIEW_ITEM
*)item
)->upsibling
= ((TREEVIEW_ITEM
*)prevItem
)->hItem
;
1642 /* get ready for the next one */
1647 /* the last item is pointed to by item and never has a sibling */
1648 ((TREEVIEW_ITEM
*)item
)->sibling
= NULL
;
1650 DPA_Destroy(sortList
);
1658 /***************************************************************************
1659 * Setup the treeview structure with regards of the sort method
1660 * and sort the children of the TV item specified in lParam
1662 static LRESULT WINAPI
TREEVIEW_SortChildrenCB(
1668 LPTVSORTCB pSort
=(LPTVSORTCB
) lParam
;
1670 return TREEVIEW_Sort (hwnd
, wParam
, pSort
->hParent
, pSort
);
1674 /***************************************************************************
1675 * Sort the children of the TV item specified in lParam.
1677 static LRESULT WINAPI
TREEVIEW_SortChildren (
1682 return TREEVIEW_Sort (hwnd
, (BOOL
) wParam
, (HTREEITEM
) lParam
, NULL
);
1687 /* the method used below isn't the most memory-friendly, but it avoids
1688 a lot of memory reallocations */
1690 /* BTW: we waste handle 0; 0 is not an allowed handle. */
1693 TREEVIEW_InsertItemA (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1696 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
1697 TVINSERTSTRUCTA
*ptdi
;
1699 TREEVIEW_ITEM
*wineItem
, *parentItem
, *prevsib
, *sibItem
;
1700 INT iItem
,listItems
,i
,len
;
1702 /* Item to insert */
1703 ptdi
= (LPTVINSERTSTRUCTA
) lParam
;
1705 /* check if memory is available */
1707 if (infoPtr
->uNumPtrsAlloced
==0) {
1708 infoPtr
->items
= COMCTL32_Alloc (TVITEM_ALLOC
*sizeof (TREEVIEW_ITEM
));
1709 infoPtr
->freeList
= COMCTL32_Alloc ((1+(TVITEM_ALLOC
>>5)) * sizeof (INT
));
1710 infoPtr
->uNumPtrsAlloced
=TVITEM_ALLOC
;
1711 infoPtr
->TopRootItem
=(HTREEITEM
)1;
1715 * Reallocate contiguous space for items
1717 if (infoPtr
->uNumItems
== (infoPtr
->uNumPtrsAlloced
-1) ) {
1718 TREEVIEW_ITEM
*oldItems
= infoPtr
->items
;
1719 INT
*oldfreeList
= infoPtr
->freeList
;
1721 infoPtr
->uNumPtrsAlloced
*=2;
1722 infoPtr
->items
= COMCTL32_Alloc (infoPtr
->uNumPtrsAlloced
*sizeof (TREEVIEW_ITEM
));
1723 infoPtr
->freeList
= COMCTL32_Alloc ((1+(infoPtr
->uNumPtrsAlloced
>>5))*sizeof (INT
));
1725 memcpy (&infoPtr
->items
[0], &oldItems
[0],
1726 infoPtr
->uNumPtrsAlloced
/2 * sizeof(TREEVIEW_ITEM
));
1727 memcpy (&infoPtr
->freeList
[0], &oldfreeList
[0],
1728 (infoPtr
->uNumPtrsAlloced
>>6) * sizeof(INT
));
1730 COMCTL32_Free (oldItems
);
1731 COMCTL32_Free (oldfreeList
);
1735 * Reset infoPtr structure with new stat according to current TV picture
1738 infoPtr
->uNumItems
++;
1739 if ((INT
)infoPtr
->uMaxHandle
==(infoPtr
->uNumItems
-1)) {
1740 iItem
=infoPtr
->uNumItems
;
1741 infoPtr
->uMaxHandle
= (HTREEITEM
)((INT
)infoPtr
->uMaxHandle
+ 1);
1742 } else { /* check freelist */
1743 for (i
=0; i
<=infoPtr
->uNumPtrsAlloced
>>5; i
++) {
1744 if (infoPtr
->freeList
[i
]) {
1745 iItem
=ffs (infoPtr
->freeList
[i
])-1;
1746 tv_clear_bit(iItem
,&infoPtr
->freeList
[i
]);
1753 if (TRACE_ON(treeview
)) {
1754 for (i
=0; i
<=infoPtr
->uNumPtrsAlloced
>>5; i
++)
1755 TRACE("%8x\n",infoPtr
->freeList
[i
]);
1758 if (!iItem
) ERR("Argh -- can't find free item.\n");
1761 * Find the parent item of the new item
1763 tvItem
= & ptdi
->DUMMYUNIONNAME
.itemex
;
1764 wineItem
=& infoPtr
->items
[iItem
];
1766 if ((ptdi
->hParent
==TVI_ROOT
) || (ptdi
->hParent
==0)) {
1768 wineItem
->parent
= 0;
1769 sibItem
= &infoPtr
->items
[(INT
)infoPtr
->TopRootItem
];
1770 listItems
= infoPtr
->uNumItems
;
1773 parentItem
= &infoPtr
->items
[(INT
)ptdi
->hParent
];
1775 /* Do the insertion here it if it's the only item of this parent */
1776 if (!parentItem
->firstChild
)
1777 parentItem
->firstChild
=(HTREEITEM
)iItem
;
1779 wineItem
->parent
= ptdi
->hParent
;
1780 sibItem
= &infoPtr
->items
[(INT
)parentItem
->firstChild
];
1781 listItems
= parentItem
->cChildren
;
1782 parentItem
->cChildren
++;
1786 /* NOTE: I am moving some setup of the wineItem object that was initialy
1787 * done at the end of the function since some of the values are
1788 * required by the Callback sorting
1791 if (tvItem
->mask
& TVIF_TEXT
)
1794 * Setup the item text stuff here since it's required by the Sort method
1795 * when the insertion are ordered
1797 if (tvItem
->pszText
!=LPSTR_TEXTCALLBACKA
)
1799 TRACE("(%p,%s)\n", &tvItem
->pszText
, tvItem
->pszText
);
1800 len
= lstrlenA (tvItem
->pszText
)+1;
1801 wineItem
->pszText
= COMCTL32_Alloc (len
+1);
1802 lstrcpyA (wineItem
->pszText
, tvItem
->pszText
);
1803 wineItem
->cchTextMax
=len
;
1807 TRACE("LPSTR_TEXTCALLBACK\n");
1808 wineItem
->pszText
= LPSTR_TEXTCALLBACKA
;
1809 wineItem
->cchTextMax
= 0;
1813 if (tvItem
->mask
& TVIF_PARAM
)
1814 wineItem
->lParam
=tvItem
->lParam
;
1817 wineItem
->upsibling
=0; /* needed in case we're the first item in a list */
1818 wineItem
->sibling
=0;
1819 wineItem
->firstChild
=0;
1820 wineItem
->hItem
=(HTREEITEM
)iItem
;
1825 switch ((DWORD
) ptdi
->hInsertAfter
) {
1826 case (DWORD
) TVI_FIRST
:
1827 if (sibItem
==wineItem
) break;
1828 if (wineItem
->parent
) {
1829 wineItem
->sibling
=parentItem
->firstChild
;
1830 parentItem
->firstChild
=(HTREEITEM
)iItem
;
1832 wineItem
->sibling
=infoPtr
->TopRootItem
;
1833 infoPtr
->TopRootItem
=(HTREEITEM
)iItem
;
1835 sibItem
->upsibling
=(HTREEITEM
)iItem
;
1838 case (DWORD
) TVI_SORT
:
1839 if (sibItem
==wineItem
)
1841 * This item is the first child of the level and it
1842 * has already been inserted
1847 TREEVIEW_ITEM
*aChild
;
1850 TREEVIEW_ITEM
*previousChild
= NULL
;
1851 BOOL bItemInserted
= FALSE
;
1854 aChild
= &infoPtr
->items
[(INT
)parentItem
->firstChild
];
1856 aChild
= &infoPtr
->items
[(INT
)infoPtr
->TopRootItem
];
1858 /* lookup the text if using LPSTR_TEXTCALLBACKs */
1859 if (wineItem
->pszText
==LPSTR_TEXTCALLBACKA
) {
1860 TREEVIEW_SendDispInfoNotify (hwnd
, wineItem
, TVN_GETDISPINFOA
, TVIF_TEXT
);
1863 /* Iterate the parent children to see where we fit in */
1864 while ( aChild
!= NULL
)
1868 /* lookup the text if using LPSTR_TEXTCALLBACKs */
1869 if (aChild
->pszText
==LPSTR_TEXTCALLBACKA
) {
1870 TREEVIEW_SendDispInfoNotify (hwnd
, aChild
, TVN_GETDISPINFOA
, TVIF_TEXT
);
1873 comp
= strcmp(wineItem
->pszText
, aChild
->pszText
);
1874 if ( comp
< 0 ) /* we are smaller than the current one */
1876 TREEVIEW_InsertBefore(infoPtr
, wineItem
, aChild
, parentItem
);
1877 bItemInserted
= TRUE
;
1880 else if ( comp
> 0 ) /* we are bigger than the current one */
1882 previousChild
= aChild
;
1883 aChild
= (aChild
->sibling
== 0) /* This will help us to exit */
1884 ? NULL
/* if there is no more sibling */
1885 : &infoPtr
->items
[(INT
)aChild
->sibling
];
1887 /* Look at the next item */
1890 else if ( comp
== 0 )
1893 * An item with this name is already existing, therefore,
1894 * we add after the one we found
1896 TREEVIEW_InsertAfter(infoPtr
, wineItem
, aChild
, parentItem
);
1897 bItemInserted
= TRUE
;
1903 * we reach the end of the child list and the item as not
1904 * yet been inserted, therefore, insert it after the last child.
1906 if ( (! bItemInserted
) && (aChild
== NULL
) )
1907 TREEVIEW_InsertAfter(infoPtr
, wineItem
, previousChild
, parentItem
);
1913 case (DWORD
) TVI_LAST
:
1914 if (sibItem
==wineItem
) break;
1915 while (sibItem
->sibling
) {
1917 sibItem
=&infoPtr
->items
[(INT
)sibItem
->sibling
];
1919 sibItem
->sibling
=(HTREEITEM
)iItem
;
1920 wineItem
->upsibling
=sibItem
->hItem
;
1923 while ((sibItem
->sibling
) && (sibItem
->hItem
!=ptdi
->hInsertAfter
))
1926 sibItem
=&infoPtr
->items
[(INT
)sibItem
->sibling
];
1928 if (sibItem
->hItem
!=ptdi
->hInsertAfter
) {
1929 ERR("tried to insert item after nonexisting handle %d.\n",
1930 (INT
) ptdi
->hInsertAfter
);
1934 if (sibItem
->sibling
) {
1935 sibItem
=&infoPtr
->items
[(INT
)sibItem
->sibling
];
1936 sibItem
->upsibling
=(HTREEITEM
)iItem
;
1937 wineItem
->sibling
=sibItem
->hItem
;
1939 prevsib
->sibling
=(HTREEITEM
)iItem
;
1940 wineItem
->upsibling
=prevsib
->hItem
;
1946 /* Fill in info structure */
1948 TRACE("new item %d; parent %d, mask %x\n", iItem
,
1949 (INT
)wineItem
->parent
,tvItem
->mask
);
1951 wineItem
->mask
=tvItem
->mask
;
1952 wineItem
->iIntegral
=1;
1954 if (tvItem
->mask
& TVIF_CHILDREN
) {
1955 wineItem
->cChildren
=tvItem
->cChildren
;
1956 if (tvItem
->cChildren
==I_CHILDRENCALLBACK
)
1957 FIXME(" I_CHILDRENCALLBACK not supported\n");
1960 wineItem
->expandBox
.left
= 0; /* Initialize the expandBox */
1961 wineItem
->expandBox
.top
= 0;
1962 wineItem
->expandBox
.right
= 0;
1963 wineItem
->expandBox
.bottom
= 0;
1965 if (tvItem
->mask
& TVIF_IMAGE
)
1966 wineItem
->iImage
=tvItem
->iImage
;
1968 /* If the application sets TVIF_INTEGRAL without
1969 supplying a TVITEMEX structure, it's toast */
1971 if (tvItem
->mask
& TVIF_INTEGRAL
)
1972 wineItem
->iIntegral
=tvItem
->iIntegral
;
1974 if (tvItem
->mask
& TVIF_SELECTEDIMAGE
)
1975 wineItem
->iSelectedImage
=tvItem
->iSelectedImage
;
1977 if (tvItem
->mask
& TVIF_STATE
) {
1978 TRACE("item state: %x ->%x\n", wineItem
->state
, tvItem
->state
);
1979 TRACE("statemask: %x ->%x\n", wineItem
->stateMask
, tvItem
->stateMask
);
1980 wineItem
->state
=tvItem
->state
;
1981 wineItem
->stateMask
=tvItem
->stateMask
;
1984 TREEVIEW_QueueRefresh (hwnd
);
1986 return (LRESULT
) iItem
;
1991 TREEVIEW_InsertItemW(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1993 TVINSERTSTRUCTW
*tvisW
;
1994 TVINSERTSTRUCTA tvisA
;
1997 tvisW
= (LPTVINSERTSTRUCTW
)lParam
;
1999 tvisA
.hParent
= tvisW
->hParent
;
2000 tvisA
.hInsertAfter
= tvisW
->hInsertAfter
;
2002 tvisA
.DUMMYUNIONNAME
.item
.mask
= tvisW
->DUMMYUNIONNAME
.item
.mask
;
2003 tvisA
.DUMMYUNIONNAME
.item
.hItem
= tvisW
->DUMMYUNIONNAME
.item
.hItem
;
2004 tvisA
.DUMMYUNIONNAME
.item
.state
= tvisW
->DUMMYUNIONNAME
.item
.state
;
2005 tvisA
.DUMMYUNIONNAME
.item
.stateMask
= tvisW
->DUMMYUNIONNAME
.item
.stateMask
;
2006 tvisA
.DUMMYUNIONNAME
.item
.cchTextMax
= tvisW
->DUMMYUNIONNAME
.item
.cchTextMax
;
2008 if(tvisW
->DUMMYUNIONNAME
.item
.pszText
)
2010 if (tvisW
->DUMMYUNIONNAME
.item
.pszText
!=LPSTR_TEXTCALLBACKW
)
2012 int len
= lstrlenW (tvisW
->DUMMYUNIONNAME
.item
.pszText
)+1;
2013 tvisA
.DUMMYUNIONNAME
.item
.pszText
= COMCTL32_Alloc (len
);
2014 lstrcpyWtoA (tvisA
.DUMMYUNIONNAME
.item
.pszText
,
2015 tvisW
->DUMMYUNIONNAME
.item
.pszText
);
2019 tvisA
.DUMMYUNIONNAME
.item
.pszText
= LPSTR_TEXTCALLBACKA
;
2020 tvisA
.DUMMYUNIONNAME
.item
.cchTextMax
= 0;
2024 tvisA
.DUMMYUNIONNAME
.item
.iImage
= tvisW
->DUMMYUNIONNAME
.item
.iImage
;
2025 tvisA
.DUMMYUNIONNAME
.item
.iSelectedImage
= tvisW
->DUMMYUNIONNAME
.item
.iSelectedImage
;
2026 tvisA
.DUMMYUNIONNAME
.item
.cChildren
= tvisW
->DUMMYUNIONNAME
.item
.cChildren
;
2027 tvisA
.DUMMYUNIONNAME
.item
.lParam
= tvisW
->DUMMYUNIONNAME
.item
.lParam
;
2029 lRes
= TREEVIEW_InsertItemA(hwnd
,wParam
,(LPARAM
)&tvisA
);
2031 if (tvisA
.DUMMYUNIONNAME
.item
.pszText
!=LPSTR_TEXTCALLBACKA
)
2033 COMCTL32_Free(tvisA
.DUMMYUNIONNAME
.item
.pszText
);
2042 TREEVIEW_DeleteItem (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2044 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2046 TREEVIEW_ITEM
*wineItem
;
2048 TRACE("item = %08lx\n", lParam
);
2050 if (lParam
== (INT
)TVI_ROOT
) {
2051 TREEVIEW_RemoveTree (hwnd
);
2053 iItem
= (INT
) lParam
;
2054 wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)iItem
);
2055 if (!wineItem
) return FALSE
;
2057 if (wineItem
->pszText
==LPSTR_TEXTCALLBACKA
)
2058 TRACE("LPSTR_TEXTCALLBACK\n");
2060 TRACE("%s\n",wineItem
->pszText
);
2061 TREEVIEW_RemoveItem (hwnd
, wineItem
);
2064 TREEVIEW_QueueRefresh (hwnd
);
2072 TREEVIEW_GetIndent (HWND hwnd
)
2074 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2077 return infoPtr
->uIndent
;
2081 TREEVIEW_SetIndent (HWND hwnd
, WPARAM wParam
)
2083 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2087 newIndent
=(INT
) wParam
;
2088 if (newIndent
< MINIMUM_INDENT
) newIndent
=MINIMUM_INDENT
;
2089 infoPtr
->uIndent
=newIndent
;
2095 TREEVIEW_GetToolTips (HWND hwnd
)
2098 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2101 return infoPtr
->hwndToolTip
;
2106 TREEVIEW_SetToolTips (HWND hwnd
, WPARAM wParam
)
2109 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2113 prevToolTip
=infoPtr
->hwndToolTip
;
2114 infoPtr
->hwndToolTip
= (HWND
) wParam
;
2120 static LRESULT CALLBACK
2121 TREEVIEW_GetEditControl (HWND hwnd
)
2124 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2126 return infoPtr
->hwndEdit
;
2130 TREEVIEW_Edit_SubclassProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
,
2138 HDC hdc
= (HDC
) wParam
;
2139 GetClientRect (hwnd
, &rc
);
2140 Rectangle (hdc
, rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
2146 return DLGC_WANTARROWS
| DLGC_WANTALLKEYS
;
2151 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(GetParent(hwnd
));
2153 return CallWindowProcA (infoPtr
->wpEditOrig
, hwnd
, uMsg
, wParam
, lParam
);
2164 /* should handle edit control messages here */
2167 TREEVIEW_Command (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2170 TRACE("%x %ld\n",wParam
, lParam
);
2172 switch (HIWORD(wParam
))
2177 * Adjust the edit window size
2179 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2180 TREEVIEW_ITEM
*editItem
= TREEVIEW_ValidItem(infoPtr
, infoPtr
->editItem
);
2181 INT iLength
= GetWindowTextLengthA(infoPtr
->hwndEdit
);
2182 HDC hdc
= GetDC(infoPtr
->hwndEdit
);
2185 if ( GetTextMetricsA(hdc
, &tm
) )
2187 LONG newWidth
= (iLength
* tm
.tmAveCharWidth
) + 15;
2192 editItem
->text
.left
- 2,
2193 editItem
->text
.top
- 1,
2195 editItem
->text
.bottom
- editItem
->text
.top
+ 3,
2198 ReleaseDC(hwnd
, hdc
);
2204 /* TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
2209 return SendMessageA (GetParent (hwnd
), WM_COMMAND
, wParam
, lParam
);
2216 TREEVIEW_Size (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2219 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2221 if (infoPtr
->bAutoSize
)
2223 infoPtr
->bAutoSize
= FALSE
;
2226 infoPtr
->bAutoSize
= TRUE
;
2228 if (wParam
== SIZE_RESTORED
)
2230 infoPtr
->uTotalWidth
= LOWORD (lParam
);
2231 infoPtr
->uTotalHeight
= HIWORD (lParam
);
2233 FIXME("WM_SIZE flag %x %lx not handled\n", wParam
, lParam
);
2236 TREEVIEW_QueueRefresh (hwnd
);
2243 TREEVIEW_StyleChanged (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2247 TRACE("(%x %lx)\n",wParam
,lParam
);
2249 TREEVIEW_Refresh (hwnd
, hdc
);
2250 ReleaseDC(hwnd
,hdc
);
2256 TREEVIEW_Create (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2258 TREEVIEW_INFO
*infoPtr
;
2259 DWORD dwStyle
= GetWindowLongA (hwnd
, GWL_STYLE
);
2264 TRACE("wnd %x, style %lx\n",hwnd
,dwStyle
);
2265 /* allocate memory for info structure */
2266 infoPtr
= (TREEVIEW_INFO
*) COMCTL32_Alloc (sizeof(TREEVIEW_INFO
));
2268 SetWindowLongA( hwnd
, 0, (DWORD
)infoPtr
);
2270 if (infoPtr
== NULL
) {
2271 ERR("could not allocate info memory!\n");
2275 if ((TREEVIEW_INFO
*) GetWindowLongA( hwnd
, 0) != infoPtr
) {
2276 ERR("pointer assignment error!\n");
2282 /* set default settings */
2283 infoPtr
->uInternalStatus
=0;
2284 infoPtr
->uNumItems
=0;
2285 infoPtr
->clrBk
= GetSysColor (COLOR_WINDOW
);
2286 infoPtr
->clrText
= GetSysColor (COLOR_WINDOWTEXT
);
2287 infoPtr
->clrLine
= GetSysColor (COLOR_WINDOWTEXT
);
2288 infoPtr
->clrInsertMark
= GetSysColor (COLOR_BTNTEXT
);
2291 infoPtr
->uIndent
= 15;
2292 infoPtr
->himlNormal
= NULL
;
2293 infoPtr
->himlState
= NULL
;
2294 infoPtr
->uItemHeight
= -1;
2295 GetTextMetricsA (hdc
, &tm
);
2296 infoPtr
->hFont
= GetStockObject (DEFAULT_GUI_FONT
);
2297 GetObjectA (infoPtr
->hFont
, sizeof (LOGFONTA
), &logFont
);
2298 logFont
.lfWeight
=FW_BOLD
;
2299 infoPtr
->hBoldFont
= CreateFontIndirectA (&logFont
);
2301 infoPtr
->items
= NULL
;
2302 infoPtr
->selectedItem
=0;
2303 infoPtr
->clrText
=-1; /* use system color */
2304 infoPtr
->dropItem
=0;
2305 infoPtr
->insertMarkItem
=0;
2306 infoPtr
->insertBeforeorAfter
=0;
2307 infoPtr
->pCallBackSort
=NULL
;
2308 infoPtr
->uScrollTime
= 300; /* milliseconds */
2309 infoPtr
->wpEditOrig
= NULL
; /* we haven't subclassed anything yet */
2311 infoPtr
->hwndToolTip
=0;
2312 if (!(dwStyle
& TVS_NOTOOLTIPS
)) { /* Create tooltip control */
2315 infoPtr
->hwndToolTip
=
2316 CreateWindowExA (0, TOOLTIPS_CLASSA
, NULL
, 0,
2317 CW_USEDEFAULT
, CW_USEDEFAULT
,
2318 CW_USEDEFAULT
, CW_USEDEFAULT
,
2321 /* Send NM_TOOLTIPSCREATED notification */
2322 if (infoPtr
->hwndToolTip
) {
2323 NMTOOLTIPSCREATED nmttc
;
2325 nmttc
.hdr
.hwndFrom
= hwnd
;
2326 nmttc
.hdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
2327 nmttc
.hdr
.code
= NM_TOOLTIPSCREATED
;
2328 nmttc
.hwndToolTips
= infoPtr
->hwndToolTip
;
2330 SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
2331 (WPARAM
) GetWindowLongA( hwnd
, GWL_ID
), (LPARAM
)&nmttc
);
2334 ZeroMemory (&ti
, sizeof(TTTOOLINFOA
));
2335 ti
.cbSize
= sizeof(TTTOOLINFOA
);
2336 ti
.uFlags
= TTF_IDISHWND
| TTF_TRACK
| TTF_TRANSPARENT
;
2339 ti
.lpszText
= "Test"; /* LPSTR_TEXTCALLBACK; */
2340 SetRectEmpty (&ti
.rect
);
2342 SendMessageA (infoPtr
->hwndToolTip
, TTM_ADDTOOLA
, 0, (LPARAM
)&ti
);
2345 infoPtr
->hwndEdit
= CreateWindowExA (
2349 WS_CHILD
| WS_BORDER
| ES_AUTOHSCROLL
|
2350 ES_WANTRETURN
| ES_LEFT
,
2353 0,0,0); /* FIXME: (HMENU)IDTVEDIT,pcs->hInstance,0);*/
2355 SendMessageA ( infoPtr
->hwndEdit
, WM_SETFONT
, infoPtr
->hFont
, FALSE
);
2356 infoPtr
->wpEditOrig
= (WNDPROC
)SetWindowLongA (
2359 (LONG
) TREEVIEW_Edit_SubclassProc
);
2361 if (dwStyle
& TVS_CHECKBOXES
) {
2365 infoPtr
->himlState
=
2366 ImageList_Create (16, 16,ILC_COLOR
|ILC_MASK
, 15, 1);
2368 hbmLoad
= LoadBitmapA (COMCTL32_hModule
, MAKEINTRESOURCEA(IDT_CHECK
));
2369 TRACE ("%x\n",hbmLoad
);
2370 nIndex
= ImageList_AddMasked (infoPtr
->himlState
, hbmLoad
, CLR_DEFAULT
);
2371 TRACE ("%d\n",nIndex
);
2372 DeleteObject (hbmLoad
);
2374 ReleaseDC (hwnd
, hdc
);
2381 TREEVIEW_Destroy (HWND hwnd
)
2383 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2386 TREEVIEW_RemoveTree (hwnd
);
2387 SetWindowLongA (hwnd
, 0, (DWORD
)NULL
);
2389 if (infoPtr
->Timer
& TV_REFRESH_TIMER_SET
)
2390 KillTimer (hwnd
, TV_REFRESH_TIMER
);
2391 if (infoPtr
->hwndToolTip
)
2392 DestroyWindow (infoPtr
->hwndToolTip
);
2394 COMCTL32_Free (infoPtr
);
2400 TREEVIEW_Paint (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2406 hdc
= wParam
==0 ? BeginPaint (hwnd
, &ps
) : (HDC
)wParam
;
2407 TREEVIEW_Refresh (hwnd
, hdc
);
2408 ReleaseDC(hwnd
,hdc
);
2409 if(!wParam
) EndPaint (hwnd
, &ps
);
2412 return DefWindowProcA (hwnd
, WM_PAINT
, wParam
, lParam
);
2416 TREEVIEW_SetFocus (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2418 TREEVIEW_SendSimpleNotify (hwnd
, NM_SETFOCUS
);
2419 InvalidateRect(hwnd
, NULL
, FALSE
);
2424 TREEVIEW_KillFocus (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2426 TREEVIEW_SendSimpleNotify (hwnd
, NM_KILLFOCUS
);
2427 InvalidateRect(hwnd
, NULL
, FALSE
);
2432 TREEVIEW_EraseBackground (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2434 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2435 HBRUSH hBrush
= CreateSolidBrush (infoPtr
->clrBk
);
2439 GetClientRect (hwnd
, &rect
);
2440 FillRect ((HDC
)wParam
, &rect
, hBrush
);
2441 DeleteObject (hBrush
);
2457 TREEVIEW_SendSimpleNotify (HWND hwnd
, UINT code
)
2462 nmhdr
.hwndFrom
= hwnd
;
2463 nmhdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
2466 return (BOOL
) SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
2467 (WPARAM
)nmhdr
.idFrom
, (LPARAM
)&nmhdr
);
2473 TREEVIEW_SendTreeviewNotify (HWND hwnd
, UINT code
, UINT action
,
2474 HTREEITEM oldItem
, HTREEITEM newItem
)
2477 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2479 TREEVIEW_ITEM
*wineItem
;
2481 TRACE("code:%x action:%x olditem:%x newitem:%x\n",
2482 code
,action
,(INT
)oldItem
,(INT
)newItem
);
2483 nmhdr
.hdr
.hwndFrom
= hwnd
;
2484 nmhdr
.hdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
2485 nmhdr
.hdr
.code
= code
;
2486 nmhdr
.action
= action
;
2488 wineItem
=& infoPtr
->items
[(INT
)oldItem
];
2489 nmhdr
.itemOld
.mask
= wineItem
->mask
;
2490 nmhdr
.itemOld
.hItem
= wineItem
->hItem
;
2491 nmhdr
.itemOld
.state
= wineItem
->state
;
2492 nmhdr
.itemOld
.stateMask
= wineItem
->stateMask
;
2493 nmhdr
.itemOld
.iImage
= wineItem
->iImage
;
2494 nmhdr
.itemOld
.pszText
= wineItem
->pszText
;
2495 nmhdr
.itemOld
.cchTextMax
= wineItem
->cchTextMax
;
2496 nmhdr
.itemOld
.iImage
= wineItem
->iImage
;
2497 nmhdr
.itemOld
.iSelectedImage
= wineItem
->iSelectedImage
;
2498 nmhdr
.itemOld
.cChildren
= wineItem
->cChildren
;
2499 nmhdr
.itemOld
.lParam
= wineItem
->lParam
;
2503 wineItem
=& infoPtr
->items
[(INT
)newItem
];
2504 nmhdr
.itemNew
.mask
= wineItem
->mask
;
2505 nmhdr
.itemNew
.hItem
= wineItem
->hItem
;
2506 nmhdr
.itemNew
.state
= wineItem
->state
;
2507 nmhdr
.itemNew
.stateMask
= wineItem
->stateMask
;
2508 nmhdr
.itemNew
.iImage
= wineItem
->iImage
;
2509 nmhdr
.itemNew
.pszText
= wineItem
->pszText
;
2510 nmhdr
.itemNew
.cchTextMax
= wineItem
->cchTextMax
;
2511 nmhdr
.itemNew
.iImage
= wineItem
->iImage
;
2512 nmhdr
.itemNew
.iSelectedImage
= wineItem
->iSelectedImage
;
2513 nmhdr
.itemNew
.cChildren
= wineItem
->cChildren
;
2514 nmhdr
.itemNew
.lParam
= wineItem
->lParam
;
2520 return (BOOL
)SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
2521 (WPARAM
) GetWindowLongA( hwnd
, GWL_ID
), (LPARAM
)&nmhdr
);
2526 TREEVIEW_SendTreeviewDnDNotify (HWND hwnd
, UINT code
, HTREEITEM dragItem
,
2529 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2531 TREEVIEW_ITEM
*wineItem
;
2533 TRACE("code:%x dragitem:%x\n", code
,(INT
)dragItem
);
2535 nmhdr
.hdr
.hwndFrom
= hwnd
;
2536 nmhdr
.hdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
2537 nmhdr
.hdr
.code
= code
;
2539 wineItem
=& infoPtr
->items
[(INT
)dragItem
];
2540 nmhdr
.itemNew
.mask
= wineItem
->mask
;
2541 nmhdr
.itemNew
.hItem
= wineItem
->hItem
;
2542 nmhdr
.itemNew
.state
= wineItem
->state
;
2543 nmhdr
.itemNew
.lParam
= wineItem
->lParam
;
2545 nmhdr
.ptDrag
.x
= pt
.x
;
2546 nmhdr
.ptDrag
.y
= pt
.y
;
2548 return (BOOL
)SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
2549 (WPARAM
) GetWindowLongA( hwnd
, GWL_ID
), (LPARAM
)&nmhdr
);
2556 TREEVIEW_SendDispInfoNotify (HWND hwnd
, TREEVIEW_ITEM
*wineItem
,
2557 UINT code
, UINT what
)
2563 TRACE("item %d, action %x, state %d\n",
2564 (INT
)wineItem
->hItem
,
2566 (INT
)wineItem
->state
);
2568 tvdi
.hdr
.hwndFrom
= hwnd
;
2569 tvdi
.hdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
2570 tvdi
.hdr
.code
= code
;
2571 tvdi
.item
.mask
= what
;
2572 tvdi
.item
.hItem
= wineItem
->hItem
;
2573 tvdi
.item
.state
= wineItem
->state
;
2574 tvdi
.item
.lParam
= wineItem
->lParam
;
2575 tvdi
.item
.pszText
= COMCTL32_Alloc (128*sizeof(char));
2576 tvdi
.item
.cchTextMax
= 128;
2577 buf
= tvdi
.item
.pszText
;
2579 retval
=(BOOL
)SendMessageA (
2582 (WPARAM
)tvdi
.hdr
.idFrom
,
2585 if (what
& TVIF_TEXT
) {
2586 wineItem
->pszText
= tvdi
.item
.pszText
;
2587 if (buf
==tvdi
.item
.pszText
) {
2588 wineItem
->cchTextMax
= 128;
2590 TRACE("user-supplied buffer\n");
2591 COMCTL32_Free (buf
);
2592 wineItem
->cchTextMax
= 0;
2595 if (what
& TVIF_SELECTEDIMAGE
)
2596 wineItem
->iSelectedImage
= tvdi
.item
.iSelectedImage
;
2597 if (what
& TVIF_IMAGE
)
2598 wineItem
->iImage
= tvdi
.item
.iImage
;
2599 if (what
& TVIF_CHILDREN
)
2600 wineItem
->cChildren
= tvdi
.item
.cChildren
;
2608 TREEVIEW_SendCustomDrawNotify (HWND hwnd
, DWORD dwDrawStage
, HDC hdc
,
2611 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2612 NMTVCUSTOMDRAW nmcdhdr
;
2613 LPNMCUSTOMDRAW nmcd
;
2615 TRACE("drawstage:%lx hdc:%x\n", dwDrawStage
, hdc
);
2617 nmcd
= & nmcdhdr
.nmcd
;
2618 nmcd
->hdr
.hwndFrom
= hwnd
;
2619 nmcd
->hdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
2620 nmcd
->hdr
.code
= NM_CUSTOMDRAW
;
2621 nmcd
->dwDrawStage
= dwDrawStage
;
2623 nmcd
->rc
.left
= rc
.left
;
2624 nmcd
->rc
.right
= rc
.right
;
2625 nmcd
->rc
.bottom
= rc
.bottom
;
2626 nmcd
->rc
.top
= rc
.top
;
2627 nmcd
->dwItemSpec
= 0;
2628 nmcd
->uItemState
= 0;
2629 nmcd
->lItemlParam
= 0;
2630 nmcdhdr
.clrText
= infoPtr
->clrText
;
2631 nmcdhdr
.clrTextBk
= infoPtr
->clrBk
;
2634 return (BOOL
)SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
2635 (WPARAM
) GetWindowLongA( hwnd
, GWL_ID
), (LPARAM
)&nmcdhdr
);
2641 /* FIXME: need to find out when the flags in uItemState need to be set */
2644 TREEVIEW_SendCustomDrawItemNotify (HWND hwnd
, HDC hdc
,
2645 TREEVIEW_ITEM
*wineItem
, UINT uItemDrawState
)
2647 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2648 NMTVCUSTOMDRAW nmcdhdr
;
2649 LPNMCUSTOMDRAW nmcd
;
2650 DWORD dwDrawStage
,dwItemSpec
;
2654 dwDrawStage
=CDDS_ITEM
| uItemDrawState
;
2655 dwItemSpec
=(DWORD
)wineItem
->hItem
;
2657 if (wineItem
->hItem
==infoPtr
->selectedItem
) uItemState
|=CDIS_SELECTED
;
2658 if (wineItem
->hItem
==infoPtr
->focusItem
) uItemState
|=CDIS_FOCUS
;
2659 if (wineItem
->hItem
==infoPtr
->hotItem
) uItemState
|=CDIS_HOT
;
2661 nmcd
= & nmcdhdr
.nmcd
;
2662 nmcd
->hdr
.hwndFrom
= hwnd
;
2663 nmcd
->hdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
2664 nmcd
->hdr
.code
= NM_CUSTOMDRAW
;
2665 nmcd
->dwDrawStage
= dwDrawStage
;
2667 nmcd
->rc
.left
= wineItem
->rect
.left
;
2668 nmcd
->rc
.right
= wineItem
->rect
.right
;
2669 nmcd
->rc
.bottom
= wineItem
->rect
.bottom
;
2670 nmcd
->rc
.top
= wineItem
->rect
.top
;
2671 nmcd
->dwItemSpec
= dwItemSpec
;
2672 nmcd
->uItemState
= uItemState
;
2673 nmcd
->lItemlParam
= wineItem
->lParam
;
2674 nmcdhdr
.clrText
= infoPtr
->clrText
;
2675 nmcdhdr
.clrTextBk
= infoPtr
->clrBk
;
2676 nmcdhdr
.iLevel
= wineItem
->iLevel
;
2678 TRACE("drawstage:%lx hdc:%x item:%lx, itemstate:%x, lItemlParam:%lx\n",
2679 nmcd
->dwDrawStage
, nmcd
->hdc
, nmcd
->dwItemSpec
,
2680 nmcd
->uItemState
, nmcd
->lItemlParam
);
2682 retval
=SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
2683 (WPARAM
) GetWindowLongA( hwnd
, GWL_ID
), (LPARAM
)&nmcdhdr
);
2685 infoPtr
->clrText
=nmcdhdr
.clrText
;
2686 infoPtr
->clrBk
=nmcdhdr
.clrTextBk
;
2687 return (BOOL
) retval
;
2692 /* Note:If the specified item is the child of a collapsed parent item,
2693 the parent's list of child items is (recursively) expanded to reveal the
2694 specified item. This is mentioned for TREEVIEW_SelectItem; don't
2695 know if it also applies here.
2699 TREEVIEW_Expand (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2701 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2702 TREEVIEW_ITEM
*wineItem
;
2706 flag
= (UINT
) wParam
;
2707 expand
= (INT
) lParam
;
2709 wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)expand
);
2713 if (!wineItem
->cChildren
)
2716 if (wineItem
->pszText
==LPSTR_TEXTCALLBACKA
)
2717 TRACE ("For item %d, flags %d, state %d\n",
2718 expand
, flag
, wineItem
->state
);
2720 TRACE("For (%s) item:%d, flags %x, state:%d\n",
2721 wineItem
->pszText
, flag
, expand
, wineItem
->state
);
2723 if (wineItem
->cChildren
==I_CHILDRENCALLBACK
) {
2724 FIXME("we don't handle I_CHILDRENCALLBACK yet\n");
2728 if (flag
== TVE_TOGGLE
) { /* FIXME: check exact behaviour here */
2729 flag
&= ~TVE_TOGGLE
; /* ie: bitwise ops or 'case' ops */
2730 if (wineItem
->state
& TVIS_EXPANDED
)
2731 flag
|= TVE_COLLAPSE
;
2738 case TVE_COLLAPSERESET
:
2739 TRACE(" case TVE_COLLAPSERESET\n");
2740 if (!wineItem
->state
& TVIS_EXPANDED
)
2743 wineItem
->state
&= ~(TVIS_EXPANDEDONCE
| TVIS_EXPANDED
);
2744 TREEVIEW_RemoveAllChildren (hwnd
, wineItem
);
2748 TRACE(" case TVE_COLLAPSE\n");
2749 if (!wineItem
->state
& TVIS_EXPANDED
)
2752 wineItem
->state
&= ~TVIS_EXPANDED
;
2756 TRACE(" case TVE_EXPAND\n");
2757 if (wineItem
->state
& TVIS_EXPANDED
)
2760 TRACE(" is not expanded...\n");
2762 if (!(wineItem
->state
& TVIS_EXPANDEDONCE
))
2764 TRACE(" and has never been expanded...\n");
2765 wineItem
->state
|= TVIS_EXPANDED
;
2767 /* this item has never been expanded */
2768 if (TREEVIEW_SendTreeviewNotify (
2775 TRACE(" TVN_ITEMEXPANDINGA returned TRUE, exiting...\n");
2780 * Since the TVN_ITEMEXPANDINGA message may has caused the parent to
2781 * insert new items which in turn may have cause items placeholder
2782 * reallocation, I reassign the current item pointer so we have
2783 * something valid to work with...
2784 * However, this should not be necessary,
2785 * investigation required in TREEVIEW_InsertItemA
2787 wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)expand
);
2791 "Catastropic situation, cannot retreive item #%d\n",
2796 wineItem
->state
|= TVIS_EXPANDEDONCE
;
2797 TRACE(" TVN_ITEMEXPANDINGA sent...\n");
2799 TREEVIEW_SendTreeviewNotify (
2806 TRACE(" TVN_ITEMEXPANDEDA sent...\n");
2811 /* this item has already been expanded */
2812 wineItem
->state
|= TVIS_EXPANDED
;
2816 case TVE_EXPANDPARTIAL
:
2817 TRACE(" case TVE_EXPANDPARTIAL\n");
2818 FIXME("TVE_EXPANDPARTIAL not implemented\n");
2819 wineItem
->state
^=TVIS_EXPANDED
;
2820 wineItem
->state
|=TVIS_EXPANDEDONCE
;
2824 TRACE("Exiting, Item %d state is now %d...\n",
2828 TREEVIEW_QueueRefresh (hwnd
);
2834 static TREEVIEW_ITEM
*
2835 TREEVIEW_HitTestPoint (HWND hwnd
, POINT pt
)
2837 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2838 TREEVIEW_ITEM
*wineItem
;
2841 GetClientRect (hwnd
, &rect
);
2843 if (!infoPtr
->firstVisible
) return NULL
;
2845 wineItem
=&infoPtr
->items
[(INT
)infoPtr
->firstVisible
];
2847 while ((wineItem
!=NULL
) && (pt
.y
> wineItem
->rect
.bottom
))
2848 wineItem
=TREEVIEW_GetNextListItem (infoPtr
,wineItem
);
2860 TREEVIEW_HitTest (HWND hwnd
, LPARAM lParam
)
2862 LPTVHITTESTINFO lpht
=(LPTVHITTESTINFO
) lParam
;
2863 TREEVIEW_ITEM
*wineItem
;
2867 GetClientRect (hwnd
, &rect
);
2871 if (x
< rect
.left
) status
|=TVHT_TOLEFT
;
2872 if (x
> rect
.right
) status
|=TVHT_TORIGHT
;
2873 if (y
< rect
.top
) status
|=TVHT_ABOVE
;
2874 if (y
> rect
.bottom
) status
|=TVHT_BELOW
;
2881 wineItem
=TREEVIEW_HitTestPoint (hwnd
, lpht
->pt
);
2883 lpht
->flags
=TVHT_NOWHERE
;
2889 if (x
< wineItem
->expandBox
.left
) {
2890 lpht
->flags
|= TVHT_ONITEMINDENT
;
2893 if ( PtInRect ( &wineItem
->expandBox
, lpht
->pt
)) {
2894 lpht
->flags
|= TVHT_ONITEMBUTTON
;
2897 if ( PtInRect ( &wineItem
->bitmap
, lpht
->pt
)) {
2898 lpht
->flags
|= TVHT_ONITEMICON
;
2901 if ( PtInRect ( &wineItem
->statebitmap
, lpht
->pt
)) {
2902 lpht
->flags
|= TVHT_ONITEMSTATEICON
;
2905 if ( PtInRect ( &wineItem
->text
, lpht
->pt
)) {
2906 lpht
->flags
|= TVHT_ONITEMLABEL
;
2910 lpht
->flags
|=TVHT_ONITEMRIGHT
;
2914 lpht
->hItem
=wineItem
->hItem
;
2915 TRACE ("(%ld,%ld):result %x\n",lpht
->pt
.x
,lpht
->pt
.y
,lpht
->flags
);
2917 return (LRESULT
) wineItem
->hItem
;
2921 TREEVIEW_EndEditLabelNow (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2923 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2924 TREEVIEW_ITEM
*editedItem
= TREEVIEW_ValidItem (infoPtr
, infoPtr
->editItem
);
2925 BOOL bRevert
= (BOOL
)wParam
;
2926 BOOL bReturn
= ! bRevert
;
2928 if ( ! (BOOL
)wParam
) /* wParam is set to true to cancel the edition */
2930 if ( TREEVIEW_SendDispInfoNotify( /* return true to cancel edition */
2941 if (bRevert
== FALSE
) /* Apply the changes */
2944 int iLength
= GetWindowTextA(infoPtr
->hwndEdit
, tmpText
, 1023);
2949 ERR("Problem retreiving new item label.");
2951 else if (iLength
>= 1023)
2954 "Insuficient space to retrieve new item label, new label ignored.");
2958 if (strcmp( tmpText
, editedItem
->pszText
) == 0)
2959 /* Do nothing if the label has not changed */
2963 LPSTR tmpLabel
= COMCTL32_Alloc( iLength
+1 );
2965 if ( tmpLabel
== NULL
)
2967 "OutOfMemory, cannot allocate space for label");
2970 COMCTL32_Free(editedItem
->pszText
);
2971 editedItem
->pszText
= tmpLabel
;
2972 lstrcpyA( editedItem
->pszText
, tmpText
);
2978 ShowWindow(infoPtr
->hwndEdit
, SW_HIDE
);
2979 EnableWindow(infoPtr
->hwndEdit
, FALSE
);
2980 infoPtr
->editItem
= 0;
2989 TREEVIEW_LButtonDoubleClick (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2991 TREEVIEW_ITEM
*wineItem
;
2995 pt
.x
= (INT
)LOWORD(lParam
);
2996 pt
.y
= (INT
)HIWORD(lParam
);
2999 wineItem
=TREEVIEW_HitTestPoint (hwnd
, pt
);
3000 if (!wineItem
) return 0;
3001 TRACE("item %d \n",(INT
)wineItem
->hItem
);
3003 if (TREEVIEW_SendSimpleNotify (hwnd
, NM_DBLCLK
)!=TRUE
) { /* FIXME!*/
3004 TREEVIEW_Expand (hwnd
, (WPARAM
) TVE_TOGGLE
, (LPARAM
) wineItem
->hItem
);
3011 TREEVIEW_LButtonDown (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3013 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3017 ht
.pt
.x
= (INT
)LOWORD(lParam
);
3018 ht
.pt
.y
= (INT
)HIWORD(lParam
);
3021 iItem
=TREEVIEW_HitTest (hwnd
, (LPARAM
) &ht
);
3022 TRACE("item %d \n",iItem
);
3024 if (ht
.flags
& TVHT_ONITEMBUTTON
) {
3025 TREEVIEW_Expand (hwnd
, (WPARAM
) TVE_TOGGLE
, (LPARAM
) iItem
);
3029 infoPtr
->uInternalStatus
|=TV_LDRAG
;
3036 TREEVIEW_LButtonUp (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3038 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3040 TREEVIEW_ITEM
*wineItem
;
3043 ht
.pt
.x
= (INT
)LOWORD(lParam
);
3044 ht
.pt
.y
= (INT
)HIWORD(lParam
);
3048 /* Return true to cancel default behaviour */
3049 if ( TREEVIEW_SendSimpleNotify (hwnd
, NM_CLICK
) )
3053 iItem
= TREEVIEW_HitTest (hwnd
, (LPARAM
) &ht
);
3054 TRACE ("%d\n",iItem
);
3058 wineItem
= TREEVIEW_ValidItem(infoPtr
, (HTREEITEM
)iItem
);
3060 infoPtr
->uInternalStatus
&= ~(TV_LDRAG
| TV_LDRAGGING
);
3063 * If the style allow editing and the node is already selected
3064 * and the click occured on the item label...
3066 if ( ( GetWindowLongA( hwnd
, GWL_STYLE
) & TVS_EDITLABELS
) &&
3067 ( wineItem
->state
& TVIS_SELECTED
) &&
3068 ( ht
.flags
& TVHT_ONITEMLABEL
))
3070 if ( infoPtr
->editItem
== 0 ) /* If we are not curently editing */
3072 if ( TREEVIEW_SendDispInfoNotify( /* Return true to cancel edition */
3075 TVN_BEGINLABELEDITA
,
3081 TRACE("Edit started for %s.\n", wineItem
->pszText
);
3082 infoPtr
->editItem
= wineItem
->hItem
;
3087 wineItem
->text
.left
- 2,
3088 wineItem
->text
.top
- 1,
3089 wineItem
->text
.right
- wineItem
->text
.left
+ 20 ,
3090 wineItem
->text
.bottom
- wineItem
->text
.top
+ 3,
3093 SetWindowTextA( infoPtr
->hwndEdit
, wineItem
->pszText
);
3094 SendMessageA ( infoPtr
->hwndEdit
, EM_SETSEL
, 0, -1 );
3095 SetFocus ( infoPtr
->hwndEdit
);
3096 ShowWindow ( infoPtr
->hwndEdit
, SW_SHOW
);
3099 else if ( infoPtr
->editItem
!= 0 ) /* If we are curently editing */
3101 TREEVIEW_EndEditLabelNow(hwnd
, (WPARAM
)FALSE
, 0);
3103 else if ( ht
.flags
& (TVHT_ONITEMLABEL
| TVHT_ONITEMICON
))
3105 TREEVIEW_DoSelectItem ( hwnd
, TVGN_CARET
, (HTREEITEM
)iItem
, TVC_BYMOUSE
);
3108 if (ht
.flags
& TVHT_ONITEMSTATEICON
) {
3109 DWORD dwStyle
= GetWindowLongA (hwnd
, GWL_STYLE
);
3112 if (dwStyle
& TVS_CHECKBOXES
) { /* TVS_CHECKBOXES requires _us_ */
3113 int state
; /* to toggle the current state */
3114 state
=1-(wineItem
->state
>>12);
3115 TRACE ("state:%x\n", state
);
3116 wineItem
->state
&= ~TVIS_STATEIMAGEMASK
;
3117 wineItem
->state
|=state
<<12;
3118 TRACE ("state:%x\n", wineItem
->state
);
3119 TREEVIEW_QueueRefresh (hwnd
);
3127 TREEVIEW_RButtonDown (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3129 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3132 infoPtr
->uInternalStatus
|=TV_RDRAG
;
3137 TREEVIEW_RButtonUp (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3139 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3142 if (TREEVIEW_SendSimpleNotify (hwnd
, NM_RCLICK
)) return 0;
3143 infoPtr
->uInternalStatus
&= ~(TV_RDRAG
| TV_RDRAGGING
);
3149 TREEVIEW_MouseMove (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3151 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3152 TREEVIEW_ITEM
*hotItem
;
3155 pt
.x
=(INT
) LOWORD (lParam
);
3156 pt
.y
=(INT
) HIWORD (lParam
);
3157 hotItem
=TREEVIEW_HitTestPoint (hwnd
, pt
);
3158 if (!hotItem
) return 0;
3159 infoPtr
->focusItem
=hotItem
->hItem
;
3161 if ( GetWindowLongA( hwnd
, GWL_STYLE
) & TVS_DISABLEDRAGDROP
) return 0;
3163 if (infoPtr
->uInternalStatus
& TV_LDRAG
) {
3164 TREEVIEW_SendTreeviewDnDNotify (hwnd
, TVN_BEGINDRAGA
, hotItem
->hItem
, pt
);
3165 infoPtr
->uInternalStatus
&= ~TV_LDRAG
;
3166 infoPtr
->uInternalStatus
|= TV_LDRAGGING
;
3167 infoPtr
->dropItem
=hotItem
->hItem
;
3171 if (infoPtr
->uInternalStatus
& TV_RDRAG
) {
3172 TREEVIEW_SendTreeviewDnDNotify (hwnd
, TVN_BEGINRDRAGA
, hotItem
->hItem
, pt
);
3173 infoPtr
->uInternalStatus
&= ~TV_RDRAG
;
3174 infoPtr
->uInternalStatus
|= TV_RDRAGGING
;
3175 infoPtr
->dropItem
=hotItem
->hItem
;
3184 TREEVIEW_CreateDragImage (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3186 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3187 TREEVIEW_ITEM
*dragItem
;
3191 HBITMAP hbmp
,hOldbmp
;
3198 if (!(infoPtr
->himlNormal
)) return 0;
3199 dragItem
=TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
) lParam
);
3201 if (!dragItem
) return 0;
3203 if (dragItem
->pszText
==LPSTR_TEXTCALLBACKA
) {
3204 TREEVIEW_SendDispInfoNotify (hwnd
, dragItem
, TVN_GETDISPINFOA
, TVIF_TEXT
);
3206 itemtxt
=dragItem
->pszText
;
3208 hwtop
=GetDesktopWindow ();
3209 htopdc
= GetDC (hwtop
);
3210 hdc
=CreateCompatibleDC (htopdc
);
3212 hOldFont
=SelectObject (hdc
, infoPtr
->hFont
);
3213 GetTextExtentPoint32A (hdc
, itemtxt
, lstrlenA (itemtxt
), &size
);
3214 TRACE("%d %d %s %d\n",size
.cx
,size
.cy
,itemtxt
,lstrlenA(itemtxt
));
3215 hbmp
=CreateCompatibleBitmap (htopdc
, size
.cx
, size
.cy
);
3216 hOldbmp
=SelectObject (hdc
, hbmp
);
3218 ImageList_GetIconSize (infoPtr
->himlNormal
, &cx
, &cy
);
3220 if (cy
>size
.cy
) size
.cy
=cy
;
3222 infoPtr
->dragList
=ImageList_Create (size
.cx
, size
.cy
, ILC_COLOR
, 10, 10);
3223 ImageList_Draw (infoPtr
->himlNormal
, dragItem
->iImage
, hdc
, 0, 0, ILD_NORMAL
);
3226 ImageList_GetImageInfo (infoPtr->himlNormal, dragItem->hItem, &iminfo);
3227 ImageList_AddMasked (infoPtr->dragList, iminfo.hbmImage, CLR_DEFAULT);
3230 /* draw item text */
3232 SetRect (&rc
, cx
, 0, size
.cx
,size
.cy
);
3233 DrawTextA (hdc
, itemtxt
, lstrlenA (itemtxt
), &rc
, DT_LEFT
);
3234 SelectObject (hdc
, hOldFont
);
3235 SelectObject (hdc
, hOldbmp
);
3237 ImageList_Add (infoPtr
->dragList
, hbmp
, 0);
3240 DeleteObject (hbmp
);
3241 ReleaseDC (hwtop
, htopdc
);
3243 return (LRESULT
)infoPtr
->dragList
;
3248 TREEVIEW_DoSelectItem (HWND hwnd
, INT action
, HTREEITEM newSelect
, INT cause
)
3251 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3252 TREEVIEW_ITEM
*prevItem
,*wineItem
;
3255 wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)newSelect
);
3257 TRACE("Entering item %d, flag %x, cause %x, state %d\n",
3263 if ( (wineItem
) && (wineItem
->parent
))
3266 * If the item has a collapse parent expand the parent so he
3267 * can expose the item
3269 TREEVIEW_ITEM
*parentItem
= TREEVIEW_ValidItem (infoPtr
, wineItem
->parent
);
3270 if ( !(parentItem
->state
& TVIS_EXPANDED
))
3271 TREEVIEW_Expand (hwnd
, TVE_EXPAND
, (LPARAM
) wineItem
->parent
);
3277 prevSelect
=(INT
)infoPtr
->selectedItem
;
3279 if ((HTREEITEM
)prevSelect
==newSelect
)
3282 prevItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)prevSelect
);
3285 if (TREEVIEW_SendTreeviewNotify(
3289 (HTREEITEM
)prevSelect
,
3290 (HTREEITEM
)newSelect
))
3291 return FALSE
; /* FIXME: OK? */
3294 prevItem
->state
&= ~TVIS_SELECTED
;
3296 wineItem
->state
|= TVIS_SELECTED
;
3298 infoPtr
->selectedItem
=(HTREEITEM
)newSelect
;
3300 TREEVIEW_SendTreeviewNotify(
3304 (HTREEITEM
)prevSelect
,
3305 (HTREEITEM
)newSelect
);
3309 case TVGN_DROPHILITE
:
3310 prevItem
= TREEVIEW_ValidItem (infoPtr
, infoPtr
->dropItem
);
3313 prevItem
->state
&= ~TVIS_DROPHILITED
;
3315 infoPtr
->dropItem
=(HTREEITEM
)newSelect
;
3318 wineItem
->state
|=TVIS_DROPHILITED
;
3322 case TVGN_FIRSTVISIBLE
:
3323 FIXME("FIRSTVISIBLE not implemented\n");
3327 TREEVIEW_QueueRefresh (hwnd
);
3329 TRACE("Leaving state %d\n", wineItem
->state
);
3333 /* FIXME: handle NM_KILLFocus etc */
3335 TREEVIEW_SelectItem (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3338 return TREEVIEW_DoSelectItem (hwnd
, wParam
, (HTREEITEM
) lParam
, TVC_UNKNOWN
);
3345 TREEVIEW_GetFont (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3348 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3350 TRACE("%x\n",infoPtr
->hFont
);
3351 return infoPtr
->hFont
;
3355 TREEVIEW_SetFont (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3358 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3361 HFONT hFont
, hOldFont
;
3365 TRACE("%x %lx\n",wParam
, lParam
);
3367 infoPtr
->hFont
= (HFONT
)wParam
;
3369 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: GetStockObject (SYSTEM_FONT
);
3371 GetObjectA (infoPtr
->hFont
, sizeof (LOGFONTA
), &logFont
);
3372 logFont
.lfWeight
=FW_BOLD
;
3373 infoPtr
->hBoldFont
= CreateFontIndirectA (&logFont
);
3376 hOldFont
= SelectObject (hdc
, hFont
);
3377 GetTextMetricsA (hdc
, &tm
);
3378 height
= tm
.tmHeight
+ tm
.tmExternalLeading
;
3379 if (height
>infoPtr
->uRealItemHeight
)
3380 infoPtr
->uRealItemHeight
=height
;
3381 SelectObject (hdc
, hOldFont
);
3385 TREEVIEW_QueueRefresh (hwnd
);
3393 TREEVIEW_VScroll (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3396 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3399 TRACE("wp %x, lp %lx\n", wParam
, lParam
);
3400 if (!infoPtr
->uInternalStatus
& TV_VSCROLL
) return FALSE
;
3402 switch (LOWORD (wParam
)) {
3404 if (!infoPtr
->cy
) return FALSE
;
3405 infoPtr
->cy
-= infoPtr
->uRealItemHeight
;
3406 if (infoPtr
->cy
< 0) infoPtr
->cy
=0;
3409 maxHeight
=infoPtr
->uTotalHeight
-infoPtr
->uVisibleHeight
;
3410 if (infoPtr
->cy
== maxHeight
) return FALSE
;
3411 infoPtr
->cy
+= infoPtr
->uRealItemHeight
;
3412 if (infoPtr
->cy
> maxHeight
)
3413 infoPtr
->cy
= maxHeight
;
3416 if (!infoPtr
->cy
) return FALSE
;
3417 infoPtr
->cy
-= infoPtr
->uVisibleHeight
;
3418 if (infoPtr
->cy
< 0) infoPtr
->cy
=0;
3421 maxHeight
=infoPtr
->uTotalHeight
-infoPtr
->uVisibleHeight
;
3422 if (infoPtr
->cy
== maxHeight
) return FALSE
;
3423 infoPtr
->cy
+= infoPtr
->uVisibleHeight
;
3424 if (infoPtr
->cy
> maxHeight
)
3425 infoPtr
->cy
= maxHeight
;
3428 infoPtr
->cy
= HIWORD (wParam
);
3433 TREEVIEW_QueueRefresh (hwnd
);
3438 TREEVIEW_HScroll (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3440 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3443 TRACE("wp %lx, lp %x\n", lParam
, wParam
);
3445 if (!infoPtr
->uInternalStatus
& TV_HSCROLL
) return FALSE
;
3447 switch (LOWORD (wParam
)) {
3449 if (!infoPtr
->cx
) return FALSE
;
3450 infoPtr
->cx
-= infoPtr
->uRealItemHeight
;
3451 if (infoPtr
->cx
< 0) infoPtr
->cx
=0;
3454 maxWidth
=infoPtr
->uTotalWidth
-infoPtr
->uVisibleWidth
;
3455 if (infoPtr
->cx
== maxWidth
) return FALSE
;
3456 infoPtr
->cx
+= infoPtr
->uRealItemHeight
; /*FIXME */
3457 if (infoPtr
->cx
> maxWidth
)
3458 infoPtr
->cx
= maxWidth
;
3461 if (!infoPtr
->cx
) return FALSE
;
3462 infoPtr
->cx
-= infoPtr
->uVisibleWidth
;
3463 if (infoPtr
->cx
< 0) infoPtr
->cx
=0;
3466 maxWidth
=infoPtr
->uTotalWidth
-infoPtr
->uVisibleWidth
;
3467 if (infoPtr
->cx
== maxWidth
) return FALSE
;
3468 infoPtr
->cx
+= infoPtr
->uVisibleWidth
;
3469 if (infoPtr
->cx
> maxWidth
)
3470 infoPtr
->cx
= maxWidth
;
3473 infoPtr
->cx
= HIWORD (wParam
);
3478 TREEVIEW_QueueRefresh (hwnd
);
3482 static LRESULT
TREEVIEW_MouseWheel (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3485 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3486 short gcWheelDelta
= 0;
3487 UINT pulScrollLines
= 3;
3489 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES
,0, &pulScrollLines
, 0);
3491 gcWheelDelta
-= (short) HIWORD(wParam
);
3492 pulScrollLines
*= (gcWheelDelta
/ WHEEL_DELTA
);
3494 if (abs(gcWheelDelta
) >= WHEEL_DELTA
&& pulScrollLines
)
3496 int wheelDy
= pulScrollLines
* infoPtr
->uRealItemHeight
;
3497 int newDy
= infoPtr
->cy
+ wheelDy
;
3498 int maxDy
= infoPtr
->uTotalHeight
- infoPtr
->uVisibleHeight
;
3500 if (newDy
> maxDy
) newDy
= maxDy
;
3501 if (newDy
< 0) newDy
= 0;
3503 if (newDy
== infoPtr
->cy
) return TRUE
;
3505 TREEVIEW_VScroll(hwnd
, MAKEWPARAM(SB_THUMBTRACK
,newDy
),0);
3511 TREEVIEW_KeyDown (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3513 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3514 HTREEITEM hNewSelection
= 0;
3515 INT scrollNeeds
= -1;
3516 INT cyChangeNeeds
= -1;
3517 INT prevSelect
= (INT
)infoPtr
->selectedItem
;
3519 TREEVIEW_ITEM
*prevItem
=
3520 (prevSelect
!= 0 ) ?
3521 TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)prevSelect
) :
3524 TREEVIEW_ITEM
*newItem
= NULL
;
3526 TRACE("%x %lx\n",wParam
, lParam
);
3528 if (prevSelect
== 0)
3533 newItem
=TREEVIEW_GetPrevListItem (infoPtr
, prevItem
);
3536 newItem
=& infoPtr
->items
[(INT
)infoPtr
->TopRootItem
];
3538 hNewSelection
= newItem
->hItem
;
3540 if (! newItem
->visible
)
3541 scrollNeeds
= SB_LINEUP
;
3545 newItem
=TREEVIEW_GetNextListItem (infoPtr
, prevItem
);
3550 hNewSelection
= newItem
->hItem
;
3552 if (! newItem
->visible
)
3553 scrollNeeds
= SB_LINEDOWN
;
3558 newItem
= &infoPtr
->items
[(INT
)infoPtr
->TopRootItem
];
3559 hNewSelection
= newItem
->hItem
;
3564 newItem
= &infoPtr
->items
[(INT
)infoPtr
->TopRootItem
];
3565 newItem
= TREEVIEW_GetLastListItem (infoPtr
, newItem
);
3566 hNewSelection
= newItem
->hItem
;
3568 if (! newItem
->visible
)
3569 cyChangeNeeds
= infoPtr
->uTotalHeight
-infoPtr
->uVisibleHeight
;
3574 if ( (prevItem
->cChildren
> 0) && (prevItem
->state
& TVIS_EXPANDED
) )
3576 TREEVIEW_Expand(hwnd
, TVE_COLLAPSE
, prevSelect
);
3578 else if ((INT
)prevItem
->parent
)
3580 newItem
= (& infoPtr
->items
[(INT
)prevItem
->parent
]);
3581 if (! newItem
->visible
)
3582 /* FIXME find a way to make this item the first visible... */
3585 hNewSelection
= newItem
->hItem
;
3591 if ( ( prevItem
->cChildren
> 0) ||
3592 ( prevItem
->cChildren
== I_CHILDRENCALLBACK
))
3594 if (! (prevItem
->state
& TVIS_EXPANDED
))
3595 TREEVIEW_Expand(hwnd
, TVE_EXPAND
, prevSelect
);
3598 newItem
= (& infoPtr
->items
[(INT
)prevItem
->firstChild
]);
3599 hNewSelection
= newItem
->hItem
;
3606 if (! (prevItem
->state
& TVIS_EXPANDED
))
3607 TREEVIEW_Expand(hwnd
, TVE_EXPAND
, prevSelect
);
3611 if (prevItem
->state
& TVIS_EXPANDED
)
3612 TREEVIEW_Expand(hwnd
, TVE_COLLAPSE
, prevSelect
);
3617 newItem
=TREEVIEW_GetListItem(
3620 -1*(TREEVIEW_GetVisibleCount(hwnd
,0,0)-3));
3624 hNewSelection
= newItem
->hItem
;
3626 if (! newItem
->visible
)
3627 scrollNeeds
= SB_PAGEUP
;
3632 newItem
=TREEVIEW_GetListItem(
3635 TREEVIEW_GetVisibleCount(hwnd
,0,0)-3);
3640 hNewSelection
= newItem
->hItem
;
3642 if (! newItem
->visible
)
3643 scrollNeeds
= SB_PAGEDOWN
;
3652 FIXME("%x not implemented\n", wParam
);
3659 This works but does not send notification...
3661 prevItem->state &= ~TVIS_SELECTED;
3662 newItem->state |= TVIS_SELECTED;
3663 infoPtr->selectedItem = hNewSelection;
3664 TREEVIEW_QueueRefresh (hwnd);
3667 if ( TREEVIEW_DoSelectItem(
3670 (HTREEITEM
)hNewSelection
,
3673 /* If selection change is allowed for the new item, perform scrolling */
3674 if (scrollNeeds
!= -1)
3675 TREEVIEW_VScroll(hwnd
, scrollNeeds
, 0);
3677 if (cyChangeNeeds
!= -1)
3678 infoPtr
->cy
= cyChangeNeeds
;
3680 /* FIXME: Something happen in the load the in the two weeks before
3681 april 1st 1999 which makes this SetFocus mandatory otherwise, the focus
3682 is lost... However the SetFocus should not be required...*/
3693 TREEVIEW_GetScrollTime (HWND hwnd
)
3695 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3697 return infoPtr
->uScrollTime
;
3702 TREEVIEW_SetScrollTime (HWND hwnd
, UINT uScrollTime
)
3704 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3705 UINT uOldScrollTime
= infoPtr
->uScrollTime
;
3707 infoPtr
->uScrollTime
= min (uScrollTime
, 100);
3709 return uOldScrollTime
;
3713 static LRESULT WINAPI
3714 TREEVIEW_WindowProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
3716 if (uMsg
==WM_CREATE
)
3717 return TREEVIEW_Create (hwnd
, wParam
, lParam
);
3719 if (!TREEVIEW_GetInfoPtr(hwnd
))
3720 return DefWindowProcA (hwnd
, uMsg
, wParam
, lParam
);
3724 case TVM_INSERTITEMA
:
3725 return TREEVIEW_InsertItemA (hwnd
, wParam
, lParam
);
3727 case TVM_INSERTITEMW
:
3728 return TREEVIEW_InsertItemW(hwnd
,wParam
,lParam
);;
3730 case TVM_DELETEITEM
:
3731 return TREEVIEW_DeleteItem (hwnd
, wParam
, lParam
);
3734 return TREEVIEW_Expand (hwnd
, wParam
, lParam
);
3736 case TVM_GETITEMRECT
:
3737 return TREEVIEW_GetItemRect (hwnd
, wParam
, lParam
);
3740 return TREEVIEW_GetCount (hwnd
, wParam
, lParam
);
3743 return TREEVIEW_GetIndent (hwnd
);
3746 return TREEVIEW_SetIndent (hwnd
, wParam
);
3748 case TVM_GETIMAGELIST
:
3749 return TREEVIEW_GetImageList (hwnd
, wParam
, lParam
);
3751 case TVM_SETIMAGELIST
:
3752 return TREEVIEW_SetImageList (hwnd
, wParam
, lParam
);
3754 case TVM_GETNEXTITEM
:
3755 return TREEVIEW_GetNextItem (hwnd
, wParam
, lParam
);
3757 case TVM_SELECTITEM
:
3758 return TREEVIEW_SelectItem (hwnd
, wParam
, lParam
);
3761 return TREEVIEW_GetItemA (hwnd
, wParam
, lParam
);
3764 FIXME("Unimplemented msg TVM_GETITEMW\n");
3768 return TREEVIEW_SetItemA (hwnd
, wParam
, lParam
);
3771 FIXME("Unimplemented msg TVM_SETITEMW\n");
3774 case TVM_EDITLABELA
:
3775 FIXME("Unimplemented msg TVM_EDITLABELA \n");
3778 case TVM_EDITLABELW
:
3779 FIXME("Unimplemented msg TVM_EDITLABELW \n");
3782 case TVM_GETEDITCONTROL
:
3783 return TREEVIEW_GetEditControl (hwnd
);
3785 case TVM_GETVISIBLECOUNT
:
3786 return TREEVIEW_GetVisibleCount (hwnd
, wParam
, lParam
);
3789 return TREEVIEW_HitTest (hwnd
, lParam
);
3791 case TVM_CREATEDRAGIMAGE
:
3792 return TREEVIEW_CreateDragImage (hwnd
, wParam
, lParam
);
3794 case TVM_SORTCHILDREN
:
3795 return TREEVIEW_SortChildren (hwnd
, wParam
, lParam
);
3797 case TVM_ENSUREVISIBLE
:
3798 FIXME("Unimplemented msg TVM_ENSUREVISIBLE\n");
3801 case TVM_SORTCHILDRENCB
:
3802 return TREEVIEW_SortChildrenCB(hwnd
, wParam
, lParam
);
3804 case TVM_ENDEDITLABELNOW
:
3805 return TREEVIEW_EndEditLabelNow (hwnd
, wParam
, lParam
);
3807 case TVM_GETISEARCHSTRINGA
:
3808 FIXME("Unimplemented msg TVM_GETISEARCHSTRINGA\n");
3811 case TVM_GETISEARCHSTRINGW
:
3812 FIXME("Unimplemented msg TVM_GETISEARCHSTRINGW\n");
3815 case TVM_GETTOOLTIPS
:
3816 return TREEVIEW_GetToolTips (hwnd
);
3818 case TVM_SETTOOLTIPS
:
3819 return TREEVIEW_SetToolTips (hwnd
, wParam
);
3821 case TVM_SETINSERTMARK
:
3822 return TREEVIEW_SetInsertMark (hwnd
,wParam
, lParam
);
3824 case TVM_SETITEMHEIGHT
:
3825 return TREEVIEW_SetItemHeight (hwnd
, wParam
);
3827 case TVM_GETITEMHEIGHT
:
3828 return TREEVIEW_GetItemHeight (hwnd
);
3830 case TVM_SETBKCOLOR
:
3831 return TREEVIEW_SetBkColor (hwnd
, wParam
, lParam
);
3833 case TVM_SETTEXTCOLOR
:
3834 return TREEVIEW_SetTextColor (hwnd
, wParam
, lParam
);
3836 case TVM_GETBKCOLOR
:
3837 return TREEVIEW_GetBkColor (hwnd
);
3839 case TVM_GETTEXTCOLOR
:
3840 return TREEVIEW_GetTextColor (hwnd
);
3842 case TVM_SETSCROLLTIME
:
3843 return TREEVIEW_SetScrollTime (hwnd
, (UINT
)wParam
);
3845 case TVM_GETSCROLLTIME
:
3846 return TREEVIEW_GetScrollTime (hwnd
);
3848 case TVM_GETITEMSTATE
:
3849 return TREEVIEW_GetItemState (hwnd
,wParam
, lParam
);
3851 case TVM_GETLINECOLOR
:
3852 return TREEVIEW_GetLineColor (hwnd
,wParam
, lParam
);
3854 case TVM_SETLINECOLOR
:
3855 return TREEVIEW_SetLineColor (hwnd
,wParam
, lParam
);
3857 case TVM_SETINSERTMARKCOLOR
:
3858 return TREEVIEW_SetInsertMarkColor (hwnd
,wParam
, lParam
);
3860 case TVM_GETINSERTMARKCOLOR
:
3861 return TREEVIEW_GetInsertMarkColor (hwnd
,wParam
, lParam
);
3863 case TVM_SETUNICODEFORMAT
:
3864 FIXME("Unimplemented msg TVM_SETUNICODEFORMAT\n");
3867 case TVM_GETUNICODEFORMAT
:
3868 FIXME("Unimplemented msg TVM_GETUNICODEFORMAT\n");
3872 return TREEVIEW_Command (hwnd
, wParam
, lParam
);
3875 return TREEVIEW_Destroy (hwnd
);
3877 /* case WM_ENABLE: */
3880 return TREEVIEW_EraseBackground (hwnd
, wParam
, lParam
);
3883 return DLGC_WANTARROWS
| DLGC_WANTCHARS
;
3886 return TREEVIEW_Paint (hwnd
, wParam
, lParam
);
3889 return TREEVIEW_GetFont (hwnd
, wParam
, lParam
);
3892 return TREEVIEW_SetFont (hwnd
, wParam
, lParam
);
3895 return TREEVIEW_KeyDown (hwnd
, wParam
, lParam
);
3898 return TREEVIEW_SetFocus (hwnd
, wParam
, lParam
);
3901 return TREEVIEW_KillFocus (hwnd
, wParam
, lParam
);
3903 case WM_LBUTTONDOWN
:
3904 return TREEVIEW_LButtonDown (hwnd
, wParam
, lParam
);
3907 return TREEVIEW_LButtonUp (hwnd
, wParam
, lParam
);
3909 case WM_LBUTTONDBLCLK
:
3910 return TREEVIEW_LButtonDoubleClick (hwnd
, wParam
, lParam
);
3912 case WM_RBUTTONDOWN
:
3913 return TREEVIEW_RButtonDown (hwnd
, wParam
, lParam
);
3916 return TREEVIEW_RButtonUp (hwnd
, wParam
, lParam
);
3919 return TREEVIEW_MouseMove (hwnd
, wParam
, lParam
);
3921 case WM_STYLECHANGED
:
3922 return TREEVIEW_StyleChanged (hwnd
, wParam
, lParam
);
3924 /* case WM_SYSCOLORCHANGE: */
3925 /* case WM_SETREDRAW: */
3928 return TREEVIEW_HandleTimer (hwnd
, wParam
, lParam
);
3931 return TREEVIEW_Size (hwnd
, wParam
,lParam
);
3934 return TREEVIEW_HScroll (hwnd
, wParam
, lParam
);
3936 return TREEVIEW_VScroll (hwnd
, wParam
, lParam
);
3939 if (wParam
& (MK_SHIFT
| MK_CONTROL
))
3940 return DefWindowProcA( hwnd
, uMsg
, wParam
, lParam
);
3941 return TREEVIEW_MouseWheel (hwnd
, wParam
, lParam
);
3944 TRACE ("drawItem\n");
3945 return DefWindowProcA (hwnd
, uMsg
, wParam
, lParam
);
3948 if (uMsg
>= WM_USER
)
3949 FIXME("Unknown msg %04x wp=%08x lp=%08lx\n",
3950 uMsg
, wParam
, lParam
);
3951 return DefWindowProcA (hwnd
, uMsg
, wParam
, lParam
);
3958 TREEVIEW_Register (void)
3964 ZeroMemory (&wndClass
, sizeof(WNDCLASSA
));
3965 wndClass
.style
= CS_GLOBALCLASS
| CS_DBLCLKS
;
3966 wndClass
.lpfnWndProc
= (WNDPROC
)TREEVIEW_WindowProc
;
3967 wndClass
.cbClsExtra
= 0;
3968 wndClass
.cbWndExtra
= sizeof(TREEVIEW_INFO
*);
3969 wndClass
.hCursor
= LoadCursorA (0, IDC_ARROWA
);
3970 wndClass
.hbrBackground
= 0;
3971 wndClass
.lpszClassName
= WC_TREEVIEWA
;
3973 RegisterClassA (&wndClass
);
3978 TREEVIEW_Unregister (void)
3980 UnregisterClassA (WC_TREEVIEWA
, (HINSTANCE
)NULL
);