Release 981025.
[wine/multimedia.git] / dlls / comctl32 / treeview.c
blob52e02dd02b08522044f338900ca9cc7724493d34
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 flag for traversing visible items
24 -DblClick: ctlmacro.exe's NM_DBLCLK seems to go wrong (returns FALSE).
28 #include "windows.h"
29 #include "commctrl.h"
30 #include "treeview.h"
31 #include "heap.h"
32 #include "win.h"
33 #include "debug.h"
35 #if defined(__FreeBSD__)
36 #include <bitstring.h>
37 #define test_bit(bit,name) bit_test(name,bit)
38 #define set_bit(bit,name) bit_set(name,bit)
39 #define clear_bit(bit,name) bit_clear(name,bit)
40 #else
41 #include <asm/bitops.h> /* FIXME: linux specific */
42 #endif
44 #define TREEVIEW_GetInfoPtr(wndPtr) ((TREEVIEW_INFO *)wndPtr->wExtra[0])
46 static BOOL32
47 TREEVIEW_SendSimpleNotify (WND *wndPtr, UINT32 code);
48 static BOOL32
49 TREEVIEW_SendTreeviewNotify (WND *wndPtr, UINT32 code, UINT32 action,
50 INT32 oldItem, INT32 newItem, POINT32 pt);
51 static LRESULT
52 TREEVIEW_SelectItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
53 static void
54 TREEVIEW_Refresh (WND *wndPtr, HDC32 hdc);
60 /* helper functions. Work with the assumption that validity of operands
61 is checked beforehand */
64 static TREEVIEW_ITEM *
65 TREEVIEW_ValidItem (TREEVIEW_INFO *infoPtr,int handle)
68 if ((!handle) || (handle>infoPtr->uMaxHandle)) return NULL;
69 if (test_bit (handle, infoPtr->freeList)) return NULL;
71 return & infoPtr->items[handle];
76 static TREEVIEW_ITEM *TREEVIEW_GetPrevListItem (TREEVIEW_INFO *infoPtr,
77 TREEVIEW_ITEM *tvItem)
80 TREEVIEW_ITEM *wineItem;
82 if (tvItem->upsibling)
83 return (& infoPtr->items[tvItem->upsibling]);
85 wineItem=tvItem;
86 while (wineItem->parent) {
87 wineItem=& infoPtr->items[wineItem->parent];
88 if (wineItem->upsibling)
89 return (& infoPtr->items[wineItem->upsibling]);
92 return NULL;
95 static TREEVIEW_ITEM *TREEVIEW_GetNextListItem (TREEVIEW_INFO *infoPtr,
96 TREEVIEW_ITEM *tvItem)
99 TREEVIEW_ITEM *wineItem;
101 if (tvItem->sibling)
102 return (& infoPtr->items[tvItem->sibling]);
104 wineItem=tvItem;
105 while (wineItem->parent) {
106 wineItem=& infoPtr->items [wineItem->parent];
107 if (wineItem->sibling)
108 return (& infoPtr->items [wineItem->sibling]);
111 return NULL;
114 static TREEVIEW_ITEM *TREEVIEW_GetLastListItem (TREEVIEW_INFO *infoPtr)
117 TREEVIEW_ITEM *wineItem;
119 wineItem=NULL;
120 if (infoPtr->TopRootItem)
121 wineItem=& infoPtr->items [infoPtr->TopRootItem];
122 while (wineItem->sibling)
123 wineItem=& infoPtr->items [wineItem->sibling];
125 return wineItem;
131 static void
132 TREEVIEW_RemoveItem (TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem)
135 TREEVIEW_ITEM *parentItem, *upsiblingItem, *siblingItem;
136 INT32 iItem;
138 iItem=wineItem->hItem;
139 set_bit ( iItem & 31, &infoPtr->freeList[iItem >>5]);
140 infoPtr->uNumItems--;
141 parentItem=NULL;
142 if (wineItem->pszText!=LPSTR_TEXTCALLBACK32A)
143 HeapFree (GetProcessHeap (), 0, wineItem->pszText);
145 if (wineItem->parent) {
146 parentItem=& infoPtr->items[ wineItem->parent];
147 if (parentItem->cChildren==1) {
148 parentItem->cChildren=0;
149 parentItem->firstChild=0;
150 return;
151 } else {
152 parentItem->cChildren--;
153 if (parentItem->firstChild==iItem)
154 parentItem->firstChild=wineItem->sibling;
158 if (iItem==infoPtr->TopRootItem)
159 infoPtr->TopRootItem=wineItem->sibling;
160 if (wineItem->upsibling) {
161 upsiblingItem=& infoPtr->items [wineItem->upsibling];
162 upsiblingItem->sibling=wineItem->sibling;
164 if (wineItem->sibling) {
165 siblingItem=& infoPtr->items [wineItem->sibling];
166 siblingItem->upsibling=wineItem->upsibling;
172 static void TREEVIEW_RemoveAllChildren (TREEVIEW_INFO *infoPtr,
173 TREEVIEW_ITEM *parentItem)
176 TREEVIEW_ITEM *killItem;
177 INT32 kill;
179 kill=parentItem->firstChild;
180 while (kill) {
181 set_bit ( kill & 31, &infoPtr->freeList[kill >>5]);
182 killItem=& infoPtr->items[kill];
183 if (killItem->pszText!=LPSTR_TEXTCALLBACK32A)
184 HeapFree (GetProcessHeap (), 0, killItem->pszText);
185 kill=killItem->sibling;
187 infoPtr->uNumItems -= parentItem->cChildren;
188 parentItem->firstChild = 0;
189 parentItem->cChildren = 0;
193 /* Note:TREEVIEW_RemoveTree doesn't remove infoPtr itself */
195 static void TREEVIEW_RemoveTree (TREEVIEW_INFO *infoPtr)
199 TREEVIEW_ITEM *killItem;
200 int i;
202 for (i=1; i<=infoPtr->uMaxHandle; i++)
203 if (!test_bit (i, infoPtr->freeList)) {
204 killItem=& infoPtr->items [i];
205 if (killItem->pszText!=LPSTR_TEXTCALLBACK32A)
206 HeapFree (GetProcessHeap (), 0, killItem->pszText);
209 if (infoPtr->uNumPtrsAlloced) {
210 HeapFree (GetProcessHeap (), 0, infoPtr->items);
211 HeapFree (GetProcessHeap (), 0, infoPtr->freeList);
212 infoPtr->uNumItems=0;
213 infoPtr->uNumPtrsAlloced=0;
214 infoPtr->uMaxHandle=0;
227 static LRESULT
228 TREEVIEW_GetImageList (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
230 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
232 TRACE (treeview,"\n");
234 if (infoPtr==NULL) return 0;
236 if ((INT32)wParam == TVSIL_NORMAL)
237 return (LRESULT) infoPtr->himlNormal;
238 if ((INT32)wParam == TVSIL_STATE)
239 return (LRESULT) infoPtr->himlState;
241 return 0;
247 static LRESULT
248 TREEVIEW_SetImageList (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
250 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
251 HIMAGELIST himlTemp;
253 switch ((INT32)wParam) {
254 case TVSIL_NORMAL:
255 himlTemp = infoPtr->himlNormal;
256 infoPtr->himlNormal = (HIMAGELIST)lParam;
257 return (LRESULT)himlTemp;
259 case TVSIL_STATE:
260 himlTemp = infoPtr->himlState;
261 infoPtr->himlState = (HIMAGELIST)lParam;
262 return (LRESULT)himlTemp;
265 return (LRESULT)NULL;
270 static LRESULT
271 TREEVIEW_SetItemHeight (WND *wndPtr, WPARAM32 wParam)
273 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
274 INT32 prevHeight=infoPtr->uItemHeight;
275 HDC32 hdc;
276 TEXTMETRIC32A tm;
279 if (wParam==-1) {
280 hdc=GetDC32 (wndPtr->hwndSelf);
281 infoPtr->uItemHeight=-1;
282 GetTextMetrics32A (hdc, &tm);
283 infoPtr->uRealItemHeight= tm.tmHeight + tm.tmExternalLeading;
284 ReleaseDC32 (wndPtr->hwndSelf, hdc);
285 return prevHeight;
288 /* FIXME: check wParam > imagelist height */
290 if (!(wndPtr->dwStyle & TVS_NONEVENHEIGHT))
291 infoPtr->uItemHeight = (INT32) wParam & 0xfffffffe;
292 return prevHeight;
295 static LRESULT
296 TREEVIEW_GetItemHeight (WND *wndPtr)
298 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
300 return infoPtr->uItemHeight;
303 static LRESULT
304 TREEVIEW_SetTextColor (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
306 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
307 COLORREF prevColor=infoPtr->clrText;
309 infoPtr->clrText=(COLORREF) lParam;
310 return (LRESULT) prevColor;
313 static LRESULT
314 TREEVIEW_GetTextColor (WND *wndPtr)
316 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
318 return (LRESULT) infoPtr->clrText;
322 static INT32
323 TREEVIEW_DrawItem (WND *wndPtr, HDC32 hdc, TREEVIEW_ITEM *wineItem,
324 TREEVIEW_ITEM *upperItem, int indent)
326 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
327 INT32 oldBkMode,center,xpos;
328 COLORREF oldBkColor;
329 UINT32 uTextJustify = DT_LEFT;
330 HPEN32 hOldPen, hnewPen,hRootPen;
331 RECT32 r,upper;
333 hnewPen = CreatePen32(PS_DOT, 0, GetSysColor32(COLOR_WINDOWTEXT) );
334 hOldPen = SelectObject32( hdc, hnewPen );
336 r=wineItem->rect;
337 if (upperItem)
338 upper=upperItem->rect;
339 else {
340 upper.top=0;
341 upper.left=8;
343 center=(r.top+r.bottom)/2;
344 xpos=r.left+8;
346 if (wndPtr->dwStyle & TVS_HASLINES) {
347 POINT32 points[3];
348 if ((wndPtr->dwStyle & TVS_LINESATROOT) && (indent==0)) {
349 points[0].y=points[1].y=center;
350 points[2].y=upper.top;
351 points[1].x=points[2].x=upper.left;
352 points[0].x=upper.left+12;
353 points[2].y+=5;
355 Polyline32 (hdc,points,3);
357 else {
358 points[0].y=points[1].y=center;
359 points[2].y=upper.top;
360 points[1].x=points[2].x=upper.left+13;
361 points[0].x=upper.left+25;
362 points[2].y+=5;
363 Polyline32 (hdc,points,3);
367 DeleteObject32(hnewPen);
368 SelectObject32(hdc, hOldPen);
370 if ((wndPtr->dwStyle & TVS_HASBUTTONS) && (wineItem->cChildren)) {
372 hRootPen = CreatePen32(PS_SOLID, 0, GetSysColor32(COLOR_WINDOW) );
373 SelectObject32( hdc, hRootPen );
376 Rectangle32 (hdc, xpos-4, center-4, xpos+5, center+5);
377 MoveToEx32 (hdc, xpos-2, center, NULL);
378 LineTo32 (hdc, xpos+3, center);
379 if (!(wineItem->state & TVIS_EXPANDED)) {
380 MoveToEx32 (hdc, xpos, center-2, NULL);
381 LineTo32 (hdc, xpos, center+3);
383 /* DeleteObject32(hRootPen); */
387 xpos+=13;
389 if (wineItem->mask & TVIF_IMAGE) {
390 if (wineItem->iImage!=I_IMAGECALLBACK) {
391 if (infoPtr->himlNormal) {
392 ImageList_Draw (infoPtr->himlNormal,wineItem->iImage, hdc,
393 xpos-2, r.top+1, ILD_NORMAL);
394 xpos+=15;
399 r.left=xpos;
400 if ((wineItem->mask & TVIF_TEXT) && (wineItem->pszText)) {
401 if (wineItem->state & TVIS_SELECTED) {
402 oldBkMode = SetBkMode32(hdc, OPAQUE);
403 oldBkColor= SetBkColor32 (hdc, GetSysColor32( COLOR_HIGHLIGHT));
404 SetTextColor32 (hdc, GetSysColor32(COLOR_HIGHLIGHTTEXT));
406 else {
407 oldBkMode = SetBkMode32(hdc, TRANSPARENT);
409 r.left += 3;
410 r.right -= 3;
411 if (infoPtr->clrText==-1)
412 SetTextColor32 (hdc, COLOR_BTNTEXT);
413 else
414 SetTextColor32 (hdc, infoPtr->clrText); /* FIXME: retval */
415 DrawText32A(hdc, wineItem->pszText, lstrlen32A(wineItem->pszText),
416 &r, uTextJustify|DT_VCENTER|DT_SINGLELINE);
417 if (oldBkMode != TRANSPARENT)
418 SetBkMode32(hdc, oldBkMode);
419 if (wineItem->state & TVIS_SELECTED)
420 SetBkColor32 (hdc, oldBkColor);
423 return wineItem->rect.right;
432 static LRESULT
433 TREEVIEW_GetItemRect (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
435 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
436 TREEVIEW_ITEM *wineItem;
437 INT32 iItem;
438 LPRECT32 lpRect;
440 TRACE (treeview,"\n");
441 if (infoPtr==NULL) return FALSE;
443 iItem = (INT32)lParam;
444 wineItem = TREEVIEW_ValidItem (infoPtr, iItem);
445 if (!wineItem) return FALSE;
447 wineItem=& infoPtr->items[ iItem ];
448 if (!wineItem->visible) return FALSE;
450 lpRect = (LPRECT32)lParam;
451 if (lpRect == NULL) return FALSE;
453 if ((INT32) wParam) {
454 lpRect->left = wineItem->text.left;
455 lpRect->right = wineItem->text.right;
456 lpRect->bottom = wineItem->text.bottom;
457 lpRect->top = wineItem->text.top;
458 } else {
459 lpRect->left = wineItem->rect.left;
460 lpRect->right = wineItem->rect.right;
461 lpRect->bottom = wineItem->rect.bottom;
462 lpRect->top = wineItem->rect.top;
465 return TRUE;
470 static LRESULT
471 TREEVIEW_GetVisibleCount (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
474 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
476 TRACE (treeview,"\n");
478 return (LRESULT) infoPtr->uVisibleHeight / infoPtr->uRealItemHeight;
483 static LRESULT
484 TREEVIEW_SetItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
486 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
487 TREEVIEW_ITEM *wineItem;
488 TV_ITEM *tvItem;
489 INT32 iItem,len;
491 TRACE (treeview,"\n");
492 tvItem=(LPTVITEM) lParam;
493 iItem=tvItem->hItem;
495 wineItem = TREEVIEW_ValidItem (infoPtr, iItem);
496 if (!wineItem) return FALSE;
498 if (tvItem->mask & TVIF_CHILDREN) {
499 wineItem->cChildren=tvItem->cChildren;
502 if (tvItem->mask & TVIF_IMAGE) {
503 wineItem->iImage=tvItem->iImage;
506 if (tvItem->mask & TVIF_INTEGRAL) {
507 /* wineItem->iIntegral=tvItem->iIntegral; */
510 if (tvItem->mask & TVIF_PARAM) {
511 wineItem->lParam=tvItem->lParam;
514 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
515 wineItem->iSelectedImage=tvItem->iSelectedImage;
518 if (tvItem->mask & TVIF_STATE) {
519 wineItem->state=tvItem->state & tvItem->stateMask;
522 if (tvItem->mask & TVIF_TEXT) {
523 len=tvItem->cchTextMax;
524 if (len>wineItem->cchTextMax) {
525 HeapFree (GetProcessHeap (), 0, wineItem->pszText);
526 wineItem->pszText= HeapAlloc (GetProcessHeap (),
527 HEAP_ZERO_MEMORY, len+1);
529 lstrcpyn32A (wineItem->pszText, tvItem->pszText,len);
532 return TRUE;
539 static void
540 TREEVIEW_Refresh (WND *wndPtr, HDC32 hdc)
543 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
544 HFONT32 hFont, hOldFont;
545 RECT32 rect;
546 HBRUSH32 hbrBk;
547 INT32 iItem, indent, x, y, height;
548 INT32 viewtop,viewbottom,viewleft,viewright;
549 TREEVIEW_ITEM *wineItem, *prevItem;
551 TRACE (treeview,"\n");
553 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
554 KillTimer32 (wndPtr->hwndSelf, TV_REFRESH_TIMER);
555 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
559 GetClientRect32 (wndPtr->hwndSelf, &rect);
560 if ((rect.left-rect.right ==0) || (rect.top-rect.bottom==0)) return;
561 viewtop=infoPtr->cy;
562 viewbottom=infoPtr->cy + rect.bottom-rect.top;
563 viewleft=infoPtr->cx;
564 viewright=infoPtr->cx + rect.right-rect.left;
566 infoPtr->uVisibleHeight=viewbottom - viewtop;
568 hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject32 (DEFAULT_GUI_FONT);
569 hOldFont = SelectObject32 (hdc, hFont);
571 /* draw background */
572 hbrBk = GetSysColorBrush32(COLOR_WINDOW);
573 FillRect32(hdc, &rect, hbrBk);
576 iItem=infoPtr->TopRootItem;
577 infoPtr->firstVisible=0;
578 wineItem=NULL;
579 indent=0;
580 x=y=0;
581 TRACE (treeview, "[%d %d %d %d]\n",viewtop,viewbottom,viewleft,viewright);
583 while (iItem) {
584 prevItem=wineItem;
585 wineItem= & infoPtr->items[iItem];
587 TRACE (treeview, "%d %d [%d %d %d %d] (%s)\n",y,x,
588 wineItem->rect.top, wineItem->rect.bottom,
589 wineItem->rect.left, wineItem->rect.right,
590 wineItem->pszText);
592 height=infoPtr->uRealItemHeight * wineItem->iIntegral;
593 if ((y >= viewtop) && (y <= viewbottom) &&
594 (x >= viewleft ) && (x <= viewright)) {
595 wineItem->rect.top = y - infoPtr->cy + rect.top;
596 wineItem->rect.bottom = wineItem->rect.top + height ;
597 wineItem->rect.left = x - infoPtr->cx + rect.left;
598 wineItem->rect.right = rect.right;
599 if (!infoPtr->firstVisible)
600 infoPtr->firstVisible=wineItem->hItem;
601 TREEVIEW_DrawItem (wndPtr, hdc, wineItem, prevItem, indent);
603 else {
604 wineItem->rect.top = wineItem->rect.bottom = -1;
605 wineItem->rect.left = wineItem->rect.right = -1;
608 /* look up next item */
610 if ((wineItem->firstChild) && (wineItem->state & TVIS_EXPANDED)) {
611 iItem=wineItem->firstChild;
612 indent++;
613 x+=infoPtr->uIndent;
615 else {
616 iItem=wineItem->sibling;
617 while ((!iItem) && (indent>0)) {
618 indent--;
619 x-=infoPtr->uIndent;
620 prevItem=wineItem;
621 wineItem=&infoPtr->items[wineItem->parent];
622 iItem=wineItem->sibling;
625 y +=height;
626 } /* while */
628 infoPtr->uTotalHeight=y;
629 if (y >= (viewbottom-viewtop)) {
630 if (!(infoPtr->uInternalStatus & TV_VSCROLL))
631 ShowScrollBar32 (wndPtr->hwndSelf, SB_VERT, TRUE);
632 infoPtr->uInternalStatus |=TV_VSCROLL;
633 SetScrollRange32 (wndPtr->hwndSelf, SB_VERT, 0,
634 y - infoPtr->uVisibleHeight, FALSE);
635 SetScrollPos32 (wndPtr->hwndSelf, SB_VERT, infoPtr->cy, TRUE);
637 else {
638 if (infoPtr->uInternalStatus & TV_VSCROLL)
639 ShowScrollBar32 (wndPtr->hwndSelf, SB_VERT, FALSE);
640 infoPtr->uInternalStatus &= ~TV_VSCROLL;
644 SelectObject32 (hdc, hOldFont);
648 static LRESULT
649 TREEVIEW_HandleTimer ( WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
651 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
652 HDC32 hdc;
654 if (!infoPtr) return FALSE;
656 TRACE (treeview, "timer\n");
658 switch (wParam) {
659 case TV_REFRESH_TIMER:
660 KillTimer32 (wndPtr->hwndSelf, TV_REFRESH_TIMER);
661 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
662 hdc=GetDC32 (wndPtr->hwndSelf);
663 TREEVIEW_Refresh (wndPtr, hdc);
664 ReleaseDC32 (wndPtr->hwndSelf, hdc);
665 return 0;
666 case TV_EDIT_TIMER:
667 KillTimer32 (wndPtr->hwndSelf, TV_EDIT_TIMER);
668 infoPtr->Timer &= ~TV_EDIT_TIMER_SET;
669 return 0;
672 return 1;
676 static void
677 TREEVIEW_QueueRefresh (WND *wndPtr)
680 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
682 TRACE (treeview,"queued\n");
683 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
684 KillTimer32 (wndPtr->hwndSelf, TV_REFRESH_TIMER);
687 SetTimer32 (wndPtr->hwndSelf, TV_REFRESH_TIMER, TV_REFRESH_DELAY, 0);
688 infoPtr->Timer|=TV_REFRESH_TIMER_SET;
693 static LRESULT
694 TREEVIEW_GetItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
696 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
697 LPTVITEM tvItem;
698 TREEVIEW_ITEM *wineItem;
699 INT32 iItem,len;
701 TRACE (treeview,"\n");
702 tvItem=(LPTVITEM) lParam;
703 iItem=tvItem->hItem;
705 wineItem = TREEVIEW_ValidItem (infoPtr, iItem);
706 if (!wineItem) return FALSE;
709 if (tvItem->mask & TVIF_CHILDREN) {
710 tvItem->cChildren=wineItem->cChildren;
713 if (tvItem->mask & TVIF_HANDLE) {
714 tvItem->hItem=wineItem->hItem;
717 if (tvItem->mask & TVIF_IMAGE) {
718 tvItem->iImage=wineItem->iImage;
721 if (tvItem->mask & TVIF_INTEGRAL) {
722 /* tvItem->iIntegral=wineItem->iIntegral; */
725 if (tvItem->mask & TVIF_PARAM) {
726 tvItem->lParam=wineItem->lParam;
729 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
730 tvItem->iSelectedImage=wineItem->iSelectedImage;
733 if (tvItem->mask & TVIF_STATE) {
734 tvItem->state=wineItem->state & tvItem->stateMask;
737 if (tvItem->mask & TVIF_TEXT) {
738 len=wineItem->cchTextMax;
739 if (wineItem->cchTextMax>tvItem->cchTextMax)
740 len=tvItem->cchTextMax-1;
741 lstrcpyn32A (tvItem->pszText, tvItem->pszText,len);
744 return TRUE;
749 static LRESULT
750 TREEVIEW_GetNextItem32 (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
753 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
754 TREEVIEW_ITEM *wineItem;
755 INT32 iItem, flag;
758 TRACE (treeview,"item:%lu, flags:%x\n", lParam, wParam);
759 if (!infoPtr) return FALSE;
761 flag= (INT32) wParam;
762 switch (flag) {
763 case TVGN_ROOT: return (LRESULT) infoPtr->TopRootItem;
764 case TVGN_CARET: return (LRESULT) infoPtr->selectedItem;
765 case TVGN_FIRSTVISIBLE: return (LRESULT) infoPtr->firstVisible;
766 case TVGN_DROPHILITE: return (LRESULT) infoPtr->dropItem;
769 iItem= (INT32) lParam;
770 wineItem = TREEVIEW_ValidItem (infoPtr, iItem);
771 if (!wineItem) return FALSE;
773 switch (flag) {
774 case TVGN_NEXT: return (LRESULT) wineItem->sibling;
775 case TVGN_PREVIOUS: return (LRESULT) wineItem->upsibling;
776 case TVGN_PARENT: return (LRESULT) wineItem->parent;
777 case TVGN_CHILD: return (LRESULT) wineItem->firstChild;
778 case TVGN_LASTVISIBLE: FIXME (treeview,"TVGN_LASTVISIBLE not implemented\n");
779 return 0;
780 case TVGN_NEXTVISIBLE: wineItem=TREEVIEW_GetNextListItem
781 (infoPtr,wineItem);
782 if (wineItem)
783 return (LRESULT) wineItem->hItem;
784 else
785 return (LRESULT) 0;
786 case TVGN_PREVIOUSVISIBLE: wineItem=TREEVIEW_GetPrevListItem
787 (infoPtr, wineItem);
788 if (wineItem)
789 return (LRESULT) wineItem->hItem;
790 else
791 return (LRESULT) 0;
792 default: FIXME (treeview,"Unknown msg %x,item %x\n", flag,iItem);
795 return 0;
799 static LRESULT
800 TREEVIEW_GetCount (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
802 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
804 return (LRESULT) infoPtr->uNumItems;
810 /* the method used below isn't the most memory-friendly, but it avoids
811 a lot of memory reallocations */
813 /* BTW: we waste handle 0; 0 is not an allowed handle. Fix this by
814 decreasing infoptr->items with 1, and increasing it by 1 if
815 it is referenced in mm-handling stuff? */
817 static LRESULT
818 TREEVIEW_InsertItem32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
821 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
822 TVINSERTSTRUCT *ptdi;
823 TV_ITEM *tvItem;
824 TREEVIEW_ITEM *wineItem, *parentItem, *prevsib, *sibItem;
825 INT32 iItem,listItems,i,len;
827 TRACE (treeview,"\n");
828 ptdi = (TVINSERTSTRUCT *) lParam;
830 /* check if memory is available */
832 if (infoPtr->uNumPtrsAlloced==0) {
833 infoPtr->items = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
834 TVITEM_ALLOC*sizeof (TREEVIEW_ITEM));
835 infoPtr->freeList= HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
836 (1+(TVITEM_ALLOC>>5)) *sizeof (INT32));
837 infoPtr->uNumPtrsAlloced=TVITEM_ALLOC;
838 infoPtr->TopRootItem=1;
841 if (infoPtr->uNumItems == (infoPtr->uNumPtrsAlloced-1) ) {
842 TREEVIEW_ITEM *oldItems = infoPtr->items;
843 INT32 *oldfreeList = infoPtr->freeList;
845 infoPtr->uNumPtrsAlloced*=2;
846 infoPtr->items = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
847 infoPtr->uNumPtrsAlloced*sizeof (TREEVIEW_ITEM));
848 infoPtr->freeList= HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
849 (1+(infoPtr->uNumPtrsAlloced>>5))*sizeof (INT32));
851 memcpy (&infoPtr->items[0], &oldItems[0],
852 infoPtr->uNumPtrsAlloced/2 * sizeof(TREEVIEW_ITEM));
853 memcpy (&infoPtr->freeList[0], &oldfreeList[0],
854 infoPtr->uNumPtrsAlloced>>6 * sizeof(INT32));
856 HeapFree (GetProcessHeap (), 0, oldItems);
857 HeapFree (GetProcessHeap (), 0, oldfreeList);
860 iItem=0;
861 infoPtr->uNumItems++;
863 if (infoPtr->uMaxHandle==(infoPtr->uNumItems-1)) {
864 iItem=infoPtr->uNumItems;
865 infoPtr->uMaxHandle++;
867 else { /* check freelist */
868 for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++) {
869 if (infoPtr->freeList[i]) {
870 iItem=ffs (infoPtr->freeList[i]);
871 clear_bit (iItem & 31, & infoPtr->freeList[i]);
872 break;
876 if (!iItem) ERR (treeview, "Argh -- can't find free item.\n");
878 tvItem= & ptdi->item;
879 wineItem=& infoPtr->items[iItem];
883 if ((ptdi->hParent==TVI_ROOT) || (ptdi->hParent==0)) {
884 parentItem=NULL;
885 wineItem->parent=0;
886 sibItem=&infoPtr->items [infoPtr->TopRootItem];
887 listItems=infoPtr->uNumItems;
889 else {
890 parentItem= &infoPtr->items[ptdi->hParent];
891 if (!parentItem->firstChild)
892 parentItem->firstChild=iItem;
893 wineItem->parent=ptdi->hParent;
894 sibItem=&infoPtr->items [parentItem->firstChild];
895 parentItem->cChildren++;
896 listItems=parentItem->cChildren;
899 wineItem->upsibling=0; /* needed in case we're the first item in a list */
900 wineItem->sibling=0;
901 wineItem->firstChild=0;
903 if (listItems>1) {
904 prevsib=NULL;
905 switch (ptdi->hInsertAfter) {
906 case TVI_FIRST: wineItem->sibling=infoPtr->TopRootItem;
907 infoPtr->TopRootItem=iItem;
908 break;
909 case TVI_LAST:
910 while (sibItem->sibling) {
911 prevsib=sibItem;
912 sibItem=&infoPtr->items [sibItem->sibling];
914 sibItem->sibling=iItem;
915 if (prevsib!=NULL)
916 wineItem->upsibling=prevsib->hItem;
917 else
918 wineItem->sibling=0; /* terminate list */
919 break;
920 case TVI_SORT:
921 FIXME (treeview, "Sorted insert not implemented yet\n");
922 break;
923 default:
924 while ((sibItem->sibling) && (sibItem->sibling!=iItem)) {
925 prevsib=sibItem;
926 sibItem=&infoPtr->items [sibItem->sibling];
928 if (sibItem->sibling)
929 WARN (treeview, "Buggy program tried to insert item after nonexisting handle.");
930 sibItem->upsibling=iItem;
931 wineItem->sibling=sibItem->hItem;
932 if (prevsib!=NULL)
933 wineItem->upsibling=prevsib->hItem;
934 break;
939 /* Fill in info structure */
941 wineItem->mask=tvItem->mask;
942 wineItem->hItem=iItem;
943 wineItem->iIntegral=1;
945 if (tvItem->mask & TVIF_CHILDREN)
946 wineItem->cChildren=tvItem->cChildren;
948 if (tvItem->mask & TVIF_IMAGE)
949 wineItem->iImage=tvItem->iImage;
951 /* if (tvItem->mask & TVIF_INTEGRAL)
952 wineItem->iIntegral=tvItem->iIntegral; */
955 if (tvItem->mask & TVIF_PARAM)
956 wineItem->lParam=tvItem->lParam;
958 if (tvItem->mask & TVIF_SELECTEDIMAGE)
959 wineItem->iSelectedImage=tvItem->iSelectedImage;
961 if (tvItem->mask & TVIF_STATE) {
962 wineItem->state=tvItem->state;
963 wineItem->stateMask=tvItem->stateMask;
966 if (tvItem->mask & TVIF_TEXT) {
967 TRACE (treeview,"(%s)\n", tvItem->pszText);
968 if (tvItem->pszText!=LPSTR_TEXTCALLBACK32A) {
969 len = lstrlen32A (tvItem->pszText)+1;
970 wineItem->pszText=
971 HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, len+1);
972 lstrcpy32A (wineItem->pszText, tvItem->pszText);
973 wineItem->cchTextMax=len;
977 TREEVIEW_QueueRefresh (wndPtr);
979 return (LRESULT) iItem;
984 static LRESULT
985 TREEVIEW_DeleteItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
987 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
988 INT32 iItem;
989 POINT32 pt;
990 TREEVIEW_ITEM *wineItem;
992 TRACE (treeview,"\n");
993 if (!infoPtr) return FALSE;
995 if ((INT32) lParam == TVI_ROOT) {
996 TREEVIEW_RemoveTree (infoPtr);
997 } else {
998 iItem= (INT32) lParam;
999 wineItem = TREEVIEW_ValidItem (infoPtr, iItem);
1000 if (!wineItem) return FALSE;
1001 TREEVIEW_SendTreeviewNotify (wndPtr, TVN_DELETEITEM, 0, iItem, 0, pt);
1002 TREEVIEW_RemoveItem (infoPtr, wineItem);
1005 TREEVIEW_QueueRefresh (wndPtr);
1007 return TRUE;
1011 static LRESULT
1012 TREEVIEW_GetIndent (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1014 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1016 return infoPtr->uIndent;
1019 static LRESULT
1020 TREEVIEW_SetIndent (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1022 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1023 INT32 newIndent;
1025 newIndent=(INT32) wParam;
1026 if (newIndent < MINIMUM_INDENT) newIndent=MINIMUM_INDENT;
1027 infoPtr->uIndent=newIndent;
1029 return 0;
1036 static LRESULT
1037 TREEVIEW_Create (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1039 TREEVIEW_INFO *infoPtr;
1040 HDC32 hdc;
1041 TEXTMETRIC32A tm;
1043 TRACE (treeview,"\n");
1044 /* allocate memory for info structure */
1045 infoPtr = (TREEVIEW_INFO *)HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
1046 sizeof(TREEVIEW_INFO));
1048 wndPtr->wExtra[0] = (DWORD)infoPtr;
1050 if (infoPtr == NULL) {
1051 ERR (treeview, "could not allocate info memory!\n");
1052 return 0;
1055 if ((TREEVIEW_INFO*)wndPtr->wExtra[0] != infoPtr) {
1056 ERR (treeview, "pointer assignment error!\n");
1057 return 0;
1060 hdc=GetDC32 (wndPtr->hwndSelf);
1062 /* set default settings */
1063 infoPtr->uInternalStatus=0;
1064 infoPtr->uNumItems=0;
1065 infoPtr->clrBk = GetSysColor32 (COLOR_WINDOW);
1066 infoPtr->clrText = GetSysColor32 (COLOR_BTNTEXT);
1067 infoPtr->cy = 0;
1068 infoPtr->cx = 0;
1069 infoPtr->uIndent = 15;
1070 infoPtr->himlNormal = NULL;
1071 infoPtr->himlState = NULL;
1072 infoPtr->uItemHeight = -1;
1073 GetTextMetrics32A (hdc, &tm);
1074 infoPtr->uRealItemHeight= tm.tmHeight + tm.tmExternalLeading;
1076 infoPtr->items = NULL;
1077 infoPtr->selectedItem=0;
1078 infoPtr->clrText=-1; /* use system color */
1079 infoPtr->dropItem=0;
1082 infoPtr->hwndNotify = GetParent32 (wndPtr->hwndSelf);
1083 infoPtr->bTransparent = (wndPtr->dwStyle & TBSTYLE_FLAT);
1086 if (wndPtr->dwStyle & TBSTYLE_TOOLTIPS) {
1087 /* Create tooltip control */
1088 // infoPtr->hwndToolTip = CreateWindowEx32A (....);
1090 /* Send TV_TOOLTIPSCREATED notification */
1093 ReleaseDC32 (wndPtr->hwndSelf, hdc);
1095 return 0;
1100 static LRESULT
1101 TREEVIEW_Destroy (WND *wndPtr)
1103 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1105 TREEVIEW_RemoveTree (infoPtr);
1106 if (infoPtr->Timer & TV_REFRESH_TIMER_SET)
1107 KillTimer32 (wndPtr->hwndSelf, TV_REFRESH_TIMER);
1109 HeapFree (GetProcessHeap (), 0, infoPtr);
1111 return 0;
1115 static LRESULT
1116 TREEVIEW_Paint (WND *wndPtr, WPARAM32 wParam)
1118 HDC32 hdc;
1119 PAINTSTRUCT32 ps;
1121 hdc = wParam==0 ? BeginPaint32 (wndPtr->hwndSelf, &ps) : (HDC32)wParam;
1122 TREEVIEW_QueueRefresh (wndPtr);
1123 if(!wParam)
1124 EndPaint32 (wndPtr->hwndSelf, &ps);
1125 return 0;
1130 static LRESULT
1131 TREEVIEW_EraseBackground (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1133 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1134 HBRUSH32 hBrush = CreateSolidBrush32 (infoPtr->clrBk);
1135 RECT32 rect;
1137 TRACE (treeview,"\n");
1138 GetClientRect32 (wndPtr->hwndSelf, &rect);
1139 FillRect32 ((HDC32)wParam, &rect, hBrush);
1140 DeleteObject32 (hBrush);
1141 return TRUE;
1152 static BOOL32
1153 TREEVIEW_SendSimpleNotify (WND *wndPtr, UINT32 code)
1155 NMHDR nmhdr;
1157 TRACE (treeview, "%x\n",code);
1158 nmhdr.hwndFrom = wndPtr->hwndSelf;
1159 nmhdr.idFrom = wndPtr->wIDmenu;
1160 nmhdr.code = code;
1162 return (BOOL32) SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
1163 (WPARAM32)nmhdr.idFrom, (LPARAM)&nmhdr);
1169 static BOOL32
1170 TREEVIEW_SendTreeviewNotify (WND *wndPtr, UINT32 code, UINT32 action,
1171 INT32 oldItem, INT32 newItem, POINT32 pt)
1173 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1174 NMTREEVIEW nmhdr;
1175 TREEVIEW_ITEM *wineItem;
1177 TRACE (treeview,"code:%x action:%x olditem:%x newitem:%x\n",
1178 code,action,oldItem,newItem);
1179 nmhdr.hdr.hwndFrom = wndPtr->hwndSelf;
1180 nmhdr.hdr.idFrom = wndPtr->wIDmenu;
1181 nmhdr.hdr.code = code;
1182 nmhdr.action = action;
1183 if (oldItem) {
1184 wineItem=& infoPtr->items[oldItem];
1185 nmhdr.itemOld.mask = wineItem->mask;
1186 nmhdr.itemOld.hItem = wineItem->hItem;
1187 nmhdr.itemOld.state = wineItem->state;
1188 nmhdr.itemOld.stateMask = wineItem->stateMask;
1189 nmhdr.itemOld.iImage = wineItem->iImage;
1190 nmhdr.itemOld.pszText = wineItem->pszText;
1191 nmhdr.itemOld.cchTextMax = wineItem->cchTextMax;
1192 nmhdr.itemOld.iImage = wineItem->iImage;
1193 nmhdr.itemOld.iSelectedImage = wineItem->iSelectedImage;
1194 nmhdr.itemOld.cChildren = wineItem->cChildren;
1195 nmhdr.itemOld.lParam = wineItem->lParam;
1198 if (newItem) {
1199 wineItem=& infoPtr->items[newItem];
1200 nmhdr.itemNew.mask = wineItem->mask;
1201 nmhdr.itemNew.hItem = wineItem->hItem;
1202 nmhdr.itemNew.state = wineItem->state;
1203 nmhdr.itemNew.stateMask = wineItem->stateMask;
1204 nmhdr.itemNew.iImage = wineItem->iImage;
1205 nmhdr.itemNew.pszText = wineItem->pszText;
1206 nmhdr.itemNew.cchTextMax = wineItem->cchTextMax;
1207 nmhdr.itemNew.iImage = wineItem->iImage;
1208 nmhdr.itemNew.iSelectedImage = wineItem->iSelectedImage;
1209 nmhdr.itemNew.cChildren = wineItem->cChildren;
1210 nmhdr.itemNew.lParam = wineItem->lParam;
1213 nmhdr.ptDrag.x = pt.x;
1214 nmhdr.ptDrag.y = pt.y;
1216 return (BOOL32)SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
1217 (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmhdr);
1224 static LRESULT
1225 TREEVIEW_Expand (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1227 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1228 TREEVIEW_ITEM *wineItem;
1229 UINT32 flag;
1230 INT32 expandItem;
1231 POINT32 pt;
1233 flag= (UINT32) wParam;
1234 expandItem= (INT32) lParam;
1235 TRACE (treeview,"flags:%x item:%x\n", expandItem, wParam);
1236 wineItem = TREEVIEW_ValidItem (infoPtr, expandItem);
1237 if (!wineItem) return 0;
1238 if (!wineItem->cChildren) return 0;
1240 if (flag & TVE_TOGGLE) { /* FIXME: check exact behaviour here */
1241 flag &= ~TVE_TOGGLE; /* ie: bitwise ops or 'case' ops */
1242 if (wineItem->state & TVIS_EXPANDED)
1243 flag |= TVE_COLLAPSE;
1244 else
1245 flag |= TVE_EXPAND;
1248 switch (flag) {
1249 case TVE_COLLAPSERESET:
1250 if (!wineItem->state & TVIS_EXPANDED) return 0;
1251 wineItem->state &= ~(TVIS_EXPANDEDONCE | TVIS_EXPANDED);
1252 TREEVIEW_RemoveAllChildren (infoPtr, wineItem);
1253 break;
1255 case TVE_COLLAPSE:
1256 if (!wineItem->state & TVIS_EXPANDED) return 0;
1257 wineItem->state &= ~TVIS_EXPANDED;
1258 break;
1260 case TVE_EXPAND:
1261 if (wineItem->state & TVIS_EXPANDED) return 0;
1262 if (!(wineItem->state & TVIS_EXPANDEDONCE)) {
1263 if (TREEVIEW_SendTreeviewNotify (wndPtr, TVN_ITEMEXPANDING,
1264 0, 0, expandItem, pt))
1265 return FALSE; /* FIXME: OK? */
1266 wineItem->state |= TVIS_EXPANDED | TVIS_EXPANDEDONCE;
1267 TREEVIEW_SendTreeviewNotify (wndPtr, TVN_ITEMEXPANDED,
1268 0, 0, expandItem, pt);
1270 wineItem->state |= TVIS_EXPANDED;
1271 break;
1272 case TVE_EXPANDPARTIAL:
1273 FIXME (treeview, "TVE_EXPANDPARTIAL not implemented\n");
1274 wineItem->state ^=TVIS_EXPANDED;
1275 wineItem->state |=TVIS_EXPANDEDONCE;
1276 break;
1279 TREEVIEW_QueueRefresh (wndPtr);
1281 return TRUE;
1286 static HTREEITEM
1287 TREEVIEW_HitTest (WND *wndPtr, LPTVHITTESTINFO lpht)
1289 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1290 TREEVIEW_ITEM *wineItem;
1291 RECT32 rect;
1292 UINT32 status,x,y;
1296 GetClientRect32 (wndPtr->hwndSelf, &rect);
1297 TRACE (treeview,"(%d,%d)\n",lpht->pt.x, lpht->pt.y);
1299 status=0;
1300 x=lpht->pt.x;
1301 y=lpht->pt.y;
1302 if (x < rect.left) status|=TVHT_TOLEFT;
1303 if (x > rect.right) status|=TVHT_TORIGHT;
1304 if (y < rect.top ) status|=TVHT_ABOVE;
1305 if (y > rect.bottom) status|=TVHT_BELOW;
1306 if (status) {
1307 lpht->flags=status;
1308 return 0;
1311 if (!infoPtr->firstVisible) WARN (treeview,"Can't fetch first visible item");
1312 wineItem=&infoPtr->items [infoPtr->firstVisible];
1314 while ((wineItem!=NULL) && (y > wineItem->rect.bottom))
1315 wineItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
1317 if (wineItem==NULL) {
1318 lpht->flags=TVHT_NOWHERE;
1319 return 0;
1322 if (x>wineItem->rect.right) {
1323 lpht->flags|=TVHT_ONITEMRIGHT;
1324 return wineItem->hItem;
1328 if (x<wineItem->rect.left+10) lpht->flags|=TVHT_ONITEMBUTTON;
1330 lpht->flags=TVHT_ONITEMLABEL; /* FIXME: implement other flags */
1333 lpht->hItem=wineItem->hItem;
1334 return wineItem->hItem;
1338 static LRESULT
1339 TREEVIEW_HitTest32 (WND *wndPtr, LPARAM lParam)
1342 return (LRESULT) TREEVIEW_HitTest (wndPtr, (LPTVHITTESTINFO) lParam);
1348 LRESULT
1349 TREEVIEW_LButtonDoubleClick (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1351 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1352 TREEVIEW_ITEM *wineItem;
1353 INT32 iItem;
1354 TVHITTESTINFO ht;
1356 TRACE (treeview,"\n");
1357 ht.pt.x = (INT32)LOWORD(lParam);
1358 ht.pt.y = (INT32)HIWORD(lParam);
1359 SetFocus32 (wndPtr->hwndSelf);
1361 iItem=TREEVIEW_HitTest (wndPtr, &ht);
1362 TRACE (treeview,"item %d \n",iItem);
1363 wineItem=TREEVIEW_ValidItem (infoPtr, iItem);
1364 if (!wineItem) return 0;
1366 if (TREEVIEW_SendSimpleNotify (wndPtr, NM_DBLCLK)!=TRUE) { /* FIXME!*/
1367 wineItem->state &= ~TVIS_EXPANDEDONCE;
1368 TREEVIEW_Expand (wndPtr, (WPARAM32) TVE_TOGGLE, (LPARAM) iItem);
1370 return TRUE;
1375 static LRESULT
1376 TREEVIEW_LButtonDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1378 INT32 iItem;
1379 TVHITTESTINFO ht;
1381 TRACE (treeview,"\n");
1382 ht.pt.x = (INT32)LOWORD(lParam);
1383 ht.pt.y = (INT32)HIWORD(lParam);
1385 SetFocus32 (wndPtr->hwndSelf);
1386 iItem=TREEVIEW_HitTest (wndPtr, &ht);
1387 TRACE (treeview,"item %d \n",iItem);
1388 if (ht.flags & TVHT_ONITEMBUTTON) {
1389 TREEVIEW_Expand (wndPtr, (WPARAM32) TVE_TOGGLE, (LPARAM) iItem);
1392 if (TREEVIEW_SelectItem (wndPtr, (WPARAM32) TVGN_CARET, (LPARAM) iItem))
1393 return 0;
1396 return 0;
1400 static LRESULT
1401 TREEVIEW_RButtonDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1404 return 0;
1410 /* FIXME: If the specified item is the child of a collapsed parent item,
1411 expand parent's list of child items to reveal the specified item.
1414 static LRESULT
1415 TREEVIEW_SelectItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1417 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1418 TREEVIEW_ITEM *prevItem,*wineItem;
1419 INT32 action,prevSelect, newSelect;
1420 POINT32 dummy;
1422 TRACE (treeview,"item %lx, flag %x\n", lParam, wParam);
1423 newSelect= (INT32) lParam;
1424 wineItem = TREEVIEW_ValidItem (infoPtr, newSelect);
1425 if (!wineItem) return FALSE;
1426 prevSelect=infoPtr->selectedItem;
1427 prevItem= TREEVIEW_ValidItem (infoPtr, prevSelect);
1428 dummy.x=0;
1429 dummy.y=0;
1431 action= (INT32) wParam;
1433 switch (action) {
1434 case TVGN_CARET:
1435 if (TREEVIEW_SendTreeviewNotify (wndPtr, TVN_SELCHANGING, TVC_BYMOUSE,
1436 prevSelect, newSelect,dummy))
1437 return FALSE; /* FIXME: OK? */
1439 if (prevItem) prevItem->state &= ~TVIS_SELECTED;
1440 infoPtr->selectedItem=newSelect;
1441 wineItem->state |=TVIS_SELECTED;
1442 TREEVIEW_SendTreeviewNotify (wndPtr, TVN_SELCHANGED,
1443 TVC_BYMOUSE, prevSelect, newSelect, dummy);
1444 break;
1445 case TVGN_DROPHILITE:
1446 FIXME (treeview, "DROPHILITE not implemented");
1447 break;
1448 case TVGN_FIRSTVISIBLE:
1449 FIXME (treeview, "FIRSTVISIBLE not implemented");
1450 break;
1453 TREEVIEW_QueueRefresh (wndPtr);
1455 return TRUE;
1460 /* FIXME: does KEYDOWN also send notifications?? If so, use
1461 TREEVIEW_SelectItem.
1465 static LRESULT
1466 TREEVIEW_KeyDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1468 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1469 TREEVIEW_ITEM *prevItem,*newItem;
1470 int prevSelect;
1473 TRACE (treeview,"%x %lx",wParam, lParam);
1474 prevSelect=infoPtr->selectedItem;
1475 if (!prevSelect) return FALSE;
1477 prevItem= TREEVIEW_ValidItem (infoPtr, prevSelect);
1479 newItem=NULL;
1480 switch (wParam) {
1481 case VK_UP:
1482 newItem=TREEVIEW_GetPrevListItem (infoPtr, prevItem);
1483 if (!newItem)
1484 newItem=& infoPtr->items[infoPtr->TopRootItem];
1485 break;
1486 case VK_DOWN:
1487 newItem=TREEVIEW_GetNextListItem (infoPtr, prevItem);
1488 if (!newItem) newItem=prevItem;
1489 break;
1490 case VK_HOME:
1491 newItem=& infoPtr->items[infoPtr->TopRootItem];
1492 break;
1493 case VK_END:
1494 newItem=TREEVIEW_GetLastListItem (infoPtr);
1495 break;
1496 case VK_PRIOR:
1497 case VK_NEXT:
1498 case VK_BACK:
1499 case VK_RETURN:
1500 FIXME (treeview, "%x not implemented\n", wParam);
1501 break;
1504 if (!newItem) return FALSE;
1506 if (prevItem!=newItem) {
1507 prevItem->state &= ~TVIS_SELECTED;
1508 newItem->state |= TVIS_SELECTED;
1509 infoPtr->selectedItem=newItem->hItem;
1510 TREEVIEW_QueueRefresh (wndPtr);
1511 return TRUE;
1514 return FALSE;
1519 static LRESULT
1520 TREEVIEW_VScroll (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1523 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1524 int maxHeight;
1526 TRACE (treeview,"wp %x, lp %lx\n", wParam, lParam);
1527 if (!infoPtr->uInternalStatus & TV_VSCROLL) return FALSE;
1529 switch (LOWORD (wParam)) {
1530 case SB_LINEUP:
1531 if (!infoPtr->cy) return FALSE;
1532 infoPtr->cy -= infoPtr->uRealItemHeight;
1533 if (infoPtr->cy < 0) infoPtr->cy=0;
1534 break;
1535 case SB_LINEDOWN:
1536 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
1537 if (infoPtr->cy == maxHeight) return FALSE;
1538 infoPtr->cy += infoPtr->uRealItemHeight;
1539 if (infoPtr->cy > maxHeight)
1540 infoPtr->cy = maxHeight;
1541 break;
1542 case SB_PAGEUP:
1543 if (!infoPtr->cy) return FALSE;
1544 infoPtr->cy -= infoPtr->uVisibleHeight;
1545 if (infoPtr->cy < 0) infoPtr->cy=0;
1546 break;
1547 case SB_PAGEDOWN:
1548 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
1549 if (infoPtr->cy == maxHeight) return FALSE;
1550 infoPtr->cy += infoPtr->uVisibleHeight;
1551 if (infoPtr->cy > maxHeight)
1552 infoPtr->cy = maxHeight;
1553 break;
1554 case SB_THUMBTRACK:
1555 infoPtr->cy = HIWORD (wParam);
1556 break;
1560 TREEVIEW_QueueRefresh (wndPtr);
1561 return TRUE;
1564 static LRESULT
1565 TREEVIEW_HScroll (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1567 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1569 TRACE (treeview,"wp %lx, lp %x\n", lParam, wParam);
1571 if (!infoPtr->uInternalStatus & TV_HSCROLL) return FALSE;
1572 return TRUE;
1578 LRESULT WINAPI
1579 TREEVIEW_WindowProc (HWND32 hwnd, UINT32 uMsg, WPARAM32 wParam, LPARAM lParam)
1581 WND *wndPtr = WIN_FindWndPtr(hwnd);
1584 switch (uMsg) {
1585 case TVM_INSERTITEM32A:
1586 return TREEVIEW_InsertItem32A (wndPtr, wParam, lParam);
1588 case TVM_INSERTITEM32W:
1589 FIXME (treeview, "Unimplemented msg TVM_INSERTITEM32W\n");
1590 return 0;
1592 case TVM_DELETEITEM:
1593 return TREEVIEW_DeleteItem (wndPtr, wParam, lParam);
1595 case TVM_EXPAND:
1596 return TREEVIEW_Expand (wndPtr, wParam, lParam);
1598 case TVM_GETITEMRECT:
1599 return TREEVIEW_GetItemRect (wndPtr, wParam, lParam);
1601 case TVM_GETCOUNT:
1602 return TREEVIEW_GetCount (wndPtr, wParam, lParam);
1604 case TVM_GETINDENT:
1605 return TREEVIEW_GetIndent (wndPtr, wParam, lParam);
1607 case TVM_SETINDENT:
1608 return TREEVIEW_SetIndent (wndPtr, wParam, lParam);
1610 case TVM_GETIMAGELIST:
1611 return TREEVIEW_GetImageList (wndPtr, wParam, lParam);
1613 case TVM_SETIMAGELIST:
1614 return TREEVIEW_SetImageList (wndPtr, wParam, lParam);
1616 case TVM_GETNEXTITEM:
1617 return TREEVIEW_GetNextItem32 (wndPtr, wParam, lParam);
1619 case TVM_SELECTITEM:
1620 return TREEVIEW_SelectItem (wndPtr, wParam, lParam);
1622 case TVM_GETITEM32A:
1623 return TREEVIEW_GetItem (wndPtr, wParam, lParam);
1625 case TVM_GETITEM32W:
1626 FIXME (treeview, "Unimplemented msg TVM_GETITEM32W\n");
1627 return 0;
1629 case TVM_SETITEM32A:
1630 return TREEVIEW_SetItem (wndPtr, wParam, lParam);
1632 case TVM_SETITEM32W:
1633 FIXME (treeview, "Unimplemented msg TVM_SETITEMW\n");
1634 return 0;
1636 case TVM_EDITLABEL32A:
1637 FIXME (treeview, "Unimplemented msg TVM_EDITLABEL32A \n");
1638 return 0;
1640 case TVM_EDITLABEL32W:
1641 FIXME (treeview, "Unimplemented msg TVM_EDITLABEL32W \n");
1642 return 0;
1644 case TVM_GETEDITCONTROL:
1645 FIXME (treeview, "Unimplemented msg TVM_GETEDITCONTROL\n");
1646 return 0;
1648 case TVM_GETVISIBLECOUNT:
1649 return TREEVIEW_GetVisibleCount (wndPtr, wParam, lParam);
1651 case TVM_HITTEST:
1652 return TREEVIEW_HitTest32 (wndPtr, lParam);
1654 case TVM_CREATEDRAGIMAGE:
1655 FIXME (treeview, "Unimplemented msg TVM_CREATEDRAGIMAGE\n");
1656 return 0;
1658 case TVM_SORTCHILDREN:
1659 FIXME (treeview, "Unimplemented msg TVM_SORTCHILDREN\n");
1660 return 0;
1662 case TVM_ENSUREVISIBLE:
1663 FIXME (treeview, "Unimplemented msg TVM_ENSUREVISIBLE\n");
1664 return 0;
1666 case TVM_SORTCHILDRENCB:
1667 FIXME (treeview, "Unimplemented msg TVM_SORTCHILDRENCB\n");
1668 return 0;
1670 case TVM_ENDEDITLABELNOW:
1671 FIXME (treeview, "Unimplemented msg TVM_ENDEDITLABELNOW\n");
1672 return 0;
1674 case TVM_GETISEARCHSTRING32A:
1675 FIXME (treeview, "Unimplemented msg TVM_GETISEARCHSTRING32A\n");
1676 return 0;
1678 case TVM_GETISEARCHSTRING32W:
1679 FIXME (treeview, "Unimplemented msg TVM_GETISEARCHSTRING32W\n");
1680 return 0;
1682 case TVM_SETTOOLTIPS:
1683 FIXME (treeview, "Unimplemented msg TVM_SETTOOLTIPS\n");
1684 return 0;
1686 case TVM_GETTOOLTIPS:
1687 FIXME (treeview, "Unimplemented msg TVM_GETTOOLTIPS\n");
1688 return 0;
1690 case TVM_SETINSERTMARK:
1691 FIXME (treeview, "Unimplemented msg TVM_SETINSERTMARK\n");
1692 return 0;
1694 case TVM_SETITEMHEIGHT:
1695 return TREEVIEW_SetItemHeight (wndPtr, wParam);
1697 case TVM_GETITEMHEIGHT:
1698 return TREEVIEW_GetItemHeight (wndPtr);
1700 case TVM_SETBKCOLOR:
1701 FIXME (treeview, "Unimplemented msg TVM_SETBKCOLOR\n");
1702 return 0;
1704 case TVM_SETTEXTCOLOR:
1705 return TREEVIEW_SetTextColor (wndPtr, wParam, lParam);
1707 case TVM_GETBKCOLOR:
1708 FIXME (treeview, "Unimplemented msg TVM_GETBKCOLOR\n");
1709 return 0;
1711 case TVM_GETTEXTCOLOR:
1712 return TREEVIEW_GetTextColor (wndPtr);
1714 case TVM_SETSCROLLTIME:
1715 FIXME (treeview, "Unimplemented msg TVM_SETSCROLLTIME\n");
1716 return 0;
1718 case TVM_GETSCROLLTIME:
1719 FIXME (treeview, "Unimplemented msg TVM_GETSCROLLTIME\n");
1720 return 0;
1722 case TVM_SETINSERTMARKCOLOR:
1723 FIXME (treeview, "Unimplemented msg TVM_SETINSERTMARKCOLOR\n");
1724 return 0;
1726 case TVM_SETUNICODEFORMAT:
1727 FIXME (treeview, "Unimplemented msg TVM_SETUNICODEFORMAT\n");
1728 return 0;
1730 case TVM_GETUNICODEFORMAT:
1731 FIXME (treeview, "Unimplemented msg TVM_GETUNICODEFORMAT\n");
1732 return 0;
1734 // case WM_COMMAND:
1736 case WM_CREATE:
1737 return TREEVIEW_Create (wndPtr, wParam, lParam);
1739 case WM_DESTROY:
1740 return TREEVIEW_Destroy (wndPtr);
1742 // case WM_ENABLE:
1744 case WM_ERASEBKGND:
1745 return TREEVIEW_EraseBackground (wndPtr, wParam, lParam);
1747 case WM_GETDLGCODE:
1748 return DLGC_WANTARROWS | DLGC_WANTCHARS;
1750 case WM_PAINT:
1751 return TREEVIEW_Paint (wndPtr, wParam);
1753 // case WM_GETFONT:
1754 // case WM_SETFONT:
1756 case WM_KEYDOWN:
1757 return TREEVIEW_KeyDown (wndPtr, wParam, lParam);
1760 // case WM_KILLFOCUS:
1761 // case WM_SETFOCUS:
1764 case WM_LBUTTONDOWN:
1765 return TREEVIEW_LButtonDown (wndPtr, wParam, lParam);
1767 case WM_LBUTTONDBLCLK:
1768 return TREEVIEW_LButtonDoubleClick (wndPtr, wParam, lParam);
1770 case WM_RBUTTONDOWN:
1771 return TREEVIEW_RButtonDown (wndPtr, wParam, lParam);
1774 // case WM_SYSCOLORCHANGE:
1775 // case WM_STYLECHANGED:
1776 // case WM_SETREDRAW:
1778 case WM_TIMER:
1779 return TREEVIEW_HandleTimer (wndPtr, wParam, lParam);
1781 // case WM_SIZE:
1782 case WM_HSCROLL:
1783 return TREEVIEW_HScroll (wndPtr, wParam, lParam);
1784 case WM_VSCROLL:
1785 return TREEVIEW_VScroll (wndPtr, wParam, lParam);
1787 default:
1788 if (uMsg >= WM_USER)
1789 FIXME (treeview, "Unknown msg %04x wp=%08x lp=%08lx\n",
1790 uMsg, wParam, lParam);
1791 return DefWindowProc32A (hwnd, uMsg, wParam, lParam);
1793 return 0;
1797 VOID
1798 TREEVIEW_Register (VOID)
1800 WNDCLASS32A wndClass;
1802 TRACE (treeview,"\n");
1804 if (GlobalFindAtom32A (WC_TREEVIEW32A)) return;
1806 ZeroMemory (&wndClass, sizeof(WNDCLASS32A));
1807 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
1808 wndClass.lpfnWndProc = (WNDPROC32)TREEVIEW_WindowProc;
1809 wndClass.cbClsExtra = 0;
1810 wndClass.cbWndExtra = sizeof(TREEVIEW_INFO *);
1811 wndClass.hCursor = LoadCursor32A (0, IDC_ARROW32A);
1812 wndClass.hbrBackground = 0;
1813 wndClass.lpszClassName = WC_TREEVIEW32A;
1815 RegisterClass32A (&wndClass);
1819 VOID
1820 TREEVIEW_Unregister (VOID)
1822 if (GlobalFindAtom32A (WC_TREEVIEW32A))
1823 UnregisterClass32A (WC_TREEVIEW32A, (HINSTANCE32)NULL);