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
1151 tvItem->lParam=wineItem->lParam;
1153 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
1154 tvItem->iSelectedImage=wineItem->iSelectedImage;
1157 if (tvItem->mask & TVIF_STATE) {
1158 tvItem->state=wineItem->state & tvItem->stateMask;
1161 if (tvItem->mask & TVIF_TEXT) {
1162 if (wineItem->pszText == LPSTR_TEXTCALLBACKA) {
1163 tvItem->pszText = LPSTR_TEXTCALLBACKA; /* FIXME:send notification? */
1164 ERR(" GetItem called with LPSTR_TEXTCALLBACK\n");
1166 else if (wineItem->pszText) {
1167 lstrcpynA (tvItem->pszText, wineItem->pszText, tvItem->cchTextMax);
1171 TRACE("item %d<%p>, txt %p, img %p, action %x\n",
1183 /* FIXME: check implementation of TVGN_NEXT/TVGN_NEXTVISIBLE */
1186 TREEVIEW_GetNextItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
1189 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1190 TREEVIEW_ITEM *wineItem, *returnItem;
1191 INT iItem, retval, flag;
1194 if (!infoPtr) return FALSE;
1195 flag = (INT) wParam;
1196 iItem = (INT) lParam;
1199 case TVGN_ROOT: retval=(INT)infoPtr->TopRootItem;
1201 case TVGN_CARET:retval=(INT)infoPtr->selectedItem;
1203 case TVGN_FIRSTVISIBLE:
1204 TREEVIEW_Refresh (hwnd);
1205 /* FIXME:we should only recalculate, not redraw */
1206 retval=(INT)infoPtr->firstVisible;
1208 case TVGN_DROPHILITE:
1209 retval=(INT)infoPtr->dropItem;
1213 TRACE("flags:%x, returns %u\n", flag, retval);
1217 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1219 if (!wineItem) return FALSE;
1222 case TVGN_NEXT: retval=(INT)wineItem->sibling;
1225 retval=(INT)wineItem->upsibling;
1228 retval=(INT)wineItem->parent;
1231 retval=(INT)wineItem->firstChild;
1233 case TVGN_LASTVISIBLE:
1234 returnItem=TREEVIEW_GetLastListItem (infoPtr,wineItem);
1236 case TVGN_NEXTVISIBLE:
1237 returnItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
1239 case TVGN_PREVIOUSVISIBLE:
1240 returnItem=TREEVIEW_GetPrevListItem (infoPtr, wineItem);
1242 default: FIXME("Unknown msg %x,item %x\n", flag,iItem);
1247 TRACE("flags:%x, item %d;returns %d\n", flag, iItem,
1248 (INT)returnItem->hItem);
1249 return (INT)returnItem->hItem;
1252 TRACE("flags:%x, item %d;returns %d\n", flag, iItem,retval);
1258 TREEVIEW_GetCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
1260 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1262 TRACE(" %d\n",infoPtr->uNumItems);
1263 return (LRESULT) infoPtr->uNumItems;
1266 /***************************************************************************
1267 * This method does the chaining of the insertion of a treeview item
1270 static void TREEVIEW_InsertBefore(
1271 TREEVIEW_INFO *infoPtr,
1272 TREEVIEW_ITEM *newItem,
1273 TREEVIEW_ITEM *sibling,
1274 TREEVIEW_ITEM *parent)
1276 HTREEITEM siblingHandle = 0;
1277 HTREEITEM upSiblingHandle = 0;
1278 TREEVIEW_ITEM *upSibling = NULL;
1280 if (newItem == NULL)
1281 ERR("NULL newItem, impossible condition\n");
1284 ERR("NULL parent, impossible condition\n");
1286 if (sibling != NULL) /* Insert before this sibling for this parent */
1288 /* Store the new item sibling up sibling and sibling tem handle */
1289 siblingHandle = sibling->hItem;
1290 upSiblingHandle = sibling->upsibling;
1291 /* As well as a pointer to the upsibling sibling object */
1292 if ( (INT)sibling->upsibling != 0 )
1293 upSibling = &infoPtr->items[(INT)sibling->upsibling];
1295 /* Adjust the sibling pointer */
1296 sibling->upsibling = newItem->hItem;
1298 /* Adjust the new item pointers */
1299 newItem->upsibling = upSiblingHandle;
1300 newItem->sibling = siblingHandle;
1302 /* Adjust the up sibling pointer */
1303 if ( upSibling != NULL )
1304 upSibling->sibling = newItem->hItem;
1306 /* this item is the first child of this parent, adjust parent pointers */
1307 parent->firstChild = newItem->hItem;
1309 else /* Insert as first child of this parent */
1310 parent->firstChild = newItem->hItem;
1313 /***************************************************************************
1314 * This method does the chaining of the insertion of a treeview item
1317 static void TREEVIEW_InsertAfter(
1318 TREEVIEW_INFO *infoPtr,
1319 TREEVIEW_ITEM *newItem,
1320 TREEVIEW_ITEM *upSibling,
1321 TREEVIEW_ITEM *parent)
1323 HTREEITEM upSiblingHandle = 0;
1324 HTREEITEM siblingHandle = 0;
1325 TREEVIEW_ITEM *sibling = NULL;
1327 if (newItem == NULL)
1328 ERR("NULL newItem, impossible condition\n");
1331 ERR("NULL parent, impossible condition\n");
1333 if (upSibling != NULL) /* Insert after this upsibling for this parent */
1335 /* Store the new item up sibling and sibling item handle */
1336 upSiblingHandle = upSibling->hItem;
1337 siblingHandle = upSibling->sibling;
1338 /* As well as a pointer to the upsibling sibling object */
1339 if ( (INT)upSibling->sibling != 0 )
1340 sibling = &infoPtr->items[(INT)upSibling->sibling];
1342 /* Adjust the up sibling pointer */
1343 upSibling->sibling = newItem->hItem;
1345 /* Adjust the new item pointers */
1346 newItem->upsibling = upSiblingHandle;
1347 newItem->sibling = siblingHandle;
1349 /* Adjust the sibling pointer */
1350 if ( sibling != NULL )
1351 sibling->upsibling = newItem->hItem;
1354 newItem is the last of the level, nothing else to do
1357 else /* Insert as first child of this parent */
1358 parent->firstChild = newItem->hItem;
1361 /***************************************************************************
1362 * Forward the DPA local callback to the treeview owner callback
1364 static INT WINAPI TREEVIEW_CallBackCompare(
1369 /* Forward the call to the client define callback */
1370 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr((HWND)tvInfoPtr);
1371 return (infoPtr->pCallBackSort->lpfnCompare)(
1372 ((TREEVIEW_ITEM*)first)->lParam,
1373 ((TREEVIEW_ITEM*)second)->lParam,
1374 infoPtr->pCallBackSort->lParam);
1377 /***************************************************************************
1378 * Setup the treeview structure with regards of the sort method
1379 * and sort the children of the TV item specified in lParam
1381 LRESULT WINAPI TREEVIEW_SortChildrenCB(
1386 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1387 TREEVIEW_ITEM *sortMe = NULL; /* Node for which we sort the children */
1389 /* Obtain the TVSORTBC struct */
1390 infoPtr->pCallBackSort = (LPTVSORTCB)lParam;
1392 /* Obtain the parent node to sort */
1393 sortMe = &infoPtr->items[ (INT)infoPtr->pCallBackSort->hParent ];
1395 /* Make sure there is something to sort */
1396 if ( sortMe->cChildren > 1 )
1398 /* pointer organization */
1399 HDPA sortList = DPA_Create(sortMe->cChildren);
1400 HTREEITEM itemHandle = sortMe->firstChild;
1401 TREEVIEW_ITEM *itemPtr = & infoPtr->items[ (INT)itemHandle ];
1403 /* TREEVIEW_ITEM rechaining */
1409 /* Build the list of item to sort */
1413 sortList, /* the list */
1414 sortMe->cChildren+1, /* force the insertion to be an append */
1415 itemPtr); /* the ptr to store */
1417 /* Get the next sibling */
1418 itemHandle = itemPtr->sibling;
1419 itemPtr = & infoPtr->items[ (INT)itemHandle ];
1420 } while ( itemHandle != NULL );
1422 /* let DPA perform the sort activity */
1424 sortList, /* what */
1425 TREEVIEW_CallBackCompare, /* how */
1429 * Reorganized TREEVIEW_ITEM structures.
1430 * Note that we know we have at least two elements.
1433 /* Get the first item and get ready to start... */
1434 item = DPA_GetPtr(sortList, count++);
1435 while ( (nextItem = DPA_GetPtr(sortList, count++)) != NULL )
1437 /* link the two current item toghether */
1438 ((TREEVIEW_ITEM*)item)->sibling = ((TREEVIEW_ITEM*)nextItem)->hItem;
1439 ((TREEVIEW_ITEM*)nextItem)->upsibling = ((TREEVIEW_ITEM*)item)->hItem;
1441 if (prevItem == NULL) /* this is the first item, update the parent */
1443 sortMe->firstChild = ((TREEVIEW_ITEM*)item)->hItem;
1444 ((TREEVIEW_ITEM*)item)->upsibling = NULL;
1446 else /* fix the back chaining */
1448 ((TREEVIEW_ITEM*)item)->upsibling = ((TREEVIEW_ITEM*)prevItem)->hItem;
1451 /* get ready for the next one */
1456 /* the last item is pointed to by item and never has a sibling */
1457 ((TREEVIEW_ITEM*)item)->sibling = NULL;
1459 DPA_Destroy(sortList);
1467 /* the method used below isn't the most memory-friendly, but it avoids
1468 a lot of memory reallocations */
1470 /* BTW: we waste handle 0; 0 is not an allowed handle. */
1473 TREEVIEW_InsertItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1476 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1477 TVINSERTSTRUCTA *ptdi;
1479 TREEVIEW_ITEM *wineItem, *parentItem, *prevsib, *sibItem;
1480 INT iItem,listItems,i,len;
1482 /* Item to insert */
1483 ptdi = (LPTVINSERTSTRUCTA) lParam;
1485 /* check if memory is available */
1487 if (infoPtr->uNumPtrsAlloced==0) {
1488 infoPtr->items = COMCTL32_Alloc (TVITEM_ALLOC*sizeof (TREEVIEW_ITEM));
1489 infoPtr->freeList= COMCTL32_Alloc ((1+(TVITEM_ALLOC>>5)) * sizeof (INT));
1490 infoPtr->uNumPtrsAlloced=TVITEM_ALLOC;
1491 infoPtr->TopRootItem=(HTREEITEM)1;
1495 * Reallocate contiguous space for items
1497 if (infoPtr->uNumItems == (infoPtr->uNumPtrsAlloced-1) ) {
1498 TREEVIEW_ITEM *oldItems = infoPtr->items;
1499 INT *oldfreeList = infoPtr->freeList;
1501 infoPtr->uNumPtrsAlloced*=2;
1502 infoPtr->items = COMCTL32_Alloc (infoPtr->uNumPtrsAlloced*sizeof (TREEVIEW_ITEM));
1503 infoPtr->freeList= COMCTL32_Alloc ((1+(infoPtr->uNumPtrsAlloced>>5))*sizeof (INT));
1505 memcpy (&infoPtr->items[0], &oldItems[0],
1506 infoPtr->uNumPtrsAlloced/2 * sizeof(TREEVIEW_ITEM));
1507 memcpy (&infoPtr->freeList[0], &oldfreeList[0],
1508 (infoPtr->uNumPtrsAlloced>>6) * sizeof(INT));
1510 COMCTL32_Free (oldItems);
1511 COMCTL32_Free (oldfreeList);
1515 * Reset infoPtr structure with new stat according to current TV picture
1518 infoPtr->uNumItems++;
1519 if ((INT)infoPtr->uMaxHandle==(infoPtr->uNumItems-1)) {
1520 iItem=infoPtr->uNumItems;
1521 infoPtr->uMaxHandle = (HTREEITEM)((INT)infoPtr->uMaxHandle + 1);
1522 } else { /* check freelist */
1523 for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++) {
1524 if (infoPtr->freeList[i]) {
1525 iItem=ffs (infoPtr->freeList[i])-1;
1526 tv_clear_bit(iItem,&infoPtr->freeList[i]);
1533 if (TRACE_ON(treeview)) {
1534 for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++)
1535 TRACE("%8x\n",infoPtr->freeList[i]);
1538 if (!iItem) ERR("Argh -- can't find free item.\n");
1541 * Find the parent item of the new item
1543 tvItem= & ptdi->DUMMYUNIONNAME.itemex;
1544 wineItem=& infoPtr->items[iItem];
1546 if ((ptdi->hParent==TVI_ROOT) || (ptdi->hParent==0)) {
1548 wineItem->parent = 0;
1549 sibItem = &infoPtr->items [(INT)infoPtr->TopRootItem];
1550 listItems = infoPtr->uNumItems;
1553 parentItem = &infoPtr->items[(INT)ptdi->hParent];
1555 /* Do the insertion here it if it's the only item of this parent */
1556 if (!parentItem->firstChild)
1557 parentItem->firstChild=(HTREEITEM)iItem;
1559 wineItem->parent = ptdi->hParent;
1560 sibItem = &infoPtr->items [(INT)parentItem->firstChild];
1561 parentItem->cChildren++;
1562 listItems = parentItem->cChildren;
1566 /* NOTE: I am moving some setup of the wineItem object that was initialy
1567 * done at the end of the function since some of the values are
1568 * required by the Callback sorting
1571 if (tvItem->mask & TVIF_TEXT)
1574 * Setup the item text stuff here since it's required by the Sort method
1575 * when the insertion are ordered
1577 if (tvItem->pszText!=LPSTR_TEXTCALLBACKA)
1579 TRACE("(%p,%s)\n", &tvItem->pszText, tvItem->pszText);
1580 len = lstrlenA (tvItem->pszText)+1;
1581 wineItem->pszText= COMCTL32_Alloc (len+1);
1582 lstrcpyA (wineItem->pszText, tvItem->pszText);
1583 wineItem->cchTextMax=len;
1587 TRACE("LPSTR_TEXTCALLBACK\n");
1588 wineItem->pszText = LPSTR_TEXTCALLBACKA;
1589 wineItem->cchTextMax = 0;
1593 if (tvItem->mask & TVIF_PARAM)
1594 wineItem->lParam=tvItem->lParam;
1597 wineItem->upsibling=0; /* needed in case we're the first item in a list */
1598 wineItem->sibling=0;
1599 wineItem->firstChild=0;
1600 wineItem->hItem=(HTREEITEM)iItem;
1605 switch ((DWORD) ptdi->hInsertAfter) {
1606 case (DWORD) TVI_FIRST:
1607 if (wineItem->parent) {
1608 wineItem->sibling=parentItem->firstChild;
1609 parentItem->firstChild=(HTREEITEM)iItem;
1611 wineItem->sibling=infoPtr->TopRootItem;
1612 infoPtr->TopRootItem=(HTREEITEM)iItem;
1614 sibItem->upsibling=(HTREEITEM)iItem;
1617 case (DWORD) TVI_SORT:
1618 if (sibItem==wineItem)
1620 * This item is the first child of the level and it
1621 * has already been inserted
1626 TREEVIEW_ITEM *aChild =
1627 &infoPtr->items[(INT)parentItem->firstChild];
1629 TREEVIEW_ITEM *previousChild = NULL;
1630 BOOL bItemInserted = FALSE;
1632 /* Iterate the parent children to see where we fit in */
1633 while ( aChild != NULL )
1635 INT comp = strcmp(wineItem->pszText, aChild->pszText);
1636 if ( comp < 0 ) /* we are smaller than the current one */
1638 TREEVIEW_InsertBefore(infoPtr, wineItem, aChild, parentItem);
1639 bItemInserted = TRUE;
1642 else if ( comp > 0 ) /* we are bigger than the current one */
1644 previousChild = aChild;
1645 aChild = (aChild->sibling == 0) /* This will help us to exit */
1646 ? NULL /* if there is no more sibling */
1647 : &infoPtr->items[(INT)aChild->sibling];
1649 /* Look at the next item */
1652 else if ( comp == 0 )
1655 * An item with this name is already existing, therefore,
1656 * we add after the one we found
1658 TREEVIEW_InsertAfter(infoPtr, wineItem, aChild, parentItem);
1659 bItemInserted = TRUE;
1665 * we reach the end of the child list and the item as not
1666 * yet been inserted, therefore, insert it after the last child.
1668 if ( (! bItemInserted ) && (aChild == NULL) )
1669 TREEVIEW_InsertAfter(infoPtr, wineItem, previousChild, parentItem);
1675 case (DWORD) TVI_LAST:
1676 if (sibItem==wineItem) break;
1677 while (sibItem->sibling) {
1679 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1681 sibItem->sibling=(HTREEITEM)iItem;
1682 wineItem->upsibling=sibItem->hItem;
1685 while ((sibItem->sibling) && (sibItem->hItem!=ptdi->hInsertAfter))
1688 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1690 if (sibItem->hItem!=ptdi->hInsertAfter) {
1691 ERR("tried to insert item after nonexisting handle.\n");
1695 if (sibItem->sibling) {
1696 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1697 sibItem->upsibling=(HTREEITEM)iItem;
1698 wineItem->sibling=sibItem->hItem;
1700 prevsib->sibling=(HTREEITEM)iItem;
1701 wineItem->upsibling=prevsib->hItem;
1707 /* Fill in info structure */
1709 TRACE("new item %d; parent %d, mask %x\n", iItem,
1710 (INT)wineItem->parent,tvItem->mask);
1712 wineItem->mask=tvItem->mask;
1713 wineItem->iIntegral=1;
1715 if (tvItem->mask & TVIF_CHILDREN) {
1716 wineItem->cChildren=tvItem->cChildren;
1717 if (tvItem->cChildren==I_CHILDRENCALLBACK)
1718 FIXME(" I_CHILDRENCALLBACK not supported\n");
1721 wineItem->expandBox.left = 0; /* Initialize the expandBox */
1722 wineItem->expandBox.top = 0;
1723 wineItem->expandBox.right = 0;
1724 wineItem->expandBox.bottom = 0;
1726 if (tvItem->mask & TVIF_IMAGE)
1727 wineItem->iImage=tvItem->iImage;
1729 /* If the application sets TVIF_INTEGRAL without
1730 supplying a TVITEMEX structure, it's toast */
1732 if (tvItem->mask & TVIF_INTEGRAL)
1733 wineItem->iIntegral=tvItem->iIntegral;
1735 if (tvItem->mask & TVIF_SELECTEDIMAGE)
1736 wineItem->iSelectedImage=tvItem->iSelectedImage;
1738 if (tvItem->mask & TVIF_STATE) {
1739 TRACE("Changing item state from %d to %d\n",
1742 wineItem->state=tvItem->state;
1743 wineItem->stateMask=tvItem->stateMask;
1747 TREEVIEW_QueueRefresh (hwnd);
1749 return (LRESULT) iItem;
1757 TREEVIEW_DeleteItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
1759 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1761 TREEVIEW_ITEM *wineItem;
1764 if (!infoPtr) return FALSE;
1766 if (lParam == (INT)TVI_ROOT) {
1767 TREEVIEW_RemoveTree (hwnd);
1769 iItem= (INT) lParam;
1770 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1771 if (!wineItem) return FALSE;
1772 TRACE("%s\n",wineItem->pszText);
1773 TREEVIEW_RemoveItem (hwnd, wineItem);
1776 TREEVIEW_QueueRefresh (hwnd);
1784 TREEVIEW_GetIndent (HWND hwnd)
1786 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1789 return infoPtr->uIndent;
1793 TREEVIEW_SetIndent (HWND hwnd, WPARAM wParam)
1795 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1799 newIndent=(INT) wParam;
1800 if (newIndent < MINIMUM_INDENT) newIndent=MINIMUM_INDENT;
1801 infoPtr->uIndent=newIndent;
1807 TREEVIEW_GetToolTips (HWND hwnd)
1810 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1813 return infoPtr->hwndToolTip;
1818 TREEVIEW_SetToolTips (HWND hwnd, WPARAM wParam)
1821 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1825 prevToolTip=infoPtr->hwndToolTip;
1826 infoPtr->hwndToolTip= (HWND) wParam;
1833 TREEVIEW_GetEditControl (HWND hwnd)
1836 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1838 return infoPtr->hwndEdit;
1842 TREEVIEW_Edit_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam,
1850 HDC hdc = (HDC) wParam;
1851 GetClientRect (hwnd, &rc);
1852 Rectangle (hdc, rc.left, rc.top, rc.right, rc.bottom);
1858 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
1863 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd));
1864 return CallWindowProcA( infoPtr->wpEditOrig, hwnd, uMsg, wParam, lParam);
1872 /* should handle edit control messages here */
1875 TREEVIEW_Command (HWND hwnd, WPARAM wParam, LPARAM lParam)
1878 TRACE("%x %ld\n",wParam, lParam);
1880 switch (HIWORD(wParam))
1885 * Adjust the edit window size
1887 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1888 TREEVIEW_ITEM *editItem = TREEVIEW_ValidItem(infoPtr, infoPtr->editItem);
1889 INT iLength = GetWindowTextLengthA(infoPtr->hwndEdit);
1890 HDC hdc = GetDC(infoPtr->hwndEdit);
1893 if ( GetTextMetricsA(hdc, &tm) )
1895 LONG newWidth = (iLength * tm.tmAveCharWidth) + 15;
1900 editItem->text.left - 2,
1901 editItem->text.top - 1,
1903 editItem->text.bottom - editItem->text.top + 3,
1906 ReleaseDC(hwnd, hdc);
1912 /* TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
1917 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
1924 TREEVIEW_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
1927 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1929 if (infoPtr->bAutoSize)
1931 infoPtr->bAutoSize = FALSE;
1934 infoPtr->bAutoSize = TRUE;
1936 if (wParam == SIZE_RESTORED)
1938 infoPtr->uTotalWidth = LOWORD (lParam);
1939 infoPtr->uTotalHeight = HIWORD (lParam);
1941 FIXME("WM_SIZE flag %x %lx not handled\n", wParam, lParam);
1944 TREEVIEW_QueueRefresh (hwnd);
1951 TREEVIEW_StyleChanged (HWND hwnd, WPARAM wParam, LPARAM lParam)
1953 LPSTYLESTRUCT lpss=(LPSTYLESTRUCT) lParam;
1955 TRACE("(%x %lx)\n",wParam,lParam);
1957 if (wParam & (GWL_STYLE))
1958 SetWindowLongA( hwnd, GWL_STYLE, lpss->styleNew);
1959 if (wParam & (GWL_EXSTYLE))
1960 SetWindowLongA( hwnd, GWL_STYLE, lpss->styleNew);
1966 TREEVIEW_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
1968 TREEVIEW_INFO *infoPtr;
1973 TRACE("wnd %x\n",hwnd);
1974 /* allocate memory for info structure */
1975 infoPtr = (TREEVIEW_INFO *) COMCTL32_Alloc (sizeof(TREEVIEW_INFO));
1977 SetWindowLongA( hwnd, 0, (DWORD)infoPtr);
1979 if (infoPtr == NULL) {
1980 ERR("could not allocate info memory!\n");
1984 if ((TREEVIEW_INFO*) GetWindowLongA( hwnd, 0) != infoPtr) {
1985 ERR("pointer assignment error!\n");
1991 /* set default settings */
1992 infoPtr->uInternalStatus=0;
1993 infoPtr->uNumItems=0;
1994 infoPtr->clrBk = GetSysColor (COLOR_WINDOW);
1995 infoPtr->clrText = GetSysColor (COLOR_BTNTEXT);
1998 infoPtr->uIndent = 15;
1999 infoPtr->himlNormal = NULL;
2000 infoPtr->himlState = NULL;
2001 infoPtr->uItemHeight = -1;
2002 GetTextMetricsA (hdc, &tm);
2003 infoPtr->hFont = GetStockObject (DEFAULT_GUI_FONT);
2004 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
2005 logFont.lfWeight=FW_BOLD;
2006 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
2008 infoPtr->items = NULL;
2009 infoPtr->selectedItem=0;
2010 infoPtr->clrText=-1; /* use system color */
2011 infoPtr->dropItem=0;
2012 infoPtr->pCallBackSort=NULL;
2015 infoPtr->hwndNotify = GetParent32 (hwnd);
2016 infoPtr->bTransparent = ( GetWindowLongA( hwnd, GWL_STYLE) & TBSTYLE_FLAT);
2019 infoPtr->hwndToolTip=0;
2020 if (!( GetWindowLongA( hwnd, GWL_STYLE) & TVS_NOTOOLTIPS)) { /* Create tooltip control */
2023 infoPtr->hwndToolTip =
2024 CreateWindowExA (0, TOOLTIPS_CLASSA, NULL, 0,
2025 CW_USEDEFAULT, CW_USEDEFAULT,
2026 CW_USEDEFAULT, CW_USEDEFAULT,
2029 /* Send NM_TOOLTIPSCREATED notification */
2030 if (infoPtr->hwndToolTip) {
2031 NMTOOLTIPSCREATED nmttc;
2033 nmttc.hdr.hwndFrom = hwnd;
2034 nmttc.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2035 nmttc.hdr.code = NM_TOOLTIPSCREATED;
2036 nmttc.hwndToolTips = infoPtr->hwndToolTip;
2038 SendMessageA (GetParent (hwnd), WM_NOTIFY,
2039 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmttc);
2042 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
2043 ti.cbSize = sizeof(TTTOOLINFOA);
2044 ti.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_TRANSPARENT ;
2047 ti.lpszText = "Test"; /* LPSTR_TEXTCALLBACK; */
2048 SetRectEmpty (&ti.rect);
2050 SendMessageA (infoPtr->hwndToolTip, TTM_ADDTOOLA, 0, (LPARAM)&ti);
2053 infoPtr->hwndEdit = CreateWindowExA (
2057 WS_CHILD | WS_BORDER | ES_AUTOHSCROLL |
2058 ES_WANTRETURN | ES_LEFT,
2061 0,0,0); /* FIXME: (HMENU)IDTVEDIT,pcs->hInstance,0);*/
2063 SendMessageA ( infoPtr->hwndEdit, WM_SETFONT, infoPtr->hFont, FALSE);
2064 infoPtr->wpEditOrig = (WNDPROC)SetWindowLongA (
2067 (LONG) TREEVIEW_Edit_SubclassProc);
2069 ReleaseDC (hwnd, hdc);
2076 TREEVIEW_Destroy (HWND hwnd)
2078 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2081 TREEVIEW_RemoveTree (hwnd);
2082 if (infoPtr->Timer & TV_REFRESH_TIMER_SET)
2083 KillTimer (hwnd, TV_REFRESH_TIMER);
2084 if (infoPtr->hwndToolTip)
2085 DestroyWindow (infoPtr->hwndToolTip);
2087 COMCTL32_Free (infoPtr);
2093 TREEVIEW_Paint (HWND hwnd, WPARAM wParam, LPARAM lParam)
2099 hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
2100 TREEVIEW_Refresh (hwnd);
2102 EndPaint (hwnd, &ps);
2105 return DefWindowProcA (hwnd, WM_PAINT, wParam, lParam);
2109 TREEVIEW_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2111 TREEVIEW_SendSimpleNotify (hwnd, NM_SETFOCUS);
2112 InvalidateRect(hwnd, NULL, FALSE);
2117 TREEVIEW_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2119 TREEVIEW_SendSimpleNotify (hwnd, NM_KILLFOCUS);
2120 InvalidateRect(hwnd, NULL, FALSE);
2125 TREEVIEW_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
2127 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2128 HBRUSH hBrush = CreateSolidBrush (infoPtr->clrBk);
2132 GetClientRect (hwnd, &rect);
2133 FillRect ((HDC)wParam, &rect, hBrush);
2134 DeleteObject (hBrush);
2150 TREEVIEW_SendSimpleNotify (HWND hwnd, UINT code)
2155 nmhdr.hwndFrom = hwnd;
2156 nmhdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2159 return (BOOL) SendMessageA (GetParent (hwnd), WM_NOTIFY,
2160 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
2166 TREEVIEW_SendTreeviewNotify (HWND hwnd, UINT code, UINT action,
2167 HTREEITEM oldItem, HTREEITEM newItem)
2170 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2172 TREEVIEW_ITEM *wineItem;
2174 TRACE("code:%x action:%x olditem:%x newitem:%x\n",
2175 code,action,(INT)oldItem,(INT)newItem);
2176 nmhdr.hdr.hwndFrom = hwnd;
2177 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2178 nmhdr.hdr.code = code;
2179 nmhdr.action = action;
2181 wineItem=& infoPtr->items[(INT)oldItem];
2182 nmhdr.itemOld.mask = wineItem->mask;
2183 nmhdr.itemOld.hItem = wineItem->hItem;
2184 nmhdr.itemOld.state = wineItem->state;
2185 nmhdr.itemOld.stateMask = wineItem->stateMask;
2186 nmhdr.itemOld.iImage = wineItem->iImage;
2187 nmhdr.itemOld.pszText = wineItem->pszText;
2188 nmhdr.itemOld.cchTextMax= wineItem->cchTextMax;
2189 nmhdr.itemOld.iImage = wineItem->iImage;
2190 nmhdr.itemOld.iSelectedImage = wineItem->iSelectedImage;
2191 nmhdr.itemOld.cChildren = wineItem->cChildren;
2192 nmhdr.itemOld.lParam = wineItem->lParam;
2196 wineItem=& infoPtr->items[(INT)newItem];
2197 nmhdr.itemNew.mask = wineItem->mask;
2198 nmhdr.itemNew.hItem = wineItem->hItem;
2199 nmhdr.itemNew.state = wineItem->state;
2200 nmhdr.itemNew.stateMask = wineItem->stateMask;
2201 nmhdr.itemNew.iImage = wineItem->iImage;
2202 nmhdr.itemNew.pszText = wineItem->pszText;
2203 nmhdr.itemNew.cchTextMax= wineItem->cchTextMax;
2204 nmhdr.itemNew.iImage = wineItem->iImage;
2205 nmhdr.itemNew.iSelectedImage = wineItem->iSelectedImage;
2206 nmhdr.itemNew.cChildren = wineItem->cChildren;
2207 nmhdr.itemNew.lParam = wineItem->lParam;
2213 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2214 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2219 TREEVIEW_SendTreeviewDnDNotify (HWND hwnd, UINT code, HTREEITEM dragItem,
2222 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2224 TREEVIEW_ITEM *wineItem;
2226 TRACE("code:%x dragitem:%x\n", code,(INT)dragItem);
2228 nmhdr.hdr.hwndFrom = hwnd;
2229 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2230 nmhdr.hdr.code = code;
2232 wineItem=& infoPtr->items[(INT)dragItem];
2233 nmhdr.itemNew.mask = wineItem->mask;
2234 nmhdr.itemNew.hItem = wineItem->hItem;
2235 nmhdr.itemNew.state = wineItem->state;
2236 nmhdr.itemNew.lParam = wineItem->lParam;
2238 nmhdr.ptDrag.x = pt.x;
2239 nmhdr.ptDrag.y = pt.y;
2241 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2242 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2249 TREEVIEW_SendDispInfoNotify (HWND hwnd, TREEVIEW_ITEM *wineItem,
2250 UINT code, UINT what)
2256 TRACE("item %d, action %x, state %d\n",
2257 (INT)wineItem->hItem,
2259 (INT)wineItem->state);
2261 tvdi.hdr.hwndFrom = hwnd;
2262 tvdi.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2263 tvdi.hdr.code = code;
2264 tvdi.item.mask = what;
2265 tvdi.item.hItem = wineItem->hItem;
2266 tvdi.item.state = wineItem->state;
2267 tvdi.item.lParam = wineItem->lParam;
2268 tvdi.item.pszText = COMCTL32_Alloc (128*sizeof(char));
2269 buf = tvdi.item.pszText;
2271 retval=(BOOL)SendMessageA (
2274 (WPARAM)tvdi.hdr.idFrom,
2277 if (what & TVIF_TEXT) {
2278 wineItem->pszText = tvdi.item.pszText;
2279 if (buf==tvdi.item.pszText) {
2280 wineItem->cchTextMax = 128;
2282 TRACE("user-supplied buffer\n");
2283 COMCTL32_Free (buf);
2284 wineItem->cchTextMax = 0;
2287 if (what & TVIF_SELECTEDIMAGE)
2288 wineItem->iSelectedImage = tvdi.item.iSelectedImage;
2289 if (what & TVIF_IMAGE)
2290 wineItem->iImage = tvdi.item.iImage;
2291 if (what & TVIF_CHILDREN)
2292 wineItem->cChildren = tvdi.item.cChildren;
2300 TREEVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
2303 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2304 NMTVCUSTOMDRAW nmcdhdr;
2305 LPNMCUSTOMDRAW nmcd;
2307 TRACE("drawstage:%lx hdc:%x\n", dwDrawStage, hdc);
2309 nmcd= & nmcdhdr.nmcd;
2310 nmcd->hdr.hwndFrom = hwnd;
2311 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2312 nmcd->hdr.code = NM_CUSTOMDRAW;
2313 nmcd->dwDrawStage= dwDrawStage;
2315 nmcd->rc.left = rc.left;
2316 nmcd->rc.right = rc.right;
2317 nmcd->rc.bottom = rc.bottom;
2318 nmcd->rc.top = rc.top;
2319 nmcd->dwItemSpec = 0;
2320 nmcd->uItemState = 0;
2321 nmcd->lItemlParam= 0;
2322 nmcdhdr.clrText = infoPtr->clrText;
2323 nmcdhdr.clrTextBk= infoPtr->clrBk;
2326 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2327 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2333 /* FIXME: need to find out when the flags in uItemState need to be set */
2336 TREEVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
2337 TREEVIEW_ITEM *wineItem, UINT uItemDrawState)
2339 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2340 NMTVCUSTOMDRAW nmcdhdr;
2341 LPNMCUSTOMDRAW nmcd;
2342 DWORD dwDrawStage,dwItemSpec;
2345 dwDrawStage=CDDS_ITEM | uItemDrawState;
2346 dwItemSpec=(DWORD)wineItem->hItem;
2348 if (wineItem->hItem==infoPtr->selectedItem) uItemState|=CDIS_SELECTED;
2349 if (wineItem->hItem==infoPtr->focusItem) uItemState|=CDIS_FOCUS;
2350 if (wineItem->hItem==infoPtr->hotItem) uItemState|=CDIS_HOT;
2352 nmcd= & nmcdhdr.nmcd;
2353 nmcd->hdr.hwndFrom = hwnd;
2354 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2355 nmcd->hdr.code = NM_CUSTOMDRAW;
2356 nmcd->dwDrawStage= dwDrawStage;
2358 nmcd->rc.left = wineItem->rect.left;
2359 nmcd->rc.right = wineItem->rect.right;
2360 nmcd->rc.bottom = wineItem->rect.bottom;
2361 nmcd->rc.top = wineItem->rect.top;
2362 nmcd->dwItemSpec = dwItemSpec;
2363 nmcd->uItemState = uItemState;
2364 nmcd->lItemlParam= wineItem->lParam;
2366 nmcdhdr.clrText = infoPtr->clrText;
2367 nmcdhdr.clrTextBk= infoPtr->clrBk;
2368 nmcdhdr.iLevel = wineItem->iLevel;
2370 TRACE("drawstage:%lx hdc:%x item:%lx, itemstate:%x\n",
2371 dwDrawStage, hdc, dwItemSpec, uItemState);
2373 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2374 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2379 /* Note:If the specified item is the child of a collapsed parent item,
2380 the parent's list of child items is (recursively) expanded to reveal the
2381 specified item. This is mentioned for TREEVIEW_SelectItem; don't
2382 know if it also applies here.
2386 TREEVIEW_Expand (HWND hwnd, WPARAM wParam, LPARAM lParam)
2388 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2389 TREEVIEW_ITEM *wineItem;
2393 flag = (UINT) wParam;
2394 expand = (INT) lParam;
2396 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2400 if (!wineItem->cChildren)
2403 TRACE("For (%s) flags:%x item:%d state:%d\n",
2409 if (wineItem->cChildren==I_CHILDRENCALLBACK) {
2410 FIXME("we don't handle I_CHILDRENCALLBACK yet\n");
2414 if (flag == TVE_TOGGLE) { /* FIXME: check exact behaviour here */
2415 flag &= ~TVE_TOGGLE; /* ie: bitwise ops or 'case' ops */
2416 if (wineItem->state & TVIS_EXPANDED)
2417 flag |= TVE_COLLAPSE;
2424 case TVE_COLLAPSERESET:
2425 TRACE(" case TVE_COLLAPSERESET\n");
2426 if (!wineItem->state & TVIS_EXPANDED)
2429 wineItem->state &= ~(TVIS_EXPANDEDONCE | TVIS_EXPANDED);
2430 TREEVIEW_RemoveAllChildren (hwnd, wineItem);
2434 TRACE(" case TVE_COLLAPSE\n");
2435 if (!wineItem->state & TVIS_EXPANDED)
2438 wineItem->state &= ~TVIS_EXPANDED;
2442 TRACE(" case TVE_EXPAND\n");
2443 if (wineItem->state & TVIS_EXPANDED)
2446 TRACE(" is not expanded...\n");
2448 if (!(wineItem->state & TVIS_EXPANDEDONCE))
2450 TRACE(" and has never been expanded...\n");
2451 wineItem->state |= TVIS_EXPANDED;
2453 /* this item has never been expanded */
2454 if (TREEVIEW_SendTreeviewNotify (
2461 TRACE(" TVN_ITEMEXPANDING returned TRUE, exiting...\n");
2466 * Since the TVN_ITEMEXPANDING message may has caused the parent to
2467 * insert new items which in turn may have cause items placeholder
2468 * reallocation, I reassign the current item pointer so we have
2469 * something valid to work with...
2470 * However, this should not be necessary,
2471 * investigation required in TREEVIEW_InsertItemA
2473 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2477 "Catastropic situation, cannot retreive item #%d\n",
2482 wineItem->state |= TVIS_EXPANDEDONCE;
2483 TRACE(" TVN_ITEMEXPANDING sent...\n");
2485 TREEVIEW_SendTreeviewNotify (
2492 TRACE(" TVN_ITEMEXPANDED sent...\n");
2497 /* this item has already been expanded */
2498 wineItem->state |= TVIS_EXPANDED;
2502 case TVE_EXPANDPARTIAL:
2503 TRACE(" case TVE_EXPANDPARTIAL\n");
2504 FIXME("TVE_EXPANDPARTIAL not implemented\n");
2505 wineItem->state ^=TVIS_EXPANDED;
2506 wineItem->state |=TVIS_EXPANDEDONCE;
2510 TRACE("Exiting, Item %d state is now %d...\n",
2514 TREEVIEW_QueueRefresh (hwnd);
2520 static TREEVIEW_ITEM *
2521 TREEVIEW_HitTestPoint (HWND hwnd, POINT pt)
2523 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2524 TREEVIEW_ITEM *wineItem;
2527 GetClientRect (hwnd, &rect);
2529 if (!infoPtr->firstVisible) return NULL;
2531 wineItem=&infoPtr->items [(INT)infoPtr->firstVisible];
2533 while ((wineItem!=NULL) && (pt.y > wineItem->rect.bottom))
2534 wineItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
2546 TREEVIEW_HitTest (HWND hwnd, LPARAM lParam)
2548 LPTVHITTESTINFO lpht=(LPTVHITTESTINFO) lParam;
2549 TREEVIEW_ITEM *wineItem;
2553 GetClientRect (hwnd, &rect);
2557 if (x < rect.left) status|=TVHT_TOLEFT;
2558 if (x > rect.right) status|=TVHT_TORIGHT;
2559 if (y < rect.top ) status|=TVHT_ABOVE;
2560 if (y > rect.bottom) status|=TVHT_BELOW;
2567 wineItem=TREEVIEW_HitTestPoint (hwnd, lpht->pt);
2569 lpht->flags=TVHT_NOWHERE;
2573 /* FIXME: implement other flags
2574 * Assign the appropriate flags depending on the click location
2575 * Intitialize flags before to "|=" it...
2579 if (x < wineItem->expandBox.left)
2581 lpht->flags |= TVHT_ONITEMINDENT;
2583 else if ( ( x >= wineItem->expandBox.left) &&
2584 ( x <= wineItem->expandBox.right))
2586 lpht->flags |= TVHT_ONITEMBUTTON;
2588 else if (x < wineItem->rect.right)
2590 lpht->flags |= TVHT_ONITEMLABEL;
2594 lpht->flags|=TVHT_ONITEMRIGHT;
2597 lpht->hItem=wineItem->hItem;
2599 return (LRESULT) wineItem->hItem;
2603 TREEVIEW_EndEditLabelNow (HWND hwnd, WPARAM wParam, LPARAM lParam)
2605 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2606 TREEVIEW_ITEM *editedItem = TREEVIEW_ValidItem (infoPtr, infoPtr->editItem);
2607 BOOL bRevert = (BOOL)wParam;
2608 BOOL bReturn = ! bRevert;
2610 if ( ! (BOOL)wParam ) /* wParam is set to true to cancel the edition */
2612 if ( TREEVIEW_SendDispInfoNotify( /* return true to cancel edition */
2623 if (bRevert == FALSE) /* Apply the changes */
2626 int iLength = GetWindowTextA(infoPtr->hwndEdit, tmpText, 1023);
2631 ERR("Problem retreiving new item label.");
2633 else if (iLength >= 1023)
2636 "Insuficient space to retrieve new item label, new label ignored.");
2640 if (strcmp( tmpText, editedItem->pszText ) == 0)
2641 /* Do nothing if the label has not changed */
2645 LPSTR tmpLabel = COMCTL32_Alloc( iLength+1 );
2647 if ( tmpLabel == NULL )
2649 "OutOfMemory, cannot allocate space for label");
2652 COMCTL32_Free(editedItem->pszText);
2653 editedItem->pszText = tmpLabel;
2654 lstrcpyA( editedItem->pszText, tmpText);
2660 ShowWindow(infoPtr->hwndEdit, SW_HIDE);
2661 EnableWindow(infoPtr->hwndEdit, FALSE);
2662 infoPtr->editItem = 0;
2671 TREEVIEW_LButtonDoubleClick (HWND hwnd, WPARAM wParam, LPARAM lParam)
2673 TREEVIEW_ITEM *wineItem;
2677 pt.x = (INT)LOWORD(lParam);
2678 pt.y = (INT)HIWORD(lParam);
2681 wineItem=TREEVIEW_HitTestPoint (hwnd, pt);
2682 if (!wineItem) return 0;
2683 TRACE("item %d \n",(INT)wineItem->hItem);
2685 if (TREEVIEW_SendSimpleNotify (hwnd, NM_DBLCLK)!=TRUE) { /* FIXME!*/
2686 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) wineItem->hItem);
2693 TREEVIEW_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
2695 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2699 ht.pt.x = (INT)LOWORD(lParam);
2700 ht.pt.y = (INT)HIWORD(lParam);
2703 iItem=TREEVIEW_HitTest (hwnd, (LPARAM) &ht);
2704 TRACE("item %d \n",iItem);
2706 if (ht.flags & TVHT_ONITEMBUTTON) {
2707 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) iItem);
2711 infoPtr->uInternalStatus|=TV_LDRAG;
2718 TREEVIEW_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
2720 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2722 TREEVIEW_ITEM *editItem;
2725 ht.pt.x = (INT)LOWORD(lParam);
2726 ht.pt.y = (INT)HIWORD(lParam);
2730 /* Return true to cancel default behaviour */
2731 if ( TREEVIEW_SendSimpleNotify (hwnd, NM_CLICK) )
2735 iItem = TREEVIEW_HitTest (hwnd, (LPARAM) &ht);
2739 editItem = TREEVIEW_ValidItem(infoPtr, (HTREEITEM)iItem);
2741 infoPtr->uInternalStatus &= ~(TV_LDRAG | TV_LDRAGGING);
2744 * If the style allow editing and the node is already selected
2745 * and the click occured on the item label...
2747 if ( ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_EDITLABELS ) &&
2748 ( editItem->state & TVIS_SELECTED ) &&
2749 ( ht.flags & TVHT_ONITEMLABEL ))
2751 if ( infoPtr->editItem == 0 ) /* If we are not curently editing */
2753 if ( TREEVIEW_SendDispInfoNotify( /* Return true to cancel edition */
2762 TRACE("Edit started for %s.\n", editItem->pszText);
2763 infoPtr->editItem = editItem->hItem;
2768 editItem->text.left - 2,
2769 editItem->text.top - 1,
2770 editItem->text.right - editItem->text.left + 20 ,
2771 editItem->text.bottom - editItem->text.top + 3,
2774 SetWindowTextA( infoPtr->hwndEdit, editItem->pszText );
2775 SendMessageA ( infoPtr->hwndEdit, EM_SETSEL, 0, -1 );
2776 SetFocus ( infoPtr->hwndEdit);
2777 ShowWindow ( infoPtr->hwndEdit, SW_SHOW);
2780 else if ( infoPtr->editItem != 0 ) /* If we are curently editing */
2782 TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
2784 else if ( ht.flags & (TVHT_ONITEMLABEL | TVHT_ONITEMICON))
2786 TREEVIEW_DoSelectItem (
2798 TREEVIEW_RButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
2800 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2803 infoPtr->uInternalStatus|=TV_RDRAG;
2808 TREEVIEW_RButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
2810 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2813 if (TREEVIEW_SendSimpleNotify (hwnd, NM_RCLICK)) return 0;
2814 infoPtr->uInternalStatus&= ~(TV_RDRAG | TV_RDRAGGING);
2820 TREEVIEW_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
2822 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2823 TREEVIEW_ITEM *hotItem;
2826 pt.x=(INT) LOWORD (lParam);
2827 pt.y=(INT) HIWORD (lParam);
2828 hotItem=TREEVIEW_HitTestPoint (hwnd, pt);
2829 if (!hotItem) return 0;
2830 infoPtr->focusItem=hotItem->hItem;
2832 if ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_DISABLEDRAGDROP) return 0;
2834 if (infoPtr->uInternalStatus & TV_LDRAG) {
2835 TREEVIEW_SendTreeviewDnDNotify (hwnd, TVN_BEGINDRAG, hotItem->hItem, pt);
2836 infoPtr->uInternalStatus &= ~TV_LDRAG;
2837 infoPtr->uInternalStatus |= TV_LDRAGGING;
2838 infoPtr->dropItem=hotItem->hItem;
2842 if (infoPtr->uInternalStatus & TV_RDRAG) {
2843 TREEVIEW_SendTreeviewDnDNotify (hwnd, TVN_BEGINRDRAG, hotItem->hItem, pt);
2844 infoPtr->uInternalStatus &= ~TV_RDRAG;
2845 infoPtr->uInternalStatus |= TV_RDRAGGING;
2846 infoPtr->dropItem=hotItem->hItem;
2855 TREEVIEW_CreateDragImage (HWND hwnd, WPARAM wParam, LPARAM lParam)
2857 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2858 TREEVIEW_ITEM *dragItem;
2862 HBITMAP hbmp,hOldbmp;
2869 if (!(infoPtr->himlNormal)) return 0;
2870 dragItem=TREEVIEW_ValidItem (infoPtr, (HTREEITEM) lParam);
2872 if (!dragItem) return 0;
2873 itemtxt=dragItem->pszText;
2875 hwtop=GetDesktopWindow ();
2876 htopdc= GetDC (hwtop);
2877 hdc=CreateCompatibleDC (htopdc);
2879 hOldFont=SelectObject (hdc, infoPtr->hFont);
2880 GetTextExtentPoint32A (hdc, itemtxt, lstrlenA (itemtxt), &size);
2881 TRACE("%d %d %s %d\n",size.cx,size.cy,itemtxt,lstrlenA(itemtxt));
2882 hbmp=CreateCompatibleBitmap (htopdc, size.cx, size.cy);
2883 hOldbmp=SelectObject (hdc, hbmp);
2885 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &cy);
2887 if (cy>size.cy) size.cy=cy;
2889 infoPtr->dragList=ImageList_Create (size.cx, size.cy, ILC_COLOR, 10, 10);
2890 ImageList_Draw (infoPtr->himlNormal, dragItem->iImage, hdc, 0, 0, ILD_NORMAL);
2893 ImageList_GetImageInfo (infoPtr->himlNormal, dragItem->hItem, &iminfo);
2894 ImageList_AddMasked (infoPtr->dragList, iminfo.hbmImage, CLR_DEFAULT);
2897 /* draw item text */
2899 SetRect (&rc, cx, 0, size.cx,size.cy);
2900 DrawTextA (hdc, itemtxt, lstrlenA (itemtxt), &rc, DT_LEFT);
2901 SelectObject (hdc, hOldFont);
2902 SelectObject (hdc, hOldbmp);
2904 ImageList_Add (infoPtr->dragList, hbmp, 0);
2907 DeleteObject (hbmp);
2908 ReleaseDC (hwtop, htopdc);
2910 return (LRESULT)infoPtr->dragList;
2915 TREEVIEW_DoSelectItem (HWND hwnd, INT action, HTREEITEM newSelect, INT cause)
2918 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2919 TREEVIEW_ITEM *prevItem,*wineItem;
2922 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)newSelect);
2924 TRACE("Entering item %d, flag %x, cause %x, state %d\n",
2930 if ( (wineItem) && (wineItem->parent))
2933 * If the item has a collapse parent expand the parent so he
2934 * can expose the item
2936 TREEVIEW_ITEM *parentItem = TREEVIEW_ValidItem (infoPtr, wineItem->parent);
2937 if ( !(parentItem->state & TVIS_EXPANDED))
2938 TREEVIEW_Expand (hwnd, TVE_EXPAND, (LPARAM) wineItem->parent);
2944 prevSelect=(INT)infoPtr->selectedItem;
2946 if ((HTREEITEM)prevSelect==newSelect)
2949 prevItem= TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect);
2952 if (TREEVIEW_SendTreeviewNotify(
2956 (HTREEITEM)prevSelect,
2957 (HTREEITEM)newSelect))
2958 return FALSE; /* FIXME: OK? */
2961 prevItem->state &= ~TVIS_SELECTED;
2963 wineItem->state |= TVIS_SELECTED;
2965 infoPtr->selectedItem=(HTREEITEM)newSelect;
2967 TREEVIEW_SendTreeviewNotify(
2971 (HTREEITEM)prevSelect,
2972 (HTREEITEM)newSelect);
2976 case TVGN_DROPHILITE:
2977 prevItem= TREEVIEW_ValidItem (infoPtr, infoPtr->dropItem);
2980 prevItem->state &= ~TVIS_DROPHILITED;
2982 infoPtr->dropItem=(HTREEITEM)newSelect;
2985 wineItem->state |=TVIS_DROPHILITED;
2989 case TVGN_FIRSTVISIBLE:
2990 FIXME("FIRSTVISIBLE not implemented\n");
2994 TREEVIEW_QueueRefresh (hwnd);
2996 TRACE("Leaving state %d\n", wineItem->state);
3000 /* FIXME: handle NM_KILLFocus enzo */
3002 TREEVIEW_SelectItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
3005 return TREEVIEW_DoSelectItem (hwnd, wParam, (HTREEITEM) lParam, TVC_UNKNOWN);
3012 TREEVIEW_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
3015 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3017 TRACE("%x\n",infoPtr->hFont);
3018 return infoPtr->hFont;
3022 TREEVIEW_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
3025 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3028 HFONT hFont, hOldFont;
3032 TRACE("%x %lx\n",wParam, lParam);
3034 infoPtr->hFont = (HFONT)wParam;
3036 hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
3038 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
3039 logFont.lfWeight=FW_BOLD;
3040 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
3043 hOldFont = SelectObject (hdc, hFont);
3044 GetTextMetricsA (hdc, &tm);
3045 height= tm.tmHeight + tm.tmExternalLeading;
3046 if (height>infoPtr->uRealItemHeight)
3047 infoPtr->uRealItemHeight=height;
3048 SelectObject (hdc, hOldFont);
3052 TREEVIEW_QueueRefresh (hwnd);
3060 TREEVIEW_VScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
3063 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3066 TRACE("wp %x, lp %lx\n", wParam, lParam);
3067 if (!infoPtr->uInternalStatus & TV_VSCROLL) return FALSE;
3069 switch (LOWORD (wParam)) {
3071 if (!infoPtr->cy) return FALSE;
3072 infoPtr->cy -= infoPtr->uRealItemHeight;
3073 if (infoPtr->cy < 0) infoPtr->cy=0;
3076 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3077 if (infoPtr->cy == maxHeight) return FALSE;
3078 infoPtr->cy += infoPtr->uRealItemHeight;
3079 if (infoPtr->cy > maxHeight)
3080 infoPtr->cy = maxHeight;
3083 if (!infoPtr->cy) return FALSE;
3084 infoPtr->cy -= infoPtr->uVisibleHeight;
3085 if (infoPtr->cy < 0) infoPtr->cy=0;
3088 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3089 if (infoPtr->cy == maxHeight) return FALSE;
3090 infoPtr->cy += infoPtr->uVisibleHeight;
3091 if (infoPtr->cy > maxHeight)
3092 infoPtr->cy = maxHeight;
3095 infoPtr->cy = HIWORD (wParam);
3100 TREEVIEW_QueueRefresh (hwnd);
3105 TREEVIEW_HScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
3107 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3110 TRACE("wp %lx, lp %x\n", lParam, wParam);
3112 if (!infoPtr->uInternalStatus & TV_HSCROLL) return FALSE;
3114 switch (LOWORD (wParam)) {
3116 if (!infoPtr->cx) return FALSE;
3117 infoPtr->cx -= infoPtr->uRealItemHeight;
3118 if (infoPtr->cx < 0) infoPtr->cx=0;
3121 maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
3122 if (infoPtr->cx == maxWidth) return FALSE;
3123 infoPtr->cx += infoPtr->uRealItemHeight; /*FIXME */
3124 if (infoPtr->cx > maxWidth)
3125 infoPtr->cx = maxWidth;
3128 if (!infoPtr->cx) return FALSE;
3129 infoPtr->cx -= infoPtr->uVisibleWidth;
3130 if (infoPtr->cx < 0) infoPtr->cx=0;
3133 maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
3134 if (infoPtr->cx == maxWidth) return FALSE;
3135 infoPtr->cx += infoPtr->uVisibleWidth;
3136 if (infoPtr->cx > maxWidth)
3137 infoPtr->cx = maxWidth;
3140 infoPtr->cx = HIWORD (wParam);
3145 TREEVIEW_QueueRefresh (hwnd);
3151 TREEVIEW_KeyDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
3153 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3154 HTREEITEM hNewSelection = 0;
3155 INT scrollNeeds = -1;
3156 INT cyChangeNeeds = -1;
3157 INT prevSelect = (INT)infoPtr->selectedItem;
3159 TREEVIEW_ITEM *prevItem =
3160 (prevSelect != 0 ) ?
3161 TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect) :
3164 TREEVIEW_ITEM *newItem = NULL;
3166 TRACE("%x %lx\n",wParam, lParam);
3168 if (prevSelect == 0)
3173 newItem=TREEVIEW_GetPrevListItem (infoPtr, prevItem);
3176 newItem=& infoPtr->items[(INT)infoPtr->TopRootItem];
3178 hNewSelection = newItem->hItem;
3180 if (! newItem->visible)
3181 scrollNeeds = SB_LINEUP;
3186 newItem=TREEVIEW_GetNextListItem (infoPtr, prevItem);
3191 hNewSelection = newItem->hItem;
3193 if (! newItem->visible)
3194 scrollNeeds = SB_LINEDOWN;
3199 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem];
3200 hNewSelection = newItem->hItem;
3205 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem];
3206 newItem = TREEVIEW_GetLastListItem (infoPtr, newItem);
3207 hNewSelection = newItem->hItem;
3209 if (! newItem->visible)
3210 cyChangeNeeds = infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3215 if ( (prevItem->cChildren > 0) && (prevItem->state & TVIS_EXPANDED) )
3217 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect );
3219 else if ((INT)prevItem->parent)
3221 newItem = (& infoPtr->items[(INT)prevItem->parent]);
3222 if (! newItem->visible)
3223 /* FIXME find a way to make this item the first visible... */
3226 hNewSelection = newItem->hItem;
3232 if ( ( prevItem->cChildren > 0) ||
3233 ( prevItem->cChildren == I_CHILDRENCALLBACK))
3235 if (! (prevItem->state & TVIS_EXPANDED))
3236 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect );
3239 newItem = (& infoPtr->items[(INT)prevItem->firstChild]);
3240 hNewSelection = newItem->hItem;
3247 if (! (prevItem->state & TVIS_EXPANDED))
3248 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect );
3252 if (prevItem->state & TVIS_EXPANDED)
3253 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect );
3258 newItem=TREEVIEW_GetListItem(
3261 -1*(TREEVIEW_GetVisibleCount(hwnd,0,0)-3));
3265 hNewSelection = newItem->hItem;
3267 if (! newItem->visible)
3268 scrollNeeds = SB_PAGEUP;
3273 newItem=TREEVIEW_GetListItem(
3276 TREEVIEW_GetVisibleCount(hwnd,0,0)-3);
3281 hNewSelection = newItem->hItem;
3283 if (! newItem->visible)
3284 scrollNeeds = SB_PAGEDOWN;
3293 FIXME("%x not implemented\n", wParam);
3300 This works but does not send notification...
3302 prevItem->state &= ~TVIS_SELECTED;
3303 newItem->state |= TVIS_SELECTED;
3304 infoPtr->selectedItem = hNewSelection;
3305 TREEVIEW_QueueRefresh (hwnd);
3308 if ( TREEVIEW_DoSelectItem(
3311 (HTREEITEM)hNewSelection,
3314 /* If selection change is allowed for the new item, perform scrolling */
3315 if (scrollNeeds != -1)
3316 TREEVIEW_VScroll(hwnd, scrollNeeds, 0);
3318 if (cyChangeNeeds != -1)
3319 infoPtr->cy = cyChangeNeeds;
3321 /* FIXME: Something happen in the load the in the two weeks before
3322 april 1st 1999 which makes this SetFocus mandatory otherwise, the focus
3323 is lost... However the SetFocus should not be required...*/
3334 TREEVIEW_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3337 case TVM_INSERTITEMA:
3338 return TREEVIEW_InsertItemA (hwnd, wParam, lParam);
3340 case TVM_INSERTITEMW:
3341 FIXME("Unimplemented msg TVM_INSERTITEM32W\n");
3344 case TVM_DELETEITEM:
3345 return TREEVIEW_DeleteItem (hwnd, wParam, lParam);
3348 return TREEVIEW_Expand (hwnd, wParam, lParam);
3350 case TVM_GETITEMRECT:
3351 return TREEVIEW_GetItemRect (hwnd, wParam, lParam);
3354 return TREEVIEW_GetCount (hwnd, wParam, lParam);
3357 return TREEVIEW_GetIndent (hwnd);
3360 return TREEVIEW_SetIndent (hwnd, wParam);
3362 case TVM_GETIMAGELIST:
3363 return TREEVIEW_GetImageList (hwnd, wParam, lParam);
3365 case TVM_SETIMAGELIST:
3366 return TREEVIEW_SetImageList (hwnd, wParam, lParam);
3368 case TVM_GETNEXTITEM:
3369 return TREEVIEW_GetNextItem (hwnd, wParam, lParam);
3371 case TVM_SELECTITEM:
3372 return TREEVIEW_SelectItem (hwnd, wParam, lParam);
3375 return TREEVIEW_GetItemA (hwnd, wParam, lParam);
3378 FIXME("Unimplemented msg TVM_GETITEM32W\n");
3382 return TREEVIEW_SetItemA (hwnd, wParam, lParam);
3385 FIXME("Unimplemented msg TVM_SETITEMW\n");
3388 case TVM_EDITLABELA:
3389 FIXME("Unimplemented msg TVM_EDITLABEL32A \n");
3392 case TVM_EDITLABELW:
3393 FIXME("Unimplemented msg TVM_EDITLABEL32W \n");
3396 case TVM_GETEDITCONTROL:
3397 return TREEVIEW_GetEditControl (hwnd);
3399 case TVM_GETVISIBLECOUNT:
3400 return TREEVIEW_GetVisibleCount (hwnd, wParam, lParam);
3403 return TREEVIEW_HitTest (hwnd, lParam);
3405 case TVM_CREATEDRAGIMAGE:
3406 return TREEVIEW_CreateDragImage (hwnd, wParam, lParam);
3408 case TVM_SORTCHILDREN:
3409 FIXME("Unimplemented msg TVM_SORTCHILDREN\n");
3412 case TVM_ENSUREVISIBLE:
3413 FIXME("Unimplemented msg TVM_ENSUREVISIBLE\n");
3416 case TVM_SORTCHILDRENCB:
3417 return TREEVIEW_SortChildrenCB(hwnd, wParam, lParam);
3419 case TVM_ENDEDITLABELNOW:
3420 return TREEVIEW_EndEditLabelNow (hwnd, wParam, lParam);
3422 case TVM_GETISEARCHSTRINGA:
3423 FIXME("Unimplemented msg TVM_GETISEARCHSTRING32A\n");
3426 case TVM_GETISEARCHSTRINGW:
3427 FIXME("Unimplemented msg TVM_GETISEARCHSTRING32W\n");
3430 case TVM_GETTOOLTIPS:
3431 return TREEVIEW_GetToolTips (hwnd);
3433 case TVM_SETTOOLTIPS:
3434 return TREEVIEW_SetToolTips (hwnd, wParam);
3436 case TVM_SETINSERTMARK:
3437 FIXME("Unimplemented msg TVM_SETINSERTMARK\n");
3440 case TVM_SETITEMHEIGHT:
3441 return TREEVIEW_SetItemHeight (hwnd, wParam);
3443 case TVM_GETITEMHEIGHT:
3444 return TREEVIEW_GetItemHeight (hwnd);
3446 case TVM_SETBKCOLOR:
3447 return TREEVIEW_SetBkColor (hwnd, wParam, lParam);
3449 case TVM_SETTEXTCOLOR:
3450 return TREEVIEW_SetTextColor (hwnd, wParam, lParam);
3452 case TVM_GETBKCOLOR:
3453 return TREEVIEW_GetBkColor (hwnd);
3455 case TVM_GETTEXTCOLOR:
3456 return TREEVIEW_GetTextColor (hwnd);
3458 case TVM_SETSCROLLTIME:
3459 FIXME("Unimplemented msg TVM_SETSCROLLTIME\n");
3462 case TVM_GETSCROLLTIME:
3463 FIXME("Unimplemented msg TVM_GETSCROLLTIME\n");
3466 case TVM_SETINSERTMARKCOLOR:
3467 FIXME("Unimplemented msg TVM_SETINSERTMARKCOLOR\n");
3470 case TVM_SETUNICODEFORMAT:
3471 FIXME("Unimplemented msg TVM_SETUNICODEFORMAT\n");
3474 case TVM_GETUNICODEFORMAT:
3475 FIXME("Unimplemented msg TVM_GETUNICODEFORMAT\n");
3479 return TREEVIEW_Command (hwnd, wParam, lParam);
3482 return TREEVIEW_Create (hwnd, wParam, lParam);
3485 return TREEVIEW_Destroy (hwnd);
3487 /* case WM_ENABLE: */
3490 return TREEVIEW_EraseBackground (hwnd, wParam, lParam);
3493 return DLGC_WANTARROWS | DLGC_WANTCHARS;
3496 return TREEVIEW_Paint (hwnd, wParam, lParam);
3499 return TREEVIEW_GetFont (hwnd, wParam, lParam);
3502 return TREEVIEW_SetFont (hwnd, wParam, lParam);
3505 return TREEVIEW_KeyDown (hwnd, wParam, lParam);
3509 return TREEVIEW_SetFocus (hwnd, wParam, lParam);
3512 return TREEVIEW_KillFocus (hwnd, wParam, lParam);
3515 case WM_LBUTTONDOWN:
3516 return TREEVIEW_LButtonDown (hwnd, wParam, lParam);
3519 return TREEVIEW_LButtonUp (hwnd, wParam, lParam);
3521 case WM_LBUTTONDBLCLK:
3522 return TREEVIEW_LButtonDoubleClick (hwnd, wParam, lParam);
3524 case WM_RBUTTONDOWN:
3525 return TREEVIEW_RButtonDown (hwnd, wParam, lParam);
3528 return TREEVIEW_RButtonUp (hwnd, wParam, lParam);
3531 return TREEVIEW_MouseMove (hwnd, wParam, lParam);
3534 /* case WM_SYSCOLORCHANGE: */
3535 case WM_STYLECHANGED:
3536 return TREEVIEW_StyleChanged (hwnd, wParam, lParam);
3538 /* case WM_SETREDRAW: */
3541 return TREEVIEW_HandleTimer (hwnd, wParam, lParam);
3544 return TREEVIEW_Size (hwnd, wParam,lParam);
3547 return TREEVIEW_HScroll (hwnd, wParam, lParam);
3549 return TREEVIEW_VScroll (hwnd, wParam, lParam);
3552 printf ("drawItem\n");
3553 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
3556 if (uMsg >= WM_USER)
3557 FIXME("Unknown msg %04x wp=%08x lp=%08lx\n",
3558 uMsg, wParam, lParam);
3559 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
3566 TREEVIEW_Register (VOID)
3572 if (GlobalFindAtomA (WC_TREEVIEWA)) return;
3574 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
3575 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
3576 wndClass.lpfnWndProc = (WNDPROC)TREEVIEW_WindowProc;
3577 wndClass.cbClsExtra = 0;
3578 wndClass.cbWndExtra = sizeof(TREEVIEW_INFO *);
3579 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
3580 wndClass.hbrBackground = 0;
3581 wndClass.lpszClassName = WC_TREEVIEWA;
3583 RegisterClassA (&wndClass);
3588 TREEVIEW_Unregister (VOID)
3590 if (GlobalFindAtomA (WC_TREEVIEWA))
3591 UnregisterClassA (WC_TREEVIEWA, (HINSTANCE)NULL);