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.
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 (treeview,"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);
393 TRACE (treeview,"\n");
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);
410 TRACE (treeview,"\n");
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;
435 TRACE (treeview,"\n");
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);
457 TRACE (treeview,"\n");
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;
467 TRACE (treeview,"\n");
468 infoPtr->clrText=(COLORREF) lParam;
469 return (LRESULT) prevColor;
473 TREEVIEW_GetBkColor (HWND hwnd)
475 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
477 TRACE (treeview,"\n");
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;
487 TRACE (treeview,"\n");
488 infoPtr->clrBk=(COLORREF) lParam;
489 return (LRESULT) prevColor;
493 TREEVIEW_GetTextColor (HWND hwnd)
495 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
497 TRACE (treeview,"\n");
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);
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 (treeview,"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 ( GetWindowLongA( hwnd, GWL_STYLE) & 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 ( GetWindowLongA( hwnd, GWL_STYLE) & 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 (( GetWindowLongA( hwnd, GWL_STYLE) & TVS_HASBUTTONS) &&
622 ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_HASLINES))
624 if ( (wineItem->cChildren) ||
625 (wineItem->cChildren == I_CHILDRENCALLBACK))
627 /* Setup expand box coordinate to facilitate the LMBClick handling */
628 wineItem->expandBox.left = xpos-4;
629 wineItem->expandBox.top = center-4;
630 wineItem->expandBox.right = xpos+5;
631 wineItem->expandBox.bottom = center+5;
635 wineItem->expandBox.left,
636 wineItem->expandBox.top ,
637 wineItem->expandBox.right,
638 wineItem->expandBox.bottom);
640 MoveToEx (hdc, xpos-2, center, NULL);
641 LineTo (hdc, xpos+3, center);
643 if (!(wineItem->state & TVIS_EXPANDED)) {
644 MoveToEx (hdc, xpos, center-2, NULL);
645 LineTo (hdc, xpos, center+3);
651 * Display the image assiciated with this item
653 xpos += 13; /* update position */
654 if (wineItem->mask & (TVIF_IMAGE|TVIF_SELECTEDIMAGE)) {
656 HIMAGELIST *himlp = NULL;
658 if (infoPtr->himlNormal)
659 himlp=&infoPtr->himlNormal; /* get the image list */
661 if ( (wineItem->state & TVIS_SELECTED) &&
662 (wineItem->iSelectedImage)) {
664 /* State images are displayed to the left of the Normal image*/
665 if (infoPtr->himlState)
666 himlp=&infoPtr->himlState;
668 /* The item is curently selected */
669 if (wineItem->iSelectedImage == I_IMAGECALLBACK)
670 TREEVIEW_SendDispInfoNotify (
676 imageIndex = wineItem->iSelectedImage;
679 /* This item is not selected */
680 if (wineItem->iImage == I_IMAGECALLBACK)
681 TREEVIEW_SendDispInfoNotify (
687 imageIndex = wineItem->iImage;
692 /* We found an image to display? Draw it. */
701 ImageList_GetIconSize (*himlp, &cx, &cy);
707 * Display the text assiciated with this item
710 if ((wineItem->mask & TVIF_TEXT) && (wineItem->pszText))
712 COLORREF oldBkColor = 0;
713 COLORREF oldTextColor = 0;
719 wineItem->text.left = r.left;
720 wineItem->text.right = r.right;
721 wineItem->text.top = r.top;
722 wineItem->text.bottom= r.bottom;
724 if (wineItem->state & (TVIS_SELECTED | TVIS_DROPHILITED) ) {
725 oldBkMode = SetBkMode (hdc, OPAQUE);
726 oldBkColor = SetBkColor (hdc, GetSysColor( COLOR_HIGHLIGHT));
727 oldTextColor = SetTextColor(hdc, GetSysColor( COLOR_HIGHLIGHTTEXT));
731 oldBkMode = SetBkMode(hdc, TRANSPARENT);
732 oldTextColor = SetTextColor(hdc, GetSysColor( COLOR_WINDOWTEXT));
735 if (wineItem->pszText== LPSTR_TEXTCALLBACKA) {
736 TRACE (treeview,"LPSTR_TEXTCALLBACK\n");
737 TREEVIEW_SendDispInfoNotify (hwnd, wineItem, TVN_GETDISPINFO, TVIF_TEXT);
744 lstrlenA(wineItem->pszText),
746 uTextJustify | DT_VCENTER | DT_SINGLELINE );
748 /* Obtain the text coordinate */
752 lstrlenA(wineItem->pszText),
754 uTextJustify | DT_VCENTER | DT_SINGLELINE | DT_CALCRECT);
756 /* Restore the hdc state */
757 SetTextColor( hdc, oldTextColor);
759 if (oldBkMode != TRANSPARENT)
760 SetBkMode(hdc, oldBkMode);
761 if (wineItem->state & (TVIS_SELECTED | TVIS_DROPHILITED))
762 SetBkColor (hdc, oldBkColor);
764 /* Draw the box arround the selected item */
765 if (wineItem->state & TVIS_SELECTED )
767 HPEN hnewPen = CreatePen(PS_DOT, 0, GetSysColor(COLOR_WINDOWTEXT) );
768 HPEN hOldPen = SelectObject( hdc, hnewPen );
770 { wineItem->text.left-1, wineItem->text.top+1 },
771 { wineItem->text.right, wineItem->text.top+1 },
772 { wineItem->text.right, wineItem->text.bottom },
773 { wineItem->text.left-1, wineItem->text.bottom }
776 Polyline (hdc,points,4);
778 DeleteObject(hnewPen);
779 SelectObject(hdc, hOldPen);
783 if (cditem & CDRF_NOTIFYPOSTPAINT)
784 TREEVIEW_SendCustomDrawItemNotify (hwnd, hdc, wineItem, CDDS_ITEMPOSTPAINT);
786 SelectObject (hdc, hOldFont);
790 TREEVIEW_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
792 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
793 TREEVIEW_ITEM *wineItem;
795 LPRECT lpRect = (LPRECT)lParam;
797 TRACE (treeview,"\n");
799 * validate parameters
801 if ( (infoPtr==NULL) || (lpRect == NULL) )
804 if (infoPtr->Timer & TV_REFRESH_TIMER_SET)
805 TREEVIEW_Refresh (hwnd); /* we want a rect for the current view */
808 * retrive the item ptr
810 iItem = (HTREEITEM *) lParam;
811 wineItem = TREEVIEW_ValidItem (infoPtr, *iItem);
812 if ((!wineItem) || (!wineItem->visible))
816 * If wParam is TRUE return the text size otherwise return
817 * the whole item size
820 lpRect->left = wineItem->text.left;
821 lpRect->right = wineItem->text.right;
822 lpRect->bottom = wineItem->text.bottom;
823 lpRect->top = wineItem->text.top;
825 lpRect->left = wineItem->rect.left;
826 lpRect->right = wineItem->rect.right;
827 lpRect->bottom = wineItem->rect.bottom;
828 lpRect->top = wineItem->rect.top;
831 TRACE (treeview,"[L:%d R:%d T:%d B:%d]\n",
832 lpRect->left,lpRect->right,
833 lpRect->top,lpRect->bottom);
839 TREEVIEW_GetVisibleCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
842 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
844 return (LRESULT) infoPtr->uVisibleHeight / infoPtr->uRealItemHeight;
850 TREEVIEW_SetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
852 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
853 TREEVIEW_ITEM *wineItem;
857 tvItem=(LPTVITEMEXA) lParam;
858 iItem=(INT)tvItem->hItem;
859 TRACE (treeview,"item %d,mask %x\n",iItem,tvItem->mask);
861 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
862 if (!wineItem) return FALSE;
864 if (tvItem->mask & TVIF_CHILDREN) {
865 wineItem->cChildren=tvItem->cChildren;
868 if (tvItem->mask & TVIF_IMAGE) {
869 wineItem->iImage=tvItem->iImage;
872 if (tvItem->mask & TVIF_INTEGRAL) {
873 wineItem->iIntegral=tvItem->iIntegral;
874 FIXME (treeview," TVIF_INTEGRAL not supported yet\n");
877 if (tvItem->mask & TVIF_PARAM) {
878 wineItem->lParam=tvItem->lParam;
881 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
882 wineItem->iSelectedImage=tvItem->iSelectedImage;
885 if (tvItem->mask & TVIF_STATE) {
886 wineItem->state=tvItem->state & tvItem->stateMask;
889 if (tvItem->mask & TVIF_TEXT) {
890 if (tvItem->pszText!=LPSTR_TEXTCALLBACKA) {
891 len=lstrlenA (tvItem->pszText);
892 if (len>wineItem->cchTextMax)
893 wineItem->pszText= COMCTL32_ReAlloc (wineItem->pszText, len+1);
894 lstrcpynA (wineItem->pszText, tvItem->pszText,len);
896 if (wineItem->cchTextMax) {
897 COMCTL32_Free (wineItem->pszText);
898 wineItem->cchTextMax=0;
900 wineItem->pszText=LPSTR_TEXTCALLBACKA;
912 TREEVIEW_Refresh (HWND hwnd)
915 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
920 INT iItem, indent, x, y, cx, height, itemHeight;
921 INT viewtop,viewbottom,viewleft,viewright;
922 TREEVIEW_ITEM *wineItem, *prevItem;
924 TRACE (treeview,"\n");
928 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
929 KillTimer (hwnd, TV_REFRESH_TIMER);
930 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
934 GetClientRect (hwnd, &rect);
935 if ((rect.left-rect.right ==0) || (rect.top-rect.bottom==0)) return;
937 infoPtr->cdmode=TREEVIEW_SendCustomDrawNotify
938 (hwnd, CDDS_PREPAINT, hdc, rect);
940 if (infoPtr->cdmode==CDRF_SKIPDEFAULT) {
941 ReleaseDC (hwnd, hdc);
945 infoPtr->uVisibleHeight= rect.bottom-rect.top;
946 infoPtr->uVisibleWidth= rect.right-rect.left;
949 viewbottom=infoPtr->cy + rect.bottom-rect.top;
950 viewleft=infoPtr->cx;
951 viewright=infoPtr->cx + rect.right-rect.left;
955 /* draw background */
957 hbrBk = GetSysColorBrush (COLOR_WINDOW);
958 FillRect(hdc, &rect, hbrBk);
961 iItem=(INT)infoPtr->TopRootItem;
962 infoPtr->firstVisible=0;
966 TRACE (treeview, "[%d %d %d %d]\n",viewtop,viewbottom,viewleft,viewright);
970 wineItem= & infoPtr->items[iItem];
971 wineItem->iLevel=indent;
973 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &itemHeight);
974 if (infoPtr->uItemHeight>itemHeight)
975 itemHeight=infoPtr->uItemHeight;
977 GetTextMetricsA (hdc, &tm);
978 if ((tm.tmHeight + tm.tmExternalLeading) > itemHeight)
979 itemHeight=tm.tmHeight + tm.tmExternalLeading;
981 infoPtr->uRealItemHeight=itemHeight;
984 /* FIXME: remove this in later stage */
986 if (wineItem->pszText!=LPSTR_TEXTCALLBACK32A)
987 TRACE (treeview, "%d %d [%d %d %d %d] (%s)\n",y,x,
988 wineItem->rect.top, wineItem->rect.bottom,
989 wineItem->rect.left, wineItem->rect.right,
992 TRACE (treeview, "%d [%d %d %d %d] (CALLBACK)\n",
994 wineItem->rect.top, wineItem->rect.bottom,
995 wineItem->rect.left, wineItem->rect.right);
998 height=itemHeight * wineItem->iIntegral +1;
999 if ((y >= viewtop) && (y <= viewbottom) &&
1000 (x >= viewleft ) && (x <= viewright)) {
1001 wineItem->visible = TRUE;
1002 wineItem->rect.top = y - infoPtr->cy + rect.top;
1003 wineItem->rect.bottom = wineItem->rect.top + height ;
1004 wineItem->rect.left = x - infoPtr->cx + rect.left;
1005 wineItem->rect.right = rect.right;
1006 if (!infoPtr->firstVisible)
1007 infoPtr->firstVisible=wineItem->hItem;
1008 TREEVIEW_DrawItem (hwnd, hdc, wineItem);
1011 wineItem->visible = FALSE;
1012 wineItem->rect.left = wineItem->rect.top = 0;
1013 wineItem->rect.right= wineItem->rect.bottom = 0;
1014 wineItem->text.left = wineItem->text.top = 0;
1015 wineItem->text.right= wineItem->text.bottom = 0;
1018 /* look up next item */
1020 if ((wineItem->firstChild) && (wineItem->state & TVIS_EXPANDED)) {
1021 iItem=(INT)wineItem->firstChild;
1023 x+=infoPtr->uIndent;
1024 if (x>infoPtr->uTotalWidth)
1025 infoPtr->uTotalWidth=x;
1028 iItem=(INT)wineItem->sibling;
1029 while ((!iItem) && (indent>0)) {
1031 x-=infoPtr->uIndent;
1033 wineItem=&infoPtr->items[(INT)wineItem->parent];
1034 iItem=(INT)wineItem->sibling;
1040 /* FIXME: infoPtr->uTotalWidth should also take item label into account */
1041 /* FIXME: or should query item sizes (ie check CDRF_NEWFONT) */
1043 infoPtr->uTotalHeight=y;
1044 if (y >= (viewbottom-viewtop)) {
1045 if (!(infoPtr->uInternalStatus & TV_VSCROLL))
1046 ShowScrollBar (hwnd, SB_VERT, TRUE);
1047 infoPtr->uInternalStatus |=TV_VSCROLL;
1048 SetScrollRange (hwnd, SB_VERT, 0,
1049 y - infoPtr->uVisibleHeight, FALSE);
1050 SetScrollPos (hwnd, SB_VERT, infoPtr->cy, TRUE);
1053 if (infoPtr->uInternalStatus & TV_VSCROLL)
1054 ShowScrollBar (hwnd, SB_VERT, FALSE);
1055 infoPtr->uInternalStatus &= ~TV_VSCROLL;
1059 if (infoPtr->cdmode & CDRF_NOTIFYPOSTPAINT)
1060 infoPtr->cdmode=TREEVIEW_SendCustomDrawNotify
1061 (hwnd, CDDS_POSTPAINT, hdc, rect);
1063 ReleaseDC (hwnd, hdc);
1064 TRACE (treeview,"done\n");
1069 TREEVIEW_HandleTimer (HWND hwnd, WPARAM wParam, LPARAM lParam)
1071 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1073 TRACE (treeview, " %d\n",wParam);
1074 if (!infoPtr) return FALSE;
1077 case TV_REFRESH_TIMER:
1078 KillTimer (hwnd, TV_REFRESH_TIMER);
1079 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
1080 InvalidateRect(hwnd, NULL, FALSE);
1083 KillTimer (hwnd, TV_EDIT_TIMER);
1084 infoPtr->Timer &= ~TV_EDIT_TIMER_SET;
1087 ERR (treeview,"got unknown timer\n");
1095 TREEVIEW_QueueRefresh (HWND hwnd)
1098 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1100 TRACE (treeview,"\n");
1101 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
1102 KillTimer (hwnd, TV_REFRESH_TIMER);
1105 SetTimer (hwnd, TV_REFRESH_TIMER, TV_REFRESH_DELAY, 0);
1106 infoPtr->Timer|=TV_REFRESH_TIMER_SET;
1112 TREEVIEW_GetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1114 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1116 TREEVIEW_ITEM *wineItem;
1119 tvItem=(LPTVITEMEXA) lParam;
1120 iItem=(INT)tvItem->hItem;
1122 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1123 if (!wineItem) return FALSE;
1125 if (tvItem->mask & TVIF_CHILDREN) {
1126 if (TVIF_CHILDREN==I_CHILDRENCALLBACK)
1127 FIXME (treeview,"I_CHILDRENCALLBACK not supported\n");
1128 tvItem->cChildren=wineItem->cChildren;
1131 if (tvItem->mask & TVIF_HANDLE) {
1132 tvItem->hItem=wineItem->hItem;
1135 if (tvItem->mask & TVIF_IMAGE) {
1136 tvItem->iImage=wineItem->iImage;
1139 if (tvItem->mask & TVIF_INTEGRAL) {
1140 tvItem->iIntegral=wineItem->iIntegral;
1141 FIXME (treeview," TVIF_INTEGRAL not supported yet\n");
1144 if (tvItem->mask & TVIF_PARAM) {
1145 tvItem->lParam=wineItem->lParam;
1148 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
1149 tvItem->iSelectedImage=wineItem->iSelectedImage;
1152 if (tvItem->mask & TVIF_STATE) {
1153 tvItem->state=wineItem->state & tvItem->stateMask;
1156 if (tvItem->mask & TVIF_TEXT) {
1157 if (wineItem->pszText == LPSTR_TEXTCALLBACKA) {
1158 tvItem->pszText = LPSTR_TEXTCALLBACKA; /* FIXME:send notification? */
1159 ERR (treeview," GetItem called with LPSTR_TEXTCALLBACK\n");
1161 else if (wineItem->pszText) {
1162 lstrcpynA (tvItem->pszText, wineItem->pszText, tvItem->cchTextMax);
1166 TRACE(treeview,"item %d<%p>, txt %p, img %p, action %x\n",
1178 /* FIXME: check implementation of TVGN_NEXT/TVGN_NEXTVISIBLE */
1181 TREEVIEW_GetNextItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
1184 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1185 TREEVIEW_ITEM *wineItem, *returnItem;
1186 INT iItem, retval, flag;
1189 if (!infoPtr) return FALSE;
1190 flag = (INT) wParam;
1191 iItem = (INT) lParam;
1194 case TVGN_ROOT: retval=(INT)infoPtr->TopRootItem;
1196 case TVGN_CARET:retval=(INT)infoPtr->selectedItem;
1198 case TVGN_FIRSTVISIBLE:
1199 TREEVIEW_Refresh (hwnd);
1200 /* FIXME:we should only recalculate, not redraw */
1201 retval=(INT)infoPtr->firstVisible;
1203 case TVGN_DROPHILITE:
1204 retval=(INT)infoPtr->dropItem;
1208 TRACE (treeview,"flags:%x, returns %u\n", flag, retval);
1212 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1214 if (!wineItem) return FALSE;
1217 case TVGN_NEXT: retval=(INT)wineItem->sibling;
1220 retval=(INT)wineItem->upsibling;
1223 retval=(INT)wineItem->parent;
1226 retval=(INT)wineItem->firstChild;
1228 case TVGN_LASTVISIBLE:
1229 returnItem=TREEVIEW_GetLastListItem (infoPtr,wineItem);
1231 case TVGN_NEXTVISIBLE:
1232 returnItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
1234 case TVGN_PREVIOUSVISIBLE:
1235 returnItem=TREEVIEW_GetPrevListItem (infoPtr, wineItem);
1237 default: FIXME (treeview,"Unknown msg %x,item %x\n", flag,iItem);
1242 TRACE (treeview,"flags:%x, item %d;returns %d\n", flag, iItem,
1243 (INT)returnItem->hItem);
1244 return (INT)returnItem->hItem;
1247 TRACE (treeview,"flags:%x, item %d;returns %d\n", flag, iItem,retval);
1253 TREEVIEW_GetCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
1255 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1257 TRACE (treeview," %d\n",infoPtr->uNumItems);
1258 return (LRESULT) infoPtr->uNumItems;
1261 /***************************************************************************
1262 * This method does the chaining of the insertion of a treeview item
1265 static void TREEVIEW_InsertBefore(
1266 TREEVIEW_INFO *infoPtr,
1267 TREEVIEW_ITEM *newItem,
1268 TREEVIEW_ITEM *sibling,
1269 TREEVIEW_ITEM *parent)
1271 HTREEITEM siblingHandle = 0;
1272 HTREEITEM upSiblingHandle = 0;
1273 TREEVIEW_ITEM *upSibling = NULL;
1275 if (newItem == NULL)
1276 ERR(treeview, "NULL newItem, impossible condition\n");
1279 ERR(treeview, "NULL parent, impossible condition\n");
1281 if (sibling != NULL) /* Insert before this sibling for this parent */
1283 /* Store the new item sibling up sibling and sibling tem handle */
1284 siblingHandle = sibling->hItem;
1285 upSiblingHandle = sibling->upsibling;
1286 /* As well as a pointer to the upsibling sibling object */
1287 if ( (INT)sibling->upsibling != 0 )
1288 upSibling = &infoPtr->items[(INT)sibling->upsibling];
1290 /* Adjust the sibling pointer */
1291 sibling->upsibling = newItem->hItem;
1293 /* Adjust the new item pointers */
1294 newItem->upsibling = upSiblingHandle;
1295 newItem->sibling = siblingHandle;
1297 /* Adjust the up sibling pointer */
1298 if ( upSibling != NULL )
1299 upSibling->sibling = newItem->hItem;
1301 /* this item is the first child of this parent, adjust parent pointers */
1302 parent->firstChild = newItem->hItem;
1304 else /* Insert as first child of this parent */
1305 parent->firstChild = newItem->hItem;
1308 /***************************************************************************
1309 * This method does the chaining of the insertion of a treeview item
1312 static void TREEVIEW_InsertAfter(
1313 TREEVIEW_INFO *infoPtr,
1314 TREEVIEW_ITEM *newItem,
1315 TREEVIEW_ITEM *upSibling,
1316 TREEVIEW_ITEM *parent)
1318 HTREEITEM upSiblingHandle = 0;
1319 HTREEITEM siblingHandle = 0;
1320 TREEVIEW_ITEM *sibling = NULL;
1322 if (newItem == NULL)
1323 ERR(treeview, "NULL newItem, impossible condition\n");
1326 ERR(treeview, "NULL parent, impossible condition\n");
1328 if (upSibling != NULL) /* Insert after this upsibling for this parent */
1330 /* Store the new item up sibling and sibling item handle */
1331 upSiblingHandle = upSibling->hItem;
1332 siblingHandle = upSibling->sibling;
1333 /* As well as a pointer to the upsibling sibling object */
1334 if ( (INT)upSibling->sibling != 0 )
1335 sibling = &infoPtr->items[(INT)upSibling->sibling];
1337 /* Adjust the up sibling pointer */
1338 upSibling->sibling = newItem->hItem;
1340 /* Adjust the new item pointers */
1341 newItem->upsibling = upSiblingHandle;
1342 newItem->sibling = siblingHandle;
1344 /* Adjust the sibling pointer */
1345 if ( sibling != NULL )
1346 sibling->upsibling = newItem->hItem;
1349 newItem is the last of the level, nothing else to do
1352 else /* Insert as first child of this parent */
1353 parent->firstChild = newItem->hItem;
1356 /***************************************************************************
1357 * Forward the DPA local callback to the treeview owner callback
1359 static INT WINAPI TREEVIEW_CallBackCompare(
1364 /* Forward the call to the client define callback */
1365 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr((HWND)tvInfoPtr);
1366 return (infoPtr->pCallBackSort->lpfnCompare)(
1367 ((TREEVIEW_ITEM*)first)->lParam,
1368 ((TREEVIEW_ITEM*)second)->lParam,
1369 infoPtr->pCallBackSort->lParam);
1372 /***************************************************************************
1373 * Setup the treeview structure with regards of the sort method
1374 * and sort the children of the TV item specified in lParam
1376 LRESULT WINAPI TREEVIEW_SortChildrenCB(
1381 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1382 TREEVIEW_ITEM *sortMe = NULL; /* Node for which we sort the children */
1384 /* Obtain the TVSORTBC struct */
1385 infoPtr->pCallBackSort = (LPTVSORTCB)lParam;
1387 /* Obtain the parent node to sort */
1388 sortMe = &infoPtr->items[ (INT)infoPtr->pCallBackSort->hParent ];
1390 /* Make sure there is something to sort */
1391 if ( sortMe->cChildren > 1 )
1393 /* pointer organization */
1394 HDPA sortList = DPA_Create(sortMe->cChildren);
1395 HTREEITEM itemHandle = sortMe->firstChild;
1396 TREEVIEW_ITEM *itemPtr = & infoPtr->items[ (INT)itemHandle ];
1398 /* TREEVIEW_ITEM rechaining */
1404 /* Build the list of item to sort */
1408 sortList, /* the list */
1409 sortMe->cChildren+1, /* force the insertion to be an append */
1410 itemPtr); /* the ptr to store */
1412 /* Get the next sibling */
1413 itemHandle = itemPtr->sibling;
1414 itemPtr = & infoPtr->items[ (INT)itemHandle ];
1415 } while ( itemHandle != NULL );
1417 /* let DPA perform the sort activity */
1419 sortList, /* what */
1420 TREEVIEW_CallBackCompare, /* how */
1424 * Reorganized TREEVIEW_ITEM structures.
1425 * Note that we know we have at least two elements.
1428 /* Get the first item and get ready to start... */
1429 item = DPA_GetPtr(sortList, count++);
1430 while ( (nextItem = DPA_GetPtr(sortList, count++)) != NULL )
1432 /* link the two current item toghether */
1433 ((TREEVIEW_ITEM*)item)->sibling = ((TREEVIEW_ITEM*)nextItem)->hItem;
1434 ((TREEVIEW_ITEM*)nextItem)->upsibling = ((TREEVIEW_ITEM*)item)->hItem;
1436 if (prevItem == NULL) /* this is the first item, update the parent */
1438 sortMe->firstChild = ((TREEVIEW_ITEM*)item)->hItem;
1439 ((TREEVIEW_ITEM*)item)->upsibling = NULL;
1441 else /* fix the back chaining */
1443 ((TREEVIEW_ITEM*)item)->upsibling = ((TREEVIEW_ITEM*)prevItem)->hItem;
1446 /* get ready for the next one */
1451 /* the last item is pointed to by item and never has a sibling */
1452 ((TREEVIEW_ITEM*)item)->sibling = NULL;
1454 DPA_Destroy(sortList);
1462 /* the method used below isn't the most memory-friendly, but it avoids
1463 a lot of memory reallocations */
1465 /* BTW: we waste handle 0; 0 is not an allowed handle. */
1468 TREEVIEW_InsertItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1471 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1472 TVINSERTSTRUCTA *ptdi;
1474 TREEVIEW_ITEM *wineItem, *parentItem, *prevsib, *sibItem;
1475 INT iItem,listItems,i,len;
1477 /* Item to insert */
1478 ptdi = (LPTVINSERTSTRUCTA) lParam;
1480 /* check if memory is available */
1482 if (infoPtr->uNumPtrsAlloced==0) {
1483 infoPtr->items = COMCTL32_Alloc (TVITEM_ALLOC*sizeof (TREEVIEW_ITEM));
1484 infoPtr->freeList= COMCTL32_Alloc ((1+(TVITEM_ALLOC>>5)) * sizeof (INT));
1485 infoPtr->uNumPtrsAlloced=TVITEM_ALLOC;
1486 infoPtr->TopRootItem=(HTREEITEM)1;
1490 * Reallocate contiguous space for items
1492 if (infoPtr->uNumItems == (infoPtr->uNumPtrsAlloced-1) ) {
1493 TREEVIEW_ITEM *oldItems = infoPtr->items;
1494 INT *oldfreeList = infoPtr->freeList;
1496 infoPtr->uNumPtrsAlloced*=2;
1497 infoPtr->items = COMCTL32_Alloc (infoPtr->uNumPtrsAlloced*sizeof (TREEVIEW_ITEM));
1498 infoPtr->freeList= COMCTL32_Alloc ((1+(infoPtr->uNumPtrsAlloced>>5))*sizeof (INT));
1500 memcpy (&infoPtr->items[0], &oldItems[0],
1501 infoPtr->uNumPtrsAlloced/2 * sizeof(TREEVIEW_ITEM));
1502 memcpy (&infoPtr->freeList[0], &oldfreeList[0],
1503 infoPtr->uNumPtrsAlloced>>6 * sizeof(INT));
1505 COMCTL32_Free (oldItems);
1506 COMCTL32_Free (oldfreeList);
1510 * Reset infoPtr structure with new stat according to current TV picture
1513 infoPtr->uNumItems++;
1514 if ((INT)infoPtr->uMaxHandle==(infoPtr->uNumItems-1)) {
1515 iItem=infoPtr->uNumItems;
1516 infoPtr->uMaxHandle = (HTREEITEM)((INT)infoPtr->uMaxHandle + 1);
1517 } else { /* check freelist */
1518 for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++) {
1519 if (infoPtr->freeList[i]) {
1520 iItem=ffs (infoPtr->freeList[i])-1;
1521 tv_clear_bit(iItem,&infoPtr->freeList[i]);
1528 if (TRACE_ON(treeview)) {
1529 for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++)
1530 TRACE (treeview,"%8x\n",infoPtr->freeList[i]);
1533 if (!iItem) ERR (treeview, "Argh -- can't find free item.\n");
1536 * Find the parent item of the new item
1538 tvItem= & ptdi->DUMMYUNIONNAME.itemex;
1539 wineItem=& infoPtr->items[iItem];
1541 if ((ptdi->hParent==TVI_ROOT) || (ptdi->hParent==0)) {
1543 wineItem->parent = 0;
1544 sibItem = &infoPtr->items [(INT)infoPtr->TopRootItem];
1545 listItems = infoPtr->uNumItems;
1548 parentItem = &infoPtr->items[(INT)ptdi->hParent];
1550 /* Do the insertion here it if it's the only item of this parent */
1551 if (!parentItem->firstChild)
1552 parentItem->firstChild=(HTREEITEM)iItem;
1554 wineItem->parent = ptdi->hParent;
1555 sibItem = &infoPtr->items [(INT)parentItem->firstChild];
1556 parentItem->cChildren++;
1557 listItems = parentItem->cChildren;
1561 /* NOTE: I am moving some setup of the wineItem object that was initialy
1562 * done at the end of the function since some of the values are
1563 * required by the Callback sorting
1566 if (tvItem->mask & TVIF_TEXT)
1569 * Setup the item text stuff here since it's required by the Sort method
1570 * when the insertion are ordered
1572 if (tvItem->pszText!=LPSTR_TEXTCALLBACKA)
1574 TRACE (treeview,"(%p,%s)\n", &tvItem->pszText, tvItem->pszText);
1575 len = lstrlenA (tvItem->pszText)+1;
1576 wineItem->pszText= COMCTL32_Alloc (len+1);
1577 lstrcpyA (wineItem->pszText, tvItem->pszText);
1578 wineItem->cchTextMax=len;
1582 TRACE (treeview,"LPSTR_TEXTCALLBACK\n");
1583 wineItem->pszText = LPSTR_TEXTCALLBACKA;
1584 wineItem->cchTextMax = 0;
1588 if (tvItem->mask & TVIF_PARAM)
1589 wineItem->lParam=tvItem->lParam;
1592 wineItem->upsibling=0; /* needed in case we're the first item in a list */
1593 wineItem->sibling=0;
1594 wineItem->firstChild=0;
1595 wineItem->hItem=(HTREEITEM)iItem;
1600 switch ((INT)ptdi->hInsertAfter) {
1602 if (wineItem->parent) {
1603 wineItem->sibling=parentItem->firstChild;
1604 parentItem->firstChild=(HTREEITEM)iItem;
1606 wineItem->sibling=infoPtr->TopRootItem;
1607 infoPtr->TopRootItem=(HTREEITEM)iItem;
1609 sibItem->upsibling=(HTREEITEM)iItem;
1613 if (sibItem==wineItem)
1615 * This item is the first child of the level and it
1616 * has already been inserted
1621 TREEVIEW_ITEM *aChild =
1622 &infoPtr->items[(INT)parentItem->firstChild];
1624 TREEVIEW_ITEM *previousChild = NULL;
1625 BOOL bItemInserted = FALSE;
1627 /* Iterate the parent children to see where we fit in */
1628 while ( aChild != NULL )
1630 INT comp = strcmp(wineItem->pszText, aChild->pszText);
1631 if ( comp < 0 ) /* we are smaller than the current one */
1633 TREEVIEW_InsertBefore(infoPtr, wineItem, aChild, parentItem);
1634 bItemInserted = TRUE;
1637 else if ( comp > 0 ) /* we are bigger than the current one */
1639 previousChild = aChild;
1640 aChild = (aChild->sibling == 0) /* This will help us to exit */
1641 ? NULL /* if there is no more sibling */
1642 : &infoPtr->items[(INT)aChild->sibling];
1644 /* Look at the next item */
1647 else if ( comp == 0 )
1650 * An item with this name is already existing, therefore,
1651 * we add after the one we found
1653 TREEVIEW_InsertAfter(infoPtr, wineItem, aChild, parentItem);
1654 bItemInserted = TRUE;
1660 * we reach the end of the child list and the item as not
1661 * yet been inserted, therefore, insert it after the last child.
1663 if ( (! bItemInserted ) && (aChild == NULL) )
1664 TREEVIEW_InsertAfter(infoPtr, wineItem, previousChild, parentItem);
1671 if (sibItem==wineItem) break;
1672 while (sibItem->sibling) {
1674 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1676 sibItem->sibling=(HTREEITEM)iItem;
1677 wineItem->upsibling=sibItem->hItem;
1680 while ((sibItem->sibling) && (sibItem->hItem!=ptdi->hInsertAfter))
1683 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1685 if (sibItem->hItem!=ptdi->hInsertAfter) {
1686 ERR (treeview, "tried to insert item after nonexisting handle.\n");
1690 if (sibItem->sibling) {
1691 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1692 sibItem->upsibling=(HTREEITEM)iItem;
1693 wineItem->sibling=sibItem->hItem;
1695 prevsib->sibling=(HTREEITEM)iItem;
1696 wineItem->upsibling=prevsib->hItem;
1702 /* Fill in info structure */
1704 TRACE (treeview,"new item %d; parent %d, mask %x\n", iItem,
1705 (INT)wineItem->parent,tvItem->mask);
1707 wineItem->mask=tvItem->mask;
1708 wineItem->iIntegral=1;
1710 if (tvItem->mask & TVIF_CHILDREN) {
1711 wineItem->cChildren=tvItem->cChildren;
1712 if (tvItem->cChildren==I_CHILDRENCALLBACK)
1713 FIXME (treeview," I_CHILDRENCALLBACK not supported\n");
1716 wineItem->expandBox.left = 0; /* Initialize the expandBox */
1717 wineItem->expandBox.top = 0;
1718 wineItem->expandBox.right = 0;
1719 wineItem->expandBox.bottom = 0;
1721 if (tvItem->mask & TVIF_IMAGE)
1722 wineItem->iImage=tvItem->iImage;
1724 /* If the application sets TVIF_INTEGRAL without
1725 supplying a TVITEMEX structure, it's toast */
1727 if (tvItem->mask & TVIF_INTEGRAL)
1728 wineItem->iIntegral=tvItem->iIntegral;
1730 if (tvItem->mask & TVIF_SELECTEDIMAGE)
1731 wineItem->iSelectedImage=tvItem->iSelectedImage;
1733 if (tvItem->mask & TVIF_STATE) {
1734 TRACE(treeview, "Changing item state from %d to %d\n",
1737 wineItem->state=tvItem->state;
1738 wineItem->stateMask=tvItem->stateMask;
1742 TREEVIEW_QueueRefresh (hwnd);
1744 return (LRESULT) iItem;
1752 TREEVIEW_DeleteItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
1754 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1756 TREEVIEW_ITEM *wineItem;
1758 TRACE (treeview,"\n");
1759 if (!infoPtr) return FALSE;
1761 if (lParam == (INT)TVI_ROOT) {
1762 TREEVIEW_RemoveTree (hwnd);
1764 iItem= (INT) lParam;
1765 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1766 if (!wineItem) return FALSE;
1767 TRACE (treeview,"%s\n",wineItem->pszText);
1768 TREEVIEW_RemoveItem (hwnd, wineItem);
1771 TREEVIEW_QueueRefresh (hwnd);
1779 TREEVIEW_GetIndent (HWND hwnd)
1781 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1783 TRACE (treeview,"\n");
1784 return infoPtr->uIndent;
1788 TREEVIEW_SetIndent (HWND hwnd, WPARAM wParam)
1790 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1793 TRACE (treeview,"\n");
1794 newIndent=(INT) wParam;
1795 if (newIndent < MINIMUM_INDENT) newIndent=MINIMUM_INDENT;
1796 infoPtr->uIndent=newIndent;
1802 TREEVIEW_GetToolTips (HWND hwnd)
1805 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1807 TRACE (treeview,"\n");
1808 return infoPtr->hwndToolTip;
1813 TREEVIEW_SetToolTips (HWND hwnd, WPARAM wParam)
1816 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1819 TRACE (treeview,"\n");
1820 prevToolTip=infoPtr->hwndToolTip;
1821 infoPtr->hwndToolTip= (HWND) wParam;
1828 TREEVIEW_GetEditControl (HWND hwnd)
1831 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1833 return infoPtr->hwndEdit;
1837 TREEVIEW_Edit_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam,
1845 HDC hdc = (HDC) wParam;
1846 GetClientRect (hwnd, &rc);
1847 Rectangle (hdc, rc.left, rc.top, rc.right, rc.bottom);
1853 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
1858 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd));
1859 return CallWindowProcA( infoPtr->wpEditOrig, hwnd, uMsg, wParam, lParam);
1867 /* should handle edit control messages here */
1870 TREEVIEW_Command (HWND hwnd, WPARAM wParam, LPARAM lParam)
1873 TRACE (treeview, "%x %ld\n",wParam, lParam);
1875 switch (HIWORD(wParam))
1880 * Adjust the edit window size
1882 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1883 TREEVIEW_ITEM *editItem = TREEVIEW_ValidItem(infoPtr, infoPtr->editItem);
1884 INT iLength = GetWindowTextLengthA(infoPtr->hwndEdit);
1885 HDC hdc = GetDC(infoPtr->hwndEdit);
1888 if ( GetTextMetricsA(hdc, &tm) )
1890 LONG newWidth = (iLength * tm.tmAveCharWidth) + 15;
1895 editItem->text.left - 2,
1896 editItem->text.top - 1,
1898 editItem->text.bottom - editItem->text.top + 3,
1901 ReleaseDC(hwnd, hdc);
1907 /* TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
1912 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
1919 TREEVIEW_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
1922 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1924 if (infoPtr->bAutoSize)
1926 infoPtr->bAutoSize = FALSE;
1929 infoPtr->bAutoSize = TRUE;
1931 if (wParam == SIZE_RESTORED)
1933 infoPtr->uTotalWidth = LOWORD (lParam);
1934 infoPtr->uTotalHeight = HIWORD (lParam);
1936 FIXME (treeview,"WM_SIZE flag %x %lx not handled\n", wParam, lParam);
1939 TREEVIEW_QueueRefresh (hwnd);
1946 TREEVIEW_StyleChanged (HWND hwnd, WPARAM wParam, LPARAM lParam)
1948 LPSTYLESTRUCT lpss=(LPSTYLESTRUCT) lParam;
1950 TRACE (treeview,"(%x %lx)\n",wParam,lParam);
1952 if (wParam & (GWL_STYLE))
1953 SetWindowLongA( hwnd, GWL_STYLE, lpss->styleNew);
1954 if (wParam & (GWL_EXSTYLE))
1955 SetWindowLongA( hwnd, GWL_STYLE, lpss->styleNew);
1961 TREEVIEW_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
1963 TREEVIEW_INFO *infoPtr;
1968 TRACE (treeview,"wnd %x\n",hwnd);
1969 /* allocate memory for info structure */
1970 infoPtr = (TREEVIEW_INFO *) COMCTL32_Alloc (sizeof(TREEVIEW_INFO));
1972 SetWindowLongA( hwnd, 0, (DWORD)infoPtr);
1974 if (infoPtr == NULL) {
1975 ERR (treeview, "could not allocate info memory!\n");
1979 if ((TREEVIEW_INFO*) GetWindowLongA( hwnd, 0) != infoPtr) {
1980 ERR (treeview, "pointer assignment error!\n");
1986 /* set default settings */
1987 infoPtr->uInternalStatus=0;
1988 infoPtr->uNumItems=0;
1989 infoPtr->clrBk = GetSysColor (COLOR_WINDOW);
1990 infoPtr->clrText = GetSysColor (COLOR_BTNTEXT);
1993 infoPtr->uIndent = 15;
1994 infoPtr->himlNormal = NULL;
1995 infoPtr->himlState = NULL;
1996 infoPtr->uItemHeight = -1;
1997 GetTextMetricsA (hdc, &tm);
1998 infoPtr->hFont = GetStockObject (DEFAULT_GUI_FONT);
1999 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
2000 logFont.lfWeight=FW_BOLD;
2001 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
2003 infoPtr->items = NULL;
2004 infoPtr->selectedItem=0;
2005 infoPtr->clrText=-1; /* use system color */
2006 infoPtr->dropItem=0;
2007 infoPtr->pCallBackSort=NULL;
2010 infoPtr->hwndNotify = GetParent32 (hwnd);
2011 infoPtr->bTransparent = ( GetWindowLongA( hwnd, GWL_STYLE) & TBSTYLE_FLAT);
2014 infoPtr->hwndToolTip=0;
2015 if (!( GetWindowLongA( hwnd, GWL_STYLE) & TVS_NOTOOLTIPS)) { /* Create tooltip control */
2018 infoPtr->hwndToolTip =
2019 CreateWindowExA (0, TOOLTIPS_CLASSA, NULL, 0,
2020 CW_USEDEFAULT, CW_USEDEFAULT,
2021 CW_USEDEFAULT, CW_USEDEFAULT,
2024 /* Send NM_TOOLTIPSCREATED notification */
2025 if (infoPtr->hwndToolTip) {
2026 NMTOOLTIPSCREATED nmttc;
2028 nmttc.hdr.hwndFrom = hwnd;
2029 nmttc.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2030 nmttc.hdr.code = NM_TOOLTIPSCREATED;
2031 nmttc.hwndToolTips = infoPtr->hwndToolTip;
2033 SendMessageA (GetParent (hwnd), WM_NOTIFY,
2034 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmttc);
2037 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
2038 ti.cbSize = sizeof(TTTOOLINFOA);
2039 ti.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_TRANSPARENT ;
2042 ti.lpszText = "Test"; /* LPSTR_TEXTCALLBACK; */
2043 SetRectEmpty (&ti.rect);
2045 SendMessageA (infoPtr->hwndToolTip, TTM_ADDTOOLA, 0, (LPARAM)&ti);
2048 infoPtr->hwndEdit = CreateWindowExA (
2052 WS_CHILD | WS_BORDER | ES_AUTOHSCROLL |
2053 ES_WANTRETURN | ES_LEFT,
2056 0,0,0); /* FIXME: (HMENU)IDTVEDIT,pcs->hInstance,0);*/
2058 SendMessageA ( infoPtr->hwndEdit, WM_SETFONT, infoPtr->hFont, FALSE);
2059 infoPtr->wpEditOrig = (WNDPROC)SetWindowLongA (
2062 (LONG) TREEVIEW_Edit_SubclassProc);
2064 ReleaseDC (hwnd, hdc);
2071 TREEVIEW_Destroy (HWND hwnd)
2073 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2075 TRACE (treeview,"\n");
2076 TREEVIEW_RemoveTree (hwnd);
2077 if (infoPtr->Timer & TV_REFRESH_TIMER_SET)
2078 KillTimer (hwnd, TV_REFRESH_TIMER);
2079 if (infoPtr->hwndToolTip)
2080 DestroyWindow (infoPtr->hwndToolTip);
2082 COMCTL32_Free (infoPtr);
2088 TREEVIEW_Paint (HWND hwnd, WPARAM wParam, LPARAM lParam)
2093 TRACE (treeview,"\n");
2094 hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
2095 TREEVIEW_Refresh (hwnd);
2097 EndPaint (hwnd, &ps);
2098 TRACE (treeview,"done\n");
2100 return DefWindowProcA (hwnd, WM_PAINT, wParam, lParam);
2104 TREEVIEW_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2106 TREEVIEW_SendSimpleNotify (hwnd, NM_SETFOCUS);
2107 InvalidateRect(hwnd, NULL, FALSE);
2112 TREEVIEW_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2114 TREEVIEW_SendSimpleNotify (hwnd, NM_KILLFOCUS);
2115 InvalidateRect(hwnd, NULL, FALSE);
2120 TREEVIEW_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
2122 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2123 HBRUSH hBrush = CreateSolidBrush (infoPtr->clrBk);
2126 TRACE (treeview,"\n");
2127 GetClientRect (hwnd, &rect);
2128 FillRect ((HDC)wParam, &rect, hBrush);
2129 DeleteObject (hBrush);
2145 TREEVIEW_SendSimpleNotify (HWND hwnd, UINT code)
2149 TRACE (treeview, "%x\n",code);
2150 nmhdr.hwndFrom = hwnd;
2151 nmhdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2154 return (BOOL) SendMessageA (GetParent (hwnd), WM_NOTIFY,
2155 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
2161 TREEVIEW_SendTreeviewNotify (HWND hwnd, UINT code, UINT action,
2162 HTREEITEM oldItem, HTREEITEM newItem)
2165 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2167 TREEVIEW_ITEM *wineItem;
2169 TRACE (treeview,"code:%x action:%x olditem:%x newitem:%x\n",
2170 code,action,(INT)oldItem,(INT)newItem);
2171 nmhdr.hdr.hwndFrom = hwnd;
2172 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2173 nmhdr.hdr.code = code;
2174 nmhdr.action = action;
2176 wineItem=& infoPtr->items[(INT)oldItem];
2177 nmhdr.itemOld.mask = wineItem->mask;
2178 nmhdr.itemOld.hItem = wineItem->hItem;
2179 nmhdr.itemOld.state = wineItem->state;
2180 nmhdr.itemOld.stateMask = wineItem->stateMask;
2181 nmhdr.itemOld.iImage = wineItem->iImage;
2182 nmhdr.itemOld.pszText = wineItem->pszText;
2183 nmhdr.itemOld.cchTextMax= wineItem->cchTextMax;
2184 nmhdr.itemOld.iImage = wineItem->iImage;
2185 nmhdr.itemOld.iSelectedImage = wineItem->iSelectedImage;
2186 nmhdr.itemOld.cChildren = wineItem->cChildren;
2187 nmhdr.itemOld.lParam = wineItem->lParam;
2191 wineItem=& infoPtr->items[(INT)newItem];
2192 nmhdr.itemNew.mask = wineItem->mask;
2193 nmhdr.itemNew.hItem = wineItem->hItem;
2194 nmhdr.itemNew.state = wineItem->state;
2195 nmhdr.itemNew.stateMask = wineItem->stateMask;
2196 nmhdr.itemNew.iImage = wineItem->iImage;
2197 nmhdr.itemNew.pszText = wineItem->pszText;
2198 nmhdr.itemNew.cchTextMax= wineItem->cchTextMax;
2199 nmhdr.itemNew.iImage = wineItem->iImage;
2200 nmhdr.itemNew.iSelectedImage = wineItem->iSelectedImage;
2201 nmhdr.itemNew.cChildren = wineItem->cChildren;
2202 nmhdr.itemNew.lParam = wineItem->lParam;
2208 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2209 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2214 TREEVIEW_SendTreeviewDnDNotify (HWND hwnd, UINT code, HTREEITEM dragItem,
2217 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2219 TREEVIEW_ITEM *wineItem;
2221 TRACE (treeview,"code:%x dragitem:%x\n", code,(INT)dragItem);
2223 nmhdr.hdr.hwndFrom = hwnd;
2224 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2225 nmhdr.hdr.code = code;
2227 wineItem=& infoPtr->items[(INT)dragItem];
2228 nmhdr.itemNew.mask = wineItem->mask;
2229 nmhdr.itemNew.hItem = wineItem->hItem;
2230 nmhdr.itemNew.state = wineItem->state;
2231 nmhdr.itemNew.lParam = wineItem->lParam;
2233 nmhdr.ptDrag.x = pt.x;
2234 nmhdr.ptDrag.y = pt.y;
2236 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2237 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2244 TREEVIEW_SendDispInfoNotify (HWND hwnd, TREEVIEW_ITEM *wineItem,
2245 UINT code, UINT what)
2251 TRACE (treeview,"item %d, action %x, state %d\n",
2252 (INT)wineItem->hItem,
2254 (INT)wineItem->state);
2256 tvdi.hdr.hwndFrom = hwnd;
2257 tvdi.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2258 tvdi.hdr.code = code;
2259 tvdi.item.mask = what;
2260 tvdi.item.hItem = wineItem->hItem;
2261 tvdi.item.state = wineItem->state;
2262 tvdi.item.lParam = wineItem->lParam;
2263 tvdi.item.pszText = COMCTL32_Alloc (128*sizeof(char));
2264 buf = tvdi.item.pszText;
2266 retval=(BOOL)SendMessageA (
2269 (WPARAM)tvdi.hdr.idFrom,
2272 if (what & TVIF_TEXT) {
2273 wineItem->pszText = tvdi.item.pszText;
2274 if (buf==tvdi.item.pszText) {
2275 wineItem->cchTextMax = 128;
2277 TRACE (treeview,"user-supplied buffer\n");
2278 COMCTL32_Free (buf);
2279 wineItem->cchTextMax = 0;
2282 if (what & TVIF_SELECTEDIMAGE)
2283 wineItem->iSelectedImage = tvdi.item.iSelectedImage;
2284 if (what & TVIF_IMAGE)
2285 wineItem->iImage = tvdi.item.iImage;
2286 if (what & TVIF_CHILDREN)
2287 wineItem->cChildren = tvdi.item.cChildren;
2295 TREEVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
2298 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2299 NMTVCUSTOMDRAW nmcdhdr;
2300 LPNMCUSTOMDRAW nmcd;
2302 TRACE (treeview,"drawstage:%lx hdc:%x\n", dwDrawStage, hdc);
2304 nmcd= & nmcdhdr.nmcd;
2305 nmcd->hdr.hwndFrom = hwnd;
2306 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2307 nmcd->hdr.code = NM_CUSTOMDRAW;
2308 nmcd->dwDrawStage= dwDrawStage;
2310 nmcd->rc.left = rc.left;
2311 nmcd->rc.right = rc.right;
2312 nmcd->rc.bottom = rc.bottom;
2313 nmcd->rc.top = rc.top;
2314 nmcd->dwItemSpec = 0;
2315 nmcd->uItemState = 0;
2316 nmcd->lItemlParam= 0;
2317 nmcdhdr.clrText = infoPtr->clrText;
2318 nmcdhdr.clrTextBk= infoPtr->clrBk;
2321 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2322 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2328 /* FIXME: need to find out when the flags in uItemState need to be set */
2331 TREEVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
2332 TREEVIEW_ITEM *wineItem, UINT uItemDrawState)
2334 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2335 NMTVCUSTOMDRAW nmcdhdr;
2336 LPNMCUSTOMDRAW nmcd;
2337 DWORD dwDrawStage,dwItemSpec;
2340 dwDrawStage=CDDS_ITEM | uItemDrawState;
2341 dwItemSpec=(DWORD)wineItem->hItem;
2343 if (wineItem->hItem==infoPtr->selectedItem) uItemState|=CDIS_SELECTED;
2344 if (wineItem->hItem==infoPtr->focusItem) uItemState|=CDIS_FOCUS;
2345 if (wineItem->hItem==infoPtr->hotItem) uItemState|=CDIS_HOT;
2347 nmcd= & nmcdhdr.nmcd;
2348 nmcd->hdr.hwndFrom = hwnd;
2349 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2350 nmcd->hdr.code = NM_CUSTOMDRAW;
2351 nmcd->dwDrawStage= dwDrawStage;
2353 nmcd->rc.left = wineItem->rect.left;
2354 nmcd->rc.right = wineItem->rect.right;
2355 nmcd->rc.bottom = wineItem->rect.bottom;
2356 nmcd->rc.top = wineItem->rect.top;
2357 nmcd->dwItemSpec = dwItemSpec;
2358 nmcd->uItemState = uItemState;
2359 nmcd->lItemlParam= wineItem->lParam;
2361 nmcdhdr.clrText = infoPtr->clrText;
2362 nmcdhdr.clrTextBk= infoPtr->clrBk;
2363 nmcdhdr.iLevel = wineItem->iLevel;
2365 TRACE (treeview,"drawstage:%lx hdc:%x item:%lx, itemstate:%x\n",
2366 dwDrawStage, hdc, dwItemSpec, uItemState);
2368 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2369 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2374 /* Note:If the specified item is the child of a collapsed parent item,
2375 the parent's list of child items is (recursively) expanded to reveal the
2376 specified item. This is mentioned for TREEVIEW_SelectItem; don't
2377 know if it also applies here.
2381 TREEVIEW_Expand (HWND hwnd, WPARAM wParam, LPARAM lParam)
2383 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2384 TREEVIEW_ITEM *wineItem;
2388 flag = (UINT) wParam;
2389 expand = (INT) lParam;
2391 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2395 if (!wineItem->cChildren)
2398 TRACE (treeview,"For (%s) flags:%x item:%d state:%d\n",
2404 if (wineItem->cChildren==I_CHILDRENCALLBACK) {
2405 FIXME (treeview,"we don't handle I_CHILDRENCALLBACK yet\n");
2409 if (flag == TVE_TOGGLE) { /* FIXME: check exact behaviour here */
2410 flag &= ~TVE_TOGGLE; /* ie: bitwise ops or 'case' ops */
2411 if (wineItem->state & TVIS_EXPANDED)
2412 flag |= TVE_COLLAPSE;
2419 case TVE_COLLAPSERESET:
2420 TRACE(treeview, " case TVE_COLLAPSERESET\n");
2421 if (!wineItem->state & TVIS_EXPANDED)
2424 wineItem->state &= ~(TVIS_EXPANDEDONCE | TVIS_EXPANDED);
2425 TREEVIEW_RemoveAllChildren (hwnd, wineItem);
2429 TRACE(treeview, " case TVE_COLLAPSE\n");
2430 if (!wineItem->state & TVIS_EXPANDED)
2433 wineItem->state &= ~TVIS_EXPANDED;
2437 TRACE(treeview, " case TVE_EXPAND\n");
2438 if (wineItem->state & TVIS_EXPANDED)
2441 TRACE(treeview, " is not expanded...\n");
2443 if (!(wineItem->state & TVIS_EXPANDEDONCE))
2445 TRACE(treeview, " and has never been expanded...\n");
2446 wineItem->state |= TVIS_EXPANDED;
2448 /* this item has never been expanded */
2449 if (TREEVIEW_SendTreeviewNotify (
2456 TRACE(treeview, " TVN_ITEMEXPANDING returned TRUE, exiting...\n");
2461 * Since the TVN_ITEMEXPANDING message may has caused the parent to
2462 * insert new items which in turn may have cause items placeholder
2463 * reallocation, I reassign the current item pointer so we have
2464 * something valid to work with...
2465 * However, this should not be necessary,
2466 * investigation required in TREEVIEW_InsertItemA
2468 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2472 "Catastropic situation, cannot retreive item #%d\n",
2477 wineItem->state |= TVIS_EXPANDEDONCE;
2478 TRACE(treeview, " TVN_ITEMEXPANDING sent...\n");
2480 TREEVIEW_SendTreeviewNotify (
2487 TRACE(treeview, " TVN_ITEMEXPANDED sent...\n");
2492 /* this item has already been expanded */
2493 wineItem->state |= TVIS_EXPANDED;
2497 case TVE_EXPANDPARTIAL:
2498 TRACE(treeview, " case TVE_EXPANDPARTIAL\n");
2499 FIXME (treeview, "TVE_EXPANDPARTIAL not implemented\n");
2500 wineItem->state ^=TVIS_EXPANDED;
2501 wineItem->state |=TVIS_EXPANDEDONCE;
2505 TRACE(treeview, "Exiting, Item %d state is now %d...\n",
2509 TREEVIEW_QueueRefresh (hwnd);
2515 static TREEVIEW_ITEM *
2516 TREEVIEW_HitTestPoint (HWND hwnd, POINT pt)
2518 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2519 TREEVIEW_ITEM *wineItem;
2522 GetClientRect (hwnd, &rect);
2524 if (!infoPtr->firstVisible) return NULL;
2526 wineItem=&infoPtr->items [(INT)infoPtr->firstVisible];
2528 while ((wineItem!=NULL) && (pt.y > wineItem->rect.bottom))
2529 wineItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
2541 TREEVIEW_HitTest (HWND hwnd, LPARAM lParam)
2543 LPTVHITTESTINFO lpht=(LPTVHITTESTINFO) lParam;
2544 TREEVIEW_ITEM *wineItem;
2548 GetClientRect (hwnd, &rect);
2552 if (x < rect.left) status|=TVHT_TOLEFT;
2553 if (x > rect.right) status|=TVHT_TORIGHT;
2554 if (y < rect.top ) status|=TVHT_ABOVE;
2555 if (y > rect.bottom) status|=TVHT_BELOW;
2562 wineItem=TREEVIEW_HitTestPoint (hwnd, lpht->pt);
2564 lpht->flags=TVHT_NOWHERE;
2568 /* FIXME: implement other flags
2569 * Assign the appropriate flags depending on the click location
2570 * Intitialize flags before to "|=" it...
2574 if (x < wineItem->expandBox.left)
2576 lpht->flags |= TVHT_ONITEMINDENT;
2578 else if ( ( x >= wineItem->expandBox.left) &&
2579 ( x <= wineItem->expandBox.right))
2581 lpht->flags |= TVHT_ONITEMBUTTON;
2583 else if (x < wineItem->rect.right)
2585 lpht->flags |= TVHT_ONITEMLABEL;
2589 lpht->flags|=TVHT_ONITEMRIGHT;
2592 lpht->hItem=wineItem->hItem;
2594 return (LRESULT) wineItem->hItem;
2598 TREEVIEW_EndEditLabelNow (HWND hwnd, WPARAM wParam, LPARAM lParam)
2600 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2601 TREEVIEW_ITEM *editedItem = TREEVIEW_ValidItem (infoPtr, infoPtr->editItem);
2602 BOOL bRevert = (BOOL)wParam;
2603 BOOL bReturn = ! bRevert;
2605 if ( ! (BOOL)wParam ) /* wParam is set to true to cancel the edition */
2607 if ( TREEVIEW_SendDispInfoNotify( /* return true to cancel edition */
2618 if (bRevert == FALSE) /* Apply the changes */
2621 int iLength = GetWindowTextA(infoPtr->hwndEdit, tmpText, 1023);
2626 ERR( treeview, "Problem retreiving new item label.");
2628 else if (iLength >= 1023)
2631 "Insuficient space to retrieve new item label, new label ignored.");
2635 if (strcmp( tmpText, editedItem->pszText ) == 0)
2636 /* Do nothing if the label has not changed */
2640 LPSTR tmpLabel = COMCTL32_Alloc( iLength+1 );
2642 if ( tmpLabel == NULL )
2644 "OutOfMemory, cannot allocate space for label");
2647 COMCTL32_Free(editedItem->pszText);
2648 editedItem->pszText = tmpLabel;
2649 lstrcpyA( editedItem->pszText, tmpText);
2655 ShowWindow(infoPtr->hwndEdit, SW_HIDE);
2656 EnableWindow(infoPtr->hwndEdit, FALSE);
2657 infoPtr->editItem = 0;
2666 TREEVIEW_LButtonDoubleClick (HWND hwnd, WPARAM wParam, LPARAM lParam)
2668 TREEVIEW_ITEM *wineItem;
2671 TRACE (treeview,"\n");
2672 pt.x = (INT)LOWORD(lParam);
2673 pt.y = (INT)HIWORD(lParam);
2676 wineItem=TREEVIEW_HitTestPoint (hwnd, pt);
2677 if (!wineItem) return 0;
2678 TRACE (treeview,"item %d \n",(INT)wineItem->hItem);
2680 if (TREEVIEW_SendSimpleNotify (hwnd, NM_DBLCLK)!=TRUE) { /* FIXME!*/
2681 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) wineItem->hItem);
2688 TREEVIEW_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
2690 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2694 ht.pt.x = (INT)LOWORD(lParam);
2695 ht.pt.y = (INT)HIWORD(lParam);
2698 iItem=TREEVIEW_HitTest (hwnd, (LPARAM) &ht);
2699 TRACE (treeview,"item %d \n",iItem);
2701 if (ht.flags & TVHT_ONITEMBUTTON) {
2702 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) iItem);
2706 infoPtr->uInternalStatus|=TV_LDRAG;
2713 TREEVIEW_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
2715 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2717 TREEVIEW_ITEM *editItem;
2720 ht.pt.x = (INT)LOWORD(lParam);
2721 ht.pt.y = (INT)HIWORD(lParam);
2723 TRACE (treeview,"\n");
2725 /* Return true to cancel default behaviour */
2726 if ( TREEVIEW_SendSimpleNotify (hwnd, NM_CLICK) )
2730 iItem = TREEVIEW_HitTest (hwnd, (LPARAM) &ht);
2734 editItem = TREEVIEW_ValidItem(infoPtr, (HTREEITEM)iItem);
2736 infoPtr->uInternalStatus &= ~(TV_LDRAG | TV_LDRAGGING);
2739 * If the style allow editing and the node is already selected
2740 * and the click occured on the item label...
2742 if ( ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_EDITLABELS ) &&
2743 ( editItem->state & TVIS_SELECTED ) &&
2744 ( ht.flags & TVHT_ONITEMLABEL ))
2746 if ( infoPtr->editItem == 0 ) /* If we are not curently editing */
2748 if ( TREEVIEW_SendDispInfoNotify( /* Return true to cancel edition */
2757 TRACE(treeview,"Edit started for %s.\n", editItem->pszText);
2758 infoPtr->editItem = editItem->hItem;
2763 editItem->text.left - 2,
2764 editItem->text.top - 1,
2765 editItem->text.right - editItem->text.left + 20 ,
2766 editItem->text.bottom - editItem->text.top + 3,
2769 SetWindowTextA( infoPtr->hwndEdit, editItem->pszText );
2770 SendMessageA ( infoPtr->hwndEdit, EM_SETSEL, 0, -1 );
2771 SetFocus ( infoPtr->hwndEdit);
2772 ShowWindow ( infoPtr->hwndEdit, SW_SHOW);
2775 else if ( infoPtr->editItem != 0 ) /* If we are curently editing */
2777 TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
2779 else if ( ht.flags & (TVHT_ONITEMLABEL | TVHT_ONITEMICON))
2781 TREEVIEW_DoSelectItem (
2793 TREEVIEW_RButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
2795 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2797 TRACE (treeview,"\n");
2798 infoPtr->uInternalStatus|=TV_RDRAG;
2803 TREEVIEW_RButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
2805 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2807 TRACE (treeview,"\n");
2808 if (TREEVIEW_SendSimpleNotify (hwnd, NM_RCLICK)) return 0;
2809 infoPtr->uInternalStatus&= ~(TV_RDRAG | TV_RDRAGGING);
2815 TREEVIEW_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
2817 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2818 TREEVIEW_ITEM *hotItem;
2821 pt.x=(INT) LOWORD (lParam);
2822 pt.y=(INT) HIWORD (lParam);
2823 hotItem=TREEVIEW_HitTestPoint (hwnd, pt);
2824 if (!hotItem) return 0;
2825 infoPtr->focusItem=hotItem->hItem;
2827 if ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_DISABLEDRAGDROP) return 0;
2829 if (infoPtr->uInternalStatus & TV_LDRAG) {
2830 TREEVIEW_SendTreeviewDnDNotify (hwnd, TVN_BEGINDRAG, hotItem->hItem, pt);
2831 infoPtr->uInternalStatus &= ~TV_LDRAG;
2832 infoPtr->uInternalStatus |= TV_LDRAGGING;
2833 infoPtr->dropItem=hotItem->hItem;
2837 if (infoPtr->uInternalStatus & TV_RDRAG) {
2838 TREEVIEW_SendTreeviewDnDNotify (hwnd, TVN_BEGINRDRAG, hotItem->hItem, pt);
2839 infoPtr->uInternalStatus &= ~TV_RDRAG;
2840 infoPtr->uInternalStatus |= TV_RDRAGGING;
2841 infoPtr->dropItem=hotItem->hItem;
2850 TREEVIEW_CreateDragImage (HWND hwnd, WPARAM wParam, LPARAM lParam)
2852 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2853 TREEVIEW_ITEM *dragItem;
2857 HBITMAP hbmp,hOldbmp;
2863 TRACE (treeview,"\n");
2864 if (!(infoPtr->himlNormal)) return 0;
2865 dragItem=TREEVIEW_ValidItem (infoPtr, (HTREEITEM) lParam);
2867 if (!dragItem) return 0;
2868 itemtxt=dragItem->pszText;
2870 hwtop=GetDesktopWindow ();
2871 htopdc= GetDC (hwtop);
2872 hdc=CreateCompatibleDC (htopdc);
2874 hOldFont=SelectObject (hdc, infoPtr->hFont);
2875 GetTextExtentPoint32A (hdc, itemtxt, lstrlenA (itemtxt), &size);
2876 TRACE (treeview,"%d %d %s %d\n",size.cx,size.cy,itemtxt,lstrlenA(itemtxt));
2877 hbmp=CreateCompatibleBitmap (htopdc, size.cx, size.cy);
2878 hOldbmp=SelectObject (hdc, hbmp);
2880 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &cy);
2882 if (cy>size.cy) size.cy=cy;
2884 infoPtr->dragList=ImageList_Create (size.cx, size.cy, ILC_COLOR, 10, 10);
2885 ImageList_Draw (infoPtr->himlNormal, dragItem->iImage, hdc, 0, 0, ILD_NORMAL);
2888 ImageList_GetImageInfo (infoPtr->himlNormal, dragItem->hItem, &iminfo);
2889 ImageList_AddMasked (infoPtr->dragList, iminfo.hbmImage, CLR_DEFAULT);
2892 /* draw item text */
2894 SetRect (&rc, cx, 0, size.cx,size.cy);
2895 DrawTextA (hdc, itemtxt, lstrlenA (itemtxt), &rc, DT_LEFT);
2896 SelectObject (hdc, hOldFont);
2897 SelectObject (hdc, hOldbmp);
2899 ImageList_Add (infoPtr->dragList, hbmp, 0);
2902 DeleteObject (hbmp);
2903 ReleaseDC (hwtop, htopdc);
2905 return (LRESULT)infoPtr->dragList;
2910 TREEVIEW_DoSelectItem (HWND hwnd, INT action, HTREEITEM newSelect, INT cause)
2913 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2914 TREEVIEW_ITEM *prevItem,*wineItem;
2917 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)newSelect);
2919 TRACE (treeview,"Entering item %d, flag %x, cause %x, state %d\n",
2925 if ( (wineItem) && (wineItem->parent))
2928 * If the item has a collapse parent expand the parent so he
2929 * can expose the item
2931 TREEVIEW_ITEM *parentItem = TREEVIEW_ValidItem (infoPtr, wineItem->parent);
2932 if ( !(parentItem->state & TVIS_EXPANDED))
2933 TREEVIEW_Expand (hwnd, TVE_EXPAND, (LPARAM) wineItem->parent);
2939 prevSelect=(INT)infoPtr->selectedItem;
2941 if ((HTREEITEM)prevSelect==newSelect)
2944 prevItem= TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect);
2947 if (TREEVIEW_SendTreeviewNotify(
2951 (HTREEITEM)prevSelect,
2952 (HTREEITEM)newSelect))
2953 return FALSE; /* FIXME: OK? */
2956 prevItem->state &= ~TVIS_SELECTED;
2958 wineItem->state |= TVIS_SELECTED;
2960 infoPtr->selectedItem=(HTREEITEM)newSelect;
2962 TREEVIEW_SendTreeviewNotify(
2966 (HTREEITEM)prevSelect,
2967 (HTREEITEM)newSelect);
2971 case TVGN_DROPHILITE:
2972 prevItem= TREEVIEW_ValidItem (infoPtr, infoPtr->dropItem);
2975 prevItem->state &= ~TVIS_DROPHILITED;
2977 infoPtr->dropItem=(HTREEITEM)newSelect;
2980 wineItem->state |=TVIS_DROPHILITED;
2984 case TVGN_FIRSTVISIBLE:
2985 FIXME (treeview, "FIRSTVISIBLE not implemented\n");
2989 TREEVIEW_QueueRefresh (hwnd);
2991 TRACE (treeview,"Leaving state %d\n", wineItem->state);
2995 /* FIXME: handle NM_KILLFocus enzo */
2997 TREEVIEW_SelectItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
3000 return TREEVIEW_DoSelectItem (hwnd, wParam, (HTREEITEM) lParam, TVC_UNKNOWN);
3007 TREEVIEW_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
3010 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3012 TRACE (treeview,"%x\n",infoPtr->hFont);
3013 return infoPtr->hFont;
3017 TREEVIEW_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
3020 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3023 HFONT hFont, hOldFont;
3027 TRACE (treeview,"%x %lx\n",wParam, lParam);
3029 infoPtr->hFont = (HFONT)wParam;
3031 hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
3033 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
3034 logFont.lfWeight=FW_BOLD;
3035 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
3038 hOldFont = SelectObject (hdc, hFont);
3039 GetTextMetricsA (hdc, &tm);
3040 height= tm.tmHeight + tm.tmExternalLeading;
3041 if (height>infoPtr->uRealItemHeight)
3042 infoPtr->uRealItemHeight=height;
3043 SelectObject (hdc, hOldFont);
3047 TREEVIEW_QueueRefresh (hwnd);
3055 TREEVIEW_VScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
3058 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3061 TRACE (treeview,"wp %x, lp %lx\n", wParam, lParam);
3062 if (!infoPtr->uInternalStatus & TV_VSCROLL) return FALSE;
3064 switch (LOWORD (wParam)) {
3066 if (!infoPtr->cy) return FALSE;
3067 infoPtr->cy -= infoPtr->uRealItemHeight;
3068 if (infoPtr->cy < 0) infoPtr->cy=0;
3071 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3072 if (infoPtr->cy == maxHeight) return FALSE;
3073 infoPtr->cy += infoPtr->uRealItemHeight;
3074 if (infoPtr->cy > maxHeight)
3075 infoPtr->cy = maxHeight;
3078 if (!infoPtr->cy) return FALSE;
3079 infoPtr->cy -= infoPtr->uVisibleHeight;
3080 if (infoPtr->cy < 0) infoPtr->cy=0;
3083 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3084 if (infoPtr->cy == maxHeight) return FALSE;
3085 infoPtr->cy += infoPtr->uVisibleHeight;
3086 if (infoPtr->cy > maxHeight)
3087 infoPtr->cy = maxHeight;
3090 infoPtr->cy = HIWORD (wParam);
3095 TREEVIEW_QueueRefresh (hwnd);
3100 TREEVIEW_HScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
3102 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3105 TRACE (treeview,"wp %lx, lp %x\n", lParam, wParam);
3107 if (!infoPtr->uInternalStatus & TV_HSCROLL) return FALSE;
3109 switch (LOWORD (wParam)) {
3111 if (!infoPtr->cx) return FALSE;
3112 infoPtr->cx -= infoPtr->uRealItemHeight;
3113 if (infoPtr->cx < 0) infoPtr->cx=0;
3116 maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
3117 if (infoPtr->cx == maxWidth) return FALSE;
3118 infoPtr->cx += infoPtr->uRealItemHeight; /*FIXME */
3119 if (infoPtr->cx > maxWidth)
3120 infoPtr->cx = maxWidth;
3123 if (!infoPtr->cx) return FALSE;
3124 infoPtr->cx -= infoPtr->uVisibleWidth;
3125 if (infoPtr->cx < 0) infoPtr->cx=0;
3128 maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
3129 if (infoPtr->cx == maxWidth) return FALSE;
3130 infoPtr->cx += infoPtr->uVisibleWidth;
3131 if (infoPtr->cx > maxWidth)
3132 infoPtr->cx = maxWidth;
3135 infoPtr->cx = HIWORD (wParam);
3140 TREEVIEW_QueueRefresh (hwnd);
3146 TREEVIEW_KeyDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
3148 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3149 HTREEITEM hNewSelection = 0;
3150 INT scrollNeeds = -1;
3151 INT cyChangeNeeds = -1;
3152 INT prevSelect = (INT)infoPtr->selectedItem;
3154 TREEVIEW_ITEM *prevItem =
3155 (prevSelect != 0 ) ?
3156 TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect) :
3159 TREEVIEW_ITEM *newItem = NULL;
3161 TRACE (treeview,"%x %lx\n",wParam, lParam);
3163 if (prevSelect == 0)
3168 newItem=TREEVIEW_GetPrevListItem (infoPtr, prevItem);
3171 newItem=& infoPtr->items[(INT)infoPtr->TopRootItem];
3173 hNewSelection = newItem->hItem;
3175 if (! newItem->visible)
3176 scrollNeeds = SB_LINEUP;
3181 newItem=TREEVIEW_GetNextListItem (infoPtr, prevItem);
3186 hNewSelection = newItem->hItem;
3188 if (! newItem->visible)
3189 scrollNeeds = SB_LINEDOWN;
3194 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem];
3195 hNewSelection = newItem->hItem;
3200 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem];
3201 newItem = TREEVIEW_GetLastListItem (infoPtr, newItem);
3202 hNewSelection = newItem->hItem;
3204 if (! newItem->visible)
3205 cyChangeNeeds = infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3210 if ( (prevItem->cChildren > 0) && (prevItem->state & TVIS_EXPANDED) )
3212 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect );
3214 else if ((INT)prevItem->parent)
3216 newItem = (& infoPtr->items[(INT)prevItem->parent]);
3217 if (! newItem->visible)
3218 /* FIXME find a way to make this item the first visible... */
3221 hNewSelection = newItem->hItem;
3227 if ( ( prevItem->cChildren > 0) ||
3228 ( prevItem->cChildren == I_CHILDRENCALLBACK))
3230 if (! (prevItem->state & TVIS_EXPANDED))
3231 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect );
3234 newItem = (& infoPtr->items[(INT)prevItem->firstChild]);
3235 hNewSelection = newItem->hItem;
3242 if (! (prevItem->state & TVIS_EXPANDED))
3243 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect );
3247 if (prevItem->state & TVIS_EXPANDED)
3248 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect );
3253 newItem=TREEVIEW_GetListItem(
3256 -1*(TREEVIEW_GetVisibleCount(hwnd,0,0)-3));
3260 hNewSelection = newItem->hItem;
3262 if (! newItem->visible)
3263 scrollNeeds = SB_PAGEUP;
3268 newItem=TREEVIEW_GetListItem(
3271 TREEVIEW_GetVisibleCount(hwnd,0,0)-3);
3276 hNewSelection = newItem->hItem;
3278 if (! newItem->visible)
3279 scrollNeeds = SB_PAGEDOWN;
3288 FIXME (treeview, "%x not implemented\n", wParam);
3295 This works but does not send notification...
3297 prevItem->state &= ~TVIS_SELECTED;
3298 newItem->state |= TVIS_SELECTED;
3299 infoPtr->selectedItem = hNewSelection;
3300 TREEVIEW_QueueRefresh (hwnd);
3303 if ( TREEVIEW_DoSelectItem(
3306 (HTREEITEM)hNewSelection,
3309 /* If selection change is allowed for the new item, perform scrolling */
3310 if (scrollNeeds != -1)
3311 TREEVIEW_VScroll(hwnd, scrollNeeds, 0);
3313 if (cyChangeNeeds != -1)
3314 infoPtr->cy = cyChangeNeeds;
3316 /* FIXME: Something happen in the load the in the two weeks before
3317 april 1st 1999 which makes this SetFocus mandatory otherwise, the focus
3318 is lost... However the SetFocus should not be required...*/
3329 TREEVIEW_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3332 case TVM_INSERTITEMA:
3333 return TREEVIEW_InsertItemA (hwnd, wParam, lParam);
3335 case TVM_INSERTITEMW:
3336 FIXME (treeview, "Unimplemented msg TVM_INSERTITEM32W\n");
3339 case TVM_DELETEITEM:
3340 return TREEVIEW_DeleteItem (hwnd, wParam, lParam);
3343 return TREEVIEW_Expand (hwnd, wParam, lParam);
3345 case TVM_GETITEMRECT:
3346 return TREEVIEW_GetItemRect (hwnd, wParam, lParam);
3349 return TREEVIEW_GetCount (hwnd, wParam, lParam);
3352 return TREEVIEW_GetIndent (hwnd);
3355 return TREEVIEW_SetIndent (hwnd, wParam);
3357 case TVM_GETIMAGELIST:
3358 return TREEVIEW_GetImageList (hwnd, wParam, lParam);
3360 case TVM_SETIMAGELIST:
3361 return TREEVIEW_SetImageList (hwnd, wParam, lParam);
3363 case TVM_GETNEXTITEM:
3364 return TREEVIEW_GetNextItem (hwnd, wParam, lParam);
3366 case TVM_SELECTITEM:
3367 return TREEVIEW_SelectItem (hwnd, wParam, lParam);
3370 return TREEVIEW_GetItemA (hwnd, wParam, lParam);
3373 FIXME (treeview, "Unimplemented msg TVM_GETITEM32W\n");
3377 return TREEVIEW_SetItemA (hwnd, wParam, lParam);
3380 FIXME (treeview, "Unimplemented msg TVM_SETITEMW\n");
3383 case TVM_EDITLABELA:
3384 FIXME (treeview, "Unimplemented msg TVM_EDITLABEL32A \n");
3387 case TVM_EDITLABELW:
3388 FIXME (treeview, "Unimplemented msg TVM_EDITLABEL32W \n");
3391 case TVM_GETEDITCONTROL:
3392 return TREEVIEW_GetEditControl (hwnd);
3394 case TVM_GETVISIBLECOUNT:
3395 return TREEVIEW_GetVisibleCount (hwnd, wParam, lParam);
3398 return TREEVIEW_HitTest (hwnd, lParam);
3400 case TVM_CREATEDRAGIMAGE:
3401 return TREEVIEW_CreateDragImage (hwnd, wParam, lParam);
3403 case TVM_SORTCHILDREN:
3404 FIXME (treeview, "Unimplemented msg TVM_SORTCHILDREN\n");
3407 case TVM_ENSUREVISIBLE:
3408 FIXME (treeview, "Unimplemented msg TVM_ENSUREVISIBLE\n");
3411 case TVM_SORTCHILDRENCB:
3412 return TREEVIEW_SortChildrenCB(hwnd, wParam, lParam);
3414 case TVM_ENDEDITLABELNOW:
3415 return TREEVIEW_EndEditLabelNow (hwnd, wParam, lParam);
3417 case TVM_GETISEARCHSTRINGA:
3418 FIXME (treeview, "Unimplemented msg TVM_GETISEARCHSTRING32A\n");
3421 case TVM_GETISEARCHSTRINGW:
3422 FIXME (treeview, "Unimplemented msg TVM_GETISEARCHSTRING32W\n");
3425 case TVM_GETTOOLTIPS:
3426 return TREEVIEW_GetToolTips (hwnd);
3428 case TVM_SETTOOLTIPS:
3429 return TREEVIEW_SetToolTips (hwnd, wParam);
3431 case TVM_SETINSERTMARK:
3432 FIXME (treeview, "Unimplemented msg TVM_SETINSERTMARK\n");
3435 case TVM_SETITEMHEIGHT:
3436 return TREEVIEW_SetItemHeight (hwnd, wParam);
3438 case TVM_GETITEMHEIGHT:
3439 return TREEVIEW_GetItemHeight (hwnd);
3441 case TVM_SETBKCOLOR:
3442 return TREEVIEW_SetBkColor (hwnd, wParam, lParam);
3444 case TVM_SETTEXTCOLOR:
3445 return TREEVIEW_SetTextColor (hwnd, wParam, lParam);
3447 case TVM_GETBKCOLOR:
3448 return TREEVIEW_GetBkColor (hwnd);
3450 case TVM_GETTEXTCOLOR:
3451 return TREEVIEW_GetTextColor (hwnd);
3453 case TVM_SETSCROLLTIME:
3454 FIXME (treeview, "Unimplemented msg TVM_SETSCROLLTIME\n");
3457 case TVM_GETSCROLLTIME:
3458 FIXME (treeview, "Unimplemented msg TVM_GETSCROLLTIME\n");
3461 case TVM_SETINSERTMARKCOLOR:
3462 FIXME (treeview, "Unimplemented msg TVM_SETINSERTMARKCOLOR\n");
3465 case TVM_SETUNICODEFORMAT:
3466 FIXME (treeview, "Unimplemented msg TVM_SETUNICODEFORMAT\n");
3469 case TVM_GETUNICODEFORMAT:
3470 FIXME (treeview, "Unimplemented msg TVM_GETUNICODEFORMAT\n");
3474 return TREEVIEW_Command (hwnd, wParam, lParam);
3477 return TREEVIEW_Create (hwnd, wParam, lParam);
3480 return TREEVIEW_Destroy (hwnd);
3482 /* case WM_ENABLE: */
3485 return TREEVIEW_EraseBackground (hwnd, wParam, lParam);
3488 return DLGC_WANTARROWS | DLGC_WANTCHARS;
3491 return TREEVIEW_Paint (hwnd, wParam, lParam);
3494 return TREEVIEW_GetFont (hwnd, wParam, lParam);
3497 return TREEVIEW_SetFont (hwnd, wParam, lParam);
3500 return TREEVIEW_KeyDown (hwnd, wParam, lParam);
3504 return TREEVIEW_SetFocus (hwnd, wParam, lParam);
3507 return TREEVIEW_KillFocus (hwnd, wParam, lParam);
3510 case WM_LBUTTONDOWN:
3511 return TREEVIEW_LButtonDown (hwnd, wParam, lParam);
3514 return TREEVIEW_LButtonUp (hwnd, wParam, lParam);
3516 case WM_LBUTTONDBLCLK:
3517 return TREEVIEW_LButtonDoubleClick (hwnd, wParam, lParam);
3519 case WM_RBUTTONDOWN:
3520 return TREEVIEW_RButtonDown (hwnd, wParam, lParam);
3523 return TREEVIEW_RButtonUp (hwnd, wParam, lParam);
3526 return TREEVIEW_MouseMove (hwnd, wParam, lParam);
3529 /* case WM_SYSCOLORCHANGE: */
3530 case WM_STYLECHANGED:
3531 return TREEVIEW_StyleChanged (hwnd, wParam, lParam);
3533 /* case WM_SETREDRAW: */
3536 return TREEVIEW_HandleTimer (hwnd, wParam, lParam);
3539 return TREEVIEW_Size (hwnd, wParam,lParam);
3542 return TREEVIEW_HScroll (hwnd, wParam, lParam);
3544 return TREEVIEW_VScroll (hwnd, wParam, lParam);
3547 printf ("drawItem\n");
3548 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
3551 if (uMsg >= WM_USER)
3552 FIXME (treeview, "Unknown msg %04x wp=%08x lp=%08lx\n",
3553 uMsg, wParam, lParam);
3554 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
3561 TREEVIEW_Register (VOID)
3565 TRACE (treeview,"\n");
3567 if (GlobalFindAtomA (WC_TREEVIEWA)) return;
3569 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
3570 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
3571 wndClass.lpfnWndProc = (WNDPROC)TREEVIEW_WindowProc;
3572 wndClass.cbClsExtra = 0;
3573 wndClass.cbWndExtra = sizeof(TREEVIEW_INFO *);
3574 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
3575 wndClass.hbrBackground = 0;
3576 wndClass.lpszClassName = WC_TREEVIEWA;
3578 RegisterClassA (&wndClass);
3583 TREEVIEW_Unregister (VOID)
3585 if (GlobalFindAtomA (WC_TREEVIEWA))
3586 UnregisterClassA (WC_TREEVIEWA, (HINSTANCE)NULL);