3 * Copyright 1998 Eric Kohl <ekohl@abo.rhein-zeitung.de>
4 * Copyright 1998,1999 Alex Priem <alexp@sci.kun.nl>
5 * Copyright 1999 Sylvain St-Germain
9 * Using DPA to store the item ptr would be good.
10 * Node label edition is implemented but something appened in wine in the
11 * two last weeks of march 99 that broke it.
13 -small array containing info about positions.
14 -better implementation of RefreshItem:
15 1) draw lines between parents
17 3) draw lines from parent<->items.
18 -implement partial drawing?
19 * -drag&drop: TVM_CREATEDRAGIMAGE should create drag bitmap.
20 * -scrollbars: horizontal scrollbar doesn't work.
24 * FIXME: check fontsize. (uRealItemHeight)
25 * test focusItem (redraw in different color)
28 better implementation.
29 * WM_HSCROLL is broken.
30 * use separate routine to get item text/image.
32 * Separate drawing/calculation.
34 * FIXMEs (for personal use)
35 Expand: -ctlmacro expands twice ->toggle.
36 -DblClick: ctlmacro.exe's NM_DBLCLK seems to go wrong (returns FALSE).
37 -treehelper: stack corruption makes big window.
47 #include "debugtools.h"
49 DEFAULT_DEBUG_CHANNEL(treeview)
51 /* ffs should be in <string.h>. */
53 /* Defines, since they do not need to return previous state, and nr
54 * has no side effects in this file.
56 #define tv_test_bit(nr,bf) (((LPBYTE)bf)[nr>>3]&(1<<(nr&7)))
57 #define tv_set_bit(nr,bf) ((LPBYTE)bf)[nr>>3]|=(1<<(nr&7))
58 #define tv_clear_bit(nr,bf) ((LPBYTE)bf)[nr>>3]&=~(1<<(nr&7))
61 #define TREEVIEW_GetInfoPtr(hwnd) \
62 ((TREEVIEW_INFO *) GetWindowLongA( hwnd, 0))
65 TREEVIEW_SendSimpleNotify (HWND hwnd, UINT code);
67 TREEVIEW_SendTreeviewNotify (HWND hwnd, UINT code, UINT action,
68 HTREEITEM oldItem, HTREEITEM newItem);
70 TREEVIEW_SendTreeviewDnDNotify (HWND hwnd, UINT code, HTREEITEM dragItem,
73 TREEVIEW_SendDispInfoNotify (HWND hwnd, TREEVIEW_ITEM *wineItem,
74 UINT code, UINT what);
76 TREEVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
79 TREEVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
80 TREEVIEW_ITEM *tvItem, UINT uItemDrawState);
82 TREEVIEW_DoSelectItem (HWND hwnd, INT action, HTREEITEM newSelect, INT cause);
84 TREEVIEW_Refresh (HWND hwnd);
86 static LRESULT CALLBACK
87 TREEVIEW_Edit_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam,
91 TREEVIEW_EndEditLabelNow (HWND hwnd, WPARAM wParam, LPARAM lParam);
96 /* helper functions. Work with the assumption that validity of operands
97 is checked beforehand, and that tree state is valid. */
99 /* FIXME: MS documentation says `GetNextVisibleItem' returns NULL
100 if not succesfull'. Probably only applies to derefencing infoPtr
101 (ie we are offered a valid treeview structure)
102 and not whether there is a next `visible' child.
103 FIXME: check other failures.
106 /***************************************************************************
107 * This method returns the TREEVIEW_ITEM object given the handle
109 static TREEVIEW_ITEM* TREEVIEW_ValidItem(
110 TREEVIEW_INFO *infoPtr,
113 if ((!handle) || (handle>infoPtr->uMaxHandle))
116 if (tv_test_bit ((INT)handle, infoPtr->freeList))
119 return &infoPtr->items[(INT)handle];
122 /***************************************************************************
123 * This method returns the last expanded child item of a tree node
125 static TREEVIEW_ITEM *TREEVIEW_GetLastListItem(
126 TREEVIEW_INFO *infoPtr,
127 TREEVIEW_ITEM *tvItem)
130 TREEVIEW_ITEM *wineItem = tvItem;
133 * Get this item last sibling
135 while (wineItem->sibling)
136 wineItem=& infoPtr->items [(INT)wineItem->sibling];
139 * If the last sibling has expanded children, restart.
141 if ( ( wineItem->cChildren > 0 ) && ( wineItem->state & TVIS_EXPANDED) )
142 return TREEVIEW_GetLastListItem(
144 &(infoPtr->items[(INT)wineItem->firstChild]));
149 /***************************************************************************
150 * This method returns the previous physical item in the list not
151 * considering the tree hierarchy.
153 static TREEVIEW_ITEM *TREEVIEW_GetPrevListItem(
154 TREEVIEW_INFO *infoPtr,
155 TREEVIEW_ITEM *tvItem)
157 if (tvItem->upsibling)
160 * This item has a upsibling, get the last item. Since, GetLastListItem
161 * first looks at siblings, we must feed it with the first child.
163 TREEVIEW_ITEM *upItem = &infoPtr->items[(INT)tvItem->upsibling];
165 if ( ( upItem->cChildren > 0 ) && ( upItem->state & TVIS_EXPANDED) )
166 return TREEVIEW_GetLastListItem(
168 &infoPtr->items[(INT)upItem->firstChild]);
175 * this item does not have a upsibling, get the parent
178 return &infoPtr->items[(INT)tvItem->parent];
185 /***************************************************************************
186 * This method returns the next physical item in the treeview not
187 * considering the tree hierarchy.
189 static TREEVIEW_ITEM *TREEVIEW_GetNextListItem(
190 TREEVIEW_INFO *infoPtr,
191 TREEVIEW_ITEM *tvItem)
193 TREEVIEW_ITEM *wineItem = NULL;
196 * If this item has children and is expanded, return the first child
198 if ((tvItem->firstChild) && (tvItem->state & TVIS_EXPANDED))
199 return (& infoPtr->items[(INT)tvItem->firstChild]);
203 * try to get the sibling
206 return (& infoPtr->items[(INT)tvItem->sibling]);
209 * Otherwise, get the parent's sibling.
212 while (wineItem->parent) {
213 wineItem=& infoPtr->items [(INT)wineItem->parent];
214 if (wineItem->sibling)
215 return (& infoPtr->items [(INT)wineItem->sibling]);
221 /***************************************************************************
222 * This method returns the nth item starting at the given item. It returns
223 * the last item (or first) we we run out of items.
225 * Will scroll backward if count is <0.
226 * forward if count is >0.
228 static TREEVIEW_ITEM *TREEVIEW_GetListItem(
229 TREEVIEW_INFO *infoPtr,
230 TREEVIEW_ITEM *tvItem,
233 TREEVIEW_ITEM *previousItem = NULL;
234 TREEVIEW_ITEM *wineItem = tvItem;
239 /* Find count item downward */
240 while ((iter++ < count) && (wineItem != NULL))
242 /* Keep a pointer to the previous in case we ask for more than we got */
243 previousItem = wineItem;
244 wineItem = TREEVIEW_GetNextListItem(infoPtr, wineItem);
247 if (wineItem == NULL)
248 wineItem = previousItem;
252 /* Find count item upward */
253 while ((iter-- > count) && (wineItem != NULL))
255 /* Keep a pointer to the previous in case we ask for more than we got */
256 previousItem = wineItem;
257 wineItem = TREEVIEW_GetPrevListItem(infoPtr, wineItem);
260 if (wineItem == NULL)
261 wineItem = previousItem;
270 /***************************************************************************
273 static void TREEVIEW_RemoveAllChildren(
275 TREEVIEW_ITEM *parentItem)
277 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
278 TREEVIEW_ITEM *killItem;
281 kill=(INT)parentItem->firstChild;
283 tv_set_bit ( kill, infoPtr->freeList);
284 killItem=& infoPtr->items[kill];
285 if (killItem->pszText!=LPSTR_TEXTCALLBACKA)
286 COMCTL32_Free (killItem->pszText);
287 TREEVIEW_SendTreeviewNotify (hwnd, TVN_DELETEITEM, 0, (HTREEITEM)kill, 0);
288 if (killItem->firstChild)
289 TREEVIEW_RemoveAllChildren (hwnd, killItem);
290 kill=(INT)killItem->sibling;
293 if (parentItem->cChildren>0) {
294 infoPtr->uNumItems -= parentItem->cChildren;
295 parentItem->firstChild = 0;
296 parentItem->cChildren = 0;
303 TREEVIEW_RemoveItem (HWND hwnd, TREEVIEW_ITEM *wineItem)
306 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
307 TREEVIEW_ITEM *parentItem, *upsiblingItem, *siblingItem;
310 iItem=(INT)wineItem->hItem;
311 tv_set_bit(iItem,infoPtr->freeList);
312 infoPtr->uNumItems--;
314 if (wineItem->pszText!=LPSTR_TEXTCALLBACKA)
315 COMCTL32_Free (wineItem->pszText);
317 TREEVIEW_SendTreeviewNotify (hwnd, TVN_DELETEITEM, 0, (HTREEITEM)iItem, 0);
319 if (wineItem->firstChild)
320 TREEVIEW_RemoveAllChildren (hwnd,wineItem);
322 if (wineItem->parent) {
323 parentItem=& infoPtr->items [(INT)wineItem->parent];
324 switch (parentItem->cChildren) {
325 case I_CHILDRENCALLBACK:
326 FIXME("we don't handle I_CHILDRENCALLBACK yet\n");
329 parentItem->cChildren=0;
330 parentItem->firstChild=0;
333 parentItem->cChildren--;
334 if ((INT)parentItem->firstChild==iItem)
335 parentItem->firstChild=wineItem->sibling;
339 if (iItem==(INT)infoPtr->TopRootItem)
340 infoPtr->TopRootItem=(HTREEITEM)wineItem->sibling;
341 if (wineItem->upsibling) {
342 upsiblingItem=& infoPtr->items [(INT)wineItem->upsibling];
343 upsiblingItem->sibling=wineItem->sibling;
345 if (wineItem->sibling) {
346 siblingItem=& infoPtr->items [(INT)wineItem->sibling];
347 siblingItem->upsibling=wineItem->upsibling;
355 /* Note:TREEVIEW_RemoveTree doesn't remove infoPtr itself */
357 static void TREEVIEW_RemoveTree (HWND hwnd)
360 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
361 TREEVIEW_ITEM *killItem;
364 for (i=1; i<=(INT)infoPtr->uMaxHandle; i++)
365 if (!tv_test_bit (i, infoPtr->freeList)) {
366 killItem=& infoPtr->items [i];
367 if (killItem->pszText!=LPSTR_TEXTCALLBACKA)
368 COMCTL32_Free (killItem->pszText);
369 TREEVIEW_SendTreeviewNotify
370 (hwnd, TVN_DELETEITEM, 0, killItem->hItem, 0);
373 if (infoPtr->uNumPtrsAlloced) {
374 COMCTL32_Free (infoPtr->items);
375 COMCTL32_Free (infoPtr->freeList);
376 infoPtr->uNumItems=0;
377 infoPtr->uNumPtrsAlloced=0;
378 infoPtr->uMaxHandle=0;
389 TREEVIEW_GetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
391 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
394 if (infoPtr==NULL) return 0;
396 if ((INT)wParam == TVSIL_NORMAL)
397 return (LRESULT) infoPtr->himlNormal;
398 if ((INT)wParam == TVSIL_STATE)
399 return (LRESULT) infoPtr->himlState;
405 TREEVIEW_SetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
407 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
411 switch ((INT)wParam) {
413 himlTemp = infoPtr->himlNormal;
414 infoPtr->himlNormal = (HIMAGELIST)lParam;
415 return (LRESULT)himlTemp;
418 himlTemp = infoPtr->himlState;
419 infoPtr->himlState = (HIMAGELIST)lParam;
420 return (LRESULT)himlTemp;
423 return (LRESULT)NULL;
429 TREEVIEW_SetItemHeight (HWND hwnd, WPARAM wParam)
431 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
432 INT cx,cy,prevHeight=infoPtr->uItemHeight;
438 infoPtr->uItemHeight=-1;
442 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &cy);
444 if (wParam>cy) cy=wParam;
445 infoPtr->uItemHeight=cy;
447 if (!( GetWindowLongA( hwnd, GWL_STYLE) & TVS_NONEVENHEIGHT))
448 infoPtr->uItemHeight = (INT) wParam & 0xfffffffe;
453 TREEVIEW_GetItemHeight (HWND hwnd)
455 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
458 return infoPtr->uItemHeight;
462 TREEVIEW_SetTextColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
464 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
465 COLORREF prevColor=infoPtr->clrText;
468 infoPtr->clrText=(COLORREF) lParam;
469 return (LRESULT) prevColor;
473 TREEVIEW_GetBkColor (HWND hwnd)
475 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
478 return (LRESULT) infoPtr->clrText;
482 TREEVIEW_SetBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
484 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
485 COLORREF prevColor=infoPtr->clrBk;
488 infoPtr->clrBk=(COLORREF) lParam;
489 return (LRESULT) prevColor;
493 TREEVIEW_GetTextColor (HWND hwnd)
495 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
498 return (LRESULT) infoPtr->clrBk;
502 /* cdmode: custom draw mode as received from app. in first NMCUSTOMDRAW
505 #define TREEVIEW_LEFT_MARGIN 8
509 TREEVIEW_DrawItem (HWND hwnd, HDC hdc, TREEVIEW_ITEM *wineItem)
511 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
512 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
513 INT center,xpos,cx,cy, cditem, drawmode;
515 UINT uTextJustify = DT_LEFT;
519 if (wineItem->state & TVIS_BOLD)
520 hOldFont = SelectObject (hdc, infoPtr->hBoldFont);
522 hOldFont = SelectObject (hdc, infoPtr->hFont);
525 if (infoPtr->cdmode & CDRF_NOTIFYITEMDRAW) {
526 drawmode=CDDS_ITEMPREPAINT;
528 if (infoPtr->cdmode & CDRF_NOTIFYSUBITEMDRAW)
529 drawmode|=CDDS_SUBITEM;
531 cditem=TREEVIEW_SendCustomDrawItemNotify (hwnd, hdc, wineItem, drawmode);
533 TRACE("cditem:%d\n",cditem);
535 if (cditem & CDRF_SKIPDEFAULT)
540 * Set drawing starting points
542 r = wineItem->rect; /* this item rectangle */
543 center = (r.top+r.bottom)/2; /* this item vertical center */
544 xpos = r.left + TREEVIEW_LEFT_MARGIN;/* horizontal starting point */
547 * Display the tree hierarchy
549 if ( dwStyle & TVS_HASLINES)
552 * Write links to parent node
553 * we draw the L starting from the child to the parent
555 * points[0] is attached to the current item
556 * points[1] is the L corner
557 * points[2] is attached to the parent or the up sibling
559 if ( dwStyle & TVS_LINESATROOT)
561 TREEVIEW_ITEM *upNode = NULL;
562 BOOL hasParentOrSibling = TRUE;
563 RECT upRect = {0,0,0,0};
564 HPEN hOldPen, hnewPen;
567 * determine the target location of the line at root, either be linked
568 * to the up sibling or to the parent node.
570 if (wineItem->upsibling)
571 upNode = TREEVIEW_ValidItem (infoPtr, wineItem->upsibling);
572 else if (wineItem->parent)
573 upNode = TREEVIEW_ValidItem (infoPtr, wineItem->parent);
575 hasParentOrSibling = FALSE;
578 upRect = upNode->rect;
580 if ( wineItem->iLevel == 0 )
582 points[2].x = points[1].x = upRect.left+8;
583 points[0].x = points[2].x + 10;
584 points[2].y = upRect.bottom-3;
585 points[1].y = points[0].y = center;
589 points[2].x = points[1].x = 8 + (20*wineItem->iLevel);
590 points[2].y = ( upNode->cChildren == 0) ?
591 upRect.top : /* is linked to the "L" above */
592 ( wineItem->upsibling != NULL) ?
593 upRect.bottom-3: /* is linked to an icon */
594 upRect.bottom+1; /* is linked to a +/- box */
595 points[1].y = points[0].y = center;
596 points[0].x = points[1].x + 10;
602 hnewPen = CreatePen(PS_DOT, 0, GetSysColor(COLOR_WINDOWTEXT) );
603 hOldPen = SelectObject( hdc, hnewPen );
605 if (hasParentOrSibling)
606 Polyline (hdc,points,3);
608 Polyline (hdc,points,2);
610 DeleteObject(hnewPen);
611 SelectObject(hdc, hOldPen);
616 * Display the (+/-) signs
618 if (wineItem->iLevel != 0)/* update position only for non root node */
619 xpos+=(5*wineItem->iLevel);
621 if (( dwStyle & TVS_HASBUTTONS) && ( dwStyle & TVS_HASLINES))
623 if ( (wineItem->cChildren) ||
624 (wineItem->cChildren == I_CHILDRENCALLBACK))
626 /* Setup expand box coordinate to facilitate the LMBClick handling */
627 wineItem->expandBox.left = xpos-4;
628 wineItem->expandBox.top = center-4;
629 wineItem->expandBox.right = xpos+5;
630 wineItem->expandBox.bottom = center+5;
634 wineItem->expandBox.left,
635 wineItem->expandBox.top ,
636 wineItem->expandBox.right,
637 wineItem->expandBox.bottom);
639 MoveToEx (hdc, xpos-2, center, NULL);
640 LineTo (hdc, xpos+3, center);
642 if (!(wineItem->state & TVIS_EXPANDED)) {
643 MoveToEx (hdc, xpos, center-2, NULL);
644 LineTo (hdc, xpos, center+3);
650 * Display the image assiciated with this item
652 xpos += 13; /* update position */
653 if (wineItem->mask & (TVIF_IMAGE|TVIF_SELECTEDIMAGE)) {
655 HIMAGELIST *himlp = NULL;
657 if (infoPtr->himlNormal)
658 himlp=&infoPtr->himlNormal; /* get the image list */
660 if ( (wineItem->state & TVIS_SELECTED) &&
661 (wineItem->iSelectedImage)) {
663 /* State images are displayed to the left of the Normal image*/
664 if (infoPtr->himlState)
665 himlp=&infoPtr->himlState;
667 /* The item is curently selected */
668 if (wineItem->iSelectedImage == I_IMAGECALLBACK)
669 TREEVIEW_SendDispInfoNotify (
675 imageIndex = wineItem->iSelectedImage;
678 /* This item is not selected */
679 if (wineItem->iImage == I_IMAGECALLBACK)
680 TREEVIEW_SendDispInfoNotify (
686 imageIndex = wineItem->iImage;
691 /* We found an image to display? Draw it. */
700 ImageList_GetIconSize (*himlp, &cx, &cy);
706 * Display the text assiciated with this item
709 if ((wineItem->mask & TVIF_TEXT) && (wineItem->pszText))
711 COLORREF oldBkColor = 0;
712 COLORREF oldTextColor = 0;
718 wineItem->text.left = r.left;
719 wineItem->text.right = r.right;
720 wineItem->text.top = r.top;
721 wineItem->text.bottom= r.bottom;
723 if (wineItem->state & (TVIS_SELECTED | TVIS_DROPHILITED) ) {
724 oldBkMode = SetBkMode (hdc, OPAQUE);
725 oldBkColor = SetBkColor (hdc, GetSysColor( COLOR_HIGHLIGHT));
726 oldTextColor = SetTextColor(hdc, GetSysColor( COLOR_HIGHLIGHTTEXT));
730 oldBkMode = SetBkMode(hdc, TRANSPARENT);
731 oldTextColor = SetTextColor(hdc, GetSysColor( COLOR_WINDOWTEXT));
734 if (wineItem->pszText== LPSTR_TEXTCALLBACKA) {
735 TRACE("LPSTR_TEXTCALLBACK\n");
736 TREEVIEW_SendDispInfoNotify (hwnd, wineItem, TVN_GETDISPINFO, TVIF_TEXT);
743 lstrlenA(wineItem->pszText),
745 uTextJustify | DT_VCENTER | DT_SINGLELINE );
747 /* Obtain the text coordinate */
751 lstrlenA(wineItem->pszText),
753 uTextJustify | DT_VCENTER | DT_SINGLELINE | DT_CALCRECT);
755 /* Restore the hdc state */
756 SetTextColor( hdc, oldTextColor);
758 if (oldBkMode != TRANSPARENT)
759 SetBkMode(hdc, oldBkMode);
760 if (wineItem->state & (TVIS_SELECTED | TVIS_DROPHILITED))
761 SetBkColor (hdc, oldBkColor);
763 /* Draw the box arround the selected item */
764 if (wineItem->state & TVIS_SELECTED )
766 HPEN hnewPen = CreatePen(PS_DOT, 0, GetSysColor(COLOR_WINDOWTEXT) );
767 HPEN hOldPen = SelectObject( hdc, hnewPen );
770 points[0].x = wineItem->text.left-1;
771 points[0].y = wineItem->text.top+1;
772 points[1].x = wineItem->text.right;
773 points[1].y = wineItem->text.top+1;
774 points[2].x = wineItem->text.right;
775 points[2].y = wineItem->text.bottom;
776 points[3].x = wineItem->text.left-1;
777 points[3].y = wineItem->text.bottom;
779 Polyline (hdc,points,4);
781 DeleteObject(hnewPen);
782 SelectObject(hdc, hOldPen);
786 if (cditem & CDRF_NOTIFYPOSTPAINT)
787 TREEVIEW_SendCustomDrawItemNotify (hwnd, hdc, wineItem, CDDS_ITEMPOSTPAINT);
789 SelectObject (hdc, hOldFont);
793 TREEVIEW_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
795 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
796 TREEVIEW_ITEM *wineItem;
798 LPRECT lpRect = (LPRECT)lParam;
802 * validate parameters
804 if ( (infoPtr==NULL) || (lpRect == NULL) )
807 if (infoPtr->Timer & TV_REFRESH_TIMER_SET)
808 TREEVIEW_Refresh (hwnd); /* we want a rect for the current view */
811 * retrive the item ptr
813 iItem = (HTREEITEM *) lParam;
814 wineItem = TREEVIEW_ValidItem (infoPtr, *iItem);
815 if ((!wineItem) || (!wineItem->visible))
819 * If wParam is TRUE return the text size otherwise return
820 * the whole item size
823 lpRect->left = wineItem->text.left;
824 lpRect->right = wineItem->text.right;
825 lpRect->bottom = wineItem->text.bottom;
826 lpRect->top = wineItem->text.top;
828 lpRect->left = wineItem->rect.left;
829 lpRect->right = wineItem->rect.right;
830 lpRect->bottom = wineItem->rect.bottom;
831 lpRect->top = wineItem->rect.top;
834 TRACE("[L:%d R:%d T:%d B:%d]\n",
835 lpRect->left,lpRect->right,
836 lpRect->top,lpRect->bottom);
842 TREEVIEW_GetVisibleCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
845 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
847 return (LRESULT) infoPtr->uVisibleHeight / infoPtr->uRealItemHeight;
853 TREEVIEW_SetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
855 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
856 TREEVIEW_ITEM *wineItem;
860 tvItem=(LPTVITEMEXA) lParam;
861 iItem=(INT)tvItem->hItem;
862 TRACE("item %d,mask %x\n",iItem,tvItem->mask);
864 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
865 if (!wineItem) return FALSE;
867 if (tvItem->mask & TVIF_CHILDREN) {
868 wineItem->cChildren=tvItem->cChildren;
871 if (tvItem->mask & TVIF_IMAGE) {
872 wineItem->iImage=tvItem->iImage;
875 if (tvItem->mask & TVIF_INTEGRAL) {
876 wineItem->iIntegral=tvItem->iIntegral;
877 FIXME(" TVIF_INTEGRAL not supported yet\n");
880 if (tvItem->mask & TVIF_PARAM) {
881 wineItem->lParam=tvItem->lParam;
884 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
885 wineItem->iSelectedImage=tvItem->iSelectedImage;
888 if (tvItem->mask & TVIF_STATE) {
889 wineItem->state=tvItem->state & tvItem->stateMask;
892 if (tvItem->mask & TVIF_TEXT) {
893 if (tvItem->pszText!=LPSTR_TEXTCALLBACKA) {
894 len=lstrlenA (tvItem->pszText);
895 if (len>wineItem->cchTextMax)
896 wineItem->pszText= COMCTL32_ReAlloc (wineItem->pszText, len+1);
897 lstrcpynA (wineItem->pszText, tvItem->pszText,len);
899 if (wineItem->cchTextMax) {
900 COMCTL32_Free (wineItem->pszText);
901 wineItem->cchTextMax=0;
903 wineItem->pszText=LPSTR_TEXTCALLBACKA;
915 TREEVIEW_Refresh (HWND hwnd)
918 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
923 INT iItem, indent, x, y, cx, height, itemHeight;
924 INT viewtop,viewbottom,viewleft,viewright;
925 TREEVIEW_ITEM *wineItem, *prevItem;
931 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
932 KillTimer (hwnd, TV_REFRESH_TIMER);
933 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
937 GetClientRect (hwnd, &rect);
938 if ((rect.left-rect.right ==0) || (rect.top-rect.bottom==0)) return;
940 infoPtr->cdmode=TREEVIEW_SendCustomDrawNotify
941 (hwnd, CDDS_PREPAINT, hdc, rect);
943 if (infoPtr->cdmode==CDRF_SKIPDEFAULT) {
944 ReleaseDC (hwnd, hdc);
948 infoPtr->uVisibleHeight= rect.bottom-rect.top;
949 infoPtr->uVisibleWidth= rect.right-rect.left;
952 viewbottom=infoPtr->cy + rect.bottom-rect.top;
953 viewleft=infoPtr->cx;
954 viewright=infoPtr->cx + rect.right-rect.left;
958 /* draw background */
960 hbrBk = GetSysColorBrush (COLOR_WINDOW);
961 FillRect(hdc, &rect, hbrBk);
964 iItem=(INT)infoPtr->TopRootItem;
965 infoPtr->firstVisible=0;
969 TRACE("[%d %d %d %d]\n",viewtop,viewbottom,viewleft,viewright);
973 wineItem= & infoPtr->items[iItem];
974 wineItem->iLevel=indent;
976 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &itemHeight);
977 if (infoPtr->uItemHeight>itemHeight)
978 itemHeight=infoPtr->uItemHeight;
980 GetTextMetricsA (hdc, &tm);
981 if ((tm.tmHeight + tm.tmExternalLeading) > itemHeight)
982 itemHeight=tm.tmHeight + tm.tmExternalLeading;
984 infoPtr->uRealItemHeight=itemHeight;
987 /* FIXME: remove this in later stage */
989 if (wineItem->pszText!=LPSTR_TEXTCALLBACK32A)
990 TRACE (treeview, "%d %d [%d %d %d %d] (%s)\n",y,x,
991 wineItem->rect.top, wineItem->rect.bottom,
992 wineItem->rect.left, wineItem->rect.right,
995 TRACE (treeview, "%d [%d %d %d %d] (CALLBACK)\n",
997 wineItem->rect.top, wineItem->rect.bottom,
998 wineItem->rect.left, wineItem->rect.right);
1001 height=itemHeight * wineItem->iIntegral +1;
1002 if ((y >= viewtop) && (y <= viewbottom) &&
1003 (x >= viewleft ) && (x <= viewright)) {
1004 wineItem->visible = TRUE;
1005 wineItem->rect.top = y - infoPtr->cy + rect.top;
1006 wineItem->rect.bottom = wineItem->rect.top + height ;
1007 wineItem->rect.left = x - infoPtr->cx + rect.left;
1008 wineItem->rect.right = rect.right;
1009 if (!infoPtr->firstVisible)
1010 infoPtr->firstVisible=wineItem->hItem;
1011 TREEVIEW_DrawItem (hwnd, hdc, wineItem);
1014 wineItem->visible = FALSE;
1015 wineItem->rect.left = wineItem->rect.top = 0;
1016 wineItem->rect.right= wineItem->rect.bottom = 0;
1017 wineItem->text.left = wineItem->text.top = 0;
1018 wineItem->text.right= wineItem->text.bottom = 0;
1021 /* look up next item */
1023 if ((wineItem->firstChild) && (wineItem->state & TVIS_EXPANDED)) {
1024 iItem=(INT)wineItem->firstChild;
1026 x+=infoPtr->uIndent;
1027 if (x>infoPtr->uTotalWidth)
1028 infoPtr->uTotalWidth=x;
1031 iItem=(INT)wineItem->sibling;
1032 while ((!iItem) && (indent>0)) {
1034 x-=infoPtr->uIndent;
1036 wineItem=&infoPtr->items[(INT)wineItem->parent];
1037 iItem=(INT)wineItem->sibling;
1043 /* FIXME: infoPtr->uTotalWidth should also take item label into account */
1044 /* FIXME: or should query item sizes (ie check CDRF_NEWFONT) */
1046 infoPtr->uTotalHeight=y;
1047 if (y >= (viewbottom-viewtop)) {
1048 if (!(infoPtr->uInternalStatus & TV_VSCROLL))
1049 ShowScrollBar (hwnd, SB_VERT, TRUE);
1050 infoPtr->uInternalStatus |=TV_VSCROLL;
1051 SetScrollRange (hwnd, SB_VERT, 0,
1052 y - infoPtr->uVisibleHeight, FALSE);
1053 SetScrollPos (hwnd, SB_VERT, infoPtr->cy, TRUE);
1056 if (infoPtr->uInternalStatus & TV_VSCROLL)
1057 ShowScrollBar (hwnd, SB_VERT, FALSE);
1058 infoPtr->uInternalStatus &= ~TV_VSCROLL;
1062 if (infoPtr->cdmode & CDRF_NOTIFYPOSTPAINT)
1063 infoPtr->cdmode=TREEVIEW_SendCustomDrawNotify
1064 (hwnd, CDDS_POSTPAINT, hdc, rect);
1066 ReleaseDC (hwnd, hdc);
1072 TREEVIEW_HandleTimer (HWND hwnd, WPARAM wParam, LPARAM lParam)
1074 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1076 TRACE(" %d\n",wParam);
1077 if (!infoPtr) return FALSE;
1080 case TV_REFRESH_TIMER:
1081 KillTimer (hwnd, TV_REFRESH_TIMER);
1082 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
1083 InvalidateRect(hwnd, NULL, FALSE);
1086 KillTimer (hwnd, TV_EDIT_TIMER);
1087 infoPtr->Timer &= ~TV_EDIT_TIMER_SET;
1090 ERR("got unknown timer\n");
1098 TREEVIEW_QueueRefresh (HWND hwnd)
1101 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1104 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
1105 KillTimer (hwnd, TV_REFRESH_TIMER);
1108 SetTimer (hwnd, TV_REFRESH_TIMER, TV_REFRESH_DELAY, 0);
1109 infoPtr->Timer|=TV_REFRESH_TIMER_SET;
1115 TREEVIEW_GetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1117 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1119 TREEVIEW_ITEM *wineItem;
1122 tvItem=(LPTVITEMEXA) lParam;
1123 iItem=(INT)tvItem->hItem;
1125 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1126 if (!wineItem) return FALSE;
1128 if (tvItem->mask & TVIF_CHILDREN) {
1129 if (TVIF_CHILDREN==I_CHILDRENCALLBACK)
1130 FIXME("I_CHILDRENCALLBACK not supported\n");
1131 tvItem->cChildren=wineItem->cChildren;
1134 if (tvItem->mask & TVIF_HANDLE) {
1135 tvItem->hItem=wineItem->hItem;
1138 if (tvItem->mask & TVIF_IMAGE) {
1139 tvItem->iImage=wineItem->iImage;
1142 if (tvItem->mask & TVIF_INTEGRAL) {
1143 tvItem->iIntegral=wineItem->iIntegral;
1144 FIXME(" TVIF_INTEGRAL not supported yet\n");
1147 /* undocumented: windows ignores TVIF_PARAM and
1148 * always sets lParam
1150 tvItem->lParam=wineItem->lParam;
1152 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
1153 tvItem->iSelectedImage=wineItem->iSelectedImage;
1156 if (tvItem->mask & TVIF_STATE) {
1157 tvItem->state=wineItem->state & tvItem->stateMask;
1160 if (tvItem->mask & TVIF_TEXT) {
1161 if (wineItem->pszText == LPSTR_TEXTCALLBACKA) {
1162 tvItem->pszText = LPSTR_TEXTCALLBACKA; /* FIXME:send notification? */
1163 ERR(" GetItem called with LPSTR_TEXTCALLBACK\n");
1165 else if (wineItem->pszText) {
1166 lstrcpynA (tvItem->pszText, wineItem->pszText, tvItem->cchTextMax);
1170 TRACE("item %d<%p>, txt %p, img %p, action %x\n",
1182 /* FIXME: check implementation of TVGN_NEXT/TVGN_NEXTVISIBLE */
1185 TREEVIEW_GetNextItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
1188 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1189 TREEVIEW_ITEM *wineItem, *returnItem;
1190 INT iItem, retval, flag;
1193 if (!infoPtr) return FALSE;
1194 flag = (INT) wParam;
1195 iItem = (INT) lParam;
1198 case TVGN_ROOT: retval=(INT)infoPtr->TopRootItem;
1200 case TVGN_CARET:retval=(INT)infoPtr->selectedItem;
1202 case TVGN_FIRSTVISIBLE:
1203 TREEVIEW_Refresh (hwnd);
1204 /* FIXME:we should only recalculate, not redraw */
1205 retval=(INT)infoPtr->firstVisible;
1207 case TVGN_DROPHILITE:
1208 retval=(INT)infoPtr->dropItem;
1212 TRACE("flags:%x, returns %u\n", flag, retval);
1216 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1218 if (!wineItem) return FALSE;
1221 case TVGN_NEXT: retval=(INT)wineItem->sibling;
1224 retval=(INT)wineItem->upsibling;
1227 retval=(INT)wineItem->parent;
1230 retval=(INT)wineItem->firstChild;
1232 case TVGN_LASTVISIBLE:
1233 returnItem=TREEVIEW_GetLastListItem (infoPtr,wineItem);
1235 case TVGN_NEXTVISIBLE:
1236 returnItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
1238 case TVGN_PREVIOUSVISIBLE:
1239 returnItem=TREEVIEW_GetPrevListItem (infoPtr, wineItem);
1241 default: FIXME("Unknown msg %x,item %x\n", flag,iItem);
1246 TRACE("flags:%x, item %d;returns %d\n", flag, iItem,
1247 (INT)returnItem->hItem);
1248 return (INT)returnItem->hItem;
1251 TRACE("flags:%x, item %d;returns %d\n", flag, iItem,retval);
1257 TREEVIEW_GetCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
1259 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1261 TRACE(" %d\n",infoPtr->uNumItems);
1262 return (LRESULT) infoPtr->uNumItems;
1265 /***************************************************************************
1266 * This method does the chaining of the insertion of a treeview item
1268 * If parent is NULL, we're inserting at the root of the list.
1270 static void TREEVIEW_InsertBefore(
1271 TREEVIEW_INFO *infoPtr,
1272 TREEVIEW_ITEM *newItem,
1273 TREEVIEW_ITEM *sibling,
1274 TREEVIEW_ITEM *parent)
1276 HTREEITEM siblingHandle = 0;
1277 HTREEITEM upSiblingHandle = 0;
1278 TREEVIEW_ITEM *upSibling = NULL;
1280 if (newItem == NULL)
1281 ERR("NULL newItem, impossible condition\n");
1283 if (sibling != NULL) /* Insert before this sibling for this parent */
1285 /* Store the new item sibling up sibling and sibling tem handle */
1286 siblingHandle = sibling->hItem;
1287 upSiblingHandle = sibling->upsibling;
1288 /* As well as a pointer to the upsibling sibling object */
1289 if ( (INT)sibling->upsibling != 0 )
1290 upSibling = &infoPtr->items[(INT)sibling->upsibling];
1292 /* Adjust the sibling pointer */
1293 sibling->upsibling = newItem->hItem;
1295 /* Adjust the new item pointers */
1296 newItem->upsibling = upSiblingHandle;
1297 newItem->sibling = siblingHandle;
1299 /* Adjust the up sibling pointer */
1300 if ( upSibling != NULL )
1301 upSibling->sibling = newItem->hItem;
1303 /* this item is the first child of this parent, adjust parent pointers */
1305 parent->firstChild = newItem->hItem;
1307 infoPtr->TopRootItem= newItem->hItem;
1309 else /* Insert as first child of this parent */
1311 parent->firstChild = newItem->hItem;
1314 /***************************************************************************
1315 * This method does the chaining of the insertion of a treeview item
1317 * If parent is NULL, we're inserting at the root of the list.
1319 static void TREEVIEW_InsertAfter(
1320 TREEVIEW_INFO *infoPtr,
1321 TREEVIEW_ITEM *newItem,
1322 TREEVIEW_ITEM *upSibling,
1323 TREEVIEW_ITEM *parent)
1325 HTREEITEM upSiblingHandle = 0;
1326 HTREEITEM siblingHandle = 0;
1327 TREEVIEW_ITEM *sibling = NULL;
1330 if (newItem == NULL)
1331 ERR("NULL newItem, impossible condition\n");
1333 if (upSibling != NULL) /* Insert after this upsibling for this parent */
1335 /* Store the new item up sibling and sibling item handle */
1336 upSiblingHandle = upSibling->hItem;
1337 siblingHandle = upSibling->sibling;
1338 /* As well as a pointer to the upsibling sibling object */
1339 if ( (INT)upSibling->sibling != 0 )
1340 sibling = &infoPtr->items[(INT)upSibling->sibling];
1342 /* Adjust the up sibling pointer */
1343 upSibling->sibling = newItem->hItem;
1345 /* Adjust the new item pointers */
1346 newItem->upsibling = upSiblingHandle;
1347 newItem->sibling = siblingHandle;
1349 /* Adjust the sibling pointer */
1350 if ( sibling != NULL )
1351 sibling->upsibling = newItem->hItem;
1354 newItem is the last of the level, nothing else to do
1357 else /* Insert as first child of this parent */
1359 parent->firstChild = newItem->hItem;
1362 /***************************************************************************
1363 * Forward the DPA local callback to the treeview owner callback
1365 static INT WINAPI TREEVIEW_CallBackCompare(
1370 /* Forward the call to the client define callback */
1371 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr((HWND)tvInfoPtr);
1372 return (infoPtr->pCallBackSort->lpfnCompare)(
1373 ((TREEVIEW_ITEM*)first)->lParam,
1374 ((TREEVIEW_ITEM*)second)->lParam,
1375 infoPtr->pCallBackSort->lParam);
1378 /***************************************************************************
1379 * Treeview native sort routine: sort on item text.
1381 static INT WINAPI TREEVIEW_SortOnName (
1386 HWND hwnd=(HWND) tvInfoPtr;
1388 TREEVIEW_ITEM *item;
1391 item=(TREEVIEW_ITEM *) first;
1392 if (item->pszText==LPSTR_TEXTCALLBACKA) {
1393 TREEVIEW_SendDispInfoNotify (hwnd, item, TVN_GETDISPINFO, TVIF_TEXT);
1397 item=(TREEVIEW_ITEM *) second;
1398 if (item->pszText==LPSTR_TEXTCALLBACKA) {
1399 TREEVIEW_SendDispInfoNotify (hwnd, item, TVN_GETDISPINFO, TVIF_TEXT);
1403 return -strcmp (txt1,txt2);
1406 /***************************************************************************
1407 * Setup the treeview structure with regards of the sort method
1408 * and sort the children of the TV item specified in lParam
1409 * fRecurse: currently unused. Should be zero.
1410 * parent: if pSort!=NULL, should equal pSort->hParent.
1411 * otherwise, item which child items are to be sorted.
1412 * pSort: sort method info. if NULL, sort on item text.
1413 * if non-NULL, sort on item's lParam content, and let the
1414 * application decide what that means. See also TVM_SORTCHILDRENCB.
1417 LRESULT WINAPI TREEVIEW_Sort (
1424 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1425 TREEVIEW_ITEM *sortMe = NULL; /* Node for which we sort the children */
1427 /* Obtain the TVSORTBC struct */
1428 infoPtr->pCallBackSort = pSort;
1430 /* Check for a valid handle to the parent item */
1431 if (!TREEVIEW_ValidItem(infoPtr, parent))
1433 ERR ("invalid item hParent=%d\n", (INT)parent);
1437 /* Obtain the parent node to sort */
1438 sortMe = &infoPtr->items[ (INT)parent ];
1440 /* Make sure there is something to sort */
1441 if ( sortMe->cChildren > 1 )
1443 /* pointer organization */
1444 HDPA sortList = DPA_Create(sortMe->cChildren);
1445 HTREEITEM itemHandle = sortMe->firstChild;
1446 TREEVIEW_ITEM *itemPtr = & infoPtr->items[ (INT)itemHandle ];
1448 /* TREEVIEW_ITEM rechaining */
1454 /* Build the list of item to sort */
1458 sortList, /* the list */
1459 sortMe->cChildren+1, /* force the insertion to be an append */
1460 itemPtr); /* the ptr to store */
1462 /* Get the next sibling */
1463 itemHandle = itemPtr->sibling;
1464 itemPtr = & infoPtr->items[ (INT)itemHandle ];
1465 } while ( itemHandle != NULL );
1467 /* let DPA perform the sort activity */
1470 sortList, /* what */
1471 TREEVIEW_CallBackCompare, /* how */
1475 sortList, /* what */
1476 TREEVIEW_SortOnName, /* how */
1480 * Reorganized TREEVIEW_ITEM structures.
1481 * Note that we know we have at least two elements.
1484 /* Get the first item and get ready to start... */
1485 item = DPA_GetPtr(sortList, count++);
1486 while ( (nextItem = DPA_GetPtr(sortList, count++)) != NULL )
1488 /* link the two current item toghether */
1489 ((TREEVIEW_ITEM*)item)->sibling = ((TREEVIEW_ITEM*)nextItem)->hItem;
1490 ((TREEVIEW_ITEM*)nextItem)->upsibling = ((TREEVIEW_ITEM*)item)->hItem;
1492 if (prevItem == NULL) /* this is the first item, update the parent */
1494 sortMe->firstChild = ((TREEVIEW_ITEM*)item)->hItem;
1495 ((TREEVIEW_ITEM*)item)->upsibling = NULL;
1497 else /* fix the back chaining */
1499 ((TREEVIEW_ITEM*)item)->upsibling = ((TREEVIEW_ITEM*)prevItem)->hItem;
1502 /* get ready for the next one */
1507 /* the last item is pointed to by item and never has a sibling */
1508 ((TREEVIEW_ITEM*)item)->sibling = NULL;
1510 DPA_Destroy(sortList);
1518 /***************************************************************************
1519 * Setup the treeview structure with regards of the sort method
1520 * and sort the children of the TV item specified in lParam
1522 LRESULT WINAPI TREEVIEW_SortChildrenCB(
1528 LPTVSORTCB pSort=(LPTVSORTCB) lParam;
1530 return TREEVIEW_Sort (hwnd, wParam, pSort->hParent, pSort);
1534 /***************************************************************************
1535 * Sort the children of the TV item specified in lParam.
1537 LRESULT WINAPI TREEVIEW_SortChildren (
1542 return TREEVIEW_Sort (hwnd, (BOOL) wParam, (HTREEITEM) lParam, NULL);
1547 /* the method used below isn't the most memory-friendly, but it avoids
1548 a lot of memory reallocations */
1550 /* BTW: we waste handle 0; 0 is not an allowed handle. */
1553 TREEVIEW_InsertItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1556 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1557 TVINSERTSTRUCTA *ptdi;
1559 TREEVIEW_ITEM *wineItem, *parentItem, *prevsib, *sibItem;
1560 INT iItem,listItems,i,len;
1562 /* Item to insert */
1563 ptdi = (LPTVINSERTSTRUCTA) lParam;
1565 /* check if memory is available */
1567 if (infoPtr->uNumPtrsAlloced==0) {
1568 infoPtr->items = COMCTL32_Alloc (TVITEM_ALLOC*sizeof (TREEVIEW_ITEM));
1569 infoPtr->freeList= COMCTL32_Alloc ((1+(TVITEM_ALLOC>>5)) * sizeof (INT));
1570 infoPtr->uNumPtrsAlloced=TVITEM_ALLOC;
1571 infoPtr->TopRootItem=(HTREEITEM)1;
1575 * Reallocate contiguous space for items
1577 if (infoPtr->uNumItems == (infoPtr->uNumPtrsAlloced-1) ) {
1578 TREEVIEW_ITEM *oldItems = infoPtr->items;
1579 INT *oldfreeList = infoPtr->freeList;
1581 infoPtr->uNumPtrsAlloced*=2;
1582 infoPtr->items = COMCTL32_Alloc (infoPtr->uNumPtrsAlloced*sizeof (TREEVIEW_ITEM));
1583 infoPtr->freeList= COMCTL32_Alloc ((1+(infoPtr->uNumPtrsAlloced>>5))*sizeof (INT));
1585 memcpy (&infoPtr->items[0], &oldItems[0],
1586 infoPtr->uNumPtrsAlloced/2 * sizeof(TREEVIEW_ITEM));
1587 memcpy (&infoPtr->freeList[0], &oldfreeList[0],
1588 (infoPtr->uNumPtrsAlloced>>6) * sizeof(INT));
1590 COMCTL32_Free (oldItems);
1591 COMCTL32_Free (oldfreeList);
1595 * Reset infoPtr structure with new stat according to current TV picture
1598 infoPtr->uNumItems++;
1599 if ((INT)infoPtr->uMaxHandle==(infoPtr->uNumItems-1)) {
1600 iItem=infoPtr->uNumItems;
1601 infoPtr->uMaxHandle = (HTREEITEM)((INT)infoPtr->uMaxHandle + 1);
1602 } else { /* check freelist */
1603 for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++) {
1604 if (infoPtr->freeList[i]) {
1605 iItem=ffs (infoPtr->freeList[i])-1;
1606 tv_clear_bit(iItem,&infoPtr->freeList[i]);
1613 if (TRACE_ON(treeview)) {
1614 for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++)
1615 TRACE("%8x\n",infoPtr->freeList[i]);
1618 if (!iItem) ERR("Argh -- can't find free item.\n");
1621 * Find the parent item of the new item
1623 tvItem= & ptdi->DUMMYUNIONNAME.itemex;
1624 wineItem=& infoPtr->items[iItem];
1626 if ((ptdi->hParent==TVI_ROOT) || (ptdi->hParent==0)) {
1628 wineItem->parent = 0;
1629 sibItem = &infoPtr->items [(INT)infoPtr->TopRootItem];
1630 listItems = infoPtr->uNumItems;
1633 parentItem = &infoPtr->items[(INT)ptdi->hParent];
1635 /* Do the insertion here it if it's the only item of this parent */
1636 if (!parentItem->firstChild)
1637 parentItem->firstChild=(HTREEITEM)iItem;
1639 wineItem->parent = ptdi->hParent;
1640 sibItem = &infoPtr->items [(INT)parentItem->firstChild];
1641 parentItem->cChildren++;
1642 listItems = parentItem->cChildren;
1646 /* NOTE: I am moving some setup of the wineItem object that was initialy
1647 * done at the end of the function since some of the values are
1648 * required by the Callback sorting
1651 if (tvItem->mask & TVIF_TEXT)
1654 * Setup the item text stuff here since it's required by the Sort method
1655 * when the insertion are ordered
1657 if (tvItem->pszText!=LPSTR_TEXTCALLBACKA)
1659 TRACE("(%p,%s)\n", &tvItem->pszText, tvItem->pszText);
1660 len = lstrlenA (tvItem->pszText)+1;
1661 wineItem->pszText= COMCTL32_Alloc (len+1);
1662 lstrcpyA (wineItem->pszText, tvItem->pszText);
1663 wineItem->cchTextMax=len;
1667 TRACE("LPSTR_TEXTCALLBACK\n");
1668 wineItem->pszText = LPSTR_TEXTCALLBACKA;
1669 wineItem->cchTextMax = 0;
1673 if (tvItem->mask & TVIF_PARAM)
1674 wineItem->lParam=tvItem->lParam;
1677 wineItem->upsibling=0; /* needed in case we're the first item in a list */
1678 wineItem->sibling=0;
1679 wineItem->firstChild=0;
1680 wineItem->hItem=(HTREEITEM)iItem;
1685 switch ((DWORD) ptdi->hInsertAfter) {
1686 case (DWORD) TVI_FIRST:
1687 if (wineItem->parent) {
1688 wineItem->sibling=parentItem->firstChild;
1689 parentItem->firstChild=(HTREEITEM)iItem;
1691 wineItem->sibling=infoPtr->TopRootItem;
1692 infoPtr->TopRootItem=(HTREEITEM)iItem;
1694 sibItem->upsibling=(HTREEITEM)iItem;
1697 case (DWORD) TVI_SORT:
1698 if (sibItem==wineItem)
1700 * This item is the first child of the level and it
1701 * has already been inserted
1706 TREEVIEW_ITEM *aChild;
1709 TREEVIEW_ITEM *previousChild = NULL;
1710 BOOL bItemInserted = FALSE;
1713 aChild = &infoPtr->items[(INT)parentItem->firstChild];
1715 aChild = &infoPtr->items[(INT)infoPtr->TopRootItem];
1717 /* Iterate the parent children to see where we fit in */
1718 while ( aChild != NULL )
1720 INT comp = strcmp(wineItem->pszText, aChild->pszText);
1721 if ( comp < 0 ) /* we are smaller than the current one */
1723 TREEVIEW_InsertBefore(infoPtr, wineItem, aChild, parentItem);
1724 bItemInserted = TRUE;
1727 else if ( comp > 0 ) /* we are bigger than the current one */
1729 previousChild = aChild;
1730 aChild = (aChild->sibling == 0) /* This will help us to exit */
1731 ? NULL /* if there is no more sibling */
1732 : &infoPtr->items[(INT)aChild->sibling];
1734 /* Look at the next item */
1737 else if ( comp == 0 )
1740 * An item with this name is already existing, therefore,
1741 * we add after the one we found
1743 TREEVIEW_InsertAfter(infoPtr, wineItem, aChild, parentItem);
1744 bItemInserted = TRUE;
1750 * we reach the end of the child list and the item as not
1751 * yet been inserted, therefore, insert it after the last child.
1753 if ( (! bItemInserted ) && (aChild == NULL) )
1754 TREEVIEW_InsertAfter(infoPtr, wineItem, previousChild, parentItem);
1760 case (DWORD) TVI_LAST:
1761 if (sibItem==wineItem) break;
1762 while (sibItem->sibling) {
1764 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1766 sibItem->sibling=(HTREEITEM)iItem;
1767 wineItem->upsibling=sibItem->hItem;
1770 while ((sibItem->sibling) && (sibItem->hItem!=ptdi->hInsertAfter))
1773 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1775 if (sibItem->hItem!=ptdi->hInsertAfter) {
1776 ERR("tried to insert item after nonexisting handle %d.\n",
1777 (INT) ptdi->hInsertAfter);
1781 if (sibItem->sibling) {
1782 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1783 sibItem->upsibling=(HTREEITEM)iItem;
1784 wineItem->sibling=sibItem->hItem;
1786 prevsib->sibling=(HTREEITEM)iItem;
1787 wineItem->upsibling=prevsib->hItem;
1793 /* Fill in info structure */
1795 TRACE("new item %d; parent %d, mask %x\n", iItem,
1796 (INT)wineItem->parent,tvItem->mask);
1798 wineItem->mask=tvItem->mask;
1799 wineItem->iIntegral=1;
1801 if (tvItem->mask & TVIF_CHILDREN) {
1802 wineItem->cChildren=tvItem->cChildren;
1803 if (tvItem->cChildren==I_CHILDRENCALLBACK)
1804 FIXME(" I_CHILDRENCALLBACK not supported\n");
1807 wineItem->expandBox.left = 0; /* Initialize the expandBox */
1808 wineItem->expandBox.top = 0;
1809 wineItem->expandBox.right = 0;
1810 wineItem->expandBox.bottom = 0;
1812 if (tvItem->mask & TVIF_IMAGE)
1813 wineItem->iImage=tvItem->iImage;
1815 /* If the application sets TVIF_INTEGRAL without
1816 supplying a TVITEMEX structure, it's toast */
1818 if (tvItem->mask & TVIF_INTEGRAL)
1819 wineItem->iIntegral=tvItem->iIntegral;
1821 if (tvItem->mask & TVIF_SELECTEDIMAGE)
1822 wineItem->iSelectedImage=tvItem->iSelectedImage;
1824 if (tvItem->mask & TVIF_STATE) {
1825 TRACE("Changing item state from %d to %d\n",
1828 wineItem->state=tvItem->state;
1829 wineItem->stateMask=tvItem->stateMask;
1833 TREEVIEW_QueueRefresh (hwnd);
1835 return (LRESULT) iItem;
1843 TREEVIEW_DeleteItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
1845 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1847 TREEVIEW_ITEM *wineItem;
1850 if (!infoPtr) return FALSE;
1852 if (lParam == (INT)TVI_ROOT) {
1853 TREEVIEW_RemoveTree (hwnd);
1855 iItem= (INT) lParam;
1856 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1857 if (!wineItem) return FALSE;
1858 TRACE("%s\n",wineItem->pszText);
1859 TREEVIEW_RemoveItem (hwnd, wineItem);
1862 TREEVIEW_QueueRefresh (hwnd);
1870 TREEVIEW_GetIndent (HWND hwnd)
1872 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1875 return infoPtr->uIndent;
1879 TREEVIEW_SetIndent (HWND hwnd, WPARAM wParam)
1881 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1885 newIndent=(INT) wParam;
1886 if (newIndent < MINIMUM_INDENT) newIndent=MINIMUM_INDENT;
1887 infoPtr->uIndent=newIndent;
1893 TREEVIEW_GetToolTips (HWND hwnd)
1896 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1899 return infoPtr->hwndToolTip;
1904 TREEVIEW_SetToolTips (HWND hwnd, WPARAM wParam)
1907 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1911 prevToolTip=infoPtr->hwndToolTip;
1912 infoPtr->hwndToolTip= (HWND) wParam;
1919 TREEVIEW_GetEditControl (HWND hwnd)
1922 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1924 return infoPtr->hwndEdit;
1928 TREEVIEW_Edit_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam,
1936 HDC hdc = (HDC) wParam;
1937 GetClientRect (hwnd, &rc);
1938 Rectangle (hdc, rc.left, rc.top, rc.right, rc.bottom);
1944 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
1949 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd));
1950 return CallWindowProcA( infoPtr->wpEditOrig, hwnd, uMsg, wParam, lParam);
1958 /* should handle edit control messages here */
1961 TREEVIEW_Command (HWND hwnd, WPARAM wParam, LPARAM lParam)
1964 TRACE("%x %ld\n",wParam, lParam);
1966 switch (HIWORD(wParam))
1971 * Adjust the edit window size
1973 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1974 TREEVIEW_ITEM *editItem = TREEVIEW_ValidItem(infoPtr, infoPtr->editItem);
1975 INT iLength = GetWindowTextLengthA(infoPtr->hwndEdit);
1976 HDC hdc = GetDC(infoPtr->hwndEdit);
1979 if ( GetTextMetricsA(hdc, &tm) )
1981 LONG newWidth = (iLength * tm.tmAveCharWidth) + 15;
1986 editItem->text.left - 2,
1987 editItem->text.top - 1,
1989 editItem->text.bottom - editItem->text.top + 3,
1992 ReleaseDC(hwnd, hdc);
1998 /* TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
2003 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
2010 TREEVIEW_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
2013 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2015 if (infoPtr->bAutoSize)
2017 infoPtr->bAutoSize = FALSE;
2020 infoPtr->bAutoSize = TRUE;
2022 if (wParam == SIZE_RESTORED)
2024 infoPtr->uTotalWidth = LOWORD (lParam);
2025 infoPtr->uTotalHeight = HIWORD (lParam);
2027 FIXME("WM_SIZE flag %x %lx not handled\n", wParam, lParam);
2030 TREEVIEW_QueueRefresh (hwnd);
2037 TREEVIEW_StyleChanged (HWND hwnd, WPARAM wParam, LPARAM lParam)
2039 TRACE("(%x %lx)\n",wParam,lParam);
2041 TREEVIEW_Refresh (hwnd);
2047 TREEVIEW_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
2049 TREEVIEW_INFO *infoPtr;
2054 TRACE("wnd %x\n",hwnd);
2055 /* allocate memory for info structure */
2056 infoPtr = (TREEVIEW_INFO *) COMCTL32_Alloc (sizeof(TREEVIEW_INFO));
2058 SetWindowLongA( hwnd, 0, (DWORD)infoPtr);
2060 if (infoPtr == NULL) {
2061 ERR("could not allocate info memory!\n");
2065 if ((TREEVIEW_INFO*) GetWindowLongA( hwnd, 0) != infoPtr) {
2066 ERR("pointer assignment error!\n");
2072 /* set default settings */
2073 infoPtr->uInternalStatus=0;
2074 infoPtr->uNumItems=0;
2075 infoPtr->clrBk = GetSysColor (COLOR_WINDOW);
2076 infoPtr->clrText = GetSysColor (COLOR_BTNTEXT);
2079 infoPtr->uIndent = 15;
2080 infoPtr->himlNormal = NULL;
2081 infoPtr->himlState = NULL;
2082 infoPtr->uItemHeight = -1;
2083 GetTextMetricsA (hdc, &tm);
2084 infoPtr->hFont = GetStockObject (DEFAULT_GUI_FONT);
2085 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
2086 logFont.lfWeight=FW_BOLD;
2087 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
2089 infoPtr->items = NULL;
2090 infoPtr->selectedItem=0;
2091 infoPtr->clrText=-1; /* use system color */
2092 infoPtr->dropItem=0;
2093 infoPtr->pCallBackSort=NULL;
2096 infoPtr->hwndNotify = GetParent32 (hwnd);
2097 infoPtr->bTransparent = ( GetWindowLongA( hwnd, GWL_STYLE) & TBSTYLE_FLAT);
2100 infoPtr->hwndToolTip=0;
2101 if (!( GetWindowLongA( hwnd, GWL_STYLE) & TVS_NOTOOLTIPS)) { /* Create tooltip control */
2104 infoPtr->hwndToolTip =
2105 CreateWindowExA (0, TOOLTIPS_CLASSA, NULL, 0,
2106 CW_USEDEFAULT, CW_USEDEFAULT,
2107 CW_USEDEFAULT, CW_USEDEFAULT,
2110 /* Send NM_TOOLTIPSCREATED notification */
2111 if (infoPtr->hwndToolTip) {
2112 NMTOOLTIPSCREATED nmttc;
2114 nmttc.hdr.hwndFrom = hwnd;
2115 nmttc.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2116 nmttc.hdr.code = NM_TOOLTIPSCREATED;
2117 nmttc.hwndToolTips = infoPtr->hwndToolTip;
2119 SendMessageA (GetParent (hwnd), WM_NOTIFY,
2120 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmttc);
2123 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
2124 ti.cbSize = sizeof(TTTOOLINFOA);
2125 ti.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_TRANSPARENT ;
2128 ti.lpszText = "Test"; /* LPSTR_TEXTCALLBACK; */
2129 SetRectEmpty (&ti.rect);
2131 SendMessageA (infoPtr->hwndToolTip, TTM_ADDTOOLA, 0, (LPARAM)&ti);
2134 infoPtr->hwndEdit = CreateWindowExA (
2138 WS_CHILD | WS_BORDER | ES_AUTOHSCROLL |
2139 ES_WANTRETURN | ES_LEFT,
2142 0,0,0); /* FIXME: (HMENU)IDTVEDIT,pcs->hInstance,0);*/
2144 SendMessageA ( infoPtr->hwndEdit, WM_SETFONT, infoPtr->hFont, FALSE);
2145 infoPtr->wpEditOrig = (WNDPROC)SetWindowLongA (
2148 (LONG) TREEVIEW_Edit_SubclassProc);
2150 ReleaseDC (hwnd, hdc);
2157 TREEVIEW_Destroy (HWND hwnd)
2159 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2162 TREEVIEW_RemoveTree (hwnd);
2163 if (infoPtr->Timer & TV_REFRESH_TIMER_SET)
2164 KillTimer (hwnd, TV_REFRESH_TIMER);
2165 if (infoPtr->hwndToolTip)
2166 DestroyWindow (infoPtr->hwndToolTip);
2168 COMCTL32_Free (infoPtr);
2174 TREEVIEW_Paint (HWND hwnd, WPARAM wParam, LPARAM lParam)
2180 hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
2181 TREEVIEW_Refresh (hwnd);
2183 EndPaint (hwnd, &ps);
2186 return DefWindowProcA (hwnd, WM_PAINT, wParam, lParam);
2190 TREEVIEW_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2192 TREEVIEW_SendSimpleNotify (hwnd, NM_SETFOCUS);
2193 InvalidateRect(hwnd, NULL, FALSE);
2198 TREEVIEW_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2200 TREEVIEW_SendSimpleNotify (hwnd, NM_KILLFOCUS);
2201 InvalidateRect(hwnd, NULL, FALSE);
2206 TREEVIEW_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
2208 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2209 HBRUSH hBrush = CreateSolidBrush (infoPtr->clrBk);
2213 GetClientRect (hwnd, &rect);
2214 FillRect ((HDC)wParam, &rect, hBrush);
2215 DeleteObject (hBrush);
2231 TREEVIEW_SendSimpleNotify (HWND hwnd, UINT code)
2236 nmhdr.hwndFrom = hwnd;
2237 nmhdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2240 return (BOOL) SendMessageA (GetParent (hwnd), WM_NOTIFY,
2241 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
2247 TREEVIEW_SendTreeviewNotify (HWND hwnd, UINT code, UINT action,
2248 HTREEITEM oldItem, HTREEITEM newItem)
2251 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2253 TREEVIEW_ITEM *wineItem;
2255 TRACE("code:%x action:%x olditem:%x newitem:%x\n",
2256 code,action,(INT)oldItem,(INT)newItem);
2257 nmhdr.hdr.hwndFrom = hwnd;
2258 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2259 nmhdr.hdr.code = code;
2260 nmhdr.action = action;
2262 wineItem=& infoPtr->items[(INT)oldItem];
2263 nmhdr.itemOld.mask = wineItem->mask;
2264 nmhdr.itemOld.hItem = wineItem->hItem;
2265 nmhdr.itemOld.state = wineItem->state;
2266 nmhdr.itemOld.stateMask = wineItem->stateMask;
2267 nmhdr.itemOld.iImage = wineItem->iImage;
2268 nmhdr.itemOld.pszText = wineItem->pszText;
2269 nmhdr.itemOld.cchTextMax= wineItem->cchTextMax;
2270 nmhdr.itemOld.iImage = wineItem->iImage;
2271 nmhdr.itemOld.iSelectedImage = wineItem->iSelectedImage;
2272 nmhdr.itemOld.cChildren = wineItem->cChildren;
2273 nmhdr.itemOld.lParam = wineItem->lParam;
2277 wineItem=& infoPtr->items[(INT)newItem];
2278 nmhdr.itemNew.mask = wineItem->mask;
2279 nmhdr.itemNew.hItem = wineItem->hItem;
2280 nmhdr.itemNew.state = wineItem->state;
2281 nmhdr.itemNew.stateMask = wineItem->stateMask;
2282 nmhdr.itemNew.iImage = wineItem->iImage;
2283 nmhdr.itemNew.pszText = wineItem->pszText;
2284 nmhdr.itemNew.cchTextMax= wineItem->cchTextMax;
2285 nmhdr.itemNew.iImage = wineItem->iImage;
2286 nmhdr.itemNew.iSelectedImage = wineItem->iSelectedImage;
2287 nmhdr.itemNew.cChildren = wineItem->cChildren;
2288 nmhdr.itemNew.lParam = wineItem->lParam;
2294 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2295 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2300 TREEVIEW_SendTreeviewDnDNotify (HWND hwnd, UINT code, HTREEITEM dragItem,
2303 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2305 TREEVIEW_ITEM *wineItem;
2307 TRACE("code:%x dragitem:%x\n", code,(INT)dragItem);
2309 nmhdr.hdr.hwndFrom = hwnd;
2310 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2311 nmhdr.hdr.code = code;
2313 wineItem=& infoPtr->items[(INT)dragItem];
2314 nmhdr.itemNew.mask = wineItem->mask;
2315 nmhdr.itemNew.hItem = wineItem->hItem;
2316 nmhdr.itemNew.state = wineItem->state;
2317 nmhdr.itemNew.lParam = wineItem->lParam;
2319 nmhdr.ptDrag.x = pt.x;
2320 nmhdr.ptDrag.y = pt.y;
2322 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2323 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2330 TREEVIEW_SendDispInfoNotify (HWND hwnd, TREEVIEW_ITEM *wineItem,
2331 UINT code, UINT what)
2337 TRACE("item %d, action %x, state %d\n",
2338 (INT)wineItem->hItem,
2340 (INT)wineItem->state);
2342 tvdi.hdr.hwndFrom = hwnd;
2343 tvdi.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2344 tvdi.hdr.code = code;
2345 tvdi.item.mask = what;
2346 tvdi.item.hItem = wineItem->hItem;
2347 tvdi.item.state = wineItem->state;
2348 tvdi.item.lParam = wineItem->lParam;
2349 tvdi.item.pszText = COMCTL32_Alloc (128*sizeof(char));
2350 buf = tvdi.item.pszText;
2352 retval=(BOOL)SendMessageA (
2355 (WPARAM)tvdi.hdr.idFrom,
2358 if (what & TVIF_TEXT) {
2359 wineItem->pszText = tvdi.item.pszText;
2360 if (buf==tvdi.item.pszText) {
2361 wineItem->cchTextMax = 128;
2363 TRACE("user-supplied buffer\n");
2364 COMCTL32_Free (buf);
2365 wineItem->cchTextMax = 0;
2368 if (what & TVIF_SELECTEDIMAGE)
2369 wineItem->iSelectedImage = tvdi.item.iSelectedImage;
2370 if (what & TVIF_IMAGE)
2371 wineItem->iImage = tvdi.item.iImage;
2372 if (what & TVIF_CHILDREN)
2373 wineItem->cChildren = tvdi.item.cChildren;
2381 TREEVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
2384 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2385 NMTVCUSTOMDRAW nmcdhdr;
2386 LPNMCUSTOMDRAW nmcd;
2388 TRACE("drawstage:%lx hdc:%x\n", dwDrawStage, hdc);
2390 nmcd= & nmcdhdr.nmcd;
2391 nmcd->hdr.hwndFrom = hwnd;
2392 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2393 nmcd->hdr.code = NM_CUSTOMDRAW;
2394 nmcd->dwDrawStage= dwDrawStage;
2396 nmcd->rc.left = rc.left;
2397 nmcd->rc.right = rc.right;
2398 nmcd->rc.bottom = rc.bottom;
2399 nmcd->rc.top = rc.top;
2400 nmcd->dwItemSpec = 0;
2401 nmcd->uItemState = 0;
2402 nmcd->lItemlParam= 0;
2403 nmcdhdr.clrText = infoPtr->clrText;
2404 nmcdhdr.clrTextBk= infoPtr->clrBk;
2407 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2408 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2414 /* FIXME: need to find out when the flags in uItemState need to be set */
2417 TREEVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
2418 TREEVIEW_ITEM *wineItem, UINT uItemDrawState)
2420 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2421 NMTVCUSTOMDRAW nmcdhdr;
2422 LPNMCUSTOMDRAW nmcd;
2423 DWORD dwDrawStage,dwItemSpec;
2426 dwDrawStage=CDDS_ITEM | uItemDrawState;
2427 dwItemSpec=(DWORD)wineItem->hItem;
2429 if (wineItem->hItem==infoPtr->selectedItem) uItemState|=CDIS_SELECTED;
2430 if (wineItem->hItem==infoPtr->focusItem) uItemState|=CDIS_FOCUS;
2431 if (wineItem->hItem==infoPtr->hotItem) uItemState|=CDIS_HOT;
2433 nmcd= & nmcdhdr.nmcd;
2434 nmcd->hdr.hwndFrom = hwnd;
2435 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2436 nmcd->hdr.code = NM_CUSTOMDRAW;
2437 nmcd->dwDrawStage= dwDrawStage;
2439 nmcd->rc.left = wineItem->rect.left;
2440 nmcd->rc.right = wineItem->rect.right;
2441 nmcd->rc.bottom = wineItem->rect.bottom;
2442 nmcd->rc.top = wineItem->rect.top;
2443 nmcd->dwItemSpec = dwItemSpec;
2444 nmcd->uItemState = uItemState;
2445 nmcd->lItemlParam= wineItem->lParam;
2447 nmcdhdr.clrText = infoPtr->clrText;
2448 nmcdhdr.clrTextBk= infoPtr->clrBk;
2449 nmcdhdr.iLevel = wineItem->iLevel;
2451 TRACE("drawstage:%lx hdc:%x item:%lx, itemstate:%x\n",
2452 dwDrawStage, hdc, dwItemSpec, uItemState);
2454 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2455 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2460 /* Note:If the specified item is the child of a collapsed parent item,
2461 the parent's list of child items is (recursively) expanded to reveal the
2462 specified item. This is mentioned for TREEVIEW_SelectItem; don't
2463 know if it also applies here.
2467 TREEVIEW_Expand (HWND hwnd, WPARAM wParam, LPARAM lParam)
2469 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2470 TREEVIEW_ITEM *wineItem;
2474 flag = (UINT) wParam;
2475 expand = (INT) lParam;
2477 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2481 if (!wineItem->cChildren)
2484 if (wineItem->pszText==LPSTR_TEXTCALLBACKA)
2485 TRACE ("For item %d, flags %d, state %d\n",
2486 expand, flag, wineItem->state);
2488 TRACE("For (%s) item:%d, flags %x, state:%d\n",
2489 wineItem->pszText, flag, expand, wineItem->state);
2492 if (wineItem->cChildren==I_CHILDRENCALLBACK) {
2493 FIXME("we don't handle I_CHILDRENCALLBACK yet\n");
2497 if (flag == TVE_TOGGLE) { /* FIXME: check exact behaviour here */
2498 flag &= ~TVE_TOGGLE; /* ie: bitwise ops or 'case' ops */
2499 if (wineItem->state & TVIS_EXPANDED)
2500 flag |= TVE_COLLAPSE;
2507 case TVE_COLLAPSERESET:
2508 TRACE(" case TVE_COLLAPSERESET\n");
2509 if (!wineItem->state & TVIS_EXPANDED)
2512 wineItem->state &= ~(TVIS_EXPANDEDONCE | TVIS_EXPANDED);
2513 TREEVIEW_RemoveAllChildren (hwnd, wineItem);
2517 TRACE(" case TVE_COLLAPSE\n");
2518 if (!wineItem->state & TVIS_EXPANDED)
2521 wineItem->state &= ~TVIS_EXPANDED;
2525 TRACE(" case TVE_EXPAND\n");
2526 if (wineItem->state & TVIS_EXPANDED)
2529 TRACE(" is not expanded...\n");
2531 if (!(wineItem->state & TVIS_EXPANDEDONCE))
2533 TRACE(" and has never been expanded...\n");
2534 wineItem->state |= TVIS_EXPANDED;
2536 /* this item has never been expanded */
2537 if (TREEVIEW_SendTreeviewNotify (
2544 TRACE(" TVN_ITEMEXPANDING returned TRUE, exiting...\n");
2549 * Since the TVN_ITEMEXPANDING message may has caused the parent to
2550 * insert new items which in turn may have cause items placeholder
2551 * reallocation, I reassign the current item pointer so we have
2552 * something valid to work with...
2553 * However, this should not be necessary,
2554 * investigation required in TREEVIEW_InsertItemA
2556 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2560 "Catastropic situation, cannot retreive item #%d\n",
2565 wineItem->state |= TVIS_EXPANDEDONCE;
2566 TRACE(" TVN_ITEMEXPANDING sent...\n");
2568 TREEVIEW_SendTreeviewNotify (
2575 TRACE(" TVN_ITEMEXPANDED sent...\n");
2580 /* this item has already been expanded */
2581 wineItem->state |= TVIS_EXPANDED;
2585 case TVE_EXPANDPARTIAL:
2586 TRACE(" case TVE_EXPANDPARTIAL\n");
2587 FIXME("TVE_EXPANDPARTIAL not implemented\n");
2588 wineItem->state ^=TVIS_EXPANDED;
2589 wineItem->state |=TVIS_EXPANDEDONCE;
2593 TRACE("Exiting, Item %d state is now %d...\n",
2597 TREEVIEW_QueueRefresh (hwnd);
2603 static TREEVIEW_ITEM *
2604 TREEVIEW_HitTestPoint (HWND hwnd, POINT pt)
2606 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2607 TREEVIEW_ITEM *wineItem;
2610 GetClientRect (hwnd, &rect);
2612 if (!infoPtr->firstVisible) return NULL;
2614 wineItem=&infoPtr->items [(INT)infoPtr->firstVisible];
2616 while ((wineItem!=NULL) && (pt.y > wineItem->rect.bottom))
2617 wineItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
2629 TREEVIEW_HitTest (HWND hwnd, LPARAM lParam)
2631 LPTVHITTESTINFO lpht=(LPTVHITTESTINFO) lParam;
2632 TREEVIEW_ITEM *wineItem;
2636 GetClientRect (hwnd, &rect);
2640 if (x < rect.left) status|=TVHT_TOLEFT;
2641 if (x > rect.right) status|=TVHT_TORIGHT;
2642 if (y < rect.top ) status|=TVHT_ABOVE;
2643 if (y > rect.bottom) status|=TVHT_BELOW;
2650 wineItem=TREEVIEW_HitTestPoint (hwnd, lpht->pt);
2652 lpht->flags=TVHT_NOWHERE;
2656 /* FIXME: implement other flags
2657 * Assign the appropriate flags depending on the click location
2658 * Intitialize flags before to "|=" it...
2662 if (x < wineItem->expandBox.left)
2664 lpht->flags |= TVHT_ONITEMINDENT;
2666 else if ( ( x >= wineItem->expandBox.left) &&
2667 ( x <= wineItem->expandBox.right))
2669 lpht->flags |= TVHT_ONITEMBUTTON;
2671 else if (x < wineItem->rect.right)
2673 lpht->flags |= TVHT_ONITEMLABEL;
2677 lpht->flags|=TVHT_ONITEMRIGHT;
2680 lpht->hItem=wineItem->hItem;
2682 return (LRESULT) wineItem->hItem;
2686 TREEVIEW_EndEditLabelNow (HWND hwnd, WPARAM wParam, LPARAM lParam)
2688 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2689 TREEVIEW_ITEM *editedItem = TREEVIEW_ValidItem (infoPtr, infoPtr->editItem);
2690 BOOL bRevert = (BOOL)wParam;
2691 BOOL bReturn = ! bRevert;
2693 if ( ! (BOOL)wParam ) /* wParam is set to true to cancel the edition */
2695 if ( TREEVIEW_SendDispInfoNotify( /* return true to cancel edition */
2706 if (bRevert == FALSE) /* Apply the changes */
2709 int iLength = GetWindowTextA(infoPtr->hwndEdit, tmpText, 1023);
2714 ERR("Problem retreiving new item label.");
2716 else if (iLength >= 1023)
2719 "Insuficient space to retrieve new item label, new label ignored.");
2723 if (strcmp( tmpText, editedItem->pszText ) == 0)
2724 /* Do nothing if the label has not changed */
2728 LPSTR tmpLabel = COMCTL32_Alloc( iLength+1 );
2730 if ( tmpLabel == NULL )
2732 "OutOfMemory, cannot allocate space for label");
2735 COMCTL32_Free(editedItem->pszText);
2736 editedItem->pszText = tmpLabel;
2737 lstrcpyA( editedItem->pszText, tmpText);
2743 ShowWindow(infoPtr->hwndEdit, SW_HIDE);
2744 EnableWindow(infoPtr->hwndEdit, FALSE);
2745 infoPtr->editItem = 0;
2754 TREEVIEW_LButtonDoubleClick (HWND hwnd, WPARAM wParam, LPARAM lParam)
2756 TREEVIEW_ITEM *wineItem;
2760 pt.x = (INT)LOWORD(lParam);
2761 pt.y = (INT)HIWORD(lParam);
2764 wineItem=TREEVIEW_HitTestPoint (hwnd, pt);
2765 if (!wineItem) return 0;
2766 TRACE("item %d \n",(INT)wineItem->hItem);
2768 if (TREEVIEW_SendSimpleNotify (hwnd, NM_DBLCLK)!=TRUE) { /* FIXME!*/
2769 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) wineItem->hItem);
2776 TREEVIEW_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
2778 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2782 ht.pt.x = (INT)LOWORD(lParam);
2783 ht.pt.y = (INT)HIWORD(lParam);
2786 iItem=TREEVIEW_HitTest (hwnd, (LPARAM) &ht);
2787 TRACE("item %d \n",iItem);
2789 if (ht.flags & TVHT_ONITEMBUTTON) {
2790 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) iItem);
2794 infoPtr->uInternalStatus|=TV_LDRAG;
2801 TREEVIEW_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
2803 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2805 TREEVIEW_ITEM *editItem;
2808 ht.pt.x = (INT)LOWORD(lParam);
2809 ht.pt.y = (INT)HIWORD(lParam);
2813 /* Return true to cancel default behaviour */
2814 if ( TREEVIEW_SendSimpleNotify (hwnd, NM_CLICK) )
2818 iItem = TREEVIEW_HitTest (hwnd, (LPARAM) &ht);
2822 editItem = TREEVIEW_ValidItem(infoPtr, (HTREEITEM)iItem);
2824 infoPtr->uInternalStatus &= ~(TV_LDRAG | TV_LDRAGGING);
2827 * If the style allow editing and the node is already selected
2828 * and the click occured on the item label...
2830 if ( ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_EDITLABELS ) &&
2831 ( editItem->state & TVIS_SELECTED ) &&
2832 ( ht.flags & TVHT_ONITEMLABEL ))
2834 if ( infoPtr->editItem == 0 ) /* If we are not curently editing */
2836 if ( TREEVIEW_SendDispInfoNotify( /* Return true to cancel edition */
2845 TRACE("Edit started for %s.\n", editItem->pszText);
2846 infoPtr->editItem = editItem->hItem;
2851 editItem->text.left - 2,
2852 editItem->text.top - 1,
2853 editItem->text.right - editItem->text.left + 20 ,
2854 editItem->text.bottom - editItem->text.top + 3,
2857 SetWindowTextA( infoPtr->hwndEdit, editItem->pszText );
2858 SendMessageA ( infoPtr->hwndEdit, EM_SETSEL, 0, -1 );
2859 SetFocus ( infoPtr->hwndEdit);
2860 ShowWindow ( infoPtr->hwndEdit, SW_SHOW);
2863 else if ( infoPtr->editItem != 0 ) /* If we are curently editing */
2865 TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
2867 else if ( ht.flags & (TVHT_ONITEMLABEL | TVHT_ONITEMICON))
2869 TREEVIEW_DoSelectItem (
2881 TREEVIEW_RButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
2883 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2886 infoPtr->uInternalStatus|=TV_RDRAG;
2891 TREEVIEW_RButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
2893 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2896 if (TREEVIEW_SendSimpleNotify (hwnd, NM_RCLICK)) return 0;
2897 infoPtr->uInternalStatus&= ~(TV_RDRAG | TV_RDRAGGING);
2903 TREEVIEW_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
2905 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2906 TREEVIEW_ITEM *hotItem;
2909 pt.x=(INT) LOWORD (lParam);
2910 pt.y=(INT) HIWORD (lParam);
2911 hotItem=TREEVIEW_HitTestPoint (hwnd, pt);
2912 if (!hotItem) return 0;
2913 infoPtr->focusItem=hotItem->hItem;
2915 if ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_DISABLEDRAGDROP) return 0;
2917 if (infoPtr->uInternalStatus & TV_LDRAG) {
2918 TREEVIEW_SendTreeviewDnDNotify (hwnd, TVN_BEGINDRAG, hotItem->hItem, pt);
2919 infoPtr->uInternalStatus &= ~TV_LDRAG;
2920 infoPtr->uInternalStatus |= TV_LDRAGGING;
2921 infoPtr->dropItem=hotItem->hItem;
2925 if (infoPtr->uInternalStatus & TV_RDRAG) {
2926 TREEVIEW_SendTreeviewDnDNotify (hwnd, TVN_BEGINRDRAG, hotItem->hItem, pt);
2927 infoPtr->uInternalStatus &= ~TV_RDRAG;
2928 infoPtr->uInternalStatus |= TV_RDRAGGING;
2929 infoPtr->dropItem=hotItem->hItem;
2938 TREEVIEW_CreateDragImage (HWND hwnd, WPARAM wParam, LPARAM lParam)
2940 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2941 TREEVIEW_ITEM *dragItem;
2945 HBITMAP hbmp,hOldbmp;
2952 if (!(infoPtr->himlNormal)) return 0;
2953 dragItem=TREEVIEW_ValidItem (infoPtr, (HTREEITEM) lParam);
2955 if (!dragItem) return 0;
2956 itemtxt=dragItem->pszText;
2958 hwtop=GetDesktopWindow ();
2959 htopdc= GetDC (hwtop);
2960 hdc=CreateCompatibleDC (htopdc);
2962 hOldFont=SelectObject (hdc, infoPtr->hFont);
2963 GetTextExtentPoint32A (hdc, itemtxt, lstrlenA (itemtxt), &size);
2964 TRACE("%d %d %s %d\n",size.cx,size.cy,itemtxt,lstrlenA(itemtxt));
2965 hbmp=CreateCompatibleBitmap (htopdc, size.cx, size.cy);
2966 hOldbmp=SelectObject (hdc, hbmp);
2968 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &cy);
2970 if (cy>size.cy) size.cy=cy;
2972 infoPtr->dragList=ImageList_Create (size.cx, size.cy, ILC_COLOR, 10, 10);
2973 ImageList_Draw (infoPtr->himlNormal, dragItem->iImage, hdc, 0, 0, ILD_NORMAL);
2976 ImageList_GetImageInfo (infoPtr->himlNormal, dragItem->hItem, &iminfo);
2977 ImageList_AddMasked (infoPtr->dragList, iminfo.hbmImage, CLR_DEFAULT);
2980 /* draw item text */
2982 SetRect (&rc, cx, 0, size.cx,size.cy);
2983 DrawTextA (hdc, itemtxt, lstrlenA (itemtxt), &rc, DT_LEFT);
2984 SelectObject (hdc, hOldFont);
2985 SelectObject (hdc, hOldbmp);
2987 ImageList_Add (infoPtr->dragList, hbmp, 0);
2990 DeleteObject (hbmp);
2991 ReleaseDC (hwtop, htopdc);
2993 return (LRESULT)infoPtr->dragList;
2998 TREEVIEW_DoSelectItem (HWND hwnd, INT action, HTREEITEM newSelect, INT cause)
3001 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3002 TREEVIEW_ITEM *prevItem,*wineItem;
3005 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)newSelect);
3007 TRACE("Entering item %d, flag %x, cause %x, state %d\n",
3013 if ( (wineItem) && (wineItem->parent))
3016 * If the item has a collapse parent expand the parent so he
3017 * can expose the item
3019 TREEVIEW_ITEM *parentItem = TREEVIEW_ValidItem (infoPtr, wineItem->parent);
3020 if ( !(parentItem->state & TVIS_EXPANDED))
3021 TREEVIEW_Expand (hwnd, TVE_EXPAND, (LPARAM) wineItem->parent);
3027 prevSelect=(INT)infoPtr->selectedItem;
3029 if ((HTREEITEM)prevSelect==newSelect)
3032 prevItem= TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect);
3035 if (TREEVIEW_SendTreeviewNotify(
3039 (HTREEITEM)prevSelect,
3040 (HTREEITEM)newSelect))
3041 return FALSE; /* FIXME: OK? */
3044 prevItem->state &= ~TVIS_SELECTED;
3046 wineItem->state |= TVIS_SELECTED;
3048 infoPtr->selectedItem=(HTREEITEM)newSelect;
3050 TREEVIEW_SendTreeviewNotify(
3054 (HTREEITEM)prevSelect,
3055 (HTREEITEM)newSelect);
3059 case TVGN_DROPHILITE:
3060 prevItem= TREEVIEW_ValidItem (infoPtr, infoPtr->dropItem);
3063 prevItem->state &= ~TVIS_DROPHILITED;
3065 infoPtr->dropItem=(HTREEITEM)newSelect;
3068 wineItem->state |=TVIS_DROPHILITED;
3072 case TVGN_FIRSTVISIBLE:
3073 FIXME("FIRSTVISIBLE not implemented\n");
3077 TREEVIEW_QueueRefresh (hwnd);
3079 TRACE("Leaving state %d\n", wineItem->state);
3083 /* FIXME: handle NM_KILLFocus enzo */
3085 TREEVIEW_SelectItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
3088 return TREEVIEW_DoSelectItem (hwnd, wParam, (HTREEITEM) lParam, TVC_UNKNOWN);
3095 TREEVIEW_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
3098 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3100 TRACE("%x\n",infoPtr->hFont);
3101 return infoPtr->hFont;
3105 TREEVIEW_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
3108 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3111 HFONT hFont, hOldFont;
3115 TRACE("%x %lx\n",wParam, lParam);
3117 infoPtr->hFont = (HFONT)wParam;
3119 hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
3121 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
3122 logFont.lfWeight=FW_BOLD;
3123 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
3126 hOldFont = SelectObject (hdc, hFont);
3127 GetTextMetricsA (hdc, &tm);
3128 height= tm.tmHeight + tm.tmExternalLeading;
3129 if (height>infoPtr->uRealItemHeight)
3130 infoPtr->uRealItemHeight=height;
3131 SelectObject (hdc, hOldFont);
3135 TREEVIEW_QueueRefresh (hwnd);
3143 TREEVIEW_VScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
3146 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3149 TRACE("wp %x, lp %lx\n", wParam, lParam);
3150 if (!infoPtr->uInternalStatus & TV_VSCROLL) return FALSE;
3152 switch (LOWORD (wParam)) {
3154 if (!infoPtr->cy) return FALSE;
3155 infoPtr->cy -= infoPtr->uRealItemHeight;
3156 if (infoPtr->cy < 0) infoPtr->cy=0;
3159 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3160 if (infoPtr->cy == maxHeight) return FALSE;
3161 infoPtr->cy += infoPtr->uRealItemHeight;
3162 if (infoPtr->cy > maxHeight)
3163 infoPtr->cy = maxHeight;
3166 if (!infoPtr->cy) return FALSE;
3167 infoPtr->cy -= infoPtr->uVisibleHeight;
3168 if (infoPtr->cy < 0) infoPtr->cy=0;
3171 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3172 if (infoPtr->cy == maxHeight) return FALSE;
3173 infoPtr->cy += infoPtr->uVisibleHeight;
3174 if (infoPtr->cy > maxHeight)
3175 infoPtr->cy = maxHeight;
3178 infoPtr->cy = HIWORD (wParam);
3183 TREEVIEW_QueueRefresh (hwnd);
3188 TREEVIEW_HScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
3190 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3193 TRACE("wp %lx, lp %x\n", lParam, wParam);
3195 if (!infoPtr->uInternalStatus & TV_HSCROLL) return FALSE;
3197 switch (LOWORD (wParam)) {
3199 if (!infoPtr->cx) return FALSE;
3200 infoPtr->cx -= infoPtr->uRealItemHeight;
3201 if (infoPtr->cx < 0) infoPtr->cx=0;
3204 maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
3205 if (infoPtr->cx == maxWidth) return FALSE;
3206 infoPtr->cx += infoPtr->uRealItemHeight; /*FIXME */
3207 if (infoPtr->cx > maxWidth)
3208 infoPtr->cx = maxWidth;
3211 if (!infoPtr->cx) return FALSE;
3212 infoPtr->cx -= infoPtr->uVisibleWidth;
3213 if (infoPtr->cx < 0) infoPtr->cx=0;
3216 maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
3217 if (infoPtr->cx == maxWidth) return FALSE;
3218 infoPtr->cx += infoPtr->uVisibleWidth;
3219 if (infoPtr->cx > maxWidth)
3220 infoPtr->cx = maxWidth;
3223 infoPtr->cx = HIWORD (wParam);
3228 TREEVIEW_QueueRefresh (hwnd);
3234 TREEVIEW_KeyDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
3236 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3237 HTREEITEM hNewSelection = 0;
3238 INT scrollNeeds = -1;
3239 INT cyChangeNeeds = -1;
3240 INT prevSelect = (INT)infoPtr->selectedItem;
3242 TREEVIEW_ITEM *prevItem =
3243 (prevSelect != 0 ) ?
3244 TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect) :
3247 TREEVIEW_ITEM *newItem = NULL;
3249 TRACE("%x %lx\n",wParam, lParam);
3251 if (prevSelect == 0)
3256 newItem=TREEVIEW_GetPrevListItem (infoPtr, prevItem);
3259 newItem=& infoPtr->items[(INT)infoPtr->TopRootItem];
3261 hNewSelection = newItem->hItem;
3263 if (! newItem->visible)
3264 scrollNeeds = SB_LINEUP;
3269 newItem=TREEVIEW_GetNextListItem (infoPtr, prevItem);
3274 hNewSelection = newItem->hItem;
3276 if (! newItem->visible)
3277 scrollNeeds = SB_LINEDOWN;
3282 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem];
3283 hNewSelection = newItem->hItem;
3288 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem];
3289 newItem = TREEVIEW_GetLastListItem (infoPtr, newItem);
3290 hNewSelection = newItem->hItem;
3292 if (! newItem->visible)
3293 cyChangeNeeds = infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3298 if ( (prevItem->cChildren > 0) && (prevItem->state & TVIS_EXPANDED) )
3300 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect );
3302 else if ((INT)prevItem->parent)
3304 newItem = (& infoPtr->items[(INT)prevItem->parent]);
3305 if (! newItem->visible)
3306 /* FIXME find a way to make this item the first visible... */
3309 hNewSelection = newItem->hItem;
3315 if ( ( prevItem->cChildren > 0) ||
3316 ( prevItem->cChildren == I_CHILDRENCALLBACK))
3318 if (! (prevItem->state & TVIS_EXPANDED))
3319 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect );
3322 newItem = (& infoPtr->items[(INT)prevItem->firstChild]);
3323 hNewSelection = newItem->hItem;
3330 if (! (prevItem->state & TVIS_EXPANDED))
3331 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect );
3335 if (prevItem->state & TVIS_EXPANDED)
3336 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect );
3341 newItem=TREEVIEW_GetListItem(
3344 -1*(TREEVIEW_GetVisibleCount(hwnd,0,0)-3));
3348 hNewSelection = newItem->hItem;
3350 if (! newItem->visible)
3351 scrollNeeds = SB_PAGEUP;
3356 newItem=TREEVIEW_GetListItem(
3359 TREEVIEW_GetVisibleCount(hwnd,0,0)-3);
3364 hNewSelection = newItem->hItem;
3366 if (! newItem->visible)
3367 scrollNeeds = SB_PAGEDOWN;
3376 FIXME("%x not implemented\n", wParam);
3383 This works but does not send notification...
3385 prevItem->state &= ~TVIS_SELECTED;
3386 newItem->state |= TVIS_SELECTED;
3387 infoPtr->selectedItem = hNewSelection;
3388 TREEVIEW_QueueRefresh (hwnd);
3391 if ( TREEVIEW_DoSelectItem(
3394 (HTREEITEM)hNewSelection,
3397 /* If selection change is allowed for the new item, perform scrolling */
3398 if (scrollNeeds != -1)
3399 TREEVIEW_VScroll(hwnd, scrollNeeds, 0);
3401 if (cyChangeNeeds != -1)
3402 infoPtr->cy = cyChangeNeeds;
3404 /* FIXME: Something happen in the load the in the two weeks before
3405 april 1st 1999 which makes this SetFocus mandatory otherwise, the focus
3406 is lost... However the SetFocus should not be required...*/
3417 TREEVIEW_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3420 case TVM_INSERTITEMA:
3421 return TREEVIEW_InsertItemA (hwnd, wParam, lParam);
3423 case TVM_INSERTITEMW:
3424 FIXME("Unimplemented msg TVM_INSERTITEM32W\n");
3427 case TVM_DELETEITEM:
3428 return TREEVIEW_DeleteItem (hwnd, wParam, lParam);
3431 return TREEVIEW_Expand (hwnd, wParam, lParam);
3433 case TVM_GETITEMRECT:
3434 return TREEVIEW_GetItemRect (hwnd, wParam, lParam);
3437 return TREEVIEW_GetCount (hwnd, wParam, lParam);
3440 return TREEVIEW_GetIndent (hwnd);
3443 return TREEVIEW_SetIndent (hwnd, wParam);
3445 case TVM_GETIMAGELIST:
3446 return TREEVIEW_GetImageList (hwnd, wParam, lParam);
3448 case TVM_SETIMAGELIST:
3449 return TREEVIEW_SetImageList (hwnd, wParam, lParam);
3451 case TVM_GETNEXTITEM:
3452 return TREEVIEW_GetNextItem (hwnd, wParam, lParam);
3454 case TVM_SELECTITEM:
3455 return TREEVIEW_SelectItem (hwnd, wParam, lParam);
3458 return TREEVIEW_GetItemA (hwnd, wParam, lParam);
3461 FIXME("Unimplemented msg TVM_GETITEM32W\n");
3465 return TREEVIEW_SetItemA (hwnd, wParam, lParam);
3468 FIXME("Unimplemented msg TVM_SETITEMW\n");
3471 case TVM_EDITLABELA:
3472 FIXME("Unimplemented msg TVM_EDITLABEL32A \n");
3475 case TVM_EDITLABELW:
3476 FIXME("Unimplemented msg TVM_EDITLABEL32W \n");
3479 case TVM_GETEDITCONTROL:
3480 return TREEVIEW_GetEditControl (hwnd);
3482 case TVM_GETVISIBLECOUNT:
3483 return TREEVIEW_GetVisibleCount (hwnd, wParam, lParam);
3486 return TREEVIEW_HitTest (hwnd, lParam);
3488 case TVM_CREATEDRAGIMAGE:
3489 return TREEVIEW_CreateDragImage (hwnd, wParam, lParam);
3491 case TVM_SORTCHILDREN:
3492 return TREEVIEW_SortChildren (hwnd, wParam, lParam);
3494 case TVM_ENSUREVISIBLE:
3495 FIXME("Unimplemented msg TVM_ENSUREVISIBLE\n");
3498 case TVM_SORTCHILDRENCB:
3499 return TREEVIEW_SortChildrenCB(hwnd, wParam, lParam);
3501 case TVM_ENDEDITLABELNOW:
3502 return TREEVIEW_EndEditLabelNow (hwnd, wParam, lParam);
3504 case TVM_GETISEARCHSTRINGA:
3505 FIXME("Unimplemented msg TVM_GETISEARCHSTRING32A\n");
3508 case TVM_GETISEARCHSTRINGW:
3509 FIXME("Unimplemented msg TVM_GETISEARCHSTRING32W\n");
3512 case TVM_GETTOOLTIPS:
3513 return TREEVIEW_GetToolTips (hwnd);
3515 case TVM_SETTOOLTIPS:
3516 return TREEVIEW_SetToolTips (hwnd, wParam);
3518 case TVM_SETINSERTMARK:
3519 FIXME("Unimplemented msg TVM_SETINSERTMARK\n");
3522 case TVM_SETITEMHEIGHT:
3523 return TREEVIEW_SetItemHeight (hwnd, wParam);
3525 case TVM_GETITEMHEIGHT:
3526 return TREEVIEW_GetItemHeight (hwnd);
3528 case TVM_SETBKCOLOR:
3529 return TREEVIEW_SetBkColor (hwnd, wParam, lParam);
3531 case TVM_SETTEXTCOLOR:
3532 return TREEVIEW_SetTextColor (hwnd, wParam, lParam);
3534 case TVM_GETBKCOLOR:
3535 return TREEVIEW_GetBkColor (hwnd);
3537 case TVM_GETTEXTCOLOR:
3538 return TREEVIEW_GetTextColor (hwnd);
3540 case TVM_SETSCROLLTIME:
3541 FIXME("Unimplemented msg TVM_SETSCROLLTIME\n");
3544 case TVM_GETSCROLLTIME:
3545 FIXME("Unimplemented msg TVM_GETSCROLLTIME\n");
3548 case TVM_SETINSERTMARKCOLOR:
3549 FIXME("Unimplemented msg TVM_SETINSERTMARKCOLOR\n");
3552 case TVM_SETUNICODEFORMAT:
3553 FIXME("Unimplemented msg TVM_SETUNICODEFORMAT\n");
3556 case TVM_GETUNICODEFORMAT:
3557 FIXME("Unimplemented msg TVM_GETUNICODEFORMAT\n");
3561 return TREEVIEW_Command (hwnd, wParam, lParam);
3564 return TREEVIEW_Create (hwnd, wParam, lParam);
3567 return TREEVIEW_Destroy (hwnd);
3569 /* case WM_ENABLE: */
3572 return TREEVIEW_EraseBackground (hwnd, wParam, lParam);
3575 return DLGC_WANTARROWS | DLGC_WANTCHARS;
3578 return TREEVIEW_Paint (hwnd, wParam, lParam);
3581 return TREEVIEW_GetFont (hwnd, wParam, lParam);
3584 return TREEVIEW_SetFont (hwnd, wParam, lParam);
3587 return TREEVIEW_KeyDown (hwnd, wParam, lParam);
3591 return TREEVIEW_SetFocus (hwnd, wParam, lParam);
3594 return TREEVIEW_KillFocus (hwnd, wParam, lParam);
3597 case WM_LBUTTONDOWN:
3598 return TREEVIEW_LButtonDown (hwnd, wParam, lParam);
3601 return TREEVIEW_LButtonUp (hwnd, wParam, lParam);
3603 case WM_LBUTTONDBLCLK:
3604 return TREEVIEW_LButtonDoubleClick (hwnd, wParam, lParam);
3606 case WM_RBUTTONDOWN:
3607 return TREEVIEW_RButtonDown (hwnd, wParam, lParam);
3610 return TREEVIEW_RButtonUp (hwnd, wParam, lParam);
3613 return TREEVIEW_MouseMove (hwnd, wParam, lParam);
3616 /* case WM_SYSCOLORCHANGE: */
3617 case WM_STYLECHANGED:
3618 return TREEVIEW_StyleChanged (hwnd, wParam, lParam);
3620 /* case WM_SETREDRAW: */
3623 return TREEVIEW_HandleTimer (hwnd, wParam, lParam);
3626 return TREEVIEW_Size (hwnd, wParam,lParam);
3629 return TREEVIEW_HScroll (hwnd, wParam, lParam);
3631 return TREEVIEW_VScroll (hwnd, wParam, lParam);
3634 TRACE ("drawItem\n");
3635 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
3638 if (uMsg >= WM_USER)
3639 FIXME("Unknown msg %04x wp=%08x lp=%08lx\n",
3640 uMsg, wParam, lParam);
3641 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
3648 TREEVIEW_Register (void)
3654 if (GlobalFindAtomA (WC_TREEVIEWA)) return;
3656 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
3657 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
3658 wndClass.lpfnWndProc = (WNDPROC)TREEVIEW_WindowProc;
3659 wndClass.cbClsExtra = 0;
3660 wndClass.cbWndExtra = sizeof(TREEVIEW_INFO *);
3661 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
3662 wndClass.hbrBackground = 0;
3663 wndClass.lpszClassName = WC_TREEVIEWA;
3665 RegisterClassA (&wndClass);
3670 TREEVIEW_Unregister (void)
3672 if (GlobalFindAtomA (WC_TREEVIEWA))
3673 UnregisterClassA (WC_TREEVIEWA, (HINSTANCE)NULL);