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;
1079 infoPtr
->cdmode
=TREEVIEW_SendCustomDrawNotify(hwnd
,CDDS_PREPAINT
,hdc
,rect
);
1081 if (infoPtr
->cdmode
==CDRF_SKIPDEFAULT
) return;
1083 infoPtr
->uVisibleHeight
= rect
.bottom
-rect
.top
;
1084 infoPtr
->uVisibleWidth
= rect
.right
-rect
.left
;
1086 viewtop
=infoPtr
->cy
;
1087 viewbottom
=infoPtr
->cy
+ rect
.bottom
-rect
.top
;
1088 viewleft
=infoPtr
->cx
;
1089 viewright
=infoPtr
->cx
+ rect
.right
-rect
.left
;
1091 TRACE("[%d %d %d %d]\n",viewtop
,viewbottom
,viewleft
,viewright
);
1093 /* draw background */
1095 hbrBk
= CreateSolidBrush (infoPtr
->clrBk
);
1096 FillRect(hdc
, &rect
, hbrBk
);
1097 DeleteObject(hbrBk
);
1099 ImageList_GetIconSize (infoPtr
->himlNormal
, &x
, &itemHeight
);
1100 if (infoPtr
->uItemHeight
>itemHeight
)
1101 itemHeight
=infoPtr
->uItemHeight
;
1103 GetTextMetricsA (hdc
, &tm
);
1104 if ((tm
.tmHeight
+ tm
.tmExternalLeading
) > itemHeight
)
1105 itemHeight
=tm
.tmHeight
+ tm
.tmExternalLeading
;
1107 infoPtr
->uRealItemHeight
=itemHeight
;
1109 iItem
=(INT
)infoPtr
->TopRootItem
;
1110 infoPtr
->firstVisible
=0;
1117 wineItem
= & infoPtr
->items
[iItem
];
1118 wineItem
->iLevel
=indent
;
1120 /* FIXME: remove this in later stage */
1122 if (wineItem->pszText!=LPSTR_TEXTCALLBACK32A)
1123 TRACE (treeview, "%d %d [%d %d %d %d] (%s)\n",y,x,
1124 wineItem->rect.top, wineItem->rect.bottom,
1125 wineItem->rect.left, wineItem->rect.right,
1128 TRACE (treeview, "%d [%d %d %d %d] (CALLBACK)\n",
1130 wineItem->rect.top, wineItem->rect.bottom,
1131 wineItem->rect.left, wineItem->rect.right);
1134 height
=itemHeight
* wineItem
->iIntegral
+1;
1135 if ((y
>= viewtop
) && (y
<= viewbottom
) &&
1136 (x
>= viewleft
) && (x
<= viewright
)) {
1137 wineItem
->visible
= TRUE
;
1138 wineItem
->rect
.top
= y
- infoPtr
->cy
+ rect
.top
;
1139 wineItem
->rect
.bottom
= wineItem
->rect
.top
+ height
;
1140 wineItem
->rect
.left
= x
- infoPtr
->cx
+ rect
.left
;
1141 wineItem
->rect
.right
= rect
.right
;
1142 if (!infoPtr
->firstVisible
)
1143 infoPtr
->firstVisible
=wineItem
->hItem
;
1144 TREEVIEW_DrawItem (hwnd
, hdc
, wineItem
);
1147 wineItem
->visible
= FALSE
;
1148 wineItem
->rect
.left
= wineItem
->rect
.top
= 0;
1149 wineItem
->rect
.right
= wineItem
->rect
.bottom
= 0;
1150 wineItem
->text
.left
= wineItem
->text
.top
= 0;
1151 wineItem
->text
.right
= wineItem
->text
.bottom
= 0;
1154 /* look up next item */
1156 if ((wineItem
->firstChild
) && (wineItem
->state
& TVIS_EXPANDED
)) {
1157 iItem
=(INT
)wineItem
->firstChild
;
1159 x
+=infoPtr
->uIndent
;
1160 if (x
>infoPtr
->uTotalWidth
)
1161 infoPtr
->uTotalWidth
=x
;
1164 iItem
=(INT
)wineItem
->sibling
;
1165 while ((!iItem
) && (indent
>0)) {
1167 x
-=infoPtr
->uIndent
;
1168 wineItem
=&infoPtr
->items
[(INT
)wineItem
->parent
];
1169 iItem
=(INT
)wineItem
->sibling
;
1175 /* FIXME: infoPtr->uTotalWidth should also take item label into account */
1176 /* FIXME: or should query item sizes (ie check CDRF_NEWFONT) */
1178 infoPtr
->uTotalHeight
=y
;
1179 if (y
>= (viewbottom
-viewtop
)) {
1180 if (!(infoPtr
->uInternalStatus
& TV_VSCROLL
))
1181 ShowScrollBar (hwnd
, SB_VERT
, TRUE
);
1182 infoPtr
->uInternalStatus
|=TV_VSCROLL
;
1183 SetScrollRange (hwnd
, SB_VERT
, 0,
1184 y
- infoPtr
->uVisibleHeight
, FALSE
);
1185 SetScrollPos (hwnd
, SB_VERT
, infoPtr
->cy
, TRUE
);
1188 if (infoPtr
->uInternalStatus
& TV_VSCROLL
)
1189 ShowScrollBar (hwnd
, SB_VERT
, FALSE
);
1190 infoPtr
->uInternalStatus
&= ~TV_VSCROLL
;
1194 if (infoPtr
->cdmode
& CDRF_NOTIFYPOSTPAINT
)
1195 infoPtr
->cdmode
=TREEVIEW_SendCustomDrawNotify
1196 (hwnd
, CDDS_POSTPAINT
, hdc
, rect
);
1203 TREEVIEW_HandleTimer (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1205 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
1207 TRACE(" %d\n",wParam
);
1210 case TV_REFRESH_TIMER
:
1211 KillTimer (hwnd
, TV_REFRESH_TIMER
);
1212 infoPtr
->Timer
&= ~TV_REFRESH_TIMER_SET
;
1213 InvalidateRect(hwnd
, NULL
, FALSE
);
1216 KillTimer (hwnd
, TV_EDIT_TIMER
);
1217 infoPtr
->Timer
&= ~TV_EDIT_TIMER_SET
;
1220 ERR("got unknown timer\n");
1228 TREEVIEW_QueueRefresh (HWND hwnd
)
1231 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
1234 if (infoPtr
->Timer
& TV_REFRESH_TIMER_SET
) {
1235 KillTimer (hwnd
, TV_REFRESH_TIMER
);
1238 SetTimer (hwnd
, TV_REFRESH_TIMER
, TV_REFRESH_DELAY
, 0);
1239 infoPtr
->Timer
|=TV_REFRESH_TIMER_SET
;
1245 TREEVIEW_GetItemA (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1247 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
1249 TREEVIEW_ITEM
*wineItem
;
1252 tvItem
=(LPTVITEMEXA
) lParam
;
1253 iItem
=(INT
)tvItem
->hItem
;
1255 wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)iItem
);
1256 if (!wineItem
) return FALSE
;
1258 if (tvItem
->mask
& TVIF_CHILDREN
) {
1259 if (TVIF_CHILDREN
==I_CHILDRENCALLBACK
)
1260 FIXME("I_CHILDRENCALLBACK not supported\n");
1261 tvItem
->cChildren
=wineItem
->cChildren
;
1264 if (tvItem
->mask
& TVIF_HANDLE
) {
1265 tvItem
->hItem
=wineItem
->hItem
;
1268 if (tvItem
->mask
& TVIF_IMAGE
) {
1269 tvItem
->iImage
=wineItem
->iImage
;
1272 if (tvItem
->mask
& TVIF_INTEGRAL
) {
1273 tvItem
->iIntegral
=wineItem
->iIntegral
;
1276 /* undocumented: windows ignores TVIF_PARAM and
1277 * always sets lParam
1279 tvItem
->lParam
=wineItem
->lParam
;
1281 if (tvItem
->mask
& TVIF_SELECTEDIMAGE
) {
1282 tvItem
->iSelectedImage
=wineItem
->iSelectedImage
;
1285 if (tvItem
->mask
& TVIF_STATE
) {
1286 tvItem
->state
=wineItem
->state
& tvItem
->stateMask
;
1289 if (tvItem
->mask
& TVIF_TEXT
) {
1290 if (wineItem
->pszText
== LPSTR_TEXTCALLBACKA
) {
1291 tvItem
->pszText
= LPSTR_TEXTCALLBACKA
; /* FIXME:send notification? */
1292 ERR(" GetItem called with LPSTR_TEXTCALLBACK\n");
1294 else if (wineItem
->pszText
) {
1295 lstrcpynA (tvItem
->pszText
, wineItem
->pszText
, tvItem
->cchTextMax
);
1299 TRACE("item %d<%p>, txt %p, img %p, action %x\n",
1300 iItem
, tvItem
, tvItem
->pszText
, &tvItem
->iImage
, tvItem
->mask
);
1307 /* FIXME: check implementation of TVGN_NEXT/TVGN_NEXTVISIBLE */
1310 TREEVIEW_GetNextItem (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1313 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
1314 TREEVIEW_ITEM
*wineItem
, *returnItem
;
1315 INT iItem
= (INT
)lParam
, retval
= 0, flag
= (INT
)wParam
;
1320 retval
= (INT
)infoPtr
->TopRootItem
;
1324 retval
= (INT
)infoPtr
->selectedItem
;
1327 case TVGN_FIRSTVISIBLE
: /* FIXME:we should only recalculate, not redraw */
1329 TREEVIEW_Refresh (hwnd
, hdc
);
1330 ReleaseDC(hwnd
,hdc
);
1331 retval
= (INT
)infoPtr
->firstVisible
;
1334 case TVGN_DROPHILITE
:
1335 retval
= (INT
)infoPtr
->dropItem
;
1339 wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)iItem
);
1340 retval
= wineItem
? (INT
)wineItem
->sibling
: 0;
1344 wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)iItem
);
1345 retval
= wineItem
? (INT
)wineItem
->upsibling
: 0;
1349 wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)iItem
);
1350 retval
= wineItem
? (INT
)wineItem
->parent
: 0;
1354 wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)iItem
);
1355 retval
= wineItem
? (INT
)wineItem
->firstChild
: 0;
1358 case TVGN_LASTVISIBLE
:
1359 if((wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)iItem
))) {
1360 returnItem
= TREEVIEW_GetLastListItem (infoPtr
,wineItem
);
1361 retval
= returnItem
? (INT
)returnItem
->hItem
: 0;
1365 case TVGN_NEXTVISIBLE
:
1366 if((wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)iItem
))) {
1367 returnItem
= TREEVIEW_GetNextListItem (infoPtr
,wineItem
);
1368 retval
= returnItem
? (INT
)returnItem
->hItem
: 0;
1372 case TVGN_PREVIOUSVISIBLE
:
1373 if((wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)iItem
))) {
1374 returnItem
= TREEVIEW_GetPrevListItem (infoPtr
, wineItem
);
1375 retval
= returnItem
? (INT
)returnItem
->hItem
: 0;
1380 FIXME("Unknown msg %x,item %x\n", flag
,iItem
);
1384 TRACE("flags %x, item %d returns %d\n", flag
, iItem
, retval
);
1390 TREEVIEW_GetCount (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1392 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
1394 TRACE(" %d\n",infoPtr
->uNumItems
);
1395 return (LRESULT
) infoPtr
->uNumItems
;
1398 /***************************************************************************
1399 * This method does the chaining of the insertion of a treeview item
1401 * If parent is NULL, we're inserting at the root of the list.
1403 static void TREEVIEW_InsertBefore(
1404 TREEVIEW_INFO
*infoPtr
,
1405 TREEVIEW_ITEM
*newItem
,
1406 TREEVIEW_ITEM
*sibling
,
1407 TREEVIEW_ITEM
*parent
)
1409 HTREEITEM siblingHandle
= 0;
1410 HTREEITEM upSiblingHandle
= 0;
1411 TREEVIEW_ITEM
*upSibling
= NULL
;
1413 if (newItem
== NULL
)
1414 ERR("NULL newItem, impossible condition\n");
1416 if (sibling
!= NULL
) /* Insert before this sibling for this parent */
1418 /* Store the new item sibling up sibling and sibling tem handle */
1419 siblingHandle
= sibling
->hItem
;
1420 upSiblingHandle
= sibling
->upsibling
;
1421 /* As well as a pointer to the upsibling sibling object */
1422 if ( (INT
)sibling
->upsibling
!= 0 )
1423 upSibling
= &infoPtr
->items
[(INT
)sibling
->upsibling
];
1425 /* Adjust the sibling pointer */
1426 sibling
->upsibling
= newItem
->hItem
;
1428 /* Adjust the new item pointers */
1429 newItem
->upsibling
= upSiblingHandle
;
1430 newItem
->sibling
= siblingHandle
;
1432 /* Adjust the up sibling pointer */
1433 if ( upSibling
!= NULL
)
1434 upSibling
->sibling
= newItem
->hItem
;
1436 /* this item is the first child of this parent, adjust parent pointers */
1438 parent
->firstChild
= newItem
->hItem
;
1440 infoPtr
->TopRootItem
= newItem
->hItem
;
1442 else /* Insert as first child of this parent */
1444 parent
->firstChild
= newItem
->hItem
;
1447 /***************************************************************************
1448 * This method does the chaining of the insertion of a treeview item
1450 * If parent is NULL, we're inserting at the root of the list.
1452 static void TREEVIEW_InsertAfter(
1453 TREEVIEW_INFO
*infoPtr
,
1454 TREEVIEW_ITEM
*newItem
,
1455 TREEVIEW_ITEM
*upSibling
,
1456 TREEVIEW_ITEM
*parent
)
1458 HTREEITEM upSiblingHandle
= 0;
1459 HTREEITEM siblingHandle
= 0;
1460 TREEVIEW_ITEM
*sibling
= NULL
;
1463 if (newItem
== NULL
)
1464 ERR("NULL newItem, impossible condition\n");
1466 if (upSibling
!= NULL
) /* Insert after this upsibling for this parent */
1468 /* Store the new item up sibling and sibling item handle */
1469 upSiblingHandle
= upSibling
->hItem
;
1470 siblingHandle
= upSibling
->sibling
;
1471 /* As well as a pointer to the upsibling sibling object */
1472 if ( (INT
)upSibling
->sibling
!= 0 )
1473 sibling
= &infoPtr
->items
[(INT
)upSibling
->sibling
];
1475 /* Adjust the up sibling pointer */
1476 upSibling
->sibling
= newItem
->hItem
;
1478 /* Adjust the new item pointers */
1479 newItem
->upsibling
= upSiblingHandle
;
1480 newItem
->sibling
= siblingHandle
;
1482 /* Adjust the sibling pointer */
1483 if ( sibling
!= NULL
)
1484 sibling
->upsibling
= newItem
->hItem
;
1487 newItem is the last of the level, nothing else to do
1490 else /* Insert as first child of this parent */
1492 parent
->firstChild
= newItem
->hItem
;
1495 /***************************************************************************
1496 * Forward the DPA local callback to the treeview owner callback
1498 static INT WINAPI
TREEVIEW_CallBackCompare(
1503 /* Forward the call to the client define callback */
1504 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr((HWND
)tvInfoPtr
);
1505 return (infoPtr
->pCallBackSort
->lpfnCompare
)(
1506 ((TREEVIEW_ITEM
*)first
)->lParam
,
1507 ((TREEVIEW_ITEM
*)second
)->lParam
,
1508 infoPtr
->pCallBackSort
->lParam
);
1511 /***************************************************************************
1512 * Treeview native sort routine: sort on item text.
1514 static INT WINAPI
TREEVIEW_SortOnName (
1519 HWND hwnd
=(HWND
) tvInfoPtr
;
1521 TREEVIEW_ITEM
*item
;
1524 item
=(TREEVIEW_ITEM
*) first
;
1525 if (item
->pszText
==LPSTR_TEXTCALLBACKA
) {
1526 TREEVIEW_SendDispInfoNotify (hwnd
, item
, TVN_GETDISPINFOA
, TVIF_TEXT
);
1530 item
=(TREEVIEW_ITEM
*) second
;
1531 if (item
->pszText
==LPSTR_TEXTCALLBACKA
) {
1532 TREEVIEW_SendDispInfoNotify (hwnd
, item
, TVN_GETDISPINFOA
, TVIF_TEXT
);
1536 return -strcmp (txt1
,txt2
);
1539 /***************************************************************************
1540 * Setup the treeview structure with regards of the sort method
1541 * and sort the children of the TV item specified in lParam
1542 * fRecurse: currently unused. Should be zero.
1543 * parent: if pSort!=NULL, should equal pSort->hParent.
1544 * otherwise, item which child items are to be sorted.
1545 * pSort: sort method info. if NULL, sort on item text.
1546 * if non-NULL, sort on item's lParam content, and let the
1547 * application decide what that means. See also TVM_SORTCHILDRENCB.
1550 static LRESULT WINAPI
TREEVIEW_Sort (
1557 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
1558 TREEVIEW_ITEM
*sortMe
= NULL
; /* Node for which we sort the children */
1560 /* Obtain the TVSORTBC struct */
1561 infoPtr
->pCallBackSort
= pSort
;
1563 /* undocumented feature: TVI_ROOT means `sort the whole tree' */
1565 if (parent
==TVI_ROOT
)
1566 parent
=infoPtr
->TopRootItem
;
1568 /* Check for a valid handle to the parent item */
1569 if (!TREEVIEW_ValidItem(infoPtr
, parent
))
1571 ERR ("invalid item hParent=%x\n", (INT
)parent
);
1575 /* Obtain the parent node to sort */
1576 sortMe
= &infoPtr
->items
[ (INT
)parent
];
1578 /* Make sure there is something to sort */
1579 if ( sortMe
->cChildren
> 1 )
1581 /* pointer organization */
1582 HDPA sortList
= DPA_Create(sortMe
->cChildren
);
1583 HTREEITEM itemHandle
= sortMe
->firstChild
;
1584 TREEVIEW_ITEM
*itemPtr
= & infoPtr
->items
[ (INT
)itemHandle
];
1586 /* TREEVIEW_ITEM rechaining */
1592 /* Build the list of item to sort */
1596 sortList
, /* the list */
1597 sortMe
->cChildren
+1, /* force the insertion to be an append */
1598 itemPtr
); /* the ptr to store */
1600 /* Get the next sibling */
1601 itemHandle
= itemPtr
->sibling
;
1602 itemPtr
= & infoPtr
->items
[ (INT
)itemHandle
];
1603 } while ( itemHandle
!= NULL
);
1605 /* let DPA perform the sort activity */
1608 sortList
, /* what */
1609 TREEVIEW_CallBackCompare
, /* how */
1613 sortList
, /* what */
1614 TREEVIEW_SortOnName
, /* how */
1618 * Reorganized TREEVIEW_ITEM structures.
1619 * Note that we know we have at least two elements.
1622 /* Get the first item and get ready to start... */
1623 item
= DPA_GetPtr(sortList
, count
++);
1624 while ( (nextItem
= DPA_GetPtr(sortList
, count
++)) != NULL
)
1626 /* link the two current item toghether */
1627 ((TREEVIEW_ITEM
*)item
)->sibling
= ((TREEVIEW_ITEM
*)nextItem
)->hItem
;
1628 ((TREEVIEW_ITEM
*)nextItem
)->upsibling
= ((TREEVIEW_ITEM
*)item
)->hItem
;
1630 if (prevItem
== NULL
) /* this is the first item, update the parent */
1632 sortMe
->firstChild
= ((TREEVIEW_ITEM
*)item
)->hItem
;
1633 ((TREEVIEW_ITEM
*)item
)->upsibling
= NULL
;
1635 else /* fix the back chaining */
1637 ((TREEVIEW_ITEM
*)item
)->upsibling
= ((TREEVIEW_ITEM
*)prevItem
)->hItem
;
1640 /* get ready for the next one */
1645 /* the last item is pointed to by item and never has a sibling */
1646 ((TREEVIEW_ITEM
*)item
)->sibling
= NULL
;
1648 DPA_Destroy(sortList
);
1656 /***************************************************************************
1657 * Setup the treeview structure with regards of the sort method
1658 * and sort the children of the TV item specified in lParam
1660 static LRESULT WINAPI
TREEVIEW_SortChildrenCB(
1666 LPTVSORTCB pSort
=(LPTVSORTCB
) lParam
;
1668 return TREEVIEW_Sort (hwnd
, wParam
, pSort
->hParent
, pSort
);
1672 /***************************************************************************
1673 * Sort the children of the TV item specified in lParam.
1675 static LRESULT WINAPI
TREEVIEW_SortChildren (
1680 return TREEVIEW_Sort (hwnd
, (BOOL
) wParam
, (HTREEITEM
) lParam
, NULL
);
1685 /* the method used below isn't the most memory-friendly, but it avoids
1686 a lot of memory reallocations */
1688 /* BTW: we waste handle 0; 0 is not an allowed handle. */
1691 TREEVIEW_InsertItemA (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1694 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
1695 TVINSERTSTRUCTA
*ptdi
;
1697 TREEVIEW_ITEM
*wineItem
, *parentItem
, *prevsib
, *sibItem
;
1698 INT iItem
,listItems
,i
,len
;
1700 /* Item to insert */
1701 ptdi
= (LPTVINSERTSTRUCTA
) lParam
;
1703 /* check if memory is available */
1705 if (infoPtr
->uNumPtrsAlloced
==0) {
1706 infoPtr
->items
= COMCTL32_Alloc (TVITEM_ALLOC
*sizeof (TREEVIEW_ITEM
));
1707 infoPtr
->freeList
= COMCTL32_Alloc ((1+(TVITEM_ALLOC
>>5)) * sizeof (INT
));
1708 infoPtr
->uNumPtrsAlloced
=TVITEM_ALLOC
;
1709 infoPtr
->TopRootItem
=(HTREEITEM
)1;
1713 * Reallocate contiguous space for items
1715 if (infoPtr
->uNumItems
== (infoPtr
->uNumPtrsAlloced
-1) ) {
1716 TREEVIEW_ITEM
*oldItems
= infoPtr
->items
;
1717 INT
*oldfreeList
= infoPtr
->freeList
;
1719 infoPtr
->uNumPtrsAlloced
*=2;
1720 infoPtr
->items
= COMCTL32_Alloc (infoPtr
->uNumPtrsAlloced
*sizeof (TREEVIEW_ITEM
));
1721 infoPtr
->freeList
= COMCTL32_Alloc ((1+(infoPtr
->uNumPtrsAlloced
>>5))*sizeof (INT
));
1723 memcpy (&infoPtr
->items
[0], &oldItems
[0],
1724 infoPtr
->uNumPtrsAlloced
/2 * sizeof(TREEVIEW_ITEM
));
1725 memcpy (&infoPtr
->freeList
[0], &oldfreeList
[0],
1726 (infoPtr
->uNumPtrsAlloced
>>6) * sizeof(INT
));
1728 COMCTL32_Free (oldItems
);
1729 COMCTL32_Free (oldfreeList
);
1733 * Reset infoPtr structure with new stat according to current TV picture
1736 infoPtr
->uNumItems
++;
1737 if ((INT
)infoPtr
->uMaxHandle
==(infoPtr
->uNumItems
-1)) {
1738 iItem
=infoPtr
->uNumItems
;
1739 infoPtr
->uMaxHandle
= (HTREEITEM
)((INT
)infoPtr
->uMaxHandle
+ 1);
1740 } else { /* check freelist */
1741 for (i
=0; i
<=infoPtr
->uNumPtrsAlloced
>>5; i
++) {
1742 if (infoPtr
->freeList
[i
]) {
1743 iItem
=ffs (infoPtr
->freeList
[i
])-1;
1744 tv_clear_bit(iItem
,&infoPtr
->freeList
[i
]);
1751 if (TRACE_ON(treeview
)) {
1752 for (i
=0; i
<=infoPtr
->uNumPtrsAlloced
>>5; i
++)
1753 TRACE("%8x\n",infoPtr
->freeList
[i
]);
1756 if (!iItem
) ERR("Argh -- can't find free item.\n");
1759 * Find the parent item of the new item
1761 tvItem
= & ptdi
->DUMMYUNIONNAME
.itemex
;
1762 wineItem
=& infoPtr
->items
[iItem
];
1764 if ((ptdi
->hParent
==TVI_ROOT
) || (ptdi
->hParent
==0)) {
1766 wineItem
->parent
= 0;
1767 sibItem
= &infoPtr
->items
[(INT
)infoPtr
->TopRootItem
];
1768 listItems
= infoPtr
->uNumItems
;
1771 parentItem
= &infoPtr
->items
[(INT
)ptdi
->hParent
];
1773 /* Do the insertion here it if it's the only item of this parent */
1774 if (!parentItem
->firstChild
)
1775 parentItem
->firstChild
=(HTREEITEM
)iItem
;
1777 wineItem
->parent
= ptdi
->hParent
;
1778 sibItem
= &infoPtr
->items
[(INT
)parentItem
->firstChild
];
1779 listItems
= parentItem
->cChildren
;
1780 parentItem
->cChildren
++;
1784 /* NOTE: I am moving some setup of the wineItem object that was initialy
1785 * done at the end of the function since some of the values are
1786 * required by the Callback sorting
1789 if (tvItem
->mask
& TVIF_TEXT
)
1792 * Setup the item text stuff here since it's required by the Sort method
1793 * when the insertion are ordered
1795 if (tvItem
->pszText
!=LPSTR_TEXTCALLBACKA
)
1797 TRACE("(%p,%s)\n", &tvItem
->pszText
, tvItem
->pszText
);
1798 len
= lstrlenA (tvItem
->pszText
)+1;
1799 wineItem
->pszText
= COMCTL32_Alloc (len
+1);
1800 lstrcpyA (wineItem
->pszText
, tvItem
->pszText
);
1801 wineItem
->cchTextMax
=len
;
1805 TRACE("LPSTR_TEXTCALLBACK\n");
1806 wineItem
->pszText
= LPSTR_TEXTCALLBACKA
;
1807 wineItem
->cchTextMax
= 0;
1811 if (tvItem
->mask
& TVIF_PARAM
)
1812 wineItem
->lParam
=tvItem
->lParam
;
1815 wineItem
->upsibling
=0; /* needed in case we're the first item in a list */
1816 wineItem
->sibling
=0;
1817 wineItem
->firstChild
=0;
1818 wineItem
->hItem
=(HTREEITEM
)iItem
;
1823 switch ((DWORD
) ptdi
->hInsertAfter
) {
1824 case (DWORD
) TVI_FIRST
:
1825 if (sibItem
==wineItem
) break;
1826 if (wineItem
->parent
) {
1827 wineItem
->sibling
=parentItem
->firstChild
;
1828 parentItem
->firstChild
=(HTREEITEM
)iItem
;
1830 wineItem
->sibling
=infoPtr
->TopRootItem
;
1831 infoPtr
->TopRootItem
=(HTREEITEM
)iItem
;
1833 sibItem
->upsibling
=(HTREEITEM
)iItem
;
1836 case (DWORD
) TVI_SORT
:
1837 if (sibItem
==wineItem
)
1839 * This item is the first child of the level and it
1840 * has already been inserted
1845 TREEVIEW_ITEM
*aChild
;
1848 TREEVIEW_ITEM
*previousChild
= NULL
;
1849 BOOL bItemInserted
= FALSE
;
1852 aChild
= &infoPtr
->items
[(INT
)parentItem
->firstChild
];
1854 aChild
= &infoPtr
->items
[(INT
)infoPtr
->TopRootItem
];
1856 /* lookup the text if using LPSTR_TEXTCALLBACKs */
1857 if (wineItem
->pszText
==LPSTR_TEXTCALLBACKA
) {
1858 TREEVIEW_SendDispInfoNotify (hwnd
, wineItem
, TVN_GETDISPINFOA
, TVIF_TEXT
);
1861 /* Iterate the parent children to see where we fit in */
1862 while ( aChild
!= NULL
)
1866 /* lookup the text if using LPSTR_TEXTCALLBACKs */
1867 if (aChild
->pszText
==LPSTR_TEXTCALLBACKA
) {
1868 TREEVIEW_SendDispInfoNotify (hwnd
, aChild
, TVN_GETDISPINFOA
, TVIF_TEXT
);
1871 comp
= strcmp(wineItem
->pszText
, aChild
->pszText
);
1872 if ( comp
< 0 ) /* we are smaller than the current one */
1874 TREEVIEW_InsertBefore(infoPtr
, wineItem
, aChild
, parentItem
);
1875 bItemInserted
= TRUE
;
1878 else if ( comp
> 0 ) /* we are bigger than the current one */
1880 previousChild
= aChild
;
1881 aChild
= (aChild
->sibling
== 0) /* This will help us to exit */
1882 ? NULL
/* if there is no more sibling */
1883 : &infoPtr
->items
[(INT
)aChild
->sibling
];
1885 /* Look at the next item */
1888 else if ( comp
== 0 )
1891 * An item with this name is already existing, therefore,
1892 * we add after the one we found
1894 TREEVIEW_InsertAfter(infoPtr
, wineItem
, aChild
, parentItem
);
1895 bItemInserted
= TRUE
;
1901 * we reach the end of the child list and the item as not
1902 * yet been inserted, therefore, insert it after the last child.
1904 if ( (! bItemInserted
) && (aChild
== NULL
) )
1905 TREEVIEW_InsertAfter(infoPtr
, wineItem
, previousChild
, parentItem
);
1911 case (DWORD
) TVI_LAST
:
1912 if (sibItem
==wineItem
) break;
1913 while (sibItem
->sibling
) {
1915 sibItem
=&infoPtr
->items
[(INT
)sibItem
->sibling
];
1917 sibItem
->sibling
=(HTREEITEM
)iItem
;
1918 wineItem
->upsibling
=sibItem
->hItem
;
1921 while ((sibItem
->sibling
) && (sibItem
->hItem
!=ptdi
->hInsertAfter
))
1924 sibItem
=&infoPtr
->items
[(INT
)sibItem
->sibling
];
1926 if (sibItem
->hItem
!=ptdi
->hInsertAfter
) {
1927 ERR("tried to insert item after nonexisting handle %d.\n",
1928 (INT
) ptdi
->hInsertAfter
);
1932 if (sibItem
->sibling
) {
1933 sibItem
=&infoPtr
->items
[(INT
)sibItem
->sibling
];
1934 sibItem
->upsibling
=(HTREEITEM
)iItem
;
1935 wineItem
->sibling
=sibItem
->hItem
;
1937 prevsib
->sibling
=(HTREEITEM
)iItem
;
1938 wineItem
->upsibling
=prevsib
->hItem
;
1944 /* Fill in info structure */
1946 TRACE("new item %d; parent %d, mask %x\n", iItem
,
1947 (INT
)wineItem
->parent
,tvItem
->mask
);
1949 wineItem
->mask
=tvItem
->mask
;
1950 wineItem
->iIntegral
=1;
1952 if (tvItem
->mask
& TVIF_CHILDREN
) {
1953 wineItem
->cChildren
=tvItem
->cChildren
;
1954 if (tvItem
->cChildren
==I_CHILDRENCALLBACK
)
1955 FIXME(" I_CHILDRENCALLBACK not supported\n");
1958 wineItem
->expandBox
.left
= 0; /* Initialize the expandBox */
1959 wineItem
->expandBox
.top
= 0;
1960 wineItem
->expandBox
.right
= 0;
1961 wineItem
->expandBox
.bottom
= 0;
1963 if (tvItem
->mask
& TVIF_IMAGE
)
1964 wineItem
->iImage
=tvItem
->iImage
;
1966 /* If the application sets TVIF_INTEGRAL without
1967 supplying a TVITEMEX structure, it's toast */
1969 if (tvItem
->mask
& TVIF_INTEGRAL
)
1970 wineItem
->iIntegral
=tvItem
->iIntegral
;
1972 if (tvItem
->mask
& TVIF_SELECTEDIMAGE
)
1973 wineItem
->iSelectedImage
=tvItem
->iSelectedImage
;
1975 if (tvItem
->mask
& TVIF_STATE
) {
1976 TRACE("item state: %x ->%x\n", wineItem
->state
, tvItem
->state
);
1977 TRACE("statemask: %x ->%x\n", wineItem
->stateMask
, tvItem
->stateMask
);
1978 wineItem
->state
=tvItem
->state
;
1979 wineItem
->stateMask
=tvItem
->stateMask
;
1982 TREEVIEW_QueueRefresh (hwnd
);
1984 return (LRESULT
) iItem
;
1989 TREEVIEW_InsertItemW(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1991 TVINSERTSTRUCTW
*tvisW
;
1992 TVINSERTSTRUCTA tvisA
;
1995 tvisW
= (LPTVINSERTSTRUCTW
)lParam
;
1997 tvisA
.hParent
= tvisW
->hParent
;
1998 tvisA
.hInsertAfter
= tvisW
->hInsertAfter
;
2000 tvisA
.DUMMYUNIONNAME
.item
.mask
= tvisW
->DUMMYUNIONNAME
.item
.mask
;
2001 tvisA
.DUMMYUNIONNAME
.item
.hItem
= tvisW
->DUMMYUNIONNAME
.item
.hItem
;
2002 tvisA
.DUMMYUNIONNAME
.item
.state
= tvisW
->DUMMYUNIONNAME
.item
.state
;
2003 tvisA
.DUMMYUNIONNAME
.item
.stateMask
= tvisW
->DUMMYUNIONNAME
.item
.stateMask
;
2004 tvisA
.DUMMYUNIONNAME
.item
.cchTextMax
= tvisW
->DUMMYUNIONNAME
.item
.cchTextMax
;
2006 if(tvisW
->DUMMYUNIONNAME
.item
.pszText
)
2008 if (tvisW
->DUMMYUNIONNAME
.item
.pszText
!=LPSTR_TEXTCALLBACKW
)
2010 int len
= lstrlenW (tvisW
->DUMMYUNIONNAME
.item
.pszText
)+1;
2011 tvisA
.DUMMYUNIONNAME
.item
.pszText
= COMCTL32_Alloc (len
);
2012 lstrcpyWtoA (tvisA
.DUMMYUNIONNAME
.item
.pszText
,
2013 tvisW
->DUMMYUNIONNAME
.item
.pszText
);
2017 tvisA
.DUMMYUNIONNAME
.item
.pszText
= LPSTR_TEXTCALLBACKA
;
2018 tvisA
.DUMMYUNIONNAME
.item
.cchTextMax
= 0;
2022 tvisA
.DUMMYUNIONNAME
.item
.iImage
= tvisW
->DUMMYUNIONNAME
.item
.iImage
;
2023 tvisA
.DUMMYUNIONNAME
.item
.iSelectedImage
= tvisW
->DUMMYUNIONNAME
.item
.iSelectedImage
;
2024 tvisA
.DUMMYUNIONNAME
.item
.cChildren
= tvisW
->DUMMYUNIONNAME
.item
.cChildren
;
2025 tvisA
.DUMMYUNIONNAME
.item
.lParam
= tvisW
->DUMMYUNIONNAME
.item
.lParam
;
2027 lRes
= TREEVIEW_InsertItemA(hwnd
,wParam
,(LPARAM
)&tvisA
);
2029 if (tvisA
.DUMMYUNIONNAME
.item
.pszText
!=LPSTR_TEXTCALLBACKA
)
2031 COMCTL32_Free(tvisA
.DUMMYUNIONNAME
.item
.pszText
);
2040 TREEVIEW_DeleteItem (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2042 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2044 TREEVIEW_ITEM
*wineItem
;
2046 TRACE("item = %08lx\n", lParam
);
2048 if (lParam
== (INT
)TVI_ROOT
) {
2049 TREEVIEW_RemoveTree (hwnd
);
2051 iItem
= (INT
) lParam
;
2052 wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)iItem
);
2053 if (!wineItem
) return FALSE
;
2055 if (wineItem
->pszText
==LPSTR_TEXTCALLBACKA
)
2056 TRACE("LPSTR_TEXTCALLBACK\n");
2058 TRACE("%s\n",wineItem
->pszText
);
2059 TREEVIEW_RemoveItem (hwnd
, wineItem
);
2062 TREEVIEW_QueueRefresh (hwnd
);
2070 TREEVIEW_GetIndent (HWND hwnd
)
2072 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2075 return infoPtr
->uIndent
;
2079 TREEVIEW_SetIndent (HWND hwnd
, WPARAM wParam
)
2081 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2085 newIndent
=(INT
) wParam
;
2086 if (newIndent
< MINIMUM_INDENT
) newIndent
=MINIMUM_INDENT
;
2087 infoPtr
->uIndent
=newIndent
;
2093 TREEVIEW_GetToolTips (HWND hwnd
)
2096 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2099 return infoPtr
->hwndToolTip
;
2104 TREEVIEW_SetToolTips (HWND hwnd
, WPARAM wParam
)
2107 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2111 prevToolTip
=infoPtr
->hwndToolTip
;
2112 infoPtr
->hwndToolTip
= (HWND
) wParam
;
2118 static LRESULT CALLBACK
2119 TREEVIEW_GetEditControl (HWND hwnd
)
2122 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2124 return infoPtr
->hwndEdit
;
2128 TREEVIEW_Edit_SubclassProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
,
2136 HDC hdc
= (HDC
) wParam
;
2137 GetClientRect (hwnd
, &rc
);
2138 Rectangle (hdc
, rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
2144 return DLGC_WANTARROWS
| DLGC_WANTALLKEYS
;
2149 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(GetParent(hwnd
));
2151 return CallWindowProcA (infoPtr
->wpEditOrig
, hwnd
, uMsg
, wParam
, lParam
);
2162 /* should handle edit control messages here */
2165 TREEVIEW_Command (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2168 TRACE("%x %ld\n",wParam
, lParam
);
2170 switch (HIWORD(wParam
))
2175 * Adjust the edit window size
2177 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2178 TREEVIEW_ITEM
*editItem
= TREEVIEW_ValidItem(infoPtr
, infoPtr
->editItem
);
2179 INT iLength
= GetWindowTextLengthA(infoPtr
->hwndEdit
);
2180 HDC hdc
= GetDC(infoPtr
->hwndEdit
);
2183 if ( GetTextMetricsA(hdc
, &tm
) )
2185 LONG newWidth
= (iLength
* tm
.tmAveCharWidth
) + 15;
2190 editItem
->text
.left
- 2,
2191 editItem
->text
.top
- 1,
2193 editItem
->text
.bottom
- editItem
->text
.top
+ 3,
2196 ReleaseDC(hwnd
, hdc
);
2202 /* TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
2207 return SendMessageA (GetParent (hwnd
), WM_COMMAND
, wParam
, lParam
);
2214 TREEVIEW_Size (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2217 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2219 if (infoPtr
->bAutoSize
)
2221 infoPtr
->bAutoSize
= FALSE
;
2224 infoPtr
->bAutoSize
= TRUE
;
2226 if (wParam
== SIZE_RESTORED
)
2228 infoPtr
->uTotalWidth
= LOWORD (lParam
);
2229 infoPtr
->uTotalHeight
= HIWORD (lParam
);
2231 FIXME("WM_SIZE flag %x %lx not handled\n", wParam
, lParam
);
2234 TREEVIEW_QueueRefresh (hwnd
);
2241 TREEVIEW_StyleChanged (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2245 TRACE("(%x %lx)\n",wParam
,lParam
);
2247 TREEVIEW_Refresh (hwnd
, hdc
);
2248 ReleaseDC(hwnd
,hdc
);
2254 TREEVIEW_Create (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2256 TREEVIEW_INFO
*infoPtr
;
2257 DWORD dwStyle
= GetWindowLongA (hwnd
, GWL_STYLE
);
2262 TRACE("wnd %x, style %lx\n",hwnd
,dwStyle
);
2263 /* allocate memory for info structure */
2264 infoPtr
= (TREEVIEW_INFO
*) COMCTL32_Alloc (sizeof(TREEVIEW_INFO
));
2266 SetWindowLongA( hwnd
, 0, (DWORD
)infoPtr
);
2268 if (infoPtr
== NULL
) {
2269 ERR("could not allocate info memory!\n");
2273 if ((TREEVIEW_INFO
*) GetWindowLongA( hwnd
, 0) != infoPtr
) {
2274 ERR("pointer assignment error!\n");
2280 /* set default settings */
2281 infoPtr
->uInternalStatus
=0;
2282 infoPtr
->uNumItems
=0;
2283 infoPtr
->clrBk
= GetSysColor (COLOR_WINDOW
);
2284 infoPtr
->clrText
= GetSysColor (COLOR_WINDOWTEXT
);
2285 infoPtr
->clrLine
= GetSysColor (COLOR_WINDOWTEXT
);
2286 infoPtr
->clrInsertMark
= GetSysColor (COLOR_BTNTEXT
);
2289 infoPtr
->uIndent
= 15;
2290 infoPtr
->himlNormal
= NULL
;
2291 infoPtr
->himlState
= NULL
;
2292 infoPtr
->uItemHeight
= -1;
2293 GetTextMetricsA (hdc
, &tm
);
2294 infoPtr
->hFont
= GetStockObject (DEFAULT_GUI_FONT
);
2295 GetObjectA (infoPtr
->hFont
, sizeof (LOGFONTA
), &logFont
);
2296 logFont
.lfWeight
=FW_BOLD
;
2297 infoPtr
->hBoldFont
= CreateFontIndirectA (&logFont
);
2299 infoPtr
->items
= NULL
;
2300 infoPtr
->selectedItem
=0;
2301 infoPtr
->clrText
=-1; /* use system color */
2302 infoPtr
->dropItem
=0;
2303 infoPtr
->insertMarkItem
=0;
2304 infoPtr
->insertBeforeorAfter
=0;
2305 infoPtr
->pCallBackSort
=NULL
;
2306 infoPtr
->uScrollTime
= 300; /* milliseconds */
2307 infoPtr
->wpEditOrig
= NULL
; /* we haven't subclassed anything yet */
2309 infoPtr
->hwndToolTip
=0;
2310 if (!(dwStyle
& TVS_NOTOOLTIPS
)) { /* Create tooltip control */
2313 infoPtr
->hwndToolTip
=
2314 CreateWindowExA (0, TOOLTIPS_CLASSA
, NULL
, 0,
2315 CW_USEDEFAULT
, CW_USEDEFAULT
,
2316 CW_USEDEFAULT
, CW_USEDEFAULT
,
2319 /* Send NM_TOOLTIPSCREATED notification */
2320 if (infoPtr
->hwndToolTip
) {
2321 NMTOOLTIPSCREATED nmttc
;
2323 nmttc
.hdr
.hwndFrom
= hwnd
;
2324 nmttc
.hdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
2325 nmttc
.hdr
.code
= NM_TOOLTIPSCREATED
;
2326 nmttc
.hwndToolTips
= infoPtr
->hwndToolTip
;
2328 SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
2329 (WPARAM
) GetWindowLongA( hwnd
, GWL_ID
), (LPARAM
)&nmttc
);
2332 ZeroMemory (&ti
, sizeof(TTTOOLINFOA
));
2333 ti
.cbSize
= sizeof(TTTOOLINFOA
);
2334 ti
.uFlags
= TTF_IDISHWND
| TTF_TRACK
| TTF_TRANSPARENT
;
2337 ti
.lpszText
= "Test"; /* LPSTR_TEXTCALLBACK; */
2338 SetRectEmpty (&ti
.rect
);
2340 SendMessageA (infoPtr
->hwndToolTip
, TTM_ADDTOOLA
, 0, (LPARAM
)&ti
);
2343 infoPtr
->hwndEdit
= CreateWindowExA (
2347 WS_CHILD
| WS_BORDER
| ES_AUTOHSCROLL
|
2348 ES_WANTRETURN
| ES_LEFT
,
2351 0,0,0); /* FIXME: (HMENU)IDTVEDIT,pcs->hInstance,0);*/
2353 SendMessageA ( infoPtr
->hwndEdit
, WM_SETFONT
, infoPtr
->hFont
, FALSE
);
2354 infoPtr
->wpEditOrig
= (WNDPROC
)SetWindowLongA (
2357 (LONG
) TREEVIEW_Edit_SubclassProc
);
2359 if (dwStyle
& TVS_CHECKBOXES
) {
2363 infoPtr
->himlState
=
2364 ImageList_Create (16, 16,ILC_COLOR
|ILC_MASK
, 15, 1);
2366 hbmLoad
= LoadBitmapA (COMCTL32_hModule
, MAKEINTRESOURCEA(IDT_CHECK
));
2367 TRACE ("%x\n",hbmLoad
);
2368 nIndex
= ImageList_AddMasked (infoPtr
->himlState
, hbmLoad
, CLR_DEFAULT
);
2369 TRACE ("%d\n",nIndex
);
2370 DeleteObject (hbmLoad
);
2372 ReleaseDC (hwnd
, hdc
);
2379 TREEVIEW_Destroy (HWND hwnd
)
2381 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2384 TREEVIEW_RemoveTree (hwnd
);
2385 SetWindowLongA (hwnd
, 0, (DWORD
)NULL
);
2387 if (infoPtr
->Timer
& TV_REFRESH_TIMER_SET
)
2388 KillTimer (hwnd
, TV_REFRESH_TIMER
);
2389 if (infoPtr
->hwndToolTip
)
2390 DestroyWindow (infoPtr
->hwndToolTip
);
2392 COMCTL32_Free (infoPtr
);
2398 TREEVIEW_Paint (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2404 hdc
= wParam
==0 ? BeginPaint (hwnd
, &ps
) : (HDC
)wParam
;
2405 TREEVIEW_Refresh (hwnd
, hdc
);
2406 if(!wParam
) EndPaint (hwnd
, &ps
);
2409 return DefWindowProcA (hwnd
, WM_PAINT
, wParam
, lParam
);
2413 TREEVIEW_SetFocus (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2415 TREEVIEW_SendSimpleNotify (hwnd
, NM_SETFOCUS
);
2416 InvalidateRect(hwnd
, NULL
, FALSE
);
2421 TREEVIEW_KillFocus (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2423 TREEVIEW_SendSimpleNotify (hwnd
, NM_KILLFOCUS
);
2424 InvalidateRect(hwnd
, NULL
, FALSE
);
2429 TREEVIEW_EraseBackground (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2431 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2432 HBRUSH hBrush
= CreateSolidBrush (infoPtr
->clrBk
);
2436 GetClientRect (hwnd
, &rect
);
2437 FillRect ((HDC
)wParam
, &rect
, hBrush
);
2438 DeleteObject (hBrush
);
2454 TREEVIEW_SendSimpleNotify (HWND hwnd
, UINT code
)
2459 nmhdr
.hwndFrom
= hwnd
;
2460 nmhdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
2463 return (BOOL
) SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
2464 (WPARAM
)nmhdr
.idFrom
, (LPARAM
)&nmhdr
);
2470 TREEVIEW_SendTreeviewNotify (HWND hwnd
, UINT code
, UINT action
,
2471 HTREEITEM oldItem
, HTREEITEM newItem
)
2474 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2476 TREEVIEW_ITEM
*wineItem
;
2478 TRACE("code:%x action:%x olditem:%x newitem:%x\n",
2479 code
,action
,(INT
)oldItem
,(INT
)newItem
);
2480 nmhdr
.hdr
.hwndFrom
= hwnd
;
2481 nmhdr
.hdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
2482 nmhdr
.hdr
.code
= code
;
2483 nmhdr
.action
= action
;
2485 wineItem
=& infoPtr
->items
[(INT
)oldItem
];
2486 nmhdr
.itemOld
.mask
= wineItem
->mask
;
2487 nmhdr
.itemOld
.hItem
= wineItem
->hItem
;
2488 nmhdr
.itemOld
.state
= wineItem
->state
;
2489 nmhdr
.itemOld
.stateMask
= wineItem
->stateMask
;
2490 nmhdr
.itemOld
.iImage
= wineItem
->iImage
;
2491 nmhdr
.itemOld
.pszText
= wineItem
->pszText
;
2492 nmhdr
.itemOld
.cchTextMax
= wineItem
->cchTextMax
;
2493 nmhdr
.itemOld
.iImage
= wineItem
->iImage
;
2494 nmhdr
.itemOld
.iSelectedImage
= wineItem
->iSelectedImage
;
2495 nmhdr
.itemOld
.cChildren
= wineItem
->cChildren
;
2496 nmhdr
.itemOld
.lParam
= wineItem
->lParam
;
2500 wineItem
=& infoPtr
->items
[(INT
)newItem
];
2501 nmhdr
.itemNew
.mask
= wineItem
->mask
;
2502 nmhdr
.itemNew
.hItem
= wineItem
->hItem
;
2503 nmhdr
.itemNew
.state
= wineItem
->state
;
2504 nmhdr
.itemNew
.stateMask
= wineItem
->stateMask
;
2505 nmhdr
.itemNew
.iImage
= wineItem
->iImage
;
2506 nmhdr
.itemNew
.pszText
= wineItem
->pszText
;
2507 nmhdr
.itemNew
.cchTextMax
= wineItem
->cchTextMax
;
2508 nmhdr
.itemNew
.iImage
= wineItem
->iImage
;
2509 nmhdr
.itemNew
.iSelectedImage
= wineItem
->iSelectedImage
;
2510 nmhdr
.itemNew
.cChildren
= wineItem
->cChildren
;
2511 nmhdr
.itemNew
.lParam
= wineItem
->lParam
;
2517 return (BOOL
)SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
2518 (WPARAM
) GetWindowLongA( hwnd
, GWL_ID
), (LPARAM
)&nmhdr
);
2523 TREEVIEW_SendTreeviewDnDNotify (HWND hwnd
, UINT code
, HTREEITEM dragItem
,
2526 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2528 TREEVIEW_ITEM
*wineItem
;
2530 TRACE("code:%x dragitem:%x\n", code
,(INT
)dragItem
);
2532 nmhdr
.hdr
.hwndFrom
= hwnd
;
2533 nmhdr
.hdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
2534 nmhdr
.hdr
.code
= code
;
2536 wineItem
=& infoPtr
->items
[(INT
)dragItem
];
2537 nmhdr
.itemNew
.mask
= wineItem
->mask
;
2538 nmhdr
.itemNew
.hItem
= wineItem
->hItem
;
2539 nmhdr
.itemNew
.state
= wineItem
->state
;
2540 nmhdr
.itemNew
.lParam
= wineItem
->lParam
;
2542 nmhdr
.ptDrag
.x
= pt
.x
;
2543 nmhdr
.ptDrag
.y
= pt
.y
;
2545 return (BOOL
)SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
2546 (WPARAM
) GetWindowLongA( hwnd
, GWL_ID
), (LPARAM
)&nmhdr
);
2553 TREEVIEW_SendDispInfoNotify (HWND hwnd
, TREEVIEW_ITEM
*wineItem
,
2554 UINT code
, UINT what
)
2560 TRACE("item %d, action %x, state %d\n",
2561 (INT
)wineItem
->hItem
,
2563 (INT
)wineItem
->state
);
2565 tvdi
.hdr
.hwndFrom
= hwnd
;
2566 tvdi
.hdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
2567 tvdi
.hdr
.code
= code
;
2568 tvdi
.item
.mask
= what
;
2569 tvdi
.item
.hItem
= wineItem
->hItem
;
2570 tvdi
.item
.state
= wineItem
->state
;
2571 tvdi
.item
.lParam
= wineItem
->lParam
;
2572 tvdi
.item
.pszText
= COMCTL32_Alloc (128*sizeof(char));
2573 tvdi
.item
.cchTextMax
= 128;
2574 buf
= tvdi
.item
.pszText
;
2576 retval
=(BOOL
)SendMessageA (
2579 (WPARAM
)tvdi
.hdr
.idFrom
,
2582 if (what
& TVIF_TEXT
) {
2583 wineItem
->pszText
= tvdi
.item
.pszText
;
2584 if (buf
==tvdi
.item
.pszText
) {
2585 wineItem
->cchTextMax
= 128;
2587 TRACE("user-supplied buffer\n");
2588 COMCTL32_Free (buf
);
2589 wineItem
->cchTextMax
= 0;
2592 if (what
& TVIF_SELECTEDIMAGE
)
2593 wineItem
->iSelectedImage
= tvdi
.item
.iSelectedImage
;
2594 if (what
& TVIF_IMAGE
)
2595 wineItem
->iImage
= tvdi
.item
.iImage
;
2596 if (what
& TVIF_CHILDREN
)
2597 wineItem
->cChildren
= tvdi
.item
.cChildren
;
2605 TREEVIEW_SendCustomDrawNotify (HWND hwnd
, DWORD dwDrawStage
, HDC hdc
,
2608 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2609 NMTVCUSTOMDRAW nmcdhdr
;
2610 LPNMCUSTOMDRAW nmcd
;
2612 TRACE("drawstage:%lx hdc:%x\n", dwDrawStage
, hdc
);
2614 nmcd
= & nmcdhdr
.nmcd
;
2615 nmcd
->hdr
.hwndFrom
= hwnd
;
2616 nmcd
->hdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
2617 nmcd
->hdr
.code
= NM_CUSTOMDRAW
;
2618 nmcd
->dwDrawStage
= dwDrawStage
;
2620 nmcd
->rc
.left
= rc
.left
;
2621 nmcd
->rc
.right
= rc
.right
;
2622 nmcd
->rc
.bottom
= rc
.bottom
;
2623 nmcd
->rc
.top
= rc
.top
;
2624 nmcd
->dwItemSpec
= 0;
2625 nmcd
->uItemState
= 0;
2626 nmcd
->lItemlParam
= 0;
2627 nmcdhdr
.clrText
= infoPtr
->clrText
;
2628 nmcdhdr
.clrTextBk
= infoPtr
->clrBk
;
2631 return (BOOL
)SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
2632 (WPARAM
) GetWindowLongA( hwnd
, GWL_ID
), (LPARAM
)&nmcdhdr
);
2638 /* FIXME: need to find out when the flags in uItemState need to be set */
2641 TREEVIEW_SendCustomDrawItemNotify (HWND hwnd
, HDC hdc
,
2642 TREEVIEW_ITEM
*wineItem
, UINT uItemDrawState
)
2644 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2645 NMTVCUSTOMDRAW nmcdhdr
;
2646 LPNMCUSTOMDRAW nmcd
;
2647 DWORD dwDrawStage
,dwItemSpec
;
2651 dwDrawStage
=CDDS_ITEM
| uItemDrawState
;
2652 dwItemSpec
=(DWORD
)wineItem
->hItem
;
2654 if (wineItem
->hItem
==infoPtr
->selectedItem
) uItemState
|=CDIS_SELECTED
;
2655 if (wineItem
->hItem
==infoPtr
->focusItem
) uItemState
|=CDIS_FOCUS
;
2656 if (wineItem
->hItem
==infoPtr
->hotItem
) uItemState
|=CDIS_HOT
;
2658 nmcd
= & nmcdhdr
.nmcd
;
2659 nmcd
->hdr
.hwndFrom
= hwnd
;
2660 nmcd
->hdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
2661 nmcd
->hdr
.code
= NM_CUSTOMDRAW
;
2662 nmcd
->dwDrawStage
= dwDrawStage
;
2664 nmcd
->rc
.left
= wineItem
->rect
.left
;
2665 nmcd
->rc
.right
= wineItem
->rect
.right
;
2666 nmcd
->rc
.bottom
= wineItem
->rect
.bottom
;
2667 nmcd
->rc
.top
= wineItem
->rect
.top
;
2668 nmcd
->dwItemSpec
= dwItemSpec
;
2669 nmcd
->uItemState
= uItemState
;
2670 nmcd
->lItemlParam
= wineItem
->lParam
;
2671 nmcdhdr
.clrText
= infoPtr
->clrText
;
2672 nmcdhdr
.clrTextBk
= infoPtr
->clrBk
;
2673 nmcdhdr
.iLevel
= wineItem
->iLevel
;
2675 TRACE("drawstage:%lx hdc:%x item:%lx, itemstate:%x, lItemlParam:%lx\n",
2676 nmcd
->dwDrawStage
, nmcd
->hdc
, nmcd
->dwItemSpec
,
2677 nmcd
->uItemState
, nmcd
->lItemlParam
);
2679 retval
=SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
2680 (WPARAM
) GetWindowLongA( hwnd
, GWL_ID
), (LPARAM
)&nmcdhdr
);
2682 infoPtr
->clrText
=nmcdhdr
.clrText
;
2683 infoPtr
->clrBk
=nmcdhdr
.clrTextBk
;
2684 return (BOOL
) retval
;
2689 /* Note:If the specified item is the child of a collapsed parent item,
2690 the parent's list of child items is (recursively) expanded to reveal the
2691 specified item. This is mentioned for TREEVIEW_SelectItem; don't
2692 know if it also applies here.
2696 TREEVIEW_Expand (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2698 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2699 TREEVIEW_ITEM
*wineItem
;
2703 flag
= (UINT
) wParam
;
2704 expand
= (INT
) lParam
;
2706 wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)expand
);
2710 if (!wineItem
->cChildren
)
2713 if (wineItem
->pszText
==LPSTR_TEXTCALLBACKA
)
2714 TRACE ("For item %d, flags %d, state %d\n",
2715 expand
, flag
, wineItem
->state
);
2717 TRACE("For (%s) item:%d, flags %x, state:%d\n",
2718 wineItem
->pszText
, flag
, expand
, wineItem
->state
);
2720 if (wineItem
->cChildren
==I_CHILDRENCALLBACK
) {
2721 FIXME("we don't handle I_CHILDRENCALLBACK yet\n");
2725 if (flag
== TVE_TOGGLE
) { /* FIXME: check exact behaviour here */
2726 flag
&= ~TVE_TOGGLE
; /* ie: bitwise ops or 'case' ops */
2727 if (wineItem
->state
& TVIS_EXPANDED
)
2728 flag
|= TVE_COLLAPSE
;
2735 case TVE_COLLAPSERESET
:
2736 TRACE(" case TVE_COLLAPSERESET\n");
2737 if (!wineItem
->state
& TVIS_EXPANDED
)
2740 wineItem
->state
&= ~(TVIS_EXPANDEDONCE
| TVIS_EXPANDED
);
2741 TREEVIEW_RemoveAllChildren (hwnd
, wineItem
);
2745 TRACE(" case TVE_COLLAPSE\n");
2746 if (!wineItem
->state
& TVIS_EXPANDED
)
2749 wineItem
->state
&= ~TVIS_EXPANDED
;
2753 TRACE(" case TVE_EXPAND\n");
2754 if (wineItem
->state
& TVIS_EXPANDED
)
2757 TRACE(" is not expanded...\n");
2759 if (!(wineItem
->state
& TVIS_EXPANDEDONCE
))
2761 TRACE(" and has never been expanded...\n");
2762 wineItem
->state
|= TVIS_EXPANDED
;
2764 /* this item has never been expanded */
2765 if (TREEVIEW_SendTreeviewNotify (
2772 TRACE(" TVN_ITEMEXPANDINGA returned TRUE, exiting...\n");
2777 * Since the TVN_ITEMEXPANDINGA message may has caused the parent to
2778 * insert new items which in turn may have cause items placeholder
2779 * reallocation, I reassign the current item pointer so we have
2780 * something valid to work with...
2781 * However, this should not be necessary,
2782 * investigation required in TREEVIEW_InsertItemA
2784 wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)expand
);
2788 "Catastropic situation, cannot retreive item #%d\n",
2793 wineItem
->state
|= TVIS_EXPANDEDONCE
;
2794 TRACE(" TVN_ITEMEXPANDINGA sent...\n");
2796 TREEVIEW_SendTreeviewNotify (
2803 TRACE(" TVN_ITEMEXPANDEDA sent...\n");
2808 /* this item has already been expanded */
2809 wineItem
->state
|= TVIS_EXPANDED
;
2813 case TVE_EXPANDPARTIAL
:
2814 TRACE(" case TVE_EXPANDPARTIAL\n");
2815 FIXME("TVE_EXPANDPARTIAL not implemented\n");
2816 wineItem
->state
^=TVIS_EXPANDED
;
2817 wineItem
->state
|=TVIS_EXPANDEDONCE
;
2821 TRACE("Exiting, Item %d state is now %d...\n",
2825 TREEVIEW_QueueRefresh (hwnd
);
2831 static TREEVIEW_ITEM
*
2832 TREEVIEW_HitTestPoint (HWND hwnd
, POINT pt
)
2834 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2835 TREEVIEW_ITEM
*wineItem
;
2838 GetClientRect (hwnd
, &rect
);
2840 if (!infoPtr
->firstVisible
) return NULL
;
2842 wineItem
=&infoPtr
->items
[(INT
)infoPtr
->firstVisible
];
2844 while ((wineItem
!=NULL
) && (pt
.y
> wineItem
->rect
.bottom
))
2845 wineItem
=TREEVIEW_GetNextListItem (infoPtr
,wineItem
);
2857 TREEVIEW_HitTest (HWND hwnd
, LPARAM lParam
)
2859 LPTVHITTESTINFO lpht
=(LPTVHITTESTINFO
) lParam
;
2860 TREEVIEW_ITEM
*wineItem
;
2864 GetClientRect (hwnd
, &rect
);
2868 if (x
< rect
.left
) status
|=TVHT_TOLEFT
;
2869 if (x
> rect
.right
) status
|=TVHT_TORIGHT
;
2870 if (y
< rect
.top
) status
|=TVHT_ABOVE
;
2871 if (y
> rect
.bottom
) status
|=TVHT_BELOW
;
2878 wineItem
=TREEVIEW_HitTestPoint (hwnd
, lpht
->pt
);
2880 lpht
->flags
=TVHT_NOWHERE
;
2886 if (x
< wineItem
->expandBox
.left
) {
2887 lpht
->flags
|= TVHT_ONITEMINDENT
;
2890 if ( PtInRect ( &wineItem
->expandBox
, lpht
->pt
)) {
2891 lpht
->flags
|= TVHT_ONITEMBUTTON
;
2894 if ( PtInRect ( &wineItem
->bitmap
, lpht
->pt
)) {
2895 lpht
->flags
|= TVHT_ONITEMICON
;
2898 if ( PtInRect ( &wineItem
->statebitmap
, lpht
->pt
)) {
2899 lpht
->flags
|= TVHT_ONITEMSTATEICON
;
2902 if ( PtInRect ( &wineItem
->text
, lpht
->pt
)) {
2903 lpht
->flags
|= TVHT_ONITEMLABEL
;
2907 lpht
->flags
|=TVHT_ONITEMRIGHT
;
2911 lpht
->hItem
=wineItem
->hItem
;
2912 TRACE ("(%ld,%ld):result %x\n",lpht
->pt
.x
,lpht
->pt
.y
,lpht
->flags
);
2914 return (LRESULT
) wineItem
->hItem
;
2918 TREEVIEW_EndEditLabelNow (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2920 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
2921 TREEVIEW_ITEM
*editedItem
= TREEVIEW_ValidItem (infoPtr
, infoPtr
->editItem
);
2922 BOOL bRevert
= (BOOL
)wParam
;
2923 BOOL bReturn
= ! bRevert
;
2925 if ( ! (BOOL
)wParam
) /* wParam is set to true to cancel the edition */
2927 if ( TREEVIEW_SendDispInfoNotify( /* return true to cancel edition */
2938 if (bRevert
== FALSE
) /* Apply the changes */
2941 int iLength
= GetWindowTextA(infoPtr
->hwndEdit
, tmpText
, 1023);
2946 ERR("Problem retreiving new item label.");
2948 else if (iLength
>= 1023)
2951 "Insuficient space to retrieve new item label, new label ignored.");
2955 if (strcmp( tmpText
, editedItem
->pszText
) == 0)
2956 /* Do nothing if the label has not changed */
2960 LPSTR tmpLabel
= COMCTL32_Alloc( iLength
+1 );
2962 if ( tmpLabel
== NULL
)
2964 "OutOfMemory, cannot allocate space for label");
2967 COMCTL32_Free(editedItem
->pszText
);
2968 editedItem
->pszText
= tmpLabel
;
2969 lstrcpyA( editedItem
->pszText
, tmpText
);
2975 ShowWindow(infoPtr
->hwndEdit
, SW_HIDE
);
2976 EnableWindow(infoPtr
->hwndEdit
, FALSE
);
2977 infoPtr
->editItem
= 0;
2986 TREEVIEW_LButtonDoubleClick (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2988 TREEVIEW_ITEM
*wineItem
;
2992 pt
.x
= (INT
)LOWORD(lParam
);
2993 pt
.y
= (INT
)HIWORD(lParam
);
2996 wineItem
=TREEVIEW_HitTestPoint (hwnd
, pt
);
2997 if (!wineItem
) return 0;
2998 TRACE("item %d \n",(INT
)wineItem
->hItem
);
3000 if (TREEVIEW_SendSimpleNotify (hwnd
, NM_DBLCLK
)!=TRUE
) { /* FIXME!*/
3001 TREEVIEW_Expand (hwnd
, (WPARAM
) TVE_TOGGLE
, (LPARAM
) wineItem
->hItem
);
3008 TREEVIEW_LButtonDown (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3010 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3014 ht
.pt
.x
= (INT
)LOWORD(lParam
);
3015 ht
.pt
.y
= (INT
)HIWORD(lParam
);
3018 iItem
=TREEVIEW_HitTest (hwnd
, (LPARAM
) &ht
);
3019 TRACE("item %d \n",iItem
);
3021 if (ht
.flags
& TVHT_ONITEMBUTTON
) {
3022 TREEVIEW_Expand (hwnd
, (WPARAM
) TVE_TOGGLE
, (LPARAM
) iItem
);
3026 infoPtr
->uInternalStatus
|=TV_LDRAG
;
3033 TREEVIEW_LButtonUp (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3035 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3037 TREEVIEW_ITEM
*wineItem
;
3040 ht
.pt
.x
= (INT
)LOWORD(lParam
);
3041 ht
.pt
.y
= (INT
)HIWORD(lParam
);
3045 /* Return true to cancel default behaviour */
3046 if ( TREEVIEW_SendSimpleNotify (hwnd
, NM_CLICK
) )
3050 iItem
= TREEVIEW_HitTest (hwnd
, (LPARAM
) &ht
);
3051 TRACE ("%d\n",iItem
);
3055 wineItem
= TREEVIEW_ValidItem(infoPtr
, (HTREEITEM
)iItem
);
3057 infoPtr
->uInternalStatus
&= ~(TV_LDRAG
| TV_LDRAGGING
);
3060 * If the style allow editing and the node is already selected
3061 * and the click occured on the item label...
3063 if ( ( GetWindowLongA( hwnd
, GWL_STYLE
) & TVS_EDITLABELS
) &&
3064 ( wineItem
->state
& TVIS_SELECTED
) &&
3065 ( ht
.flags
& TVHT_ONITEMLABEL
))
3067 if ( infoPtr
->editItem
== 0 ) /* If we are not curently editing */
3069 if ( TREEVIEW_SendDispInfoNotify( /* Return true to cancel edition */
3072 TVN_BEGINLABELEDITA
,
3078 TRACE("Edit started for %s.\n", wineItem
->pszText
);
3079 infoPtr
->editItem
= wineItem
->hItem
;
3084 wineItem
->text
.left
- 2,
3085 wineItem
->text
.top
- 1,
3086 wineItem
->text
.right
- wineItem
->text
.left
+ 20 ,
3087 wineItem
->text
.bottom
- wineItem
->text
.top
+ 3,
3090 SetWindowTextA( infoPtr
->hwndEdit
, wineItem
->pszText
);
3091 SendMessageA ( infoPtr
->hwndEdit
, EM_SETSEL
, 0, -1 );
3092 SetFocus ( infoPtr
->hwndEdit
);
3093 ShowWindow ( infoPtr
->hwndEdit
, SW_SHOW
);
3096 else if ( infoPtr
->editItem
!= 0 ) /* If we are curently editing */
3098 TREEVIEW_EndEditLabelNow(hwnd
, (WPARAM
)FALSE
, 0);
3100 else if ( ht
.flags
& (TVHT_ONITEMLABEL
| TVHT_ONITEMICON
))
3102 TREEVIEW_DoSelectItem ( hwnd
, TVGN_CARET
, (HTREEITEM
)iItem
, TVC_BYMOUSE
);
3105 if (ht
.flags
& TVHT_ONITEMSTATEICON
) {
3106 DWORD dwStyle
= GetWindowLongA (hwnd
, GWL_STYLE
);
3109 if (dwStyle
& TVS_CHECKBOXES
) { /* TVS_CHECKBOXES requires _us_ */
3110 int state
; /* to toggle the current state */
3111 state
=1-(wineItem
->state
>>12);
3112 TRACE ("state:%x\n", state
);
3113 wineItem
->state
&= ~TVIS_STATEIMAGEMASK
;
3114 wineItem
->state
|=state
<<12;
3115 TRACE ("state:%x\n", wineItem
->state
);
3116 TREEVIEW_QueueRefresh (hwnd
);
3124 TREEVIEW_RButtonDown (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3126 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3129 infoPtr
->uInternalStatus
|=TV_RDRAG
;
3134 TREEVIEW_RButtonUp (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3136 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3139 if (TREEVIEW_SendSimpleNotify (hwnd
, NM_RCLICK
)) return 0;
3140 infoPtr
->uInternalStatus
&= ~(TV_RDRAG
| TV_RDRAGGING
);
3146 TREEVIEW_MouseMove (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3148 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3149 TREEVIEW_ITEM
*hotItem
;
3152 pt
.x
=(INT
) LOWORD (lParam
);
3153 pt
.y
=(INT
) HIWORD (lParam
);
3154 hotItem
=TREEVIEW_HitTestPoint (hwnd
, pt
);
3155 if (!hotItem
) return 0;
3156 infoPtr
->focusItem
=hotItem
->hItem
;
3158 if ( GetWindowLongA( hwnd
, GWL_STYLE
) & TVS_DISABLEDRAGDROP
) return 0;
3160 if (infoPtr
->uInternalStatus
& TV_LDRAG
) {
3161 TREEVIEW_SendTreeviewDnDNotify (hwnd
, TVN_BEGINDRAGA
, hotItem
->hItem
, pt
);
3162 infoPtr
->uInternalStatus
&= ~TV_LDRAG
;
3163 infoPtr
->uInternalStatus
|= TV_LDRAGGING
;
3164 infoPtr
->dropItem
=hotItem
->hItem
;
3168 if (infoPtr
->uInternalStatus
& TV_RDRAG
) {
3169 TREEVIEW_SendTreeviewDnDNotify (hwnd
, TVN_BEGINRDRAGA
, hotItem
->hItem
, pt
);
3170 infoPtr
->uInternalStatus
&= ~TV_RDRAG
;
3171 infoPtr
->uInternalStatus
|= TV_RDRAGGING
;
3172 infoPtr
->dropItem
=hotItem
->hItem
;
3181 TREEVIEW_CreateDragImage (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3183 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3184 TREEVIEW_ITEM
*dragItem
;
3188 HBITMAP hbmp
,hOldbmp
;
3195 if (!(infoPtr
->himlNormal
)) return 0;
3196 dragItem
=TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
) lParam
);
3198 if (!dragItem
) return 0;
3200 if (dragItem
->pszText
==LPSTR_TEXTCALLBACKA
) {
3201 TREEVIEW_SendDispInfoNotify (hwnd
, dragItem
, TVN_GETDISPINFOA
, TVIF_TEXT
);
3203 itemtxt
=dragItem
->pszText
;
3205 hwtop
=GetDesktopWindow ();
3206 htopdc
= GetDC (hwtop
);
3207 hdc
=CreateCompatibleDC (htopdc
);
3209 hOldFont
=SelectObject (hdc
, infoPtr
->hFont
);
3210 GetTextExtentPoint32A (hdc
, itemtxt
, lstrlenA (itemtxt
), &size
);
3211 TRACE("%d %d %s %d\n",size
.cx
,size
.cy
,itemtxt
,lstrlenA(itemtxt
));
3212 hbmp
=CreateCompatibleBitmap (htopdc
, size
.cx
, size
.cy
);
3213 hOldbmp
=SelectObject (hdc
, hbmp
);
3215 ImageList_GetIconSize (infoPtr
->himlNormal
, &cx
, &cy
);
3217 if (cy
>size
.cy
) size
.cy
=cy
;
3219 infoPtr
->dragList
=ImageList_Create (size
.cx
, size
.cy
, ILC_COLOR
, 10, 10);
3220 ImageList_Draw (infoPtr
->himlNormal
, dragItem
->iImage
, hdc
, 0, 0, ILD_NORMAL
);
3223 ImageList_GetImageInfo (infoPtr->himlNormal, dragItem->hItem, &iminfo);
3224 ImageList_AddMasked (infoPtr->dragList, iminfo.hbmImage, CLR_DEFAULT);
3227 /* draw item text */
3229 SetRect (&rc
, cx
, 0, size
.cx
,size
.cy
);
3230 DrawTextA (hdc
, itemtxt
, lstrlenA (itemtxt
), &rc
, DT_LEFT
);
3231 SelectObject (hdc
, hOldFont
);
3232 SelectObject (hdc
, hOldbmp
);
3234 ImageList_Add (infoPtr
->dragList
, hbmp
, 0);
3237 DeleteObject (hbmp
);
3238 ReleaseDC (hwtop
, htopdc
);
3240 return (LRESULT
)infoPtr
->dragList
;
3245 TREEVIEW_DoSelectItem (HWND hwnd
, INT action
, HTREEITEM newSelect
, INT cause
)
3248 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3249 TREEVIEW_ITEM
*prevItem
,*wineItem
;
3252 wineItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)newSelect
);
3254 TRACE("Entering item %d, flag %x, cause %x, state %d\n",
3260 if ( (wineItem
) && (wineItem
->parent
))
3263 * If the item has a collapse parent expand the parent so he
3264 * can expose the item
3266 TREEVIEW_ITEM
*parentItem
= TREEVIEW_ValidItem (infoPtr
, wineItem
->parent
);
3267 if ( !(parentItem
->state
& TVIS_EXPANDED
))
3268 TREEVIEW_Expand (hwnd
, TVE_EXPAND
, (LPARAM
) wineItem
->parent
);
3274 prevSelect
=(INT
)infoPtr
->selectedItem
;
3276 if ((HTREEITEM
)prevSelect
==newSelect
)
3279 prevItem
= TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)prevSelect
);
3282 if (TREEVIEW_SendTreeviewNotify(
3286 (HTREEITEM
)prevSelect
,
3287 (HTREEITEM
)newSelect
))
3288 return FALSE
; /* FIXME: OK? */
3291 prevItem
->state
&= ~TVIS_SELECTED
;
3293 wineItem
->state
|= TVIS_SELECTED
;
3295 infoPtr
->selectedItem
=(HTREEITEM
)newSelect
;
3297 TREEVIEW_SendTreeviewNotify(
3301 (HTREEITEM
)prevSelect
,
3302 (HTREEITEM
)newSelect
);
3306 case TVGN_DROPHILITE
:
3307 prevItem
= TREEVIEW_ValidItem (infoPtr
, infoPtr
->dropItem
);
3310 prevItem
->state
&= ~TVIS_DROPHILITED
;
3312 infoPtr
->dropItem
=(HTREEITEM
)newSelect
;
3315 wineItem
->state
|=TVIS_DROPHILITED
;
3319 case TVGN_FIRSTVISIBLE
:
3320 FIXME("FIRSTVISIBLE not implemented\n");
3324 TREEVIEW_QueueRefresh (hwnd
);
3326 TRACE("Leaving state %d\n", wineItem
->state
);
3330 /* FIXME: handle NM_KILLFocus etc */
3332 TREEVIEW_SelectItem (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3335 return TREEVIEW_DoSelectItem (hwnd
, wParam
, (HTREEITEM
) lParam
, TVC_UNKNOWN
);
3342 TREEVIEW_GetFont (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3345 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3347 TRACE("%x\n",infoPtr
->hFont
);
3348 return infoPtr
->hFont
;
3352 TREEVIEW_SetFont (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3355 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3358 HFONT hFont
, hOldFont
;
3362 TRACE("%x %lx\n",wParam
, lParam
);
3364 infoPtr
->hFont
= (HFONT
)wParam
;
3366 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: GetStockObject (SYSTEM_FONT
);
3368 GetObjectA (infoPtr
->hFont
, sizeof (LOGFONTA
), &logFont
);
3369 logFont
.lfWeight
=FW_BOLD
;
3370 infoPtr
->hBoldFont
= CreateFontIndirectA (&logFont
);
3373 hOldFont
= SelectObject (hdc
, hFont
);
3374 GetTextMetricsA (hdc
, &tm
);
3375 height
= tm
.tmHeight
+ tm
.tmExternalLeading
;
3376 if (height
>infoPtr
->uRealItemHeight
)
3377 infoPtr
->uRealItemHeight
=height
;
3378 SelectObject (hdc
, hOldFont
);
3382 TREEVIEW_QueueRefresh (hwnd
);
3390 TREEVIEW_VScroll (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3393 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3396 TRACE("wp %x, lp %lx\n", wParam
, lParam
);
3397 if (!infoPtr
->uInternalStatus
& TV_VSCROLL
) return FALSE
;
3399 switch (LOWORD (wParam
)) {
3401 if (!infoPtr
->cy
) return FALSE
;
3402 infoPtr
->cy
-= infoPtr
->uRealItemHeight
;
3403 if (infoPtr
->cy
< 0) infoPtr
->cy
=0;
3406 maxHeight
=infoPtr
->uTotalHeight
-infoPtr
->uVisibleHeight
;
3407 if (infoPtr
->cy
== maxHeight
) return FALSE
;
3408 infoPtr
->cy
+= infoPtr
->uRealItemHeight
;
3409 if (infoPtr
->cy
> maxHeight
)
3410 infoPtr
->cy
= maxHeight
;
3413 if (!infoPtr
->cy
) return FALSE
;
3414 infoPtr
->cy
-= infoPtr
->uVisibleHeight
;
3415 if (infoPtr
->cy
< 0) infoPtr
->cy
=0;
3418 maxHeight
=infoPtr
->uTotalHeight
-infoPtr
->uVisibleHeight
;
3419 if (infoPtr
->cy
== maxHeight
) return FALSE
;
3420 infoPtr
->cy
+= infoPtr
->uVisibleHeight
;
3421 if (infoPtr
->cy
> maxHeight
)
3422 infoPtr
->cy
= maxHeight
;
3425 infoPtr
->cy
= HIWORD (wParam
);
3430 TREEVIEW_QueueRefresh (hwnd
);
3435 TREEVIEW_HScroll (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3437 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3440 TRACE("wp %lx, lp %x\n", lParam
, wParam
);
3442 if (!infoPtr
->uInternalStatus
& TV_HSCROLL
) return FALSE
;
3444 switch (LOWORD (wParam
)) {
3446 if (!infoPtr
->cx
) return FALSE
;
3447 infoPtr
->cx
-= infoPtr
->uRealItemHeight
;
3448 if (infoPtr
->cx
< 0) infoPtr
->cx
=0;
3451 maxWidth
=infoPtr
->uTotalWidth
-infoPtr
->uVisibleWidth
;
3452 if (infoPtr
->cx
== maxWidth
) return FALSE
;
3453 infoPtr
->cx
+= infoPtr
->uRealItemHeight
; /*FIXME */
3454 if (infoPtr
->cx
> maxWidth
)
3455 infoPtr
->cx
= maxWidth
;
3458 if (!infoPtr
->cx
) return FALSE
;
3459 infoPtr
->cx
-= infoPtr
->uVisibleWidth
;
3460 if (infoPtr
->cx
< 0) infoPtr
->cx
=0;
3463 maxWidth
=infoPtr
->uTotalWidth
-infoPtr
->uVisibleWidth
;
3464 if (infoPtr
->cx
== maxWidth
) return FALSE
;
3465 infoPtr
->cx
+= infoPtr
->uVisibleWidth
;
3466 if (infoPtr
->cx
> maxWidth
)
3467 infoPtr
->cx
= maxWidth
;
3470 infoPtr
->cx
= HIWORD (wParam
);
3475 TREEVIEW_QueueRefresh (hwnd
);
3479 static LRESULT
TREEVIEW_MouseWheel (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3482 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3483 short gcWheelDelta
= 0;
3484 UINT pulScrollLines
= 3;
3486 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES
,0, &pulScrollLines
, 0);
3488 gcWheelDelta
-= (short) HIWORD(wParam
);
3489 pulScrollLines
*= (gcWheelDelta
/ WHEEL_DELTA
);
3491 if (abs(gcWheelDelta
) >= WHEEL_DELTA
&& pulScrollLines
)
3493 int wheelDy
= pulScrollLines
* infoPtr
->uRealItemHeight
;
3494 int newDy
= infoPtr
->cy
+ wheelDy
;
3495 int maxDy
= infoPtr
->uTotalHeight
- infoPtr
->uVisibleHeight
;
3497 if (newDy
> maxDy
) newDy
= maxDy
;
3498 if (newDy
< 0) newDy
= 0;
3500 if (newDy
== infoPtr
->cy
) return TRUE
;
3502 TREEVIEW_VScroll(hwnd
, MAKEWPARAM(SB_THUMBTRACK
,newDy
),0);
3508 TREEVIEW_KeyDown (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3510 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3511 HTREEITEM hNewSelection
= 0;
3512 INT scrollNeeds
= -1;
3513 INT cyChangeNeeds
= -1;
3514 INT prevSelect
= (INT
)infoPtr
->selectedItem
;
3516 TREEVIEW_ITEM
*prevItem
=
3517 (prevSelect
!= 0 ) ?
3518 TREEVIEW_ValidItem (infoPtr
, (HTREEITEM
)prevSelect
) :
3521 TREEVIEW_ITEM
*newItem
= NULL
;
3523 TRACE("%x %lx\n",wParam
, lParam
);
3525 if (prevSelect
== 0)
3530 newItem
=TREEVIEW_GetPrevListItem (infoPtr
, prevItem
);
3533 newItem
=& infoPtr
->items
[(INT
)infoPtr
->TopRootItem
];
3535 hNewSelection
= newItem
->hItem
;
3537 if (! newItem
->visible
)
3538 scrollNeeds
= SB_LINEUP
;
3542 newItem
=TREEVIEW_GetNextListItem (infoPtr
, prevItem
);
3547 hNewSelection
= newItem
->hItem
;
3549 if (! newItem
->visible
)
3550 scrollNeeds
= SB_LINEDOWN
;
3555 newItem
= &infoPtr
->items
[(INT
)infoPtr
->TopRootItem
];
3556 hNewSelection
= newItem
->hItem
;
3561 newItem
= &infoPtr
->items
[(INT
)infoPtr
->TopRootItem
];
3562 newItem
= TREEVIEW_GetLastListItem (infoPtr
, newItem
);
3563 hNewSelection
= newItem
->hItem
;
3565 if (! newItem
->visible
)
3566 cyChangeNeeds
= infoPtr
->uTotalHeight
-infoPtr
->uVisibleHeight
;
3571 if ( (prevItem
->cChildren
> 0) && (prevItem
->state
& TVIS_EXPANDED
) )
3573 TREEVIEW_Expand(hwnd
, TVE_COLLAPSE
, prevSelect
);
3575 else if ((INT
)prevItem
->parent
)
3577 newItem
= (& infoPtr
->items
[(INT
)prevItem
->parent
]);
3578 if (! newItem
->visible
)
3579 /* FIXME find a way to make this item the first visible... */
3582 hNewSelection
= newItem
->hItem
;
3588 if ( ( prevItem
->cChildren
> 0) ||
3589 ( prevItem
->cChildren
== I_CHILDRENCALLBACK
))
3591 if (! (prevItem
->state
& TVIS_EXPANDED
))
3592 TREEVIEW_Expand(hwnd
, TVE_EXPAND
, prevSelect
);
3595 newItem
= (& infoPtr
->items
[(INT
)prevItem
->firstChild
]);
3596 hNewSelection
= newItem
->hItem
;
3603 if (! (prevItem
->state
& TVIS_EXPANDED
))
3604 TREEVIEW_Expand(hwnd
, TVE_EXPAND
, prevSelect
);
3608 if (prevItem
->state
& TVIS_EXPANDED
)
3609 TREEVIEW_Expand(hwnd
, TVE_COLLAPSE
, prevSelect
);
3614 newItem
=TREEVIEW_GetListItem(
3617 -1*(TREEVIEW_GetVisibleCount(hwnd
,0,0)-3));
3621 hNewSelection
= newItem
->hItem
;
3623 if (! newItem
->visible
)
3624 scrollNeeds
= SB_PAGEUP
;
3629 newItem
=TREEVIEW_GetListItem(
3632 TREEVIEW_GetVisibleCount(hwnd
,0,0)-3);
3637 hNewSelection
= newItem
->hItem
;
3639 if (! newItem
->visible
)
3640 scrollNeeds
= SB_PAGEDOWN
;
3649 FIXME("%x not implemented\n", wParam
);
3656 This works but does not send notification...
3658 prevItem->state &= ~TVIS_SELECTED;
3659 newItem->state |= TVIS_SELECTED;
3660 infoPtr->selectedItem = hNewSelection;
3661 TREEVIEW_QueueRefresh (hwnd);
3664 if ( TREEVIEW_DoSelectItem(
3667 (HTREEITEM
)hNewSelection
,
3670 /* If selection change is allowed for the new item, perform scrolling */
3671 if (scrollNeeds
!= -1)
3672 TREEVIEW_VScroll(hwnd
, scrollNeeds
, 0);
3674 if (cyChangeNeeds
!= -1)
3675 infoPtr
->cy
= cyChangeNeeds
;
3677 /* FIXME: Something happen in the load the in the two weeks before
3678 april 1st 1999 which makes this SetFocus mandatory otherwise, the focus
3679 is lost... However the SetFocus should not be required...*/
3690 TREEVIEW_GetScrollTime (HWND hwnd
)
3692 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3694 return infoPtr
->uScrollTime
;
3699 TREEVIEW_SetScrollTime (HWND hwnd
, UINT uScrollTime
)
3701 TREEVIEW_INFO
*infoPtr
= TREEVIEW_GetInfoPtr(hwnd
);
3702 UINT uOldScrollTime
= infoPtr
->uScrollTime
;
3704 infoPtr
->uScrollTime
= min (uScrollTime
, 100);
3706 return uOldScrollTime
;
3710 static LRESULT WINAPI
3711 TREEVIEW_WindowProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
3713 if (uMsg
==WM_CREATE
)
3714 return TREEVIEW_Create (hwnd
, wParam
, lParam
);
3716 if (!TREEVIEW_GetInfoPtr(hwnd
))
3717 return DefWindowProcA (hwnd
, uMsg
, wParam
, lParam
);
3721 case TVM_INSERTITEMA
:
3722 return TREEVIEW_InsertItemA (hwnd
, wParam
, lParam
);
3724 case TVM_INSERTITEMW
:
3725 return TREEVIEW_InsertItemW(hwnd
,wParam
,lParam
);;
3727 case TVM_DELETEITEM
:
3728 return TREEVIEW_DeleteItem (hwnd
, wParam
, lParam
);
3731 return TREEVIEW_Expand (hwnd
, wParam
, lParam
);
3733 case TVM_GETITEMRECT
:
3734 return TREEVIEW_GetItemRect (hwnd
, wParam
, lParam
);
3737 return TREEVIEW_GetCount (hwnd
, wParam
, lParam
);
3740 return TREEVIEW_GetIndent (hwnd
);
3743 return TREEVIEW_SetIndent (hwnd
, wParam
);
3745 case TVM_GETIMAGELIST
:
3746 return TREEVIEW_GetImageList (hwnd
, wParam
, lParam
);
3748 case TVM_SETIMAGELIST
:
3749 return TREEVIEW_SetImageList (hwnd
, wParam
, lParam
);
3751 case TVM_GETNEXTITEM
:
3752 return TREEVIEW_GetNextItem (hwnd
, wParam
, lParam
);
3754 case TVM_SELECTITEM
:
3755 return TREEVIEW_SelectItem (hwnd
, wParam
, lParam
);
3758 return TREEVIEW_GetItemA (hwnd
, wParam
, lParam
);
3761 FIXME("Unimplemented msg TVM_GETITEMW\n");
3765 return TREEVIEW_SetItemA (hwnd
, wParam
, lParam
);
3768 FIXME("Unimplemented msg TVM_SETITEMW\n");
3771 case TVM_EDITLABELA
:
3772 FIXME("Unimplemented msg TVM_EDITLABELA \n");
3775 case TVM_EDITLABELW
:
3776 FIXME("Unimplemented msg TVM_EDITLABELW \n");
3779 case TVM_GETEDITCONTROL
:
3780 return TREEVIEW_GetEditControl (hwnd
);
3782 case TVM_GETVISIBLECOUNT
:
3783 return TREEVIEW_GetVisibleCount (hwnd
, wParam
, lParam
);
3786 return TREEVIEW_HitTest (hwnd
, lParam
);
3788 case TVM_CREATEDRAGIMAGE
:
3789 return TREEVIEW_CreateDragImage (hwnd
, wParam
, lParam
);
3791 case TVM_SORTCHILDREN
:
3792 return TREEVIEW_SortChildren (hwnd
, wParam
, lParam
);
3794 case TVM_ENSUREVISIBLE
:
3795 FIXME("Unimplemented msg TVM_ENSUREVISIBLE\n");
3798 case TVM_SORTCHILDRENCB
:
3799 return TREEVIEW_SortChildrenCB(hwnd
, wParam
, lParam
);
3801 case TVM_ENDEDITLABELNOW
:
3802 return TREEVIEW_EndEditLabelNow (hwnd
, wParam
, lParam
);
3804 case TVM_GETISEARCHSTRINGA
:
3805 FIXME("Unimplemented msg TVM_GETISEARCHSTRINGA\n");
3808 case TVM_GETISEARCHSTRINGW
:
3809 FIXME("Unimplemented msg TVM_GETISEARCHSTRINGW\n");
3812 case TVM_GETTOOLTIPS
:
3813 return TREEVIEW_GetToolTips (hwnd
);
3815 case TVM_SETTOOLTIPS
:
3816 return TREEVIEW_SetToolTips (hwnd
, wParam
);
3818 case TVM_SETINSERTMARK
:
3819 return TREEVIEW_SetInsertMark (hwnd
,wParam
, lParam
);
3821 case TVM_SETITEMHEIGHT
:
3822 return TREEVIEW_SetItemHeight (hwnd
, wParam
);
3824 case TVM_GETITEMHEIGHT
:
3825 return TREEVIEW_GetItemHeight (hwnd
);
3827 case TVM_SETBKCOLOR
:
3828 return TREEVIEW_SetBkColor (hwnd
, wParam
, lParam
);
3830 case TVM_SETTEXTCOLOR
:
3831 return TREEVIEW_SetTextColor (hwnd
, wParam
, lParam
);
3833 case TVM_GETBKCOLOR
:
3834 return TREEVIEW_GetBkColor (hwnd
);
3836 case TVM_GETTEXTCOLOR
:
3837 return TREEVIEW_GetTextColor (hwnd
);
3839 case TVM_SETSCROLLTIME
:
3840 return TREEVIEW_SetScrollTime (hwnd
, (UINT
)wParam
);
3842 case TVM_GETSCROLLTIME
:
3843 return TREEVIEW_GetScrollTime (hwnd
);
3845 case TVM_GETITEMSTATE
:
3846 return TREEVIEW_GetItemState (hwnd
,wParam
, lParam
);
3848 case TVM_GETLINECOLOR
:
3849 return TREEVIEW_GetLineColor (hwnd
,wParam
, lParam
);
3851 case TVM_SETLINECOLOR
:
3852 return TREEVIEW_SetLineColor (hwnd
,wParam
, lParam
);
3854 case TVM_SETINSERTMARKCOLOR
:
3855 return TREEVIEW_SetInsertMarkColor (hwnd
,wParam
, lParam
);
3857 case TVM_GETINSERTMARKCOLOR
:
3858 return TREEVIEW_GetInsertMarkColor (hwnd
,wParam
, lParam
);
3860 case TVM_SETUNICODEFORMAT
:
3861 FIXME("Unimplemented msg TVM_SETUNICODEFORMAT\n");
3864 case TVM_GETUNICODEFORMAT
:
3865 FIXME("Unimplemented msg TVM_GETUNICODEFORMAT\n");
3869 return TREEVIEW_Command (hwnd
, wParam
, lParam
);
3872 return TREEVIEW_Destroy (hwnd
);
3874 /* case WM_ENABLE: */
3877 return TREEVIEW_EraseBackground (hwnd
, wParam
, lParam
);
3880 return DLGC_WANTARROWS
| DLGC_WANTCHARS
;
3883 return TREEVIEW_Paint (hwnd
, wParam
, lParam
);
3886 return TREEVIEW_GetFont (hwnd
, wParam
, lParam
);
3889 return TREEVIEW_SetFont (hwnd
, wParam
, lParam
);
3892 return TREEVIEW_KeyDown (hwnd
, wParam
, lParam
);
3895 return TREEVIEW_SetFocus (hwnd
, wParam
, lParam
);
3898 return TREEVIEW_KillFocus (hwnd
, wParam
, lParam
);
3900 case WM_LBUTTONDOWN
:
3901 return TREEVIEW_LButtonDown (hwnd
, wParam
, lParam
);
3904 return TREEVIEW_LButtonUp (hwnd
, wParam
, lParam
);
3906 case WM_LBUTTONDBLCLK
:
3907 return TREEVIEW_LButtonDoubleClick (hwnd
, wParam
, lParam
);
3909 case WM_RBUTTONDOWN
:
3910 return TREEVIEW_RButtonDown (hwnd
, wParam
, lParam
);
3913 return TREEVIEW_RButtonUp (hwnd
, wParam
, lParam
);
3916 return TREEVIEW_MouseMove (hwnd
, wParam
, lParam
);
3918 case WM_STYLECHANGED
:
3919 return TREEVIEW_StyleChanged (hwnd
, wParam
, lParam
);
3921 /* case WM_SYSCOLORCHANGE: */
3922 /* case WM_SETREDRAW: */
3925 return TREEVIEW_HandleTimer (hwnd
, wParam
, lParam
);
3928 return TREEVIEW_Size (hwnd
, wParam
,lParam
);
3931 return TREEVIEW_HScroll (hwnd
, wParam
, lParam
);
3933 return TREEVIEW_VScroll (hwnd
, wParam
, lParam
);
3936 if (wParam
& (MK_SHIFT
| MK_CONTROL
))
3937 return DefWindowProcA( hwnd
, uMsg
, wParam
, lParam
);
3938 return TREEVIEW_MouseWheel (hwnd
, wParam
, lParam
);
3941 TRACE ("drawItem\n");
3942 return DefWindowProcA (hwnd
, uMsg
, wParam
, lParam
);
3945 if (uMsg
>= WM_USER
)
3946 FIXME("Unknown msg %04x wp=%08x lp=%08lx\n",
3947 uMsg
, wParam
, lParam
);
3948 return DefWindowProcA (hwnd
, uMsg
, wParam
, lParam
);
3955 TREEVIEW_Register (void)
3961 ZeroMemory (&wndClass
, sizeof(WNDCLASSA
));
3962 wndClass
.style
= CS_GLOBALCLASS
| CS_DBLCLKS
;
3963 wndClass
.lpfnWndProc
= (WNDPROC
)TREEVIEW_WindowProc
;
3964 wndClass
.cbClsExtra
= 0;
3965 wndClass
.cbWndExtra
= sizeof(TREEVIEW_INFO
*);
3966 wndClass
.hCursor
= LoadCursorA (0, IDC_ARROWA
);
3967 wndClass
.hbrBackground
= 0;
3968 wndClass
.lpszClassName
= WC_TREEVIEWA
;
3970 RegisterClassA (&wndClass
);
3975 TREEVIEW_Unregister (void)
3977 UnregisterClassA (WC_TREEVIEWA
, (HINSTANCE
)NULL
);