Further improvements.
[wine.git] / dlls / comctl32 / treeview.c
blob52ec8805f8303c6bfe0c222e2d4eac498b0ed9ce
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"
34 #include <asm/bitops.h> /* FIXME: linux specific */
36 #define TREEVIEW_GetInfoPtr(wndPtr) ((TREEVIEW_INFO *)wndPtr->wExtra[0])
38 static BOOL32
39 TREEVIEW_SendSimpleNotify (WND *wndPtr, UINT32 code);
40 static BOOL32
41 TREEVIEW_SendTreeviewNotify (WND *wndPtr, UINT32 code, UINT32 action,
42 INT32 oldItem, INT32 newItem, POINT32 pt);
43 static LRESULT
44 TREEVIEW_SelectItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
45 static void
46 TREEVIEW_Refresh (WND *wndPtr, HDC32 hdc);
52 /* helper functions. Work with the assumption that validity of operands
53 is checked beforehand */
56 static TREEVIEW_ITEM *
57 TREEVIEW_ValidItem (TREEVIEW_INFO *infoPtr,int handle)
60 if ((!handle) || (handle>infoPtr->uMaxHandle)) return NULL;
61 if (test_bit (handle, infoPtr->freeList)) return NULL;
63 return & infoPtr->items[handle];
68 static TREEVIEW_ITEM *TREEVIEW_GetPrevListItem (TREEVIEW_INFO *infoPtr,
69 TREEVIEW_ITEM *tvItem)
72 TREEVIEW_ITEM *wineItem;
74 if (tvItem->upsibling)
75 return (& infoPtr->items[tvItem->upsibling]);
77 wineItem=tvItem;
78 while (wineItem->parent) {
79 wineItem=& infoPtr->items[wineItem->parent];
80 if (wineItem->upsibling)
81 return (& infoPtr->items[wineItem->upsibling]);
84 return NULL;
87 static TREEVIEW_ITEM *TREEVIEW_GetNextListItem (TREEVIEW_INFO *infoPtr,
88 TREEVIEW_ITEM *tvItem)
91 TREEVIEW_ITEM *wineItem;
93 if (tvItem->sibling)
94 return (& infoPtr->items[tvItem->sibling]);
96 wineItem=tvItem;
97 while (wineItem->parent) {
98 wineItem=& infoPtr->items [wineItem->parent];
99 if (wineItem->sibling)
100 return (& infoPtr->items [wineItem->sibling]);
103 return NULL;
106 static TREEVIEW_ITEM *TREEVIEW_GetLastListItem (TREEVIEW_INFO *infoPtr)
109 TREEVIEW_ITEM *wineItem;
111 wineItem=NULL;
112 if (infoPtr->TopRootItem)
113 wineItem=& infoPtr->items [infoPtr->TopRootItem];
114 while (wineItem->sibling)
115 wineItem=& infoPtr->items [wineItem->sibling];
117 return wineItem;
123 static void
124 TREEVIEW_RemoveItem (TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem)
127 TREEVIEW_ITEM *parentItem, *upsiblingItem, *siblingItem;
128 INT32 iItem;
130 iItem=wineItem->hItem;
131 set_bit ( iItem & 31, &infoPtr->freeList[iItem >>5]);
132 infoPtr->uNumItems--;
133 parentItem=NULL;
134 if (wineItem->pszText!=LPSTR_TEXTCALLBACK32A)
135 HeapFree (GetProcessHeap (), 0, wineItem->pszText);
137 if (wineItem->parent) {
138 parentItem=& infoPtr->items[ wineItem->parent];
139 if (parentItem->cChildren==1) {
140 parentItem->cChildren=0;
141 parentItem->firstChild=0;
142 return;
143 } else {
144 parentItem->cChildren--;
145 if (parentItem->firstChild==iItem)
146 parentItem->firstChild=wineItem->sibling;
150 if (iItem==infoPtr->TopRootItem)
151 infoPtr->TopRootItem=wineItem->sibling;
152 if (wineItem->upsibling) {
153 upsiblingItem=& infoPtr->items [wineItem->upsibling];
154 upsiblingItem->sibling=wineItem->sibling;
156 if (wineItem->sibling) {
157 siblingItem=& infoPtr->items [wineItem->sibling];
158 siblingItem->upsibling=wineItem->upsibling;
164 static void TREEVIEW_RemoveAllChildren (TREEVIEW_INFO *infoPtr,
165 TREEVIEW_ITEM *parentItem)
168 TREEVIEW_ITEM *killItem;
169 INT32 kill;
171 kill=parentItem->firstChild;
172 while (kill) {
173 set_bit ( kill & 31, &infoPtr->freeList[kill >>5]);
174 killItem=& infoPtr->items[kill];
175 if (killItem->pszText!=LPSTR_TEXTCALLBACK32A)
176 HeapFree (GetProcessHeap (), 0, killItem->pszText);
177 kill=killItem->sibling;
179 infoPtr->uNumItems -= parentItem->cChildren;
180 parentItem->firstChild = 0;
181 parentItem->cChildren = 0;
185 /* Note:TREEVIEW_RemoveTree doesn't remove infoPtr itself */
187 static void TREEVIEW_RemoveTree (TREEVIEW_INFO *infoPtr)
191 TREEVIEW_ITEM *killItem;
192 int i;
194 for (i=1; i<=infoPtr->uMaxHandle; i++)
195 if (!test_bit (i, infoPtr->freeList)) {
196 killItem=& infoPtr->items [i];
197 if (killItem->pszText!=LPSTR_TEXTCALLBACK32A)
198 HeapFree (GetProcessHeap (), 0, killItem->pszText);
201 if (infoPtr->uNumPtrsAlloced) {
202 HeapFree (GetProcessHeap (), 0, infoPtr->items);
203 HeapFree (GetProcessHeap (), 0, infoPtr->freeList);
204 infoPtr->uNumItems=0;
205 infoPtr->uNumPtrsAlloced=0;
206 infoPtr->uMaxHandle=0;
219 static LRESULT
220 TREEVIEW_GetImageList (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
222 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
224 TRACE (treeview,"\n");
226 if (infoPtr==NULL) return 0;
228 if ((INT32)wParam == TVSIL_NORMAL)
229 return (LRESULT) infoPtr->himlNormal;
230 if ((INT32)wParam == TVSIL_STATE)
231 return (LRESULT) infoPtr->himlState;
233 return 0;
239 static LRESULT
240 TREEVIEW_SetImageList (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
242 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
243 HIMAGELIST himlTemp;
245 switch ((INT32)wParam) {
246 case TVSIL_NORMAL:
247 himlTemp = infoPtr->himlNormal;
248 infoPtr->himlNormal = (HIMAGELIST)lParam;
249 return (LRESULT)himlTemp;
251 case TVSIL_STATE:
252 himlTemp = infoPtr->himlState;
253 infoPtr->himlState = (HIMAGELIST)lParam;
254 return (LRESULT)himlTemp;
257 return (LRESULT)NULL;
262 static LRESULT
263 TREEVIEW_SetItemHeight (WND *wndPtr, WPARAM32 wParam)
265 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
266 INT32 prevHeight=infoPtr->uItemHeight;
267 HDC32 hdc;
268 TEXTMETRIC32A tm;
271 if (wParam==-1) {
272 hdc=GetDC32 (wndPtr->hwndSelf);
273 infoPtr->uItemHeight=-1;
274 GetTextMetrics32A (hdc, &tm);
275 infoPtr->uRealItemHeight= tm.tmHeight + tm.tmExternalLeading;
276 ReleaseDC32 (wndPtr->hwndSelf, hdc);
277 return prevHeight;
280 /* FIXME: check wParam > imagelist height */
282 if (!(wndPtr->dwStyle & TVS_NONEVENHEIGHT))
283 infoPtr->uItemHeight = (INT32) wParam & 0xfffffffe;
284 return prevHeight;
287 static LRESULT
288 TREEVIEW_GetItemHeight (WND *wndPtr)
290 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
292 return infoPtr->uItemHeight;
295 static LRESULT
296 TREEVIEW_SetTextColor (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
298 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
299 COLORREF prevColor=infoPtr->clrText;
301 infoPtr->clrText=(COLORREF) lParam;
302 return (LRESULT) prevColor;
305 static LRESULT
306 TREEVIEW_GetTextColor (WND *wndPtr)
308 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
310 return (LRESULT) infoPtr->clrText;
314 static INT32
315 TREEVIEW_DrawItem (WND *wndPtr, HDC32 hdc, TREEVIEW_ITEM *wineItem,
316 TREEVIEW_ITEM *upperItem, int indent)
318 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
319 INT32 oldBkMode,center,xpos;
320 COLORREF oldBkColor;
321 UINT32 uTextJustify = DT_LEFT;
322 HPEN32 hOldPen, hnewPen,hRootPen;
323 RECT32 r,upper;
325 hnewPen = CreatePen32(PS_DOT, 0, GetSysColor32(COLOR_WINDOWTEXT) );
326 hOldPen = SelectObject32( hdc, hnewPen );
328 r=wineItem->rect;
329 if (upperItem)
330 upper=upperItem->rect;
331 else {
332 upper.top=0;
333 upper.left=8;
335 center=(r.top+r.bottom)/2;
336 xpos=r.left+8;
338 if (wndPtr->dwStyle & TVS_HASLINES) {
339 POINT32 points[3];
340 if ((wndPtr->dwStyle & TVS_LINESATROOT) && (indent==0)) {
341 points[0].y=points[1].y=center;
342 points[2].y=upper.top;
343 points[1].x=points[2].x=upper.left;
344 points[0].x=upper.left+12;
345 points[2].y+=5;
347 Polyline32 (hdc,points,3);
349 else {
350 points[0].y=points[1].y=center;
351 points[2].y=upper.top;
352 points[1].x=points[2].x=upper.left+13;
353 points[0].x=upper.left+25;
354 points[2].y+=5;
355 Polyline32 (hdc,points,3);
359 DeleteObject32(hnewPen);
360 SelectObject32(hdc, hOldPen);
362 if ((wndPtr->dwStyle & TVS_HASBUTTONS) && (wineItem->cChildren)) {
364 hRootPen = CreatePen32(PS_SOLID, 0, GetSysColor32(COLOR_WINDOW) );
365 SelectObject32( hdc, hRootPen );
368 Rectangle32 (hdc, xpos-4, center-4, xpos+5, center+5);
369 MoveToEx32 (hdc, xpos-2, center, NULL);
370 LineTo32 (hdc, xpos+3, center);
371 if (!(wineItem->state & TVIS_EXPANDED)) {
372 MoveToEx32 (hdc, xpos, center-2, NULL);
373 LineTo32 (hdc, xpos, center+3);
375 /* DeleteObject32(hRootPen); */
379 xpos+=13;
381 if (wineItem->mask & TVIF_IMAGE) {
382 if (wineItem->iImage!=I_IMAGECALLBACK) {
383 if (infoPtr->himlNormal) {
384 ImageList_Draw (infoPtr->himlNormal,wineItem->iImage, hdc,
385 xpos-2, r.top+1, ILD_NORMAL);
386 xpos+=15;
391 r.left=xpos;
392 if ((wineItem->mask & TVIF_TEXT) && (wineItem->pszText)) {
393 if (wineItem->state & TVIS_SELECTED) {
394 oldBkMode = SetBkMode32(hdc, OPAQUE);
395 oldBkColor= SetBkColor32 (hdc, GetSysColor32( COLOR_HIGHLIGHT));
396 SetTextColor32 (hdc, GetSysColor32(COLOR_HIGHLIGHTTEXT));
398 else {
399 oldBkMode = SetBkMode32(hdc, TRANSPARENT);
401 r.left += 3;
402 r.right -= 3;
403 if (infoPtr->clrText==-1)
404 SetTextColor32 (hdc, COLOR_BTNTEXT);
405 else
406 SetTextColor32 (hdc, infoPtr->clrText); /* FIXME: retval */
407 DrawText32A(hdc, wineItem->pszText, lstrlen32A(wineItem->pszText),
408 &r, uTextJustify|DT_VCENTER|DT_SINGLELINE);
409 if (oldBkMode != TRANSPARENT)
410 SetBkMode32(hdc, oldBkMode);
411 if (wineItem->state & TVIS_SELECTED)
412 SetBkColor32 (hdc, oldBkColor);
415 return wineItem->rect.right;
424 static LRESULT
425 TREEVIEW_GetItemRect (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
427 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
428 TREEVIEW_ITEM *wineItem;
429 INT32 iItem;
430 LPRECT32 lpRect;
432 TRACE (treeview,"\n");
433 if (infoPtr==NULL) return FALSE;
435 iItem = (INT32)lParam;
436 wineItem = TREEVIEW_ValidItem (infoPtr, iItem);
437 if (!wineItem) return FALSE;
439 wineItem=& infoPtr->items[ iItem ];
440 if (!wineItem->visible) return FALSE;
442 lpRect = (LPRECT32)lParam;
443 if (lpRect == NULL) return FALSE;
445 if ((INT32) wParam) {
446 lpRect->left = wineItem->text.left;
447 lpRect->right = wineItem->text.right;
448 lpRect->bottom = wineItem->text.bottom;
449 lpRect->top = wineItem->text.top;
450 } else {
451 lpRect->left = wineItem->rect.left;
452 lpRect->right = wineItem->rect.right;
453 lpRect->bottom = wineItem->rect.bottom;
454 lpRect->top = wineItem->rect.top;
457 return TRUE;
462 static LRESULT
463 TREEVIEW_GetVisibleCount (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
466 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
468 TRACE (treeview,"\n");
470 return (LRESULT) infoPtr->uVisibleHeight / infoPtr->uRealItemHeight;
475 static LRESULT
476 TREEVIEW_SetItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
478 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
479 TREEVIEW_ITEM *wineItem;
480 TV_ITEM *tvItem;
481 INT32 iItem,len;
483 TRACE (treeview,"\n");
484 tvItem=(LPTVITEM) lParam;
485 iItem=tvItem->hItem;
487 wineItem = TREEVIEW_ValidItem (infoPtr, iItem);
488 if (!wineItem) return FALSE;
490 if (tvItem->mask & TVIF_CHILDREN) {
491 wineItem->cChildren=tvItem->cChildren;
494 if (tvItem->mask & TVIF_IMAGE) {
495 wineItem->iImage=tvItem->iImage;
498 if (tvItem->mask & TVIF_INTEGRAL) {
499 /* wineItem->iIntegral=tvItem->iIntegral; */
502 if (tvItem->mask & TVIF_PARAM) {
503 wineItem->lParam=tvItem->lParam;
506 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
507 wineItem->iSelectedImage=tvItem->iSelectedImage;
510 if (tvItem->mask & TVIF_STATE) {
511 wineItem->state=tvItem->state & tvItem->stateMask;
514 if (tvItem->mask & TVIF_TEXT) {
515 len=tvItem->cchTextMax;
516 if (len>wineItem->cchTextMax) {
517 HeapFree (GetProcessHeap (), 0, wineItem->pszText);
518 wineItem->pszText= HeapAlloc (GetProcessHeap (),
519 HEAP_ZERO_MEMORY, len+1);
521 lstrcpyn32A (wineItem->pszText, tvItem->pszText,len);
524 return TRUE;
531 static void
532 TREEVIEW_Refresh (WND *wndPtr, HDC32 hdc)
535 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
536 HFONT32 hFont, hOldFont;
537 RECT32 rect;
538 HBRUSH32 hbrBk;
539 INT32 iItem, indent, x, y, height;
540 INT32 viewtop,viewbottom,viewleft,viewright;
541 TREEVIEW_ITEM *wineItem, *prevItem;
543 TRACE (treeview,"\n");
545 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
546 KillTimer32 (wndPtr->hwndSelf, TV_REFRESH_TIMER);
547 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
551 GetClientRect32 (wndPtr->hwndSelf, &rect);
552 if ((rect.left-rect.right ==0) || (rect.top-rect.bottom==0)) return;
553 viewtop=infoPtr->cy;
554 viewbottom=infoPtr->cy + rect.bottom-rect.top;
555 viewleft=infoPtr->cx;
556 viewright=infoPtr->cx + rect.right-rect.left;
558 infoPtr->uVisibleHeight=viewbottom - viewtop;
560 hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject32 (DEFAULT_GUI_FONT);
561 hOldFont = SelectObject32 (hdc, hFont);
563 /* draw background */
564 hbrBk = GetSysColorBrush32(COLOR_WINDOW);
565 FillRect32(hdc, &rect, hbrBk);
568 iItem=infoPtr->TopRootItem;
569 infoPtr->firstVisible=0;
570 wineItem=NULL;
571 indent=0;
572 x=y=0;
573 TRACE (treeview, "[%d %d %d %d]\n",viewtop,viewbottom,viewleft,viewright);
575 while (iItem) {
576 prevItem=wineItem;
577 wineItem= & infoPtr->items[iItem];
579 TRACE (treeview, "%d %d [%d %d %d %d] (%s)\n",y,x,
580 wineItem->rect.top, wineItem->rect.bottom,
581 wineItem->rect.left, wineItem->rect.right,
582 wineItem->pszText);
584 height=infoPtr->uRealItemHeight * wineItem->iIntegral;
585 if ((y >= viewtop) && (y <= viewbottom) &&
586 (x >= viewleft ) && (x <= viewright)) {
587 wineItem->rect.top = y - infoPtr->cy + rect.top;
588 wineItem->rect.bottom = wineItem->rect.top + height ;
589 wineItem->rect.left = x - infoPtr->cx + rect.left;
590 wineItem->rect.right = rect.right;
591 if (!infoPtr->firstVisible)
592 infoPtr->firstVisible=wineItem->hItem;
593 TREEVIEW_DrawItem (wndPtr, hdc, wineItem, prevItem, indent);
595 else {
596 wineItem->rect.top = wineItem->rect.bottom = -1;
597 wineItem->rect.left = wineItem->rect.right = -1;
600 /* look up next item */
602 if ((wineItem->firstChild) && (wineItem->state & TVIS_EXPANDED)) {
603 iItem=wineItem->firstChild;
604 indent++;
605 x+=infoPtr->uIndent;
607 else {
608 iItem=wineItem->sibling;
609 while ((!iItem) && (indent>0)) {
610 indent--;
611 x-=infoPtr->uIndent;
612 prevItem=wineItem;
613 wineItem=&infoPtr->items[wineItem->parent];
614 iItem=wineItem->sibling;
617 y +=height;
618 } /* while */
620 infoPtr->uTotalHeight=y;
621 if (y >= (viewbottom-viewtop)) {
622 if (!(infoPtr->uInternalStatus & TV_VSCROLL))
623 ShowScrollBar32 (wndPtr->hwndSelf, SB_VERT, TRUE);
624 infoPtr->uInternalStatus |=TV_VSCROLL;
625 SetScrollRange32 (wndPtr->hwndSelf, SB_VERT, 0,
626 y - infoPtr->uVisibleHeight, FALSE);
627 SetScrollPos32 (wndPtr->hwndSelf, SB_VERT, infoPtr->cy, TRUE);
629 else {
630 if (infoPtr->uInternalStatus & TV_VSCROLL)
631 ShowScrollBar32 (wndPtr->hwndSelf, SB_VERT, FALSE);
632 infoPtr->uInternalStatus &= ~TV_VSCROLL;
636 SelectObject32 (hdc, hOldFont);
640 static LRESULT
641 TREEVIEW_HandleTimer ( WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
643 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
644 HDC32 hdc;
646 if (!infoPtr) return FALSE;
648 TRACE (treeview, "timer\n");
650 switch (wParam) {
651 case TV_REFRESH_TIMER:
652 KillTimer32 (wndPtr->hwndSelf, TV_REFRESH_TIMER);
653 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
654 hdc=GetDC32 (wndPtr->hwndSelf);
655 TREEVIEW_Refresh (wndPtr, hdc);
656 ReleaseDC32 (wndPtr->hwndSelf, hdc);
657 return 0;
658 case TV_EDIT_TIMER:
659 KillTimer32 (wndPtr->hwndSelf, TV_EDIT_TIMER);
660 infoPtr->Timer &= ~TV_EDIT_TIMER_SET;
661 return 0;
664 return 1;
668 static void
669 TREEVIEW_QueueRefresh (WND *wndPtr)
672 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
674 TRACE (treeview,"queued\n");
675 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
676 KillTimer32 (wndPtr->hwndSelf, TV_REFRESH_TIMER);
679 SetTimer32 (wndPtr->hwndSelf, TV_REFRESH_TIMER, TV_REFRESH_DELAY, 0);
680 infoPtr->Timer|=TV_REFRESH_TIMER_SET;
685 static LRESULT
686 TREEVIEW_GetItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
688 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
689 LPTVITEM tvItem;
690 TREEVIEW_ITEM *wineItem;
691 INT32 iItem,len;
693 TRACE (treeview,"\n");
694 tvItem=(LPTVITEM) lParam;
695 iItem=tvItem->hItem;
697 wineItem = TREEVIEW_ValidItem (infoPtr, iItem);
698 if (!wineItem) return FALSE;
701 if (tvItem->mask & TVIF_CHILDREN) {
702 tvItem->cChildren=wineItem->cChildren;
705 if (tvItem->mask & TVIF_HANDLE) {
706 tvItem->hItem=wineItem->hItem;
709 if (tvItem->mask & TVIF_IMAGE) {
710 tvItem->iImage=wineItem->iImage;
713 if (tvItem->mask & TVIF_INTEGRAL) {
714 /* tvItem->iIntegral=wineItem->iIntegral; */
717 if (tvItem->mask & TVIF_PARAM) {
718 tvItem->lParam=wineItem->lParam;
721 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
722 tvItem->iSelectedImage=wineItem->iSelectedImage;
725 if (tvItem->mask & TVIF_STATE) {
726 tvItem->state=wineItem->state & tvItem->stateMask;
729 if (tvItem->mask & TVIF_TEXT) {
730 len=wineItem->cchTextMax;
731 if (wineItem->cchTextMax>tvItem->cchTextMax)
732 len=tvItem->cchTextMax-1;
733 lstrcpyn32A (tvItem->pszText, tvItem->pszText,len);
736 return TRUE;
741 static LRESULT
742 TREEVIEW_GetNextItem32 (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
745 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
746 TREEVIEW_ITEM *wineItem;
747 INT32 iItem, flag;
750 TRACE (treeview,"item:%lu, flags:%x\n", lParam, wParam);
751 if (!infoPtr) return FALSE;
753 flag= (INT32) wParam;
754 switch (flag) {
755 case TVGN_ROOT: return (LRESULT) infoPtr->TopRootItem;
756 case TVGN_CARET: return (LRESULT) infoPtr->selectedItem;
757 case TVGN_FIRSTVISIBLE: return (LRESULT) infoPtr->firstVisible;
758 case TVGN_DROPHILITE: return (LRESULT) infoPtr->dropItem;
761 iItem= (INT32) lParam;
762 wineItem = TREEVIEW_ValidItem (infoPtr, iItem);
763 if (!wineItem) return FALSE;
765 switch (flag) {
766 case TVGN_NEXT: return (LRESULT) wineItem->sibling;
767 case TVGN_PREVIOUS: return (LRESULT) wineItem->upsibling;
768 case TVGN_PARENT: return (LRESULT) wineItem->parent;
769 case TVGN_CHILD: return (LRESULT) wineItem->firstChild;
770 case TVGN_LASTVISIBLE: FIXME (treeview,"TVGN_LASTVISIBLE not implemented\n");
771 return 0;
772 case TVGN_NEXTVISIBLE: wineItem=TREEVIEW_GetNextListItem
773 (infoPtr,wineItem);
774 if (wineItem)
775 return (LRESULT) wineItem->hItem;
776 else
777 return (LRESULT) 0;
778 case TVGN_PREVIOUSVISIBLE: wineItem=TREEVIEW_GetPrevListItem
779 (infoPtr, wineItem);
780 if (wineItem)
781 return (LRESULT) wineItem->hItem;
782 else
783 return (LRESULT) 0;
784 default: FIXME (treeview,"Unknown msg %x,item %x\n", flag,iItem);
787 return 0;
791 static LRESULT
792 TREEVIEW_GetCount (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
794 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
796 return (LRESULT) infoPtr->uNumItems;
802 /* the method used below isn't the most memory-friendly, but it avoids
803 a lot of memory reallocations */
805 /* BTW: we waste handle 0; 0 is not an allowed handle. Fix this by
806 decreasing infoptr->items with 1, and increasing it by 1 if
807 it is referenced in mm-handling stuff? */
809 static LRESULT
810 TREEVIEW_InsertItem32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
813 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
814 TVINSERTSTRUCT *ptdi;
815 TV_ITEM *tvItem;
816 TREEVIEW_ITEM *wineItem, *parentItem, *prevsib, *sibItem;
817 INT32 iItem,listItems,i,len;
819 TRACE (treeview,"\n");
820 ptdi = (TVINSERTSTRUCT *) lParam;
822 /* check if memory is available */
824 if (infoPtr->uNumPtrsAlloced==0) {
825 infoPtr->items = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
826 TVITEM_ALLOC*sizeof (TREEVIEW_ITEM));
827 infoPtr->freeList= HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
828 (1+(TVITEM_ALLOC>>5)) *sizeof (INT32));
829 infoPtr->uNumPtrsAlloced=TVITEM_ALLOC;
830 infoPtr->TopRootItem=1;
833 if (infoPtr->uNumItems == (infoPtr->uNumPtrsAlloced-1) ) {
834 TREEVIEW_ITEM *oldItems = infoPtr->items;
835 INT32 *oldfreeList = infoPtr->freeList;
837 infoPtr->uNumPtrsAlloced*=2;
838 infoPtr->items = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
839 infoPtr->uNumPtrsAlloced*sizeof (TREEVIEW_ITEM));
840 infoPtr->freeList= HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
841 (1+(infoPtr->uNumPtrsAlloced>>5))*sizeof (INT32));
843 memcpy (&infoPtr->items[0], &oldItems[0],
844 infoPtr->uNumPtrsAlloced/2 * sizeof(TREEVIEW_ITEM));
845 memcpy (&infoPtr->freeList[0], &oldfreeList[0],
846 infoPtr->uNumPtrsAlloced>>6 * sizeof(INT32));
848 HeapFree (GetProcessHeap (), 0, oldItems);
849 HeapFree (GetProcessHeap (), 0, oldfreeList);
852 iItem=0;
853 infoPtr->uNumItems++;
855 if (infoPtr->uMaxHandle==(infoPtr->uNumItems-1)) {
856 iItem=infoPtr->uNumItems;
857 infoPtr->uMaxHandle++;
859 else { /* check freelist */
860 for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++) {
861 if (infoPtr->freeList[i]) {
862 iItem=ffs (infoPtr->freeList[i]);
863 clear_bit (iItem & 31, & infoPtr->freeList[i]);
864 break;
868 if (!iItem) ERR (treeview, "Argh -- can't find free item.\n");
870 tvItem= & ptdi->item;
871 wineItem=& infoPtr->items[iItem];
875 if ((ptdi->hParent==TVI_ROOT) || (ptdi->hParent==0)) {
876 parentItem=NULL;
877 wineItem->parent=0;
878 sibItem=&infoPtr->items [infoPtr->TopRootItem];
879 listItems=infoPtr->uNumItems;
881 else {
882 parentItem= &infoPtr->items[ptdi->hParent];
883 if (!parentItem->firstChild)
884 parentItem->firstChild=iItem;
885 wineItem->parent=ptdi->hParent;
886 sibItem=&infoPtr->items [parentItem->firstChild];
887 parentItem->cChildren++;
888 listItems=parentItem->cChildren;
891 wineItem->upsibling=0; /* needed in case we're the first item in a list */
892 wineItem->sibling=0;
893 wineItem->firstChild=0;
895 if (listItems>1) {
896 prevsib=NULL;
897 switch (ptdi->hInsertAfter) {
898 case TVI_FIRST: wineItem->sibling=infoPtr->TopRootItem;
899 infoPtr->TopRootItem=iItem;
900 break;
901 case TVI_LAST:
902 while (sibItem->sibling) {
903 prevsib=sibItem;
904 sibItem=&infoPtr->items [sibItem->sibling];
906 sibItem->sibling=iItem;
907 if (prevsib!=NULL)
908 wineItem->upsibling=prevsib->hItem;
909 else
910 wineItem->sibling=0; /* terminate list */
911 break;
912 case TVI_SORT:
913 FIXME (treeview, "Sorted insert not implemented yet\n");
914 break;
915 default:
916 while ((sibItem->sibling) && (sibItem->sibling!=iItem)) {
917 prevsib=sibItem;
918 sibItem=&infoPtr->items [sibItem->sibling];
920 if (sibItem->sibling)
921 WARN (treeview, "Buggy program tried to insert item after nonexisting handle.");
922 sibItem->upsibling=iItem;
923 wineItem->sibling=sibItem->hItem;
924 if (prevsib!=NULL)
925 wineItem->upsibling=prevsib->hItem;
926 break;
931 /* Fill in info structure */
933 wineItem->mask=tvItem->mask;
934 wineItem->hItem=iItem;
935 wineItem->iIntegral=1;
937 if (tvItem->mask & TVIF_CHILDREN)
938 wineItem->cChildren=tvItem->cChildren;
940 if (tvItem->mask & TVIF_IMAGE)
941 wineItem->iImage=tvItem->iImage;
943 /* if (tvItem->mask & TVIF_INTEGRAL)
944 wineItem->iIntegral=tvItem->iIntegral; */
947 if (tvItem->mask & TVIF_PARAM)
948 wineItem->lParam=tvItem->lParam;
950 if (tvItem->mask & TVIF_SELECTEDIMAGE)
951 wineItem->iSelectedImage=tvItem->iSelectedImage;
953 if (tvItem->mask & TVIF_STATE) {
954 wineItem->state=tvItem->state;
955 wineItem->stateMask=tvItem->stateMask;
958 if (tvItem->mask & TVIF_TEXT) {
959 TRACE (treeview,"(%s)\n", tvItem->pszText);
960 if (tvItem->pszText!=LPSTR_TEXTCALLBACK32A) {
961 len = lstrlen32A (tvItem->pszText)+1;
962 wineItem->pszText=
963 HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, len+1);
964 lstrcpy32A (wineItem->pszText, tvItem->pszText);
965 wineItem->cchTextMax=len;
969 TREEVIEW_QueueRefresh (wndPtr);
971 return (LRESULT) iItem;
976 static LRESULT
977 TREEVIEW_DeleteItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
979 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
980 INT32 iItem;
981 POINT32 pt;
982 TREEVIEW_ITEM *wineItem;
984 TRACE (treeview,"\n");
985 if (!infoPtr) return FALSE;
987 if ((INT32) lParam == TVI_ROOT) {
988 TREEVIEW_RemoveTree (infoPtr);
989 } else {
990 iItem= (INT32) lParam;
991 wineItem = TREEVIEW_ValidItem (infoPtr, iItem);
992 if (!wineItem) return FALSE;
993 TREEVIEW_SendTreeviewNotify (wndPtr, TVN_DELETEITEM, 0, iItem, 0, pt);
994 TREEVIEW_RemoveItem (infoPtr, wineItem);
997 TREEVIEW_QueueRefresh (wndPtr);
999 return TRUE;
1003 static LRESULT
1004 TREEVIEW_GetIndent (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1006 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1008 return infoPtr->uIndent;
1011 static LRESULT
1012 TREEVIEW_SetIndent (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1014 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1015 INT32 newIndent;
1017 newIndent=(INT32) wParam;
1018 if (newIndent < MINIMUM_INDENT) newIndent=MINIMUM_INDENT;
1019 infoPtr->uIndent=newIndent;
1021 return 0;
1028 static LRESULT
1029 TREEVIEW_Create (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1031 TREEVIEW_INFO *infoPtr;
1032 HDC32 hdc;
1033 TEXTMETRIC32A tm;
1035 TRACE (treeview,"\n");
1036 /* allocate memory for info structure */
1037 infoPtr = (TREEVIEW_INFO *)HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
1038 sizeof(TREEVIEW_INFO));
1040 wndPtr->wExtra[0] = (DWORD)infoPtr;
1042 if (infoPtr == NULL) {
1043 ERR (treeview, "could not allocate info memory!\n");
1044 return 0;
1047 if ((TREEVIEW_INFO*)wndPtr->wExtra[0] != infoPtr) {
1048 ERR (treeview, "pointer assignment error!\n");
1049 return 0;
1052 hdc=GetDC32 (wndPtr->hwndSelf);
1054 /* set default settings */
1055 infoPtr->uInternalStatus=0;
1056 infoPtr->uNumItems=0;
1057 infoPtr->clrBk = GetSysColor32 (COLOR_WINDOW);
1058 infoPtr->clrText = GetSysColor32 (COLOR_BTNTEXT);
1059 infoPtr->cy = 0;
1060 infoPtr->cx = 0;
1061 infoPtr->uIndent = 15;
1062 infoPtr->himlNormal = NULL;
1063 infoPtr->himlState = NULL;
1064 infoPtr->uItemHeight = -1;
1065 GetTextMetrics32A (hdc, &tm);
1066 infoPtr->uRealItemHeight= tm.tmHeight + tm.tmExternalLeading;
1068 infoPtr->items = NULL;
1069 infoPtr->selectedItem=0;
1070 infoPtr->clrText=-1; /* use system color */
1071 infoPtr->dropItem=0;
1074 infoPtr->hwndNotify = GetParent32 (wndPtr->hwndSelf);
1075 infoPtr->bTransparent = (wndPtr->dwStyle & TBSTYLE_FLAT);
1078 if (wndPtr->dwStyle & TBSTYLE_TOOLTIPS) {
1079 /* Create tooltip control */
1080 // infoPtr->hwndToolTip = CreateWindowEx32A (....);
1082 /* Send TV_TOOLTIPSCREATED notification */
1085 ReleaseDC32 (wndPtr->hwndSelf, hdc);
1087 return 0;
1092 static LRESULT
1093 TREEVIEW_Destroy (WND *wndPtr)
1095 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1097 TREEVIEW_RemoveTree (infoPtr);
1098 if (infoPtr->Timer & TV_REFRESH_TIMER_SET)
1099 KillTimer32 (wndPtr->hwndSelf, TV_REFRESH_TIMER);
1101 HeapFree (GetProcessHeap (), 0, infoPtr);
1103 return 0;
1107 static LRESULT
1108 TREEVIEW_Paint (WND *wndPtr, WPARAM32 wParam)
1110 HDC32 hdc;
1111 PAINTSTRUCT32 ps;
1113 hdc = wParam==0 ? BeginPaint32 (wndPtr->hwndSelf, &ps) : (HDC32)wParam;
1114 TREEVIEW_QueueRefresh (wndPtr);
1115 if(!wParam)
1116 EndPaint32 (wndPtr->hwndSelf, &ps);
1117 return 0;
1122 static LRESULT
1123 TREEVIEW_EraseBackground (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1125 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1126 HBRUSH32 hBrush = CreateSolidBrush32 (infoPtr->clrBk);
1127 RECT32 rect;
1129 TRACE (treeview,"\n");
1130 GetClientRect32 (wndPtr->hwndSelf, &rect);
1131 FillRect32 ((HDC32)wParam, &rect, hBrush);
1132 DeleteObject32 (hBrush);
1133 return TRUE;
1144 static BOOL32
1145 TREEVIEW_SendSimpleNotify (WND *wndPtr, UINT32 code)
1147 NMHDR nmhdr;
1149 TRACE (treeview, "%x\n",code);
1150 nmhdr.hwndFrom = wndPtr->hwndSelf;
1151 nmhdr.idFrom = wndPtr->wIDmenu;
1152 nmhdr.code = code;
1154 return (BOOL32) SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
1155 (WPARAM32)nmhdr.idFrom, (LPARAM)&nmhdr);
1161 static BOOL32
1162 TREEVIEW_SendTreeviewNotify (WND *wndPtr, UINT32 code, UINT32 action,
1163 INT32 oldItem, INT32 newItem, POINT32 pt)
1165 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1166 NMTREEVIEW nmhdr;
1167 TREEVIEW_ITEM *wineItem;
1169 TRACE (treeview,"code:%x action:%x olditem:%x newitem:%x\n",
1170 code,action,oldItem,newItem);
1171 nmhdr.hdr.hwndFrom = wndPtr->hwndSelf;
1172 nmhdr.hdr.idFrom = wndPtr->wIDmenu;
1173 nmhdr.hdr.code = code;
1174 nmhdr.action = action;
1175 if (oldItem) {
1176 wineItem=& infoPtr->items[oldItem];
1177 nmhdr.itemOld.mask = wineItem->mask;
1178 nmhdr.itemOld.hItem = wineItem->hItem;
1179 nmhdr.itemOld.state = wineItem->state;
1180 nmhdr.itemOld.stateMask = wineItem->stateMask;
1181 nmhdr.itemOld.iImage = wineItem->iImage;
1182 nmhdr.itemOld.pszText = wineItem->pszText;
1183 nmhdr.itemOld.cchTextMax = wineItem->cchTextMax;
1184 nmhdr.itemOld.iImage = wineItem->iImage;
1185 nmhdr.itemOld.iSelectedImage = wineItem->iSelectedImage;
1186 nmhdr.itemOld.cChildren = wineItem->cChildren;
1187 nmhdr.itemOld.lParam = wineItem->lParam;
1190 if (newItem) {
1191 wineItem=& infoPtr->items[newItem];
1192 nmhdr.itemNew.mask = wineItem->mask;
1193 nmhdr.itemNew.hItem = wineItem->hItem;
1194 nmhdr.itemNew.state = wineItem->state;
1195 nmhdr.itemNew.stateMask = wineItem->stateMask;
1196 nmhdr.itemNew.iImage = wineItem->iImage;
1197 nmhdr.itemNew.pszText = wineItem->pszText;
1198 nmhdr.itemNew.cchTextMax = wineItem->cchTextMax;
1199 nmhdr.itemNew.iImage = wineItem->iImage;
1200 nmhdr.itemNew.iSelectedImage = wineItem->iSelectedImage;
1201 nmhdr.itemNew.cChildren = wineItem->cChildren;
1202 nmhdr.itemNew.lParam = wineItem->lParam;
1205 nmhdr.ptDrag.x = pt.x;
1206 nmhdr.ptDrag.y = pt.y;
1208 return (BOOL32)SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
1209 (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmhdr);
1216 static LRESULT
1217 TREEVIEW_Expand (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1219 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1220 TREEVIEW_ITEM *wineItem;
1221 UINT32 flag;
1222 INT32 expandItem;
1223 POINT32 pt;
1225 flag= (UINT32) wParam;
1226 expandItem= (INT32) lParam;
1227 TRACE (treeview,"flags:%x item:%x\n", expandItem, wParam);
1228 wineItem = TREEVIEW_ValidItem (infoPtr, expandItem);
1229 if (!wineItem) return 0;
1230 if (!wineItem->cChildren) return 0;
1232 if (flag & TVE_TOGGLE) { /* FIXME: check exact behaviour here */
1233 flag &= ~TVE_TOGGLE; /* ie: bitwise ops or 'case' ops */
1234 if (wineItem->state & TVIS_EXPANDED)
1235 flag |= TVE_COLLAPSE;
1236 else
1237 flag |= TVE_EXPAND;
1240 switch (flag) {
1241 case TVE_COLLAPSERESET:
1242 if (!wineItem->state & TVIS_EXPANDED) return 0;
1243 wineItem->state &= ~(TVIS_EXPANDEDONCE | TVIS_EXPANDED);
1244 TREEVIEW_RemoveAllChildren (infoPtr, wineItem);
1245 break;
1247 case TVE_COLLAPSE:
1248 if (!wineItem->state & TVIS_EXPANDED) return 0;
1249 wineItem->state &= ~TVIS_EXPANDED;
1250 break;
1252 case TVE_EXPAND:
1253 if (wineItem->state & TVIS_EXPANDED) return 0;
1254 if (!(wineItem->state & TVIS_EXPANDEDONCE)) {
1255 if (TREEVIEW_SendTreeviewNotify (wndPtr, TVN_ITEMEXPANDING,
1256 0, 0, expandItem, pt))
1257 return FALSE; /* FIXME: OK? */
1258 wineItem->state |= TVIS_EXPANDED | TVIS_EXPANDEDONCE;
1259 TREEVIEW_SendTreeviewNotify (wndPtr, TVN_ITEMEXPANDED,
1260 0, 0, expandItem, pt);
1262 wineItem->state |= TVIS_EXPANDED;
1263 break;
1264 case TVE_EXPANDPARTIAL:
1265 FIXME (treeview, "TVE_EXPANDPARTIAL not implemented\n");
1266 wineItem->state ^=TVIS_EXPANDED;
1267 wineItem->state |=TVIS_EXPANDEDONCE;
1268 break;
1271 TREEVIEW_QueueRefresh (wndPtr);
1273 return TRUE;
1278 static HTREEITEM
1279 TREEVIEW_HitTest (WND *wndPtr, LPTVHITTESTINFO lpht)
1281 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1282 TREEVIEW_ITEM *wineItem;
1283 RECT32 rect;
1284 UINT32 status,x,y;
1288 GetClientRect32 (wndPtr->hwndSelf, &rect);
1289 TRACE (treeview,"(%d,%d)\n",lpht->pt.x, lpht->pt.y);
1291 status=0;
1292 x=lpht->pt.x;
1293 y=lpht->pt.y;
1294 if (x < rect.left) status|=TVHT_TOLEFT;
1295 if (x > rect.right) status|=TVHT_TORIGHT;
1296 if (y < rect.top ) status|=TVHT_ABOVE;
1297 if (y > rect.bottom) status|=TVHT_BELOW;
1298 if (status) {
1299 lpht->flags=status;
1300 return 0;
1303 if (!infoPtr->firstVisible) WARN (treeview,"Can't fetch first visible item");
1304 wineItem=&infoPtr->items [infoPtr->firstVisible];
1306 while ((wineItem!=NULL) && (y > wineItem->rect.bottom))
1307 wineItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
1309 if (wineItem==NULL) {
1310 lpht->flags=TVHT_NOWHERE;
1311 return 0;
1314 if (x>wineItem->rect.right) {
1315 lpht->flags|=TVHT_ONITEMRIGHT;
1316 return wineItem->hItem;
1320 if (x<wineItem->rect.left+10) lpht->flags|=TVHT_ONITEMBUTTON;
1322 lpht->flags=TVHT_ONITEMLABEL; /* FIXME: implement other flags */
1325 lpht->hItem=wineItem->hItem;
1326 return wineItem->hItem;
1330 static LRESULT
1331 TREEVIEW_HitTest32 (WND *wndPtr, LPARAM lParam)
1334 return (LRESULT) TREEVIEW_HitTest (wndPtr, (LPTVHITTESTINFO) lParam);
1340 LRESULT
1341 TREEVIEW_LButtonDoubleClick (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1343 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1344 TREEVIEW_ITEM *wineItem;
1345 INT32 iItem;
1346 TVHITTESTINFO ht;
1348 TRACE (treeview,"\n");
1349 ht.pt.x = (INT32)LOWORD(lParam);
1350 ht.pt.y = (INT32)HIWORD(lParam);
1351 SetFocus32 (wndPtr->hwndSelf);
1353 iItem=TREEVIEW_HitTest (wndPtr, &ht);
1354 TRACE (treeview,"item %d \n",iItem);
1355 wineItem=TREEVIEW_ValidItem (infoPtr, iItem);
1356 if (!wineItem) return 0;
1358 if (TREEVIEW_SendSimpleNotify (wndPtr, NM_DBLCLK)!=TRUE) { /* FIXME!*/
1359 wineItem->state &= ~TVIS_EXPANDEDONCE;
1360 TREEVIEW_Expand (wndPtr, (WPARAM32) TVE_TOGGLE, (LPARAM) iItem);
1362 return TRUE;
1367 static LRESULT
1368 TREEVIEW_LButtonDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1370 INT32 iItem;
1371 TVHITTESTINFO ht;
1373 TRACE (treeview,"\n");
1374 ht.pt.x = (INT32)LOWORD(lParam);
1375 ht.pt.y = (INT32)HIWORD(lParam);
1377 SetFocus32 (wndPtr->hwndSelf);
1378 iItem=TREEVIEW_HitTest (wndPtr, &ht);
1379 TRACE (treeview,"item %d \n",iItem);
1380 if (ht.flags & TVHT_ONITEMBUTTON) {
1381 TREEVIEW_Expand (wndPtr, (WPARAM32) TVE_TOGGLE, (LPARAM) iItem);
1384 if (TREEVIEW_SelectItem (wndPtr, (WPARAM32) TVGN_CARET, (LPARAM) iItem))
1385 return 0;
1388 return 0;
1392 static LRESULT
1393 TREEVIEW_RButtonDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1396 return 0;
1402 /* FIXME: If the specified item is the child of a collapsed parent item,
1403 expand parent's list of child items to reveal the specified item.
1406 static LRESULT
1407 TREEVIEW_SelectItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1409 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1410 TREEVIEW_ITEM *prevItem,*wineItem;
1411 INT32 action,prevSelect, newSelect;
1412 POINT32 dummy;
1414 TRACE (treeview,"item %lx, flag %x\n", lParam, wParam);
1415 newSelect= (INT32) lParam;
1416 wineItem = TREEVIEW_ValidItem (infoPtr, newSelect);
1417 if (!wineItem) return FALSE;
1418 prevSelect=infoPtr->selectedItem;
1419 prevItem= TREEVIEW_ValidItem (infoPtr, prevSelect);
1420 dummy.x=0;
1421 dummy.y=0;
1423 action= (INT32) wParam;
1425 switch (action) {
1426 case TVGN_CARET:
1427 if (TREEVIEW_SendTreeviewNotify (wndPtr, TVN_SELCHANGING, TVC_BYMOUSE,
1428 prevSelect, newSelect,dummy))
1429 return FALSE; /* FIXME: OK? */
1431 if (prevItem) prevItem->state &= ~TVIS_SELECTED;
1432 infoPtr->selectedItem=newSelect;
1433 wineItem->state |=TVIS_SELECTED;
1434 TREEVIEW_SendTreeviewNotify (wndPtr, TVN_SELCHANGED,
1435 TVC_BYMOUSE, prevSelect, newSelect, dummy);
1436 break;
1437 case TVGN_DROPHILITE:
1438 FIXME (treeview, "DROPHILITE not implemented");
1439 break;
1440 case TVGN_FIRSTVISIBLE:
1441 FIXME (treeview, "FIRSTVISIBLE not implemented");
1442 break;
1445 TREEVIEW_QueueRefresh (wndPtr);
1447 return TRUE;
1452 /* FIXME: does KEYDOWN also send notifications?? If so, use
1453 TREEVIEW_SelectItem.
1457 static LRESULT
1458 TREEVIEW_KeyDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1460 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1461 TREEVIEW_ITEM *prevItem,*newItem;
1462 int prevSelect;
1465 TRACE (treeview,"%x %lx",wParam, lParam);
1466 prevSelect=infoPtr->selectedItem;
1467 if (!prevSelect) return FALSE;
1469 prevItem= TREEVIEW_ValidItem (infoPtr, prevSelect);
1471 newItem=NULL;
1472 switch (wParam) {
1473 case VK_UP:
1474 newItem=TREEVIEW_GetPrevListItem (infoPtr, prevItem);
1475 if (!newItem)
1476 newItem=& infoPtr->items[infoPtr->TopRootItem];
1477 break;
1478 case VK_DOWN:
1479 newItem=TREEVIEW_GetNextListItem (infoPtr, prevItem);
1480 if (!newItem) newItem=prevItem;
1481 break;
1482 case VK_HOME:
1483 newItem=& infoPtr->items[infoPtr->TopRootItem];
1484 break;
1485 case VK_END:
1486 newItem=TREEVIEW_GetLastListItem (infoPtr);
1487 break;
1488 case VK_PRIOR:
1489 case VK_NEXT:
1490 case VK_BACK:
1491 case VK_RETURN:
1492 FIXME (treeview, "%x not implemented\n", wParam);
1493 break;
1496 if (!newItem) return FALSE;
1498 if (prevItem!=newItem) {
1499 prevItem->state &= ~TVIS_SELECTED;
1500 newItem->state |= TVIS_SELECTED;
1501 infoPtr->selectedItem=newItem->hItem;
1502 TREEVIEW_QueueRefresh (wndPtr);
1503 return TRUE;
1506 return FALSE;
1511 static LRESULT
1512 TREEVIEW_VScroll (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1515 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1516 int maxHeight;
1518 TRACE (treeview,"wp %x, lp %lx\n", wParam, lParam);
1519 if (!infoPtr->uInternalStatus & TV_VSCROLL) return FALSE;
1521 switch (LOWORD (wParam)) {
1522 case SB_LINEUP:
1523 if (!infoPtr->cy) return FALSE;
1524 infoPtr->cy -= infoPtr->uRealItemHeight;
1525 if (infoPtr->cy < 0) infoPtr->cy=0;
1526 break;
1527 case SB_LINEDOWN:
1528 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
1529 if (infoPtr->cy == maxHeight) return FALSE;
1530 infoPtr->cy += infoPtr->uRealItemHeight;
1531 if (infoPtr->cy > maxHeight)
1532 infoPtr->cy = maxHeight;
1533 break;
1534 case SB_PAGEUP:
1535 if (!infoPtr->cy) return FALSE;
1536 infoPtr->cy -= infoPtr->uVisibleHeight;
1537 if (infoPtr->cy < 0) infoPtr->cy=0;
1538 break;
1539 case SB_PAGEDOWN:
1540 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
1541 if (infoPtr->cy == maxHeight) return FALSE;
1542 infoPtr->cy += infoPtr->uVisibleHeight;
1543 if (infoPtr->cy > maxHeight)
1544 infoPtr->cy = maxHeight;
1545 break;
1546 case SB_THUMBTRACK:
1547 infoPtr->cy = HIWORD (wParam);
1548 break;
1552 TREEVIEW_QueueRefresh (wndPtr);
1553 return TRUE;
1556 static LRESULT
1557 TREEVIEW_HScroll (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1559 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1561 TRACE (treeview,"wp %lx, lp %x\n", lParam, wParam);
1563 if (!infoPtr->uInternalStatus & TV_HSCROLL) return FALSE;
1564 return TRUE;
1570 LRESULT WINAPI
1571 TREEVIEW_WindowProc (HWND32 hwnd, UINT32 uMsg, WPARAM32 wParam, LPARAM lParam)
1573 WND *wndPtr = WIN_FindWndPtr(hwnd);
1576 switch (uMsg) {
1577 case TVM_INSERTITEM32A:
1578 return TREEVIEW_InsertItem32A (wndPtr, wParam, lParam);
1580 case TVM_INSERTITEM32W:
1581 FIXME (treeview, "Unimplemented msg TVM_INSERTITEM32W\n");
1582 return 0;
1584 case TVM_DELETEITEM:
1585 return TREEVIEW_DeleteItem (wndPtr, wParam, lParam);
1587 case TVM_EXPAND:
1588 return TREEVIEW_Expand (wndPtr, wParam, lParam);
1590 case TVM_GETITEMRECT:
1591 return TREEVIEW_GetItemRect (wndPtr, wParam, lParam);
1593 case TVM_GETCOUNT:
1594 return TREEVIEW_GetCount (wndPtr, wParam, lParam);
1596 case TVM_GETINDENT:
1597 return TREEVIEW_GetIndent (wndPtr, wParam, lParam);
1599 case TVM_SETINDENT:
1600 return TREEVIEW_SetIndent (wndPtr, wParam, lParam);
1602 case TVM_GETIMAGELIST:
1603 return TREEVIEW_GetImageList (wndPtr, wParam, lParam);
1605 case TVM_SETIMAGELIST:
1606 return TREEVIEW_SetImageList (wndPtr, wParam, lParam);
1608 case TVM_GETNEXTITEM:
1609 return TREEVIEW_GetNextItem32 (wndPtr, wParam, lParam);
1611 case TVM_SELECTITEM:
1612 return TREEVIEW_SelectItem (wndPtr, wParam, lParam);
1614 case TVM_GETITEM32A:
1615 return TREEVIEW_GetItem (wndPtr, wParam, lParam);
1617 case TVM_GETITEM32W:
1618 FIXME (treeview, "Unimplemented msg TVM_GETITEM32W\n");
1619 return 0;
1621 case TVM_SETITEM32A:
1622 return TREEVIEW_SetItem (wndPtr, wParam, lParam);
1624 case TVM_SETITEM32W:
1625 FIXME (treeview, "Unimplemented msg TVM_SETITEMW\n");
1626 return 0;
1628 case TVM_EDITLABEL32A:
1629 FIXME (treeview, "Unimplemented msg TVM_EDITLABEL32A \n");
1630 return 0;
1632 case TVM_EDITLABEL32W:
1633 FIXME (treeview, "Unimplemented msg TVM_EDITLABEL32W \n");
1634 return 0;
1636 case TVM_GETEDITCONTROL:
1637 FIXME (treeview, "Unimplemented msg TVM_GETEDITCONTROL\n");
1638 return 0;
1640 case TVM_GETVISIBLECOUNT:
1641 return TREEVIEW_GetVisibleCount (wndPtr, wParam, lParam);
1643 case TVM_HITTEST:
1644 return TREEVIEW_HitTest32 (wndPtr, lParam);
1646 case TVM_CREATEDRAGIMAGE:
1647 FIXME (treeview, "Unimplemented msg TVM_CREATEDRAGIMAGE\n");
1648 return 0;
1650 case TVM_SORTCHILDREN:
1651 FIXME (treeview, "Unimplemented msg TVM_SORTCHILDREN\n");
1652 return 0;
1654 case TVM_ENSUREVISIBLE:
1655 FIXME (treeview, "Unimplemented msg TVM_ENSUREVISIBLE\n");
1656 return 0;
1658 case TVM_SORTCHILDRENCB:
1659 FIXME (treeview, "Unimplemented msg TVM_SORTCHILDRENCB\n");
1660 return 0;
1662 case TVM_ENDEDITLABELNOW:
1663 FIXME (treeview, "Unimplemented msg TVM_ENDEDITLABELNOW\n");
1664 return 0;
1666 case TVM_GETISEARCHSTRING32A:
1667 FIXME (treeview, "Unimplemented msg TVM_GETISEARCHSTRING32A\n");
1668 return 0;
1670 case TVM_GETISEARCHSTRING32W:
1671 FIXME (treeview, "Unimplemented msg TVM_GETISEARCHSTRING32W\n");
1672 return 0;
1674 case TVM_SETTOOLTIPS:
1675 FIXME (treeview, "Unimplemented msg TVM_SETTOOLTIPS\n");
1676 return 0;
1678 case TVM_GETTOOLTIPS:
1679 FIXME (treeview, "Unimplemented msg TVM_GETTOOLTIPS\n");
1680 return 0;
1682 case TVM_SETINSERTMARK:
1683 FIXME (treeview, "Unimplemented msg TVM_SETINSERTMARK\n");
1684 return 0;
1686 case TVM_SETITEMHEIGHT:
1687 return TREEVIEW_SetItemHeight (wndPtr, wParam);
1689 case TVM_GETITEMHEIGHT:
1690 return TREEVIEW_GetItemHeight (wndPtr);
1692 case TVM_SETBKCOLOR:
1693 FIXME (treeview, "Unimplemented msg TVM_SETBKCOLOR\n");
1694 return 0;
1696 case TVM_SETTEXTCOLOR:
1697 return TREEVIEW_SetTextColor (wndPtr, wParam, lParam);
1699 case TVM_GETBKCOLOR:
1700 FIXME (treeview, "Unimplemented msg TVM_GETBKCOLOR\n");
1701 return 0;
1703 case TVM_GETTEXTCOLOR:
1704 return TREEVIEW_GetTextColor (wndPtr);
1706 case TVM_SETSCROLLTIME:
1707 FIXME (treeview, "Unimplemented msg TVM_SETSCROLLTIME\n");
1708 return 0;
1710 case TVM_GETSCROLLTIME:
1711 FIXME (treeview, "Unimplemented msg TVM_GETSCROLLTIME\n");
1712 return 0;
1714 case TVM_SETINSERTMARKCOLOR:
1715 FIXME (treeview, "Unimplemented msg TVM_SETINSERTMARKCOLOR\n");
1716 return 0;
1718 case TVM_SETUNICODEFORMAT:
1719 FIXME (treeview, "Unimplemented msg TVM_SETUNICODEFORMAT\n");
1720 return 0;
1722 case TVM_GETUNICODEFORMAT:
1723 FIXME (treeview, "Unimplemented msg TVM_GETUNICODEFORMAT\n");
1724 return 0;
1726 // case WM_COMMAND:
1728 case WM_CREATE:
1729 return TREEVIEW_Create (wndPtr, wParam, lParam);
1731 case WM_DESTROY:
1732 return TREEVIEW_Destroy (wndPtr);
1734 // case WM_ENABLE:
1736 case WM_ERASEBKGND:
1737 return TREEVIEW_EraseBackground (wndPtr, wParam, lParam);
1739 case WM_GETDLGCODE:
1740 return DLGC_WANTARROWS | DLGC_WANTCHARS;
1742 case WM_PAINT:
1743 return TREEVIEW_Paint (wndPtr, wParam);
1745 // case WM_GETFONT:
1746 // case WM_SETFONT:
1748 case WM_KEYDOWN:
1749 return TREEVIEW_KeyDown (wndPtr, wParam, lParam);
1752 // case WM_KILLFOCUS:
1753 // case WM_SETFOCUS:
1756 case WM_LBUTTONDOWN:
1757 return TREEVIEW_LButtonDown (wndPtr, wParam, lParam);
1759 case WM_LBUTTONDBLCLK:
1760 return TREEVIEW_LButtonDoubleClick (wndPtr, wParam, lParam);
1762 case WM_RBUTTONDOWN:
1763 return TREEVIEW_RButtonDown (wndPtr, wParam, lParam);
1766 // case WM_SYSCOLORCHANGE:
1767 // case WM_STYLECHANGED:
1768 // case WM_SETREDRAW:
1770 case WM_TIMER:
1771 return TREEVIEW_HandleTimer (wndPtr, wParam, lParam);
1773 // case WM_SIZE:
1774 case WM_HSCROLL:
1775 return TREEVIEW_HScroll (wndPtr, wParam, lParam);
1776 case WM_VSCROLL:
1777 return TREEVIEW_VScroll (wndPtr, wParam, lParam);
1779 default:
1780 if (uMsg >= WM_USER)
1781 FIXME (treeview, "Unknown msg %04x wp=%08x lp=%08lx\n",
1782 uMsg, wParam, lParam);
1783 return DefWindowProc32A (hwnd, uMsg, wParam, lParam);
1785 return 0;
1789 void
1790 TREEVIEW_Register (void)
1792 WNDCLASS32A wndClass;
1794 TRACE (treeview,"\n");
1796 if (GlobalFindAtom32A (WC_TREEVIEW32A)) return;
1798 ZeroMemory (&wndClass, sizeof(WNDCLASS32A));
1799 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
1800 wndClass.lpfnWndProc = (WNDPROC32)TREEVIEW_WindowProc;
1801 wndClass.cbClsExtra = 0;
1802 wndClass.cbWndExtra = sizeof(TREEVIEW_INFO *);
1803 wndClass.hCursor = LoadCursor32A (0, IDC_ARROW32A);
1804 wndClass.hbrBackground = 0;
1805 wndClass.lpszClassName = WC_TREEVIEW32A;
1807 RegisterClass32A (&wndClass);