Large-scale renaming of all Win32 functions and types to use the
[wine] / dlls / comctl32 / treeview.c
1 /* Treeview control
2  *
3  * Copyright 1998 Eric Kohl <ekohl@abo.rhein-zeitung.de>
4  * Copyright 1998,1999 Alex Priem <alexp@sci.kun.nl>
5  *
6  *
7  * TODO:
8  *   list-handling stuff: sort, sorted insertitem. 
9  *           [should be merged with mm-handling stuff as done in listview]
10  *   refreshtreeview:   
11                 -small array containing info about positions.
12                 -better implementation of RefreshItem:
13               1) draw lines between parents
14               2) draw items
15                           3) draw lines from parent<->items.
16                 -implement partial drawing?
17  *  -drag&drop: TVM_CREATEDRAGIMAGE should create drag bitmap.
18  *  -scrollbars: horizontal scrollbar doesn't work.
19  *  -Unicode messages
20  *  -check custom draw
21  *  -I_CHILDRENCALLBACK
22  *   FIXME: check fontsize. (uRealItemHeight)
23  *          test focusItem  (redraw in different color)
24                         uHotItem
25                         Edit: needs timer
26                                   better implementation.
27  *   WM_HSCROLL is broken.
28  *   use separate routine to get item text/image.
29  *  
30  *   Separate drawing/calculation.
31  *
32  * FIXMEs  (for personal use)
33     Expand:             -ctlmacro expands twice ->toggle.
34    -DblClick:   ctlmacro.exe's NM_DBLCLK seems to go wrong (returns FALSE).
35    -treehelper: stack corruption makes big window. 
36              
37  */
38
39
40 #include <string.h>
41 #include "winbase.h"
42 #include "commctrl.h"
43 #include "treeview.h"
44 #include "win.h"
45 #include "debug.h"
46
47 /* ffs should be in <string.h>. */
48
49 /* Defines, since they do not need to return previous state, and nr
50  * has no side effects in this file.
51  */
52 #define tv_test_bit(nr,bf)      (((LPBYTE)bf)[nr>>3]&(1<<(nr&7)))
53 #define tv_set_bit(nr,bf)       ((LPBYTE)bf)[nr>>3]|=(1<<(nr&7))
54 #define tv_clear_bit(nr,bf)     ((LPBYTE)bf)[nr>>3]&=~(1<<(nr&7))
55
56
57 #define TREEVIEW_GetInfoPtr(wndPtr) ((TREEVIEW_INFO *)wndPtr->wExtra[0])
58
59 static BOOL
60 TREEVIEW_SendSimpleNotify (WND *wndPtr, UINT code);
61 static BOOL
62 TREEVIEW_SendTreeviewNotify (WND *wndPtr, UINT code, UINT action, 
63                         HTREEITEM oldItem, HTREEITEM newItem);
64 static BOOL
65 TREEVIEW_SendTreeviewDnDNotify (WND *wndPtr, UINT code, HTREEITEM dragItem, 
66                         POINT pt);
67 static BOOL
68 TREEVIEW_SendDispInfoNotify (WND *wndPtr, TREEVIEW_ITEM *wineItem, 
69                         UINT code, UINT what);
70 static BOOL
71 TREEVIEW_SendCustomDrawNotify (WND *wndPtr, DWORD dwDrawStage, HDC hdc,
72                         RECT rc);
73 static BOOL
74 TREEVIEW_SendCustomDrawItemNotify (WND *wndPtr, HDC hdc,
75             TREEVIEW_ITEM *tvItem, UINT uItemDrawState);
76 static LRESULT
77 TREEVIEW_DoSelectItem (WND *wndPtr, INT action, HTREEITEM newSelect, INT cause);
78 static void
79 TREEVIEW_Refresh (WND *wndPtr);
80
81 static LRESULT CALLBACK
82 TREEVIEW_Edit_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, 
83                                                         LPARAM lParam);
84
85
86
87
88
89 /* helper functions. Work with the assumption that validity of operands 
90    is checked beforehand, and that tree state is valid.  */
91
92 /* FIXME: MS documentation says `GetNextVisibleItem' returns NULL 
93    if not succesfull'. Probably only applies to derefencing infoPtr
94    (ie we are offered a valid treeview structure)
95    and not whether there is a next `visible' child. 
96    FIXME: check other failures.
97  */
98
99
100
101 static TREEVIEW_ITEM *
102 TREEVIEW_ValidItem (TREEVIEW_INFO *infoPtr,HTREEITEM  handle)
103 {
104  
105  if ((!handle) || (handle>infoPtr->uMaxHandle)) return NULL;
106  if (tv_test_bit ((INT)handle, infoPtr->freeList)) return NULL;
107
108  return & infoPtr->items[(INT)handle];
109 }
110
111
112
113 static TREEVIEW_ITEM *TREEVIEW_GetPrevListItem (TREEVIEW_INFO *infoPtr, 
114                                         TREEVIEW_ITEM *tvItem)
115
116 {
117  TREEVIEW_ITEM *wineItem;
118
119  if (tvItem->upsibling) {
120                 wineItem=& infoPtr->items[(INT)tvItem->upsibling];
121                 if ((wineItem->firstChild) && (wineItem->state & TVIS_EXPANDED)) {
122                         wineItem=& infoPtr->items[(INT)wineItem->firstChild];
123                         while (wineItem->sibling)
124                                  wineItem= & infoPtr->items[(INT)wineItem->sibling];
125                 }
126                 return wineItem;
127  }
128
129  wineItem=tvItem;
130  while (wineItem->parent) {
131         wineItem=& infoPtr->items[(INT)wineItem->parent];
132         if (wineItem->upsibling) 
133                 return (& infoPtr->items[(INT)wineItem->upsibling]);
134  } 
135
136  return wineItem;
137 }
138
139
140 static TREEVIEW_ITEM *TREEVIEW_GetNextListItem (TREEVIEW_INFO *infoPtr, 
141                                         TREEVIEW_ITEM *tvItem)
142
143 {
144  TREEVIEW_ITEM *wineItem;
145
146   if ((tvItem->firstChild) && (tvItem->state & TVIS_EXPANDED)) 
147                 return (& infoPtr->items[(INT)tvItem->firstChild]);
148
149
150  if (tvItem->sibling) 
151                 return (& infoPtr->items[(INT)tvItem->sibling]);
152
153  wineItem=tvItem;
154  while (wineItem->parent) {
155         wineItem=& infoPtr->items [(INT)wineItem->parent];
156         if (wineItem->sibling) 
157                 return (& infoPtr->items [(INT)wineItem->sibling]);
158  } 
159
160  return NULL;  /* was wineItem */
161 }
162
163 static TREEVIEW_ITEM *TREEVIEW_GetLastListItem (TREEVIEW_INFO *infoPtr,
164                                         TREEVIEW_ITEM *tvItem)
165
166 {
167  TREEVIEW_ITEM *wineItem;
168
169  wineItem=tvItem;
170  while (wineItem->sibling) 
171         wineItem=& infoPtr->items [(INT)wineItem->sibling];
172
173  return wineItem;
174 }
175         
176  
177 static void TREEVIEW_RemoveAllChildren (WND *wndPtr,
178                                            TREEVIEW_ITEM *parentItem)
179
180 {
181  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
182  TREEVIEW_ITEM *killItem;
183  INT    kill;
184  
185  kill=(INT)parentItem->firstChild;
186  while (kill) {
187         tv_set_bit ( kill, infoPtr->freeList);
188         killItem=& infoPtr->items[kill];
189         if (killItem->pszText!=LPSTR_TEXTCALLBACKA) 
190                 COMCTL32_Free (killItem->pszText);
191         TREEVIEW_SendTreeviewNotify (wndPtr, TVN_DELETEITEM, 0, (HTREEITEM)kill, 0);
192         if (killItem->firstChild) 
193                         TREEVIEW_RemoveAllChildren (wndPtr, killItem);
194         kill=(INT)killItem->sibling;
195  }
196
197  if (parentItem->cChildren>0) {
198         infoPtr->uNumItems -= parentItem->cChildren;
199         parentItem->firstChild = 0;
200         parentItem->cChildren  = 0;
201  }
202
203 }
204
205
206 static void
207 TREEVIEW_RemoveItem (WND *wndPtr, TREEVIEW_ITEM *wineItem)
208
209 {
210  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
211  TREEVIEW_ITEM *parentItem, *upsiblingItem, *siblingItem;
212  INT iItem;
213
214  iItem=(INT)wineItem->hItem;
215  tv_set_bit(iItem,infoPtr->freeList);
216  infoPtr->uNumItems--;
217  parentItem=NULL;
218  if (wineItem->pszText!=LPSTR_TEXTCALLBACKA) 
219         COMCTL32_Free (wineItem->pszText);
220
221  TREEVIEW_SendTreeviewNotify (wndPtr, TVN_DELETEITEM, 0, (HTREEITEM)iItem, 0);
222
223  if (wineItem->firstChild) 
224         TREEVIEW_RemoveAllChildren (wndPtr,wineItem);
225
226  if (wineItem->parent) {
227         parentItem=& infoPtr->items [(INT)wineItem->parent];
228         switch (parentItem->cChildren) {
229                 case I_CHILDRENCALLBACK: 
230                                 FIXME (treeview,"we don't handle I_CHILDRENCALLBACK yet\n");
231                                 break;
232                 case 1:
233                         parentItem->cChildren=0;
234                         parentItem->firstChild=0;    
235                         return;
236                 default:
237                         parentItem->cChildren--;
238                         if ((INT)parentItem->firstChild==iItem) 
239                                 parentItem->firstChild=wineItem->sibling;
240                 }
241  }
242
243  if (iItem==(INT)infoPtr->TopRootItem) 
244         infoPtr->TopRootItem=(HTREEITEM)wineItem->sibling;
245  if (wineItem->upsibling) {
246         upsiblingItem=& infoPtr->items [(INT)wineItem->upsibling];
247         upsiblingItem->sibling=wineItem->sibling;
248  }
249  if (wineItem->sibling) {
250         siblingItem=& infoPtr->items [(INT)wineItem->sibling];
251         siblingItem->upsibling=wineItem->upsibling;
252  }
253 }
254
255
256
257
258
259 /* Note:TREEVIEW_RemoveTree doesn't remove infoPtr itself */
260
261 static void TREEVIEW_RemoveTree (WND *wndPtr)
262                                            
263 {
264  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
265  TREEVIEW_ITEM *killItem;
266  int i;
267
268  for (i=1; i<=(INT)infoPtr->uMaxHandle; i++) 
269         if (!tv_test_bit (i, infoPtr->freeList)) {
270                 killItem=& infoPtr->items [i];  
271                 if (killItem->pszText!=LPSTR_TEXTCALLBACKA)
272                         COMCTL32_Free (killItem->pszText);
273                 TREEVIEW_SendTreeviewNotify 
274                                         (wndPtr, TVN_DELETEITEM, 0, killItem->hItem, 0);
275                 } 
276
277  if (infoPtr->uNumPtrsAlloced) {
278         COMCTL32_Free (infoPtr->items);
279         COMCTL32_Free (infoPtr->freeList);
280         infoPtr->uNumItems=0;
281         infoPtr->uNumPtrsAlloced=0;
282         infoPtr->uMaxHandle=0;
283     }   
284 }
285
286
287
288
289
290
291
292 static LRESULT
293 TREEVIEW_GetImageList (WND *wndPtr, WPARAM wParam, LPARAM lParam)
294 {
295   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
296
297   TRACE (treeview,"\n");
298   if (infoPtr==NULL) return 0;
299
300   if ((INT)wParam == TVSIL_NORMAL) 
301         return (LRESULT) infoPtr->himlNormal;
302   if ((INT)wParam == TVSIL_STATE) 
303         return (LRESULT) infoPtr->himlState;
304
305   return 0;
306 }
307
308 static LRESULT
309 TREEVIEW_SetImageList (WND *wndPtr, WPARAM wParam, LPARAM lParam)
310 {
311     TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
312     HIMAGELIST himlTemp;
313
314     TRACE (treeview,"\n");
315     switch ((INT)wParam) {
316         case TVSIL_NORMAL:
317             himlTemp = infoPtr->himlNormal;
318             infoPtr->himlNormal = (HIMAGELIST)lParam;
319             return (LRESULT)himlTemp;
320
321         case TVSIL_STATE:
322             himlTemp = infoPtr->himlState;
323             infoPtr->himlState = (HIMAGELIST)lParam;
324             return (LRESULT)himlTemp;
325     }
326
327     return (LRESULT)NULL;
328 }
329
330
331
332 static LRESULT
333 TREEVIEW_SetItemHeight (WND *wndPtr, WPARAM wParam)
334 {
335   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
336   INT cx,cy,prevHeight=infoPtr->uItemHeight;
337   HDC hdc;
338
339   TRACE (treeview,"\n");
340   if (wParam==-1) {
341         hdc=GetDC (wndPtr->hwndSelf);
342         infoPtr->uItemHeight=-1;
343         return prevHeight;
344   }
345
346   ImageList_GetIconSize (infoPtr->himlNormal, &cx, &cy);
347
348   if (wParam>cy) cy=wParam;
349   infoPtr->uItemHeight=cy;
350
351   if (!(wndPtr->dwStyle & TVS_NONEVENHEIGHT))
352         infoPtr->uItemHeight = (INT) wParam & 0xfffffffe;
353   return prevHeight;
354 }
355
356 static LRESULT
357 TREEVIEW_GetItemHeight (WND *wndPtr)
358 {
359   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
360   
361   TRACE (treeview,"\n");
362   return infoPtr->uItemHeight;
363 }
364   
365 static LRESULT
366 TREEVIEW_SetTextColor (WND *wndPtr, WPARAM wParam, LPARAM lParam)
367 {
368   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
369   COLORREF prevColor=infoPtr->clrText;
370
371   TRACE (treeview,"\n");
372   infoPtr->clrText=(COLORREF) lParam;
373   return (LRESULT) prevColor;
374 }
375
376 static LRESULT
377 TREEVIEW_GetBkColor (WND *wndPtr)
378 {
379   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
380         
381   TRACE (treeview,"\n");
382   return (LRESULT) infoPtr->clrText;
383 }
384
385 static LRESULT
386 TREEVIEW_SetBkColor (WND *wndPtr, WPARAM wParam, LPARAM lParam)
387 {
388   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
389   COLORREF prevColor=infoPtr->clrBk;
390
391   TRACE (treeview,"\n");
392   infoPtr->clrBk=(COLORREF) lParam;
393   return (LRESULT) prevColor;
394 }
395
396 static LRESULT
397 TREEVIEW_GetTextColor (WND *wndPtr)
398 {
399   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
400         
401   TRACE (treeview,"\n");
402   return (LRESULT) infoPtr->clrBk;
403 }
404
405
406
407
408
409 /* FIXME: draw background (infoPtr->clrBk) */
410
411
412 /* cdmode: custom draw mode as received from app. in first NMCUSTOMDRAW 
413            notification */
414
415 static void
416 TREEVIEW_DrawItem (WND *wndPtr, HDC hdc, TREEVIEW_ITEM *wineItem)
417
418 {
419   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
420   INT  oldBkMode,center,xpos,cx,cy, cditem, drawmode;
421   TREEVIEW_ITEM *parentItem;
422   COLORREF oldBkColor;
423   HFONT hOldFont;
424   UINT uTextJustify = DT_LEFT;
425   HPEN hOldPen, hnewPen;
426   RECT r,upper;
427
428   HIMAGELIST *himlp;
429   
430   if (wineItem->state & TVIS_BOLD) 
431         hOldFont = SelectObject (hdc, infoPtr->hBoldFont);
432   else 
433         hOldFont = SelectObject (hdc, infoPtr->hFont);
434
435   cditem=0;
436   if (infoPtr->cdmode & CDRF_NOTIFYITEMDRAW) {
437                 drawmode=CDDS_ITEMPREPAINT;
438                 if (infoPtr->cdmode & CDRF_NOTIFYSUBITEMDRAW) drawmode|=CDDS_SUBITEM;
439                 cditem=TREEVIEW_SendCustomDrawItemNotify (wndPtr, hdc, wineItem, drawmode);
440                 TRACE (treeview,"cditem:%d\n",cditem);
441                 if (cditem & CDRF_SKIPDEFAULT) 
442                         return;
443         }
444  
445   
446   hnewPen = CreatePen(PS_DOT, 0, GetSysColor(COLOR_WINDOWTEXT) );
447   hOldPen = SelectObject( hdc, hnewPen );
448  
449   r=wineItem->rect;
450   if (wineItem->parent) {
451         parentItem=TREEVIEW_ValidItem (infoPtr, wineItem->parent);
452         upper=parentItem->rect;
453   }
454   else {
455         upper.top=0;
456         upper.left=8;
457   }
458   center=(r.top+r.bottom)/2;
459   xpos=r.left+8;
460
461   if (wndPtr->dwStyle & TVS_HASLINES) {
462         POINT points[3];
463         if ((wndPtr->dwStyle & TVS_LINESATROOT) && (wineItem->iLevel==0)) {
464                 points[0].y=points[1].y=center;
465                 points[2].y=upper.top;
466                 points[1].x=points[2].x=upper.left;
467                 points[0].x=upper.left+12;
468                 points[2].y+=5;
469
470                 Polyline (hdc,points,3);
471         }
472         else {
473                 points[0].y=points[1].y=center;
474                 points[2].y=upper.top;
475                 points[1].x=points[2].x=upper.left+13;
476                 points[0].x=upper.left+25;
477                 points[2].y+=5;
478                 Polyline (hdc,points,3);
479         }
480  }
481
482   DeleteObject(hnewPen);
483   SelectObject(hdc, hOldPen);
484
485   if ((wndPtr->dwStyle & TVS_HASBUTTONS) && (wndPtr->dwStyle & TVS_HASLINES) && 
486                 (wineItem->cChildren)) {
487                 Rectangle (hdc, xpos-4, center-4, xpos+5, center+5);
488                 MoveToEx (hdc, xpos-2, center, NULL);
489                 LineTo   (hdc, xpos+3, center);
490                 if (!(wineItem->state & TVIS_EXPANDED)) {
491                         MoveToEx (hdc, xpos,   center-2, NULL);
492                         LineTo   (hdc, xpos,   center+3);
493         }
494    }
495
496
497   xpos+=13;
498
499   if (wineItem->mask & (TVIF_IMAGE|TVIF_SELECTEDIMAGE)) {
500
501     himlp=NULL;
502         if (infoPtr->himlNormal) himlp=&infoPtr->himlNormal;
503
504         if ((wineItem->state & TVIS_SELECTED) && (wineItem->iSelectedImage)) {
505                 if (infoPtr->himlState) himlp=&infoPtr->himlState;
506                 if (wineItem->iSelectedImage==I_IMAGECALLBACK) 
507                         TREEVIEW_SendDispInfoNotify (wndPtr, wineItem, 
508                                                                                 TVN_GETDISPINFO, TVIF_SELECTEDIMAGE);
509         } else { /* NOT selected */
510                 if (wineItem->iImage==I_IMAGECALLBACK) 
511                         TREEVIEW_SendDispInfoNotify (wndPtr, wineItem,
512                                                                                 TVN_GETDISPINFO, TVIF_IMAGE);
513         }
514
515         if (himlp) {
516         ImageList_Draw (*himlp, wineItem->iImage, hdc, xpos-2, r.top+1, ILD_NORMAL);
517         ImageList_GetIconSize (*himlp, &cx, &cy);
518         xpos+=cx;
519         }
520  }
521
522
523   r.left=xpos;
524   if ((wineItem->mask & TVIF_TEXT) && (wineItem->pszText)) {
525
526             if (wineItem->state & (TVIS_SELECTED | TVIS_DROPHILITED) ) {
527                 oldBkMode = SetBkMode(hdc, OPAQUE);
528                         oldBkColor= SetBkColor (hdc, GetSysColor( COLOR_HIGHLIGHT));
529                         SetTextColor (hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
530             } else {
531                 oldBkMode = SetBkMode(hdc, TRANSPARENT);
532             }
533         r.left += 3;
534         r.right -= 3;
535                 wineItem->text.left=r.left;
536                 wineItem->text.right=r.right;
537                 if (infoPtr->clrText==-1)
538                 SetTextColor (hdc, COLOR_BTNTEXT);
539                 else 
540                         SetTextColor (hdc, infoPtr->clrText);  /* FIXME: setback retval */
541
542                 if (wineItem->pszText== LPSTR_TEXTCALLBACKA) {
543                         TRACE (treeview,"LPSTR_TEXTCALLBACK\n");
544                         TREEVIEW_SendDispInfoNotify (wndPtr, wineItem, 
545                                                                                         TVN_GETDISPINFO, TVIF_TEXT);
546                 }
547
548         DrawTextA (hdc, wineItem->pszText, lstrlenA(wineItem->pszText), &r, 
549                                                 uTextJustify|DT_VCENTER|DT_SINGLELINE);
550
551         if (oldBkMode != TRANSPARENT)
552             SetBkMode(hdc, oldBkMode);
553             if (wineItem->state & (TVIS_SELECTED | TVIS_DROPHILITED))
554                         SetBkColor (hdc, oldBkColor);
555         }
556
557   if (cditem & CDRF_NOTIFYPOSTPAINT)
558                 TREEVIEW_SendCustomDrawItemNotify (wndPtr, hdc, wineItem, 
559                                                                                         CDDS_ITEMPOSTPAINT);
560
561   SelectObject (hdc, hOldFont);
562 }
563
564
565
566
567
568
569
570 static LRESULT
571 TREEVIEW_GetItemRect (WND *wndPtr, WPARAM wParam, LPARAM lParam)
572 {
573   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
574   TREEVIEW_ITEM *wineItem;
575   HTREEITEM *iItem;
576   LPRECT lpRect;
577
578   TRACE (treeview,"\n");
579   if (infoPtr==NULL) return FALSE;
580
581   if (infoPtr->Timer & TV_REFRESH_TIMER_SET)          
582                 TREEVIEW_Refresh (wndPtr);      /* we want a rect for the current view */
583   
584   iItem = (HTREEITEM *) lParam;
585   wineItem = TREEVIEW_ValidItem (infoPtr, *iItem);
586   if (!wineItem) return FALSE;
587
588   wineItem=& infoPtr->items[ (INT)*iItem ];
589   if (!wineItem->visible) return FALSE; 
590
591   lpRect = (LPRECT)lParam;
592   if (lpRect == NULL) return FALSE;
593         
594   if ((INT) wParam) {
595         lpRect->left    = wineItem->text.left;
596         lpRect->right   = wineItem->text.right;
597         lpRect->bottom  = wineItem->text.bottom;
598         lpRect->top         = wineItem->text.top;
599   } else {
600         lpRect->left    = wineItem->rect.left;
601         lpRect->right   = wineItem->rect.right;
602         lpRect->bottom  = wineItem->rect.bottom;
603         lpRect->top     = wineItem->rect.top;
604   }
605
606   TRACE (treeview,"[L:%d R:%d T:%d B:%d]\n", lpRect->left,lpRect->right,
607                                                                         lpRect->top,lpRect->bottom);
608   return TRUE;
609 }
610
611
612
613 static LRESULT
614 TREEVIEW_GetVisibleCount (WND *wndPtr,  WPARAM wParam, LPARAM lParam)
615
616 {
617   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
618
619   return (LRESULT) infoPtr->uVisibleHeight / infoPtr->uRealItemHeight;
620 }
621
622
623
624 static LRESULT
625 TREEVIEW_SetItemA (WND *wndPtr, WPARAM wParam, LPARAM lParam)
626 {
627   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
628   TREEVIEW_ITEM *wineItem;
629   TVITEMEXA *tvItem;
630   INT iItem,len;
631
632   tvItem=(LPTVITEMEXA) lParam;
633   iItem=(INT)tvItem->hItem;
634   TRACE (treeview,"item %d,mask %x\n",iItem,tvItem->mask);
635
636   wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
637   if (!wineItem) return FALSE;
638
639   if (tvItem->mask & TVIF_CHILDREN) {
640         wineItem->cChildren=tvItem->cChildren;
641   }
642
643   if (tvItem->mask & TVIF_IMAGE) {
644        wineItem->iImage=tvItem->iImage;
645   }
646
647   if (tvItem->mask & TVIF_INTEGRAL) {
648         wineItem->iIntegral=tvItem->iIntegral; 
649         FIXME (treeview," TVIF_INTEGRAL not supported yet\n");
650   }
651
652   if (tvItem->mask & TVIF_PARAM) {
653         wineItem->lParam=tvItem->lParam;
654   }
655
656   if (tvItem->mask & TVIF_SELECTEDIMAGE) {
657         wineItem->iSelectedImage=tvItem->iSelectedImage;
658   }
659
660   if (tvItem->mask & TVIF_STATE) {
661         wineItem->state=tvItem->state & tvItem->stateMask;
662   }
663
664   if (tvItem->mask & TVIF_TEXT) {
665                 if (tvItem->pszText!=LPSTR_TEXTCALLBACKA) {
666         len=lstrlenA (tvItem->pszText);
667         if (len>wineItem->cchTextMax) 
668                         wineItem->pszText= COMCTL32_ReAlloc (wineItem->pszText, len+1);
669         lstrcpynA (wineItem->pszText, tvItem->pszText,len);
670                 } else {
671                         if (wineItem->cchTextMax) {
672                                 COMCTL32_Free (wineItem->pszText);
673                                 wineItem->cchTextMax=0;
674                         }
675                 wineItem->pszText=LPSTR_TEXTCALLBACKA;
676                 }
677    }
678
679   return TRUE;
680 }
681
682
683
684
685
686 static void
687 TREEVIEW_Refresh (WND *wndPtr)
688
689 {
690     TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
691         TEXTMETRICA tm;
692         HBRUSH hbrBk;
693     RECT rect;
694         HDC hdc;
695     INT iItem, indent, x, y, cx, height, itemHeight;
696     INT viewtop,viewbottom,viewleft,viewright;
697     TREEVIEW_ITEM *wineItem, *prevItem;
698
699     TRACE (treeview,"\n");
700
701         hdc=GetDC (wndPtr->hwndSelf);
702
703     if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
704                 KillTimer (wndPtr->hwndSelf, TV_REFRESH_TIMER);
705                 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
706     }
707
708     
709     GetClientRect (wndPtr->hwndSelf, &rect);
710     if ((rect.left-rect.right ==0) || (rect.top-rect.bottom==0)) return;
711
712     infoPtr->cdmode=TREEVIEW_SendCustomDrawNotify 
713                                                 (wndPtr, CDDS_PREPAINT, hdc, rect);
714
715         if (infoPtr->cdmode==CDRF_SKIPDEFAULT) {
716                   ReleaseDC (wndPtr->hwndSelf, hdc);
717                   return;
718         }
719
720         infoPtr->uVisibleHeight= rect.bottom-rect.top;
721         infoPtr->uVisibleWidth= rect.right-rect.left;
722
723     viewtop=infoPtr->cy;
724     viewbottom=infoPtr->cy + rect.bottom-rect.top;
725     viewleft=infoPtr->cx;
726     viewright=infoPtr->cx + rect.right-rect.left;
727
728
729
730     /* draw background */
731     
732     hbrBk = GetSysColorBrush (COLOR_WINDOW);
733     FillRect(hdc, &rect, hbrBk);
734
735
736     iItem=(INT)infoPtr->TopRootItem;
737     infoPtr->firstVisible=0;
738     wineItem=NULL;
739     indent=0;
740     x=y=0;
741     TRACE (treeview, "[%d %d %d %d]\n",viewtop,viewbottom,viewleft,viewright);
742
743     while (iItem) {
744                 prevItem=wineItem;
745         wineItem= & infoPtr->items[iItem];
746                 wineItem->iLevel=indent;
747
748         ImageList_GetIconSize (infoPtr->himlNormal, &cx, &itemHeight);
749         if (infoPtr->uItemHeight>itemHeight)
750                     itemHeight=infoPtr->uItemHeight;
751
752             GetTextMetricsA (hdc, &tm);
753             if ((tm.tmHeight + tm.tmExternalLeading) > itemHeight)
754                      itemHeight=tm.tmHeight + tm.tmExternalLeading;
755
756         infoPtr->uRealItemHeight=itemHeight;    
757
758
759 /* FIXME: remove this in later stage  */
760 /*
761                 if (wineItem->pszText!=LPSTR_TEXTCALLBACK32A) 
762                 TRACE (treeview, "%d %d [%d %d %d %d] (%s)\n",y,x,
763                         wineItem->rect.top, wineItem->rect.bottom,
764                         wineItem->rect.left, wineItem->rect.right,
765                         wineItem->pszText);
766                 else 
767                 TRACE (treeview, "%d [%d %d %d %d] (CALLBACK)\n",
768                                 wineItem->hItem,
769                                 wineItem->rect.top, wineItem->rect.bottom,
770                                 wineItem->rect.left, wineItem->rect.right);
771 */
772
773                 height=itemHeight * wineItem->iIntegral +1;
774                 if ((y >= viewtop) && (y <= viewbottom) &&
775                 (x >= viewleft  ) && (x <= viewright)) {
776                                 wineItem->visible = TRUE;
777                         wineItem->rect.top = y - infoPtr->cy + rect.top;
778                         wineItem->rect.bottom = wineItem->rect.top + height ;
779                         wineItem->rect.left = x - infoPtr->cx + rect.left;
780                         wineItem->rect.right = rect.right;
781                                 wineItem->text.left = wineItem->rect.left;
782                                 wineItem->text.top  = wineItem->rect.top;
783                                 wineItem->text.right= wineItem->rect.right;
784                                 wineItem->text.bottom=wineItem->rect.bottom;
785                         if (!infoPtr->firstVisible)
786                                 infoPtr->firstVisible=wineItem->hItem;
787                 TREEVIEW_DrawItem (wndPtr, hdc, wineItem);
788                 }
789                 else {
790                         wineItem->visible   = FALSE;
791                         wineItem->rect.left = wineItem->rect.top    = 0;
792                         wineItem->rect.right= wineItem->rect.bottom = 0;
793                         wineItem->text.left = wineItem->text.top    = 0;
794                         wineItem->text.right= wineItem->text.bottom = 0;
795                 }
796
797                 /* look up next item */
798         
799                 if ((wineItem->firstChild) && (wineItem->state & TVIS_EXPANDED)) {
800                         iItem=(INT)wineItem->firstChild;
801                         indent++;
802                         x+=infoPtr->uIndent;
803                         if (x>infoPtr->uTotalWidth)     
804                                 infoPtr->uTotalWidth=x;
805                 }
806                 else {
807                         iItem=(INT)wineItem->sibling;
808                         while ((!iItem) && (indent>0)) {
809                                 indent--;
810                                 x-=infoPtr->uIndent;
811                                 prevItem=wineItem;
812                                 wineItem=&infoPtr->items[(INT)wineItem->parent];
813                                 iItem=(INT)wineItem->sibling;
814                         }
815                 }
816         y +=height;
817     }                           /* while */
818
819 /* FIXME: infoPtr->uTotalWidth should also take item label into account */
820 /* FIXME: or should query item sizes (ie check CDRF_NEWFONT) */
821
822     infoPtr->uTotalHeight=y;
823     if (y >= (viewbottom-viewtop)) {
824                 if (!(infoPtr->uInternalStatus & TV_VSCROLL))
825                         ShowScrollBar (wndPtr->hwndSelf, SB_VERT, TRUE);
826                 infoPtr->uInternalStatus |=TV_VSCROLL;
827                 SetScrollRange (wndPtr->hwndSelf, SB_VERT, 0, 
828                                         y - infoPtr->uVisibleHeight, FALSE);
829                 SetScrollPos (wndPtr->hwndSelf, SB_VERT, infoPtr->cy, TRUE);
830         }
831     else {
832                 if (infoPtr->uInternalStatus & TV_VSCROLL) 
833                         ShowScrollBar (wndPtr->hwndSelf, SB_VERT, FALSE);
834                 infoPtr->uInternalStatus &= ~TV_VSCROLL;
835         }
836
837
838         if (infoPtr->cdmode & CDRF_NOTIFYPOSTPAINT) 
839         infoPtr->cdmode=TREEVIEW_SendCustomDrawNotify 
840                                                                 (wndPtr, CDDS_POSTPAINT, hdc, rect);
841
842     ReleaseDC (wndPtr->hwndSelf, hdc);
843     TRACE (treeview,"done\n");
844 }
845
846
847 static LRESULT 
848 TREEVIEW_HandleTimer ( WND *wndPtr, WPARAM wParam, LPARAM lParam)
849 {
850   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
851
852   TRACE (treeview, " %d\n",wParam);
853   if (!infoPtr) return FALSE;
854
855   switch (wParam) {
856         case TV_REFRESH_TIMER:
857                 KillTimer (wndPtr->hwndSelf, TV_REFRESH_TIMER);
858                 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
859                 SendMessageA (wndPtr->hwndSelf, WM_PAINT, 0, 0);
860                 return 0;
861         case TV_EDIT_TIMER:
862                 KillTimer (wndPtr->hwndSelf, TV_EDIT_TIMER);
863                 infoPtr->Timer &= ~TV_EDIT_TIMER_SET;
864                 return 0;
865         default:
866                 ERR (treeview,"got unknown timer\n");
867  }
868                 
869  return 1;
870 }
871
872
873 static void
874 TREEVIEW_QueueRefresh (WND *wndPtr)
875
876 {
877  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
878
879  TRACE (treeview,"\n");
880  if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
881         KillTimer (wndPtr->hwndSelf, TV_REFRESH_TIMER);
882  }
883
884  SetTimer (wndPtr->hwndSelf, TV_REFRESH_TIMER, TV_REFRESH_DELAY, 0);
885  infoPtr->Timer|=TV_REFRESH_TIMER_SET;
886 }
887
888
889
890 static LRESULT
891 TREEVIEW_GetItemA (WND *wndPtr, WPARAM wParam, LPARAM lParam)
892 {
893   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
894   LPTVITEMEXA    tvItem;
895   TREEVIEW_ITEM *wineItem;
896   INT         iItem;
897
898   tvItem=(LPTVITEMEXA) lParam;
899   iItem=(INT)tvItem->hItem;
900   TRACE (treeview,"item %d<%p>, txt %p, img %p, action %x\n", iItem,
901 tvItem, tvItem->pszText, & tvItem->iImage, tvItem->mask);
902
903   wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
904   if (!wineItem) return FALSE;
905
906    if (tvItem->mask & TVIF_CHILDREN) {
907                 if (TVIF_CHILDREN==I_CHILDRENCALLBACK) 
908                         FIXME (treeview,"I_CHILDRENCALLBACK not supported\n");
909         tvItem->cChildren=wineItem->cChildren;
910    }
911
912    if (tvItem->mask & TVIF_HANDLE) {
913         tvItem->hItem=wineItem->hItem;
914    }
915
916    if (tvItem->mask & TVIF_IMAGE) {
917         tvItem->iImage=wineItem->iImage;
918    }
919
920    if (tvItem->mask & TVIF_INTEGRAL) {
921         tvItem->iIntegral=wineItem->iIntegral; 
922                 FIXME (treeview," TVIF_INTEGRAL not supported yet\n");
923    }
924
925    if (tvItem->mask & TVIF_PARAM) {
926         tvItem->lParam=wineItem->lParam;
927    }
928
929    if (tvItem->mask & TVIF_SELECTEDIMAGE) {
930         tvItem->iSelectedImage=wineItem->iSelectedImage;
931    }
932
933    if (tvItem->mask & TVIF_STATE) {
934         tvItem->state=wineItem->state & tvItem->stateMask;
935    }
936
937    if (tvItem->mask & TVIF_TEXT) {
938         if (wineItem->pszText == LPSTR_TEXTCALLBACKA) {
939             tvItem->pszText = LPSTR_TEXTCALLBACKA;  /* FIXME:send notification? */
940                 ERR (treeview," GetItem called with LPSTR_TEXTCALLBACK\n");
941         }
942         else if (wineItem->pszText) {
943             lstrcpynA (tvItem->pszText, wineItem->pszText, tvItem->cchTextMax);
944         }
945    }
946
947   return TRUE;
948 }
949
950
951
952 /* FIXME: check implementation of TVGN_NEXT/TVGN_NEXTVISIBLE */
953
954 static LRESULT
955 TREEVIEW_GetNextItem (WND *wndPtr, WPARAM wParam, LPARAM lParam)
956
957 {
958   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
959   TREEVIEW_ITEM *wineItem, *returnItem;
960   INT iItem, retval, flag;
961
962
963   if (!infoPtr) return FALSE;
964   flag  = (INT) wParam;
965   iItem = (INT) lParam;
966   retval=0;
967   switch (flag) {
968         case TVGN_ROOT: retval=(INT)infoPtr->TopRootItem;
969                                         break;
970         case TVGN_CARET:retval=(INT)infoPtr->selectedItem;
971                                         break;
972         case TVGN_FIRSTVISIBLE: 
973                                 TREEVIEW_Refresh (wndPtr);       
974 /* FIXME:we should only recalculate, not redraw */
975                                         retval=(INT)infoPtr->firstVisible;
976                                         break;
977         case TVGN_DROPHILITE:
978                                         retval=(INT)infoPtr->dropItem;
979                                         break;
980         }
981   if (retval) {
982                 TRACE (treeview,"flags:%x, returns %u\n", flag, retval);
983                 return retval;
984   }
985  
986   wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
987   returnItem = NULL;
988   if (!wineItem) return FALSE;
989
990   switch (flag) {
991         case TVGN_NEXT: retval=(INT)wineItem->sibling;
992                                         break;
993         case TVGN_PREVIOUS:     
994                                         retval=(INT)wineItem->upsibling;
995                                         break;
996         case TVGN_PARENT:
997                                         retval=(INT)wineItem->parent;
998                                         break;
999         case TVGN_CHILD:
1000                                         retval=(INT)wineItem->firstChild;
1001                                         break;
1002         case TVGN_LASTVISIBLE:  
1003                                         returnItem=TREEVIEW_GetLastListItem (infoPtr,wineItem);
1004                                         break;
1005         case TVGN_NEXTVISIBLE:  
1006                                         returnItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
1007                                         break;
1008         case TVGN_PREVIOUSVISIBLE: 
1009                                         returnItem=TREEVIEW_GetPrevListItem (infoPtr, wineItem);
1010                                         break;
1011         default:                FIXME (treeview,"Unknown msg %x,item %x\n", flag,iItem);
1012                                         break;
1013         }
1014
1015   if (returnItem) {
1016                   TRACE (treeview,"flags:%x, item %d;returns %d\n", flag, iItem,
1017                                                         (INT)returnItem->hItem);
1018                   return (INT)returnItem->hItem;
1019   }
1020
1021   TRACE (treeview,"flags:%x, item %d;returns %d\n", flag, iItem,retval);
1022   return retval;
1023 }
1024
1025
1026 static LRESULT
1027 TREEVIEW_GetCount (WND *wndPtr, WPARAM wParam, LPARAM lParam)
1028 {
1029  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1030
1031  TRACE (treeview," %d\n",infoPtr->uNumItems);
1032  return (LRESULT) infoPtr->uNumItems;
1033 }
1034
1035
1036
1037
1038 /* the method used below isn't the most memory-friendly, but it avoids 
1039    a lot of memory reallocations */ 
1040
1041 /* BTW: we waste handle 0; 0 is not an allowed handle. */
1042
1043 static LRESULT
1044 TREEVIEW_InsertItemA (WND *wndPtr, WPARAM wParam, LPARAM lParam)
1045
1046 {
1047   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1048   TVINSERTSTRUCTA  *ptdi;
1049   TVITEMEXA     *tvItem;
1050   TREEVIEW_ITEM *wineItem, *parentItem, *prevsib, *sibItem;
1051   INT           iItem,listItems,i,len;
1052   
1053   ptdi = (LPTVINSERTSTRUCTA) lParam;
1054
1055         /* check if memory is available */
1056
1057   if (infoPtr->uNumPtrsAlloced==0) {
1058         infoPtr->items = COMCTL32_Alloc (TVITEM_ALLOC*sizeof (TREEVIEW_ITEM));
1059         infoPtr->freeList= COMCTL32_Alloc ((1+(TVITEM_ALLOC>>5)) * sizeof (INT));
1060         infoPtr->uNumPtrsAlloced=TVITEM_ALLOC;
1061         infoPtr->TopRootItem=(HTREEITEM)1;
1062    }
1063
1064   if (infoPtr->uNumItems == (infoPtr->uNumPtrsAlloced-1) ) {
1065         TREEVIEW_ITEM *oldItems = infoPtr->items;
1066         INT *oldfreeList = infoPtr->freeList;
1067
1068         infoPtr->uNumPtrsAlloced*=2;
1069     infoPtr->items = COMCTL32_Alloc (infoPtr->uNumPtrsAlloced*sizeof (TREEVIEW_ITEM));
1070     infoPtr->freeList= COMCTL32_Alloc ((1+(infoPtr->uNumPtrsAlloced>>5))*sizeof (INT));
1071
1072     memcpy (&infoPtr->items[0], &oldItems[0],
1073                     infoPtr->uNumPtrsAlloced/2 * sizeof(TREEVIEW_ITEM));
1074     memcpy (&infoPtr->freeList[0], &oldfreeList[0],
1075                     infoPtr->uNumPtrsAlloced>>6 * sizeof(INT));
1076
1077     COMCTL32_Free (oldItems);  
1078     COMCTL32_Free (oldfreeList);  
1079    }
1080
1081   iItem=0;
1082   infoPtr->uNumItems++;
1083
1084   if ((INT)infoPtr->uMaxHandle==(infoPtr->uNumItems-1))  { 
1085         iItem=infoPtr->uNumItems;
1086         infoPtr->uMaxHandle = (HTREEITEM)((INT)infoPtr->uMaxHandle + 1);
1087   } else {                                       /* check freelist */
1088         for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++) {
1089                 if (infoPtr->freeList[i]) {
1090                         iItem=ffs (infoPtr->freeList[i])-1;
1091                         tv_clear_bit(iItem,&infoPtr->freeList[i]);
1092                         iItem+=i<<5;
1093                         break;
1094                 }
1095          } 
1096   }
1097  
1098  for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++) 
1099         TRACE (treeview,"%8x\n",infoPtr->freeList[i]);
1100
1101   if (!iItem) ERR (treeview, "Argh -- can't find free item.\n");
1102   
1103   tvItem= & ptdi->DUMMYUNIONNAME.itemex;
1104   wineItem=& infoPtr->items[iItem];
1105
1106   if ((ptdi->hParent==TVI_ROOT) || (ptdi->hParent==0)) {
1107         parentItem=NULL;
1108         wineItem->parent=0; 
1109         sibItem=&infoPtr->items [(INT)infoPtr->TopRootItem];
1110         listItems=infoPtr->uNumItems;
1111   }
1112   else  {
1113         parentItem= &infoPtr->items[(INT)ptdi->hParent];
1114         if (!parentItem->firstChild) 
1115                 parentItem->firstChild=(HTREEITEM)iItem;
1116         wineItem->parent=ptdi->hParent;
1117         sibItem=&infoPtr->items [(INT)parentItem->firstChild];
1118         parentItem->cChildren++;
1119         listItems=parentItem->cChildren;
1120   }
1121
1122   wineItem->upsibling=0;  /* needed in case we're the first item in a list */ 
1123   wineItem->sibling=0;     
1124   wineItem->firstChild=0;
1125   wineItem->hItem=(HTREEITEM)iItem;
1126
1127   if (listItems>1) {
1128      prevsib=NULL;
1129      switch ((INT)ptdi->hInsertAfter) {
1130                 case TVI_FIRST: 
1131                         if (wineItem->parent) {
1132                                 wineItem->sibling=parentItem->firstChild;
1133                                 parentItem->firstChild=(HTREEITEM)iItem;
1134                         } else {
1135                                 wineItem->sibling=infoPtr->TopRootItem;
1136                                 infoPtr->TopRootItem=(HTREEITEM)iItem;
1137                         }
1138                         sibItem->upsibling=(HTREEITEM)iItem;
1139                         break;
1140                 case TVI_LAST:  
1141                         if (sibItem==wineItem) break;
1142                         while (sibItem->sibling) {
1143                                 prevsib=sibItem;
1144                                 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1145                         }
1146                         sibItem->sibling=(HTREEITEM)iItem;
1147                         wineItem->upsibling=sibItem->hItem;
1148                         break;
1149                 case TVI_SORT:  
1150                         FIXME (treeview, "Sorted insert not implemented yet\n");
1151                         break;
1152                 default:
1153                         while ((sibItem->sibling) && (sibItem->hItem!=ptdi->hInsertAfter))
1154                                 {
1155                                 prevsib=sibItem;
1156                 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1157               }
1158                         if (sibItem->hItem!=ptdi->hInsertAfter) {
1159                          ERR (treeview, "tried to insert item after nonexisting handle.\n");
1160                          break;
1161                         }
1162                         prevsib=sibItem;
1163                         if (sibItem->sibling) {
1164                 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1165                                 sibItem->upsibling=(HTREEITEM)iItem;
1166                                 wineItem->sibling=sibItem->hItem;
1167                         }
1168                         prevsib->sibling=(HTREEITEM)iItem;
1169                         wineItem->upsibling=prevsib->hItem;
1170                         break;
1171         }
1172    }    
1173
1174
1175 /* Fill in info structure */
1176
1177    TRACE (treeview,"new item %d; parent %d, mask %x\n", iItem, 
1178                         (INT)wineItem->parent,tvItem->mask);
1179
1180    wineItem->mask=tvItem->mask;
1181    wineItem->iIntegral=1; 
1182
1183    if (tvItem->mask & TVIF_CHILDREN) {
1184          wineItem->cChildren=tvItem->cChildren;
1185          if (tvItem->cChildren==I_CHILDRENCALLBACK) 
1186                         FIXME (treeview," I_CHILDRENCALLBACK not supported\n");
1187         }
1188
1189
1190    if (tvItem->mask & TVIF_IMAGE) 
1191         wineItem->iImage=tvItem->iImage;
1192
1193                 /* If the application sets TVIF_INTEGRAL without
1194                         supplying a TVITEMEX structure, it's toast */
1195
1196    if (tvItem->mask & TVIF_INTEGRAL) 
1197                 wineItem->iIntegral=tvItem->iIntegral;   
1198
1199    if (tvItem->mask & TVIF_PARAM) 
1200         wineItem->lParam=tvItem->lParam;
1201
1202    if (tvItem->mask & TVIF_SELECTEDIMAGE) 
1203         wineItem->iSelectedImage=tvItem->iSelectedImage;
1204
1205    if (tvItem->mask & TVIF_STATE) {
1206         wineItem->state=tvItem->state;
1207         wineItem->stateMask=tvItem->stateMask;
1208    }
1209
1210    if (tvItem->mask & TVIF_TEXT) {
1211         if (tvItem->pszText!=LPSTR_TEXTCALLBACKA) {
1212                 TRACE (treeview,"(%p,%s)\n", &tvItem->pszText, tvItem->pszText); 
1213                 len = lstrlenA (tvItem->pszText)+1;
1214                 wineItem->pszText= COMCTL32_Alloc (len+1);
1215                 lstrcpyA (wineItem->pszText, tvItem->pszText);
1216                 wineItem->cchTextMax=len;
1217         }
1218         else {
1219                 TRACE (treeview,"LPSTR_TEXTCALLBACK\n");
1220             wineItem->pszText = LPSTR_TEXTCALLBACKA;
1221             wineItem->cchTextMax = 0;
1222         }
1223    }
1224
1225    TREEVIEW_QueueRefresh (wndPtr);
1226
1227    return (LRESULT) iItem;
1228 }
1229
1230
1231
1232
1233
1234 static LRESULT
1235 TREEVIEW_DeleteItem (WND *wndPtr, WPARAM wParam, LPARAM lParam)
1236 {
1237   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1238   INT iItem;
1239   TREEVIEW_ITEM *wineItem;
1240
1241   TRACE (treeview,"\n");
1242   if (!infoPtr) return FALSE;
1243
1244   if (lParam == (INT)TVI_ROOT) {
1245         TREEVIEW_RemoveTree (wndPtr);
1246   } else {
1247         iItem= (INT) lParam;
1248         wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1249         if (!wineItem) return FALSE;
1250     TRACE (treeview,"%s\n",wineItem->pszText);
1251         TREEVIEW_RemoveItem (wndPtr, wineItem);
1252   }
1253
1254   TREEVIEW_QueueRefresh (wndPtr);
1255
1256   return TRUE;
1257 }
1258
1259
1260
1261 static LRESULT
1262 TREEVIEW_GetIndent (WND *wndPtr)
1263 {
1264  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1265
1266  TRACE (treeview,"\n");
1267  return infoPtr->uIndent;
1268 }
1269
1270 static LRESULT
1271 TREEVIEW_SetIndent (WND *wndPtr, WPARAM wParam)
1272 {
1273   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1274   INT newIndent;
1275    
1276   TRACE (treeview,"\n");
1277   newIndent=(INT) wParam;
1278   if (newIndent < MINIMUM_INDENT) newIndent=MINIMUM_INDENT;
1279   infoPtr->uIndent=newIndent;
1280   
1281   return 0;
1282 }
1283
1284 static LRESULT
1285 TREEVIEW_GetToolTips (WND *wndPtr)
1286
1287 {
1288  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1289
1290  TRACE (treeview,"\n");
1291  return infoPtr->hwndToolTip;
1292 }
1293
1294
1295 static LRESULT
1296 TREEVIEW_SetToolTips (WND *wndPtr, WPARAM wParam)
1297
1298 {
1299  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1300  HWND prevToolTip;
1301
1302  TRACE (treeview,"\n");
1303  prevToolTip=infoPtr->hwndToolTip;
1304  infoPtr->hwndToolTip= (HWND) wParam;
1305
1306  return prevToolTip;
1307 }
1308
1309
1310 LRESULT CALLBACK
1311 TREEVIEW_GetEditControl (WND *wndPtr)
1312
1313 {
1314  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1315
1316  return infoPtr->hwndEdit;
1317 }
1318
1319 LRESULT CALLBACK
1320 TREEVIEW_Edit_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, 
1321                                                         LPARAM lParam)
1322 {
1323   switch (uMsg) {
1324    case WM_ERASEBKGND: {
1325            RECT rc;
1326            HDC  hdc = (HDC) wParam;
1327            GetClientRect (hwnd, &rc);
1328            Rectangle (hdc, rc.left, rc.top, rc.right, rc.bottom);
1329            return -1;
1330                 }
1331    case WM_GETDLGCODE:
1332             return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
1333    default:
1334                          return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1335   }
1336   return 0;
1337 }
1338
1339
1340 /* should handle edit control messages here */
1341
1342 static LRESULT
1343 TREEVIEW_Command (WND *wndPtr, WPARAM wParam, LPARAM lParam)
1344
1345 {
1346   TRACE (treeview, "%x %ld\n",wParam, lParam);
1347  
1348   switch (HIWORD(wParam)) {
1349                 case EN_UPDATE:
1350                          FIXME (treeview, "got EN_UPDATE.\n");
1351                          break;
1352                 case EN_KILLFOCUS:
1353                          FIXME (treeview, "got EN_KILLFOCUS.\n");
1354                          break;
1355                 default:
1356                          return SendMessageA (GetParent (wndPtr->hwndSelf), 
1357                                                                                 WM_COMMAND, wParam, lParam);
1358         }
1359  return 0;
1360 }
1361
1362
1363
1364
1365 static LRESULT
1366 TREEVIEW_Size (WND *wndPtr, WPARAM wParam, LPARAM lParam)
1367
1368 {
1369   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1370   RECT parent_rect;
1371   UINT  cx,cy;
1372   HWND parent;
1373
1374   if (infoPtr->bAutoSize) {
1375     infoPtr->bAutoSize = FALSE;
1376     return 0;
1377     }
1378     infoPtr->bAutoSize = TRUE;
1379
1380     if (!wParam)  {
1381     parent = GetParent (wndPtr->hwndSelf);
1382     GetClientRect(parent, &parent_rect);
1383     cx=LOWORD (lParam);
1384         cy=HIWORD (lParam);
1385         SetWindowPos (wndPtr->hwndSelf, 0, parent_rect.left, parent_rect.top, 
1386                         cx, cy, SWP_NOZORDER);
1387    } else {
1388         FIXME (treeview,"WM_SIZE flag %x %lx not handled\n", wParam, lParam);
1389   }
1390
1391   TREEVIEW_QueueRefresh (wndPtr);
1392   return 0;
1393 }
1394
1395
1396
1397 static LRESULT
1398 TREEVIEW_StyleChanged (WND *wndPtr, WPARAM wParam, LPARAM lParam)
1399 {
1400   LPSTYLESTRUCT lpss=(LPSTYLESTRUCT) lParam;
1401
1402   TRACE (treeview,"(%x %lx)\n",wParam,lParam);
1403   
1404   if (wParam & (GWL_STYLE)) 
1405         wndPtr->dwStyle=lpss->styleNew;
1406   if (wParam & (GWL_EXSTYLE)) 
1407         wndPtr->dwExStyle=lpss->styleNew;
1408
1409   return 0;
1410 }
1411
1412 static LRESULT
1413 TREEVIEW_Create (WND *wndPtr, WPARAM wParam, LPARAM lParam)
1414 {
1415     TREEVIEW_INFO *infoPtr;
1416         LOGFONTA logFont;
1417     TEXTMETRICA tm;
1418         HDC hdc;
1419   
1420     TRACE (treeview,"wnd %x\n",wndPtr->hwndSelf);
1421       /* allocate memory for info structure */
1422       infoPtr = (TREEVIEW_INFO *) COMCTL32_Alloc (sizeof(TREEVIEW_INFO));
1423
1424     wndPtr->wExtra[0] = (DWORD)infoPtr;
1425
1426     if (infoPtr == NULL) {
1427                 ERR (treeview, "could not allocate info memory!\n");
1428                 return 0;
1429     }
1430
1431     if ((TREEVIEW_INFO*)wndPtr->wExtra[0] != infoPtr) {
1432                 ERR (treeview, "pointer assignment error!\n");
1433                 return 0;
1434     }
1435
1436         hdc=GetDC (wndPtr->hwndSelf);
1437
1438     /* set default settings */
1439     infoPtr->uInternalStatus=0;
1440     infoPtr->uNumItems=0;
1441     infoPtr->clrBk = GetSysColor (COLOR_WINDOW);
1442     infoPtr->clrText = GetSysColor (COLOR_BTNTEXT);
1443     infoPtr->cy = 0;
1444     infoPtr->cx = 0;
1445     infoPtr->uIndent = 15;
1446     infoPtr->himlNormal = NULL;
1447     infoPtr->himlState = NULL;
1448         infoPtr->uItemHeight = -1;
1449     GetTextMetricsA (hdc, &tm);
1450     infoPtr->hFont = GetStockObject (DEFAULT_GUI_FONT);
1451         GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
1452         logFont.lfWeight=FW_BOLD;
1453     infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
1454     
1455     infoPtr->items = NULL;
1456     infoPtr->selectedItem=0;
1457     infoPtr->clrText=-1;        /* use system color */
1458     infoPtr->dropItem=0;
1459
1460 /*
1461     infoPtr->hwndNotify = GetParent32 (wndPtr->hwndSelf);
1462     infoPtr->bTransparent = (wndPtr->dwStyle & TBSTYLE_FLAT);
1463 */
1464
1465         infoPtr->hwndToolTip=0;
1466     if (!(wndPtr->dwStyle & TVS_NOTOOLTIPS)) {   /* Create tooltip control */
1467                 TTTOOLINFOA ti;
1468
1469                 infoPtr->hwndToolTip =  
1470                         CreateWindowExA (0, TOOLTIPS_CLASSA, NULL, 0,
1471                    CW_USEDEFAULT, CW_USEDEFAULT,
1472                    CW_USEDEFAULT, CW_USEDEFAULT,
1473                    wndPtr->hwndSelf, 0, 0, 0);
1474
1475         /* Send NM_TOOLTIPSCREATED notification */
1476         if (infoPtr->hwndToolTip) {
1477             NMTOOLTIPSCREATED nmttc;
1478
1479             nmttc.hdr.hwndFrom = wndPtr->hwndSelf;
1480             nmttc.hdr.idFrom = wndPtr->wIDmenu;
1481             nmttc.hdr.code = NM_TOOLTIPSCREATED;
1482             nmttc.hwndToolTips = infoPtr->hwndToolTip;
1483
1484             SendMessageA (GetParent (wndPtr->hwndSelf), WM_NOTIFY,
1485                 (WPARAM)wndPtr->wIDmenu, (LPARAM)&nmttc);
1486         }
1487
1488                 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
1489         ti.cbSize   = sizeof(TTTOOLINFOA);
1490         ti.uFlags   = TTF_IDISHWND | TTF_TRACK | TTF_TRANSPARENT ;
1491         ti.hwnd     = wndPtr->hwndSelf;
1492         ti.uId      = 0;
1493         ti.lpszText = "Test"; /* LPSTR_TEXTCALLBACK; */
1494         SetRectEmpty (&ti.rect);
1495
1496         SendMessageA (infoPtr->hwndToolTip, TTM_ADDTOOLA, 0, (LPARAM)&ti);
1497     }
1498
1499
1500         infoPtr->hwndEdit = CreateWindowExA ( 0, "EDIT",NULL,
1501                  WS_CHILD | WS_BORDER | ES_AUTOHSCROLL | ES_WANTRETURN,
1502                  0, 0, 0, 0,
1503                  wndPtr->hwndSelf, 0,0,0);
1504                                 /* FIXME:   (HMENU)IDTVEDIT, pcs->hInstance, 0); */
1505
1506     SendMessageA ( infoPtr->hwndEdit, WM_SETFONT, infoPtr->hFont, FALSE);
1507         infoPtr->wpEditOrig= (WNDPROC)
1508                     SetWindowLongA (infoPtr->hwndEdit,GWL_WNDPROC, 
1509                                         (LONG) TREEVIEW_Edit_SubclassProc);
1510
1511     ReleaseDC (wndPtr->hwndSelf, hdc);
1512
1513     return 0;
1514 }
1515
1516
1517
1518 static LRESULT 
1519 TREEVIEW_Destroy (WND *wndPtr) 
1520 {
1521    TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1522      
1523    TRACE (treeview,"\n");
1524    TREEVIEW_RemoveTree (wndPtr);
1525    if (infoPtr->Timer & TV_REFRESH_TIMER_SET) 
1526         KillTimer (wndPtr->hwndSelf, TV_REFRESH_TIMER);
1527    if (infoPtr->hwndToolTip) 
1528                 DestroyWindow (infoPtr->hwndToolTip);
1529
1530    COMCTL32_Free (infoPtr);
1531    return 0;
1532 }
1533
1534
1535 static LRESULT
1536 TREEVIEW_Paint (WND *wndPtr, WPARAM wParam, LPARAM lParam)
1537 {
1538     HDC hdc;
1539     PAINTSTRUCT ps;
1540
1541     TRACE (treeview,"\n");
1542     hdc = wParam==0 ? BeginPaint (wndPtr->hwndSelf, &ps) : (HDC)wParam;
1543     TREEVIEW_Refresh (wndPtr);
1544     if(!wParam)
1545         EndPaint (wndPtr->hwndSelf, &ps);
1546     TRACE (treeview,"done\n");
1547       
1548     return DefWindowProcA (wndPtr->hwndSelf, WM_PAINT, wParam, lParam);
1549 }
1550
1551 static LRESULT
1552 TREEVIEW_SetFocus (WND *wndPtr, WPARAM wParam, LPARAM lParam)
1553 {
1554    TREEVIEW_SendSimpleNotify (wndPtr, NM_SETFOCUS);
1555    SendMessageA (wndPtr->hwndSelf, WM_PAINT, 0, 0);
1556    return 0;
1557 }
1558
1559 static LRESULT
1560 TREEVIEW_KillFocus (WND *wndPtr, WPARAM wParam, LPARAM lParam)
1561 {
1562    TREEVIEW_SendSimpleNotify (wndPtr, NM_KILLFOCUS);
1563    SendMessageA (wndPtr->hwndSelf, WM_PAINT, 0, 0);
1564    return 0;
1565 }
1566
1567 static LRESULT
1568 TREEVIEW_EraseBackground (WND *wndPtr, WPARAM wParam, LPARAM lParam)
1569 {
1570     TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1571     HBRUSH hBrush = CreateSolidBrush (infoPtr->clrBk);
1572     RECT rect;
1573
1574     TRACE (treeview,"\n");
1575     GetClientRect (wndPtr->hwndSelf, &rect);
1576     FillRect ((HDC)wParam, &rect, hBrush);
1577     DeleteObject (hBrush);
1578     return TRUE;
1579 }
1580
1581
1582
1583
1584
1585   
1586 /* Notifications */
1587
1588   
1589
1590
1591
1592 static BOOL
1593 TREEVIEW_SendSimpleNotify (WND *wndPtr, UINT code)
1594 {
1595     NMHDR nmhdr;
1596
1597     TRACE (treeview, "%x\n",code);
1598     nmhdr.hwndFrom = wndPtr->hwndSelf;
1599     nmhdr.idFrom   = wndPtr->wIDmenu;
1600     nmhdr.code     = code;
1601
1602     return (BOOL) SendMessageA (GetParent (wndPtr->hwndSelf), WM_NOTIFY,
1603                                    (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
1604 }
1605
1606
1607
1608 static BOOL
1609 TREEVIEW_SendTreeviewNotify (WND *wndPtr, UINT code, UINT action, 
1610                         HTREEITEM oldItem, HTREEITEM newItem)
1611
1612 {
1613   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1614   NMTREEVIEWA nmhdr;
1615   TREEVIEW_ITEM  *wineItem;
1616
1617   TRACE (treeview,"code:%x action:%x olditem:%x newitem:%x\n",
1618                   code,action,(INT)oldItem,(INT)newItem);
1619   nmhdr.hdr.hwndFrom = wndPtr->hwndSelf;
1620   nmhdr.hdr.idFrom = wndPtr->wIDmenu;
1621   nmhdr.hdr.code = code;
1622   nmhdr.action = action;
1623   if (oldItem) {
1624         wineItem=& infoPtr->items[(INT)oldItem];
1625         nmhdr.itemOld.mask              = wineItem->mask;
1626         nmhdr.itemOld.hItem             = wineItem->hItem;
1627         nmhdr.itemOld.state             = wineItem->state;
1628         nmhdr.itemOld.stateMask = wineItem->stateMask;
1629         nmhdr.itemOld.iImage    = wineItem->iImage;
1630         nmhdr.itemOld.pszText   = wineItem->pszText;
1631         nmhdr.itemOld.cchTextMax= wineItem->cchTextMax;
1632         nmhdr.itemOld.iImage    = wineItem->iImage;
1633         nmhdr.itemOld.iSelectedImage    = wineItem->iSelectedImage;
1634         nmhdr.itemOld.cChildren = wineItem->cChildren;
1635         nmhdr.itemOld.lParam    = wineItem->lParam;
1636   }
1637
1638   if (newItem) {
1639         wineItem=& infoPtr->items[(INT)newItem];
1640         nmhdr.itemNew.mask              = wineItem->mask;
1641         nmhdr.itemNew.hItem             = wineItem->hItem;
1642         nmhdr.itemNew.state             = wineItem->state;
1643         nmhdr.itemNew.stateMask = wineItem->stateMask;
1644         nmhdr.itemNew.iImage    = wineItem->iImage;
1645         nmhdr.itemNew.pszText   = wineItem->pszText;
1646         nmhdr.itemNew.cchTextMax= wineItem->cchTextMax;
1647         nmhdr.itemNew.iImage    = wineItem->iImage;
1648         nmhdr.itemNew.iSelectedImage    = wineItem->iSelectedImage;
1649         nmhdr.itemNew.cChildren = wineItem->cChildren;
1650         nmhdr.itemNew.lParam    = wineItem->lParam;
1651   }
1652
1653   nmhdr.ptDrag.x = 0;
1654   nmhdr.ptDrag.y = 0;
1655
1656   return (BOOL)SendMessageA (GetParent (wndPtr->hwndSelf), WM_NOTIFY,
1657                                    (WPARAM)wndPtr->wIDmenu, (LPARAM)&nmhdr);
1658
1659 }
1660
1661 static BOOL
1662 TREEVIEW_SendTreeviewDnDNotify (WND *wndPtr, UINT code, HTREEITEM dragItem, 
1663                                                                 POINT pt)
1664 {
1665   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1666   NMTREEVIEWA nmhdr;
1667   TREEVIEW_ITEM  *wineItem;
1668
1669   TRACE (treeview,"code:%x dragitem:%x\n", code,(INT)dragItem);
1670
1671   nmhdr.hdr.hwndFrom = wndPtr->hwndSelf;
1672   nmhdr.hdr.idFrom = wndPtr->wIDmenu;
1673   nmhdr.hdr.code = code;
1674   nmhdr.action = 0;
1675   wineItem=& infoPtr->items[(INT)dragItem];
1676   nmhdr.itemNew.mask    = wineItem->mask;
1677   nmhdr.itemNew.hItem   = wineItem->hItem;
1678   nmhdr.itemNew.state   = wineItem->state;
1679   nmhdr.itemNew.lParam  = wineItem->lParam;
1680
1681   nmhdr.ptDrag.x = pt.x;
1682   nmhdr.ptDrag.y = pt.y;
1683
1684   return (BOOL)SendMessageA (GetParent (wndPtr->hwndSelf), WM_NOTIFY,
1685                                    (WPARAM)wndPtr->wIDmenu, (LPARAM)&nmhdr);
1686
1687 }
1688
1689
1690
1691 static BOOL
1692 TREEVIEW_SendDispInfoNotify (WND *wndPtr, TREEVIEW_ITEM *wineItem, 
1693                                                                 UINT code, UINT what)
1694 {
1695   NMTVDISPINFOA tvdi;
1696   BOOL retval;
1697   char *buf;
1698
1699   TRACE (treeview,"item %d, action %x\n",(INT)wineItem->hItem,what);
1700
1701   tvdi.hdr.hwndFrom     = wndPtr->hwndSelf;
1702   tvdi.hdr.idFrom       = wndPtr->wIDmenu;
1703   tvdi.hdr.code         = code;
1704   tvdi.item.mask        = what;
1705   tvdi.item.hItem       = wineItem->hItem;
1706   tvdi.item.state       = wineItem->state;
1707   tvdi.item.lParam      = wineItem->lParam;
1708   tvdi.item.pszText = COMCTL32_Alloc (128*sizeof(char));
1709   buf = tvdi.item.pszText;
1710   retval=(BOOL)SendMessageA (GetParent (wndPtr->hwndSelf), WM_NOTIFY,
1711                                    (WPARAM)wndPtr->wIDmenu, (LPARAM)&tvdi);
1712   if (what & TVIF_TEXT) {
1713                 wineItem->pszText        = tvdi.item.pszText;
1714                 if (buf==tvdi.item.pszText) {
1715                         wineItem->cchTextMax = 128;
1716                 } else { 
1717                         TRACE (treeview,"user-supplied buffer\n");
1718                         COMCTL32_Free (buf);
1719                         wineItem->cchTextMax = 0;
1720                 }
1721         }
1722   if (what & TVIF_SELECTEDIMAGE) 
1723                 wineItem->iSelectedImage = tvdi.item.iSelectedImage;
1724   if (what & TVIF_IMAGE) 
1725                 wineItem->iImage         = tvdi.item.iImage;
1726   if (what & TVIF_CHILDREN) 
1727                 wineItem->cChildren      = tvdi.item.cChildren;
1728
1729  return retval;
1730 }
1731
1732
1733
1734 static BOOL
1735 TREEVIEW_SendCustomDrawNotify (WND *wndPtr, DWORD dwDrawStage, HDC hdc,
1736                         RECT rc)
1737 {
1738   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1739   NMTVCUSTOMDRAW nmcdhdr;
1740   LPNMCUSTOMDRAW nmcd;
1741
1742   TRACE (treeview,"drawstage:%lx hdc:%x\n", dwDrawStage, hdc);
1743
1744   nmcd= & nmcdhdr.nmcd;
1745   nmcd->hdr.hwndFrom = wndPtr->hwndSelf;
1746   nmcd->hdr.idFrom = wndPtr->wIDmenu;
1747   nmcd->hdr.code   = NM_CUSTOMDRAW;
1748   nmcd->dwDrawStage= dwDrawStage;
1749   nmcd->hdc                = hdc;
1750   nmcd->rc.left    = rc.left;
1751   nmcd->rc.right   = rc.right;
1752   nmcd->rc.bottom  = rc.bottom;
1753   nmcd->rc.top     = rc.top;
1754   nmcd->dwItemSpec = 0;
1755   nmcd->uItemState = 0;
1756   nmcd->lItemlParam= 0;
1757   nmcdhdr.clrText  = infoPtr->clrText;
1758   nmcdhdr.clrTextBk= infoPtr->clrBk;
1759   nmcdhdr.iLevel   = 0;
1760
1761   return (BOOL)SendMessageA (GetParent (wndPtr->hwndSelf), WM_NOTIFY,
1762                                (WPARAM)wndPtr->wIDmenu, (LPARAM)&nmcdhdr);
1763
1764 }
1765
1766
1767
1768 /* FIXME: need to find out when the flags in uItemState need to be set */
1769
1770 static BOOL
1771 TREEVIEW_SendCustomDrawItemNotify (WND *wndPtr, HDC hdc,
1772                         TREEVIEW_ITEM *wineItem, UINT uItemDrawState)
1773 {
1774  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1775  NMTVCUSTOMDRAW nmcdhdr;
1776  LPNMCUSTOMDRAW nmcd;
1777  DWORD dwDrawStage,dwItemSpec;
1778  UINT uItemState;
1779  
1780  dwDrawStage=CDDS_ITEM | uItemDrawState;
1781  dwItemSpec=(DWORD)wineItem->hItem;
1782  uItemState=0;
1783  if (wineItem->hItem==infoPtr->selectedItem) uItemState|=CDIS_SELECTED;
1784  if (wineItem->hItem==infoPtr->focusItem)        uItemState|=CDIS_FOCUS;
1785  if (wineItem->hItem==infoPtr->hotItem)      uItemState|=CDIS_HOT;
1786
1787  nmcd= & nmcdhdr.nmcd;
1788  nmcd->hdr.hwndFrom = wndPtr->hwndSelf;
1789  nmcd->hdr.idFrom = wndPtr->wIDmenu;
1790  nmcd->hdr.code   = NM_CUSTOMDRAW;
1791  nmcd->dwDrawStage= dwDrawStage;
1792  nmcd->hdc                = hdc;
1793  nmcd->rc.left    = wineItem->rect.left;
1794  nmcd->rc.right   = wineItem->rect.right;
1795  nmcd->rc.bottom  = wineItem->rect.bottom;
1796  nmcd->rc.top     = wineItem->rect.top;
1797  nmcd->dwItemSpec = dwItemSpec;
1798  nmcd->uItemState = uItemState;
1799  nmcd->lItemlParam= wineItem->lParam;
1800
1801  nmcdhdr.clrText  = infoPtr->clrText;
1802  nmcdhdr.clrTextBk= infoPtr->clrBk;
1803  nmcdhdr.iLevel   = wineItem->iLevel;
1804
1805  TRACE (treeview,"drawstage:%lx hdc:%x item:%lx, itemstate:%x\n",
1806                   dwDrawStage, hdc, dwItemSpec, uItemState);
1807
1808  return (BOOL)SendMessageA (GetParent (wndPtr->hwndSelf), WM_NOTIFY,
1809                                (WPARAM)wndPtr->wIDmenu, (LPARAM)&nmcdhdr);
1810 }
1811
1812
1813
1814 /* Note:If the specified item is the child of a collapsed parent item,
1815    the parent's list of child items is (recursively) expanded to reveal the 
1816    specified item. This is mentioned for TREEVIEW_SelectItem; don't 
1817    know if it also applies here.
1818 */
1819
1820
1821 static LRESULT
1822 TREEVIEW_Expand (WND *wndPtr, WPARAM wParam, LPARAM lParam)
1823 {
1824  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1825  TREEVIEW_ITEM *wineItem, *parentItem;
1826  UINT flag;
1827  INT expand;
1828  
1829  flag= (UINT) wParam;
1830  expand= (INT) lParam;
1831  TRACE (treeview,"flags:%x item:%x\n", expand, wParam);
1832  wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
1833  if (!wineItem) return 0;
1834  if (!wineItem->cChildren) return 0;
1835
1836  if (wineItem->cChildren==I_CHILDRENCALLBACK) {
1837                 FIXME (treeview,"we don't handle I_CHILDRENCALLBACK yet\n");
1838                 return 0;
1839  }
1840
1841  if (flag & TVE_TOGGLE) {               /* FIXME: check exact behaviour here */
1842         flag &= ~TVE_TOGGLE;            /* ie: bitwise ops or 'case' ops */
1843         if (wineItem->state & TVIS_EXPANDED) 
1844                 flag |= TVE_COLLAPSE;
1845         else
1846                 flag |= TVE_EXPAND;
1847  }
1848
1849  switch (flag) {
1850     case TVE_COLLAPSERESET: 
1851                 if (!wineItem->state & TVIS_EXPANDED) return 0;
1852                 wineItem->state &= ~(TVIS_EXPANDEDONCE | TVIS_EXPANDED);
1853                 TREEVIEW_RemoveAllChildren (wndPtr, wineItem);
1854                 break;
1855
1856     case TVE_COLLAPSE: 
1857                 if (!wineItem->state & TVIS_EXPANDED) return 0;
1858                 wineItem->state &= ~TVIS_EXPANDED;
1859                 break;
1860
1861     case TVE_EXPAND: 
1862                 if (wineItem->state & TVIS_EXPANDED) return 0;
1863                 if (wineItem->parent) {
1864                                 parentItem=TREEVIEW_ValidItem(infoPtr,wineItem->parent);
1865                                 TREEVIEW_Expand (wndPtr, wParam, (LPARAM) wineItem->parent);
1866                 }
1867                 if (!(wineItem->state & TVIS_EXPANDEDONCE)) {
1868                 if (TREEVIEW_SendTreeviewNotify (wndPtr, TVN_ITEMEXPANDING, 
1869                                                                                         0, 0, (HTREEITEM)expand))
1870                                         return FALSE;   /* FIXME: OK? */
1871             wineItem->state |= TVIS_EXPANDED | TVIS_EXPANDEDONCE;
1872                 TREEVIEW_SendTreeviewNotify (wndPtr, TVN_ITEMEXPANDED, 
1873                                          0, 0, (HTREEITEM)expand);
1874         }
1875         wineItem->state |= TVIS_EXPANDED;
1876         break;
1877    case TVE_EXPANDPARTIAL:
1878                 FIXME (treeview, "TVE_EXPANDPARTIAL not implemented\n");
1879                 wineItem->state ^=TVIS_EXPANDED;
1880                 wineItem->state |=TVIS_EXPANDEDONCE;
1881                 break;
1882   }
1883  
1884  TREEVIEW_QueueRefresh (wndPtr);
1885
1886  return TRUE;
1887 }
1888
1889
1890
1891
1892
1893 static TREEVIEW_ITEM *
1894 TREEVIEW_HitTestPoint (WND *wndPtr, POINT pt)
1895 {
1896  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1897  TREEVIEW_ITEM *wineItem;
1898  RECT rect;
1899
1900  GetClientRect (wndPtr->hwndSelf, &rect);
1901
1902  if (!infoPtr->firstVisible) return NULL;
1903
1904  wineItem=&infoPtr->items [(INT)infoPtr->firstVisible];
1905
1906  while ((wineItem!=NULL) && (pt.y > wineItem->rect.bottom))
1907        wineItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
1908         
1909  if (!wineItem) 
1910         return NULL;
1911
1912  return wineItem;
1913 }
1914
1915
1916
1917
1918 static LRESULT
1919 TREEVIEW_HitTest (WND *wndPtr, LPARAM lParam)
1920 {
1921   LPTVHITTESTINFO lpht=(LPTVHITTESTINFO) lParam;
1922   TREEVIEW_ITEM *wineItem;
1923   RECT rect;
1924   UINT status,x,y;
1925
1926   GetClientRect (wndPtr->hwndSelf, &rect);
1927   status=0;
1928   x=lpht->pt.x;
1929   y=lpht->pt.y;
1930   if (x < rect.left)  status|=TVHT_TOLEFT;
1931   if (x > rect.right) status|=TVHT_TORIGHT;
1932   if (y < rect.top )  status|=TVHT_ABOVE;
1933   if (y > rect.bottom) status|=TVHT_BELOW;
1934   if (status) {
1935         lpht->flags=status;
1936         return 0;
1937   }
1938
1939   wineItem=TREEVIEW_HitTestPoint (wndPtr, lpht->pt);
1940   if (!wineItem) {      
1941                 lpht->flags=TVHT_NOWHERE;
1942                 return 0;
1943   }
1944
1945  if (x>wineItem->rect.right) {
1946         lpht->flags|=TVHT_ONITEMRIGHT;
1947         return (LRESULT) wineItem->hItem;
1948  }
1949  
1950  if (x<wineItem->rect.left+10) lpht->flags|=TVHT_ONITEMBUTTON;
1951
1952  lpht->flags=TVHT_ONITEMLABEL;    /* FIXME: implement other flags */
1953  lpht->hItem=wineItem->hItem;
1954
1955  return (LRESULT) wineItem->hItem;
1956 }
1957
1958
1959
1960
1961 LRESULT
1962 TREEVIEW_LButtonDoubleClick (WND *wndPtr, WPARAM wParam, LPARAM lParam)
1963 {
1964   TREEVIEW_ITEM *wineItem;
1965   POINT pt;
1966
1967   TRACE (treeview,"\n");
1968   pt.x = (INT)LOWORD(lParam);
1969   pt.y = (INT)HIWORD(lParam);
1970   SetFocus (wndPtr->hwndSelf);
1971
1972   wineItem=TREEVIEW_HitTestPoint (wndPtr, pt);
1973   if (!wineItem) return 0;
1974   TRACE (treeview,"item %d \n",(INT)wineItem->hItem);
1975  
1976   if (TREEVIEW_SendSimpleNotify (wndPtr, NM_DBLCLK)!=TRUE) {     /* FIXME!*/
1977         wineItem->state &= ~TVIS_EXPANDEDONCE;
1978         TREEVIEW_Expand (wndPtr, (WPARAM) TVE_TOGGLE, (LPARAM) wineItem->hItem);
1979  }
1980  return TRUE;
1981 }
1982
1983
1984
1985 static LRESULT
1986 TREEVIEW_LButtonDown (WND *wndPtr, WPARAM wParam, LPARAM lParam)
1987 {
1988   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
1989   INT iItem;
1990   TVHITTESTINFO ht;
1991
1992   ht.pt.x = (INT)LOWORD(lParam);
1993   ht.pt.y = (INT)HIWORD(lParam);
1994
1995   SetFocus (wndPtr->hwndSelf);
1996   iItem=TREEVIEW_HitTest (wndPtr, (LPARAM) &ht);
1997   TRACE (treeview,"item %d \n",iItem);
1998   if (ht.flags & TVHT_ONITEMBUTTON) {
1999         TREEVIEW_Expand (wndPtr, (WPARAM) TVE_TOGGLE, (LPARAM) iItem);
2000   }
2001
2002   infoPtr->uInternalStatus|=TV_LDRAG;
2003         
2004   if (TREEVIEW_DoSelectItem (wndPtr, TVGN_CARET, (HTREEITEM)iItem, TVC_BYMOUSE))
2005          return 0;
2006
2007   
2008  return 0;
2009 }
2010
2011 static LRESULT
2012 TREEVIEW_LButtonUp (WND *wndPtr, WPARAM wParam, LPARAM lParam)
2013 {
2014  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
2015  TREEVIEW_ITEM *editItem;
2016  INT ret;
2017  POINT pt;
2018
2019  pt.x = (INT)LOWORD(lParam);
2020  pt.y = (INT)HIWORD(lParam);
2021
2022  TRACE (treeview,"\n");
2023  if (TREEVIEW_SendSimpleNotify (wndPtr, NM_CLICK)) return 0;
2024  editItem=TREEVIEW_HitTestPoint (wndPtr, pt);    
2025  if (!editItem) return 0;
2026
2027  infoPtr->uInternalStatus &= ~(TV_LDRAG | TV_LDRAGGING);
2028
2029  if (wndPtr->dwStyle & TVS_EDITLABELS) {
2030                 RECT *r;
2031                 ret=TREEVIEW_SendDispInfoNotify (wndPtr, editItem, 
2032                                                                                         TVN_BEGINLABELEDIT, 0);
2033                 if (ret) return 0;
2034                 printf ("edit started..\n");
2035                 r=& editItem->rect;
2036                 infoPtr->editItem=editItem->hItem;
2037                 SetWindowPos ( infoPtr->hwndEdit, HWND_TOP, r->left, r->top,
2038                            r->right - r->left + 5,
2039                            r->bottom - r->top + 2,
2040                            SWP_SHOWWINDOW );
2041                 SetFocus (infoPtr->hwndEdit);
2042                 SetWindowTextA ( infoPtr->hwndEdit, editItem->pszText );
2043         SendMessageA ( infoPtr->hwndEdit, EM_SETSEL, 0, -1 );
2044         }
2045
2046
2047  
2048  return 0;
2049 }
2050
2051
2052 static LRESULT
2053 TREEVIEW_RButtonDown (WND *wndPtr, WPARAM wParam, LPARAM lParam)
2054 {
2055  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
2056
2057  TRACE (treeview,"\n");
2058  infoPtr->uInternalStatus|=TV_RDRAG;
2059  return 0;
2060 }
2061
2062 static LRESULT
2063 TREEVIEW_RButtonUp (WND *wndPtr, WPARAM wParam, LPARAM lParam)
2064 {
2065  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
2066
2067  TRACE (treeview,"\n");
2068  if (TREEVIEW_SendSimpleNotify (wndPtr, NM_RCLICK)) return 0;
2069  infoPtr->uInternalStatus&= ~(TV_RDRAG | TV_RDRAGGING);
2070  return 0;
2071 }
2072
2073
2074 static LRESULT
2075 TREEVIEW_MouseMove (WND *wndPtr, WPARAM wParam, LPARAM lParam)
2076 {
2077  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
2078  TREEVIEW_ITEM *hotItem;
2079  POINT pt;
2080
2081  pt.x=(INT) LOWORD (lParam);
2082  pt.y=(INT) HIWORD (lParam);
2083  hotItem=TREEVIEW_HitTestPoint (wndPtr, pt);
2084  if (!hotItem) return 0;
2085  infoPtr->focusItem=hotItem->hItem;
2086
2087  if (wndPtr->dwStyle & TVS_DISABLEDRAGDROP) return 0;
2088
2089  if (infoPtr->uInternalStatus & TV_LDRAG) {
2090         TREEVIEW_SendTreeviewDnDNotify (wndPtr, TVN_BEGINDRAG, hotItem->hItem, pt);
2091         infoPtr->uInternalStatus &= ~TV_LDRAG;
2092         infoPtr->uInternalStatus |= TV_LDRAGGING;
2093         infoPtr->dropItem=hotItem->hItem;
2094         return 0;
2095  }
2096
2097  if (infoPtr->uInternalStatus & TV_RDRAG) {
2098         TREEVIEW_SendTreeviewDnDNotify (wndPtr, TVN_BEGINRDRAG, hotItem->hItem, pt);
2099         infoPtr->uInternalStatus &= ~TV_RDRAG;
2100         infoPtr->uInternalStatus |= TV_RDRAGGING;
2101         infoPtr->dropItem=hotItem->hItem;
2102         return 0;
2103  }
2104  
2105  return 0;
2106 }
2107
2108
2109 static LRESULT
2110 TREEVIEW_CreateDragImage (WND *wndPtr, WPARAM wParam, LPARAM lParam)
2111 {
2112  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
2113  TREEVIEW_ITEM *dragItem;
2114  INT cx,cy;
2115  HDC    hdc,htopdc;
2116  HWND hwtop;
2117  HBITMAP hbmp,hOldbmp;
2118  SIZE  size;
2119  RECT  rc;
2120  HFONT hOldFont;
2121  char    *itemtxt;
2122  
2123  TRACE (treeview,"\n");
2124  if (!(infoPtr->himlNormal))  return 0;
2125  dragItem=TREEVIEW_ValidItem (infoPtr, (HTREEITEM) lParam);
2126  
2127  if (!dragItem) return 0;
2128  itemtxt=dragItem->pszText;
2129
2130  hwtop=GetDesktopWindow ();
2131  htopdc= GetDC (hwtop);
2132  hdc=CreateCompatibleDC (htopdc); 
2133  
2134  hOldFont=SelectObject (hdc, infoPtr->hFont);
2135  GetTextExtentPoint32A (hdc, itemtxt, lstrlenA (itemtxt), &size);
2136  TRACE (treeview,"%d %d %s %d\n",size.cx,size.cy,itemtxt,lstrlenA(itemtxt));
2137  hbmp=CreateCompatibleBitmap (htopdc, size.cx, size.cy);
2138  hOldbmp=SelectObject (hdc, hbmp);
2139
2140  ImageList_GetIconSize (infoPtr->himlNormal, &cx, &cy);
2141  size.cx+=cx;
2142  if (cy>size.cy) size.cy=cy;
2143
2144  infoPtr->dragList=ImageList_Create (size.cx, size.cy, ILC_COLOR, 10, 10);
2145  ImageList_Draw (infoPtr->himlNormal, dragItem->iImage, hdc, 0, 0, ILD_NORMAL);
2146
2147 /*
2148  ImageList_GetImageInfo (infoPtr->himlNormal, dragItem->hItem, &iminfo);
2149  ImageList_AddMasked (infoPtr->dragList, iminfo.hbmImage, CLR_DEFAULT);
2150 */
2151
2152 /* draw item text */
2153
2154  SetRect (&rc, cx, 0, size.cx,size.cy);
2155  DrawTextA (hdc, itemtxt, lstrlenA (itemtxt), &rc, DT_LEFT);
2156  SelectObject (hdc, hOldFont);
2157  SelectObject (hdc, hOldbmp);
2158
2159  ImageList_Add (infoPtr->dragList, hbmp, 0);
2160
2161  DeleteDC (hdc);
2162  DeleteObject (hbmp);
2163  ReleaseDC (hwtop, htopdc);
2164
2165  return (LRESULT)infoPtr->dragList;
2166 }
2167
2168
2169
2170 /* FIXME: handle NM_KILLFocus enzo */
2171
2172 static LRESULT
2173 TREEVIEW_DoSelectItem (WND *wndPtr, INT action, HTREEITEM newSelect, INT cause)
2174
2175 {
2176  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
2177  TREEVIEW_ITEM *prevItem,*wineItem, *parentItem;
2178  INT prevSelect;
2179
2180   TRACE (treeview,"item %x, flag %x, cause %x\n", (INT)newSelect, action, cause);
2181   wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)newSelect);
2182
2183   if (wineItem) {
2184         if (wineItem->parent) {
2185         parentItem=TREEVIEW_ValidItem (infoPtr, wineItem->parent);
2186         if (!(parentItem->state & TVIS_EXPANDED)) 
2187                 TREEVIEW_Expand (wndPtr, TVE_EXPAND, (LPARAM) wineItem->parent);
2188         }
2189   }
2190
2191   switch (action) {
2192         case TVGN_CARET: 
2193                 prevSelect=(INT)infoPtr->selectedItem;
2194                 if ((HTREEITEM)prevSelect==newSelect) return FALSE;
2195                 prevItem= TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect);
2196                 if (newSelect) 
2197                 if (TREEVIEW_SendTreeviewNotify (wndPtr, TVN_SELCHANGING, 
2198                                                         cause, (HTREEITEM)prevSelect, (HTREEITEM)newSelect)) 
2199                         return FALSE;       /* FIXME: OK? */
2200                 
2201             if (prevItem) prevItem->state &= ~TVIS_SELECTED;
2202                 infoPtr->selectedItem=(HTREEITEM)newSelect;
2203                 if (wineItem) wineItem->state |=TVIS_SELECTED;
2204                 if (newSelect)
2205                         TREEVIEW_SendTreeviewNotify (wndPtr, TVN_SELCHANGED, 
2206                                 cause, (HTREEITEM)prevSelect, (HTREEITEM)newSelect);
2207                 break;
2208         case TVGN_DROPHILITE: 
2209                 prevItem= TREEVIEW_ValidItem (infoPtr, infoPtr->dropItem);
2210                 if (prevItem) prevItem->state &= ~TVIS_DROPHILITED;
2211                 infoPtr->dropItem=(HTREEITEM)newSelect;
2212                 if (wineItem) wineItem->state |=TVIS_DROPHILITED;
2213                 break;
2214         case TVGN_FIRSTVISIBLE:
2215                 FIXME (treeview, "FIRSTVISIBLE not implemented\n");
2216                 break;
2217  }
2218  
2219  TREEVIEW_QueueRefresh (wndPtr);
2220   
2221  return TRUE;
2222 }
2223
2224
2225 static LRESULT
2226 TREEVIEW_SelectItem (WND *wndPtr, WPARAM wParam, LPARAM lParam)
2227
2228 {
2229  return TREEVIEW_DoSelectItem (wndPtr, wParam, (HTREEITEM) lParam, TVC_UNKNOWN);
2230 }
2231
2232
2233
2234    
2235 static LRESULT
2236 TREEVIEW_GetFont (WND *wndPtr, WPARAM wParam, LPARAM lParam)
2237
2238 {
2239  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
2240
2241  TRACE (treeview,"%x\n",infoPtr->hFont);
2242  return infoPtr->hFont;
2243 }
2244
2245 static LRESULT
2246 TREEVIEW_SetFont (WND *wndPtr, WPARAM wParam, LPARAM lParam)
2247
2248 {
2249  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
2250  TEXTMETRICA tm;
2251  LOGFONTA logFont;
2252  HFONT hFont, hOldFont;
2253  INT height;
2254  HDC hdc;
2255
2256  TRACE (treeview,"%x %lx\n",wParam, lParam);
2257  
2258  infoPtr->hFont = (HFONT)wParam;
2259
2260  hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
2261
2262  GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
2263  logFont.lfWeight=FW_BOLD;
2264  infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
2265
2266  hdc = GetDC (0);
2267  hOldFont = SelectObject (hdc, hFont);
2268  GetTextMetricsA (hdc, &tm);
2269  height= tm.tmHeight + tm.tmExternalLeading;
2270  if (height>infoPtr->uRealItemHeight) 
2271         infoPtr->uRealItemHeight=height;
2272  SelectObject (hdc, hOldFont);
2273  ReleaseDC (0, hdc);
2274
2275  if (lParam)    
2276         TREEVIEW_QueueRefresh (wndPtr);
2277  
2278  return 0;
2279 }
2280
2281
2282 /* FIXME: does KEYDOWN also send notifications?? If so, use 
2283    TREEVIEW_DoSelectItem.
2284 */
2285
2286
2287 static LRESULT
2288 TREEVIEW_KeyDown (WND *wndPtr, WPARAM wParam, LPARAM lParam)
2289 {
2290  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
2291  TREEVIEW_ITEM *prevItem,*newItem;
2292  int prevSelect;
2293
2294
2295  TRACE (treeview,"%x %lx\n",wParam, lParam);
2296  prevSelect=(INT)infoPtr->selectedItem;
2297  if (!prevSelect) return FALSE;
2298
2299  prevItem= TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect);
2300  
2301  newItem=NULL;
2302  switch (wParam) {
2303         case VK_UP: 
2304                 newItem=TREEVIEW_GetPrevListItem (infoPtr, prevItem);
2305                 if (!newItem) 
2306                         newItem=& infoPtr->items[(INT)infoPtr->TopRootItem];
2307                 break;
2308         case VK_DOWN: 
2309                 newItem=TREEVIEW_GetNextListItem (infoPtr, prevItem);
2310                 if (!newItem) newItem=prevItem;
2311                 break;
2312         case VK_HOME:
2313                 newItem=& infoPtr->items[(INT)infoPtr->TopRootItem];
2314                 break;
2315         case VK_END:
2316                 newItem=& infoPtr->items[(INT)infoPtr->TopRootItem];
2317                 newItem=TREEVIEW_GetLastListItem (infoPtr, newItem);
2318                 break;
2319         case VK_PRIOR:
2320         case VK_NEXT:
2321         case VK_BACK:
2322         case VK_RETURN:
2323                 FIXME (treeview, "%x not implemented\n", wParam);
2324                 break;
2325  }
2326
2327  if (!newItem) return FALSE;
2328
2329  if (prevItem!=newItem) {
2330         prevItem->state &= ~TVIS_SELECTED;
2331         newItem->state |= TVIS_SELECTED;
2332         infoPtr->selectedItem=newItem->hItem;
2333         TREEVIEW_QueueRefresh (wndPtr);
2334         return TRUE;
2335  }
2336
2337  return FALSE;
2338 }
2339
2340
2341
2342 static LRESULT
2343 TREEVIEW_VScroll (WND *wndPtr, WPARAM wParam, LPARAM lParam)
2344
2345 {
2346   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
2347   int maxHeight;
2348
2349   TRACE (treeview,"wp %x, lp %lx\n", wParam, lParam);
2350   if (!infoPtr->uInternalStatus & TV_VSCROLL) return FALSE;
2351
2352   switch (LOWORD (wParam)) {
2353         case SB_LINEUP: 
2354                         if (!infoPtr->cy) return FALSE;
2355                         infoPtr->cy -= infoPtr->uRealItemHeight;
2356                         if (infoPtr->cy < 0) infoPtr->cy=0;
2357                         break;
2358         case SB_LINEDOWN: 
2359                         maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
2360                         if (infoPtr->cy == maxHeight) return FALSE;
2361                         infoPtr->cy += infoPtr->uRealItemHeight;
2362                         if (infoPtr->cy > maxHeight) 
2363                                 infoPtr->cy = maxHeight;
2364                         break;
2365         case SB_PAGEUP: 
2366                         if (!infoPtr->cy) return FALSE;
2367                         infoPtr->cy -= infoPtr->uVisibleHeight;
2368                         if (infoPtr->cy < 0) infoPtr->cy=0;
2369                         break;
2370         case SB_PAGEDOWN:
2371                         maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
2372                         if (infoPtr->cy == maxHeight) return FALSE;
2373                         infoPtr->cy += infoPtr->uVisibleHeight;
2374             if (infoPtr->cy > maxHeight)
2375                 infoPtr->cy = maxHeight;
2376                         break;
2377         case SB_THUMBTRACK: 
2378                         infoPtr->cy = HIWORD (wParam);
2379                         break;
2380                         
2381   }
2382   
2383   TREEVIEW_QueueRefresh (wndPtr);
2384   return TRUE;
2385 }
2386
2387 static LRESULT
2388 TREEVIEW_HScroll (WND *wndPtr, WPARAM wParam, LPARAM lParam) 
2389 {
2390   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(wndPtr);
2391   int maxWidth;
2392
2393   TRACE (treeview,"wp %lx, lp %x\n", lParam, wParam);
2394         
2395   if (!infoPtr->uInternalStatus & TV_HSCROLL) return FALSE;
2396
2397   switch (LOWORD (wParam)) {
2398         case SB_LINEUP: 
2399                         if (!infoPtr->cx) return FALSE;
2400                         infoPtr->cx -= infoPtr->uRealItemHeight;
2401                         if (infoPtr->cx < 0) infoPtr->cx=0;
2402                         break;
2403         case SB_LINEDOWN: 
2404                         maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
2405                         if (infoPtr->cx == maxWidth) return FALSE;
2406                         infoPtr->cx += infoPtr->uRealItemHeight; /*FIXME */
2407                         if (infoPtr->cx > maxWidth) 
2408                                 infoPtr->cx = maxWidth;
2409                         break;
2410         case SB_PAGEUP: 
2411                         if (!infoPtr->cx) return FALSE;
2412                         infoPtr->cx -= infoPtr->uVisibleWidth;
2413                         if (infoPtr->cx < 0) infoPtr->cx=0;
2414                         break;
2415         case SB_PAGEDOWN:
2416                         maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
2417                         if (infoPtr->cx == maxWidth) return FALSE;
2418                         infoPtr->cx += infoPtr->uVisibleWidth;
2419             if (infoPtr->cx > maxWidth)
2420                 infoPtr->cx = maxWidth;
2421                         break;
2422         case SB_THUMBTRACK: 
2423                         infoPtr->cx = HIWORD (wParam);
2424                         break;
2425                         
2426   }
2427   
2428   TREEVIEW_QueueRefresh (wndPtr);
2429   return TRUE;
2430 }
2431
2432
2433
2434
2435 LRESULT WINAPI
2436 TREEVIEW_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2437 {
2438   WND *wndPtr = WIN_FindWndPtr(hwnd);
2439   
2440   
2441     switch (uMsg) {
2442         case TVM_INSERTITEMA:
2443           return TREEVIEW_InsertItemA (wndPtr, wParam, lParam);
2444
2445         case TVM_INSERTITEMW:
2446                 FIXME (treeview, "Unimplemented msg TVM_INSERTITEM32W\n");
2447                 return 0;
2448
2449         case TVM_DELETEITEM:
2450                 return TREEVIEW_DeleteItem (wndPtr, wParam, lParam);
2451
2452         case TVM_EXPAND:
2453                 return TREEVIEW_Expand (wndPtr, wParam, lParam);
2454
2455         case TVM_GETITEMRECT:
2456                 return TREEVIEW_GetItemRect (wndPtr, wParam, lParam);
2457
2458         case TVM_GETCOUNT:
2459                 return TREEVIEW_GetCount (wndPtr, wParam, lParam);
2460
2461         case TVM_GETINDENT:
2462                 return TREEVIEW_GetIndent (wndPtr);
2463
2464         case TVM_SETINDENT:
2465                 return TREEVIEW_SetIndent (wndPtr, wParam);
2466
2467         case TVM_GETIMAGELIST:
2468                 return TREEVIEW_GetImageList (wndPtr, wParam, lParam);
2469
2470                 case TVM_SETIMAGELIST:
2471                 return TREEVIEW_SetImageList (wndPtr, wParam, lParam);
2472
2473         case TVM_GETNEXTITEM:
2474                 return TREEVIEW_GetNextItem (wndPtr, wParam, lParam);
2475
2476         case TVM_SELECTITEM:
2477                 return TREEVIEW_SelectItem (wndPtr, wParam, lParam);
2478
2479         case TVM_GETITEMA:
2480                 return TREEVIEW_GetItemA (wndPtr, wParam, lParam);
2481
2482         case TVM_GETITEMW:
2483                 FIXME (treeview, "Unimplemented msg TVM_GETITEM32W\n");
2484                 return 0;
2485
2486         case TVM_SETITEMA:
2487                 return TREEVIEW_SetItemA (wndPtr, wParam, lParam);
2488
2489         case TVM_SETITEMW:
2490                 FIXME (treeview, "Unimplemented msg TVM_SETITEMW\n");
2491                 return 0;
2492
2493         case TVM_EDITLABELA:
2494                 FIXME (treeview, "Unimplemented msg TVM_EDITLABEL32A \n");
2495                 return 0;
2496
2497         case TVM_EDITLABELW:
2498                 FIXME (treeview, "Unimplemented msg TVM_EDITLABEL32W \n");
2499                 return 0;
2500
2501         case TVM_GETEDITCONTROL:
2502                 return TREEVIEW_GetEditControl (wndPtr);
2503
2504         case TVM_GETVISIBLECOUNT:
2505                 return TREEVIEW_GetVisibleCount (wndPtr, wParam, lParam);
2506
2507         case TVM_HITTEST:
2508                 return TREEVIEW_HitTest (wndPtr, lParam);
2509
2510         case TVM_CREATEDRAGIMAGE:
2511                 return TREEVIEW_CreateDragImage (wndPtr, wParam, lParam);
2512   
2513         case TVM_SORTCHILDREN:
2514                 FIXME (treeview, "Unimplemented msg TVM_SORTCHILDREN\n");
2515                 return 0;
2516   
2517         case TVM_ENSUREVISIBLE:
2518                 FIXME (treeview, "Unimplemented msg TVM_ENSUREVISIBLE\n");
2519                 return 0;
2520   
2521         case TVM_SORTCHILDRENCB:
2522                 FIXME (treeview, "Unimplemented msg TVM_SORTCHILDRENCB\n");
2523                 return 0;
2524   
2525         case TVM_ENDEDITLABELNOW:
2526                 FIXME (treeview, "Unimplemented msg TVM_ENDEDITLABELNOW\n");
2527                 return 0;
2528   
2529         case TVM_GETISEARCHSTRINGA:
2530                 FIXME (treeview, "Unimplemented msg TVM_GETISEARCHSTRING32A\n");
2531                 return 0;
2532   
2533         case TVM_GETISEARCHSTRINGW:
2534                 FIXME (treeview, "Unimplemented msg TVM_GETISEARCHSTRING32W\n");
2535                 return 0;
2536   
2537         case TVM_GETTOOLTIPS:
2538                 return TREEVIEW_GetToolTips (wndPtr);
2539
2540         case TVM_SETTOOLTIPS:
2541                 return TREEVIEW_SetToolTips (wndPtr, wParam);
2542   
2543         case TVM_SETINSERTMARK:
2544                 FIXME (treeview, "Unimplemented msg TVM_SETINSERTMARK\n");
2545                 return 0;
2546   
2547         case TVM_SETITEMHEIGHT:
2548                 return TREEVIEW_SetItemHeight (wndPtr, wParam);
2549   
2550         case TVM_GETITEMHEIGHT:
2551                 return TREEVIEW_GetItemHeight (wndPtr);
2552   
2553         case TVM_SETBKCOLOR:
2554                 return TREEVIEW_SetBkColor (wndPtr, wParam, lParam);
2555         
2556         case TVM_SETTEXTCOLOR:
2557                 return TREEVIEW_SetTextColor (wndPtr, wParam, lParam);
2558   
2559         case TVM_GETBKCOLOR:
2560                 return TREEVIEW_GetBkColor (wndPtr);
2561   
2562         case TVM_GETTEXTCOLOR:
2563                 return TREEVIEW_GetTextColor (wndPtr);
2564   
2565         case TVM_SETSCROLLTIME:
2566                 FIXME (treeview, "Unimplemented msg TVM_SETSCROLLTIME\n");
2567                 return 0;
2568   
2569         case TVM_GETSCROLLTIME:
2570                 FIXME (treeview, "Unimplemented msg TVM_GETSCROLLTIME\n");
2571                 return 0;
2572   
2573         case TVM_SETINSERTMARKCOLOR:
2574                 FIXME (treeview, "Unimplemented msg TVM_SETINSERTMARKCOLOR\n");
2575                 return 0;
2576   
2577         case TVM_SETUNICODEFORMAT:
2578                 FIXME (treeview, "Unimplemented msg TVM_SETUNICODEFORMAT\n");
2579                 return 0;
2580   
2581         case TVM_GETUNICODEFORMAT:
2582                 FIXME (treeview, "Unimplemented msg TVM_GETUNICODEFORMAT\n");
2583                 return 0;
2584   
2585                 case WM_COMMAND: 
2586                          return TREEVIEW_Command (wndPtr, wParam, lParam);
2587   
2588                 case WM_CREATE:
2589                         return TREEVIEW_Create (wndPtr, wParam, lParam);
2590   
2591                 case WM_DESTROY:
2592                         return TREEVIEW_Destroy (wndPtr);
2593   
2594 /*              case WM_ENABLE: */
2595   
2596                 case WM_ERASEBKGND:
2597                         return TREEVIEW_EraseBackground (wndPtr, wParam, lParam);
2598   
2599                 case WM_GETDLGCODE:
2600                 return DLGC_WANTARROWS | DLGC_WANTCHARS;
2601   
2602                 case WM_PAINT:
2603                 return TREEVIEW_Paint (wndPtr, wParam, lParam);
2604   
2605                 case WM_GETFONT:
2606                 return TREEVIEW_GetFont (wndPtr, wParam, lParam);
2607
2608                 case WM_SETFONT:
2609                 return TREEVIEW_SetFont (wndPtr, wParam, lParam);
2610   
2611                 case WM_KEYDOWN:
2612                         return TREEVIEW_KeyDown (wndPtr, wParam, lParam);
2613   
2614   
2615                 case WM_SETFOCUS: 
2616                         return TREEVIEW_SetFocus (wndPtr, wParam, lParam);
2617
2618                 case WM_KILLFOCUS: 
2619                         return TREEVIEW_KillFocus (wndPtr, wParam, lParam);
2620   
2621   
2622                 case WM_LBUTTONDOWN:
2623                         return TREEVIEW_LButtonDown (wndPtr, wParam, lParam);
2624
2625                 case WM_LBUTTONUP:
2626                         return TREEVIEW_LButtonUp (wndPtr, wParam, lParam);
2627   
2628                 case WM_LBUTTONDBLCLK:
2629                         return TREEVIEW_LButtonDoubleClick (wndPtr, wParam, lParam);
2630   
2631                 case WM_RBUTTONDOWN:
2632                         return TREEVIEW_RButtonDown (wndPtr, wParam, lParam);
2633
2634                 case WM_RBUTTONUP:
2635                         return TREEVIEW_RButtonUp (wndPtr, wParam, lParam);
2636
2637                 case WM_MOUSEMOVE:
2638                         return TREEVIEW_MouseMove (wndPtr, wParam, lParam);
2639   
2640   
2641 /*              case WM_SYSCOLORCHANGE: */
2642                 case WM_STYLECHANGED: 
2643                         return TREEVIEW_StyleChanged (wndPtr, wParam, lParam);
2644
2645 /*              case WM_SETREDRAW: */
2646   
2647                 case WM_TIMER:
2648                         return TREEVIEW_HandleTimer (wndPtr, wParam, lParam);
2649  
2650                 case WM_SIZE: 
2651                         return TREEVIEW_Size (wndPtr, wParam,lParam);
2652
2653                 case WM_HSCROLL: 
2654                         return TREEVIEW_HScroll (wndPtr, wParam, lParam);
2655                 case WM_VSCROLL: 
2656                         return TREEVIEW_VScroll (wndPtr, wParam, lParam);
2657   
2658                 case WM_DRAWITEM:
2659                         printf ("drawItem\n");
2660                         return DefWindowProcA (hwnd, uMsg, wParam, lParam);
2661   
2662                 default:
2663                 if (uMsg >= WM_USER)
2664                 FIXME (treeview, "Unknown msg %04x wp=%08x lp=%08lx\n",
2665                      uMsg, wParam, lParam);
2666             return DefWindowProcA (hwnd, uMsg, wParam, lParam);
2667       }
2668     return 0;
2669 }
2670
2671
2672 VOID
2673 TREEVIEW_Register (VOID)
2674 {
2675     WNDCLASSA wndClass;
2676
2677     TRACE (treeview,"\n");
2678
2679     if (GlobalFindAtomA (WC_TREEVIEWA)) return;
2680
2681     ZeroMemory (&wndClass, sizeof(WNDCLASSA));
2682     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS;
2683     wndClass.lpfnWndProc   = (WNDPROC)TREEVIEW_WindowProc;
2684     wndClass.cbClsExtra    = 0;
2685     wndClass.cbWndExtra    = sizeof(TREEVIEW_INFO *);
2686     wndClass.hCursor       = LoadCursorA (0, IDC_ARROWA);
2687     wndClass.hbrBackground = 0;
2688     wndClass.lpszClassName = WC_TREEVIEWA;
2689  
2690     RegisterClassA (&wndClass);
2691 }
2692
2693
2694 VOID
2695 TREEVIEW_Unregister (VOID)
2696 {
2697     if (GlobalFindAtomA (WC_TREEVIEWA))
2698         UnregisterClassA (WC_TREEVIEWA, (HINSTANCE)NULL);
2699 }
2700