Added add_queue/remove_queue to server object operations.
[wine/testsucceed.git] / dlls / comctl32 / treeview.c
blobafd848711f7aa5ac9af7713636cc1fb61a8708b7
1 /* Treeview control
3 * Copyright 1998 Eric Kohl <ekohl@abo.rhein-zeitung.de>
4 * Copyright 1998 Alex Priem <alexp@sci.kun.nl>
7 * TODO:
8 * - Nearly all notifications.
9 *
10 * list-handling stuff: sort, sorted insertitem.
12 * refreshtreeview:
13 -small array containing info about positions.
14 -better implementation of DrawItem (connecting lines).
15 -implement partial drawing?
16 * Expand: -ctlmacro expands twice ->toggle.
17 * -drag&drop.
18 * -scrollbars.
19 * -Unicode messages
20 * -TVITEMEX
22 * FIXMEs:
23 -GetNextItem: add flags for traversing child lists.
24 (DESCEND_ALWAYS, DESCEND_NEVER, DESCEND_VISIBLE)
25 -DblClick: ctlmacro.exe's NM_DBLCLK seems to go wrong (returns FALSE).
29 #include <string.h>
30 #include "windows.h"
31 #include "commctrl.h"
32 #include "treeview.h"
33 #include "heap.h"
34 #include "win.h"
35 #include "debug.h"
37 /* ffs should be in <string.h>. */
39 /* Defines, since they do not need to return previous state, and nr
40 * has no side effects in this file.
42 #define tv_test_bit(nr,bf) (((LPBYTE)bf)[nr>>3]&(1<<(nr&7)))
43 #define tv_set_bit(nr,bf) ((LPBYTE)bf)[nr>>3]|=(1<<(nr&7))
44 #define tv_clear_bit(nr,bf) ((LPBYTE)bf)[nr>>3]&=~(1<<(nr&7))
47 #define TREEVIEW_GetInfoPtr(wndPtr) ((TREEVIEW_INFO *)wndPtr->wExtra[0])
49 static BOOL32
50 TREEVIEW_SendSimpleNotify (WND *wndPtr, UINT32 code);
51 static BOOL32
52 TREEVIEW_SendTreeviewNotify (WND *wndPtr, UINT32 code, UINT32 action,
53 INT32 oldItem, INT32 newItem, POINT32 pt);
54 static LRESULT
55 TREEVIEW_SelectItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
56 static void
57 TREEVIEW_Refresh (WND *wndPtr);
63 /* helper functions. Work with the assumption that validity of operands
64 is checked beforehand */
66 /* FIXME: MS documentation says `GetNextVisibleItem' returns NULL
67 if not succesfull'. Probably means derefencing, and not whether
68 there is a next `visible' child. */
71 static TREEVIEW_ITEM *
72 TREEVIEW_ValidItem (TREEVIEW_INFO *infoPtr,int handle)
75 if ((!handle) || (handle>infoPtr->uMaxHandle)) return NULL;
76 if (tv_test_bit (handle, infoPtr->freeList)) return NULL;
78 return & infoPtr->items[handle];
83 static TREEVIEW_ITEM *TREEVIEW_GetPrevListItem (TREEVIEW_INFO *infoPtr,
84 TREEVIEW_ITEM *tvItem)
87 TREEVIEW_ITEM *wineItem;
89 if (tvItem->upsibling) {
90 wineItem=& infoPtr->items[tvItem->upsibling];
91 if ((wineItem->firstChild) && (wineItem->state & TVIS_EXPANDED)) {
92 wineItem=& infoPtr->items[wineItem->firstChild];
93 while (wineItem->sibling)
94 wineItem= & infoPtr->items[wineItem->sibling];
96 return wineItem;
99 wineItem=tvItem;
100 while (wineItem->parent) {
101 wineItem=& infoPtr->items[wineItem->parent];
102 if (wineItem->upsibling)
103 return (& infoPtr->items[wineItem->upsibling]);
106 return wineItem;
110 static TREEVIEW_ITEM *TREEVIEW_GetNextListItem (TREEVIEW_INFO *infoPtr,
111 TREEVIEW_ITEM *tvItem)
114 TREEVIEW_ITEM *wineItem;
116 if ((tvItem->firstChild) && (tvItem->state & TVIS_EXPANDED))
117 return (& infoPtr->items[tvItem->firstChild]);
119 if (tvItem->sibling)
120 return (& infoPtr->items[tvItem->sibling]);
122 wineItem=tvItem;
123 while (wineItem->parent) {
124 wineItem=& infoPtr->items [wineItem->parent];
125 if (wineItem->sibling)
126 return (& infoPtr->items [wineItem->sibling]);
129 return wineItem;
132 static TREEVIEW_ITEM *TREEVIEW_GetLastListItem (TREEVIEW_INFO *infoPtr)
135 TREEVIEW_ITEM *wineItem;
137 wineItem=NULL;
138 if (infoPtr->TopRootItem)
139 wineItem=& infoPtr->items [infoPtr->TopRootItem];
140 while (wineItem->sibling)
141 wineItem=& infoPtr->items [wineItem->sibling];
143 return wineItem;
149 static void
150 TREEVIEW_RemoveItem (TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem)
153 TREEVIEW_ITEM *parentItem, *upsiblingItem, *siblingItem;
154 INT32 iItem;
156 iItem=wineItem->hItem;
157 tv_set_bit(iItem,infoPtr->freeList);
158 infoPtr->uNumItems--;
159 parentItem=NULL;
160 if (wineItem->pszText!=LPSTR_TEXTCALLBACK32A)
161 COMCTL32_Free (wineItem->pszText);
163 if (wineItem->parent) {
164 parentItem=& infoPtr->items[ wineItem->parent];
165 if (parentItem->cChildren==1) {
166 parentItem->cChildren=0;
167 parentItem->firstChild=0;
168 return;
169 } else {
170 parentItem->cChildren--;
171 if (parentItem->firstChild==iItem)
172 parentItem->firstChild=wineItem->sibling;
176 if (iItem==infoPtr->TopRootItem)
177 infoPtr->TopRootItem=wineItem->sibling;
178 if (wineItem->upsibling) {
179 upsiblingItem=& infoPtr->items [wineItem->upsibling];
180 upsiblingItem->sibling=wineItem->sibling;
182 if (wineItem->sibling) {
183 siblingItem=& infoPtr->items [wineItem->sibling];
184 siblingItem->upsibling=wineItem->upsibling;
190 static void TREEVIEW_RemoveAllChildren (TREEVIEW_INFO *infoPtr,
191 TREEVIEW_ITEM *parentItem)
194 TREEVIEW_ITEM *killItem;
195 INT32 kill;
197 kill=parentItem->firstChild;
198 while (kill) {
199 tv_set_bit ( kill, infoPtr->freeList);
200 killItem=& infoPtr->items[kill];
201 if (killItem->pszText!=LPSTR_TEXTCALLBACK32A)
202 COMCTL32_Free (killItem->pszText);
203 kill=killItem->sibling;
205 infoPtr->uNumItems -= parentItem->cChildren;
206 parentItem->firstChild = 0;
207 parentItem->cChildren = 0;
211 /* Note:TREEVIEW_RemoveTree doesn't remove infoPtr itself */
213 static void TREEVIEW_RemoveTree (TREEVIEW_INFO *infoPtr)
217 TREEVIEW_ITEM *killItem;
218 int i;
220 for (i=1; i<=infoPtr->uMaxHandle; i++)
221 if (!tv_test_bit (i, infoPtr->freeList)) {
222 killItem=& infoPtr->items [i];
223 if (killItem->pszText!=LPSTR_TEXTCALLBACK32A)
224 COMCTL32_Free (killItem->pszText);
227 if (infoPtr->uNumPtrsAlloced) {
228 COMCTL32_Free (infoPtr->items);
229 COMCTL32_Free (infoPtr->freeList);
230 infoPtr->uNumItems=0;
231 infoPtr->uNumPtrsAlloced=0;
232 infoPtr->uMaxHandle=0;
245 static LRESULT
246 TREEVIEW_GetImageList (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
248 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
250 TRACE (treeview,"\n");
251 if (infoPtr==NULL) return 0;
253 if ((INT32)wParam == TVSIL_NORMAL)
254 return (LRESULT) infoPtr->himlNormal;
255 if ((INT32)wParam == TVSIL_STATE)
256 return (LRESULT) infoPtr->himlState;
258 return 0;
264 static LRESULT
265 TREEVIEW_SetImageList (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
267 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
268 HIMAGELIST himlTemp;
270 TRACE (treeview,"\n");
271 switch ((INT32)wParam) {
272 case TVSIL_NORMAL:
273 himlTemp = infoPtr->himlNormal;
274 infoPtr->himlNormal = (HIMAGELIST)lParam;
275 return (LRESULT)himlTemp;
277 case TVSIL_STATE:
278 himlTemp = infoPtr->himlState;
279 infoPtr->himlState = (HIMAGELIST)lParam;
280 return (LRESULT)himlTemp;
283 return (LRESULT)NULL;
288 static LRESULT
289 TREEVIEW_SetItemHeight (WND *wndPtr, WPARAM32 wParam)
291 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
292 INT32 prevHeight=infoPtr->uItemHeight;
293 HDC32 hdc;
294 TEXTMETRIC32A tm;
296 TRACE (treeview,"\n");
297 if (wParam==-1) {
298 hdc=GetDC32 (wndPtr->hwndSelf);
299 infoPtr->uItemHeight=-1;
300 GetTextMetrics32A (hdc, &tm);
301 infoPtr->uRealItemHeight= tm.tmHeight + tm.tmExternalLeading;
302 ReleaseDC32 (wndPtr->hwndSelf, hdc);
303 return prevHeight;
306 /* FIXME: check wParam > imagelist height */
308 if (!(wndPtr->dwStyle & TVS_NONEVENHEIGHT))
309 infoPtr->uItemHeight = (INT32) wParam & 0xfffffffe;
310 return prevHeight;
313 static LRESULT
314 TREEVIEW_GetItemHeight (WND *wndPtr)
316 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
318 TRACE (treeview,"\n");
319 return infoPtr->uItemHeight;
322 static LRESULT
323 TREEVIEW_SetTextColor (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
325 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
326 COLORREF prevColor=infoPtr->clrText;
328 TRACE (treeview,"\n");
329 infoPtr->clrText=(COLORREF) lParam;
330 return (LRESULT) prevColor;
333 static LRESULT
334 TREEVIEW_GetTextColor (WND *wndPtr)
336 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
338 TRACE (treeview,"\n");
339 return (LRESULT) infoPtr->clrText;
343 static INT32
344 TREEVIEW_DrawItem (WND *wndPtr, HDC32 hdc, TREEVIEW_ITEM *wineItem,
345 TREEVIEW_ITEM *upperItem, int indent)
347 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
348 INT32 oldBkMode,center,xpos;
349 COLORREF oldBkColor;
350 UINT32 uTextJustify = DT_LEFT;
351 HPEN32 hOldPen, hnewPen,hRootPen;
352 RECT32 r,upper;
354 hnewPen = CreatePen32(PS_DOT, 0, GetSysColor32(COLOR_WINDOWTEXT) );
355 hOldPen = SelectObject32( hdc, hnewPen );
357 r=wineItem->rect;
358 if (upperItem)
359 upper=upperItem->rect;
360 else {
361 upper.top=0;
362 upper.left=8;
364 center=(r.top+r.bottom)/2;
365 xpos=r.left+8;
367 if (wndPtr->dwStyle & TVS_HASLINES) {
368 POINT32 points[3];
369 if ((wndPtr->dwStyle & TVS_LINESATROOT) && (indent==0)) {
370 points[0].y=points[1].y=center;
371 points[2].y=upper.top;
372 points[1].x=points[2].x=upper.left;
373 points[0].x=upper.left+12;
374 points[2].y+=5;
376 Polyline32 (hdc,points,3);
378 else {
379 points[0].y=points[1].y=center;
380 points[2].y=upper.top;
381 points[1].x=points[2].x=upper.left+13;
382 points[0].x=upper.left+25;
383 points[2].y+=5;
384 Polyline32 (hdc,points,3);
388 DeleteObject32(hnewPen);
389 SelectObject32(hdc, hOldPen);
391 if ((wndPtr->dwStyle & TVS_HASBUTTONS) && (wineItem->cChildren)) {
393 hRootPen = CreatePen32(PS_SOLID, 0, GetSysColor32(COLOR_WINDOW) );
394 SelectObject32( hdc, hRootPen );
397 Rectangle32 (hdc, xpos-4, center-4, xpos+5, center+5);
398 MoveToEx32 (hdc, xpos-2, center, NULL);
399 LineTo32 (hdc, xpos+3, center);
400 if (!(wineItem->state & TVIS_EXPANDED)) {
401 MoveToEx32 (hdc, xpos, center-2, NULL);
402 LineTo32 (hdc, xpos, center+3);
404 /* DeleteObject32(hRootPen); */
408 xpos+=13;
410 if (wineItem->mask & TVIF_IMAGE) {
411 if (wineItem->iImage!=I_IMAGECALLBACK) {
412 if (infoPtr->himlNormal) {
413 ImageList_Draw (infoPtr->himlNormal,wineItem->iImage, hdc,
414 xpos-2, r.top+1, ILD_NORMAL);
415 xpos+=15;
420 r.left=xpos;
421 if ((wineItem->mask & TVIF_TEXT) && (wineItem->pszText)) {
422 if (wineItem->state & TVIS_SELECTED) {
423 oldBkMode = SetBkMode32(hdc, OPAQUE);
424 oldBkColor= SetBkColor32 (hdc, GetSysColor32( COLOR_HIGHLIGHT));
425 SetTextColor32 (hdc, GetSysColor32(COLOR_HIGHLIGHTTEXT));
426 } else {
427 oldBkMode = SetBkMode32(hdc, TRANSPARENT);
429 r.left += 3;
430 r.right -= 3;
431 if (infoPtr->clrText==-1)
432 SetTextColor32 (hdc, COLOR_BTNTEXT);
433 else
434 SetTextColor32 (hdc, infoPtr->clrText); /* FIXME: retval */
435 if (wineItem->pszText!= LPSTR_TEXTCALLBACK32A)
436 DrawText32A (hdc, wineItem->pszText, lstrlen32A(wineItem->pszText),
437 &r, uTextJustify|DT_VCENTER|DT_SINGLELINE);
438 else {
439 /* send TVN_GETDISPINFO notification */
440 TRACE (treeview,"LPSTR_TEXTCALLBACK\n");
442 if (oldBkMode != TRANSPARENT)
443 SetBkMode32(hdc, oldBkMode);
444 if (wineItem->state & TVIS_SELECTED)
445 SetBkColor32 (hdc, oldBkColor);
448 return wineItem->rect.right;
457 static LRESULT
458 TREEVIEW_GetItemRect (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
460 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
461 TREEVIEW_ITEM *wineItem;
462 INT32 iItem;
463 LPRECT32 lpRect;
465 TRACE (treeview,"\n");
466 if (infoPtr==NULL) return FALSE;
468 iItem = (INT32)lParam;
469 wineItem = TREEVIEW_ValidItem (infoPtr, iItem);
470 if (!wineItem) return FALSE;
472 wineItem=& infoPtr->items[ iItem ];
473 if (!wineItem->visible) return FALSE;
475 lpRect = (LPRECT32)lParam;
476 if (lpRect == NULL) return FALSE;
478 if ((INT32) wParam) {
479 lpRect->left = wineItem->text.left;
480 lpRect->right = wineItem->text.right;
481 lpRect->bottom = wineItem->text.bottom;
482 lpRect->top = wineItem->text.top;
483 } else {
484 lpRect->left = wineItem->rect.left;
485 lpRect->right = wineItem->rect.right;
486 lpRect->bottom = wineItem->rect.bottom;
487 lpRect->top = wineItem->rect.top;
490 return TRUE;
495 static LRESULT
496 TREEVIEW_GetVisibleCount (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
499 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
501 TRACE (treeview,"\n");
502 return (LRESULT) infoPtr->uVisibleHeight / infoPtr->uRealItemHeight;
507 static LRESULT
508 TREEVIEW_SetItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
510 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
511 TREEVIEW_ITEM *wineItem;
512 TV_ITEM *tvItem;
513 INT32 iItem,len;
515 tvItem=(LPTVITEM) lParam;
516 iItem=tvItem->hItem;
517 TRACE (treeview,"item %d,mask %x\n",iItem,tvItem->mask);
519 wineItem = TREEVIEW_ValidItem (infoPtr, iItem);
520 if (!wineItem) return FALSE;
522 if (tvItem->mask & TVIF_CHILDREN) {
523 wineItem->cChildren=tvItem->cChildren;
526 if (tvItem->mask & TVIF_IMAGE) {
527 wineItem->iImage=tvItem->iImage;
530 if (tvItem->mask & TVIF_INTEGRAL) {
531 /* wineItem->iIntegral=tvItem->iIntegral; */
534 if (tvItem->mask & TVIF_PARAM) {
535 wineItem->lParam=tvItem->lParam;
538 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
539 wineItem->iSelectedImage=tvItem->iSelectedImage;
542 if (tvItem->mask & TVIF_STATE) {
543 wineItem->state=tvItem->state & tvItem->stateMask;
546 if (tvItem->mask & TVIF_TEXT) {
547 len=lstrlen32A (tvItem->pszText);
548 if (len>wineItem->cchTextMax)
549 wineItem->pszText= COMCTL32_ReAlloc (wineItem->pszText, len+1);
550 lstrcpyn32A (wineItem->pszText, tvItem->pszText,len);
553 return TRUE;
560 static void
561 TREEVIEW_Refresh (WND *wndPtr)
564 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
565 HFONT32 hFont, hOldFont;
566 RECT32 rect;
567 HBRUSH32 hbrBk;
568 HDC32 hdc;
569 INT32 iItem, indent, x, y, height;
570 INT32 viewtop,viewbottom,viewleft,viewright;
571 TREEVIEW_ITEM *wineItem, *prevItem;
573 TRACE (treeview,"\n");
575 hdc=GetDC32 (wndPtr->hwndSelf);
577 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
578 KillTimer32 (wndPtr->hwndSelf, TV_REFRESH_TIMER);
579 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
583 GetClientRect32 (wndPtr->hwndSelf, &rect);
584 if ((rect.left-rect.right ==0) || (rect.top-rect.bottom==0)) return;
585 viewtop=infoPtr->cy;
586 viewbottom=infoPtr->cy + rect.bottom-rect.top;
587 viewleft=infoPtr->cx;
588 viewright=infoPtr->cx + rect.right-rect.left;
590 infoPtr->uVisibleHeight=viewbottom - viewtop;
592 hFont = infoPtr->hFont;
593 hOldFont = SelectObject32 (hdc, hFont);
595 /* draw background */
596 hbrBk = GetSysColorBrush32(COLOR_WINDOW);
597 FillRect32(hdc, &rect, hbrBk);
600 iItem=infoPtr->TopRootItem;
601 infoPtr->firstVisible=0;
602 wineItem=NULL;
603 indent=0;
604 x=y=0;
605 TRACE (treeview, "[%d %d %d %d]\n",viewtop,viewbottom,viewleft,viewright);
607 while (iItem) {
608 prevItem=wineItem;
609 wineItem= & infoPtr->items[iItem];
611 TRACE (treeview, "%d %d [%d %d %d %d] (%s)\n",y,x,
612 wineItem->rect.top, wineItem->rect.bottom,
613 wineItem->rect.left, wineItem->rect.right,
614 wineItem->pszText);
616 height=infoPtr->uRealItemHeight * wineItem->iIntegral;
617 if ((y >= viewtop) && (y <= viewbottom) &&
618 (x >= viewleft ) && (x <= viewright)) {
619 wineItem->rect.top = y - infoPtr->cy + rect.top;
620 wineItem->rect.bottom = wineItem->rect.top + height ;
621 wineItem->rect.left = x - infoPtr->cx + rect.left;
622 wineItem->rect.right = rect.right;
623 if (!infoPtr->firstVisible)
624 infoPtr->firstVisible=wineItem->hItem;
625 TREEVIEW_DrawItem (wndPtr, hdc, wineItem, prevItem, indent);
627 else {
628 wineItem->rect.top = wineItem->rect.bottom = -1;
629 wineItem->rect.left = wineItem->rect.right = -1;
632 /* look up next item */
634 if ((wineItem->firstChild) && (wineItem->state & TVIS_EXPANDED)) {
635 iItem=wineItem->firstChild;
636 indent++;
637 x+=infoPtr->uIndent;
639 else {
640 iItem=wineItem->sibling;
641 while ((!iItem) && (indent>0)) {
642 indent--;
643 x-=infoPtr->uIndent;
644 prevItem=wineItem;
645 wineItem=&infoPtr->items[wineItem->parent];
646 iItem=wineItem->sibling;
649 y +=height;
650 } /* while */
652 infoPtr->uTotalHeight=y;
653 if (y >= (viewbottom-viewtop)) {
654 if (!(infoPtr->uInternalStatus & TV_VSCROLL))
655 ShowScrollBar32 (wndPtr->hwndSelf, SB_VERT, TRUE);
656 infoPtr->uInternalStatus |=TV_VSCROLL;
657 SetScrollRange32 (wndPtr->hwndSelf, SB_VERT, 0,
658 y - infoPtr->uVisibleHeight, FALSE);
659 SetScrollPos32 (wndPtr->hwndSelf, SB_VERT, infoPtr->cy, TRUE);
661 else {
662 if (infoPtr->uInternalStatus & TV_VSCROLL)
663 ShowScrollBar32 (wndPtr->hwndSelf, SB_VERT, FALSE);
664 infoPtr->uInternalStatus &= ~TV_VSCROLL;
668 SelectObject32 (hdc, hOldFont);
669 ReleaseDC32 (wndPtr->hwndSelf, hdc);
673 static LRESULT
674 TREEVIEW_HandleTimer ( WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
676 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
678 TRACE (treeview, " %d\n",wParam);
679 if (!infoPtr) return FALSE;
681 switch (wParam) {
682 case TV_REFRESH_TIMER:
683 KillTimer32 (wndPtr->hwndSelf, TV_REFRESH_TIMER);
684 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
685 TREEVIEW_Refresh (wndPtr);
686 return 0;
687 case TV_EDIT_TIMER:
688 KillTimer32 (wndPtr->hwndSelf, TV_EDIT_TIMER);
689 infoPtr->Timer &= ~TV_EDIT_TIMER_SET;
690 return 0;
693 return 1;
697 static void
698 TREEVIEW_QueueRefresh (WND *wndPtr)
701 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
703 TRACE (treeview,"\n");
704 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
705 KillTimer32 (wndPtr->hwndSelf, TV_REFRESH_TIMER);
708 SetTimer32 (wndPtr->hwndSelf, TV_REFRESH_TIMER, TV_REFRESH_DELAY, 0);
709 infoPtr->Timer|=TV_REFRESH_TIMER_SET;
714 static LRESULT
715 TREEVIEW_GetItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
717 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
718 LPTVITEM tvItem;
719 TREEVIEW_ITEM *wineItem;
720 INT32 iItem;
722 TRACE (treeview,"\n");
723 tvItem=(LPTVITEM) lParam;
724 iItem=tvItem->hItem;
726 wineItem = TREEVIEW_ValidItem (infoPtr, iItem);
727 if (!wineItem) return FALSE;
730 if (tvItem->mask & TVIF_CHILDREN) {
731 tvItem->cChildren=wineItem->cChildren;
734 if (tvItem->mask & TVIF_HANDLE) {
735 tvItem->hItem=wineItem->hItem;
738 if (tvItem->mask & TVIF_IMAGE) {
739 tvItem->iImage=wineItem->iImage;
742 if (tvItem->mask & TVIF_INTEGRAL) {
743 /* tvItem->iIntegral=wineItem->iIntegral; */
746 if (tvItem->mask & TVIF_PARAM) {
747 tvItem->lParam=wineItem->lParam;
750 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
751 tvItem->iSelectedImage=wineItem->iSelectedImage;
754 if (tvItem->mask & TVIF_STATE) {
755 tvItem->state=wineItem->state & tvItem->stateMask;
758 if (tvItem->mask & TVIF_TEXT) {
759 if (wineItem->pszText == LPSTR_TEXTCALLBACK32A) {
760 tvItem->pszText = LPSTR_TEXTCALLBACK32A;
762 else if (wineItem->pszText) {
763 lstrcpyn32A (tvItem->pszText, wineItem->pszText, tvItem->cchTextMax);
767 return TRUE;
772 /* FIXME: check implementation of TVGN_NEXT/TVGN_NEXTVISIBLE */
775 static LRESULT
776 TREEVIEW_GetNextItem32 (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
779 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
780 TREEVIEW_ITEM *wineItem;
781 INT32 iItem, flag;
784 TRACE (treeview,"item:%lu, flags:%x\n", lParam, wParam);
785 if (!infoPtr) return FALSE;
787 flag= (INT32) wParam;
788 switch (flag) {
789 case TVGN_ROOT: return (LRESULT) infoPtr->TopRootItem;
790 case TVGN_CARET: return (LRESULT) infoPtr->selectedItem;
791 case TVGN_FIRSTVISIBLE:
792 TREEVIEW_Refresh (wndPtr);
793 return (LRESULT) infoPtr->firstVisible;
794 case TVGN_DROPHILITE:
795 return (LRESULT) infoPtr->dropItem;
798 iItem= (INT32) lParam;
799 wineItem = TREEVIEW_ValidItem (infoPtr, iItem);
800 if (!wineItem) return FALSE;
802 switch (flag) {
803 case TVGN_NEXT: return (LRESULT) wineItem->sibling;
804 case TVGN_PREVIOUS: return (LRESULT) wineItem->upsibling;
805 case TVGN_PARENT: return (LRESULT) wineItem->parent;
806 case TVGN_CHILD: return (LRESULT) wineItem->firstChild;
807 case TVGN_LASTVISIBLE:
808 wineItem=TREEVIEW_GetLastListItem (infoPtr);
809 break;
810 case TVGN_NEXTVISIBLE:
811 wineItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
812 TRACE (treeview,"(%s)\n",wineItem->pszText);
813 break;
814 case TVGN_PREVIOUSVISIBLE:
815 wineItem=TREEVIEW_GetPrevListItem (infoPtr, wineItem);
816 TRACE (treeview,"(%s)\n",wineItem->pszText);
817 break;
818 default: FIXME (treeview,"Unknown msg %x,item %x\n", flag,iItem);
819 break;
822 if (wineItem) return (LRESULT) wineItem->hItem;
824 FIXME (treeview, "returning 0\n");
825 return 0;
829 static LRESULT
830 TREEVIEW_GetCount (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
832 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
834 TRACE (treeview,"\n");
835 return (LRESULT) infoPtr->uNumItems;
841 /* the method used below isn't the most memory-friendly, but it avoids
842 a lot of memory reallocations */
844 /* BTW: we waste handle 0; 0 is not an allowed handle. Fix this by
845 decreasing infoptr->items with 1, and increasing it by 1 if
846 it is referenced in mm-handling stuff? */
848 static LRESULT
849 TREEVIEW_InsertItem32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
852 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
853 TVINSERTSTRUCT *ptdi;
854 TV_ITEM *tvItem;
855 TREEVIEW_ITEM *wineItem, *parentItem, *prevsib, *sibItem;
856 INT32 iItem,listItems,i,len;
858 TRACE (treeview,"\n");
859 ptdi = (TVINSERTSTRUCT *) lParam;
861 /* check if memory is available */
863 if (infoPtr->uNumPtrsAlloced==0) {
864 infoPtr->items = COMCTL32_Alloc (TVITEM_ALLOC*sizeof (TREEVIEW_ITEM));
865 infoPtr->freeList= COMCTL32_Alloc ((1+(TVITEM_ALLOC>>5)) * sizeof (INT32));
866 infoPtr->uNumPtrsAlloced=TVITEM_ALLOC;
867 infoPtr->TopRootItem=1;
870 if (infoPtr->uNumItems == (infoPtr->uNumPtrsAlloced-1) ) {
871 TREEVIEW_ITEM *oldItems = infoPtr->items;
872 INT32 *oldfreeList = infoPtr->freeList;
874 infoPtr->uNumPtrsAlloced*=2;
875 infoPtr->items = COMCTL32_Alloc ( infoPtr->uNumPtrsAlloced * sizeof (TREEVIEW_ITEM));
876 infoPtr->freeList= COMCTL32_Alloc ((1+(infoPtr->uNumPtrsAlloced>>5))*sizeof (INT32));
878 memcpy (&infoPtr->items[0], &oldItems[0],
879 infoPtr->uNumPtrsAlloced/2 * sizeof(TREEVIEW_ITEM));
880 memcpy (&infoPtr->freeList[0], &oldfreeList[0],
881 infoPtr->uNumPtrsAlloced>>6 * sizeof(INT32));
883 COMCTL32_Free (oldItems);
884 COMCTL32_Free (oldfreeList);
887 iItem=0;
888 infoPtr->uNumItems++;
890 if (infoPtr->uMaxHandle==(infoPtr->uNumItems-1)) {
891 iItem=infoPtr->uNumItems;
892 infoPtr->uMaxHandle++;
894 else { /* check freelist */
895 for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++) {
896 if (infoPtr->freeList[i]) {
897 iItem=ffs (infoPtr->freeList[i]);
898 tv_clear_bit(iItem,&infoPtr->freeList[i]);
899 break;
903 if (!iItem) ERR (treeview, "Argh -- can't find free item.\n");
905 tvItem= & ptdi->item;
906 wineItem=& infoPtr->items[iItem];
910 if ((ptdi->hParent==TVI_ROOT) || (ptdi->hParent==0)) {
911 parentItem=NULL;
912 wineItem->parent=0;
913 sibItem=&infoPtr->items [infoPtr->TopRootItem];
914 listItems=infoPtr->uNumItems;
916 else {
917 parentItem= &infoPtr->items[ptdi->hParent];
918 if (!parentItem->firstChild)
919 parentItem->firstChild=iItem;
920 wineItem->parent=ptdi->hParent;
921 sibItem=&infoPtr->items [parentItem->firstChild];
922 parentItem->cChildren++;
923 listItems=parentItem->cChildren;
926 wineItem->upsibling=0; /* needed in case we're the first item in a list */
927 wineItem->sibling=0;
928 wineItem->firstChild=0;
930 if (listItems>1) {
931 prevsib=NULL;
932 switch (ptdi->hInsertAfter) {
933 case TVI_FIRST: wineItem->sibling=infoPtr->TopRootItem;
934 infoPtr->TopRootItem=iItem;
935 break;
936 case TVI_LAST:
937 while (sibItem->sibling) {
938 prevsib=sibItem;
939 sibItem=&infoPtr->items [sibItem->sibling];
941 sibItem->sibling=iItem;
942 if (prevsib!=NULL)
943 wineItem->upsibling=prevsib->hItem;
944 else
945 wineItem->sibling=0; /* terminate list */
946 break;
947 case TVI_SORT:
948 FIXME (treeview, "Sorted insert not implemented yet\n");
949 break;
950 default:
951 while ((sibItem->sibling) && (sibItem->sibling!=iItem)) {
952 prevsib=sibItem;
953 sibItem=&infoPtr->items [sibItem->sibling];
955 if (sibItem->sibling)
956 WARN (treeview, "Buggy program tried to insert item after nonexisting handle.");
957 sibItem->upsibling=iItem;
958 wineItem->sibling=sibItem->hItem;
959 if (prevsib!=NULL)
960 wineItem->upsibling=prevsib->hItem;
961 break;
966 /* Fill in info structure */
968 TRACE (treeview,"item %d, mask %x\n",iItem, tvItem->mask);
969 wineItem->mask=tvItem->mask;
970 wineItem->hItem=iItem;
971 wineItem->iIntegral=1;
973 if (tvItem->mask & TVIF_CHILDREN)
974 wineItem->cChildren=tvItem->cChildren;
976 if (tvItem->mask & TVIF_IMAGE)
977 wineItem->iImage=tvItem->iImage;
979 /* if (tvItem->mask & TVIF_INTEGRAL)
980 wineItem->iIntegral=tvItem->iIntegral; */
983 if (tvItem->mask & TVIF_PARAM)
984 wineItem->lParam=tvItem->lParam;
986 if (tvItem->mask & TVIF_SELECTEDIMAGE)
987 wineItem->iSelectedImage=tvItem->iSelectedImage;
989 if (tvItem->mask & TVIF_STATE) {
990 wineItem->state=tvItem->state;
991 wineItem->stateMask=tvItem->stateMask;
994 if (tvItem->mask & TVIF_TEXT) {
995 TRACE (treeview,"(%s)\n", tvItem->pszText);
996 if (tvItem->pszText!=LPSTR_TEXTCALLBACK32A) {
997 len = lstrlen32A (tvItem->pszText)+1;
998 wineItem->pszText= COMCTL32_Alloc (len+1);
999 lstrcpy32A (wineItem->pszText, tvItem->pszText);
1000 wineItem->cchTextMax=len;
1002 else {
1003 wineItem->pszText = LPSTR_TEXTCALLBACK32A;
1004 TRACE (treeview,"LPSTR_TEXTCALLBACK\n");
1005 wineItem->cchTextMax = 0;
1009 TREEVIEW_QueueRefresh (wndPtr);
1011 return (LRESULT) iItem;
1016 static LRESULT
1017 TREEVIEW_DeleteItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1019 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1020 INT32 iItem;
1021 POINT32 pt;
1022 TREEVIEW_ITEM *wineItem;
1024 TRACE (treeview,"\n");
1025 if (!infoPtr) return FALSE;
1027 if ((INT32) lParam == TVI_ROOT) {
1028 TREEVIEW_RemoveTree (infoPtr);
1029 } else {
1030 iItem= (INT32) lParam;
1031 wineItem = TREEVIEW_ValidItem (infoPtr, iItem);
1032 if (!wineItem) return FALSE;
1033 TREEVIEW_SendTreeviewNotify (wndPtr, TVN_DELETEITEM, 0, iItem, 0, pt);
1034 TREEVIEW_RemoveItem (infoPtr, wineItem);
1037 TREEVIEW_QueueRefresh (wndPtr);
1039 return TRUE;
1043 static LRESULT
1044 TREEVIEW_GetIndent (WND *wndPtr)
1046 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1048 TRACE (treeview,"\n");
1049 return infoPtr->uIndent;
1052 static LRESULT
1053 TREEVIEW_SetIndent (WND *wndPtr, WPARAM32 wParam)
1055 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1056 INT32 newIndent;
1058 TRACE (treeview,"\n");
1059 newIndent=(INT32) wParam;
1060 if (newIndent < MINIMUM_INDENT) newIndent=MINIMUM_INDENT;
1061 infoPtr->uIndent=newIndent;
1063 return 0;
1066 static LRESULT
1067 TREEVIEW_GetToolTips (WND *wndPtr)
1070 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1072 TRACE (treeview,"\n");
1073 return infoPtr->hwndToolTip;
1077 static LRESULT
1078 TREEVIEW_SetToolTips (WND *wndPtr, WPARAM32 wParam)
1081 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1082 HWND32 prevToolTip;
1084 TRACE (treeview,"\n");
1085 prevToolTip=infoPtr->hwndToolTip;
1086 infoPtr->hwndToolTip= (HWND32) wParam;
1088 return prevToolTip;
1096 static LRESULT
1097 TREEVIEW_Create (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1099 TREEVIEW_INFO *infoPtr;
1100 HDC32 hdc;
1101 TEXTMETRIC32A tm;
1103 TRACE (treeview,"\n");
1104 /* allocate memory for info structure */
1105 infoPtr = (TREEVIEW_INFO *) COMCTL32_Alloc (sizeof(TREEVIEW_INFO));
1107 wndPtr->wExtra[0] = (DWORD)infoPtr;
1109 if (infoPtr == NULL) {
1110 ERR (treeview, "could not allocate info memory!\n");
1111 return 0;
1114 if ((TREEVIEW_INFO*)wndPtr->wExtra[0] != infoPtr) {
1115 ERR (treeview, "pointer assignment error!\n");
1116 return 0;
1119 hdc=GetDC32 (wndPtr->hwndSelf);
1121 /* set default settings */
1122 infoPtr->uInternalStatus=0;
1123 infoPtr->uNumItems=0;
1124 infoPtr->clrBk = GetSysColor32 (COLOR_WINDOW);
1125 infoPtr->clrText = GetSysColor32 (COLOR_BTNTEXT);
1126 infoPtr->cy = 0;
1127 infoPtr->cx = 0;
1128 infoPtr->uIndent = 15;
1129 infoPtr->himlNormal = NULL;
1130 infoPtr->himlState = NULL;
1131 infoPtr->uItemHeight = -1;
1132 GetTextMetrics32A (hdc, &tm);
1133 infoPtr->hFont = GetStockObject32 (DEFAULT_GUI_FONT);
1134 infoPtr->uRealItemHeight= tm.tmHeight + tm.tmExternalLeading;
1136 infoPtr->items = NULL;
1137 infoPtr->selectedItem=0;
1138 infoPtr->clrText=-1; /* use system color */
1139 infoPtr->dropItem=0;
1142 infoPtr->hwndNotify = GetParent32 (wndPtr->hwndSelf);
1143 infoPtr->bTransparent = (wndPtr->dwStyle & TBSTYLE_FLAT);
1146 infoPtr->hwndToolTip=0;
1147 if (!(wndPtr->dwStyle & TVS_NOTOOLTIPS)) { /* Create tooltip control */
1148 TTTOOLINFO32A ti;
1150 infoPtr->hwndToolTip =
1151 CreateWindowEx32A (0, TOOLTIPS_CLASS32A, NULL, 0,
1152 CW_USEDEFAULT32, CW_USEDEFAULT32,
1153 CW_USEDEFAULT32, CW_USEDEFAULT32,
1154 wndPtr->hwndSelf, 0, 0, 0);
1156 /* Send NM_TOOLTIPSCREATED notification */
1157 if (infoPtr->hwndToolTip) {
1158 NMTOOLTIPSCREATED nmttc;
1160 nmttc.hdr.hwndFrom = wndPtr->hwndSelf;
1161 nmttc.hdr.idFrom = wndPtr->wIDmenu;
1162 nmttc.hdr.code = NM_TOOLTIPSCREATED;
1163 nmttc.hwndToolTips = infoPtr->hwndToolTip;
1165 SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
1166 (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmttc);
1169 ZeroMemory (&ti, sizeof(TTTOOLINFO32A));
1170 ti.cbSize = sizeof(TTTOOLINFO32A);
1171 ti.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_TRANSPARENT ;
1172 ti.hwnd = wndPtr->hwndSelf;
1173 ti.uId = 0;
1174 ti.lpszText = "Test"; /* LPSTR_TEXTCALLBACK; */
1175 SetRectEmpty32 (&ti.rect);
1177 SendMessage32A (infoPtr->hwndToolTip, TTM_ADDTOOL32A, 0, (LPARAM)&ti);
1180 ReleaseDC32 (wndPtr->hwndSelf, hdc);
1182 return 0;
1187 static LRESULT
1188 TREEVIEW_Destroy (WND *wndPtr)
1190 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1192 TRACE (treeview,"\n");
1193 TREEVIEW_RemoveTree (infoPtr);
1194 if (infoPtr->Timer & TV_REFRESH_TIMER_SET)
1195 KillTimer32 (wndPtr->hwndSelf, TV_REFRESH_TIMER);
1196 if (infoPtr->hwndToolTip)
1197 DestroyWindow32 (infoPtr->hwndToolTip);
1199 COMCTL32_Free (infoPtr);
1200 return 0;
1204 static LRESULT
1205 TREEVIEW_Paint (WND *wndPtr, WPARAM32 wParam)
1207 HDC32 hdc;
1208 PAINTSTRUCT32 ps;
1210 TRACE (treeview,"\n");
1211 hdc = wParam==0 ? BeginPaint32 (wndPtr->hwndSelf, &ps) : (HDC32)wParam;
1212 TREEVIEW_QueueRefresh (wndPtr);
1213 if(!wParam)
1214 EndPaint32 (wndPtr->hwndSelf, &ps);
1215 return 0;
1220 static LRESULT
1221 TREEVIEW_EraseBackground (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1223 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1224 HBRUSH32 hBrush = CreateSolidBrush32 (infoPtr->clrBk);
1225 RECT32 rect;
1227 TRACE (treeview,"\n");
1228 GetClientRect32 (wndPtr->hwndSelf, &rect);
1229 FillRect32 ((HDC32)wParam, &rect, hBrush);
1230 DeleteObject32 (hBrush);
1231 return TRUE;
1242 static BOOL32
1243 TREEVIEW_SendSimpleNotify (WND *wndPtr, UINT32 code)
1245 NMHDR nmhdr;
1247 TRACE (treeview, "%x\n",code);
1248 nmhdr.hwndFrom = wndPtr->hwndSelf;
1249 nmhdr.idFrom = wndPtr->wIDmenu;
1250 nmhdr.code = code;
1252 return (BOOL32) SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
1253 (WPARAM32)nmhdr.idFrom, (LPARAM)&nmhdr);
1259 static BOOL32
1260 TREEVIEW_SendTreeviewNotify (WND *wndPtr, UINT32 code, UINT32 action,
1261 INT32 oldItem, INT32 newItem, POINT32 pt)
1263 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1264 NMTREEVIEW nmhdr;
1265 TREEVIEW_ITEM *wineItem;
1267 TRACE (treeview,"code:%x action:%x olditem:%x newitem:%x\n",
1268 code,action,oldItem,newItem);
1269 nmhdr.hdr.hwndFrom = wndPtr->hwndSelf;
1270 nmhdr.hdr.idFrom = wndPtr->wIDmenu;
1271 nmhdr.hdr.code = code;
1272 nmhdr.action = action;
1273 if (oldItem) {
1274 wineItem=& infoPtr->items[oldItem];
1275 nmhdr.itemOld.mask = wineItem->mask;
1276 nmhdr.itemOld.hItem = wineItem->hItem;
1277 nmhdr.itemOld.state = wineItem->state;
1278 nmhdr.itemOld.stateMask = wineItem->stateMask;
1279 nmhdr.itemOld.iImage = wineItem->iImage;
1280 nmhdr.itemOld.pszText = wineItem->pszText;
1281 nmhdr.itemOld.cchTextMax = wineItem->cchTextMax;
1282 nmhdr.itemOld.iImage = wineItem->iImage;
1283 nmhdr.itemOld.iSelectedImage = wineItem->iSelectedImage;
1284 nmhdr.itemOld.cChildren = wineItem->cChildren;
1285 nmhdr.itemOld.lParam = wineItem->lParam;
1288 if (newItem) {
1289 wineItem=& infoPtr->items[newItem];
1290 nmhdr.itemNew.mask = wineItem->mask;
1291 nmhdr.itemNew.hItem = wineItem->hItem;
1292 nmhdr.itemNew.state = wineItem->state;
1293 nmhdr.itemNew.stateMask = wineItem->stateMask;
1294 nmhdr.itemNew.iImage = wineItem->iImage;
1295 nmhdr.itemNew.pszText = wineItem->pszText;
1296 nmhdr.itemNew.cchTextMax = wineItem->cchTextMax;
1297 nmhdr.itemNew.iImage = wineItem->iImage;
1298 nmhdr.itemNew.iSelectedImage = wineItem->iSelectedImage;
1299 nmhdr.itemNew.cChildren = wineItem->cChildren;
1300 nmhdr.itemNew.lParam = wineItem->lParam;
1303 nmhdr.ptDrag.x = pt.x;
1304 nmhdr.ptDrag.y = pt.y;
1306 return (BOOL32)SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
1307 (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmhdr);
1314 static LRESULT
1315 TREEVIEW_Expand (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1317 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1318 TREEVIEW_ITEM *wineItem;
1319 UINT32 flag;
1320 INT32 expandItem;
1321 POINT32 pt;
1323 flag= (UINT32) wParam;
1324 expandItem= (INT32) lParam;
1325 TRACE (treeview,"flags:%x item:%x\n", expandItem, wParam);
1326 wineItem = TREEVIEW_ValidItem (infoPtr, expandItem);
1327 if (!wineItem) return 0;
1328 if (!wineItem->cChildren) return 0;
1330 if (flag & TVE_TOGGLE) { /* FIXME: check exact behaviour here */
1331 flag &= ~TVE_TOGGLE; /* ie: bitwise ops or 'case' ops */
1332 if (wineItem->state & TVIS_EXPANDED)
1333 flag |= TVE_COLLAPSE;
1334 else
1335 flag |= TVE_EXPAND;
1338 switch (flag) {
1339 case TVE_COLLAPSERESET:
1340 if (!wineItem->state & TVIS_EXPANDED) return 0;
1341 wineItem->state &= ~(TVIS_EXPANDEDONCE | TVIS_EXPANDED);
1342 TREEVIEW_RemoveAllChildren (infoPtr, wineItem);
1343 break;
1345 case TVE_COLLAPSE:
1346 if (!wineItem->state & TVIS_EXPANDED) return 0;
1347 wineItem->state &= ~TVIS_EXPANDED;
1348 break;
1350 case TVE_EXPAND:
1351 if (wineItem->state & TVIS_EXPANDED) return 0;
1352 if (!(wineItem->state & TVIS_EXPANDEDONCE)) {
1353 if (TREEVIEW_SendTreeviewNotify (wndPtr, TVN_ITEMEXPANDING,
1354 0, 0, expandItem, pt))
1355 return FALSE; /* FIXME: OK? */
1356 wineItem->state |= TVIS_EXPANDED | TVIS_EXPANDEDONCE;
1357 TREEVIEW_SendTreeviewNotify (wndPtr, TVN_ITEMEXPANDED,
1358 0, 0, expandItem, pt);
1360 wineItem->state |= TVIS_EXPANDED;
1361 break;
1362 case TVE_EXPANDPARTIAL:
1363 FIXME (treeview, "TVE_EXPANDPARTIAL not implemented\n");
1364 wineItem->state ^=TVIS_EXPANDED;
1365 wineItem->state |=TVIS_EXPANDEDONCE;
1366 break;
1369 TREEVIEW_QueueRefresh (wndPtr);
1371 return TRUE;
1376 static HTREEITEM
1377 TREEVIEW_HitTest (WND *wndPtr, LPTVHITTESTINFO lpht)
1379 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1380 TREEVIEW_ITEM *wineItem;
1381 RECT32 rect;
1382 UINT32 status,x,y;
1386 GetClientRect32 (wndPtr->hwndSelf, &rect);
1387 TRACE (treeview,"(%d,%d)\n",lpht->pt.x, lpht->pt.y);
1389 status=0;
1390 x=lpht->pt.x;
1391 y=lpht->pt.y;
1392 if (x < rect.left) status|=TVHT_TOLEFT;
1393 if (x > rect.right) status|=TVHT_TORIGHT;
1394 if (y < rect.top ) status|=TVHT_ABOVE;
1395 if (y > rect.bottom) status|=TVHT_BELOW;
1396 if (status) {
1397 lpht->flags=status;
1398 return 0;
1401 if (!infoPtr->firstVisible) WARN (treeview,"Can't fetch first visible item");
1402 wineItem=&infoPtr->items [infoPtr->firstVisible];
1404 while ((wineItem!=NULL) && (y > wineItem->rect.bottom))
1405 wineItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
1407 if (wineItem==NULL) {
1408 lpht->flags=TVHT_NOWHERE;
1409 return 0;
1412 if (x>wineItem->rect.right) {
1413 lpht->flags|=TVHT_ONITEMRIGHT;
1414 return wineItem->hItem;
1418 if (x<wineItem->rect.left+10) lpht->flags|=TVHT_ONITEMBUTTON;
1420 lpht->flags=TVHT_ONITEMLABEL; /* FIXME: implement other flags */
1423 lpht->hItem=wineItem->hItem;
1424 return wineItem->hItem;
1428 static LRESULT
1429 TREEVIEW_HitTest32 (WND *wndPtr, LPARAM lParam)
1432 return (LRESULT) TREEVIEW_HitTest (wndPtr, (LPTVHITTESTINFO) lParam);
1438 LRESULT
1439 TREEVIEW_LButtonDoubleClick (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1441 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1442 TREEVIEW_ITEM *wineItem;
1443 INT32 iItem;
1444 TVHITTESTINFO ht;
1446 TRACE (treeview,"\n");
1447 ht.pt.x = (INT32)LOWORD(lParam);
1448 ht.pt.y = (INT32)HIWORD(lParam);
1449 SetFocus32 (wndPtr->hwndSelf);
1451 iItem=TREEVIEW_HitTest (wndPtr, &ht);
1452 TRACE (treeview,"item %d \n",iItem);
1453 wineItem=TREEVIEW_ValidItem (infoPtr, iItem);
1454 if (!wineItem) return 0;
1456 if (TREEVIEW_SendSimpleNotify (wndPtr, NM_DBLCLK)!=TRUE) { /* FIXME!*/
1457 wineItem->state &= ~TVIS_EXPANDEDONCE;
1458 TREEVIEW_Expand (wndPtr, (WPARAM32) TVE_TOGGLE, (LPARAM) iItem);
1460 return TRUE;
1465 static LRESULT
1466 TREEVIEW_LButtonDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1468 INT32 iItem;
1469 TVHITTESTINFO ht;
1471 TRACE (treeview,"\n");
1472 ht.pt.x = (INT32)LOWORD(lParam);
1473 ht.pt.y = (INT32)HIWORD(lParam);
1475 SetFocus32 (wndPtr->hwndSelf);
1476 iItem=TREEVIEW_HitTest (wndPtr, &ht);
1477 TRACE (treeview,"item %d \n",iItem);
1478 if (ht.flags & TVHT_ONITEMBUTTON) {
1479 TREEVIEW_Expand (wndPtr, (WPARAM32) TVE_TOGGLE, (LPARAM) iItem);
1482 if (TREEVIEW_SelectItem (wndPtr, (WPARAM32) TVGN_CARET, (LPARAM) iItem))
1483 return 0;
1486 return 0;
1490 static LRESULT
1491 TREEVIEW_RButtonDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1494 TRACE (treeview,"\n");
1495 return 0;
1501 /* FIXME: If the specified item is the child of a collapsed parent item,
1502 expand parent's list of child items to reveal the specified item.
1505 static LRESULT
1506 TREEVIEW_SelectItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1508 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1509 TREEVIEW_ITEM *prevItem,*wineItem;
1510 INT32 action,prevSelect, newSelect;
1511 POINT32 dummy;
1513 TRACE (treeview,"item %lx, flag %x\n", lParam, wParam);
1514 newSelect= (INT32) lParam;
1515 wineItem = TREEVIEW_ValidItem (infoPtr, newSelect);
1516 if (!wineItem) return FALSE;
1517 prevSelect=infoPtr->selectedItem;
1518 prevItem= TREEVIEW_ValidItem (infoPtr, prevSelect);
1519 dummy.x=0;
1520 dummy.y=0;
1522 action= (INT32) wParam;
1524 switch (action) {
1525 case TVGN_CARET:
1526 if (TREEVIEW_SendTreeviewNotify (wndPtr, TVN_SELCHANGING, TVC_BYMOUSE,
1527 prevSelect, newSelect,dummy))
1528 return FALSE; /* FIXME: OK? */
1530 if (prevItem) prevItem->state &= ~TVIS_SELECTED;
1531 infoPtr->selectedItem=newSelect;
1532 wineItem->state |=TVIS_SELECTED;
1533 TREEVIEW_SendTreeviewNotify (wndPtr, TVN_SELCHANGED,
1534 TVC_BYMOUSE, prevSelect, newSelect, dummy);
1535 break;
1536 case TVGN_DROPHILITE:
1537 FIXME (treeview, "DROPHILITE not implemented");
1538 break;
1539 case TVGN_FIRSTVISIBLE:
1540 FIXME (treeview, "FIRSTVISIBLE not implemented");
1541 break;
1544 TREEVIEW_QueueRefresh (wndPtr);
1546 return TRUE;
1552 static LRESULT
1553 TREEVIEW_GetFont (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1556 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1558 TRACE (treeview,"%x\n",infoPtr->hFont);
1559 return infoPtr->hFont;
1562 static LRESULT
1563 TREEVIEW_SetFont (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1566 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1567 TEXTMETRIC32A tm;
1568 HFONT32 hFont, hOldFont;
1569 HDC32 hdc;
1571 TRACE (treeview,"%x %lx\n",wParam, lParam);
1573 infoPtr->hFont = (HFONT32)wParam;
1575 hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject32 (SYSTEM_FONT);
1577 hdc = GetDC32 (0);
1578 hOldFont = SelectObject32 (hdc, hFont);
1579 GetTextMetrics32A (hdc, &tm);
1580 infoPtr->uRealItemHeight= tm.tmHeight + tm.tmExternalLeading;
1581 SelectObject32 (hdc, hOldFont);
1582 ReleaseDC32 (0, hdc);
1584 if (lParam)
1585 TREEVIEW_QueueRefresh (wndPtr);
1587 return 0;
1591 /* FIXME: does KEYDOWN also send notifications?? If so, use
1592 TREEVIEW_SelectItem.
1596 static LRESULT
1597 TREEVIEW_KeyDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1599 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1600 TREEVIEW_ITEM *prevItem,*newItem;
1601 int prevSelect;
1604 TRACE (treeview,"%x %lx\n",wParam, lParam);
1605 prevSelect=infoPtr->selectedItem;
1606 if (!prevSelect) return FALSE;
1608 prevItem= TREEVIEW_ValidItem (infoPtr, prevSelect);
1610 newItem=NULL;
1611 switch (wParam) {
1612 case VK_UP:
1613 newItem=TREEVIEW_GetPrevListItem (infoPtr, prevItem);
1614 if (!newItem)
1615 newItem=& infoPtr->items[infoPtr->TopRootItem];
1616 break;
1617 case VK_DOWN:
1618 newItem=TREEVIEW_GetNextListItem (infoPtr, prevItem);
1619 if (!newItem) newItem=prevItem;
1620 break;
1621 case VK_HOME:
1622 newItem=& infoPtr->items[infoPtr->TopRootItem];
1623 break;
1624 case VK_END:
1625 newItem=TREEVIEW_GetLastListItem (infoPtr);
1626 break;
1627 case VK_PRIOR:
1628 case VK_NEXT:
1629 case VK_BACK:
1630 case VK_RETURN:
1631 FIXME (treeview, "%x not implemented\n", wParam);
1632 break;
1635 if (!newItem) return FALSE;
1637 if (prevItem!=newItem) {
1638 prevItem->state &= ~TVIS_SELECTED;
1639 newItem->state |= TVIS_SELECTED;
1640 infoPtr->selectedItem=newItem->hItem;
1641 TREEVIEW_QueueRefresh (wndPtr);
1642 return TRUE;
1645 return FALSE;
1650 static LRESULT
1651 TREEVIEW_VScroll (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1654 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1655 int maxHeight;
1657 TRACE (treeview,"wp %x, lp %lx\n", wParam, lParam);
1658 if (!infoPtr->uInternalStatus & TV_VSCROLL) return FALSE;
1660 switch (LOWORD (wParam)) {
1661 case SB_LINEUP:
1662 if (!infoPtr->cy) return FALSE;
1663 infoPtr->cy -= infoPtr->uRealItemHeight;
1664 if (infoPtr->cy < 0) infoPtr->cy=0;
1665 break;
1666 case SB_LINEDOWN:
1667 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
1668 if (infoPtr->cy == maxHeight) return FALSE;
1669 infoPtr->cy += infoPtr->uRealItemHeight;
1670 if (infoPtr->cy > maxHeight)
1671 infoPtr->cy = maxHeight;
1672 break;
1673 case SB_PAGEUP:
1674 if (!infoPtr->cy) return FALSE;
1675 infoPtr->cy -= infoPtr->uVisibleHeight;
1676 if (infoPtr->cy < 0) infoPtr->cy=0;
1677 break;
1678 case SB_PAGEDOWN:
1679 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
1680 if (infoPtr->cy == maxHeight) return FALSE;
1681 infoPtr->cy += infoPtr->uVisibleHeight;
1682 if (infoPtr->cy > maxHeight)
1683 infoPtr->cy = maxHeight;
1684 break;
1685 case SB_THUMBTRACK:
1686 infoPtr->cy = HIWORD (wParam);
1687 break;
1691 TREEVIEW_QueueRefresh (wndPtr);
1692 return TRUE;
1695 static LRESULT
1696 TREEVIEW_HScroll (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1698 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1700 TRACE (treeview,"wp %lx, lp %x\n", lParam, wParam);
1702 if (!infoPtr->uInternalStatus & TV_HSCROLL) return FALSE;
1703 return TRUE;
1709 LRESULT WINAPI
1710 TREEVIEW_WindowProc (HWND32 hwnd, UINT32 uMsg, WPARAM32 wParam, LPARAM lParam)
1712 WND *wndPtr = WIN_FindWndPtr(hwnd);
1715 switch (uMsg) {
1716 case TVM_INSERTITEM32A:
1717 return TREEVIEW_InsertItem32A (wndPtr, wParam, lParam);
1719 case TVM_INSERTITEM32W:
1720 FIXME (treeview, "Unimplemented msg TVM_INSERTITEM32W\n");
1721 return 0;
1723 case TVM_DELETEITEM:
1724 return TREEVIEW_DeleteItem (wndPtr, wParam, lParam);
1726 case TVM_EXPAND:
1727 return TREEVIEW_Expand (wndPtr, wParam, lParam);
1729 case TVM_GETITEMRECT:
1730 return TREEVIEW_GetItemRect (wndPtr, wParam, lParam);
1732 case TVM_GETCOUNT:
1733 return TREEVIEW_GetCount (wndPtr, wParam, lParam);
1735 case TVM_GETINDENT:
1736 return TREEVIEW_GetIndent (wndPtr);
1738 case TVM_SETINDENT:
1739 return TREEVIEW_SetIndent (wndPtr, wParam);
1741 case TVM_GETIMAGELIST:
1742 return TREEVIEW_GetImageList (wndPtr, wParam, lParam);
1744 case TVM_SETIMAGELIST:
1745 return TREEVIEW_SetImageList (wndPtr, wParam, lParam);
1747 case TVM_GETNEXTITEM:
1748 return TREEVIEW_GetNextItem32 (wndPtr, wParam, lParam);
1750 case TVM_SELECTITEM:
1751 return TREEVIEW_SelectItem (wndPtr, wParam, lParam);
1753 case TVM_GETITEM32A:
1754 return TREEVIEW_GetItem (wndPtr, wParam, lParam);
1756 case TVM_GETITEM32W:
1757 FIXME (treeview, "Unimplemented msg TVM_GETITEM32W\n");
1758 return 0;
1760 case TVM_SETITEM32A:
1761 return TREEVIEW_SetItem (wndPtr, wParam, lParam);
1763 case TVM_SETITEM32W:
1764 FIXME (treeview, "Unimplemented msg TVM_SETITEMW\n");
1765 return 0;
1767 case TVM_EDITLABEL32A:
1768 FIXME (treeview, "Unimplemented msg TVM_EDITLABEL32A \n");
1769 return 0;
1771 case TVM_EDITLABEL32W:
1772 FIXME (treeview, "Unimplemented msg TVM_EDITLABEL32W \n");
1773 return 0;
1775 case TVM_GETEDITCONTROL:
1776 FIXME (treeview, "Unimplemented msg TVM_GETEDITCONTROL\n");
1777 return 0;
1779 case TVM_GETVISIBLECOUNT:
1780 return TREEVIEW_GetVisibleCount (wndPtr, wParam, lParam);
1782 case TVM_HITTEST:
1783 return TREEVIEW_HitTest32 (wndPtr, lParam);
1785 case TVM_CREATEDRAGIMAGE:
1786 FIXME (treeview, "Unimplemented msg TVM_CREATEDRAGIMAGE\n");
1787 return 0;
1789 case TVM_SORTCHILDREN:
1790 FIXME (treeview, "Unimplemented msg TVM_SORTCHILDREN\n");
1791 return 0;
1793 case TVM_ENSUREVISIBLE:
1794 FIXME (treeview, "Unimplemented msg TVM_ENSUREVISIBLE\n");
1795 return 0;
1797 case TVM_SORTCHILDRENCB:
1798 FIXME (treeview, "Unimplemented msg TVM_SORTCHILDRENCB\n");
1799 return 0;
1801 case TVM_ENDEDITLABELNOW:
1802 FIXME (treeview, "Unimplemented msg TVM_ENDEDITLABELNOW\n");
1803 return 0;
1805 case TVM_GETISEARCHSTRING32A:
1806 FIXME (treeview, "Unimplemented msg TVM_GETISEARCHSTRING32A\n");
1807 return 0;
1809 case TVM_GETISEARCHSTRING32W:
1810 FIXME (treeview, "Unimplemented msg TVM_GETISEARCHSTRING32W\n");
1811 return 0;
1813 case TVM_GETTOOLTIPS:
1814 return TREEVIEW_GetToolTips (wndPtr);
1816 case TVM_SETTOOLTIPS:
1817 return TREEVIEW_SetToolTips (wndPtr, wParam);
1819 case TVM_SETINSERTMARK:
1820 FIXME (treeview, "Unimplemented msg TVM_SETINSERTMARK\n");
1821 return 0;
1823 case TVM_SETITEMHEIGHT:
1824 return TREEVIEW_SetItemHeight (wndPtr, wParam);
1826 case TVM_GETITEMHEIGHT:
1827 return TREEVIEW_GetItemHeight (wndPtr);
1829 case TVM_SETBKCOLOR:
1830 FIXME (treeview, "Unimplemented msg TVM_SETBKCOLOR\n");
1831 return 0;
1833 case TVM_SETTEXTCOLOR:
1834 return TREEVIEW_SetTextColor (wndPtr, wParam, lParam);
1836 case TVM_GETBKCOLOR:
1837 FIXME (treeview, "Unimplemented msg TVM_GETBKCOLOR\n");
1838 return 0;
1840 case TVM_GETTEXTCOLOR:
1841 return TREEVIEW_GetTextColor (wndPtr);
1843 case TVM_SETSCROLLTIME:
1844 FIXME (treeview, "Unimplemented msg TVM_SETSCROLLTIME\n");
1845 return 0;
1847 case TVM_GETSCROLLTIME:
1848 FIXME (treeview, "Unimplemented msg TVM_GETSCROLLTIME\n");
1849 return 0;
1851 case TVM_SETINSERTMARKCOLOR:
1852 FIXME (treeview, "Unimplemented msg TVM_SETINSERTMARKCOLOR\n");
1853 return 0;
1855 case TVM_SETUNICODEFORMAT:
1856 FIXME (treeview, "Unimplemented msg TVM_SETUNICODEFORMAT\n");
1857 return 0;
1859 case TVM_GETUNICODEFORMAT:
1860 FIXME (treeview, "Unimplemented msg TVM_GETUNICODEFORMAT\n");
1861 return 0;
1863 /* case WM_COMMAND: */
1865 case WM_CREATE:
1866 return TREEVIEW_Create (wndPtr, wParam, lParam);
1868 case WM_DESTROY:
1869 return TREEVIEW_Destroy (wndPtr);
1871 /* case WM_ENABLE: */
1873 case WM_ERASEBKGND:
1874 return TREEVIEW_EraseBackground (wndPtr, wParam, lParam);
1876 case WM_GETDLGCODE:
1877 return DLGC_WANTARROWS | DLGC_WANTCHARS;
1879 case WM_PAINT:
1880 return TREEVIEW_Paint (wndPtr, wParam);
1882 case WM_GETFONT:
1883 return TREEVIEW_GetFont (wndPtr, wParam, lParam);
1885 case WM_SETFONT:
1886 return TREEVIEW_SetFont (wndPtr, wParam, lParam);
1888 case WM_KEYDOWN:
1889 return TREEVIEW_KeyDown (wndPtr, wParam, lParam);
1892 /* case WM_KILLFOCUS: */
1893 /* case WM_SETFOCUS: */
1896 case WM_LBUTTONDOWN:
1897 return TREEVIEW_LButtonDown (wndPtr, wParam, lParam);
1899 case WM_LBUTTONDBLCLK:
1900 return TREEVIEW_LButtonDoubleClick (wndPtr, wParam, lParam);
1902 case WM_RBUTTONDOWN:
1903 return TREEVIEW_RButtonDown (wndPtr, wParam, lParam);
1906 /* case WM_SYSCOLORCHANGE: */
1907 /* case WM_STYLECHANGED: */
1908 /* case WM_SETREDRAW: */
1910 case WM_TIMER:
1911 return TREEVIEW_HandleTimer (wndPtr, wParam, lParam);
1913 /* case WM_SIZE: */
1914 case WM_HSCROLL:
1915 return TREEVIEW_HScroll (wndPtr, wParam, lParam);
1916 case WM_VSCROLL:
1917 return TREEVIEW_VScroll (wndPtr, wParam, lParam);
1919 default:
1920 if (uMsg >= WM_USER)
1921 FIXME (treeview, "Unknown msg %04x wp=%08x lp=%08lx\n",
1922 uMsg, wParam, lParam);
1923 return DefWindowProc32A (hwnd, uMsg, wParam, lParam);
1925 return 0;
1929 VOID
1930 TREEVIEW_Register (VOID)
1932 WNDCLASS32A wndClass;
1934 TRACE (treeview,"\n");
1936 if (GlobalFindAtom32A (WC_TREEVIEW32A)) return;
1938 ZeroMemory (&wndClass, sizeof(WNDCLASS32A));
1939 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
1940 wndClass.lpfnWndProc = (WNDPROC32)TREEVIEW_WindowProc;
1941 wndClass.cbClsExtra = 0;
1942 wndClass.cbWndExtra = sizeof(TREEVIEW_INFO *);
1943 wndClass.hCursor = LoadCursor32A (0, IDC_ARROW32A);
1944 wndClass.hbrBackground = 0;
1945 wndClass.lpszClassName = WC_TREEVIEW32A;
1947 RegisterClass32A (&wndClass);
1951 VOID
1952 TREEVIEW_Unregister (VOID)
1954 if (GlobalFindAtom32A (WC_TREEVIEW32A))
1955 UnregisterClass32A (WC_TREEVIEW32A, (HINSTANCE32)NULL);