Fixes for FreeBSD.
[wine] / dlls / comctl32 / treeview.c
1 /* Treeview control
2  *
3  * Copyright 1998 Eric Kohl <ekohl@abo.rhein-zeitung.de>
4  * Copyright 1998 Alex Priem <alexp@sci.kun.nl>
5  *
6  *
7  * TODO:
8  *   - Nearly all notifications.
9  * 
10  *   list-handling stuff: sort, sorted insertitem.
11  *
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 
21  *
22  * FIXMEs:  
23    -GetNextItem: add flag for traversing visible items 
24    -DblClick:   ctlmacro.exe's NM_DBLCLK seems to go wrong (returns FALSE).
25              
26  */
27
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
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
43
44 #define TREEVIEW_GetInfoPtr(wndPtr) ((TREEVIEW_INFO *)wndPtr->wExtra[0])
45
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);
55
56
57
58
59
60 /* helper functions. Work with the assumption that validity of operands 
61    is checked beforehand */
62
63
64 static TREEVIEW_ITEM *
65 TREEVIEW_ValidItem (TREEVIEW_INFO *infoPtr,int  handle)
66 {
67  
68  if ((!handle) || (handle>infoPtr->uMaxHandle)) return NULL;
69  if (test_bit (handle, infoPtr->freeList)) return NULL;
70
71  return & infoPtr->items[handle];
72 }
73
74
75
76 static TREEVIEW_ITEM *TREEVIEW_GetPrevListItem (TREEVIEW_INFO *infoPtr, 
77                                         TREEVIEW_ITEM *tvItem)
78
79 {
80  TREEVIEW_ITEM *wineItem;
81
82  if (tvItem->upsibling) 
83                 return (& infoPtr->items[tvItem->upsibling]);
84
85  wineItem=tvItem;
86  while (wineItem->parent) {
87         wineItem=& infoPtr->items[wineItem->parent];
88         if (wineItem->upsibling) 
89                 return (& infoPtr->items[wineItem->upsibling]);
90  } 
91
92  return NULL;
93 }
94
95 static TREEVIEW_ITEM *TREEVIEW_GetNextListItem (TREEVIEW_INFO *infoPtr, 
96                                         TREEVIEW_ITEM *tvItem)
97
98 {
99  TREEVIEW_ITEM *wineItem;
100
101  if (tvItem->sibling) 
102                 return (& infoPtr->items[tvItem->sibling]);
103
104  wineItem=tvItem;
105  while (wineItem->parent) {
106         wineItem=& infoPtr->items [wineItem->parent];
107         if (wineItem->sibling) 
108                 return (& infoPtr->items [wineItem->sibling]);
109  } 
110
111  return NULL;
112 }
113
114 static TREEVIEW_ITEM *TREEVIEW_GetLastListItem (TREEVIEW_INFO *infoPtr)
115
116 {
117   TREEVIEW_ITEM *wineItem;
118   
119  wineItem=NULL;
120  if (infoPtr->TopRootItem) 
121         wineItem=& infoPtr->items [infoPtr->TopRootItem];
122  while (wineItem->sibling) 
123         wineItem=& infoPtr->items [wineItem->sibling];
124
125  return wineItem;
126 }
127         
128  
129
130
131 static void
132 TREEVIEW_RemoveItem (TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem)
133
134 {
135  TREEVIEW_ITEM *parentItem, *upsiblingItem, *siblingItem;
136  INT32 iItem;
137
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);
144
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;
155                 }
156  }
157
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;
163  }
164  if (wineItem->sibling) {
165         siblingItem=& infoPtr->items [wineItem->sibling];
166         siblingItem->upsibling=wineItem->upsibling;
167  }
168 }
169
170
171
172 static void TREEVIEW_RemoveAllChildren (TREEVIEW_INFO *infoPtr, 
173                                            TREEVIEW_ITEM *parentItem)
174
175 {
176  TREEVIEW_ITEM *killItem;
177  INT32  kill;
178  
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;
186  }
187  infoPtr->uNumItems -= parentItem->cChildren;
188  parentItem->firstChild = 0;
189  parentItem->cChildren = 0;
190 }
191
192
193 /* Note:TREEVIEW_RemoveTree doesn't remove infoPtr itself */
194
195 static void TREEVIEW_RemoveTree (TREEVIEW_INFO *infoPtr)
196                                            
197
198 {
199         TREEVIEW_ITEM *killItem;
200         int i;
201
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);
207                 } 
208
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;
215     }   
216 }
217
218
219
220
221
222
223
224
225
226
227 static LRESULT
228 TREEVIEW_GetImageList (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
229 {
230   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
231
232   TRACE (treeview,"\n");
233
234   if (infoPtr==NULL) return 0;
235
236   if ((INT32)wParam == TVSIL_NORMAL) 
237         return (LRESULT) infoPtr->himlNormal;
238   if ((INT32)wParam == TVSIL_STATE) 
239         return (LRESULT) infoPtr->himlState;
240
241   return 0;
242 }
243
244
245
246
247 static LRESULT
248 TREEVIEW_SetImageList (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
249 {
250     TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
251     HIMAGELIST himlTemp;
252
253     switch ((INT32)wParam) {
254         case TVSIL_NORMAL:
255             himlTemp = infoPtr->himlNormal;
256             infoPtr->himlNormal = (HIMAGELIST)lParam;
257             return (LRESULT)himlTemp;
258
259         case TVSIL_STATE:
260             himlTemp = infoPtr->himlState;
261             infoPtr->himlState = (HIMAGELIST)lParam;
262             return (LRESULT)himlTemp;
263     }
264
265     return (LRESULT)NULL;
266 }
267
268
269
270 static LRESULT
271 TREEVIEW_SetItemHeight (WND *wndPtr, WPARAM32 wParam)
272 {
273   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
274   INT32 prevHeight=infoPtr->uItemHeight;
275   HDC32 hdc;
276   TEXTMETRIC32A tm;
277
278
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;
286   }
287
288         /* FIXME: check wParam > imagelist height */
289
290   if (!(wndPtr->dwStyle & TVS_NONEVENHEIGHT))
291         infoPtr->uItemHeight = (INT32) wParam & 0xfffffffe;
292   return prevHeight;
293 }
294
295 static LRESULT
296 TREEVIEW_GetItemHeight (WND *wndPtr)
297 {
298   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
299   
300   return infoPtr->uItemHeight;
301 }
302   
303 static LRESULT
304 TREEVIEW_SetTextColor (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
305 {
306   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
307   COLORREF prevColor=infoPtr->clrText;
308
309   infoPtr->clrText=(COLORREF) lParam;
310   return (LRESULT) prevColor;
311 }
312
313 static LRESULT
314 TREEVIEW_GetTextColor (WND *wndPtr)
315 {
316   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
317         
318   return (LRESULT) infoPtr->clrText;
319 }
320
321
322 static INT32
323 TREEVIEW_DrawItem (WND *wndPtr, HDC32 hdc, TREEVIEW_ITEM *wineItem, 
324                    TREEVIEW_ITEM *upperItem, int indent)
325 {
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;
332   
333   hnewPen = CreatePen32(PS_DOT, 0, GetSysColor32(COLOR_WINDOWTEXT) );
334   hOldPen = SelectObject32( hdc, hnewPen );
335  
336   r=wineItem->rect;
337   if (upperItem) 
338         upper=upperItem->rect;
339   else {
340         upper.top=0;
341         upper.left=8;
342   }
343   center=(r.top+r.bottom)/2;
344   xpos=r.left+8;
345
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;
354
355                 Polyline32 (hdc,points,3);
356         }
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);
364         }
365  }
366
367   DeleteObject32(hnewPen);
368   SelectObject32(hdc, hOldPen);
369
370   if ((wndPtr->dwStyle & TVS_HASBUTTONS) && (wineItem->cChildren)) {
371 /*
372         hRootPen = CreatePen32(PS_SOLID, 0, GetSysColor32(COLOR_WINDOW) );
373         SelectObject32( hdc, hRootPen );
374 */
375
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);
382         }
383  /*     DeleteObject32(hRootPen); */
384         }
385
386
387   xpos+=13;
388
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;
395                 }
396         }
397   }
398
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));
405             }
406             else {
407                 oldBkMode = SetBkMode32(hdc, TRANSPARENT);
408             }
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);
421         }
422
423  return wineItem->rect.right;
424 }
425
426
427
428
429
430
431
432 static LRESULT
433 TREEVIEW_GetItemRect (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
434 {
435   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
436   TREEVIEW_ITEM *wineItem;
437   INT32 iItem;
438   LPRECT32 lpRect;
439
440   TRACE (treeview,"\n");
441   if (infoPtr==NULL) return FALSE;
442   
443   iItem = (INT32)lParam;
444   wineItem = TREEVIEW_ValidItem (infoPtr, iItem);
445   if (!wineItem) return FALSE;
446
447   wineItem=& infoPtr->items[ iItem ];
448   if (!wineItem->visible) return FALSE;
449
450   lpRect = (LPRECT32)lParam;
451   if (lpRect == NULL) return FALSE;
452         
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;
463   }
464
465   return TRUE;
466 }
467
468
469
470 static LRESULT
471 TREEVIEW_GetVisibleCount (WND *wndPtr,  WPARAM32 wParam, LPARAM lParam)
472
473 {
474   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
475
476   TRACE (treeview,"\n");
477
478   return (LRESULT) infoPtr->uVisibleHeight / infoPtr->uRealItemHeight;
479 }
480
481
482
483 static LRESULT
484 TREEVIEW_SetItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
485 {
486   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
487   TREEVIEW_ITEM *wineItem;
488   TV_ITEM *tvItem;
489   INT32 iItem,len;
490
491   TRACE (treeview,"\n");
492   tvItem=(LPTVITEM) lParam;
493   iItem=tvItem->hItem;
494
495   wineItem = TREEVIEW_ValidItem (infoPtr, iItem);
496   if (!wineItem) return FALSE;
497
498   if (tvItem->mask & TVIF_CHILDREN) {
499         wineItem->cChildren=tvItem->cChildren;
500   }
501
502   if (tvItem->mask & TVIF_IMAGE) {
503        wineItem->iImage=tvItem->iImage;
504   }
505
506   if (tvItem->mask & TVIF_INTEGRAL) {
507 /*        wineItem->iIntegral=tvItem->iIntegral; */
508   }
509
510   if (tvItem->mask & TVIF_PARAM) {
511         wineItem->lParam=tvItem->lParam;
512   }
513
514   if (tvItem->mask & TVIF_SELECTEDIMAGE) {
515         wineItem->iSelectedImage=tvItem->iSelectedImage;
516   }
517
518   if (tvItem->mask & TVIF_STATE) {
519         wineItem->state=tvItem->state & tvItem->stateMask;
520   }
521
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);
528         }
529         lstrcpyn32A (wineItem->pszText, tvItem->pszText,len);
530    }
531
532   return TRUE;
533 }
534
535
536
537
538
539 static void
540 TREEVIEW_Refresh (WND *wndPtr, HDC32 hdc)
541
542 {
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;
550
551     TRACE (treeview,"\n");
552
553     if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
554                 KillTimer32 (wndPtr->hwndSelf, TV_REFRESH_TIMER);
555                 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
556     }
557
558     
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;
565
566         infoPtr->uVisibleHeight=viewbottom - viewtop;
567
568     hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject32 (DEFAULT_GUI_FONT);
569     hOldFont = SelectObject32 (hdc, hFont);
570
571     /* draw background */
572     hbrBk = GetSysColorBrush32(COLOR_WINDOW);
573     FillRect32(hdc, &rect, hbrBk);
574
575
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);
582
583     while (iItem) {
584                 prevItem=wineItem;
585         wineItem= & infoPtr->items[iItem];
586
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);
591
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);
602                 }
603                 else {
604                         wineItem->rect.top  = wineItem->rect.bottom = -1;
605                         wineItem->rect.left = wineItem->rect.right = -1;
606                 }
607
608                 /* look up next item */
609         
610                 if ((wineItem->firstChild) && (wineItem->state & TVIS_EXPANDED)) {
611                         iItem=wineItem->firstChild;
612                         indent++;
613                         x+=infoPtr->uIndent;
614                 }
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;
623                         }
624                 }
625         y +=height;
626     }                           /* while */
627
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);
636         }
637     else {
638                 if (infoPtr->uInternalStatus & TV_VSCROLL) 
639                         ShowScrollBar32 (wndPtr->hwndSelf, SB_VERT, FALSE);
640                 infoPtr->uInternalStatus &= ~TV_VSCROLL;
641         }
642
643
644     SelectObject32 (hdc, hOldFont);
645 }
646
647
648 static LRESULT 
649 TREEVIEW_HandleTimer ( WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
650 {
651   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
652   HDC32 hdc;
653
654   if (!infoPtr) return FALSE;
655  
656   TRACE (treeview, "timer\n");
657
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;
670  }
671                 
672  return 1;
673 }
674
675
676 static void
677 TREEVIEW_QueueRefresh (WND *wndPtr)
678
679 {
680  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
681
682  TRACE (treeview,"queued\n");
683  if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
684         KillTimer32 (wndPtr->hwndSelf, TV_REFRESH_TIMER);
685  }
686
687  SetTimer32 (wndPtr->hwndSelf, TV_REFRESH_TIMER, TV_REFRESH_DELAY, 0);
688  infoPtr->Timer|=TV_REFRESH_TIMER_SET;
689 }
690
691
692
693 static LRESULT
694 TREEVIEW_GetItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
695 {
696   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
697   LPTVITEM      tvItem;
698   TREEVIEW_ITEM *wineItem;
699   INT32         iItem,len;
700
701   TRACE (treeview,"\n");
702   tvItem=(LPTVITEM) lParam;
703   iItem=tvItem->hItem;
704
705   wineItem = TREEVIEW_ValidItem (infoPtr, iItem);
706   if (!wineItem) return FALSE;
707
708
709    if (tvItem->mask & TVIF_CHILDREN) {
710         tvItem->cChildren=wineItem->cChildren;
711    }
712
713    if (tvItem->mask & TVIF_HANDLE) {
714         tvItem->hItem=wineItem->hItem;
715    }
716
717    if (tvItem->mask & TVIF_IMAGE) {
718         tvItem->iImage=wineItem->iImage;
719    }
720
721    if (tvItem->mask & TVIF_INTEGRAL) {
722 /*        tvItem->iIntegral=wineItem->iIntegral; */
723    }
724
725    if (tvItem->mask & TVIF_PARAM) {
726         tvItem->lParam=wineItem->lParam;
727    }
728
729    if (tvItem->mask & TVIF_SELECTEDIMAGE) {
730         tvItem->iSelectedImage=wineItem->iSelectedImage;
731    }
732
733    if (tvItem->mask & TVIF_STATE) {
734         tvItem->state=wineItem->state & tvItem->stateMask;
735    }
736
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);
742    }
743
744   return TRUE;
745 }
746
747
748
749 static LRESULT
750 TREEVIEW_GetNextItem32 (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
751
752 {
753   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
754   TREEVIEW_ITEM *wineItem;
755   INT32 iItem, flag;
756
757
758   TRACE (treeview,"item:%lu, flags:%x\n", lParam, wParam);
759   if (!infoPtr) return FALSE;
760
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;
767         }
768         
769   iItem= (INT32) lParam;
770   wineItem = TREEVIEW_ValidItem (infoPtr, iItem);
771   if (!wineItem) return FALSE;
772
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);
793         }
794
795  return 0;
796 }
797
798
799 static LRESULT
800 TREEVIEW_GetCount (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
801 {
802  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
803
804  return (LRESULT) infoPtr->uNumItems;
805 }
806
807
808
809
810 /* the method used below isn't the most memory-friendly, but it avoids 
811    a lot of memory reallocations */ 
812
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? */
816
817 static LRESULT
818 TREEVIEW_InsertItem32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
819
820 {
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;
826   
827   TRACE (treeview,"\n");
828   ptdi = (TVINSERTSTRUCT *) lParam;
829
830         /* check if memory is available */
831
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;
839    }
840
841   if (infoPtr->uNumItems == (infoPtr->uNumPtrsAlloced-1) ) {
842         TREEVIEW_ITEM *oldItems = infoPtr->items;
843         INT32 *oldfreeList = infoPtr->freeList;
844
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));
850
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));
855
856          HeapFree (GetProcessHeap (), 0, oldItems);  
857          HeapFree (GetProcessHeap (), 0, oldfreeList);  
858     }
859
860   iItem=0;
861   infoPtr->uNumItems++;
862
863   if (infoPtr->uMaxHandle==(infoPtr->uNumItems-1))  { 
864         iItem=infoPtr->uNumItems;
865         infoPtr->uMaxHandle++;
866   } 
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;
873                 }
874          } 
875   }
876   if (!iItem) ERR (treeview, "Argh -- can't find free item.\n");
877   
878   tvItem= & ptdi->item;
879   wineItem=& infoPtr->items[iItem];
880
881
882
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;
888   }
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;
897   }
898
899   wineItem->upsibling=0;  /* needed in case we're the first item in a list */ 
900   wineItem->sibling=0;     
901   wineItem->firstChild=0;
902
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];
913                         }
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];
927             }
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;
935         }
936    }    
937
938
939 /* Fill in info structure */
940
941    wineItem->mask=tvItem->mask;
942    wineItem->hItem=iItem;
943    wineItem->iIntegral=1; 
944
945    if (tvItem->mask & TVIF_CHILDREN)
946          wineItem->cChildren=tvItem->cChildren;
947
948    if (tvItem->mask & TVIF_IMAGE) 
949         wineItem->iImage=tvItem->iImage;
950
951 /*   if (tvItem->mask & TVIF_INTEGRAL) 
952         wineItem->iIntegral=tvItem->iIntegral;  */
953    
954
955    if (tvItem->mask & TVIF_PARAM) 
956         wineItem->lParam=tvItem->lParam;
957
958    if (tvItem->mask & TVIF_SELECTEDIMAGE) 
959         wineItem->iSelectedImage=tvItem->iSelectedImage;
960
961    if (tvItem->mask & TVIF_STATE) {
962         wineItem->state=tvItem->state;
963         wineItem->stateMask=tvItem->stateMask;
964    }
965
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;
974         }
975    }
976
977    TREEVIEW_QueueRefresh (wndPtr);
978
979    return (LRESULT) iItem;
980 }
981
982
983
984 static LRESULT
985 TREEVIEW_DeleteItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
986 {
987   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
988   INT32 iItem;
989   POINT32 pt;
990   TREEVIEW_ITEM *wineItem;
991
992   TRACE (treeview,"\n");
993   if (!infoPtr) return FALSE;
994
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);
1003   }
1004
1005   TREEVIEW_QueueRefresh (wndPtr);
1006
1007   return TRUE;
1008 }
1009
1010
1011 static LRESULT
1012 TREEVIEW_GetIndent (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1013 {
1014  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1015
1016  return infoPtr->uIndent;
1017 }
1018
1019 static LRESULT
1020 TREEVIEW_SetIndent (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1021 {
1022   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1023   INT32 newIndent;
1024    
1025   newIndent=(INT32) wParam;
1026   if (newIndent < MINIMUM_INDENT) newIndent=MINIMUM_INDENT;
1027   infoPtr->uIndent=newIndent;
1028   
1029   return 0;
1030 }
1031
1032
1033
1034
1035
1036 static LRESULT
1037 TREEVIEW_Create (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1038 {
1039     TREEVIEW_INFO *infoPtr;
1040         HDC32 hdc;
1041     TEXTMETRIC32A tm;
1042   
1043     TRACE (treeview,"\n");
1044       /* allocate memory for info structure */
1045       infoPtr = (TREEVIEW_INFO *)HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
1046                                      sizeof(TREEVIEW_INFO));
1047
1048     wndPtr->wExtra[0] = (DWORD)infoPtr;
1049
1050     if (infoPtr == NULL) {
1051                 ERR (treeview, "could not allocate info memory!\n");
1052                 return 0;
1053     }
1054
1055     if ((TREEVIEW_INFO*)wndPtr->wExtra[0] != infoPtr) {
1056                 ERR (treeview, "pointer assignment error!\n");
1057                 return 0;
1058     }
1059
1060         hdc=GetDC32 (wndPtr->hwndSelf);
1061
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;
1075
1076     infoPtr->items = NULL;
1077     infoPtr->selectedItem=0;
1078     infoPtr->clrText=-1;        /* use system color */
1079     infoPtr->dropItem=0;
1080
1081 /*
1082     infoPtr->hwndNotify = GetParent32 (wndPtr->hwndSelf);
1083     infoPtr->bTransparent = (wndPtr->dwStyle & TBSTYLE_FLAT);
1084 */
1085
1086     if (wndPtr->dwStyle & TBSTYLE_TOOLTIPS) {
1087         /* Create tooltip control */
1088 //      infoPtr->hwndToolTip = CreateWindowEx32A (....);
1089
1090         /* Send TV_TOOLTIPSCREATED notification */
1091
1092     }
1093     ReleaseDC32 (wndPtr->hwndSelf, hdc);
1094
1095     return 0;
1096 }
1097
1098
1099
1100 static LRESULT 
1101 TREEVIEW_Destroy (WND *wndPtr) 
1102 {
1103    TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1104      
1105    TREEVIEW_RemoveTree (infoPtr);
1106    if (infoPtr->Timer & TV_REFRESH_TIMER_SET) 
1107         KillTimer32 (wndPtr->hwndSelf, TV_REFRESH_TIMER);
1108
1109    HeapFree (GetProcessHeap (), 0, infoPtr);
1110
1111    return 0;
1112 }
1113
1114
1115 static LRESULT
1116 TREEVIEW_Paint (WND *wndPtr, WPARAM32 wParam)
1117 {
1118     HDC32 hdc;
1119     PAINTSTRUCT32 ps;
1120
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;
1126 }
1127
1128
1129
1130 static LRESULT
1131 TREEVIEW_EraseBackground (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1132 {
1133     TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1134     HBRUSH32 hBrush = CreateSolidBrush32 (infoPtr->clrBk);
1135     RECT32 rect;
1136
1137     TRACE (treeview,"\n");
1138     GetClientRect32 (wndPtr->hwndSelf, &rect);
1139     FillRect32 ((HDC32)wParam, &rect, hBrush);
1140     DeleteObject32 (hBrush);
1141     return TRUE;
1142 }
1143
1144
1145
1146
1147
1148   
1149
1150
1151
1152 static BOOL32
1153 TREEVIEW_SendSimpleNotify (WND *wndPtr, UINT32 code)
1154 {
1155     NMHDR nmhdr;
1156
1157     TRACE (treeview, "%x\n",code);
1158     nmhdr.hwndFrom = wndPtr->hwndSelf;
1159     nmhdr.idFrom   = wndPtr->wIDmenu;
1160     nmhdr.code     = code;
1161
1162     return (BOOL32) SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
1163                                    (WPARAM32)nmhdr.idFrom, (LPARAM)&nmhdr);
1164 }
1165
1166
1167
1168
1169 static BOOL32
1170 TREEVIEW_SendTreeviewNotify (WND *wndPtr, UINT32 code, UINT32 action, 
1171                         INT32 oldItem, INT32 newItem, POINT32 pt)
1172 {
1173   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1174   NMTREEVIEW nmhdr;
1175   TREEVIEW_ITEM  *wineItem;
1176
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;
1196   }
1197
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;
1211   }
1212
1213   nmhdr.ptDrag.x = pt.x;
1214   nmhdr.ptDrag.y = pt.y;
1215
1216   return (BOOL32)SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
1217                                    (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmhdr);
1218
1219 }
1220
1221
1222
1223
1224 static LRESULT
1225 TREEVIEW_Expand (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1226 {
1227  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1228  TREEVIEW_ITEM *wineItem;
1229  UINT32 flag;
1230  INT32 expandItem;
1231  POINT32 pt;
1232  
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;
1239
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;
1246  }
1247
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;
1254
1255     case TVE_COLLAPSE: 
1256                 if (!wineItem->state & TVIS_EXPANDED) return 0;
1257                 wineItem->state &= ~TVIS_EXPANDED;
1258                 break;
1259
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);
1269         }
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;
1277   }
1278  
1279  TREEVIEW_QueueRefresh (wndPtr);
1280
1281  return TRUE;
1282 }
1283
1284
1285
1286 static HTREEITEM
1287 TREEVIEW_HitTest (WND *wndPtr, LPTVHITTESTINFO lpht)
1288 {
1289  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1290  TREEVIEW_ITEM *wineItem;
1291  RECT32 rect;
1292  UINT32 status,x,y;
1293  
1294
1295
1296  GetClientRect32 (wndPtr->hwndSelf, &rect);
1297  TRACE (treeview,"(%d,%d)\n",lpht->pt.x, lpht->pt.y);
1298
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;
1309  }
1310
1311  if (!infoPtr->firstVisible) WARN (treeview,"Can't fetch first visible item");
1312  wineItem=&infoPtr->items [infoPtr->firstVisible];
1313
1314  while ((wineItem!=NULL) && (y > wineItem->rect.bottom))
1315        wineItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
1316         
1317  if (wineItem==NULL) {
1318         lpht->flags=TVHT_NOWHERE;
1319         return 0;
1320  }
1321
1322  if (x>wineItem->rect.right) {
1323         lpht->flags|=TVHT_ONITEMRIGHT;
1324         return wineItem->hItem;
1325  }
1326  
1327         
1328  if (x<wineItem->rect.left+10) lpht->flags|=TVHT_ONITEMBUTTON;
1329
1330  lpht->flags=TVHT_ONITEMLABEL;    /* FIXME: implement other flags */
1331         
1332
1333  lpht->hItem=wineItem->hItem;
1334  return wineItem->hItem;
1335 }
1336
1337
1338 static LRESULT
1339 TREEVIEW_HitTest32 (WND *wndPtr, LPARAM lParam)
1340 {
1341  
1342   return (LRESULT) TREEVIEW_HitTest (wndPtr, (LPTVHITTESTINFO) lParam);
1343 }
1344
1345
1346
1347
1348 LRESULT
1349 TREEVIEW_LButtonDoubleClick (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1350 {
1351   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1352   TREEVIEW_ITEM *wineItem;
1353   INT32 iItem;
1354   TVHITTESTINFO ht;
1355
1356   TRACE (treeview,"\n");
1357   ht.pt.x = (INT32)LOWORD(lParam);
1358   ht.pt.y = (INT32)HIWORD(lParam);
1359   SetFocus32 (wndPtr->hwndSelf);
1360
1361   iItem=TREEVIEW_HitTest (wndPtr, &ht);
1362   TRACE (treeview,"item %d \n",iItem);
1363   wineItem=TREEVIEW_ValidItem (infoPtr, iItem);
1364   if (!wineItem) return 0;
1365  
1366   if (TREEVIEW_SendSimpleNotify (wndPtr, NM_DBLCLK)!=TRUE) {     /* FIXME!*/
1367         wineItem->state &= ~TVIS_EXPANDEDONCE;
1368         TREEVIEW_Expand (wndPtr, (WPARAM32) TVE_TOGGLE, (LPARAM) iItem);
1369  }
1370  return TRUE;
1371 }
1372
1373
1374
1375 static LRESULT
1376 TREEVIEW_LButtonDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1377 {
1378   INT32 iItem;
1379   TVHITTESTINFO ht;
1380
1381   TRACE (treeview,"\n");
1382   ht.pt.x = (INT32)LOWORD(lParam);
1383   ht.pt.y = (INT32)HIWORD(lParam);
1384
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);
1390   }
1391         
1392   if (TREEVIEW_SelectItem (wndPtr, (WPARAM32) TVGN_CARET, (LPARAM) iItem))
1393          return 0;
1394
1395   
1396  return 0;
1397 }
1398
1399
1400 static LRESULT
1401 TREEVIEW_RButtonDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1402 {
1403
1404  return 0;
1405 }
1406
1407
1408
1409
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.
1412 */
1413
1414 static LRESULT
1415 TREEVIEW_SelectItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1416 {
1417  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1418  TREEVIEW_ITEM *prevItem,*wineItem;
1419  INT32 action,prevSelect, newSelect;
1420  POINT32 dummy;
1421
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;
1430
1431   action= (INT32) wParam;
1432
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? */
1438                 
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;
1451  }
1452  
1453  TREEVIEW_QueueRefresh (wndPtr);
1454   
1455  return TRUE;
1456 }
1457
1458
1459
1460 /* FIXME: does KEYDOWN also send notifications?? If so, use 
1461    TREEVIEW_SelectItem.
1462 */
1463    
1464
1465 static LRESULT
1466 TREEVIEW_KeyDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1467 {
1468  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1469  TREEVIEW_ITEM *prevItem,*newItem;
1470  int prevSelect;
1471
1472
1473  TRACE (treeview,"%x %lx",wParam, lParam);
1474  prevSelect=infoPtr->selectedItem;
1475  if (!prevSelect) return FALSE;
1476
1477  prevItem= TREEVIEW_ValidItem (infoPtr, prevSelect);
1478  
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;
1502  }
1503
1504  if (!newItem) return FALSE;
1505
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;
1512  }
1513
1514  return FALSE;
1515 }
1516
1517
1518
1519 static LRESULT
1520 TREEVIEW_VScroll (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1521
1522 {
1523   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1524   int maxHeight;
1525
1526   TRACE (treeview,"wp %x, lp %lx\n", wParam, lParam);
1527   if (!infoPtr->uInternalStatus & TV_VSCROLL) return FALSE;
1528
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;
1557                         
1558   }
1559   
1560   TREEVIEW_QueueRefresh (wndPtr);
1561   return TRUE;
1562 }
1563
1564 static LRESULT
1565 TREEVIEW_HScroll (WND *wndPtr, WPARAM32 wParam, LPARAM lParam) 
1566 {
1567   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1568
1569   TRACE (treeview,"wp %lx, lp %x\n", lParam, wParam);
1570         
1571   if (!infoPtr->uInternalStatus & TV_HSCROLL) return FALSE;
1572   return TRUE;
1573 }
1574
1575
1576
1577
1578   LRESULT WINAPI
1579   TREEVIEW_WindowProc (HWND32 hwnd, UINT32 uMsg, WPARAM32 wParam, LPARAM lParam)
1580   {
1581       WND *wndPtr = WIN_FindWndPtr(hwnd);
1582   
1583   
1584     switch (uMsg) {
1585         case TVM_INSERTITEM32A:
1586           return TREEVIEW_InsertItem32A (wndPtr, wParam, lParam);
1587
1588         case TVM_INSERTITEM32W:
1589                 FIXME (treeview, "Unimplemented msg TVM_INSERTITEM32W\n");
1590                 return 0;
1591
1592         case TVM_DELETEITEM:
1593                 return TREEVIEW_DeleteItem (wndPtr, wParam, lParam);
1594
1595         case TVM_EXPAND:
1596                 return TREEVIEW_Expand (wndPtr, wParam, lParam);
1597
1598         case TVM_GETITEMRECT:
1599                 return TREEVIEW_GetItemRect (wndPtr, wParam, lParam);
1600
1601         case TVM_GETCOUNT:
1602                 return TREEVIEW_GetCount (wndPtr, wParam, lParam);
1603
1604         case TVM_GETINDENT:
1605                 return TREEVIEW_GetIndent (wndPtr, wParam, lParam);
1606
1607         case TVM_SETINDENT:
1608                 return TREEVIEW_SetIndent (wndPtr, wParam, lParam);
1609
1610         case TVM_GETIMAGELIST:
1611                 return TREEVIEW_GetImageList (wndPtr, wParam, lParam);
1612
1613                 case TVM_SETIMAGELIST:
1614                 return TREEVIEW_SetImageList (wndPtr, wParam, lParam);
1615
1616         case TVM_GETNEXTITEM:
1617                 return TREEVIEW_GetNextItem32 (wndPtr, wParam, lParam);
1618
1619         case TVM_SELECTITEM:
1620                 return TREEVIEW_SelectItem (wndPtr, wParam, lParam);
1621
1622         case TVM_GETITEM32A:
1623                 return TREEVIEW_GetItem (wndPtr, wParam, lParam);
1624
1625         case TVM_GETITEM32W:
1626                 FIXME (treeview, "Unimplemented msg TVM_GETITEM32W\n");
1627                 return 0;
1628
1629         case TVM_SETITEM32A:
1630                 return TREEVIEW_SetItem (wndPtr, wParam, lParam);
1631
1632         case TVM_SETITEM32W:
1633                 FIXME (treeview, "Unimplemented msg TVM_SETITEMW\n");
1634                 return 0;
1635
1636         case TVM_EDITLABEL32A:
1637                 FIXME (treeview, "Unimplemented msg TVM_EDITLABEL32A \n");
1638                 return 0;
1639
1640         case TVM_EDITLABEL32W:
1641                 FIXME (treeview, "Unimplemented msg TVM_EDITLABEL32W \n");
1642                 return 0;
1643
1644         case TVM_GETEDITCONTROL:
1645                 FIXME (treeview, "Unimplemented msg TVM_GETEDITCONTROL\n");
1646                 return 0;
1647
1648         case TVM_GETVISIBLECOUNT:
1649                 return TREEVIEW_GetVisibleCount (wndPtr, wParam, lParam);
1650
1651         case TVM_HITTEST:
1652                 return TREEVIEW_HitTest32 (wndPtr, lParam);
1653
1654         case TVM_CREATEDRAGIMAGE:
1655                 FIXME (treeview, "Unimplemented msg TVM_CREATEDRAGIMAGE\n");
1656                 return 0;
1657   
1658         case TVM_SORTCHILDREN:
1659                 FIXME (treeview, "Unimplemented msg TVM_SORTCHILDREN\n");
1660                 return 0;
1661   
1662         case TVM_ENSUREVISIBLE:
1663                 FIXME (treeview, "Unimplemented msg TVM_ENSUREVISIBLE\n");
1664                 return 0;
1665   
1666         case TVM_SORTCHILDRENCB:
1667                 FIXME (treeview, "Unimplemented msg TVM_SORTCHILDRENCB\n");
1668                 return 0;
1669   
1670         case TVM_ENDEDITLABELNOW:
1671                 FIXME (treeview, "Unimplemented msg TVM_ENDEDITLABELNOW\n");
1672                 return 0;
1673   
1674         case TVM_GETISEARCHSTRING32A:
1675                 FIXME (treeview, "Unimplemented msg TVM_GETISEARCHSTRING32A\n");
1676                 return 0;
1677   
1678         case TVM_GETISEARCHSTRING32W:
1679                 FIXME (treeview, "Unimplemented msg TVM_GETISEARCHSTRING32W\n");
1680                 return 0;
1681   
1682         case TVM_SETTOOLTIPS:
1683                 FIXME (treeview, "Unimplemented msg TVM_SETTOOLTIPS\n");
1684                 return 0;
1685   
1686         case TVM_GETTOOLTIPS:
1687                 FIXME (treeview, "Unimplemented msg TVM_GETTOOLTIPS\n");
1688                 return 0;
1689   
1690         case TVM_SETINSERTMARK:
1691                 FIXME (treeview, "Unimplemented msg TVM_SETINSERTMARK\n");
1692                 return 0;
1693   
1694         case TVM_SETITEMHEIGHT:
1695                 return TREEVIEW_SetItemHeight (wndPtr, wParam);
1696   
1697         case TVM_GETITEMHEIGHT:
1698                 return TREEVIEW_GetItemHeight (wndPtr);
1699   
1700         case TVM_SETBKCOLOR:
1701                 FIXME (treeview, "Unimplemented msg TVM_SETBKCOLOR\n");
1702                 return 0;
1703         
1704         case TVM_SETTEXTCOLOR:
1705                 return TREEVIEW_SetTextColor (wndPtr, wParam, lParam);
1706   
1707         case TVM_GETBKCOLOR:
1708                 FIXME (treeview, "Unimplemented msg TVM_GETBKCOLOR\n");
1709                 return 0;
1710   
1711         case TVM_GETTEXTCOLOR:
1712                 return TREEVIEW_GetTextColor (wndPtr);
1713   
1714         case TVM_SETSCROLLTIME:
1715                 FIXME (treeview, "Unimplemented msg TVM_SETSCROLLTIME\n");
1716                 return 0;
1717   
1718         case TVM_GETSCROLLTIME:
1719                 FIXME (treeview, "Unimplemented msg TVM_GETSCROLLTIME\n");
1720                 return 0;
1721   
1722         case TVM_SETINSERTMARKCOLOR:
1723                 FIXME (treeview, "Unimplemented msg TVM_SETINSERTMARKCOLOR\n");
1724                 return 0;
1725   
1726         case TVM_SETUNICODEFORMAT:
1727                 FIXME (treeview, "Unimplemented msg TVM_SETUNICODEFORMAT\n");
1728                 return 0;
1729   
1730         case TVM_GETUNICODEFORMAT:
1731                 FIXME (treeview, "Unimplemented msg TVM_GETUNICODEFORMAT\n");
1732                 return 0;
1733   
1734 //              case WM_COMMAND:
1735   
1736                 case WM_CREATE:
1737                         return TREEVIEW_Create (wndPtr, wParam, lParam);
1738   
1739                 case WM_DESTROY:
1740                         return TREEVIEW_Destroy (wndPtr);
1741   
1742 //              case WM_ENABLE:
1743   
1744                 case WM_ERASEBKGND:
1745                 return TREEVIEW_EraseBackground (wndPtr, wParam, lParam);
1746   
1747                 case WM_GETDLGCODE:
1748                 return DLGC_WANTARROWS | DLGC_WANTCHARS;
1749   
1750                 case WM_PAINT:
1751                 return TREEVIEW_Paint (wndPtr, wParam);
1752   
1753 //              case WM_GETFONT:
1754 //              case WM_SETFONT:
1755   
1756                 case WM_KEYDOWN:
1757                         return TREEVIEW_KeyDown (wndPtr, wParam, lParam);
1758   
1759   
1760 //              case WM_KILLFOCUS:
1761 //              case WM_SETFOCUS:
1762   
1763   
1764                 case WM_LBUTTONDOWN:
1765                         return TREEVIEW_LButtonDown (wndPtr, wParam, lParam);
1766   
1767                 case WM_LBUTTONDBLCLK:
1768                         return TREEVIEW_LButtonDoubleClick (wndPtr, wParam, lParam);
1769   
1770                 case WM_RBUTTONDOWN:
1771                         return TREEVIEW_RButtonDown (wndPtr, wParam, lParam);
1772   
1773   
1774 //              case WM_SYSCOLORCHANGE:
1775 //              case WM_STYLECHANGED:
1776 //              case WM_SETREDRAW:
1777   
1778                 case WM_TIMER:
1779                         return TREEVIEW_HandleTimer (wndPtr, wParam, lParam);
1780   
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);
1786   
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);
1792       }
1793     return 0;
1794 }
1795
1796
1797 void
1798 TREEVIEW_Register (void)
1799 {
1800     WNDCLASS32A wndClass;
1801
1802     TRACE (treeview,"\n");
1803
1804     if (GlobalFindAtom32A (WC_TREEVIEW32A)) return;
1805
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;
1814  
1815     RegisterClass32A (&wndClass);
1816 }
1817