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);
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 ( 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("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 );
771 points[0].x = wineItem->text.left-1;
772 points[0].y = wineItem->text.top+1;
773 points[1].x = wineItem->text.right;
774 points[1].y = wineItem->text.top+1;
775 points[2].x = wineItem->text.right;
776 points[2].y = wineItem->text.bottom;
777 points[3].x = wineItem->text.left-1;
778 points[3].y = wineItem->text.bottom;
780 Polyline (hdc,points,4);
782 DeleteObject(hnewPen);
783 SelectObject(hdc, hOldPen);
787 if (cditem & CDRF_NOTIFYPOSTPAINT)
788 TREEVIEW_SendCustomDrawItemNotify (hwnd, hdc, wineItem, CDDS_ITEMPOSTPAINT);
790 SelectObject (hdc, hOldFont);
794 TREEVIEW_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
796 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
797 TREEVIEW_ITEM *wineItem;
799 LPRECT lpRect = (LPRECT)lParam;
803 * validate parameters
805 if ( (infoPtr==NULL) || (lpRect == NULL) )
808 if (infoPtr->Timer & TV_REFRESH_TIMER_SET)
809 TREEVIEW_Refresh (hwnd); /* we want a rect for the current view */
812 * retrive the item ptr
814 iItem = (HTREEITEM *) lParam;
815 wineItem = TREEVIEW_ValidItem (infoPtr, *iItem);
816 if ((!wineItem) || (!wineItem->visible))
820 * If wParam is TRUE return the text size otherwise return
821 * the whole item size
824 lpRect->left = wineItem->text.left;
825 lpRect->right = wineItem->text.right;
826 lpRect->bottom = wineItem->text.bottom;
827 lpRect->top = wineItem->text.top;
829 lpRect->left = wineItem->rect.left;
830 lpRect->right = wineItem->rect.right;
831 lpRect->bottom = wineItem->rect.bottom;
832 lpRect->top = wineItem->rect.top;
835 TRACE("[L:%d R:%d T:%d B:%d]\n",
836 lpRect->left,lpRect->right,
837 lpRect->top,lpRect->bottom);
843 TREEVIEW_GetVisibleCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
846 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
848 return (LRESULT) infoPtr->uVisibleHeight / infoPtr->uRealItemHeight;
854 TREEVIEW_SetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
856 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
857 TREEVIEW_ITEM *wineItem;
861 tvItem=(LPTVITEMEXA) lParam;
862 iItem=(INT)tvItem->hItem;
863 TRACE("item %d,mask %x\n",iItem,tvItem->mask);
865 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
866 if (!wineItem) return FALSE;
868 if (tvItem->mask & TVIF_CHILDREN) {
869 wineItem->cChildren=tvItem->cChildren;
872 if (tvItem->mask & TVIF_IMAGE) {
873 wineItem->iImage=tvItem->iImage;
876 if (tvItem->mask & TVIF_INTEGRAL) {
877 wineItem->iIntegral=tvItem->iIntegral;
878 FIXME(" TVIF_INTEGRAL not supported yet\n");
881 if (tvItem->mask & TVIF_PARAM) {
882 wineItem->lParam=tvItem->lParam;
885 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
886 wineItem->iSelectedImage=tvItem->iSelectedImage;
889 if (tvItem->mask & TVIF_STATE) {
890 wineItem->state=tvItem->state & tvItem->stateMask;
893 if (tvItem->mask & TVIF_TEXT) {
894 if (tvItem->pszText!=LPSTR_TEXTCALLBACKA) {
895 len=lstrlenA (tvItem->pszText);
896 if (len>wineItem->cchTextMax)
897 wineItem->pszText= COMCTL32_ReAlloc (wineItem->pszText, len+1);
898 lstrcpynA (wineItem->pszText, tvItem->pszText,len);
900 if (wineItem->cchTextMax) {
901 COMCTL32_Free (wineItem->pszText);
902 wineItem->cchTextMax=0;
904 wineItem->pszText=LPSTR_TEXTCALLBACKA;
916 TREEVIEW_Refresh (HWND hwnd)
919 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
924 INT iItem, indent, x, y, cx, height, itemHeight;
925 INT viewtop,viewbottom,viewleft,viewright;
926 TREEVIEW_ITEM *wineItem, *prevItem;
932 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
933 KillTimer (hwnd, TV_REFRESH_TIMER);
934 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
938 GetClientRect (hwnd, &rect);
939 if ((rect.left-rect.right ==0) || (rect.top-rect.bottom==0)) return;
941 infoPtr->cdmode=TREEVIEW_SendCustomDrawNotify
942 (hwnd, CDDS_PREPAINT, hdc, rect);
944 if (infoPtr->cdmode==CDRF_SKIPDEFAULT) {
945 ReleaseDC (hwnd, hdc);
949 infoPtr->uVisibleHeight= rect.bottom-rect.top;
950 infoPtr->uVisibleWidth= rect.right-rect.left;
953 viewbottom=infoPtr->cy + rect.bottom-rect.top;
954 viewleft=infoPtr->cx;
955 viewright=infoPtr->cx + rect.right-rect.left;
959 /* draw background */
961 hbrBk = GetSysColorBrush (COLOR_WINDOW);
962 FillRect(hdc, &rect, hbrBk);
965 iItem=(INT)infoPtr->TopRootItem;
966 infoPtr->firstVisible=0;
970 TRACE("[%d %d %d %d]\n",viewtop,viewbottom,viewleft,viewright);
974 wineItem= & infoPtr->items[iItem];
975 wineItem->iLevel=indent;
977 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &itemHeight);
978 if (infoPtr->uItemHeight>itemHeight)
979 itemHeight=infoPtr->uItemHeight;
981 GetTextMetricsA (hdc, &tm);
982 if ((tm.tmHeight + tm.tmExternalLeading) > itemHeight)
983 itemHeight=tm.tmHeight + tm.tmExternalLeading;
985 infoPtr->uRealItemHeight=itemHeight;
988 /* FIXME: remove this in later stage */
990 if (wineItem->pszText!=LPSTR_TEXTCALLBACK32A)
991 TRACE (treeview, "%d %d [%d %d %d %d] (%s)\n",y,x,
992 wineItem->rect.top, wineItem->rect.bottom,
993 wineItem->rect.left, wineItem->rect.right,
996 TRACE (treeview, "%d [%d %d %d %d] (CALLBACK)\n",
998 wineItem->rect.top, wineItem->rect.bottom,
999 wineItem->rect.left, wineItem->rect.right);
1002 height=itemHeight * wineItem->iIntegral +1;
1003 if ((y >= viewtop) && (y <= viewbottom) &&
1004 (x >= viewleft ) && (x <= viewright)) {
1005 wineItem->visible = TRUE;
1006 wineItem->rect.top = y - infoPtr->cy + rect.top;
1007 wineItem->rect.bottom = wineItem->rect.top + height ;
1008 wineItem->rect.left = x - infoPtr->cx + rect.left;
1009 wineItem->rect.right = rect.right;
1010 if (!infoPtr->firstVisible)
1011 infoPtr->firstVisible=wineItem->hItem;
1012 TREEVIEW_DrawItem (hwnd, hdc, wineItem);
1015 wineItem->visible = FALSE;
1016 wineItem->rect.left = wineItem->rect.top = 0;
1017 wineItem->rect.right= wineItem->rect.bottom = 0;
1018 wineItem->text.left = wineItem->text.top = 0;
1019 wineItem->text.right= wineItem->text.bottom = 0;
1022 /* look up next item */
1024 if ((wineItem->firstChild) && (wineItem->state & TVIS_EXPANDED)) {
1025 iItem=(INT)wineItem->firstChild;
1027 x+=infoPtr->uIndent;
1028 if (x>infoPtr->uTotalWidth)
1029 infoPtr->uTotalWidth=x;
1032 iItem=(INT)wineItem->sibling;
1033 while ((!iItem) && (indent>0)) {
1035 x-=infoPtr->uIndent;
1037 wineItem=&infoPtr->items[(INT)wineItem->parent];
1038 iItem=(INT)wineItem->sibling;
1044 /* FIXME: infoPtr->uTotalWidth should also take item label into account */
1045 /* FIXME: or should query item sizes (ie check CDRF_NEWFONT) */
1047 infoPtr->uTotalHeight=y;
1048 if (y >= (viewbottom-viewtop)) {
1049 if (!(infoPtr->uInternalStatus & TV_VSCROLL))
1050 ShowScrollBar (hwnd, SB_VERT, TRUE);
1051 infoPtr->uInternalStatus |=TV_VSCROLL;
1052 SetScrollRange (hwnd, SB_VERT, 0,
1053 y - infoPtr->uVisibleHeight, FALSE);
1054 SetScrollPos (hwnd, SB_VERT, infoPtr->cy, TRUE);
1057 if (infoPtr->uInternalStatus & TV_VSCROLL)
1058 ShowScrollBar (hwnd, SB_VERT, FALSE);
1059 infoPtr->uInternalStatus &= ~TV_VSCROLL;
1063 if (infoPtr->cdmode & CDRF_NOTIFYPOSTPAINT)
1064 infoPtr->cdmode=TREEVIEW_SendCustomDrawNotify
1065 (hwnd, CDDS_POSTPAINT, hdc, rect);
1067 ReleaseDC (hwnd, hdc);
1073 TREEVIEW_HandleTimer (HWND hwnd, WPARAM wParam, LPARAM lParam)
1075 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1077 TRACE(" %d\n",wParam);
1078 if (!infoPtr) return FALSE;
1081 case TV_REFRESH_TIMER:
1082 KillTimer (hwnd, TV_REFRESH_TIMER);
1083 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
1084 InvalidateRect(hwnd, NULL, FALSE);
1087 KillTimer (hwnd, TV_EDIT_TIMER);
1088 infoPtr->Timer &= ~TV_EDIT_TIMER_SET;
1091 ERR("got unknown timer\n");
1099 TREEVIEW_QueueRefresh (HWND hwnd)
1102 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1105 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
1106 KillTimer (hwnd, TV_REFRESH_TIMER);
1109 SetTimer (hwnd, TV_REFRESH_TIMER, TV_REFRESH_DELAY, 0);
1110 infoPtr->Timer|=TV_REFRESH_TIMER_SET;
1116 TREEVIEW_GetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1118 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1120 TREEVIEW_ITEM *wineItem;
1123 tvItem=(LPTVITEMEXA) lParam;
1124 iItem=(INT)tvItem->hItem;
1126 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1127 if (!wineItem) return FALSE;
1129 if (tvItem->mask & TVIF_CHILDREN) {
1130 if (TVIF_CHILDREN==I_CHILDRENCALLBACK)
1131 FIXME("I_CHILDRENCALLBACK not supported\n");
1132 tvItem->cChildren=wineItem->cChildren;
1135 if (tvItem->mask & TVIF_HANDLE) {
1136 tvItem->hItem=wineItem->hItem;
1139 if (tvItem->mask & TVIF_IMAGE) {
1140 tvItem->iImage=wineItem->iImage;
1143 if (tvItem->mask & TVIF_INTEGRAL) {
1144 tvItem->iIntegral=wineItem->iIntegral;
1145 FIXME(" TVIF_INTEGRAL not supported yet\n");
1148 // undocumented: windows ignores TVIF_PARAM and
1149 // 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
1269 static void TREEVIEW_InsertBefore(
1270 TREEVIEW_INFO *infoPtr,
1271 TREEVIEW_ITEM *newItem,
1272 TREEVIEW_ITEM *sibling,
1273 TREEVIEW_ITEM *parent)
1275 HTREEITEM siblingHandle = 0;
1276 HTREEITEM upSiblingHandle = 0;
1277 TREEVIEW_ITEM *upSibling = NULL;
1279 if (newItem == NULL)
1280 ERR("NULL newItem, impossible condition\n");
1283 ERR("NULL parent, impossible condition\n");
1285 if (sibling != NULL) /* Insert before this sibling for this parent */
1287 /* Store the new item sibling up sibling and sibling tem handle */
1288 siblingHandle = sibling->hItem;
1289 upSiblingHandle = sibling->upsibling;
1290 /* As well as a pointer to the upsibling sibling object */
1291 if ( (INT)sibling->upsibling != 0 )
1292 upSibling = &infoPtr->items[(INT)sibling->upsibling];
1294 /* Adjust the sibling pointer */
1295 sibling->upsibling = newItem->hItem;
1297 /* Adjust the new item pointers */
1298 newItem->upsibling = upSiblingHandle;
1299 newItem->sibling = siblingHandle;
1301 /* Adjust the up sibling pointer */
1302 if ( upSibling != NULL )
1303 upSibling->sibling = newItem->hItem;
1305 /* this item is the first child of this parent, adjust parent pointers */
1306 parent->firstChild = newItem->hItem;
1308 else /* Insert as first child of this parent */
1309 parent->firstChild = newItem->hItem;
1312 /***************************************************************************
1313 * This method does the chaining of the insertion of a treeview item
1316 static void TREEVIEW_InsertAfter(
1317 TREEVIEW_INFO *infoPtr,
1318 TREEVIEW_ITEM *newItem,
1319 TREEVIEW_ITEM *upSibling,
1320 TREEVIEW_ITEM *parent)
1322 HTREEITEM upSiblingHandle = 0;
1323 HTREEITEM siblingHandle = 0;
1324 TREEVIEW_ITEM *sibling = NULL;
1326 if (newItem == NULL)
1327 ERR("NULL newItem, impossible condition\n");
1330 ERR("NULL parent, impossible condition\n");
1332 if (upSibling != NULL) /* Insert after this upsibling for this parent */
1334 /* Store the new item up sibling and sibling item handle */
1335 upSiblingHandle = upSibling->hItem;
1336 siblingHandle = upSibling->sibling;
1337 /* As well as a pointer to the upsibling sibling object */
1338 if ( (INT)upSibling->sibling != 0 )
1339 sibling = &infoPtr->items[(INT)upSibling->sibling];
1341 /* Adjust the up sibling pointer */
1342 upSibling->sibling = newItem->hItem;
1344 /* Adjust the new item pointers */
1345 newItem->upsibling = upSiblingHandle;
1346 newItem->sibling = siblingHandle;
1348 /* Adjust the sibling pointer */
1349 if ( sibling != NULL )
1350 sibling->upsibling = newItem->hItem;
1353 newItem is the last of the level, nothing else to do
1356 else /* Insert as first child of this parent */
1357 parent->firstChild = newItem->hItem;
1360 /***************************************************************************
1361 * Forward the DPA local callback to the treeview owner callback
1363 static INT WINAPI TREEVIEW_CallBackCompare(
1368 /* Forward the call to the client define callback */
1369 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr((HWND)tvInfoPtr);
1370 return (infoPtr->pCallBackSort->lpfnCompare)(
1371 ((TREEVIEW_ITEM*)first)->lParam,
1372 ((TREEVIEW_ITEM*)second)->lParam,
1373 infoPtr->pCallBackSort->lParam);
1376 /***************************************************************************
1377 * Setup the treeview structure with regards of the sort method
1378 * and sort the children of the TV item specified in lParam
1380 LRESULT WINAPI TREEVIEW_SortChildrenCB(
1385 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1386 TREEVIEW_ITEM *sortMe = NULL; /* Node for which we sort the children */
1388 /* Obtain the TVSORTBC struct */
1389 infoPtr->pCallBackSort = (LPTVSORTCB)lParam;
1391 /* Obtain the parent node to sort */
1392 sortMe = &infoPtr->items[ (INT)infoPtr->pCallBackSort->hParent ];
1394 /* Make sure there is something to sort */
1395 if ( sortMe->cChildren > 1 )
1397 /* pointer organization */
1398 HDPA sortList = DPA_Create(sortMe->cChildren);
1399 HTREEITEM itemHandle = sortMe->firstChild;
1400 TREEVIEW_ITEM *itemPtr = & infoPtr->items[ (INT)itemHandle ];
1402 /* TREEVIEW_ITEM rechaining */
1408 /* Build the list of item to sort */
1412 sortList, /* the list */
1413 sortMe->cChildren+1, /* force the insertion to be an append */
1414 itemPtr); /* the ptr to store */
1416 /* Get the next sibling */
1417 itemHandle = itemPtr->sibling;
1418 itemPtr = & infoPtr->items[ (INT)itemHandle ];
1419 } while ( itemHandle != NULL );
1421 /* let DPA perform the sort activity */
1423 sortList, /* what */
1424 TREEVIEW_CallBackCompare, /* how */
1428 * Reorganized TREEVIEW_ITEM structures.
1429 * Note that we know we have at least two elements.
1432 /* Get the first item and get ready to start... */
1433 item = DPA_GetPtr(sortList, count++);
1434 while ( (nextItem = DPA_GetPtr(sortList, count++)) != NULL )
1436 /* link the two current item toghether */
1437 ((TREEVIEW_ITEM*)item)->sibling = ((TREEVIEW_ITEM*)nextItem)->hItem;
1438 ((TREEVIEW_ITEM*)nextItem)->upsibling = ((TREEVIEW_ITEM*)item)->hItem;
1440 if (prevItem == NULL) /* this is the first item, update the parent */
1442 sortMe->firstChild = ((TREEVIEW_ITEM*)item)->hItem;
1443 ((TREEVIEW_ITEM*)item)->upsibling = NULL;
1445 else /* fix the back chaining */
1447 ((TREEVIEW_ITEM*)item)->upsibling = ((TREEVIEW_ITEM*)prevItem)->hItem;
1450 /* get ready for the next one */
1455 /* the last item is pointed to by item and never has a sibling */
1456 ((TREEVIEW_ITEM*)item)->sibling = NULL;
1458 DPA_Destroy(sortList);
1466 /* the method used below isn't the most memory-friendly, but it avoids
1467 a lot of memory reallocations */
1469 /* BTW: we waste handle 0; 0 is not an allowed handle. */
1472 TREEVIEW_InsertItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1475 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1476 TVINSERTSTRUCTA *ptdi;
1478 TREEVIEW_ITEM *wineItem, *parentItem, *prevsib, *sibItem;
1479 INT iItem,listItems,i,len;
1481 /* Item to insert */
1482 ptdi = (LPTVINSERTSTRUCTA) lParam;
1484 /* check if memory is available */
1486 if (infoPtr->uNumPtrsAlloced==0) {
1487 infoPtr->items = COMCTL32_Alloc (TVITEM_ALLOC*sizeof (TREEVIEW_ITEM));
1488 infoPtr->freeList= COMCTL32_Alloc ((1+(TVITEM_ALLOC>>5)) * sizeof (INT));
1489 infoPtr->uNumPtrsAlloced=TVITEM_ALLOC;
1490 infoPtr->TopRootItem=(HTREEITEM)1;
1494 * Reallocate contiguous space for items
1496 if (infoPtr->uNumItems == (infoPtr->uNumPtrsAlloced-1) ) {
1497 TREEVIEW_ITEM *oldItems = infoPtr->items;
1498 INT *oldfreeList = infoPtr->freeList;
1500 infoPtr->uNumPtrsAlloced*=2;
1501 infoPtr->items = COMCTL32_Alloc (infoPtr->uNumPtrsAlloced*sizeof (TREEVIEW_ITEM));
1502 infoPtr->freeList= COMCTL32_Alloc ((1+(infoPtr->uNumPtrsAlloced>>5))*sizeof (INT));
1504 memcpy (&infoPtr->items[0], &oldItems[0],
1505 infoPtr->uNumPtrsAlloced/2 * sizeof(TREEVIEW_ITEM));
1506 memcpy (&infoPtr->freeList[0], &oldfreeList[0],
1507 (infoPtr->uNumPtrsAlloced>>6) * sizeof(INT));
1509 COMCTL32_Free (oldItems);
1510 COMCTL32_Free (oldfreeList);
1514 * Reset infoPtr structure with new stat according to current TV picture
1517 infoPtr->uNumItems++;
1518 if ((INT)infoPtr->uMaxHandle==(infoPtr->uNumItems-1)) {
1519 iItem=infoPtr->uNumItems;
1520 infoPtr->uMaxHandle = (HTREEITEM)((INT)infoPtr->uMaxHandle + 1);
1521 } else { /* check freelist */
1522 for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++) {
1523 if (infoPtr->freeList[i]) {
1524 iItem=ffs (infoPtr->freeList[i])-1;
1525 tv_clear_bit(iItem,&infoPtr->freeList[i]);
1532 if (TRACE_ON(treeview)) {
1533 for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++)
1534 TRACE("%8x\n",infoPtr->freeList[i]);
1537 if (!iItem) ERR("Argh -- can't find free item.\n");
1540 * Find the parent item of the new item
1542 tvItem= & ptdi->DUMMYUNIONNAME.itemex;
1543 wineItem=& infoPtr->items[iItem];
1545 if ((ptdi->hParent==TVI_ROOT) || (ptdi->hParent==0)) {
1547 wineItem->parent = 0;
1548 sibItem = &infoPtr->items [(INT)infoPtr->TopRootItem];
1549 listItems = infoPtr->uNumItems;
1552 parentItem = &infoPtr->items[(INT)ptdi->hParent];
1554 /* Do the insertion here it if it's the only item of this parent */
1555 if (!parentItem->firstChild)
1556 parentItem->firstChild=(HTREEITEM)iItem;
1558 wineItem->parent = ptdi->hParent;
1559 sibItem = &infoPtr->items [(INT)parentItem->firstChild];
1560 parentItem->cChildren++;
1561 listItems = parentItem->cChildren;
1565 /* NOTE: I am moving some setup of the wineItem object that was initialy
1566 * done at the end of the function since some of the values are
1567 * required by the Callback sorting
1570 if (tvItem->mask & TVIF_TEXT)
1573 * Setup the item text stuff here since it's required by the Sort method
1574 * when the insertion are ordered
1576 if (tvItem->pszText!=LPSTR_TEXTCALLBACKA)
1578 TRACE("(%p,%s)\n", &tvItem->pszText, tvItem->pszText);
1579 len = lstrlenA (tvItem->pszText)+1;
1580 wineItem->pszText= COMCTL32_Alloc (len+1);
1581 lstrcpyA (wineItem->pszText, tvItem->pszText);
1582 wineItem->cchTextMax=len;
1586 TRACE("LPSTR_TEXTCALLBACK\n");
1587 wineItem->pszText = LPSTR_TEXTCALLBACKA;
1588 wineItem->cchTextMax = 0;
1592 if (tvItem->mask & TVIF_PARAM)
1593 wineItem->lParam=tvItem->lParam;
1596 wineItem->upsibling=0; /* needed in case we're the first item in a list */
1597 wineItem->sibling=0;
1598 wineItem->firstChild=0;
1599 wineItem->hItem=(HTREEITEM)iItem;
1604 switch ((DWORD) ptdi->hInsertAfter) {
1605 case (DWORD) TVI_FIRST:
1606 if (wineItem->parent) {
1607 wineItem->sibling=parentItem->firstChild;
1608 parentItem->firstChild=(HTREEITEM)iItem;
1610 wineItem->sibling=infoPtr->TopRootItem;
1611 infoPtr->TopRootItem=(HTREEITEM)iItem;
1613 sibItem->upsibling=(HTREEITEM)iItem;
1616 case (DWORD) TVI_SORT:
1617 if (sibItem==wineItem)
1619 * This item is the first child of the level and it
1620 * has already been inserted
1625 TREEVIEW_ITEM *aChild =
1626 &infoPtr->items[(INT)parentItem->firstChild];
1628 TREEVIEW_ITEM *previousChild = NULL;
1629 BOOL bItemInserted = FALSE;
1631 /* Iterate the parent children to see where we fit in */
1632 while ( aChild != NULL )
1634 INT comp = strcmp(wineItem->pszText, aChild->pszText);
1635 if ( comp < 0 ) /* we are smaller than the current one */
1637 TREEVIEW_InsertBefore(infoPtr, wineItem, aChild, parentItem);
1638 bItemInserted = TRUE;
1641 else if ( comp > 0 ) /* we are bigger than the current one */
1643 previousChild = aChild;
1644 aChild = (aChild->sibling == 0) /* This will help us to exit */
1645 ? NULL /* if there is no more sibling */
1646 : &infoPtr->items[(INT)aChild->sibling];
1648 /* Look at the next item */
1651 else if ( comp == 0 )
1654 * An item with this name is already existing, therefore,
1655 * we add after the one we found
1657 TREEVIEW_InsertAfter(infoPtr, wineItem, aChild, parentItem);
1658 bItemInserted = TRUE;
1664 * we reach the end of the child list and the item as not
1665 * yet been inserted, therefore, insert it after the last child.
1667 if ( (! bItemInserted ) && (aChild == NULL) )
1668 TREEVIEW_InsertAfter(infoPtr, wineItem, previousChild, parentItem);
1674 case (DWORD) TVI_LAST:
1675 if (sibItem==wineItem) break;
1676 while (sibItem->sibling) {
1678 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1680 sibItem->sibling=(HTREEITEM)iItem;
1681 wineItem->upsibling=sibItem->hItem;
1684 while ((sibItem->sibling) && (sibItem->hItem!=ptdi->hInsertAfter))
1687 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1689 if (sibItem->hItem!=ptdi->hInsertAfter) {
1690 ERR("tried to insert item after nonexisting handle.\n");
1694 if (sibItem->sibling) {
1695 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1696 sibItem->upsibling=(HTREEITEM)iItem;
1697 wineItem->sibling=sibItem->hItem;
1699 prevsib->sibling=(HTREEITEM)iItem;
1700 wineItem->upsibling=prevsib->hItem;
1706 /* Fill in info structure */
1708 TRACE("new item %d; parent %d, mask %x\n", iItem,
1709 (INT)wineItem->parent,tvItem->mask);
1711 wineItem->mask=tvItem->mask;
1712 wineItem->iIntegral=1;
1714 if (tvItem->mask & TVIF_CHILDREN) {
1715 wineItem->cChildren=tvItem->cChildren;
1716 if (tvItem->cChildren==I_CHILDRENCALLBACK)
1717 FIXME(" I_CHILDRENCALLBACK not supported\n");
1720 wineItem->expandBox.left = 0; /* Initialize the expandBox */
1721 wineItem->expandBox.top = 0;
1722 wineItem->expandBox.right = 0;
1723 wineItem->expandBox.bottom = 0;
1725 if (tvItem->mask & TVIF_IMAGE)
1726 wineItem->iImage=tvItem->iImage;
1728 /* If the application sets TVIF_INTEGRAL without
1729 supplying a TVITEMEX structure, it's toast */
1731 if (tvItem->mask & TVIF_INTEGRAL)
1732 wineItem->iIntegral=tvItem->iIntegral;
1734 if (tvItem->mask & TVIF_SELECTEDIMAGE)
1735 wineItem->iSelectedImage=tvItem->iSelectedImage;
1737 if (tvItem->mask & TVIF_STATE) {
1738 TRACE("Changing item state from %d to %d\n",
1741 wineItem->state=tvItem->state;
1742 wineItem->stateMask=tvItem->stateMask;
1746 TREEVIEW_QueueRefresh (hwnd);
1748 return (LRESULT) iItem;
1756 TREEVIEW_DeleteItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
1758 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1760 TREEVIEW_ITEM *wineItem;
1763 if (!infoPtr) return FALSE;
1765 if (lParam == (INT)TVI_ROOT) {
1766 TREEVIEW_RemoveTree (hwnd);
1768 iItem= (INT) lParam;
1769 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1770 if (!wineItem) return FALSE;
1771 TRACE("%s\n",wineItem->pszText);
1772 TREEVIEW_RemoveItem (hwnd, wineItem);
1775 TREEVIEW_QueueRefresh (hwnd);
1783 TREEVIEW_GetIndent (HWND hwnd)
1785 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1788 return infoPtr->uIndent;
1792 TREEVIEW_SetIndent (HWND hwnd, WPARAM wParam)
1794 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1798 newIndent=(INT) wParam;
1799 if (newIndent < MINIMUM_INDENT) newIndent=MINIMUM_INDENT;
1800 infoPtr->uIndent=newIndent;
1806 TREEVIEW_GetToolTips (HWND hwnd)
1809 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1812 return infoPtr->hwndToolTip;
1817 TREEVIEW_SetToolTips (HWND hwnd, WPARAM wParam)
1820 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1824 prevToolTip=infoPtr->hwndToolTip;
1825 infoPtr->hwndToolTip= (HWND) wParam;
1832 TREEVIEW_GetEditControl (HWND hwnd)
1835 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1837 return infoPtr->hwndEdit;
1841 TREEVIEW_Edit_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam,
1849 HDC hdc = (HDC) wParam;
1850 GetClientRect (hwnd, &rc);
1851 Rectangle (hdc, rc.left, rc.top, rc.right, rc.bottom);
1857 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
1862 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd));
1863 return CallWindowProcA( infoPtr->wpEditOrig, hwnd, uMsg, wParam, lParam);
1871 /* should handle edit control messages here */
1874 TREEVIEW_Command (HWND hwnd, WPARAM wParam, LPARAM lParam)
1877 TRACE("%x %ld\n",wParam, lParam);
1879 switch (HIWORD(wParam))
1884 * Adjust the edit window size
1886 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1887 TREEVIEW_ITEM *editItem = TREEVIEW_ValidItem(infoPtr, infoPtr->editItem);
1888 INT iLength = GetWindowTextLengthA(infoPtr->hwndEdit);
1889 HDC hdc = GetDC(infoPtr->hwndEdit);
1892 if ( GetTextMetricsA(hdc, &tm) )
1894 LONG newWidth = (iLength * tm.tmAveCharWidth) + 15;
1899 editItem->text.left - 2,
1900 editItem->text.top - 1,
1902 editItem->text.bottom - editItem->text.top + 3,
1905 ReleaseDC(hwnd, hdc);
1911 /* TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
1916 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
1923 TREEVIEW_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
1926 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1928 if (infoPtr->bAutoSize)
1930 infoPtr->bAutoSize = FALSE;
1933 infoPtr->bAutoSize = TRUE;
1935 if (wParam == SIZE_RESTORED)
1937 infoPtr->uTotalWidth = LOWORD (lParam);
1938 infoPtr->uTotalHeight = HIWORD (lParam);
1940 FIXME("WM_SIZE flag %x %lx not handled\n", wParam, lParam);
1943 TREEVIEW_QueueRefresh (hwnd);
1950 TREEVIEW_StyleChanged (HWND hwnd, WPARAM wParam, LPARAM lParam)
1952 LPSTYLESTRUCT lpss=(LPSTYLESTRUCT) lParam;
1954 TRACE("(%x %lx)\n",wParam,lParam);
1956 if (wParam & (GWL_STYLE))
1957 SetWindowLongA( hwnd, GWL_STYLE, lpss->styleNew);
1958 if (wParam & (GWL_EXSTYLE))
1959 SetWindowLongA( hwnd, GWL_STYLE, lpss->styleNew);
1965 TREEVIEW_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
1967 TREEVIEW_INFO *infoPtr;
1972 TRACE("wnd %x\n",hwnd);
1973 /* allocate memory for info structure */
1974 infoPtr = (TREEVIEW_INFO *) COMCTL32_Alloc (sizeof(TREEVIEW_INFO));
1976 SetWindowLongA( hwnd, 0, (DWORD)infoPtr);
1978 if (infoPtr == NULL) {
1979 ERR("could not allocate info memory!\n");
1983 if ((TREEVIEW_INFO*) GetWindowLongA( hwnd, 0) != infoPtr) {
1984 ERR("pointer assignment error!\n");
1990 /* set default settings */
1991 infoPtr->uInternalStatus=0;
1992 infoPtr->uNumItems=0;
1993 infoPtr->clrBk = GetSysColor (COLOR_WINDOW);
1994 infoPtr->clrText = GetSysColor (COLOR_BTNTEXT);
1997 infoPtr->uIndent = 15;
1998 infoPtr->himlNormal = NULL;
1999 infoPtr->himlState = NULL;
2000 infoPtr->uItemHeight = -1;
2001 GetTextMetricsA (hdc, &tm);
2002 infoPtr->hFont = GetStockObject (DEFAULT_GUI_FONT);
2003 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
2004 logFont.lfWeight=FW_BOLD;
2005 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
2007 infoPtr->items = NULL;
2008 infoPtr->selectedItem=0;
2009 infoPtr->clrText=-1; /* use system color */
2010 infoPtr->dropItem=0;
2011 infoPtr->pCallBackSort=NULL;
2014 infoPtr->hwndNotify = GetParent32 (hwnd);
2015 infoPtr->bTransparent = ( GetWindowLongA( hwnd, GWL_STYLE) & TBSTYLE_FLAT);
2018 infoPtr->hwndToolTip=0;
2019 if (!( GetWindowLongA( hwnd, GWL_STYLE) & TVS_NOTOOLTIPS)) { /* Create tooltip control */
2022 infoPtr->hwndToolTip =
2023 CreateWindowExA (0, TOOLTIPS_CLASSA, NULL, 0,
2024 CW_USEDEFAULT, CW_USEDEFAULT,
2025 CW_USEDEFAULT, CW_USEDEFAULT,
2028 /* Send NM_TOOLTIPSCREATED notification */
2029 if (infoPtr->hwndToolTip) {
2030 NMTOOLTIPSCREATED nmttc;
2032 nmttc.hdr.hwndFrom = hwnd;
2033 nmttc.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2034 nmttc.hdr.code = NM_TOOLTIPSCREATED;
2035 nmttc.hwndToolTips = infoPtr->hwndToolTip;
2037 SendMessageA (GetParent (hwnd), WM_NOTIFY,
2038 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmttc);
2041 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
2042 ti.cbSize = sizeof(TTTOOLINFOA);
2043 ti.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_TRANSPARENT ;
2046 ti.lpszText = "Test"; /* LPSTR_TEXTCALLBACK; */
2047 SetRectEmpty (&ti.rect);
2049 SendMessageA (infoPtr->hwndToolTip, TTM_ADDTOOLA, 0, (LPARAM)&ti);
2052 infoPtr->hwndEdit = CreateWindowExA (
2056 WS_CHILD | WS_BORDER | ES_AUTOHSCROLL |
2057 ES_WANTRETURN | ES_LEFT,
2060 0,0,0); /* FIXME: (HMENU)IDTVEDIT,pcs->hInstance,0);*/
2062 SendMessageA ( infoPtr->hwndEdit, WM_SETFONT, infoPtr->hFont, FALSE);
2063 infoPtr->wpEditOrig = (WNDPROC)SetWindowLongA (
2066 (LONG) TREEVIEW_Edit_SubclassProc);
2068 ReleaseDC (hwnd, hdc);
2075 TREEVIEW_Destroy (HWND hwnd)
2077 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2080 TREEVIEW_RemoveTree (hwnd);
2081 if (infoPtr->Timer & TV_REFRESH_TIMER_SET)
2082 KillTimer (hwnd, TV_REFRESH_TIMER);
2083 if (infoPtr->hwndToolTip)
2084 DestroyWindow (infoPtr->hwndToolTip);
2086 COMCTL32_Free (infoPtr);
2092 TREEVIEW_Paint (HWND hwnd, WPARAM wParam, LPARAM lParam)
2098 hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
2099 TREEVIEW_Refresh (hwnd);
2101 EndPaint (hwnd, &ps);
2104 return DefWindowProcA (hwnd, WM_PAINT, wParam, lParam);
2108 TREEVIEW_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2110 TREEVIEW_SendSimpleNotify (hwnd, NM_SETFOCUS);
2111 InvalidateRect(hwnd, NULL, FALSE);
2116 TREEVIEW_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2118 TREEVIEW_SendSimpleNotify (hwnd, NM_KILLFOCUS);
2119 InvalidateRect(hwnd, NULL, FALSE);
2124 TREEVIEW_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
2126 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2127 HBRUSH hBrush = CreateSolidBrush (infoPtr->clrBk);
2131 GetClientRect (hwnd, &rect);
2132 FillRect ((HDC)wParam, &rect, hBrush);
2133 DeleteObject (hBrush);
2149 TREEVIEW_SendSimpleNotify (HWND hwnd, UINT code)
2154 nmhdr.hwndFrom = hwnd;
2155 nmhdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2158 return (BOOL) SendMessageA (GetParent (hwnd), WM_NOTIFY,
2159 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
2165 TREEVIEW_SendTreeviewNotify (HWND hwnd, UINT code, UINT action,
2166 HTREEITEM oldItem, HTREEITEM newItem)
2169 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2171 TREEVIEW_ITEM *wineItem;
2173 TRACE("code:%x action:%x olditem:%x newitem:%x\n",
2174 code,action,(INT)oldItem,(INT)newItem);
2175 nmhdr.hdr.hwndFrom = hwnd;
2176 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2177 nmhdr.hdr.code = code;
2178 nmhdr.action = action;
2180 wineItem=& infoPtr->items[(INT)oldItem];
2181 nmhdr.itemOld.mask = wineItem->mask;
2182 nmhdr.itemOld.hItem = wineItem->hItem;
2183 nmhdr.itemOld.state = wineItem->state;
2184 nmhdr.itemOld.stateMask = wineItem->stateMask;
2185 nmhdr.itemOld.iImage = wineItem->iImage;
2186 nmhdr.itemOld.pszText = wineItem->pszText;
2187 nmhdr.itemOld.cchTextMax= wineItem->cchTextMax;
2188 nmhdr.itemOld.iImage = wineItem->iImage;
2189 nmhdr.itemOld.iSelectedImage = wineItem->iSelectedImage;
2190 nmhdr.itemOld.cChildren = wineItem->cChildren;
2191 nmhdr.itemOld.lParam = wineItem->lParam;
2195 wineItem=& infoPtr->items[(INT)newItem];
2196 nmhdr.itemNew.mask = wineItem->mask;
2197 nmhdr.itemNew.hItem = wineItem->hItem;
2198 nmhdr.itemNew.state = wineItem->state;
2199 nmhdr.itemNew.stateMask = wineItem->stateMask;
2200 nmhdr.itemNew.iImage = wineItem->iImage;
2201 nmhdr.itemNew.pszText = wineItem->pszText;
2202 nmhdr.itemNew.cchTextMax= wineItem->cchTextMax;
2203 nmhdr.itemNew.iImage = wineItem->iImage;
2204 nmhdr.itemNew.iSelectedImage = wineItem->iSelectedImage;
2205 nmhdr.itemNew.cChildren = wineItem->cChildren;
2206 nmhdr.itemNew.lParam = wineItem->lParam;
2212 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2213 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2218 TREEVIEW_SendTreeviewDnDNotify (HWND hwnd, UINT code, HTREEITEM dragItem,
2221 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2223 TREEVIEW_ITEM *wineItem;
2225 TRACE("code:%x dragitem:%x\n", code,(INT)dragItem);
2227 nmhdr.hdr.hwndFrom = hwnd;
2228 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2229 nmhdr.hdr.code = code;
2231 wineItem=& infoPtr->items[(INT)dragItem];
2232 nmhdr.itemNew.mask = wineItem->mask;
2233 nmhdr.itemNew.hItem = wineItem->hItem;
2234 nmhdr.itemNew.state = wineItem->state;
2235 nmhdr.itemNew.lParam = wineItem->lParam;
2237 nmhdr.ptDrag.x = pt.x;
2238 nmhdr.ptDrag.y = pt.y;
2240 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2241 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2248 TREEVIEW_SendDispInfoNotify (HWND hwnd, TREEVIEW_ITEM *wineItem,
2249 UINT code, UINT what)
2255 TRACE("item %d, action %x, state %d\n",
2256 (INT)wineItem->hItem,
2258 (INT)wineItem->state);
2260 tvdi.hdr.hwndFrom = hwnd;
2261 tvdi.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2262 tvdi.hdr.code = code;
2263 tvdi.item.mask = what;
2264 tvdi.item.hItem = wineItem->hItem;
2265 tvdi.item.state = wineItem->state;
2266 tvdi.item.lParam = wineItem->lParam;
2267 tvdi.item.pszText = COMCTL32_Alloc (128*sizeof(char));
2268 buf = tvdi.item.pszText;
2270 retval=(BOOL)SendMessageA (
2273 (WPARAM)tvdi.hdr.idFrom,
2276 if (what & TVIF_TEXT) {
2277 wineItem->pszText = tvdi.item.pszText;
2278 if (buf==tvdi.item.pszText) {
2279 wineItem->cchTextMax = 128;
2281 TRACE("user-supplied buffer\n");
2282 COMCTL32_Free (buf);
2283 wineItem->cchTextMax = 0;
2286 if (what & TVIF_SELECTEDIMAGE)
2287 wineItem->iSelectedImage = tvdi.item.iSelectedImage;
2288 if (what & TVIF_IMAGE)
2289 wineItem->iImage = tvdi.item.iImage;
2290 if (what & TVIF_CHILDREN)
2291 wineItem->cChildren = tvdi.item.cChildren;
2299 TREEVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
2302 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2303 NMTVCUSTOMDRAW nmcdhdr;
2304 LPNMCUSTOMDRAW nmcd;
2306 TRACE("drawstage:%lx hdc:%x\n", dwDrawStage, hdc);
2308 nmcd= & nmcdhdr.nmcd;
2309 nmcd->hdr.hwndFrom = hwnd;
2310 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2311 nmcd->hdr.code = NM_CUSTOMDRAW;
2312 nmcd->dwDrawStage= dwDrawStage;
2314 nmcd->rc.left = rc.left;
2315 nmcd->rc.right = rc.right;
2316 nmcd->rc.bottom = rc.bottom;
2317 nmcd->rc.top = rc.top;
2318 nmcd->dwItemSpec = 0;
2319 nmcd->uItemState = 0;
2320 nmcd->lItemlParam= 0;
2321 nmcdhdr.clrText = infoPtr->clrText;
2322 nmcdhdr.clrTextBk= infoPtr->clrBk;
2325 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2326 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2332 /* FIXME: need to find out when the flags in uItemState need to be set */
2335 TREEVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
2336 TREEVIEW_ITEM *wineItem, UINT uItemDrawState)
2338 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2339 NMTVCUSTOMDRAW nmcdhdr;
2340 LPNMCUSTOMDRAW nmcd;
2341 DWORD dwDrawStage,dwItemSpec;
2344 dwDrawStage=CDDS_ITEM | uItemDrawState;
2345 dwItemSpec=(DWORD)wineItem->hItem;
2347 if (wineItem->hItem==infoPtr->selectedItem) uItemState|=CDIS_SELECTED;
2348 if (wineItem->hItem==infoPtr->focusItem) uItemState|=CDIS_FOCUS;
2349 if (wineItem->hItem==infoPtr->hotItem) uItemState|=CDIS_HOT;
2351 nmcd= & nmcdhdr.nmcd;
2352 nmcd->hdr.hwndFrom = hwnd;
2353 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2354 nmcd->hdr.code = NM_CUSTOMDRAW;
2355 nmcd->dwDrawStage= dwDrawStage;
2357 nmcd->rc.left = wineItem->rect.left;
2358 nmcd->rc.right = wineItem->rect.right;
2359 nmcd->rc.bottom = wineItem->rect.bottom;
2360 nmcd->rc.top = wineItem->rect.top;
2361 nmcd->dwItemSpec = dwItemSpec;
2362 nmcd->uItemState = uItemState;
2363 nmcd->lItemlParam= wineItem->lParam;
2365 nmcdhdr.clrText = infoPtr->clrText;
2366 nmcdhdr.clrTextBk= infoPtr->clrBk;
2367 nmcdhdr.iLevel = wineItem->iLevel;
2369 TRACE("drawstage:%lx hdc:%x item:%lx, itemstate:%x\n",
2370 dwDrawStage, hdc, dwItemSpec, uItemState);
2372 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2373 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2378 /* Note:If the specified item is the child of a collapsed parent item,
2379 the parent's list of child items is (recursively) expanded to reveal the
2380 specified item. This is mentioned for TREEVIEW_SelectItem; don't
2381 know if it also applies here.
2385 TREEVIEW_Expand (HWND hwnd, WPARAM wParam, LPARAM lParam)
2387 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2388 TREEVIEW_ITEM *wineItem;
2392 flag = (UINT) wParam;
2393 expand = (INT) lParam;
2395 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2399 if (!wineItem->cChildren)
2402 TRACE("For (%s) flags:%x item:%d state:%d\n",
2408 if (wineItem->cChildren==I_CHILDRENCALLBACK) {
2409 FIXME("we don't handle I_CHILDRENCALLBACK yet\n");
2413 if (flag == TVE_TOGGLE) { /* FIXME: check exact behaviour here */
2414 flag &= ~TVE_TOGGLE; /* ie: bitwise ops or 'case' ops */
2415 if (wineItem->state & TVIS_EXPANDED)
2416 flag |= TVE_COLLAPSE;
2423 case TVE_COLLAPSERESET:
2424 TRACE(" case TVE_COLLAPSERESET\n");
2425 if (!wineItem->state & TVIS_EXPANDED)
2428 wineItem->state &= ~(TVIS_EXPANDEDONCE | TVIS_EXPANDED);
2429 TREEVIEW_RemoveAllChildren (hwnd, wineItem);
2433 TRACE(" case TVE_COLLAPSE\n");
2434 if (!wineItem->state & TVIS_EXPANDED)
2437 wineItem->state &= ~TVIS_EXPANDED;
2441 TRACE(" case TVE_EXPAND\n");
2442 if (wineItem->state & TVIS_EXPANDED)
2445 TRACE(" is not expanded...\n");
2447 if (!(wineItem->state & TVIS_EXPANDEDONCE))
2449 TRACE(" and has never been expanded...\n");
2450 wineItem->state |= TVIS_EXPANDED;
2452 /* this item has never been expanded */
2453 if (TREEVIEW_SendTreeviewNotify (
2460 TRACE(" TVN_ITEMEXPANDING returned TRUE, exiting...\n");
2465 * Since the TVN_ITEMEXPANDING message may has caused the parent to
2466 * insert new items which in turn may have cause items placeholder
2467 * reallocation, I reassign the current item pointer so we have
2468 * something valid to work with...
2469 * However, this should not be necessary,
2470 * investigation required in TREEVIEW_InsertItemA
2472 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2476 "Catastropic situation, cannot retreive item #%d\n",
2481 wineItem->state |= TVIS_EXPANDEDONCE;
2482 TRACE(" TVN_ITEMEXPANDING sent...\n");
2484 TREEVIEW_SendTreeviewNotify (
2491 TRACE(" TVN_ITEMEXPANDED sent...\n");
2496 /* this item has already been expanded */
2497 wineItem->state |= TVIS_EXPANDED;
2501 case TVE_EXPANDPARTIAL:
2502 TRACE(" case TVE_EXPANDPARTIAL\n");
2503 FIXME("TVE_EXPANDPARTIAL not implemented\n");
2504 wineItem->state ^=TVIS_EXPANDED;
2505 wineItem->state |=TVIS_EXPANDEDONCE;
2509 TRACE("Exiting, Item %d state is now %d...\n",
2513 TREEVIEW_QueueRefresh (hwnd);
2519 static TREEVIEW_ITEM *
2520 TREEVIEW_HitTestPoint (HWND hwnd, POINT pt)
2522 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2523 TREEVIEW_ITEM *wineItem;
2526 GetClientRect (hwnd, &rect);
2528 if (!infoPtr->firstVisible) return NULL;
2530 wineItem=&infoPtr->items [(INT)infoPtr->firstVisible];
2532 while ((wineItem!=NULL) && (pt.y > wineItem->rect.bottom))
2533 wineItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
2545 TREEVIEW_HitTest (HWND hwnd, LPARAM lParam)
2547 LPTVHITTESTINFO lpht=(LPTVHITTESTINFO) lParam;
2548 TREEVIEW_ITEM *wineItem;
2552 GetClientRect (hwnd, &rect);
2556 if (x < rect.left) status|=TVHT_TOLEFT;
2557 if (x > rect.right) status|=TVHT_TORIGHT;
2558 if (y < rect.top ) status|=TVHT_ABOVE;
2559 if (y > rect.bottom) status|=TVHT_BELOW;
2566 wineItem=TREEVIEW_HitTestPoint (hwnd, lpht->pt);
2568 lpht->flags=TVHT_NOWHERE;
2572 /* FIXME: implement other flags
2573 * Assign the appropriate flags depending on the click location
2574 * Intitialize flags before to "|=" it...
2578 if (x < wineItem->expandBox.left)
2580 lpht->flags |= TVHT_ONITEMINDENT;
2582 else if ( ( x >= wineItem->expandBox.left) &&
2583 ( x <= wineItem->expandBox.right))
2585 lpht->flags |= TVHT_ONITEMBUTTON;
2587 else if (x < wineItem->rect.right)
2589 lpht->flags |= TVHT_ONITEMLABEL;
2593 lpht->flags|=TVHT_ONITEMRIGHT;
2596 lpht->hItem=wineItem->hItem;
2598 return (LRESULT) wineItem->hItem;
2602 TREEVIEW_EndEditLabelNow (HWND hwnd, WPARAM wParam, LPARAM lParam)
2604 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2605 TREEVIEW_ITEM *editedItem = TREEVIEW_ValidItem (infoPtr, infoPtr->editItem);
2606 BOOL bRevert = (BOOL)wParam;
2607 BOOL bReturn = ! bRevert;
2609 if ( ! (BOOL)wParam ) /* wParam is set to true to cancel the edition */
2611 if ( TREEVIEW_SendDispInfoNotify( /* return true to cancel edition */
2622 if (bRevert == FALSE) /* Apply the changes */
2625 int iLength = GetWindowTextA(infoPtr->hwndEdit, tmpText, 1023);
2630 ERR("Problem retreiving new item label.");
2632 else if (iLength >= 1023)
2635 "Insuficient space to retrieve new item label, new label ignored.");
2639 if (strcmp( tmpText, editedItem->pszText ) == 0)
2640 /* Do nothing if the label has not changed */
2644 LPSTR tmpLabel = COMCTL32_Alloc( iLength+1 );
2646 if ( tmpLabel == NULL )
2648 "OutOfMemory, cannot allocate space for label");
2651 COMCTL32_Free(editedItem->pszText);
2652 editedItem->pszText = tmpLabel;
2653 lstrcpyA( editedItem->pszText, tmpText);
2659 ShowWindow(infoPtr->hwndEdit, SW_HIDE);
2660 EnableWindow(infoPtr->hwndEdit, FALSE);
2661 infoPtr->editItem = 0;
2670 TREEVIEW_LButtonDoubleClick (HWND hwnd, WPARAM wParam, LPARAM lParam)
2672 TREEVIEW_ITEM *wineItem;
2676 pt.x = (INT)LOWORD(lParam);
2677 pt.y = (INT)HIWORD(lParam);
2680 wineItem=TREEVIEW_HitTestPoint (hwnd, pt);
2681 if (!wineItem) return 0;
2682 TRACE("item %d \n",(INT)wineItem->hItem);
2684 if (TREEVIEW_SendSimpleNotify (hwnd, NM_DBLCLK)!=TRUE) { /* FIXME!*/
2685 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) wineItem->hItem);
2692 TREEVIEW_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
2694 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2698 ht.pt.x = (INT)LOWORD(lParam);
2699 ht.pt.y = (INT)HIWORD(lParam);
2702 iItem=TREEVIEW_HitTest (hwnd, (LPARAM) &ht);
2703 TRACE("item %d \n",iItem);
2705 if (ht.flags & TVHT_ONITEMBUTTON) {
2706 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) iItem);
2710 infoPtr->uInternalStatus|=TV_LDRAG;
2717 TREEVIEW_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
2719 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2721 TREEVIEW_ITEM *editItem;
2724 ht.pt.x = (INT)LOWORD(lParam);
2725 ht.pt.y = (INT)HIWORD(lParam);
2729 /* Return true to cancel default behaviour */
2730 if ( TREEVIEW_SendSimpleNotify (hwnd, NM_CLICK) )
2734 iItem = TREEVIEW_HitTest (hwnd, (LPARAM) &ht);
2738 editItem = TREEVIEW_ValidItem(infoPtr, (HTREEITEM)iItem);
2740 infoPtr->uInternalStatus &= ~(TV_LDRAG | TV_LDRAGGING);
2743 * If the style allow editing and the node is already selected
2744 * and the click occured on the item label...
2746 if ( ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_EDITLABELS ) &&
2747 ( editItem->state & TVIS_SELECTED ) &&
2748 ( ht.flags & TVHT_ONITEMLABEL ))
2750 if ( infoPtr->editItem == 0 ) /* If we are not curently editing */
2752 if ( TREEVIEW_SendDispInfoNotify( /* Return true to cancel edition */
2761 TRACE("Edit started for %s.\n", editItem->pszText);
2762 infoPtr->editItem = editItem->hItem;
2767 editItem->text.left - 2,
2768 editItem->text.top - 1,
2769 editItem->text.right - editItem->text.left + 20 ,
2770 editItem->text.bottom - editItem->text.top + 3,
2773 SetWindowTextA( infoPtr->hwndEdit, editItem->pszText );
2774 SendMessageA ( infoPtr->hwndEdit, EM_SETSEL, 0, -1 );
2775 SetFocus ( infoPtr->hwndEdit);
2776 ShowWindow ( infoPtr->hwndEdit, SW_SHOW);
2779 else if ( infoPtr->editItem != 0 ) /* If we are curently editing */
2781 TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
2783 else if ( ht.flags & (TVHT_ONITEMLABEL | TVHT_ONITEMICON))
2785 TREEVIEW_DoSelectItem (
2797 TREEVIEW_RButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
2799 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2802 infoPtr->uInternalStatus|=TV_RDRAG;
2807 TREEVIEW_RButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
2809 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2812 if (TREEVIEW_SendSimpleNotify (hwnd, NM_RCLICK)) return 0;
2813 infoPtr->uInternalStatus&= ~(TV_RDRAG | TV_RDRAGGING);
2819 TREEVIEW_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
2821 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2822 TREEVIEW_ITEM *hotItem;
2825 pt.x=(INT) LOWORD (lParam);
2826 pt.y=(INT) HIWORD (lParam);
2827 hotItem=TREEVIEW_HitTestPoint (hwnd, pt);
2828 if (!hotItem) return 0;
2829 infoPtr->focusItem=hotItem->hItem;
2831 if ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_DISABLEDRAGDROP) return 0;
2833 if (infoPtr->uInternalStatus & TV_LDRAG) {
2834 TREEVIEW_SendTreeviewDnDNotify (hwnd, TVN_BEGINDRAG, hotItem->hItem, pt);
2835 infoPtr->uInternalStatus &= ~TV_LDRAG;
2836 infoPtr->uInternalStatus |= TV_LDRAGGING;
2837 infoPtr->dropItem=hotItem->hItem;
2841 if (infoPtr->uInternalStatus & TV_RDRAG) {
2842 TREEVIEW_SendTreeviewDnDNotify (hwnd, TVN_BEGINRDRAG, hotItem->hItem, pt);
2843 infoPtr->uInternalStatus &= ~TV_RDRAG;
2844 infoPtr->uInternalStatus |= TV_RDRAGGING;
2845 infoPtr->dropItem=hotItem->hItem;
2854 TREEVIEW_CreateDragImage (HWND hwnd, WPARAM wParam, LPARAM lParam)
2856 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2857 TREEVIEW_ITEM *dragItem;
2861 HBITMAP hbmp,hOldbmp;
2868 if (!(infoPtr->himlNormal)) return 0;
2869 dragItem=TREEVIEW_ValidItem (infoPtr, (HTREEITEM) lParam);
2871 if (!dragItem) return 0;
2872 itemtxt=dragItem->pszText;
2874 hwtop=GetDesktopWindow ();
2875 htopdc= GetDC (hwtop);
2876 hdc=CreateCompatibleDC (htopdc);
2878 hOldFont=SelectObject (hdc, infoPtr->hFont);
2879 GetTextExtentPoint32A (hdc, itemtxt, lstrlenA (itemtxt), &size);
2880 TRACE("%d %d %s %d\n",size.cx,size.cy,itemtxt,lstrlenA(itemtxt));
2881 hbmp=CreateCompatibleBitmap (htopdc, size.cx, size.cy);
2882 hOldbmp=SelectObject (hdc, hbmp);
2884 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &cy);
2886 if (cy>size.cy) size.cy=cy;
2888 infoPtr->dragList=ImageList_Create (size.cx, size.cy, ILC_COLOR, 10, 10);
2889 ImageList_Draw (infoPtr->himlNormal, dragItem->iImage, hdc, 0, 0, ILD_NORMAL);
2892 ImageList_GetImageInfo (infoPtr->himlNormal, dragItem->hItem, &iminfo);
2893 ImageList_AddMasked (infoPtr->dragList, iminfo.hbmImage, CLR_DEFAULT);
2896 /* draw item text */
2898 SetRect (&rc, cx, 0, size.cx,size.cy);
2899 DrawTextA (hdc, itemtxt, lstrlenA (itemtxt), &rc, DT_LEFT);
2900 SelectObject (hdc, hOldFont);
2901 SelectObject (hdc, hOldbmp);
2903 ImageList_Add (infoPtr->dragList, hbmp, 0);
2906 DeleteObject (hbmp);
2907 ReleaseDC (hwtop, htopdc);
2909 return (LRESULT)infoPtr->dragList;
2914 TREEVIEW_DoSelectItem (HWND hwnd, INT action, HTREEITEM newSelect, INT cause)
2917 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2918 TREEVIEW_ITEM *prevItem,*wineItem;
2921 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)newSelect);
2923 TRACE("Entering item %d, flag %x, cause %x, state %d\n",
2929 if ( (wineItem) && (wineItem->parent))
2932 * If the item has a collapse parent expand the parent so he
2933 * can expose the item
2935 TREEVIEW_ITEM *parentItem = TREEVIEW_ValidItem (infoPtr, wineItem->parent);
2936 if ( !(parentItem->state & TVIS_EXPANDED))
2937 TREEVIEW_Expand (hwnd, TVE_EXPAND, (LPARAM) wineItem->parent);
2943 prevSelect=(INT)infoPtr->selectedItem;
2945 if ((HTREEITEM)prevSelect==newSelect)
2948 prevItem= TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect);
2951 if (TREEVIEW_SendTreeviewNotify(
2955 (HTREEITEM)prevSelect,
2956 (HTREEITEM)newSelect))
2957 return FALSE; /* FIXME: OK? */
2960 prevItem->state &= ~TVIS_SELECTED;
2962 wineItem->state |= TVIS_SELECTED;
2964 infoPtr->selectedItem=(HTREEITEM)newSelect;
2966 TREEVIEW_SendTreeviewNotify(
2970 (HTREEITEM)prevSelect,
2971 (HTREEITEM)newSelect);
2975 case TVGN_DROPHILITE:
2976 prevItem= TREEVIEW_ValidItem (infoPtr, infoPtr->dropItem);
2979 prevItem->state &= ~TVIS_DROPHILITED;
2981 infoPtr->dropItem=(HTREEITEM)newSelect;
2984 wineItem->state |=TVIS_DROPHILITED;
2988 case TVGN_FIRSTVISIBLE:
2989 FIXME("FIRSTVISIBLE not implemented\n");
2993 TREEVIEW_QueueRefresh (hwnd);
2995 TRACE("Leaving state %d\n", wineItem->state);
2999 /* FIXME: handle NM_KILLFocus enzo */
3001 TREEVIEW_SelectItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
3004 return TREEVIEW_DoSelectItem (hwnd, wParam, (HTREEITEM) lParam, TVC_UNKNOWN);
3011 TREEVIEW_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
3014 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3016 TRACE("%x\n",infoPtr->hFont);
3017 return infoPtr->hFont;
3021 TREEVIEW_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
3024 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3027 HFONT hFont, hOldFont;
3031 TRACE("%x %lx\n",wParam, lParam);
3033 infoPtr->hFont = (HFONT)wParam;
3035 hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
3037 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
3038 logFont.lfWeight=FW_BOLD;
3039 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
3042 hOldFont = SelectObject (hdc, hFont);
3043 GetTextMetricsA (hdc, &tm);
3044 height= tm.tmHeight + tm.tmExternalLeading;
3045 if (height>infoPtr->uRealItemHeight)
3046 infoPtr->uRealItemHeight=height;
3047 SelectObject (hdc, hOldFont);
3051 TREEVIEW_QueueRefresh (hwnd);
3059 TREEVIEW_VScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
3062 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3065 TRACE("wp %x, lp %lx\n", wParam, lParam);
3066 if (!infoPtr->uInternalStatus & TV_VSCROLL) return FALSE;
3068 switch (LOWORD (wParam)) {
3070 if (!infoPtr->cy) return FALSE;
3071 infoPtr->cy -= infoPtr->uRealItemHeight;
3072 if (infoPtr->cy < 0) infoPtr->cy=0;
3075 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3076 if (infoPtr->cy == maxHeight) return FALSE;
3077 infoPtr->cy += infoPtr->uRealItemHeight;
3078 if (infoPtr->cy > maxHeight)
3079 infoPtr->cy = maxHeight;
3082 if (!infoPtr->cy) return FALSE;
3083 infoPtr->cy -= infoPtr->uVisibleHeight;
3084 if (infoPtr->cy < 0) infoPtr->cy=0;
3087 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3088 if (infoPtr->cy == maxHeight) return FALSE;
3089 infoPtr->cy += infoPtr->uVisibleHeight;
3090 if (infoPtr->cy > maxHeight)
3091 infoPtr->cy = maxHeight;
3094 infoPtr->cy = HIWORD (wParam);
3099 TREEVIEW_QueueRefresh (hwnd);
3104 TREEVIEW_HScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
3106 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3109 TRACE("wp %lx, lp %x\n", lParam, wParam);
3111 if (!infoPtr->uInternalStatus & TV_HSCROLL) return FALSE;
3113 switch (LOWORD (wParam)) {
3115 if (!infoPtr->cx) return FALSE;
3116 infoPtr->cx -= infoPtr->uRealItemHeight;
3117 if (infoPtr->cx < 0) infoPtr->cx=0;
3120 maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
3121 if (infoPtr->cx == maxWidth) return FALSE;
3122 infoPtr->cx += infoPtr->uRealItemHeight; /*FIXME */
3123 if (infoPtr->cx > maxWidth)
3124 infoPtr->cx = maxWidth;
3127 if (!infoPtr->cx) return FALSE;
3128 infoPtr->cx -= infoPtr->uVisibleWidth;
3129 if (infoPtr->cx < 0) infoPtr->cx=0;
3132 maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
3133 if (infoPtr->cx == maxWidth) return FALSE;
3134 infoPtr->cx += infoPtr->uVisibleWidth;
3135 if (infoPtr->cx > maxWidth)
3136 infoPtr->cx = maxWidth;
3139 infoPtr->cx = HIWORD (wParam);
3144 TREEVIEW_QueueRefresh (hwnd);
3150 TREEVIEW_KeyDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
3152 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3153 HTREEITEM hNewSelection = 0;
3154 INT scrollNeeds = -1;
3155 INT cyChangeNeeds = -1;
3156 INT prevSelect = (INT)infoPtr->selectedItem;
3158 TREEVIEW_ITEM *prevItem =
3159 (prevSelect != 0 ) ?
3160 TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect) :
3163 TREEVIEW_ITEM *newItem = NULL;
3165 TRACE("%x %lx\n",wParam, lParam);
3167 if (prevSelect == 0)
3172 newItem=TREEVIEW_GetPrevListItem (infoPtr, prevItem);
3175 newItem=& infoPtr->items[(INT)infoPtr->TopRootItem];
3177 hNewSelection = newItem->hItem;
3179 if (! newItem->visible)
3180 scrollNeeds = SB_LINEUP;
3185 newItem=TREEVIEW_GetNextListItem (infoPtr, prevItem);
3190 hNewSelection = newItem->hItem;
3192 if (! newItem->visible)
3193 scrollNeeds = SB_LINEDOWN;
3198 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem];
3199 hNewSelection = newItem->hItem;
3204 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem];
3205 newItem = TREEVIEW_GetLastListItem (infoPtr, newItem);
3206 hNewSelection = newItem->hItem;
3208 if (! newItem->visible)
3209 cyChangeNeeds = infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3214 if ( (prevItem->cChildren > 0) && (prevItem->state & TVIS_EXPANDED) )
3216 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect );
3218 else if ((INT)prevItem->parent)
3220 newItem = (& infoPtr->items[(INT)prevItem->parent]);
3221 if (! newItem->visible)
3222 /* FIXME find a way to make this item the first visible... */
3225 hNewSelection = newItem->hItem;
3231 if ( ( prevItem->cChildren > 0) ||
3232 ( prevItem->cChildren == I_CHILDRENCALLBACK))
3234 if (! (prevItem->state & TVIS_EXPANDED))
3235 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect );
3238 newItem = (& infoPtr->items[(INT)prevItem->firstChild]);
3239 hNewSelection = newItem->hItem;
3246 if (! (prevItem->state & TVIS_EXPANDED))
3247 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect );
3251 if (prevItem->state & TVIS_EXPANDED)
3252 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect );
3257 newItem=TREEVIEW_GetListItem(
3260 -1*(TREEVIEW_GetVisibleCount(hwnd,0,0)-3));
3264 hNewSelection = newItem->hItem;
3266 if (! newItem->visible)
3267 scrollNeeds = SB_PAGEUP;
3272 newItem=TREEVIEW_GetListItem(
3275 TREEVIEW_GetVisibleCount(hwnd,0,0)-3);
3280 hNewSelection = newItem->hItem;
3282 if (! newItem->visible)
3283 scrollNeeds = SB_PAGEDOWN;
3292 FIXME("%x not implemented\n", wParam);
3299 This works but does not send notification...
3301 prevItem->state &= ~TVIS_SELECTED;
3302 newItem->state |= TVIS_SELECTED;
3303 infoPtr->selectedItem = hNewSelection;
3304 TREEVIEW_QueueRefresh (hwnd);
3307 if ( TREEVIEW_DoSelectItem(
3310 (HTREEITEM)hNewSelection,
3313 /* If selection change is allowed for the new item, perform scrolling */
3314 if (scrollNeeds != -1)
3315 TREEVIEW_VScroll(hwnd, scrollNeeds, 0);
3317 if (cyChangeNeeds != -1)
3318 infoPtr->cy = cyChangeNeeds;
3320 /* FIXME: Something happen in the load the in the two weeks before
3321 april 1st 1999 which makes this SetFocus mandatory otherwise, the focus
3322 is lost... However the SetFocus should not be required...*/
3333 TREEVIEW_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3336 case TVM_INSERTITEMA:
3337 return TREEVIEW_InsertItemA (hwnd, wParam, lParam);
3339 case TVM_INSERTITEMW:
3340 FIXME("Unimplemented msg TVM_INSERTITEM32W\n");
3343 case TVM_DELETEITEM:
3344 return TREEVIEW_DeleteItem (hwnd, wParam, lParam);
3347 return TREEVIEW_Expand (hwnd, wParam, lParam);
3349 case TVM_GETITEMRECT:
3350 return TREEVIEW_GetItemRect (hwnd, wParam, lParam);
3353 return TREEVIEW_GetCount (hwnd, wParam, lParam);
3356 return TREEVIEW_GetIndent (hwnd);
3359 return TREEVIEW_SetIndent (hwnd, wParam);
3361 case TVM_GETIMAGELIST:
3362 return TREEVIEW_GetImageList (hwnd, wParam, lParam);
3364 case TVM_SETIMAGELIST:
3365 return TREEVIEW_SetImageList (hwnd, wParam, lParam);
3367 case TVM_GETNEXTITEM:
3368 return TREEVIEW_GetNextItem (hwnd, wParam, lParam);
3370 case TVM_SELECTITEM:
3371 return TREEVIEW_SelectItem (hwnd, wParam, lParam);
3374 return TREEVIEW_GetItemA (hwnd, wParam, lParam);
3377 FIXME("Unimplemented msg TVM_GETITEM32W\n");
3381 return TREEVIEW_SetItemA (hwnd, wParam, lParam);
3384 FIXME("Unimplemented msg TVM_SETITEMW\n");
3387 case TVM_EDITLABELA:
3388 FIXME("Unimplemented msg TVM_EDITLABEL32A \n");
3391 case TVM_EDITLABELW:
3392 FIXME("Unimplemented msg TVM_EDITLABEL32W \n");
3395 case TVM_GETEDITCONTROL:
3396 return TREEVIEW_GetEditControl (hwnd);
3398 case TVM_GETVISIBLECOUNT:
3399 return TREEVIEW_GetVisibleCount (hwnd, wParam, lParam);
3402 return TREEVIEW_HitTest (hwnd, lParam);
3404 case TVM_CREATEDRAGIMAGE:
3405 return TREEVIEW_CreateDragImage (hwnd, wParam, lParam);
3407 case TVM_SORTCHILDREN:
3408 FIXME("Unimplemented msg TVM_SORTCHILDREN\n");
3411 case TVM_ENSUREVISIBLE:
3412 FIXME("Unimplemented msg TVM_ENSUREVISIBLE\n");
3415 case TVM_SORTCHILDRENCB:
3416 return TREEVIEW_SortChildrenCB(hwnd, wParam, lParam);
3418 case TVM_ENDEDITLABELNOW:
3419 return TREEVIEW_EndEditLabelNow (hwnd, wParam, lParam);
3421 case TVM_GETISEARCHSTRINGA:
3422 FIXME("Unimplemented msg TVM_GETISEARCHSTRING32A\n");
3425 case TVM_GETISEARCHSTRINGW:
3426 FIXME("Unimplemented msg TVM_GETISEARCHSTRING32W\n");
3429 case TVM_GETTOOLTIPS:
3430 return TREEVIEW_GetToolTips (hwnd);
3432 case TVM_SETTOOLTIPS:
3433 return TREEVIEW_SetToolTips (hwnd, wParam);
3435 case TVM_SETINSERTMARK:
3436 FIXME("Unimplemented msg TVM_SETINSERTMARK\n");
3439 case TVM_SETITEMHEIGHT:
3440 return TREEVIEW_SetItemHeight (hwnd, wParam);
3442 case TVM_GETITEMHEIGHT:
3443 return TREEVIEW_GetItemHeight (hwnd);
3445 case TVM_SETBKCOLOR:
3446 return TREEVIEW_SetBkColor (hwnd, wParam, lParam);
3448 case TVM_SETTEXTCOLOR:
3449 return TREEVIEW_SetTextColor (hwnd, wParam, lParam);
3451 case TVM_GETBKCOLOR:
3452 return TREEVIEW_GetBkColor (hwnd);
3454 case TVM_GETTEXTCOLOR:
3455 return TREEVIEW_GetTextColor (hwnd);
3457 case TVM_SETSCROLLTIME:
3458 FIXME("Unimplemented msg TVM_SETSCROLLTIME\n");
3461 case TVM_GETSCROLLTIME:
3462 FIXME("Unimplemented msg TVM_GETSCROLLTIME\n");
3465 case TVM_SETINSERTMARKCOLOR:
3466 FIXME("Unimplemented msg TVM_SETINSERTMARKCOLOR\n");
3469 case TVM_SETUNICODEFORMAT:
3470 FIXME("Unimplemented msg TVM_SETUNICODEFORMAT\n");
3473 case TVM_GETUNICODEFORMAT:
3474 FIXME("Unimplemented msg TVM_GETUNICODEFORMAT\n");
3478 return TREEVIEW_Command (hwnd, wParam, lParam);
3481 return TREEVIEW_Create (hwnd, wParam, lParam);
3484 return TREEVIEW_Destroy (hwnd);
3486 /* case WM_ENABLE: */
3489 return TREEVIEW_EraseBackground (hwnd, wParam, lParam);
3492 return DLGC_WANTARROWS | DLGC_WANTCHARS;
3495 return TREEVIEW_Paint (hwnd, wParam, lParam);
3498 return TREEVIEW_GetFont (hwnd, wParam, lParam);
3501 return TREEVIEW_SetFont (hwnd, wParam, lParam);
3504 return TREEVIEW_KeyDown (hwnd, wParam, lParam);
3508 return TREEVIEW_SetFocus (hwnd, wParam, lParam);
3511 return TREEVIEW_KillFocus (hwnd, wParam, lParam);
3514 case WM_LBUTTONDOWN:
3515 return TREEVIEW_LButtonDown (hwnd, wParam, lParam);
3518 return TREEVIEW_LButtonUp (hwnd, wParam, lParam);
3520 case WM_LBUTTONDBLCLK:
3521 return TREEVIEW_LButtonDoubleClick (hwnd, wParam, lParam);
3523 case WM_RBUTTONDOWN:
3524 return TREEVIEW_RButtonDown (hwnd, wParam, lParam);
3527 return TREEVIEW_RButtonUp (hwnd, wParam, lParam);
3530 return TREEVIEW_MouseMove (hwnd, wParam, lParam);
3533 /* case WM_SYSCOLORCHANGE: */
3534 case WM_STYLECHANGED:
3535 return TREEVIEW_StyleChanged (hwnd, wParam, lParam);
3537 /* case WM_SETREDRAW: */
3540 return TREEVIEW_HandleTimer (hwnd, wParam, lParam);
3543 return TREEVIEW_Size (hwnd, wParam,lParam);
3546 return TREEVIEW_HScroll (hwnd, wParam, lParam);
3548 return TREEVIEW_VScroll (hwnd, wParam, lParam);
3551 printf ("drawItem\n");
3552 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
3555 if (uMsg >= WM_USER)
3556 FIXME("Unknown msg %04x wp=%08x lp=%08lx\n",
3557 uMsg, wParam, lParam);
3558 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
3565 TREEVIEW_Register (VOID)
3571 if (GlobalFindAtomA (WC_TREEVIEWA)) return;
3573 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
3574 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
3575 wndClass.lpfnWndProc = (WNDPROC)TREEVIEW_WindowProc;
3576 wndClass.cbClsExtra = 0;
3577 wndClass.cbWndExtra = sizeof(TREEVIEW_INFO *);
3578 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
3579 wndClass.hbrBackground = 0;
3580 wndClass.lpszClassName = WC_TREEVIEWA;
3582 RegisterClassA (&wndClass);
3587 TREEVIEW_Unregister (VOID)
3589 if (GlobalFindAtomA (WC_TREEVIEWA))
3590 UnregisterClassA (WC_TREEVIEWA, (HINSTANCE)NULL);