Release 980927
[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 #include <asm/bitops.h>      /* FIXME: linux specific */
35
36 static int TREEVIEW_Timer;
37
38
39
40 #define TREEVIEW_GetInfoPtr(wndPtr) ((TREEVIEW_INFO *)wndPtr->wExtra[0])
41
42
43
44 #include <asm/bitops.h>      /* FIXME: linux specific */
45
46 static int TREEVIEW_Timer;
47
48   
49   #define TREEVIEW_GetInfoPtr(wndPtr) ((TREEVIEW_INFO *)wndPtr->wExtra[0])
50   
51   
52   
53
54 static BOOL32
55 TREEVIEW_SendSimpleNotify (WND *wndPtr, UINT32 code);
56 static BOOL32
57 TREEVIEW_SendTreeviewNotify (WND *wndPtr, UINT32 code, UINT32 action, 
58                         INT32 oldItem, INT32 newItem, POINT32 pt);
59 static LRESULT
60 TREEVIEW_SelectItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
61 static void
62 TREEVIEW_Refresh (WND *wndPtr, HDC32 hdc);
63
64
65
66
67
68 /* helper functions. Work with the assumption that validity of operands 
69    is checked beforehand */
70
71
72 static TREEVIEW_ITEM *
73 TREEVIEW_ValidItem (TREEVIEW_INFO *infoPtr,int  handle)
74 {
75  
76  if ((!handle) || (handle>infoPtr->uMaxHandle)) return NULL;
77  if (test_bit (handle, infoPtr->freeList)) return NULL;
78
79  return & infoPtr->items[handle];
80 }
81
82
83
84 static TREEVIEW_ITEM *TREEVIEW_GetPrevListItem (TREEVIEW_INFO *infoPtr, 
85                                         TREEVIEW_ITEM *tvItem)
86
87 {
88  TREEVIEW_ITEM *wineItem;
89
90  if (tvItem->upsibling) 
91                 return (& infoPtr->items[tvItem->upsibling]);
92
93  wineItem=tvItem;
94  while (wineItem->parent) {
95         wineItem=& infoPtr->items[wineItem->parent];
96         if (wineItem->upsibling) 
97                 return (& infoPtr->items[wineItem->upsibling]);
98  } 
99
100  return NULL;
101 }
102
103 static TREEVIEW_ITEM *TREEVIEW_GetNextListItem (TREEVIEW_INFO *infoPtr, 
104                                         TREEVIEW_ITEM *tvItem)
105
106 {
107  TREEVIEW_ITEM *wineItem;
108
109  if (tvItem->sibling) 
110                 return (& infoPtr->items[tvItem->sibling]);
111
112  wineItem=tvItem;
113  while (wineItem->parent) {
114         wineItem=& infoPtr->items [wineItem->parent];
115         if (wineItem->sibling) 
116                 return (& infoPtr->items [wineItem->sibling]);
117  } 
118
119  return NULL;
120 }
121
122 static TREEVIEW_ITEM *TREEVIEW_GetLastListItem (TREEVIEW_INFO *infoPtr)
123
124 {
125   TREEVIEW_ITEM *wineItem;
126   
127  wineItem=NULL;
128  if (infoPtr->TopRootItem) 
129         wineItem=& infoPtr->items [infoPtr->TopRootItem];
130  while (wineItem->sibling) 
131         wineItem=& infoPtr->items [wineItem->sibling];
132
133  return wineItem;
134 }
135         
136  
137
138
139 static void
140 TREEVIEW_RemoveItem (TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem)
141
142 {
143  TREEVIEW_ITEM *parentItem, *upsiblingItem, *siblingItem;
144  INT32 iItem;
145
146  iItem=wineItem->hItem;
147  set_bit ( iItem & 31, &infoPtr->freeList[iItem >>5]);
148  infoPtr->uNumItems--;
149  parentItem=NULL;
150  if (wineItem->pszText!=LPSTR_TEXTCALLBACK32A) 
151         HeapFree (GetProcessHeap (), 0, wineItem->pszText);
152
153  if (wineItem->parent) {
154         parentItem=& infoPtr->items[ wineItem->parent];
155         if (parentItem->cChildren==1) {
156                 parentItem->cChildren=0;
157                 parentItem->firstChild=0;    
158                 return;
159         } else {
160                 parentItem->cChildren--;
161                 if (parentItem->firstChild==iItem) 
162                         parentItem->firstChild=wineItem->sibling;
163                 }
164  }
165
166  if (iItem==infoPtr->TopRootItem) 
167         infoPtr->TopRootItem=wineItem->sibling;
168  if (wineItem->upsibling) {
169         upsiblingItem=& infoPtr->items [wineItem->upsibling];
170         upsiblingItem->sibling=wineItem->sibling;
171  }
172  if (wineItem->sibling) {
173         siblingItem=& infoPtr->items [wineItem->sibling];
174         siblingItem->upsibling=wineItem->upsibling;
175  }
176 }
177
178
179
180 static void TREEVIEW_RemoveAllChildren (TREEVIEW_INFO *infoPtr, 
181                                            TREEVIEW_ITEM *parentItem)
182
183 {
184  TREEVIEW_ITEM *killItem;
185  INT32  kill;
186  
187  kill=parentItem->firstChild;
188  while (kill) {
189         set_bit ( kill & 31, &infoPtr->freeList[kill >>5]);
190         killItem=& infoPtr->items[kill];
191         if (killItem->pszText!=LPSTR_TEXTCALLBACK32A) 
192                 HeapFree (GetProcessHeap (), 0, killItem->pszText);
193         kill=killItem->sibling;
194  }
195  infoPtr->uNumItems -= parentItem->cChildren;
196  parentItem->firstChild = 0;
197  parentItem->cChildren = 0;
198 }
199
200
201
202 static void TREEVIEW_RemoveTree (TREEVIEW_INFO *infoPtr)
203                                            
204
205 {
206  TREEVIEW_ITEM *killItem;
207  int i;
208
209         /* bummer: if we didn't delete anything, test_bit is overhead */
210  
211     for (i=1; i<=infoPtr->uMaxHandle; i++) 
212         if (!test_bit (i, infoPtr->freeList)) {
213                 killItem=& infoPtr->items [i];  
214                 if (killItem->pszText!=LPSTR_TEXTCALLBACK32A)
215                         HeapFree (GetProcessHeap (), 0, killItem->pszText);
216         } 
217
218     if (infoPtr->uNumPtrsAlloced) {
219         HeapFree (GetProcessHeap (), 0, infoPtr->items);
220         HeapFree (GetProcessHeap (), 0, infoPtr->freeList);
221         infoPtr->uNumItems=0;
222         infoPtr->uNumPtrsAlloced=0;
223         infoPtr->uMaxHandle=0;
224     }   
225
226         /* this function doesn't remove infoPtr itself */
227 }
228
229
230
231
232
233
234
235
236
237
238 static LRESULT
239 TREEVIEW_GetImageList (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
240 {
241   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
242
243   TRACE (treeview,"\n");
244
245   if (infoPtr==NULL) return 0;
246
247   if ((INT32)wParam == TVSIL_NORMAL) 
248         return (LRESULT) infoPtr->himlNormal;
249   if ((INT32)wParam == TVSIL_STATE) 
250         return (LRESULT) infoPtr->himlState;
251
252   return 0;
253 }
254
255
256
257
258 static LRESULT
259 TREEVIEW_SetImageList (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
260 {
261     TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
262     HIMAGELIST himlTemp;
263
264     switch ((INT32)wParam) {
265         case TVSIL_NORMAL:
266             himlTemp = infoPtr->himlNormal;
267             infoPtr->himlNormal = (HIMAGELIST)lParam;
268             return (LRESULT)himlTemp;
269
270         case TVSIL_STATE:
271             himlTemp = infoPtr->himlState;
272             infoPtr->himlState = (HIMAGELIST)lParam;
273             return (LRESULT)himlTemp;
274     }
275
276     return (LRESULT)NULL;
277 }
278
279
280
281 static LRESULT
282 TREEVIEW_SetItemHeight (WND *wndPtr, WPARAM32 wParam)
283 {
284   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
285   INT32 prevHeight=infoPtr->uItemHeight;
286   HDC32 hdc;
287   TEXTMETRIC32A tm;
288
289
290   if (wParam==-1) {
291         hdc=GetDC32 (wndPtr->hwndSelf);
292         infoPtr->uItemHeight=-1;
293         GetTextMetrics32A (hdc, &tm);
294     infoPtr->uRealItemHeight= tm.tmHeight + tm.tmExternalLeading;
295         ReleaseDC32 (wndPtr->hwndSelf, hdc);
296         return prevHeight;
297   }
298
299         /* FIXME: check wParam > imagelist height */
300
301   if (!(wndPtr->dwStyle & TVS_NONEVENHEIGHT))
302         infoPtr->uItemHeight = (INT32) wParam & 0xfffffffe;
303   return prevHeight;
304 }
305
306 static LRESULT
307 TREEVIEW_GetItemHeight (WND *wndPtr)
308 {
309   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
310   
311   return infoPtr->uItemHeight;
312 }
313   
314 static LRESULT
315 TREEVIEW_SetTextColor (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
316 {
317   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
318   COLORREF prevColor=infoPtr->clrText;
319
320   infoPtr->clrText=(COLORREF) lParam;
321   return (LRESULT) prevColor;
322 }
323
324 static LRESULT
325 TREEVIEW_GetTextColor (WND *wndPtr)
326 {
327   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
328         
329   return (LRESULT) infoPtr->clrText;
330 }
331
332
333 static INT32
334 TREEVIEW_DrawItem (WND *wndPtr, HDC32 hdc, TREEVIEW_ITEM *wineItem, 
335                    TREEVIEW_ITEM *upperItem, int indent)
336 {
337   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
338   INT32  oldBkMode,center,xpos;
339   COLORREF oldBkColor;
340   UINT32 uTextJustify = DT_LEFT;
341   HPEN32 hOldPen, hnewPen,hRootPen;
342   RECT32 r,upper;
343   
344   hnewPen = CreatePen32(PS_DOT, 0, GetSysColor32(COLOR_WINDOWTEXT) );
345   hOldPen = SelectObject32( hdc, hnewPen );
346  
347   r=wineItem->rect;
348   if (upperItem) 
349         upper=upperItem->rect;
350   else {
351         upper.top=0;
352         upper.left=8;
353   }
354   center=(r.top+r.bottom)/2;
355   xpos=r.left+8;
356
357   if (wndPtr->dwStyle & TVS_HASLINES) {
358         POINT32 points[3];
359         if ((wndPtr->dwStyle & TVS_LINESATROOT) && (indent==0)) {
360                 points[0].y=points[1].y=center;
361                 points[2].y=upper.top;
362                 points[1].x=points[2].x=upper.left;
363                 points[0].x=upper.left+12;
364                 points[2].y+=5;
365
366                 Polyline32 (hdc,points,3);
367         }
368         else {
369                 points[0].y=points[1].y=center;
370                 points[2].y=upper.top;
371                 points[1].x=points[2].x=upper.left+13;
372                 points[0].x=upper.left+25;
373                 points[2].y+=5;
374                 Polyline32 (hdc,points,3);
375         }
376  }
377
378   DeleteObject32(hnewPen);
379   SelectObject32(hdc, hOldPen);
380
381   if ((wndPtr->dwStyle & TVS_HASBUTTONS) && (wineItem->cChildren)) {
382 /*
383         hRootPen = CreatePen32(PS_SOLID, 0, GetSysColor32(COLOR_WINDOW) );
384         SelectObject32( hdc, hRootPen );
385 */
386
387         Rectangle32 (hdc, xpos-4, center-4, xpos+5, center+5);
388         MoveToEx32 (hdc, xpos-2, center, NULL);
389         LineTo32   (hdc, xpos+3, center);
390         if (!(wineItem->state & TVIS_EXPANDED)) {
391                 MoveToEx32 (hdc, xpos,   center-2, NULL);
392                 LineTo32   (hdc, xpos,   center+3);
393         }
394  /*     DeleteObject32(hRootPen); */
395         }
396
397
398   xpos+=13;
399
400   if (wineItem->mask & TVIF_IMAGE) {
401         if (wineItem->iImage!=I_IMAGECALLBACK) {
402                 if (infoPtr->himlNormal) {
403                         ImageList_Draw (infoPtr->himlNormal,wineItem->iImage, hdc,
404                                         xpos-2, r.top+1, ILD_NORMAL);
405                         xpos+=15;
406                 }
407         }
408   }
409
410   r.left=xpos;
411   if ((wineItem->mask & TVIF_TEXT) && (wineItem->pszText)) {
412             if (wineItem->state & TVIS_SELECTED) {
413                 oldBkMode = SetBkMode32(hdc, OPAQUE);
414                 oldBkColor= SetBkColor32 (hdc, GetSysColor32( COLOR_HIGHLIGHT));
415                 SetTextColor32 (hdc, GetSysColor32(COLOR_HIGHLIGHTTEXT));
416             }
417             else {
418                 oldBkMode = SetBkMode32(hdc, TRANSPARENT);
419             }
420             r.left += 3;
421             r.right -= 3;
422                         if (infoPtr->clrText==-1)
423                 SetTextColor32 (hdc, COLOR_BTNTEXT);
424                         else 
425                                 SetTextColor32 (hdc, infoPtr->clrText);  /* FIXME: retval */
426             DrawText32A(hdc, wineItem->pszText, lstrlen32A(wineItem->pszText),
427                   &r, uTextJustify|DT_VCENTER|DT_SINGLELINE);
428             if (oldBkMode != TRANSPARENT)
429                 SetBkMode32(hdc, oldBkMode);
430             if (wineItem->state & TVIS_SELECTED)
431                 SetBkColor32 (hdc, oldBkColor);
432         }
433
434  return wineItem->rect.right;
435 }
436
437
438
439
440
441
442
443 static LRESULT
444 TREEVIEW_GetItemRect (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
445 {
446   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
447   TREEVIEW_ITEM *wineItem;
448   INT32 iItem;
449   LPRECT32 lpRect;
450
451   TRACE (treeview,"\n");
452   if (infoPtr==NULL) return FALSE;
453   
454   iItem = (INT32)lParam;
455   wineItem = TREEVIEW_ValidItem (infoPtr, iItem);
456   if (!wineItem) return FALSE;
457
458   wineItem=& infoPtr->items[ iItem ];
459   if (!wineItem->visible) return FALSE;
460
461   lpRect = (LPRECT32)lParam;
462   if (lpRect == NULL) return FALSE;
463         
464   if ((INT32) wParam) {
465         lpRect->left    = wineItem->text.left;
466         lpRect->right   = wineItem->text.right;
467         lpRect->bottom  = wineItem->text.bottom;
468         lpRect->top     = wineItem->text.top;
469   } else {
470         lpRect->left    = wineItem->rect.left;
471         lpRect->right   = wineItem->rect.right;
472         lpRect->bottom  = wineItem->rect.bottom;
473         lpRect->top     = wineItem->rect.top;
474   }
475
476   return TRUE;
477 }
478
479
480
481 static LRESULT
482 TREEVIEW_GetVisibleCount (WND *wndPtr,  WPARAM32 wParam, LPARAM lParam)
483
484 {
485   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
486
487   TRACE (treeview,"\n");
488
489   return (LRESULT) infoPtr->uVisibleHeight / infoPtr->uRealItemHeight;
490 }
491
492
493
494 static LRESULT
495 TREEVIEW_SetItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
496 {
497   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
498   TREEVIEW_ITEM *wineItem;
499   TV_ITEM *tvItem;
500   INT32 iItem,len;
501
502   TRACE (treeview,"\n");
503   tvItem=(LPTVITEM) lParam;
504   iItem=tvItem->hItem;
505
506   wineItem = TREEVIEW_ValidItem (infoPtr, iItem);
507   if (!wineItem) return FALSE;
508
509   if (tvItem->mask & TVIF_CHILDREN) {
510         wineItem->cChildren=tvItem->cChildren;
511   }
512
513   if (tvItem->mask & TVIF_IMAGE) {
514        wineItem->iImage=tvItem->iImage;
515   }
516
517   if (tvItem->mask & TVIF_INTEGRAL) {
518 /*        wineItem->iIntegral=tvItem->iIntegral; */
519   }
520
521   if (tvItem->mask & TVIF_PARAM) {
522         wineItem->lParam=tvItem->lParam;
523   }
524
525   if (tvItem->mask & TVIF_SELECTEDIMAGE) {
526         wineItem->iSelectedImage=tvItem->iSelectedImage;
527   }
528
529   if (tvItem->mask & TVIF_STATE) {
530         wineItem->state=tvItem->state & tvItem->stateMask;
531   }
532
533   if (tvItem->mask & TVIF_TEXT) {
534         len=tvItem->cchTextMax;
535         if (len>wineItem->cchTextMax) {
536                 HeapFree (GetProcessHeap (), 0, wineItem->pszText);
537                 wineItem->pszText= HeapAlloc (GetProcessHeap (), 
538                                 HEAP_ZERO_MEMORY, len+1);
539         }
540         lstrcpyn32A (wineItem->pszText, tvItem->pszText,len);
541    }
542
543   return TRUE;
544 }
545
546
547
548
549
550 static void
551 TREEVIEW_Refresh (WND *wndPtr, HDC32 hdc)
552
553 {
554     TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
555     HFONT32 hFont, hOldFont;
556     RECT32 rect;
557     HBRUSH32 hbrBk;
558     INT32 iItem, indent, x, y, height;
559     INT32 viewtop,viewbottom,viewleft,viewright;
560     TREEVIEW_ITEM *wineItem, *prevItem;
561
562     TRACE (treeview,"\n");
563
564     if (TREEVIEW_Timer & TV_REFRESH_TIMER_SET) {
565                 KillTimer32 (wndPtr->hwndSelf, TV_REFRESH_TIMER);
566                 TREEVIEW_Timer &= ~TV_REFRESH_TIMER_SET;
567     }
568
569     
570     GetClientRect32 (wndPtr->hwndSelf, &rect);
571     if ((rect.left-rect.right ==0) || (rect.top-rect.bottom==0)) return;
572     viewtop=infoPtr->cy;
573     viewbottom=infoPtr->cy + rect.bottom-rect.top;
574     viewleft=infoPtr->cx;
575     viewright=infoPtr->cx + rect.right-rect.left;
576
577         infoPtr->uVisibleHeight=viewbottom - viewtop;
578
579     hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject32 (DEFAULT_GUI_FONT);
580     hOldFont = SelectObject32 (hdc, hFont);
581
582     /* draw background */
583     hbrBk = GetSysColorBrush32(COLOR_WINDOW);
584     FillRect32(hdc, &rect, hbrBk);
585
586
587     iItem=infoPtr->TopRootItem;
588     infoPtr->firstVisible=0;
589     wineItem=NULL;
590     indent=0;
591     x=y=0;
592     TRACE (treeview, "[%d %d %d %d]\n",viewtop,viewbottom,viewleft,viewright);
593
594     while (iItem) {
595                 prevItem=wineItem;
596         wineItem= & infoPtr->items[iItem];
597
598                 TRACE (treeview, "%d %d [%d %d %d %d] (%s)\n",y,x,
599                         wineItem->rect.top, wineItem->rect.bottom,
600                         wineItem->rect.left, wineItem->rect.right,
601                         wineItem->pszText);
602
603                 height=infoPtr->uRealItemHeight * wineItem->iIntegral;
604                 if ((y >= viewtop) && (y <= viewbottom) &&
605                 (x >= viewleft  ) && (x <= viewright)) {
606                         wineItem->rect.top = y - infoPtr->cy + rect.top;
607                         wineItem->rect.bottom = wineItem->rect.top + height ;
608                         wineItem->rect.left = x - infoPtr->cx + rect.left;
609                         wineItem->rect.right = rect.right;
610                         if (!infoPtr->firstVisible)
611                                 infoPtr->firstVisible=wineItem->hItem;
612                         TREEVIEW_DrawItem (wndPtr, hdc, wineItem, prevItem, indent);
613                 }
614                 else {
615                         wineItem->rect.top  = wineItem->rect.bottom = -1;
616                         wineItem->rect.left = wineItem->rect.right = -1;
617                 }
618
619                 /* look up next item */
620         
621                 if ((wineItem->firstChild) && (wineItem->state & TVIS_EXPANDED)) {
622                         iItem=wineItem->firstChild;
623                         indent++;
624                         x+=infoPtr->uIndent;
625                 }
626                 else {
627                         iItem=wineItem->sibling;
628                         while ((!iItem) && (indent>0)) {
629                                 indent--;
630                                 x-=infoPtr->uIndent;
631                                 prevItem=wineItem;
632                                 wineItem=&infoPtr->items[wineItem->parent];
633                                 iItem=wineItem->sibling;
634                         }
635                 }
636         y +=height;
637     }                           /* while */
638
639     infoPtr->uTotalHeight=y;
640     if (y >= (viewbottom-viewtop)) {
641                 if (!(infoPtr->uInternalStatus & TV_VSCROLL))
642                         ShowScrollBar32 (wndPtr->hwndSelf, SB_VERT, TRUE);
643                 infoPtr->uInternalStatus |=TV_VSCROLL;
644                 SetScrollRange32 (wndPtr->hwndSelf, SB_VERT, 0, 
645                                         y - infoPtr->uVisibleHeight, FALSE);
646                 SetScrollPos32 (wndPtr->hwndSelf, SB_VERT, infoPtr->cy, TRUE);
647         }
648     else {
649                 if (infoPtr->uInternalStatus & TV_VSCROLL) 
650                         ShowScrollBar32 (wndPtr->hwndSelf, SB_VERT, FALSE);
651                 infoPtr->uInternalStatus &= ~TV_VSCROLL;
652         }
653
654
655     SelectObject32 (hdc, hOldFont);
656 }
657
658
659 static LRESULT 
660 TREEVIEW_HandleTimer ( WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
661 {
662   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
663   HDC32 hdc;
664
665   if (!infoPtr) return FALSE;
666  
667   TRACE (treeview, "timer\n");
668
669   switch (wParam) {
670         case TV_REFRESH_TIMER:
671                 KillTimer32 (wndPtr->hwndSelf, TV_REFRESH_TIMER);
672                 TREEVIEW_Timer &= ~TV_REFRESH_TIMER_SET;
673                 hdc=GetDC32 (wndPtr->hwndSelf);
674                 TREEVIEW_Refresh (wndPtr, hdc);
675                 ReleaseDC32 (wndPtr->hwndSelf, hdc);
676                 return 0;
677         case TV_EDIT_TIMER:
678                 KillTimer32 (wndPtr->hwndSelf, TV_EDIT_TIMER);
679                 TREEVIEW_Timer &= ~TV_EDIT_TIMER_SET;
680                 return 0;
681  }
682                 
683  return 1;
684 }
685
686
687 static void
688 TREEVIEW_QueueRefresh (WND *wndPtr)
689
690 {
691  
692  TRACE (treeview,"queued\n");
693  if (TREEVIEW_Timer & TV_REFRESH_TIMER_SET) {
694         KillTimer32 (wndPtr->hwndSelf, TV_REFRESH_TIMER);
695  }
696
697  SetTimer32 (wndPtr->hwndSelf, TV_REFRESH_TIMER, TV_REFRESH_DELAY, 0);
698  TREEVIEW_Timer|=TV_REFRESH_TIMER_SET;
699 }
700
701
702
703 static LRESULT
704 TREEVIEW_GetItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
705 {
706   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
707   LPTVITEM      tvItem;
708   TREEVIEW_ITEM *wineItem;
709   INT32         iItem,len;
710
711   TRACE (treeview,"\n");
712   tvItem=(LPTVITEM) lParam;
713   iItem=tvItem->hItem;
714
715   wineItem = TREEVIEW_ValidItem (infoPtr, iItem);
716   if (!wineItem) return FALSE;
717
718
719    if (tvItem->mask & TVIF_CHILDREN) {
720         tvItem->cChildren=wineItem->cChildren;
721    }
722
723    if (tvItem->mask & TVIF_HANDLE) {
724         tvItem->hItem=wineItem->hItem;
725    }
726
727    if (tvItem->mask & TVIF_IMAGE) {
728         tvItem->iImage=wineItem->iImage;
729    }
730
731    if (tvItem->mask & TVIF_INTEGRAL) {
732 /*        tvItem->iIntegral=wineItem->iIntegral; */
733    }
734
735    if (tvItem->mask & TVIF_PARAM) {
736         tvItem->lParam=wineItem->lParam;
737    }
738
739    if (tvItem->mask & TVIF_SELECTEDIMAGE) {
740         tvItem->iSelectedImage=wineItem->iSelectedImage;
741    }
742
743    if (tvItem->mask & TVIF_STATE) {
744         tvItem->state=wineItem->state & tvItem->stateMask;
745    }
746
747    if (tvItem->mask & TVIF_TEXT) {
748         len=wineItem->cchTextMax;
749         if (wineItem->cchTextMax>tvItem->cchTextMax) 
750                 len=tvItem->cchTextMax-1;
751         lstrcpyn32A (tvItem->pszText, tvItem->pszText,len);
752    }
753
754   return TRUE;
755 }
756
757
758
759 static LRESULT
760 TREEVIEW_GetNextItem32 (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
761
762 {
763   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
764   TREEVIEW_ITEM *wineItem;
765   INT32 iItem, flag;
766
767
768   TRACE (treeview,"item:%lu, flags:%x\n", lParam, wParam);
769   if (!infoPtr) return FALSE;
770
771   flag= (INT32) wParam;
772   switch (flag) {
773         case TVGN_ROOT:         return (LRESULT) infoPtr->TopRootItem;
774         case TVGN_CARET:        return (LRESULT) infoPtr->selectedItem;
775         case TVGN_FIRSTVISIBLE: return (LRESULT) infoPtr->firstVisible;
776         case TVGN_DROPHILITE:   return (LRESULT) infoPtr->dropItem;
777         }
778         
779   iItem= (INT32) lParam;
780   wineItem = TREEVIEW_ValidItem (infoPtr, iItem);
781   if (!wineItem) return FALSE;
782
783   switch (flag) {
784         case TVGN_NEXT:         return (LRESULT) wineItem->sibling;
785         case TVGN_PREVIOUS:     return (LRESULT) wineItem->upsibling;
786         case TVGN_PARENT:       return (LRESULT) wineItem->parent;
787         case TVGN_CHILD:        return (LRESULT) wineItem->firstChild;
788         case TVGN_LASTVISIBLE:  FIXME (treeview,"TVGN_LASTVISIBLE not implemented\n");
789                                 return 0;
790         case TVGN_NEXTVISIBLE:  wineItem=TREEVIEW_GetNextListItem 
791                                                 (infoPtr,wineItem);
792                                 if (wineItem) 
793                                         return (LRESULT) wineItem->hItem;
794                                 else
795                                         return (LRESULT) 0;
796         case TVGN_PREVIOUSVISIBLE: wineItem=TREEVIEW_GetPrevListItem
797                                                 (infoPtr, wineItem);
798                                 if (wineItem) 
799                                         return (LRESULT) wineItem->hItem;
800                                 else
801                                         return (LRESULT) 0;
802         default:        FIXME (treeview,"Unknown msg %x,item %x\n", flag,iItem);
803         }
804
805  return 0;
806 }
807
808
809 static LRESULT
810 TREEVIEW_GetCount (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
811 {
812  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
813
814  return (LRESULT) infoPtr->uNumItems;
815 }
816
817
818
819
820 /* the method used below isn't the most memory-friendly, but it avoids 
821    a lot of memory reallocations */ 
822
823 /* BTW: we waste handle 0; 0 is not an allowed handle. Fix this by
824         decreasing infoptr->items with 1, and increasing it by 1 if 
825         it is referenced in mm-handling stuff? */
826
827 static LRESULT
828 TREEVIEW_InsertItem32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
829
830 {
831   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
832   TVINSERTSTRUCT  *ptdi;
833   TV_ITEM       *tvItem;
834   TREEVIEW_ITEM *wineItem, *parentItem, *prevsib, *sibItem;
835   INT32         iItem,listItems,i,len;
836   
837   TRACE (treeview,"\n");
838   ptdi = (TVINSERTSTRUCT *) lParam;
839
840         /* check if memory is available */
841
842   if (infoPtr->uNumPtrsAlloced==0) {
843         infoPtr->items = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
844                                     TVITEM_ALLOC*sizeof (TREEVIEW_ITEM));
845         infoPtr->freeList= HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
846                                     (1+(TVITEM_ALLOC>>5)) *sizeof (INT32));
847         infoPtr->uNumPtrsAlloced=TVITEM_ALLOC;
848         infoPtr->TopRootItem=1;
849    }
850
851   if (infoPtr->uNumItems == (infoPtr->uNumPtrsAlloced-1) ) {
852         TREEVIEW_ITEM *oldItems = infoPtr->items;
853         INT32 *oldfreeList = infoPtr->freeList;
854
855         infoPtr->uNumPtrsAlloced*=2;
856         infoPtr->items = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
857                               infoPtr->uNumPtrsAlloced*sizeof (TREEVIEW_ITEM));
858         infoPtr->freeList= HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
859                               (1+(infoPtr->uNumPtrsAlloced>>5))*sizeof (INT32));
860
861         memcpy (&infoPtr->items[0], &oldItems[0],
862                     infoPtr->uNumPtrsAlloced/2 * sizeof(TREEVIEW_ITEM));
863         memcpy (&infoPtr->freeList[0], &oldfreeList[0],
864                     infoPtr->uNumPtrsAlloced>>6 * sizeof(INT32));
865
866          HeapFree (GetProcessHeap (), 0, oldItems);  
867          HeapFree (GetProcessHeap (), 0, oldfreeList);  
868     }
869
870   iItem=0;
871   infoPtr->uNumItems++;
872
873   if (infoPtr->uMaxHandle==(infoPtr->uNumItems-1))  { 
874         iItem=infoPtr->uNumItems;
875         infoPtr->uMaxHandle++;
876   } 
877   else {                                         /* check freelist */
878         for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++) {
879                 if (infoPtr->freeList[i]) {
880                         iItem=ffs (infoPtr->freeList[i]);
881                         clear_bit (iItem & 31, & infoPtr->freeList[i]);
882                         break;
883                 }
884          } 
885   }
886   if (!iItem) ERR (treeview, "Argh -- can't find free item.\n");
887   
888   tvItem= & ptdi->item;
889   wineItem=& infoPtr->items[iItem];
890
891
892
893   if ((ptdi->hParent==TVI_ROOT) || (ptdi->hParent==0)) {
894         parentItem=NULL;
895         wineItem->parent=0; 
896         sibItem=&infoPtr->items [infoPtr->TopRootItem];
897         listItems=infoPtr->uNumItems;
898   }
899   else  {
900         parentItem= &infoPtr->items[ptdi->hParent];
901         if (!parentItem->firstChild) 
902                 parentItem->firstChild=iItem;
903         wineItem->parent=ptdi->hParent;
904         sibItem=&infoPtr->items [parentItem->firstChild];
905         parentItem->cChildren++;
906         listItems=parentItem->cChildren;
907   }
908
909   wineItem->upsibling=0;  /* needed in case we're the first item in a list */ 
910   wineItem->sibling=0;     
911   wineItem->firstChild=0;
912
913   if (listItems>1) {
914      prevsib=NULL;
915      switch (ptdi->hInsertAfter) {
916                 case TVI_FIRST: wineItem->sibling=infoPtr->TopRootItem;
917                         infoPtr->TopRootItem=iItem;
918                         break;
919                 case TVI_LAST:  
920                         while (sibItem->sibling) {
921                                 prevsib=sibItem;
922                                 sibItem=&infoPtr->items [sibItem->sibling];
923                         }
924                         sibItem->sibling=iItem;
925                         if (prevsib!=NULL) 
926                                 wineItem->upsibling=prevsib->hItem;
927                         else
928                                 wineItem->sibling=0;    /* terminate list */
929                         break;
930                 case TVI_SORT:  
931                         FIXME (treeview, "Sorted insert not implemented yet\n");
932                         break;
933                 default:        
934                         while ((sibItem->sibling) && (sibItem->sibling!=iItem)) {
935                                 prevsib=sibItem;
936                 sibItem=&infoPtr->items [sibItem->sibling];
937             }
938                         if (sibItem->sibling) 
939                                 WARN (treeview, "Buggy program tried to insert item after nonexisting handle.");
940                         sibItem->upsibling=iItem;
941                         wineItem->sibling=sibItem->hItem;
942                         if (prevsib!=NULL) 
943                                 wineItem->upsibling=prevsib->hItem;
944                         break;
945         }
946    }    
947
948
949 /* Fill in info structure */
950
951    wineItem->mask=tvItem->mask;
952    wineItem->hItem=iItem;
953    wineItem->iIntegral=1; 
954
955    if (tvItem->mask & TVIF_CHILDREN)
956          wineItem->cChildren=tvItem->cChildren;
957
958    if (tvItem->mask & TVIF_IMAGE) 
959         wineItem->iImage=tvItem->iImage;
960
961 /*   if (tvItem->mask & TVIF_INTEGRAL) 
962         wineItem->iIntegral=tvItem->iIntegral;  */
963    
964
965    if (tvItem->mask & TVIF_PARAM) 
966         wineItem->lParam=tvItem->lParam;
967
968    if (tvItem->mask & TVIF_SELECTEDIMAGE) 
969         wineItem->iSelectedImage=tvItem->iSelectedImage;
970
971    if (tvItem->mask & TVIF_STATE) {
972         wineItem->state=tvItem->state;
973         wineItem->stateMask=tvItem->stateMask;
974    }
975
976    if (tvItem->mask & TVIF_TEXT) {
977         TRACE (treeview,"(%s)\n", tvItem->pszText); 
978         if (tvItem->pszText!=LPSTR_TEXTCALLBACK32A) {
979                 len = lstrlen32A (tvItem->pszText)+1;
980                 wineItem->pszText=
981                         HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, len+1);
982                 lstrcpy32A (wineItem->pszText, tvItem->pszText);
983                 wineItem->cchTextMax=len;
984         }
985    }
986
987    TREEVIEW_QueueRefresh (wndPtr);
988
989    return (LRESULT) iItem;
990 }
991
992
993
994 static LRESULT
995 TREEVIEW_DeleteItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
996 {
997   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
998   INT32 iItem;
999   POINT32 pt;
1000   TREEVIEW_ITEM *wineItem;
1001
1002   TRACE (treeview,"\n");
1003   if (!infoPtr) return FALSE;
1004
1005   if ((INT32) lParam == TVI_ROOT) {
1006         TREEVIEW_RemoveTree (infoPtr);
1007   } else {
1008         iItem= (INT32) lParam;
1009         wineItem = TREEVIEW_ValidItem (infoPtr, iItem);
1010         if (!wineItem) return FALSE;
1011         TREEVIEW_SendTreeviewNotify (wndPtr, TVN_DELETEITEM, 0, iItem, 0, pt);
1012         TREEVIEW_RemoveItem (infoPtr, wineItem);
1013   }
1014
1015   TREEVIEW_QueueRefresh (wndPtr);
1016
1017   return TRUE;
1018 }
1019
1020
1021 static LRESULT
1022 TREEVIEW_GetIndent (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1023 {
1024  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1025
1026  return infoPtr->uIndent;
1027 }
1028
1029 static LRESULT
1030 TREEVIEW_SetIndent (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1031 {
1032   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1033   INT32 newIndent;
1034    
1035   newIndent=(INT32) wParam;
1036   if (newIndent < MINIMUM_INDENT) newIndent=MINIMUM_INDENT;
1037   infoPtr->uIndent=newIndent;
1038   
1039   return 0;
1040 }
1041
1042
1043
1044
1045
1046 static LRESULT
1047 TREEVIEW_Create (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1048 {
1049     TREEVIEW_INFO *infoPtr;
1050         HDC32 hdc;
1051     TEXTMETRIC32A tm;
1052   
1053     TRACE (treeview,"\n");
1054       /* allocate memory for info structure */
1055       infoPtr = (TREEVIEW_INFO *)HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
1056                                      sizeof(TREEVIEW_INFO));
1057
1058     wndPtr->wExtra[0] = (DWORD)infoPtr;
1059
1060     if (infoPtr == NULL) {
1061                 ERR (treeview, "could not allocate info memory!\n");
1062                 return 0;
1063     }
1064
1065     if ((TREEVIEW_INFO*)wndPtr->wExtra[0] != infoPtr) {
1066                 ERR (treeview, "pointer assignment error!\n");
1067                 return 0;
1068     }
1069
1070         hdc=GetDC32 (wndPtr->hwndSelf);
1071
1072     /* set default settings */
1073     infoPtr->uInternalStatus=0;
1074     infoPtr->uNumItems=0;
1075     infoPtr->clrBk = GetSysColor32 (COLOR_WINDOW);
1076     infoPtr->clrText = GetSysColor32 (COLOR_BTNTEXT);
1077     infoPtr->cy = 0;
1078     infoPtr->cx = 0;
1079     infoPtr->uIndent = 15;
1080     infoPtr->himlNormal = NULL;
1081     infoPtr->himlState = NULL;
1082         infoPtr->uItemHeight = -1;
1083     GetTextMetrics32A (hdc, &tm);
1084     infoPtr->uRealItemHeight= tm.tmHeight + tm.tmExternalLeading;
1085
1086     infoPtr->items = NULL;
1087     infoPtr->selectedItem=0;
1088     infoPtr->clrText=-1;        /* use system color */
1089     infoPtr->dropItem=0;
1090
1091 /*
1092     infoPtr->hwndNotify = GetParent32 (wndPtr->hwndSelf);
1093     infoPtr->bTransparent = (wndPtr->dwStyle & TBSTYLE_FLAT);
1094 */
1095
1096     if (wndPtr->dwStyle & TBSTYLE_TOOLTIPS) {
1097         /* Create tooltip control */
1098 //      infoPtr->hwndToolTip = CreateWindowEx32A (....);
1099
1100         /* Send TV_TOOLTIPSCREATED notification */
1101
1102     }
1103     ReleaseDC32 (wndPtr->hwndSelf, hdc);
1104
1105     return 0;
1106 }
1107
1108
1109
1110 static LRESULT 
1111 TREEVIEW_Destroy (WND *wndPtr) 
1112 {
1113    TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1114      
1115    TREEVIEW_RemoveTree (infoPtr);
1116
1117    HeapFree (GetProcessHeap (), 0, infoPtr);
1118
1119    return 0;
1120 }
1121
1122
1123 static LRESULT
1124 TREEVIEW_Paint (WND *wndPtr, WPARAM32 wParam)
1125 {
1126     HDC32 hdc;
1127     PAINTSTRUCT32 ps;
1128
1129     hdc = wParam==0 ? BeginPaint32 (wndPtr->hwndSelf, &ps) : (HDC32)wParam;
1130     TREEVIEW_QueueRefresh (wndPtr);
1131     if(!wParam)
1132         EndPaint32 (wndPtr->hwndSelf, &ps);
1133     return 0;
1134 }
1135
1136
1137
1138 static LRESULT
1139 TREEVIEW_EraseBackground (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1140 {
1141     TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1142     HBRUSH32 hBrush = CreateSolidBrush32 (infoPtr->clrBk);
1143     RECT32 rect;
1144
1145     TRACE (treeview,"\n");
1146     GetClientRect32 (wndPtr->hwndSelf, &rect);
1147     FillRect32 ((HDC32)wParam, &rect, hBrush);
1148     DeleteObject32 (hBrush);
1149     return TRUE;
1150 }
1151
1152
1153
1154
1155
1156   
1157
1158
1159
1160 static BOOL32
1161 TREEVIEW_SendSimpleNotify (WND *wndPtr, UINT32 code)
1162 {
1163     NMHDR nmhdr;
1164
1165     TRACE (treeview, "%x\n",code);
1166     nmhdr.hwndFrom = wndPtr->hwndSelf;
1167     nmhdr.idFrom   = wndPtr->wIDmenu;
1168     nmhdr.code     = code;
1169
1170     return (BOOL32) SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
1171                                    (WPARAM32)nmhdr.idFrom, (LPARAM)&nmhdr);
1172 }
1173
1174
1175
1176
1177 static BOOL32
1178 TREEVIEW_SendTreeviewNotify (WND *wndPtr, UINT32 code, UINT32 action, 
1179                         INT32 oldItem, INT32 newItem, POINT32 pt)
1180 {
1181   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1182   NMTREEVIEW nmhdr;
1183   TREEVIEW_ITEM  *wineItem;
1184
1185   TRACE (treeview,"code:%x action:%x olditem:%x newitem:%x\n",
1186                   code,action,oldItem,newItem);
1187   nmhdr.hdr.hwndFrom = wndPtr->hwndSelf;
1188   nmhdr.hdr.idFrom = wndPtr->wIDmenu;
1189   nmhdr.hdr.code = code;
1190   nmhdr.action = action;
1191   if (oldItem) {
1192         wineItem=& infoPtr->items[oldItem];
1193         nmhdr.itemOld.mask              = wineItem->mask;
1194         nmhdr.itemOld.hItem             = wineItem->hItem;
1195         nmhdr.itemOld.state             = wineItem->state;
1196         nmhdr.itemOld.stateMask = wineItem->stateMask;
1197         nmhdr.itemOld.iImage            = wineItem->iImage;
1198         nmhdr.itemOld.pszText   = wineItem->pszText;
1199         nmhdr.itemOld.cchTextMax        = wineItem->cchTextMax;
1200         nmhdr.itemOld.iImage            = wineItem->iImage;
1201         nmhdr.itemOld.iSelectedImage    = wineItem->iSelectedImage;
1202         nmhdr.itemOld.cChildren         = wineItem->cChildren;
1203         nmhdr.itemOld.lParam            = wineItem->lParam;
1204   }
1205
1206   if (newItem) {
1207         wineItem=& infoPtr->items[newItem];
1208         nmhdr.itemNew.mask              = wineItem->mask;
1209         nmhdr.itemNew.hItem             = wineItem->hItem;
1210         nmhdr.itemNew.state             = wineItem->state;
1211         nmhdr.itemNew.stateMask = wineItem->stateMask;
1212         nmhdr.itemNew.iImage            = wineItem->iImage;
1213         nmhdr.itemNew.pszText   = wineItem->pszText;
1214         nmhdr.itemNew.cchTextMax        = wineItem->cchTextMax;
1215         nmhdr.itemNew.iImage            = wineItem->iImage;
1216         nmhdr.itemNew.iSelectedImage    = wineItem->iSelectedImage;
1217         nmhdr.itemNew.cChildren         = wineItem->cChildren;
1218         nmhdr.itemNew.lParam            = wineItem->lParam;
1219   }
1220
1221   nmhdr.ptDrag.x = pt.x;
1222   nmhdr.ptDrag.y = pt.y;
1223
1224   return (BOOL32)SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
1225                                    (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmhdr);
1226
1227 }
1228
1229
1230
1231
1232 static LRESULT
1233 TREEVIEW_Expand (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1234 {
1235  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1236  TREEVIEW_ITEM *wineItem;
1237  UINT32 flag;
1238  INT32 expandItem;
1239  POINT32 pt;
1240  
1241  flag= (UINT32) wParam;
1242  expandItem= (INT32) lParam;
1243  TRACE (treeview,"flags:%x item:%x\n", expandItem, wParam);
1244  wineItem = TREEVIEW_ValidItem (infoPtr, expandItem);
1245  if (!wineItem) return 0;
1246  if (!wineItem->cChildren) return 0;
1247
1248  if (flag & TVE_TOGGLE) {               /* FIXME: check exact behaviour here */
1249         flag &= ~TVE_TOGGLE;            /* ie: bitwise ops or 'case' ops */
1250         if (wineItem->state & TVIS_EXPANDED) 
1251                 flag |= TVE_COLLAPSE;
1252         else
1253                 flag |= TVE_EXPAND;
1254  }
1255
1256  switch (flag) {
1257     case TVE_COLLAPSERESET: 
1258                 if (!wineItem->state & TVIS_EXPANDED) return 0;
1259                 wineItem->state &= ~(TVIS_EXPANDEDONCE | TVIS_EXPANDED);
1260                 TREEVIEW_RemoveAllChildren (infoPtr, wineItem);
1261                 break;
1262
1263     case TVE_COLLAPSE: 
1264                 if (!wineItem->state & TVIS_EXPANDED) return 0;
1265                 wineItem->state &= ~TVIS_EXPANDED;
1266                 break;
1267
1268     case TVE_EXPAND: 
1269                 if (wineItem->state & TVIS_EXPANDED) return 0;
1270                 if (!(wineItem->state & TVIS_EXPANDEDONCE)) {
1271                 if (TREEVIEW_SendTreeviewNotify (wndPtr, TVN_ITEMEXPANDING, 
1272                                                                                         0, 0, expandItem, pt))
1273                                         return FALSE;   /* FIXME: OK? */
1274                 wineItem->state |= TVIS_EXPANDED | TVIS_EXPANDEDONCE;
1275         TREEVIEW_SendTreeviewNotify (wndPtr, TVN_ITEMEXPANDED, 
1276                                                                                         0, 0, expandItem, pt);
1277         }
1278         wineItem->state |= TVIS_EXPANDED;
1279         break;
1280    case TVE_EXPANDPARTIAL:
1281                 FIXME (treeview, "TVE_EXPANDPARTIAL not implemented\n");
1282                 wineItem->state ^=TVIS_EXPANDED;
1283                 wineItem->state |=TVIS_EXPANDEDONCE;
1284                 break;
1285   }
1286  
1287  TREEVIEW_QueueRefresh (wndPtr);
1288
1289  return TRUE;
1290 }
1291
1292
1293
1294 static HTREEITEM
1295 TREEVIEW_HitTest (WND *wndPtr, LPTVHITTESTINFO lpht)
1296 {
1297  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1298  TREEVIEW_ITEM *wineItem;
1299  RECT32 rect;
1300  UINT32 status,x,y;
1301  
1302
1303
1304  GetClientRect32 (wndPtr->hwndSelf, &rect);
1305  TRACE (treeview,"(%d,%d)\n",lpht->pt.x, lpht->pt.y);
1306
1307  status=0;
1308  x=lpht->pt.x;
1309  y=lpht->pt.y;
1310  if (x < rect.left)  status|=TVHT_TOLEFT;
1311  if (x > rect.right) status|=TVHT_TORIGHT;
1312  if (y < rect.top )  status|=TVHT_ABOVE;
1313  if (y > rect.bottom) status|=TVHT_BELOW;
1314  if (status) {
1315         lpht->flags=status;
1316         return 0;
1317  }
1318
1319  if (!infoPtr->firstVisible) WARN (treeview,"Can't fetch first visible item");
1320  wineItem=&infoPtr->items [infoPtr->firstVisible];
1321
1322  while ((wineItem!=NULL) && (y > wineItem->rect.bottom))
1323        wineItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
1324         
1325  if (wineItem==NULL) {
1326         lpht->flags=TVHT_NOWHERE;
1327         return 0;
1328  }
1329
1330  if (x>wineItem->rect.right) {
1331         lpht->flags|=TVHT_ONITEMRIGHT;
1332         return wineItem->hItem;
1333  }
1334  
1335         
1336  if (x<wineItem->rect.left+10) lpht->flags|=TVHT_ONITEMBUTTON;
1337
1338  lpht->flags=TVHT_ONITEMLABEL;    /* FIXME: implement other flags */
1339         
1340
1341  lpht->hItem=wineItem->hItem;
1342  return wineItem->hItem;
1343 }
1344
1345
1346 static LRESULT
1347 TREEVIEW_HitTest32 (WND *wndPtr, LPARAM lParam)
1348 {
1349  
1350   return (LRESULT) TREEVIEW_HitTest (wndPtr, (LPTVHITTESTINFO) lParam);
1351 }
1352
1353
1354
1355
1356 LRESULT
1357 TREEVIEW_LButtonDoubleClick (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1358 {
1359   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1360   TREEVIEW_ITEM *wineItem;
1361   INT32 iItem;
1362   TVHITTESTINFO ht;
1363
1364   TRACE (treeview,"\n");
1365   ht.pt.x = (INT32)LOWORD(lParam);
1366   ht.pt.y = (INT32)HIWORD(lParam);
1367   SetFocus32 (wndPtr->hwndSelf);
1368
1369   iItem=TREEVIEW_HitTest (wndPtr, &ht);
1370   TRACE (treeview,"item %d \n",iItem);
1371   wineItem=TREEVIEW_ValidItem (infoPtr, iItem);
1372   if (!wineItem) return 0;
1373  
1374   if (TREEVIEW_SendSimpleNotify (wndPtr, NM_DBLCLK)!=TRUE) {     /* FIXME!*/
1375         wineItem->state &= ~TVIS_EXPANDEDONCE;
1376         TREEVIEW_Expand (wndPtr, (WPARAM32) TVE_TOGGLE, (LPARAM) iItem);
1377  }
1378  return TRUE;
1379 }
1380
1381
1382
1383 static LRESULT
1384 TREEVIEW_LButtonDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1385 {
1386   INT32 iItem;
1387   TVHITTESTINFO ht;
1388
1389   TRACE (treeview,"\n");
1390   ht.pt.x = (INT32)LOWORD(lParam);
1391   ht.pt.y = (INT32)HIWORD(lParam);
1392
1393   SetFocus32 (wndPtr->hwndSelf);
1394   iItem=TREEVIEW_HitTest (wndPtr, &ht);
1395   TRACE (treeview,"item %d \n",iItem);
1396   if (ht.flags & TVHT_ONITEMBUTTON) {
1397         TREEVIEW_Expand (wndPtr, (WPARAM32) TVE_TOGGLE, (LPARAM) iItem);
1398   }
1399         
1400   if (TREEVIEW_SelectItem (wndPtr, (WPARAM32) TVGN_CARET, (LPARAM) iItem))
1401          return 0;
1402
1403   
1404  return 0;
1405 }
1406
1407
1408 static LRESULT
1409 TREEVIEW_RButtonDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1410 {
1411
1412  return 0;
1413 }
1414
1415
1416
1417
1418 /* FIXME: If the specified item is the child of a collapsed parent item,
1419 expand parent's list of child items to reveal the specified item.
1420 */
1421
1422 static LRESULT
1423 TREEVIEW_SelectItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1424 {
1425  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1426  TREEVIEW_ITEM *prevItem,*wineItem;
1427  INT32 action,prevSelect, newSelect;
1428  POINT32 dummy;
1429
1430   TRACE (treeview,"item %lx, flag %x\n", lParam, wParam);
1431   newSelect= (INT32) lParam;
1432   wineItem = TREEVIEW_ValidItem (infoPtr, newSelect);
1433   if (!wineItem) return FALSE;
1434   prevSelect=infoPtr->selectedItem;
1435   prevItem= TREEVIEW_ValidItem (infoPtr, prevSelect);
1436   dummy.x=0;
1437   dummy.y=0;
1438
1439   action= (INT32) wParam;
1440
1441   switch (action) {
1442         case TVGN_CARET: 
1443             if (TREEVIEW_SendTreeviewNotify (wndPtr, TVN_SELCHANGING, TVC_BYMOUSE, 
1444                                                                                 prevSelect, newSelect,dummy)) 
1445                         return FALSE;       /* FIXME: OK? */
1446                 
1447             if (prevItem) prevItem->state &= ~TVIS_SELECTED;
1448                 infoPtr->selectedItem=newSelect;
1449                 wineItem->state |=TVIS_SELECTED;
1450                 TREEVIEW_SendTreeviewNotify (wndPtr, TVN_SELCHANGED, 
1451                                 TVC_BYMOUSE, prevSelect, newSelect, dummy);
1452                 break;
1453         case TVGN_DROPHILITE: 
1454                 FIXME (treeview, "DROPHILITE not implemented");
1455                 break;
1456         case TVGN_FIRSTVISIBLE:
1457                 FIXME (treeview, "FIRSTVISIBLE not implemented");
1458                 break;
1459  }
1460  
1461  TREEVIEW_QueueRefresh (wndPtr);
1462   
1463  return TRUE;
1464 }
1465
1466
1467
1468 /* FIXME: does KEYDOWN also send notifications?? If so, use 
1469    TREEVIEW_SelectItem.
1470 */
1471    
1472
1473 static LRESULT
1474 TREEVIEW_KeyDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1475 {
1476  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1477  TREEVIEW_ITEM *prevItem,*newItem;
1478  int prevSelect;
1479
1480
1481  TRACE (treeview,"%x %lx",wParam, lParam);
1482  prevSelect=infoPtr->selectedItem;
1483  if (!prevSelect) return FALSE;
1484
1485  prevItem= TREEVIEW_ValidItem (infoPtr, prevSelect);
1486  
1487  newItem=NULL;
1488  switch (wParam) {
1489         case VK_UP: 
1490                 newItem=TREEVIEW_GetPrevListItem (infoPtr, prevItem);
1491                 if (!newItem) 
1492                         newItem=& infoPtr->items[infoPtr->TopRootItem];
1493                 break;
1494         case VK_DOWN: 
1495                 newItem=TREEVIEW_GetNextListItem (infoPtr, prevItem);
1496                 if (!newItem) newItem=prevItem;
1497                 break;
1498         case VK_HOME:
1499                 newItem=& infoPtr->items[infoPtr->TopRootItem];
1500                 break;
1501         case VK_END:
1502                 newItem=TREEVIEW_GetLastListItem (infoPtr);
1503                 break;
1504         case VK_PRIOR:
1505         case VK_NEXT:
1506         case VK_BACK:
1507         case VK_RETURN:
1508                 FIXME (treeview, "%x not implemented\n", wParam);
1509                 break;
1510  }
1511
1512  if (!newItem) return FALSE;
1513
1514  if (prevItem!=newItem) {
1515         prevItem->state &= ~TVIS_SELECTED;
1516         newItem->state |= TVIS_SELECTED;
1517         infoPtr->selectedItem=newItem->hItem;
1518         TREEVIEW_QueueRefresh (wndPtr);
1519         return TRUE;
1520  }
1521
1522  return FALSE;
1523 }
1524
1525
1526
1527 static LRESULT
1528 TREEVIEW_VScroll (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1529
1530 {
1531   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1532   int maxHeight;
1533
1534   TRACE (treeview,"wp %x, lp %lx\n", wParam, lParam);
1535   if (!infoPtr->uInternalStatus & TV_VSCROLL) return FALSE;
1536
1537   switch (LOWORD (wParam)) {
1538         case SB_LINEUP: 
1539                         if (!infoPtr->cy) return FALSE;
1540                         infoPtr->cy -= infoPtr->uRealItemHeight;
1541                         if (infoPtr->cy < 0) infoPtr->cy=0;
1542                         break;
1543         case SB_LINEDOWN: 
1544                         maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
1545                         if (infoPtr->cy == maxHeight) return FALSE;
1546                         infoPtr->cy += infoPtr->uRealItemHeight;
1547                         if (infoPtr->cy > maxHeight) 
1548                                 infoPtr->cy = maxHeight;
1549                         break;
1550         case SB_PAGEUP: 
1551                         if (!infoPtr->cy) return FALSE;
1552                         infoPtr->cy -= infoPtr->uVisibleHeight;
1553                         if (infoPtr->cy < 0) infoPtr->cy=0;
1554                         break;
1555         case SB_PAGEDOWN:
1556                         maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
1557                         if (infoPtr->cy == maxHeight) return FALSE;
1558                         infoPtr->cy += infoPtr->uVisibleHeight;
1559             if (infoPtr->cy > maxHeight)
1560                 infoPtr->cy = maxHeight;
1561                         break;
1562         case SB_THUMBTRACK: 
1563                         infoPtr->cy = HIWORD (wParam);
1564                         break;
1565                         
1566   }
1567   
1568   TREEVIEW_QueueRefresh (wndPtr);
1569   return TRUE;
1570 }
1571
1572 static LRESULT
1573 TREEVIEW_HScroll (WND *wndPtr, WPARAM32 wParam, LPARAM lParam) 
1574 {
1575   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1576
1577   TRACE (treeview,"wp %lx, lp %x\n", lParam, wParam);
1578         
1579   if (!infoPtr->uInternalStatus & TV_HSCROLL) return FALSE;
1580   return TRUE;
1581 }
1582
1583
1584
1585
1586   LRESULT WINAPI
1587   TREEVIEW_WindowProc (HWND32 hwnd, UINT32 uMsg, WPARAM32 wParam, LPARAM lParam)
1588   {
1589       WND *wndPtr = WIN_FindWndPtr(hwnd);
1590   
1591   
1592     switch (uMsg) {
1593         case TVM_INSERTITEM32A:
1594           return TREEVIEW_InsertItem32A (wndPtr, wParam, lParam);
1595
1596         case TVM_INSERTITEM32W:
1597                 FIXME (treeview, "Unimplemented msg TVM_INSERTITEM32W\n");
1598                 return 0;
1599
1600         case TVM_DELETEITEM:
1601                 return TREEVIEW_DeleteItem (wndPtr, wParam, lParam);
1602
1603         case TVM_EXPAND:
1604                 return TREEVIEW_Expand (wndPtr, wParam, lParam);
1605
1606         case TVM_GETITEMRECT:
1607                 return TREEVIEW_GetItemRect (wndPtr, wParam, lParam);
1608
1609         case TVM_GETCOUNT:
1610                 return TREEVIEW_GetCount (wndPtr, wParam, lParam);
1611
1612         case TVM_GETINDENT:
1613                 return TREEVIEW_GetIndent (wndPtr, wParam, lParam);
1614
1615         case TVM_SETINDENT:
1616                 return TREEVIEW_SetIndent (wndPtr, wParam, lParam);
1617
1618         case TVM_GETIMAGELIST:
1619                 return TREEVIEW_GetImageList (wndPtr, wParam, lParam);
1620
1621                 case TVM_SETIMAGELIST:
1622                 return TREEVIEW_SetImageList (wndPtr, wParam, lParam);
1623
1624         case TVM_GETNEXTITEM:
1625                 return TREEVIEW_GetNextItem32 (wndPtr, wParam, lParam);
1626
1627         case TVM_SELECTITEM:
1628                 return TREEVIEW_SelectItem (wndPtr, wParam, lParam);
1629
1630         case TVM_GETITEM32A:
1631                 return TREEVIEW_GetItem (wndPtr, wParam, lParam);
1632
1633         case TVM_GETITEM32W:
1634                 FIXME (treeview, "Unimplemented msg TVM_GETITEM32W\n");
1635                 return 0;
1636
1637         case TVM_SETITEM32A:
1638                 return TREEVIEW_SetItem (wndPtr, wParam, lParam);
1639
1640         case TVM_SETITEM32W:
1641                 FIXME (treeview, "Unimplemented msg TVM_SETITEMW\n");
1642                 return 0;
1643
1644         case TVM_EDITLABEL32A:
1645                 FIXME (treeview, "Unimplemented msg TVM_EDITLABEL32A \n");
1646                 return 0;
1647
1648         case TVM_EDITLABEL32W:
1649                 FIXME (treeview, "Unimplemented msg TVM_EDITLABEL32W \n");
1650                 return 0;
1651
1652         case TVM_GETEDITCONTROL:
1653                 FIXME (treeview, "Unimplemented msg TVM_GETEDITCONTROL\n");
1654                 return 0;
1655
1656         case TVM_GETVISIBLECOUNT:
1657                 return TREEVIEW_GetVisibleCount (wndPtr, wParam, lParam);
1658
1659         case TVM_HITTEST:
1660                 return TREEVIEW_HitTest32 (wndPtr, lParam);
1661
1662         case TVM_CREATEDRAGIMAGE:
1663                 FIXME (treeview, "Unimplemented msg TVM_CREATEDRAGIMAGE\n");
1664                 return 0;
1665   
1666         case TVM_SORTCHILDREN:
1667                 FIXME (treeview, "Unimplemented msg TVM_SORTCHILDREN\n");
1668                 return 0;
1669   
1670         case TVM_ENSUREVISIBLE:
1671                 FIXME (treeview, "Unimplemented msg TVM_ENSUREVISIBLE\n");
1672                 return 0;
1673   
1674         case TVM_SORTCHILDRENCB:
1675                 FIXME (treeview, "Unimplemented msg TVM_SORTCHILDRENCB\n");
1676                 return 0;
1677   
1678         case TVM_ENDEDITLABELNOW:
1679                 FIXME (treeview, "Unimplemented msg TVM_ENDEDITLABELNOW\n");
1680                 return 0;
1681   
1682         case TVM_GETISEARCHSTRING32A:
1683                 FIXME (treeview, "Unimplemented msg TVM_GETISEARCHSTRING32A\n");
1684                 return 0;
1685   
1686         case TVM_GETISEARCHSTRING32W:
1687                 FIXME (treeview, "Unimplemented msg TVM_GETISEARCHSTRING32W\n");
1688                 return 0;
1689   
1690         case TVM_SETTOOLTIPS:
1691                 FIXME (treeview, "Unimplemented msg TVM_SETTOOLTIPS\n");
1692                 return 0;
1693   
1694         case TVM_GETTOOLTIPS:
1695                 FIXME (treeview, "Unimplemented msg TVM_GETTOOLTIPS\n");
1696                 return 0;
1697   
1698         case TVM_SETINSERTMARK:
1699                 FIXME (treeview, "Unimplemented msg TVM_SETINSERTMARK\n");
1700                 return 0;
1701   
1702         case TVM_SETITEMHEIGHT:
1703                 return TREEVIEW_SetItemHeight (wndPtr, wParam);
1704   
1705         case TVM_GETITEMHEIGHT:
1706                 return TREEVIEW_GetItemHeight (wndPtr);
1707   
1708         case TVM_SETBKCOLOR:
1709                 FIXME (treeview, "Unimplemented msg TVM_SETBKCOLOR\n");
1710                 return 0;
1711         
1712         case TVM_SETTEXTCOLOR:
1713                 return TREEVIEW_SetTextColor (wndPtr, wParam, lParam);
1714   
1715         case TVM_GETBKCOLOR:
1716                 FIXME (treeview, "Unimplemented msg TVM_GETBKCOLOR\n");
1717                 return 0;
1718   
1719         case TVM_GETTEXTCOLOR:
1720                 return TREEVIEW_GetTextColor (wndPtr);
1721   
1722         case TVM_SETSCROLLTIME:
1723                 FIXME (treeview, "Unimplemented msg TVM_SETSCROLLTIME\n");
1724                 return 0;
1725   
1726         case TVM_GETSCROLLTIME:
1727                 FIXME (treeview, "Unimplemented msg TVM_GETSCROLLTIME\n");
1728                 return 0;
1729   
1730         case TVM_SETINSERTMARKCOLOR:
1731                 FIXME (treeview, "Unimplemented msg TVM_SETINSERTMARKCOLOR\n");
1732                 return 0;
1733   
1734         case TVM_SETUNICODEFORMAT:
1735                 FIXME (treeview, "Unimplemented msg TVM_SETUNICODEFORMAT\n");
1736                 return 0;
1737   
1738         case TVM_GETUNICODEFORMAT:
1739                 FIXME (treeview, "Unimplemented msg TVM_GETUNICODEFORMAT\n");
1740                 return 0;
1741   
1742 //              case WM_COMMAND:
1743   
1744                 case WM_CREATE:
1745                         return TREEVIEW_Create (wndPtr, wParam, lParam);
1746   
1747                 case WM_DESTROY:
1748                         return TREEVIEW_Destroy (wndPtr);
1749   
1750 //              case WM_ENABLE:
1751   
1752                 case WM_ERASEBKGND:
1753                 return TREEVIEW_EraseBackground (wndPtr, wParam, lParam);
1754   
1755                 case WM_GETDLGCODE:
1756                 return DLGC_WANTARROWS | DLGC_WANTCHARS;
1757   
1758                 case WM_PAINT:
1759                 return TREEVIEW_Paint (wndPtr, wParam);
1760   
1761 //              case WM_GETFONT:
1762 //              case WM_SETFONT:
1763   
1764                 case WM_KEYDOWN:
1765                         return TREEVIEW_KeyDown (wndPtr, wParam, lParam);
1766   
1767   
1768 //              case WM_KILLFOCUS:
1769 //              case WM_SETFOCUS:
1770   
1771   
1772                 case WM_LBUTTONDOWN:
1773                         return TREEVIEW_LButtonDown (wndPtr, wParam, lParam);
1774   
1775                 case WM_LBUTTONDBLCLK:
1776                         return TREEVIEW_LButtonDoubleClick (wndPtr, wParam, lParam);
1777   
1778                 case WM_RBUTTONDOWN:
1779                         return TREEVIEW_RButtonDown (wndPtr, wParam, lParam);
1780   
1781   
1782 //              case WM_SYSCOLORCHANGE:
1783 //              case WM_STYLECHANGED:
1784 //              case WM_SETREDRAW:
1785   
1786                 case WM_TIMER:
1787                         return TREEVIEW_HandleTimer (wndPtr, wParam, lParam);
1788   
1789 //              case WM_SIZE:
1790                 case WM_HSCROLL: 
1791                         return TREEVIEW_HScroll (wndPtr, wParam, lParam);
1792                 case WM_VSCROLL: 
1793                         return TREEVIEW_VScroll (wndPtr, wParam, lParam);
1794   
1795                 default:
1796                 if (uMsg >= WM_USER)
1797                 FIXME (treeview, "Unknown msg %04x wp=%08x lp=%08lx\n",
1798                      uMsg, wParam, lParam);
1799             return DefWindowProc32A (hwnd, uMsg, wParam, lParam);
1800       }
1801     return 0;
1802 }
1803
1804
1805 void
1806 TREEVIEW_Register (void)
1807 {
1808     WNDCLASS32A wndClass;
1809
1810     TRACE (treeview,"\n");
1811
1812     if (GlobalFindAtom32A (WC_TREEVIEW32A)) return;
1813
1814     ZeroMemory (&wndClass, sizeof(WNDCLASS32A));
1815     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS;
1816     wndClass.lpfnWndProc   = (WNDPROC32)TREEVIEW_WindowProc;
1817     wndClass.cbClsExtra    = 0;
1818     wndClass.cbWndExtra    = sizeof(TREEVIEW_INFO *);
1819     wndClass.hCursor       = LoadCursor32A (0, IDC_ARROW32A);
1820     wndClass.hbrBackground = 0;
1821     wndClass.lpszClassName = WC_TREEVIEW32A;
1822  
1823     RegisterClass32A (&wndClass);
1824 }
1825