source: trunk/src/comctl32/treeview.c@ 2131

Last change on this file since 2131 was 2131, checked in by achimha, 26 years ago

updated to WINE 991212 level

File size: 110.6 KB
Line 
1/* $Id: treeview.c,v 1.20 1999-12-19 10:32:12 achimha Exp $ */
2/* Treeview control
3 *
4 * Copyright 1998 Eric Kohl <ekohl@abo.rhein-zeitung.de>
5 * Copyright 1998,1999 Alex Priem <alexp@sci.kun.nl>
6 * Copyright 1999 Sylvain St-Germain
7 * Copyright 1999 Achim Hasenmueller
8 * Copyright 1999 Christoph Bratschi
9 *
10 *
11 * TODO:
12 * Using DPA to store the item ptr would be good.
13 * Node label edition is implemented but something appened in wine in the
14 * two last weeks of march 99 that broke it.
15 * refreshtreeview:
16 -small array containing info about positions.
17 -better implementation of RefreshItem:
18 1) draw lines between parents
19 2) draw items
20 3) draw lines from parent<->items.
21 -implement partial drawing?
22 * -drag&drop: TVM_CREATEDRAGIMAGE should create drag bitmap.
23 * -scrollbars: horizontal scrollbar doesn't work.
24 * -Unicode messages
25 * -check custom draw
26 * -I_CHILDRENCALLBACK
27 * FIXME: check fontsize. (uRealItemHeight)
28 * test focusItem (redraw in different color)
29 uHotItem
30 Edit: needs timer
31 better implementation.
32 * WM_HSCROLL is broken.
33 * use separate routine to get item text/image.
34 *
35 * Separate drawing/calculation.
36 *
37 * FIXMEs (for personal use)
38 Expand: -ctlmacro expands twice ->toggle.
39 -DblClick: ctlmacro.exe's NM_DBLCLK seems to go wrong (returns FALSE).
40 -treehelper: stack corruption makes big window.
41
42 */
43
44/* WINE 991212 level */
45
46#include <string.h>
47#include "winbase.h"
48#include "wingdi.h"
49#include "commctrl.h"
50#include "comctl32.h"
51#include "treeview.h"
52
53/* ffs should be in <string.h>. */
54
55/* Defines, since they do not need to return previous state, and nr
56 * has no side effects in this file.
57 */
58#define tv_test_bit(nr,bf) (((LPBYTE)bf)[nr>>3]&(1<<(nr&7)))
59#define tv_set_bit(nr,bf) ((LPBYTE)bf)[nr>>3]|=(1<<(nr&7))
60#define tv_clear_bit(nr,bf) ((LPBYTE)bf)[nr>>3]&=~(1<<(nr&7))
61
62
63#define TREEVIEW_GetInfoPtr(hwnd) \
64 ((TREEVIEW_INFO *) GetWindowLongA( hwnd, 0))
65
66static BOOL
67TREEVIEW_SendSimpleNotify (HWND hwnd, UINT code);
68static BOOL
69TREEVIEW_SendTreeviewNotify (HWND hwnd, UINT code, UINT action,
70 HTREEITEM oldItem, HTREEITEM newItem);
71static BOOL
72TREEVIEW_SendTreeviewDnDNotify (HWND hwnd, UINT code, HTREEITEM dragItem,
73 POINT pt);
74static BOOL
75TREEVIEW_SendDispInfoNotify (HWND hwnd, TREEVIEW_ITEM *wineItem,
76 UINT code, UINT what);
77static BOOL
78TREEVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
79 RECT rc);
80static BOOL
81TREEVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
82 TREEVIEW_ITEM *tvItem, UINT uItemDrawState);
83static LRESULT
84TREEVIEW_DoSelectItem (HWND hwnd, INT action, HTREEITEM newSelect, INT cause);
85static void
86TREEVIEW_Refresh (HWND hwnd);
87
88static LRESULT CALLBACK
89TREEVIEW_Edit_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam,
90 LPARAM lParam);
91
92LRESULT WINAPI
93TREEVIEW_EndEditLabelNow (HWND hwnd, WPARAM wParam, LPARAM lParam);
94
95
96
97
98/* helper functions. Work with the assumption that validity of operands
99 is checked beforehand, and that tree state is valid. */
100
101/* FIXME: MS documentation says `GetNextVisibleItem' returns NULL
102 if not succesfull'. Probably only applies to derefencing infoPtr
103 (ie we are offered a valid treeview structure)
104 and not whether there is a next `visible' child.
105 FIXME: check other failures.
106 */
107
108/***************************************************************************
109 * This method returns the TREEVIEW_ITEM object given the handle
110 */
111static TREEVIEW_ITEM* TREEVIEW_ValidItem(
112 TREEVIEW_INFO *infoPtr,
113 HTREEITEM handle)
114{
115 if ((!handle) || (handle>infoPtr->uMaxHandle))
116 return NULL;
117
118 if (tv_test_bit ((INT)handle, infoPtr->freeList))
119 return NULL;
120
121 return &infoPtr->items[(INT)handle];
122}
123
124/***************************************************************************
125 * This method returns the last expanded child item of a tree node
126 */
127static TREEVIEW_ITEM *TREEVIEW_GetLastListItem(
128 TREEVIEW_INFO *infoPtr,
129 TREEVIEW_ITEM *tvItem)
130
131{
132 TREEVIEW_ITEM *wineItem = tvItem;
133
134 /*
135 * Get this item last sibling
136 */
137 while (wineItem->sibling)
138 wineItem=& infoPtr->items [(INT)wineItem->sibling];
139
140 /*
141 * If the last sibling has expanded children, restart.
142 */
143 if ( ( wineItem->cChildren > 0 ) && ( wineItem->state & TVIS_EXPANDED) )
144 return TREEVIEW_GetLastListItem(
145 infoPtr,
146 &(infoPtr->items[(INT)wineItem->firstChild]));
147
148 return wineItem;
149}
150
151/***************************************************************************
152 * This method returns the previous physical item in the list not
153 * considering the tree hierarchy.
154 */
155static TREEVIEW_ITEM *TREEVIEW_GetPrevListItem(
156 TREEVIEW_INFO *infoPtr,
157 TREEVIEW_ITEM *tvItem)
158{
159 if (tvItem->upsibling)
160 {
161 /*
162 * This item has a upsibling, get the last item. Since, GetLastListItem
163 * first looks at siblings, we must feed it with the first child.
164 */
165 TREEVIEW_ITEM *upItem = &infoPtr->items[(INT)tvItem->upsibling];
166
167 if ( ( upItem->cChildren > 0 ) && ( upItem->state & TVIS_EXPANDED) )
168 return TREEVIEW_GetLastListItem(
169 infoPtr,
170 &infoPtr->items[(INT)upItem->firstChild]);
171 else
172 return upItem;
173 }
174 else
175 {
176 /*
177 * this item does not have a upsibling, get the parent
178 */
179 if (tvItem->parent)
180 return &infoPtr->items[(INT)tvItem->parent];
181 }
182
183 return NULL;
184}
185
186
187/***************************************************************************
188 * This method returns the next physical item in the treeview not
189 * considering the tree hierarchy.
190 */
191static TREEVIEW_ITEM *TREEVIEW_GetNextListItem(
192 TREEVIEW_INFO *infoPtr,
193 TREEVIEW_ITEM *tvItem)
194{
195 TREEVIEW_ITEM *wineItem = NULL;
196
197 /*
198 * If this item has children and is expanded, return the first child
199 */
200 if ((tvItem->firstChild) && (tvItem->state & TVIS_EXPANDED))
201 return (& infoPtr->items[(INT)tvItem->firstChild]);
202
203
204 /*
205 * try to get the sibling
206 */
207 if (tvItem->sibling)
208 return (& infoPtr->items[(INT)tvItem->sibling]);
209
210 /*
211 * Otherwise, get the parent's sibling.
212 */
213 wineItem=tvItem;
214 while (wineItem->parent) {
215 wineItem=& infoPtr->items [(INT)wineItem->parent];
216 if (wineItem->sibling)
217 return (& infoPtr->items [(INT)wineItem->sibling]);
218 }
219
220 return NULL;
221}
222
223/***************************************************************************
224 * This method returns the nth item starting at the given item. It returns
225 * the last item (or first) we we run out of items.
226 *
227 * Will scroll backward if count is <0.
228 * forward if count is >0.
229 */
230static TREEVIEW_ITEM *TREEVIEW_GetListItem(
231 TREEVIEW_INFO *infoPtr,
232 TREEVIEW_ITEM *tvItem,
233 LONG count)
234{
235 TREEVIEW_ITEM *previousItem = NULL;
236 TREEVIEW_ITEM *wineItem = tvItem;
237 LONG iter = 0;
238
239 if (count > 0)
240 {
241 /* Find count item downward */
242 while ((iter++ < count) && (wineItem != NULL))
243 {
244 /* Keep a pointer to the previous in case we ask for more than we got */
245 previousItem = wineItem;
246 wineItem = TREEVIEW_GetNextListItem(infoPtr, wineItem);
247 }
248
249 if (wineItem == NULL)
250 wineItem = previousItem;
251 }
252 else if (count < 0)
253 {
254 /* Find count item upward */
255 while ((iter-- > count) && (wineItem != NULL))
256 {
257 /* Keep a pointer to the previous in case we ask for more than we got */
258 previousItem = wineItem;
259 wineItem = TREEVIEW_GetPrevListItem(infoPtr, wineItem);
260 }
261
262 if (wineItem == NULL)
263 wineItem = previousItem;
264 }
265 else
266 wineItem = NULL;
267
268 return wineItem;
269}
270
271
272/***************************************************************************
273 * This method
274 */
275static void TREEVIEW_RemoveAllChildren(
276 HWND hwnd,
277 TREEVIEW_ITEM *parentItem)
278{
279 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
280 TREEVIEW_ITEM *killItem;
281 INT kill;
282
283 kill=(INT)parentItem->firstChild;
284 while (kill) {
285 tv_set_bit ( kill, infoPtr->freeList);
286 killItem=& infoPtr->items[kill];
287 if (killItem->pszText!=LPSTR_TEXTCALLBACKA)
288 COMCTL32_Free (killItem->pszText);
289 TREEVIEW_SendTreeviewNotify (hwnd, TVN_DELETEITEM, 0, (HTREEITEM)kill, 0);
290 if (killItem->firstChild)
291 TREEVIEW_RemoveAllChildren (hwnd, killItem);
292 kill=(INT)killItem->sibling;
293 }
294
295 if (parentItem->cChildren>0) {
296 infoPtr->uNumItems -= parentItem->cChildren;
297 parentItem->firstChild = 0;
298 parentItem->cChildren = 0;
299 }
300
301}
302
303
304static void
305TREEVIEW_RemoveItem (HWND hwnd, TREEVIEW_ITEM *wineItem)
306
307{
308 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
309 TREEVIEW_ITEM *parentItem, *upsiblingItem, *siblingItem;
310 INT iItem;
311
312 iItem=(INT)wineItem->hItem;
313 tv_set_bit(iItem,infoPtr->freeList);
314 infoPtr->uNumItems--;
315 parentItem=NULL;
316 if (wineItem->pszText!=LPSTR_TEXTCALLBACKA)
317 COMCTL32_Free (wineItem->pszText);
318
319 TREEVIEW_SendTreeviewNotify (hwnd, TVN_DELETEITEM, 0, (HTREEITEM)iItem, 0);
320
321 if (wineItem->firstChild)
322 TREEVIEW_RemoveAllChildren (hwnd,wineItem);
323
324 if (wineItem->parent) {
325 parentItem=& infoPtr->items [(INT)wineItem->parent];
326 switch (parentItem->cChildren) {
327 case I_CHILDRENCALLBACK:
328// FIXME (treeview,"we don't handle I_CHILDRENCALLBACK yet\n");
329 break;
330 case 1:
331 parentItem->cChildren=0;
332 parentItem->firstChild=0;
333 return;
334 default:
335 parentItem->cChildren--;
336 if ((INT)parentItem->firstChild==iItem)
337 parentItem->firstChild=wineItem->sibling;
338 }
339 }
340
341 if (iItem==(INT)infoPtr->TopRootItem)
342 infoPtr->TopRootItem=(HTREEITEM)wineItem->sibling;
343 if (wineItem->upsibling) {
344 upsiblingItem=& infoPtr->items [(INT)wineItem->upsibling];
345 upsiblingItem->sibling=wineItem->sibling;
346 }
347 if (wineItem->sibling) {
348 siblingItem=& infoPtr->items [(INT)wineItem->sibling];
349 siblingItem->upsibling=wineItem->upsibling;
350 }
351}
352
353
354
355
356
357/* Note:TREEVIEW_RemoveTree doesn't remove infoPtr itself */
358
359static void TREEVIEW_RemoveTree (HWND hwnd)
360
361{
362 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
363 TREEVIEW_ITEM *killItem;
364 int i;
365
366 for (i=1; i<=(INT)infoPtr->uMaxHandle; i++)
367 if (!tv_test_bit (i, infoPtr->freeList)) {
368 killItem=& infoPtr->items [i];
369 if (killItem->pszText!=LPSTR_TEXTCALLBACKA)
370 COMCTL32_Free (killItem->pszText);
371 TREEVIEW_SendTreeviewNotify
372 (hwnd, TVN_DELETEITEM, 0, killItem->hItem, 0);
373 }
374
375 if (infoPtr->uNumPtrsAlloced) {
376 COMCTL32_Free (infoPtr->items);
377 COMCTL32_Free (infoPtr->freeList);
378 infoPtr->uNumItems=0;
379 infoPtr->uNumPtrsAlloced=0;
380 infoPtr->uMaxHandle=0;
381 }
382}
383
384
385
386
387
388
389
390static LRESULT
391TREEVIEW_GetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
392{
393 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
394
395// TRACE (treeview,"\n");
396 if (infoPtr==NULL) return 0;
397
398 if ((INT)wParam == TVSIL_NORMAL)
399 return (LRESULT) infoPtr->himlNormal;
400 if ((INT)wParam == TVSIL_STATE)
401 return (LRESULT) infoPtr->himlState;
402
403 return 0;
404}
405
406static LRESULT
407TREEVIEW_SetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
408{
409 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
410 HIMAGELIST himlTemp;
411
412// TRACE (treeview,"\n");
413 switch ((INT)wParam) {
414 case TVSIL_NORMAL:
415 himlTemp = infoPtr->himlNormal;
416 infoPtr->himlNormal = (HIMAGELIST)lParam;
417 return (LRESULT)himlTemp;
418
419 case TVSIL_STATE:
420 himlTemp = infoPtr->himlState;
421 infoPtr->himlState = (HIMAGELIST)lParam;
422 return (LRESULT)himlTemp;
423 }
424
425 return (LRESULT)NULL;
426}
427
428
429
430static LRESULT
431TREEVIEW_SetItemHeight (HWND hwnd, WPARAM wParam)
432{
433 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
434 INT cx,cy,prevHeight=infoPtr->uItemHeight;
435
436// TRACE (treeview,"\n");
437 if (wParam==-1) {
438 infoPtr->uItemHeight=-1;
439 return prevHeight;
440 }
441
442 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &cy);
443
444 if (wParam>cy) cy=wParam;
445 infoPtr->uItemHeight=cy;
446
447 if (!( GetWindowLongA( hwnd, GWL_STYLE) & TVS_NONEVENHEIGHT))
448 infoPtr->uItemHeight = (INT) wParam & 0xfffffffe;
449 return prevHeight;
450}
451
452static LRESULT
453TREEVIEW_GetItemHeight (HWND hwnd)
454{
455 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
456
457// TRACE (treeview,"\n");
458 return infoPtr->uItemHeight;
459}
460
461static LRESULT
462TREEVIEW_GetLineColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
463{
464 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
465
466 //TRACE("\n");
467 return (LRESULT) infoPtr->clrLine;
468}
469
470static LRESULT
471TREEVIEW_SetLineColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
472{
473 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
474 COLORREF prevColor=infoPtr->clrLine;
475
476 //TRACE("\n");
477 infoPtr->clrLine=(COLORREF) lParam;
478 return (LRESULT) prevColor;
479}
480
481static LRESULT
482TREEVIEW_GetInsertMarkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
483{
484 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
485
486 TRACE("\n");
487 return (LRESULT) infoPtr->clrInsertMark;
488}
489
490static LRESULT
491TREEVIEW_SetInsertMarkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
492{
493 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
494 COLORREF prevColor=infoPtr->clrInsertMark;
495
496 TRACE("%d %ld\n",wParam,lParam);
497 infoPtr->clrInsertMark=(COLORREF) lParam;
498 return (LRESULT) prevColor;
499}
500
501static LRESULT
502TREEVIEW_SetInsertMark (HWND hwnd, WPARAM wParam, LPARAM lParam)
503{
504 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
505
506 FIXME("%d %ld\n",wParam,lParam);
507 if (!TREEVIEW_ValidItem (infoPtr, (HTREEITEM)lParam)) return 0;
508 FIXME("%d %ld\n",wParam,lParam);
509
510 infoPtr->insertBeforeorAfter=(BOOL) wParam;
511 infoPtr->insertMarkItem=(HTREEITEM) lParam;
512 TREEVIEW_Refresh (hwnd);
513 return 1;
514}
515
516static LRESULT
517TREEVIEW_SetTextColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
518{
519 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
520 COLORREF prevColor=infoPtr->clrText;
521
522// TRACE (treeview,"\n");
523 infoPtr->clrText=(COLORREF) lParam;
524 return (LRESULT) prevColor;
525}
526
527static LRESULT
528TREEVIEW_GetBkColor (HWND hwnd)
529{
530 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
531
532 //TRACE("\n");
533 return (LRESULT) infoPtr->clrBk;
534}
535
536static LRESULT
537TREEVIEW_SetBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
538{
539 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
540 COLORREF prevColor=infoPtr->clrBk;
541
542 //TRACE("\n");
543 infoPtr->clrBk=(COLORREF) lParam;
544 return (LRESULT) prevColor;
545}
546
547static LRESULT
548TREEVIEW_GetTextColor (HWND hwnd)
549{
550 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
551
552 //TRACE("\n");
553 return (LRESULT) infoPtr->clrText;
554}
555
556
557/* cdmode: custom draw mode as received from app. in first NMCUSTOMDRAW
558 notification */
559
560#define TREEVIEW_LEFT_MARGIN 8
561
562
563static void
564TREEVIEW_DrawItem (HWND hwnd, HDC hdc, TREEVIEW_ITEM *wineItem)
565{
566 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
567 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
568 INT center,xpos,cx,cy, cditem;
569 HFONT hOldFont;
570 UINT uTextJustify = DT_LEFT;
571 RECT r;
572
573
574 if (wineItem->state & TVIS_BOLD)
575 hOldFont = SelectObject (hdc, infoPtr->hBoldFont);
576 else
577 hOldFont = SelectObject (hdc, infoPtr->hFont);
578
579 cditem=0;
580 //TRACE ("cdmode:%x\n",infoPtr->cdmode);
581 if (infoPtr->cdmode & CDRF_NOTIFYITEMDRAW) {
582 cditem = TREEVIEW_SendCustomDrawItemNotify(hwnd, hdc,
583 wineItem, CDDS_ITEMPREPAINT);
584
585 if (cditem & CDRF_SKIPDEFAULT)
586 return;
587 }
588
589 /*
590 * Set drawing starting points
591 */
592 r = wineItem->rect; /* this item rectangle */
593 center = (r.top+r.bottom)/2; /* this item vertical center */
594 xpos = r.left + TREEVIEW_LEFT_MARGIN;/* horizontal starting point */
595
596 /*
597 * Display the tree hierarchy
598 */
599 if ( dwStyle & TVS_HASLINES)
600 {
601 /*
602 * Write links to parent node
603 * we draw the L starting from the child to the parent
604 *
605 * points[0] is attached to the current item
606 * points[1] is the L corner
607 * points[2] is attached to the parent or the up sibling
608 */
609 if ( dwStyle & TVS_LINESATROOT)
610 {
611 TREEVIEW_ITEM *upNode = NULL;
612 BOOL hasParentOrSibling = TRUE;
613 RECT upRect = {0,0,0,0};
614 HPEN hOldPen, hnewPen;
615 POINT points[3];
616 /*
617 * determine the target location of the line at root, either be linked
618 * to the up sibling or to the parent node.
619 */
620 if (wineItem->upsibling)
621 upNode = TREEVIEW_ValidItem (infoPtr, wineItem->upsibling);
622 else if (wineItem->parent)
623 upNode = TREEVIEW_ValidItem (infoPtr, wineItem->parent);
624 else
625 hasParentOrSibling = FALSE;
626
627 if (upNode)
628 upRect = upNode->rect;
629
630 if ( wineItem->iLevel == 0 )
631 {
632 points[2].x = points[1].x = upRect.left+8;
633 points[0].x = points[2].x + 10;
634 points[2].y = upRect.bottom-3;
635 points[1].y = points[0].y = center;
636 }
637 else
638 {
639 points[2].x = points[1].x = 8 + (20*wineItem->iLevel);
640 points[2].y = ( upNode->cChildren == 0) ?
641 upRect.top : /* is linked to the "L" above */
642 ( wineItem->upsibling != NULL) ?
643 upRect.bottom-3: /* is linked to an icon */
644 upRect.bottom+1; /* is linked to a +/- box */
645 points[1].y = points[0].y = center;
646 points[0].x = points[1].x + 10;
647 }
648
649 /*
650 * Get a dotted pen
651 */
652 hnewPen = CreatePen(PS_DOT, 0, infoPtr->clrLine);
653 hOldPen = SelectObject( hdc, hnewPen );
654
655 if (hasParentOrSibling)
656 Polyline (hdc,points,3);
657 else
658 Polyline (hdc,points,2);
659
660 DeleteObject(hnewPen);
661 SelectObject(hdc, hOldPen);
662 }
663 }
664
665 /*
666 * Display the (+/-) signs
667 */
668 if (wineItem->iLevel != 0)/* update position only for non root node */
669 xpos+=(5*wineItem->iLevel);
670
671 if (( dwStyle & TVS_HASBUTTONS) && ( dwStyle & TVS_HASLINES))
672 {
673 if ( (wineItem->cChildren) ||
674 (wineItem->cChildren == I_CHILDRENCALLBACK))
675 {
676 /* Setup expand box coordinate to facilitate the LMBClick handling */
677 wineItem->expandBox.left = xpos-4;
678 wineItem->expandBox.top = center-4;
679 wineItem->expandBox.right = xpos+5;
680 wineItem->expandBox.bottom = center+5;
681
682 Rectangle (
683 hdc,
684 wineItem->expandBox.left,
685 wineItem->expandBox.top ,
686 wineItem->expandBox.right,
687 wineItem->expandBox.bottom);
688
689 MoveToEx (hdc, xpos-2, center, NULL);
690 LineTo (hdc, xpos+3, center);
691
692 if (!(wineItem->state & TVIS_EXPANDED)) {
693 MoveToEx (hdc, xpos, center-2, NULL);
694 LineTo (hdc, xpos, center+3);
695 }
696 }
697 }
698
699 /*
700 * Display the image associated with this item
701 */
702 xpos += 13; /* update position */
703 if (wineItem->mask & (TVIF_IMAGE|TVIF_SELECTEDIMAGE)) {
704 INT imageIndex;
705 HIMAGELIST *himlp = NULL;
706
707 /* State images are displayed to the left of the Normal image
708 * image number is in state; zero should be `display no image'.
709 * FIXME: that last sentence looks like it needs some checking.
710 */
711 if (infoPtr->himlState)
712 himlp=&infoPtr->himlState;
713 imageIndex=wineItem->state>>12;
714 imageIndex++; /* yeah, right */
715 TRACE ("imindex:%d\n",imageIndex);
716 if ((himlp) && (imageIndex))
717 {
718 imageIndex--; /* see FIXME */
719 ImageList_Draw ( *himlp, imageIndex, hdc, xpos-2, r.top+1, ILD_NORMAL);
720 ImageList_GetIconSize (*himlp, &cx, &cy);
721 wineItem->statebitmap.left=xpos-2;
722 wineItem->statebitmap.right=xpos-2+cx;
723 wineItem->statebitmap.top=r.top+1;
724 wineItem->statebitmap.bottom=r.top+1+cy;
725 xpos+=cx;
726 }
727
728 /* Now, draw the normal image; can be either selected or
729 * non-selected image.
730 */
731
732 himlp=NULL;
733 if (infoPtr->himlNormal)
734 himlp=&infoPtr->himlNormal; /* get the image list */
735
736 imageIndex = wineItem->iImage;
737 if ( (wineItem->state & TVIS_SELECTED) &&
738 (wineItem->iSelectedImage)) {
739
740 /* The item is curently selected */
741 if (wineItem->iSelectedImage == I_IMAGECALLBACK)
742 TREEVIEW_SendDispInfoNotify
743 (hwnd, wineItem, TVN_GETDISPINFO, TVIF_SELECTEDIMAGE);
744
745 imageIndex = wineItem->iSelectedImage;
746 } else {
747 /* The item is not selected */
748 if (wineItem->iImage == I_IMAGECALLBACK)
749 TREEVIEW_SendDispInfoNotify
750 (hwnd, wineItem, TVN_GETDISPINFO, TVIF_IMAGE);
751
752 imageIndex = wineItem->iImage;
753 }
754
755 if (himlp)
756 {
757 ImageList_Draw ( *himlp, imageIndex, hdc, xpos-2, r.top+1, ILD_NORMAL);
758 ImageList_GetIconSize (*himlp, &cx, &cy);
759 wineItem->bitmap.left=xpos-2;
760 wineItem->bitmap.right=xpos-2+cx;
761 wineItem->bitmap.top=r.top+1;
762 wineItem->bitmap.bottom=r.top+1+cy;
763 xpos+=cx;
764 }
765 }
766
767
768 /*
769 * Display the text associated with this item
770 */
771 r.left=xpos;
772 if ((wineItem->mask & TVIF_TEXT) && (wineItem->pszText))
773 {
774 COLORREF oldBkColor = 0;
775 COLORREF oldTextColor = 0;
776 INT oldBkMode;
777
778 r.left += 3;
779 r.right -= 3;
780
781 wineItem->text.left = r.left;
782 wineItem->text.right = r.right;
783 wineItem->text.top = r.top;
784 wineItem->text.bottom= r.bottom;
785
786 if (wineItem->pszText== LPSTR_TEXTCALLBACKA) {
787 TRACE("LPSTR_TEXTCALLBACK\n");
788 TREEVIEW_SendDispInfoNotify (hwnd, wineItem, TVN_GETDISPINFO, TVIF_TEXT);
789 }
790
791/* Yep, there are some things that need to be straightened out here.
792 Removing the comments around the setTextColor does not give the right
793 results. Dito FillRect.
794*/
795
796
797/* GetTextExtentPoint32A (hdc, wineItem->pszText,
798 strlen (wineItem->pszText), &size); */
799
800/* FillRect ( hdc, &wineItem->text, GetSysColorBrush (infoPtr->clrBk));
801 */
802
803
804 if (!(cditem & CDRF_NOTIFYPOSTPAINT) &&
805 (wineItem->state & (TVIS_SELECTED | TVIS_DROPHILITED)) ) {
806 oldBkMode = SetBkMode (hdc, OPAQUE);
807 oldBkColor = SetBkColor (hdc, GetSysColor( COLOR_HIGHLIGHT));
808 oldTextColor = SetTextColor(hdc, GetSysColor( COLOR_HIGHLIGHTTEXT));
809 } else {
810 oldBkMode = SetBkMode (hdc, TRANSPARENT);
811 oldBkColor = SetBkColor (hdc, infoPtr->clrBk);
812 /* oldTextColor = SetTextColor(hdc, infoPtr->clrText); */
813 }
814
815
816
817 /* Draw it */
818 DrawTextA ( hdc,
819 wineItem->pszText,
820 lstrlenA(wineItem->pszText),
821 &wineItem->text,
822 uTextJustify | DT_VCENTER | DT_SINGLELINE );
823
824 /* Obtain the text coordinate */
825 DrawTextA (
826 hdc,
827 wineItem->pszText,
828 lstrlenA(wineItem->pszText),
829 &wineItem->text,
830 uTextJustify | DT_VCENTER | DT_SINGLELINE | DT_CALCRECT);
831
832 /* Restore the hdc state */
833 SetTextColor( hdc, oldTextColor);
834
835 if (oldBkMode != TRANSPARENT)
836 SetBkMode(hdc, oldBkMode);
837 if (wineItem->state & (TVIS_SELECTED | TVIS_DROPHILITED))
838 SetBkColor (hdc, oldBkColor);
839
840 /* Draw the box arround the selected item */
841 if (wineItem->state & TVIS_SELECTED )
842 {
843 HPEN hNewPen = CreatePen(PS_DOT, 0, GetSysColor(COLOR_WINDOWTEXT) );
844 HPEN hOldPen = SelectObject( hdc, hNewPen );
845 POINT points[4];
846
847 points[0].x = wineItem->text.left-1;
848 points[0].y = wineItem->text.top+1;
849 points[1].x = wineItem->text.right;
850 points[1].y = wineItem->text.top+1;
851 points[2].x = wineItem->text.right;
852 points[2].y = wineItem->text.bottom;
853 points[3].x = wineItem->text.left-1;
854 points[3].y = wineItem->text.bottom;
855
856 Polyline (hdc,points,4);
857
858 DeleteObject(hNewPen);
859 SelectObject(hdc, hOldPen);
860 }
861 }
862
863 /* Draw insertion mark if necessary */
864
865 if (infoPtr->insertMarkItem)
866 TRACE ("item:%d,mark:%d\n", (int)wineItem->hItem,
867 (int) infoPtr->insertMarkItem);
868 if (wineItem->hItem==infoPtr->insertMarkItem) {
869 HPEN hNewPen, hOldPen;
870 int offset;
871
872 hNewPen = CreatePen(PS_SOLID, 2, infoPtr->clrInsertMark);
873 hOldPen = SelectObject( hdc, hNewPen );
874
875 if (infoPtr->insertBeforeorAfter)
876 offset=wineItem->text.top+1;
877 else
878 offset=wineItem->text.bottom-1;
879
880 MoveToEx (hdc, wineItem->text.left, offset-3, NULL);
881 LineTo (hdc, wineItem->text.left, offset+3);
882
883 MoveToEx (hdc, wineItem->text.left, offset, NULL);
884 LineTo (hdc, r.right-2, offset);
885
886 MoveToEx (hdc, r.right-2, offset+3, NULL);
887 LineTo (hdc, r.right-2, offset-3);
888
889 DeleteObject(hNewPen);
890
891 SelectObject(hdc, hOldPen);
892 }
893
894 if (cditem & CDRF_NOTIFYPOSTPAINT) {
895 cditem=TREEVIEW_SendCustomDrawItemNotify
896 (hwnd, hdc, wineItem, CDDS_ITEMPOSTPAINT);
897 TRACE("postpaint:cditem-app returns 0x%x\n",cditem);
898 }
899
900 SelectObject (hdc, hOldFont);
901}
902
903static LRESULT
904TREEVIEW_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
905{
906 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
907 TREEVIEW_ITEM *wineItem;
908 HTREEITEM *iItem;
909 LPRECT lpRect = (LPRECT)lParam;
910
911// TRACE (treeview,"\n");
912 /*
913 * validate parameters
914 */
915 if ( (infoPtr==NULL) || (lpRect == NULL) )
916 return FALSE;
917
918 if (infoPtr->Timer & TV_REFRESH_TIMER_SET)
919 TREEVIEW_Refresh (hwnd); /* we want a rect for the current view */
920
921 /*
922 * retrieve the item ptr
923 */
924 iItem = (HTREEITEM *) lParam;
925 wineItem = TREEVIEW_ValidItem (infoPtr, *iItem);
926 if ((!wineItem) || (!wineItem->visible))
927 return FALSE;
928
929 /*
930 * If wParam is TRUE return the text size otherwise return
931 * the whole item size
932 */
933 if ((INT) wParam) {
934 lpRect->left = wineItem->text.left;
935 lpRect->right = wineItem->text.right;
936 lpRect->bottom = wineItem->text.bottom;
937 lpRect->top = wineItem->text.top;
938 } else {
939 lpRect->left = wineItem->rect.left;
940 lpRect->right = wineItem->rect.right;
941 lpRect->bottom = wineItem->rect.bottom;
942 lpRect->top = wineItem->rect.top;
943 }
944
945// TRACE (treeview,"[L:%d R:%d T:%d B:%d]\n",
946// lpRect->left,lpRect->right,
947// lpRect->top,lpRect->bottom);
948
949 return TRUE;
950}
951
952static LRESULT
953TREEVIEW_GetVisibleCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
954
955{
956 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
957
958 return (LRESULT) infoPtr->uVisibleHeight / infoPtr->uRealItemHeight;
959}
960
961
962
963static LRESULT
964TREEVIEW_SetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
965{
966 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
967 TREEVIEW_ITEM *wineItem;
968 TVITEMEXA *tvItem;
969 INT iItem,len;
970
971 tvItem=(LPTVITEMEXA) lParam;
972 iItem=(INT)tvItem->hItem;
973// TRACE (treeview,"item %d,mask %x\n",iItem,tvItem->mask);
974
975 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
976 if (!wineItem) return FALSE;
977
978 if (tvItem->mask & TVIF_CHILDREN) {
979 wineItem->cChildren=tvItem->cChildren;
980 }
981
982 if (tvItem->mask & TVIF_IMAGE) {
983 wineItem->iImage=tvItem->iImage;
984 }
985
986 if (tvItem->mask & TVIF_INTEGRAL) {
987 wineItem->iIntegral=tvItem->iIntegral;
988 }
989
990 if (tvItem->mask & TVIF_PARAM) {
991 wineItem->lParam=tvItem->lParam;
992 }
993
994 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
995 wineItem->iSelectedImage=tvItem->iSelectedImage;
996 }
997
998 if (tvItem->mask & TVIF_STATE) {
999 TRACE ("prevstate,state,mask:%x,%x,%x\n",wineItem->state,tvItem->state,
1000tvItem->stateMask);
1001 wineItem->state&= ~tvItem->stateMask;
1002 wineItem->state|= (tvItem->state & tvItem->stateMask);
1003 wineItem->stateMask|= tvItem->stateMask;
1004 }
1005
1006 if (tvItem->mask & TVIF_TEXT) {
1007 if (tvItem->pszText!=LPSTR_TEXTCALLBACKA) {
1008 len = lstrlenA (tvItem->pszText);
1009 if (len > wineItem->cchTextMax)
1010 wineItem->pszText = COMCTL32_ReAlloc (wineItem->pszText, len+1);
1011 lstrcpynA (wineItem->pszText, tvItem->pszText,len+1);
1012 } else {
1013 if (wineItem->cchTextMax) {
1014 COMCTL32_Free (wineItem->pszText);
1015 wineItem->cchTextMax=0;
1016 }
1017 wineItem->pszText = LPSTR_TEXTCALLBACKA;
1018 }
1019 }
1020
1021 wineItem->mask |= tvItem->mask;
1022
1023 return TRUE;
1024}
1025
1026static LRESULT
1027TREEVIEW_GetItemState (HWND hwnd, WPARAM wParam, LPARAM lParam)
1028
1029{
1030 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1031 TREEVIEW_ITEM *wineItem;
1032
1033 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)wParam);
1034 if (!wineItem) return 0;
1035
1036 return (wineItem->state & lParam);
1037}
1038
1039static void
1040TREEVIEW_Refresh (HWND hwnd)
1041
1042{
1043 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1044 TEXTMETRICA tm;
1045 HBRUSH hbrBk;
1046 RECT rect;
1047 HDC hdc;
1048 INT iItem, indent, x, y, cx, height, itemHeight;
1049 INT viewtop,viewbottom,viewleft,viewright;
1050 TREEVIEW_ITEM *wineItem, *prevItem;
1051
1052 //TRACE("\n");
1053
1054 hdc=GetDC (hwnd);
1055
1056 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
1057 KillTimer (hwnd, TV_REFRESH_TIMER);
1058 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
1059 }
1060
1061
1062 GetClientRect (hwnd, &rect);
1063 if ((rect.left-rect.right ==0) || (rect.top-rect.bottom==0)) return;
1064
1065 infoPtr->cdmode=TREEVIEW_SendCustomDrawNotify
1066 (hwnd, CDDS_PREPAINT, hdc, rect);
1067
1068 if (infoPtr->cdmode==CDRF_SKIPDEFAULT) {
1069 ReleaseDC (hwnd, hdc);
1070 return;
1071 }
1072
1073 infoPtr->uVisibleHeight= rect.bottom-rect.top;
1074 infoPtr->uVisibleWidth= rect.right-rect.left;
1075
1076 viewtop=infoPtr->cy;
1077 viewbottom=infoPtr->cy + rect.bottom-rect.top;
1078 viewleft=infoPtr->cx;
1079 viewright=infoPtr->cx + rect.right-rect.left;
1080
1081 /* draw background */
1082
1083 hbrBk = CreateSolidBrush (infoPtr->clrBk);
1084 FillRect(hdc, &rect, hbrBk);
1085 DeleteObject(hbrBk);
1086
1087 iItem=(INT)infoPtr->TopRootItem;
1088 infoPtr->firstVisible=0;
1089 wineItem=NULL;
1090 indent=0;
1091 x=y=0;
1092 //TRACE("[%d %d %d %d]\n",viewtop,viewbottom,viewleft,viewright);
1093
1094 while (iItem) {
1095 prevItem=wineItem;
1096 wineItem= & infoPtr->items[iItem];
1097 wineItem->iLevel=indent;
1098
1099 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &itemHeight);
1100 if (infoPtr->uItemHeight>itemHeight)
1101 itemHeight=infoPtr->uItemHeight;
1102
1103 GetTextMetricsA (hdc, &tm);
1104 if ((tm.tmHeight + tm.tmExternalLeading) > itemHeight)
1105 itemHeight=tm.tmHeight + tm.tmExternalLeading;
1106
1107 infoPtr->uRealItemHeight=itemHeight;
1108
1109
1110/* FIXME: remove this in later stage */
1111/*
1112 if (wineItem->pszText!=LPSTR_TEXTCALLBACK32A)
1113 TRACE (treeview, "%d %d [%d %d %d %d] (%s)\n",y,x,
1114 wineItem->rect.top, wineItem->rect.bottom,
1115 wineItem->rect.left, wineItem->rect.right,
1116 wineItem->pszText);
1117 else
1118 TRACE (treeview, "%d [%d %d %d %d] (CALLBACK)\n",
1119 wineItem->hItem,
1120 wineItem->rect.top, wineItem->rect.bottom,
1121 wineItem->rect.left, wineItem->rect.right);
1122*/
1123
1124 height=itemHeight * wineItem->iIntegral +1;
1125 if ((y >= viewtop) && (y <= viewbottom) &&
1126 (x >= viewleft ) && (x <= viewright)) {
1127 wineItem->visible = TRUE;
1128 wineItem->rect.top = y - infoPtr->cy + rect.top;
1129 wineItem->rect.bottom = wineItem->rect.top + height ;
1130 wineItem->rect.left = x - infoPtr->cx + rect.left;
1131 wineItem->rect.right = rect.right;
1132 if (!infoPtr->firstVisible)
1133 infoPtr->firstVisible=wineItem->hItem;
1134 TREEVIEW_DrawItem (hwnd, hdc, wineItem);
1135 }
1136 else {
1137 wineItem->visible = FALSE;
1138 wineItem->rect.left = wineItem->rect.top = 0;
1139 wineItem->rect.right= wineItem->rect.bottom = 0;
1140 wineItem->text.left = wineItem->text.top = 0;
1141 wineItem->text.right= wineItem->text.bottom = 0;
1142 }
1143
1144 /* look up next item */
1145
1146 if ((wineItem->firstChild) && (wineItem->state & TVIS_EXPANDED)) {
1147 iItem=(INT)wineItem->firstChild;
1148 indent++;
1149 x+=infoPtr->uIndent;
1150 if (x>infoPtr->uTotalWidth)
1151 infoPtr->uTotalWidth=x;
1152 }
1153 else {
1154 iItem=(INT)wineItem->sibling;
1155 while ((!iItem) && (indent>0)) {
1156 indent--;
1157 x-=infoPtr->uIndent;
1158 prevItem=wineItem;
1159 wineItem=&infoPtr->items[(INT)wineItem->parent];
1160 iItem=(INT)wineItem->sibling;
1161 }
1162 }
1163 y +=height;
1164 } /* while */
1165
1166/* FIXME: infoPtr->uTotalWidth should also take item label into account */
1167/* FIXME: or should query item sizes (ie check CDRF_NEWFONT) */
1168
1169 infoPtr->uTotalHeight=y;
1170 if (y >= (viewbottom-viewtop)) {
1171 if (!(infoPtr->uInternalStatus & TV_VSCROLL))
1172 ShowScrollBar (hwnd, SB_VERT, TRUE);
1173 infoPtr->uInternalStatus |=TV_VSCROLL;
1174 SetScrollRange (hwnd, SB_VERT, 0,
1175 y - infoPtr->uVisibleHeight, FALSE);
1176 SetScrollPos (hwnd, SB_VERT, infoPtr->cy, TRUE);
1177 }
1178 else {
1179 if (infoPtr->uInternalStatus & TV_VSCROLL)
1180 ShowScrollBar (hwnd, SB_VERT, FALSE);
1181 infoPtr->uInternalStatus &= ~TV_VSCROLL;
1182 }
1183
1184
1185 if (infoPtr->cdmode & CDRF_NOTIFYPOSTPAINT)
1186 infoPtr->cdmode=TREEVIEW_SendCustomDrawNotify
1187 (hwnd, CDDS_POSTPAINT, hdc, rect);
1188
1189 ReleaseDC (hwnd, hdc);
1190 //TRACE("done\n");
1191}
1192
1193
1194static LRESULT
1195TREEVIEW_HandleTimer (HWND hwnd, WPARAM wParam, LPARAM lParam)
1196{
1197 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1198
1199// TRACE (treeview, " %d\n",wParam);
1200 if (!infoPtr) return FALSE;
1201
1202 switch (wParam) {
1203 case TV_REFRESH_TIMER:
1204 KillTimer (hwnd, TV_REFRESH_TIMER);
1205 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET;
1206 InvalidateRect(hwnd, NULL, FALSE);
1207 return 0;
1208 case TV_EDIT_TIMER:
1209 KillTimer (hwnd, TV_EDIT_TIMER);
1210 infoPtr->Timer &= ~TV_EDIT_TIMER_SET;
1211 return 0;
1212 default:
1213// ERR (treeview,"got unknown timer\n");
1214 break;
1215 }
1216
1217 return 1;
1218}
1219
1220
1221static void
1222TREEVIEW_QueueRefresh (HWND hwnd)
1223
1224{
1225 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1226
1227// TRACE (treeview,"\n");
1228 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) {
1229 KillTimer (hwnd, TV_REFRESH_TIMER);
1230 }
1231
1232 SetTimer (hwnd, TV_REFRESH_TIMER, TV_REFRESH_DELAY, 0);
1233 infoPtr->Timer|=TV_REFRESH_TIMER_SET;
1234}
1235
1236
1237
1238static LRESULT
1239TREEVIEW_GetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1240{
1241 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1242 LPTVITEMEXA tvItem;
1243 TREEVIEW_ITEM *wineItem;
1244 INT iItem;
1245
1246 tvItem=(LPTVITEMEXA) lParam;
1247 iItem=(INT)tvItem->hItem;
1248
1249 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1250 if (!wineItem) return FALSE;
1251
1252 if (tvItem->mask & TVIF_CHILDREN) {
1253// if (TVIF_CHILDREN==I_CHILDRENCALLBACK)
1254// FIXME (treeview,"I_CHILDRENCALLBACK not supported\n");
1255 tvItem->cChildren=wineItem->cChildren;
1256 }
1257
1258 if (tvItem->mask & TVIF_HANDLE) {
1259 tvItem->hItem=wineItem->hItem;
1260 }
1261
1262 if (tvItem->mask & TVIF_IMAGE) {
1263 tvItem->iImage=wineItem->iImage;
1264 }
1265
1266 if (tvItem->mask & TVIF_INTEGRAL) {
1267 tvItem->iIntegral=wineItem->iIntegral;
1268 }
1269
1270 // undocumented: windows ignores TVIF_PARAM and
1271 // always sets lParam
1272 tvItem->lParam=wineItem->lParam;
1273
1274 if (tvItem->mask & TVIF_SELECTEDIMAGE) {
1275 tvItem->iSelectedImage=wineItem->iSelectedImage;
1276 }
1277
1278 if (tvItem->mask & TVIF_STATE) {
1279 tvItem->state=wineItem->state & tvItem->stateMask;
1280 }
1281
1282 if (tvItem->mask & TVIF_TEXT) {
1283 if (wineItem->pszText == LPSTR_TEXTCALLBACKA) {
1284 tvItem->pszText = LPSTR_TEXTCALLBACKA; /* FIXME:send notification? */
1285// ERR (treeview," GetItem called with LPSTR_TEXTCALLBACK\n");
1286 }
1287 else if (wineItem->pszText) {
1288 lstrcpynA (tvItem->pszText, wineItem->pszText,tvItem->cchTextMax);
1289 }
1290 }
1291
1292// TRACE(treeview,"item %d<%p>, txt %p, img %p, action %x\n",
1293// iItem,
1294// tvItem,
1295// tvItem->pszText,
1296// & tvItem->iImage,
1297// tvItem->mask);
1298
1299 return TRUE;
1300}
1301
1302
1303
1304/* FIXME: check implementation of TVGN_NEXT/TVGN_NEXTVISIBLE */
1305
1306static LRESULT
1307TREEVIEW_GetNextItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
1308
1309{
1310 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1311 TREEVIEW_ITEM *wineItem, *returnItem;
1312 INT iItem, retval, flag;
1313
1314
1315 if (!infoPtr) return FALSE;
1316 flag = (INT) wParam;
1317 iItem = (INT) lParam;
1318 retval=0;
1319 switch (flag) {
1320 case TVGN_ROOT: retval=(INT)infoPtr->TopRootItem;
1321 break;
1322 case TVGN_CARET:retval=(INT)infoPtr->selectedItem;
1323 break;
1324 case TVGN_FIRSTVISIBLE:
1325 TREEVIEW_Refresh (hwnd);
1326/* FIXME:we should only recalculate, not redraw */
1327 retval=(INT)infoPtr->firstVisible;
1328 break;
1329 case TVGN_DROPHILITE:
1330 retval=(INT)infoPtr->dropItem;
1331 break;
1332 }
1333 if (retval) {
1334// TRACE (treeview,"flags:%x, returns %u\n", flag, retval);
1335 return retval;
1336 }
1337
1338 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
1339 returnItem = NULL;
1340 if (!wineItem) return FALSE;
1341
1342 switch (flag) {
1343 case TVGN_NEXT: retval=(INT)wineItem->sibling;
1344 break;
1345 case TVGN_PREVIOUS:
1346 retval=(INT)wineItem->upsibling;
1347 break;
1348 case TVGN_PARENT:
1349 retval=(INT)wineItem->parent;
1350 break;
1351 case TVGN_CHILD:
1352 retval=(INT)wineItem->firstChild;
1353 break;
1354 case TVGN_LASTVISIBLE:
1355 returnItem=TREEVIEW_GetLastListItem (infoPtr,wineItem);
1356 break;
1357 case TVGN_NEXTVISIBLE:
1358 returnItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
1359 break;
1360 case TVGN_PREVIOUSVISIBLE:
1361 returnItem=TREEVIEW_GetPrevListItem (infoPtr, wineItem);
1362 break;
1363 default: // FIXME (treeview,"Unknown msg %x,item %x\n", flag,iItem);
1364 break;
1365 }
1366
1367 if (returnItem) {
1368// TRACE (treeview,"flags:%x, item %d;returns %d\n", flag, iItem,
1369// (INT)returnItem->hItem);
1370 return (INT)returnItem->hItem;
1371 }
1372
1373// TRACE (treeview,"flags:%x, item %d;returns %d\n", flag, iItem,retval);
1374 return retval;
1375}
1376
1377
1378static LRESULT
1379TREEVIEW_GetCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
1380{
1381 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1382
1383// TRACE (treeview," %d\n",infoPtr->uNumItems);
1384 return (LRESULT) infoPtr->uNumItems;
1385}
1386
1387/***************************************************************************
1388 * This method does the chaining of the insertion of a treeview item
1389 * before an item.
1390 * If parent is NULL, we're inserting at the root of the list.
1391 */
1392static void TREEVIEW_InsertBefore(
1393 TREEVIEW_INFO *infoPtr,
1394 TREEVIEW_ITEM *newItem,
1395 TREEVIEW_ITEM *sibling,
1396 TREEVIEW_ITEM *parent)
1397{
1398 HTREEITEM siblingHandle = 0;
1399 HTREEITEM upSiblingHandle = 0;
1400 TREEVIEW_ITEM *upSibling = NULL;
1401
1402// if (newItem == NULL)
1403// ERR(treeview, "NULL newItem, impossible condition\n");
1404
1405// if (parent == NULL)
1406// ERR(treeview, "NULL parent, impossible condition\n");
1407
1408 if (sibling != NULL) /* Insert before this sibling for this parent */
1409 {
1410 /* Store the new item sibling up sibling and sibling tem handle */
1411 siblingHandle = sibling->hItem;
1412 upSiblingHandle = sibling->upsibling;
1413 /* As well as a pointer to the upsibling sibling object */
1414 if ( (INT)sibling->upsibling != 0 )
1415 upSibling = &infoPtr->items[(INT)sibling->upsibling];
1416
1417 /* Adjust the sibling pointer */
1418 sibling->upsibling = newItem->hItem;
1419
1420 /* Adjust the new item pointers */
1421 newItem->upsibling = upSiblingHandle;
1422 newItem->sibling = siblingHandle;
1423
1424 /* Adjust the up sibling pointer */
1425 if ( upSibling != NULL )
1426 upSibling->sibling = newItem->hItem;
1427 else
1428 if (parent)
1429 /* this item is the first child of this parent, adjust parent pointers */
1430 parent->firstChild = newItem->hItem;
1431 else infoPtr->TopRootItem = newItem->hItem;
1432 }
1433 else /* Insert as first child of this parent */
1434 if (parent)
1435 parent->firstChild = newItem->hItem;
1436}
1437
1438/***************************************************************************
1439 * This method does the chaining of the insertion of a treeview item
1440 * If parent is NULL, we're inserting at the root of the list.
1441 * after an item.
1442 */
1443static void TREEVIEW_InsertAfter(
1444 TREEVIEW_INFO *infoPtr,
1445 TREEVIEW_ITEM *newItem,
1446 TREEVIEW_ITEM *upSibling,
1447 TREEVIEW_ITEM *parent)
1448{
1449 HTREEITEM upSiblingHandle = 0;
1450 HTREEITEM siblingHandle = 0;
1451 TREEVIEW_ITEM *sibling = NULL;
1452
1453// if (newItem == NULL)
1454// ERR(treeview, "NULL newItem, impossible condition\n");
1455
1456// if (parent == NULL)
1457// ERR(treeview, "NULL parent, impossible condition\n");
1458
1459 if (upSibling != NULL) /* Insert after this upsibling for this parent */
1460 {
1461 /* Store the new item up sibling and sibling item handle */
1462 upSiblingHandle = upSibling->hItem;
1463 siblingHandle = upSibling->sibling;
1464 /* As well as a pointer to the upsibling sibling object */
1465 if ( (INT)upSibling->sibling != 0 )
1466 sibling = &infoPtr->items[(INT)upSibling->sibling];
1467
1468 /* Adjust the up sibling pointer */
1469 upSibling->sibling = newItem->hItem;
1470
1471 /* Adjust the new item pointers */
1472 newItem->upsibling = upSiblingHandle;
1473 newItem->sibling = siblingHandle;
1474
1475 /* Adjust the sibling pointer */
1476 if ( sibling != NULL )
1477 sibling->upsibling = newItem->hItem;
1478 /*
1479 else
1480 newItem is the last of the level, nothing else to do
1481 */
1482 }
1483 else /* Insert as first child of this parent */
1484 if (parent)
1485 parent->firstChild = newItem->hItem;
1486}
1487
1488/***************************************************************************
1489 * Forward the DPA local callback to the treeview owner callback
1490 */
1491static INT WINAPI TREEVIEW_CallBackCompare(
1492 LPVOID first,
1493 LPVOID second,
1494 LPARAM tvInfoPtr)
1495{
1496 /* Forward the call to the client define callback */
1497 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr((HWND)tvInfoPtr);
1498 return (infoPtr->pCallBackSort->lpfnCompare)(
1499 ((TREEVIEW_ITEM*)first)->lParam,
1500 ((TREEVIEW_ITEM*)second)->lParam,
1501 infoPtr->pCallBackSort->lParam);
1502}
1503
1504/***************************************************************************
1505 * Treeview native sort routine: sort on item text.
1506 */
1507static INT WINAPI TREEVIEW_SortOnName (
1508 LPVOID first,
1509 LPVOID second,
1510 LPARAM tvInfoPtr)
1511{
1512 HWND hwnd=(HWND) tvInfoPtr;
1513 char *txt1, *txt2;
1514 TREEVIEW_ITEM *item;
1515
1516
1517 item=(TREEVIEW_ITEM *) first;
1518 if (item->pszText==LPSTR_TEXTCALLBACKA) {
1519 TREEVIEW_SendDispInfoNotify (hwnd, item, TVN_GETDISPINFO, TVIF_TEXT);
1520 }
1521 txt1=item->pszText;
1522
1523 item=(TREEVIEW_ITEM *) second;
1524 if (item->pszText==LPSTR_TEXTCALLBACKA) {
1525 TREEVIEW_SendDispInfoNotify (hwnd, item, TVN_GETDISPINFO, TVIF_TEXT);
1526 }
1527 txt2=item->pszText;
1528
1529 return -strcmp (txt1,txt2);
1530}
1531
1532/***************************************************************************
1533 * Setup the treeview structure with regards of the sort method
1534 * and sort the children of the TV item specified in lParam
1535 * fRecurse: currently unused. Should be zero.
1536 * parent: if pSort!=NULL, should equal pSort->hParent.
1537 * otherwise, item which child items are to be sorted.
1538 * pSort: sort method info. if NULL, sort on item text.
1539 * if non-NULL, sort on item's lParam content, and let the
1540 * application decide what that means. See also TVM_SORTCHILDRENCB.
1541 */
1542
1543static LRESULT WINAPI TREEVIEW_Sort (
1544 HWND hwnd,
1545 BOOL fRecurse,
1546 HTREEITEM parent,
1547 LPTVSORTCB pSort
1548 )
1549{
1550 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1551 TREEVIEW_ITEM *sortMe = NULL; /* Node for which we sort the children */
1552
1553 /* Obtain the TVSORTBC struct */
1554 infoPtr->pCallBackSort = pSort;
1555
1556 /* undocumented feature: TVI_ROOT means `sort the whole tree' */
1557
1558 if (parent==TVI_ROOT)
1559 parent=infoPtr->TopRootItem;
1560
1561 /* Check for a valid handle to the parent item */
1562 if (!TREEVIEW_ValidItem(infoPtr, parent))
1563 {
1564 //ERR ("invalid item hParent=%x\n", (INT)parent);
1565 return FALSE;
1566 }
1567
1568 /* Obtain the parent node to sort */
1569 sortMe = &infoPtr->items[ (INT)parent ];
1570
1571 /* Make sure there is something to sort */
1572 if ( sortMe->cChildren > 1 )
1573 {
1574 /* pointer organization */
1575 HDPA sortList = DPA_Create(sortMe->cChildren);
1576 HTREEITEM itemHandle = sortMe->firstChild;
1577 TREEVIEW_ITEM *itemPtr = & infoPtr->items[ (INT)itemHandle ];
1578
1579 /* TREEVIEW_ITEM rechaining */
1580 INT count = 0;
1581 VOID *item = 0;
1582 VOID *nextItem = 0;
1583 VOID *prevItem = 0;
1584
1585 /* Build the list of item to sort */
1586 do
1587 {
1588 DPA_InsertPtr(
1589 sortList, /* the list */
1590 sortMe->cChildren+1, /* force the insertion to be an append */
1591 itemPtr); /* the ptr to store */
1592
1593 /* Get the next sibling */
1594 itemHandle = itemPtr->sibling;
1595 itemPtr = & infoPtr->items[ (INT)itemHandle ];
1596 } while ( itemHandle != NULL );
1597
1598 /* let DPA perform the sort activity */
1599 if (pSort)
1600 DPA_Sort(
1601 sortList, /* what */
1602 TREEVIEW_CallBackCompare, /* how */
1603 hwnd); /* owner */
1604 else
1605 DPA_Sort (
1606 sortList, /* what */
1607 TREEVIEW_SortOnName, /* how */
1608 hwnd); /* owner */
1609
1610 /*
1611 * Reorganized TREEVIEW_ITEM structures.
1612 * Note that we know we have at least two elements.
1613 */
1614
1615 /* Get the first item and get ready to start... */
1616 item = DPA_GetPtr(sortList, count++);
1617 while ( (nextItem = DPA_GetPtr(sortList, count++)) != NULL )
1618 {
1619 /* link the two current item toghether */
1620 ((TREEVIEW_ITEM*)item)->sibling = ((TREEVIEW_ITEM*)nextItem)->hItem;
1621 ((TREEVIEW_ITEM*)nextItem)->upsibling = ((TREEVIEW_ITEM*)item)->hItem;
1622
1623 if (prevItem == NULL) /* this is the first item, update the parent */
1624 {
1625 sortMe->firstChild = ((TREEVIEW_ITEM*)item)->hItem;
1626 ((TREEVIEW_ITEM*)item)->upsibling = NULL;
1627 }
1628 else /* fix the back chaining */
1629 {
1630 ((TREEVIEW_ITEM*)item)->upsibling = ((TREEVIEW_ITEM*)prevItem)->hItem;
1631 }
1632
1633 /* get ready for the next one */
1634 prevItem = item;
1635 item = nextItem;
1636 }
1637
1638 /* the last item is pointed to by item and never has a sibling */
1639 ((TREEVIEW_ITEM*)item)->sibling = NULL;
1640
1641 DPA_Destroy(sortList);
1642
1643 return TRUE;
1644 }
1645 return FALSE;
1646}
1647
1648/***************************************************************************
1649 * Setup the treeview structure with regards of the sort method
1650 * and sort the children of the TV item specified in lParam
1651 */
1652static LRESULT WINAPI TREEVIEW_SortChildrenCB(
1653 HWND hwnd,
1654 WPARAM wParam,
1655 LPARAM lParam
1656 )
1657{
1658 LPTVSORTCB pSort=(LPTVSORTCB) lParam;
1659
1660 return TREEVIEW_Sort (hwnd, wParam, pSort->hParent, pSort);
1661}
1662
1663
1664/***************************************************************************
1665 * Sort the children of the TV item specified in lParam.
1666 */
1667static LRESULT WINAPI TREEVIEW_SortChildren (
1668 HWND hwnd,
1669 WPARAM wParam,
1670 LPARAM lParam)
1671{
1672 return TREEVIEW_Sort (hwnd, (BOOL) wParam, (HTREEITEM) lParam, NULL);
1673}
1674
1675
1676int ffs(int mask)
1677{
1678 int bit;
1679
1680 if (mask == 0)
1681 return(0);
1682 for (bit = 1; !(mask & 1); bit++)
1683 mask >>= 1;
1684 return(bit);
1685}
1686
1687/* the method used below isn't the most memory-friendly, but it avoids
1688 a lot of memory reallocations */
1689
1690/* BTW: we waste handle 0; 0 is not an allowed handle. */
1691
1692static LRESULT
1693TREEVIEW_InsertItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1694
1695{
1696 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
1697 TVINSERTSTRUCTA *ptdi;
1698 TVITEMEXA *tvItem;
1699 TREEVIEW_ITEM *wineItem, *parentItem, *prevsib, *sibItem;
1700 INT iItem,listItems,i,len;
1701
1702 /* Item to insert */
1703 ptdi = (LPTVINSERTSTRUCTA) lParam;
1704
1705 /* check if memory is available */
1706
1707 if (infoPtr->uNumPtrsAlloced==0) {
1708 infoPtr->items = COMCTL32_Alloc (TVITEM_ALLOC*sizeof (TREEVIEW_ITEM));
1709 infoPtr->freeList= COMCTL32_Alloc ((1+(TVITEM_ALLOC>>5)) * sizeof (INT));
1710 infoPtr->uNumPtrsAlloced=TVITEM_ALLOC;
1711 infoPtr->TopRootItem=(HTREEITEM)1;
1712 }
1713
1714 /*
1715 * Reallocate contiguous space for items
1716 */
1717 if (infoPtr->uNumItems == (infoPtr->uNumPtrsAlloced-1) ) {
1718 TREEVIEW_ITEM *oldItems = infoPtr->items;
1719 INT *oldfreeList = infoPtr->freeList;
1720
1721 infoPtr->uNumPtrsAlloced*=2;
1722 infoPtr->items = COMCTL32_Alloc (infoPtr->uNumPtrsAlloced*sizeof (TREEVIEW_ITEM));
1723 infoPtr->freeList= COMCTL32_Alloc ((1+(infoPtr->uNumPtrsAlloced>>5))*sizeof (INT));
1724
1725 memcpy (&infoPtr->items[0], &oldItems[0],
1726 infoPtr->uNumPtrsAlloced/2 * sizeof(TREEVIEW_ITEM));
1727 memcpy (&infoPtr->freeList[0], &oldfreeList[0],
1728 (infoPtr->uNumPtrsAlloced>>6) * sizeof(INT));
1729
1730 COMCTL32_Free (oldItems);
1731 COMCTL32_Free (oldfreeList);
1732 }
1733
1734 /*
1735 * Reset infoPtr structure with new stat according to current TV picture
1736 */
1737 iItem=0;
1738 infoPtr->uNumItems++;
1739 if ((INT)infoPtr->uMaxHandle==(infoPtr->uNumItems-1)) {
1740 iItem=infoPtr->uNumItems;
1741 infoPtr->uMaxHandle = (HTREEITEM)((INT)infoPtr->uMaxHandle + 1);
1742 } else { /* check freelist */
1743 for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++) {
1744 if (infoPtr->freeList[i]) {
1745 iItem=ffs (infoPtr->freeList[i])-1;
1746
1747 tv_clear_bit(iItem,&infoPtr->freeList[i]);
1748 iItem+=i<<5;
1749 break;
1750 }
1751 }
1752 }
1753
1754// if (TRACE_ON(treeview)) {
1755// for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++)
1756// TRACE (treeview,"%8x\n",infoPtr->freeList[i]);
1757// }
1758
1759// if (!iItem) ERR (treeview, "Argh -- can't find free item.\n");
1760
1761 /*
1762 * Find the parent item of the new item
1763 */
1764 tvItem= & ptdi->DUMMYUNIONNAME.itemex;
1765 wineItem=& infoPtr->items[iItem];
1766
1767 if ((ptdi->hParent==TVI_ROOT) || (ptdi->hParent==0)) {
1768 parentItem = NULL;
1769 wineItem->parent = 0;
1770 sibItem = &infoPtr->items [(INT)infoPtr->TopRootItem];
1771 listItems = infoPtr->uNumItems;
1772 }
1773 else {
1774 parentItem = &infoPtr->items[(INT)ptdi->hParent];
1775
1776 /* Do the insertion here it if it's the only item of this parent */
1777 if (!parentItem->firstChild)
1778 parentItem->firstChild=(HTREEITEM)iItem;
1779
1780 wineItem->parent = ptdi->hParent;
1781 sibItem = &infoPtr->items [(INT)parentItem->firstChild];
1782 parentItem->cChildren++;
1783 listItems = parentItem->cChildren;
1784 }
1785
1786
1787 /* NOTE: I am moving some setup of the wineItem object that was initialy
1788 * done at the end of the function since some of the values are
1789 * required by the Callback sorting
1790 */
1791
1792 if (tvItem->mask & TVIF_TEXT)
1793 {
1794 /*
1795 * Setup the item text stuff here since it's required by the Sort method
1796 * when the insertion are ordered
1797 */
1798 if (tvItem->pszText!=LPSTR_TEXTCALLBACKA)
1799 {
1800// TRACE (treeview,"(%p,%s)\n", &tvItem->pszText, tvItem->pszText);
1801 len = lstrlenA (tvItem->pszText)+1;
1802 wineItem->pszText= COMCTL32_Alloc (len+1);
1803 lstrcpyA (wineItem->pszText, tvItem->pszText);
1804 wineItem->cchTextMax=len;
1805 }
1806 else
1807 {
1808// TRACE (treeview,"LPSTR_TEXTCALLBACK\n");
1809 wineItem->pszText = LPSTR_TEXTCALLBACKA;
1810 wineItem->cchTextMax = 0;
1811 }
1812 }
1813
1814 if (tvItem->mask & TVIF_PARAM)
1815 wineItem->lParam=tvItem->lParam;
1816
1817
1818 wineItem->upsibling=0; /* needed in case we're the first item in a list */
1819 wineItem->sibling=0;
1820 wineItem->firstChild=0;
1821 wineItem->hItem=(HTREEITEM)iItem;
1822
1823 if (listItems>1) {
1824 prevsib=NULL;
1825
1826 switch ((DWORD) ptdi->hInsertAfter) {
1827 case (DWORD) TVI_FIRST:
1828 if (sibItem==wineItem) break;
1829 if (wineItem->parent) {
1830 wineItem->sibling=parentItem->firstChild;
1831 parentItem->firstChild=(HTREEITEM)iItem;
1832 } else {
1833 wineItem->sibling=infoPtr->TopRootItem;
1834 infoPtr->TopRootItem=(HTREEITEM)iItem;
1835 }
1836 sibItem->upsibling=(HTREEITEM)iItem;
1837 break;
1838
1839 case (DWORD) TVI_SORT:
1840 if (sibItem==wineItem)
1841 /*
1842 * This item is the first child of the level and it
1843 * has already been inserted
1844 */
1845 break;
1846 else
1847 {
1848 TREEVIEW_ITEM *aChild;
1849
1850 TREEVIEW_ITEM *previousChild = NULL;
1851 BOOL bItemInserted = FALSE;
1852
1853 if (parentItem)
1854 aChild = &infoPtr->items[(INT)parentItem->firstChild];
1855 else
1856 aChild = &infoPtr->items[(INT)infoPtr->TopRootItem];
1857
1858 /* lookup the text if using LPSTR_TEXTCALLBACKs */
1859 if (wineItem->pszText==LPSTR_TEXTCALLBACKA) {
1860 TREEVIEW_SendDispInfoNotify (hwnd, wineItem, TVN_GETDISPINFO, TVIF_TEXT);
1861 }
1862
1863 /* Iterate the parent children to see where we fit in */
1864 while ( aChild != NULL )
1865 {
1866 INT comp;
1867
1868 /* lookup the text if using LPSTR_TEXTCALLBACKs */
1869 if (aChild->pszText==LPSTR_TEXTCALLBACKA) {
1870 TREEVIEW_SendDispInfoNotify (hwnd, aChild, TVN_GETDISPINFO, TVIF_TEXT);
1871 }
1872
1873 comp = strcmp(wineItem->pszText, aChild->pszText);
1874 if ( comp < 0 ) /* we are smaller than the current one */
1875 {
1876 TREEVIEW_InsertBefore(infoPtr, wineItem, aChild, parentItem);
1877 bItemInserted = TRUE;
1878 break;
1879 }
1880 else if ( comp > 0 ) /* we are bigger than the current one */
1881 {
1882 previousChild = aChild;
1883 aChild = (aChild->sibling == 0) /* This will help us to exit */
1884 ? NULL /* if there is no more sibling */
1885 : &infoPtr->items[(INT)aChild->sibling];
1886
1887 /* Look at the next item */
1888 continue;
1889 }
1890 else if ( comp == 0 )
1891 {
1892 /*
1893 * An item with this name is already existing, therefore,
1894 * we add after the one we found
1895 */
1896 TREEVIEW_InsertAfter(infoPtr, wineItem, aChild, parentItem);
1897 bItemInserted = TRUE;
1898 break;
1899 }
1900 }
1901
1902 /*
1903 * we reach the end of the child list and the item as not
1904 * yet been inserted, therefore, insert it after the last child.
1905 */
1906 if ( (! bItemInserted ) && (aChild == NULL) )
1907 TREEVIEW_InsertAfter(infoPtr, wineItem, previousChild, parentItem);
1908
1909 break;
1910 }
1911
1912
1913 case (DWORD) TVI_LAST:
1914 if (sibItem==wineItem) break;
1915 while (sibItem->sibling) {
1916 prevsib=sibItem;
1917 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1918 }
1919 sibItem->sibling=(HTREEITEM)iItem;
1920 wineItem->upsibling=sibItem->hItem;
1921 break;
1922 default:
1923 while ((sibItem->sibling) && (sibItem->hItem!=ptdi->hInsertAfter))
1924 {
1925 prevsib=sibItem;
1926 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1927 }
1928 if (sibItem->hItem!=ptdi->hInsertAfter) {
1929// ERR (treeview, "tried to insert item after nonexisting handle.\n");
1930 break;
1931 }
1932 prevsib=sibItem;
1933 if (sibItem->sibling) {
1934 sibItem=&infoPtr->items [(INT)sibItem->sibling];
1935 sibItem->upsibling=(HTREEITEM)iItem;
1936 wineItem->sibling=sibItem->hItem;
1937 }
1938 prevsib->sibling=(HTREEITEM)iItem;
1939 wineItem->upsibling=prevsib->hItem;
1940 break;
1941 }
1942 }
1943
1944
1945/* Fill in info structure */
1946
1947// TRACE (treeview,"new item %d; parent %d, mask %x\n", iItem,
1948// (INT)wineItem->parent,tvItem->mask);
1949
1950 wineItem->mask=tvItem->mask;
1951 wineItem->iIntegral=1;
1952
1953 if (tvItem->mask & TVIF_CHILDREN) {
1954 wineItem->cChildren=tvItem->cChildren;
1955// if (tvItem->cChildren==I_CHILDRENCALLBACK)
1956// FIXME (treeview," I_CHILDRENCALLBACK not supported\n");
1957 }
1958
1959 wineItem->expandBox.left = 0; /* Initialize the expandBox */
1960 wineItem->expandBox.top = 0;
1961 wineItem->expandBox.right = 0;
1962 wineItem->expandBox.bottom = 0;
1963
1964 if (tvItem->mask & TVIF_IMAGE)
1965 wineItem->iImage=tvItem->iImage;
1966
1967 /* If the application sets TVIF_INTEGRAL without
1968 supplying a TVITEMEX structure, it's toast */
1969
1970 if (tvItem->mask & TVIF_INTEGRAL)
1971 wineItem->iIntegral=tvItem->iIntegral;
1972
1973 if (tvItem->mask & TVIF_SELECTEDIMAGE)
1974 wineItem->iSelectedImage=tvItem->iSelectedImage;
1975
1976 if (tvItem->mask & TVIF_STATE) {
1977// TRACE(treeview, "Changing item state from %d to %d\n",
1978// wineItem->state,
1979// tvItem->state);
1980 wineItem->state=tvItem->state;
1981 wineItem->stateMask=tvItem->stateMask;
1982 }
1983
1984
1985 TREEVIEW_QueueRefresh (hwnd);
1986
1987 return (LRESULT) iItem;
1988}
1989
1990
1991static LRESULT
1992TREEVIEW_InsertItemW(HWND hwnd, WPARAM wParam, LPARAM lParam)
1993{
1994 TVINSERTSTRUCTW *tvisW;
1995 TVINSERTSTRUCTA tvisA;
1996 LRESULT lRes;
1997
1998 tvisW = (LPTVINSERTSTRUCTW)lParam;
1999
2000 tvisA.hParent = tvisW->hParent;
2001 tvisA.hInsertAfter = tvisW->hInsertAfter;
2002
2003 tvisA.DUMMYUNIONNAME.item.mask = tvisW->DUMMYUNIONNAME.item.mask;
2004 tvisA.DUMMYUNIONNAME.item.hItem = tvisW->DUMMYUNIONNAME.item.hItem;
2005 tvisA.DUMMYUNIONNAME.item.state = tvisW->DUMMYUNIONNAME.item.state;
2006 tvisA.DUMMYUNIONNAME.item.stateMask = tvisW->DUMMYUNIONNAME.item.stateMask;
2007 tvisA.DUMMYUNIONNAME.item.cchTextMax = tvisW->DUMMYUNIONNAME.item.cchTextMax;
2008
2009 if(tvisW->DUMMYUNIONNAME.item.pszText)
2010 {
2011 if (tvisW->DUMMYUNIONNAME.item.pszText!=LPSTR_TEXTCALLBACKW)
2012 {
2013 int len = lstrlenW (tvisW->DUMMYUNIONNAME.item.pszText)+1;
2014 tvisA.DUMMYUNIONNAME.item.pszText = COMCTL32_Alloc (len);
2015 lstrcpyWtoA (tvisA.DUMMYUNIONNAME.item.pszText,
2016 tvisW->DUMMYUNIONNAME.item.pszText );
2017 }
2018 else
2019 {
2020 tvisA.DUMMYUNIONNAME.item.pszText = LPSTR_TEXTCALLBACKA;
2021 tvisA.DUMMYUNIONNAME.item.cchTextMax = 0;
2022 }
2023 }
2024
2025 tvisA.DUMMYUNIONNAME.item.iImage = tvisW->DUMMYUNIONNAME.item.iImage;
2026 tvisA.DUMMYUNIONNAME.item.iSelectedImage = tvisW->DUMMYUNIONNAME.item.iSelectedImage;
2027 tvisA.DUMMYUNIONNAME.item.cChildren = tvisW->DUMMYUNIONNAME.item.cChildren;
2028 tvisA.DUMMYUNIONNAME.item.lParam = tvisW->DUMMYUNIONNAME.item.lParam;
2029
2030 lRes = TREEVIEW_InsertItemA(hwnd,wParam,(LPARAM)&tvisA);
2031
2032 if (tvisA.DUMMYUNIONNAME.item.pszText!=LPSTR_TEXTCALLBACKA)
2033 {
2034 COMCTL32_Free(tvisA.DUMMYUNIONNAME.item.pszText);
2035 }
2036
2037 return lRes;
2038
2039}
2040
2041
2042static LRESULT
2043TREEVIEW_DeleteItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
2044{
2045 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2046 INT iItem;
2047 TREEVIEW_ITEM *wineItem;
2048
2049// TRACE (treeview,"\n");
2050 if (!infoPtr) return FALSE;
2051
2052 if (lParam == (INT)TVI_ROOT) {
2053 TREEVIEW_RemoveTree (hwnd);
2054 } else {
2055 iItem= (INT) lParam;
2056 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem);
2057 if (!wineItem) return FALSE;
2058// TRACE (treeview,"%s\n",wineItem->pszText);
2059 TREEVIEW_RemoveItem (hwnd, wineItem);
2060 }
2061
2062 TREEVIEW_QueueRefresh (hwnd);
2063
2064 return TRUE;
2065}
2066
2067
2068
2069static LRESULT
2070TREEVIEW_GetIndent (HWND hwnd)
2071{
2072 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2073
2074// TRACE (treeview,"\n");
2075 return infoPtr->uIndent;
2076}
2077
2078static LRESULT
2079TREEVIEW_SetIndent (HWND hwnd, WPARAM wParam)
2080{
2081 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2082 INT newIndent;
2083
2084// TRACE (treeview,"\n");
2085 newIndent=(INT) wParam;
2086 if (newIndent < MINIMUM_INDENT) newIndent=MINIMUM_INDENT;
2087 infoPtr->uIndent=newIndent;
2088
2089 return 0;
2090}
2091
2092static LRESULT
2093TREEVIEW_GetToolTips (HWND hwnd)
2094
2095{
2096 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2097
2098// TRACE (treeview,"\n");
2099 return infoPtr->hwndToolTip;
2100}
2101
2102
2103static LRESULT
2104TREEVIEW_SetToolTips (HWND hwnd, WPARAM wParam)
2105
2106{
2107 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2108 HWND prevToolTip;
2109
2110// TRACE (treeview,"\n");
2111 prevToolTip=infoPtr->hwndToolTip;
2112 infoPtr->hwndToolTip= (HWND) wParam;
2113
2114 return prevToolTip;
2115}
2116
2117
2118static LRESULT CALLBACK
2119TREEVIEW_GetEditControl (HWND hwnd)
2120
2121{
2122 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2123
2124 return infoPtr->hwndEdit;
2125}
2126
2127
2128//@@@PH: Note - this SubclassProc is sometimes called with the
2129// wrong window handle. Therefore, infoPtr points to anything
2130// but the expected structure.
2131LRESULT CALLBACK
2132TREEVIEW_Edit_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam,
2133 LPARAM lParam)
2134{
2135 switch (uMsg)
2136 {
2137 case WM_ERASEBKGND:
2138 {
2139 RECT rc;
2140 HDC hdc = (HDC) wParam;
2141 GetClientRect (hwnd, &rc);
2142 Rectangle (hdc, rc.left, rc.top, rc.right, rc.bottom);
2143 return -1;
2144 }
2145
2146 case WM_GETDLGCODE:
2147 {
2148 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
2149 }
2150
2151 default:
2152 {
2153 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd));
2154
2155 //@@@PH 1999/11/05 method called with freed infoPtr memory object
2156 if (infoPtr != NULL)
2157 return CallWindowProcA( infoPtr->wpEditOrig, hwnd, uMsg, wParam, lParam);
2158 else
2159 break;
2160 }
2161 }
2162
2163 return 0;
2164}
2165
2166
2167/* should handle edit control messages here */
2168
2169static LRESULT
2170TREEVIEW_Command (HWND hwnd, WPARAM wParam, LPARAM lParam)
2171
2172{
2173// TRACE (treeview, "%x %ld\n",wParam, lParam);
2174
2175 switch (HIWORD(wParam))
2176 {
2177 case EN_UPDATE:
2178 {
2179 /*
2180 * Adjust the edit window size
2181 */
2182 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2183 TREEVIEW_ITEM *editItem = TREEVIEW_ValidItem(infoPtr, infoPtr->editItem);
2184 INT iLength = GetWindowTextLengthA(infoPtr->hwndEdit);
2185 HDC hdc = GetDC(infoPtr->hwndEdit);
2186 TEXTMETRICA tm;
2187
2188 if ( GetTextMetricsA(hdc, &tm) )
2189 {
2190 LONG newWidth = (iLength * tm.tmAveCharWidth) + 15;
2191
2192 SetWindowPos (
2193 infoPtr->hwndEdit,
2194 HWND_TOP,
2195 editItem->text.left - 2,
2196 editItem->text.top - 1,
2197 newWidth,
2198 editItem->text.bottom - editItem->text.top + 3,
2199 SWP_DRAWFRAME );
2200 }
2201 ReleaseDC(hwnd, hdc);
2202
2203 break;
2204 }
2205
2206 case EN_KILLFOCUS:
2207/* TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
2208*/
2209 break;
2210
2211 default:
2212 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
2213 }
2214
2215 return 0;
2216}
2217
2218static LRESULT
2219TREEVIEW_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
2220
2221{
2222 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2223
2224 if (infoPtr->bAutoSize)
2225 {
2226 infoPtr->bAutoSize = FALSE;
2227 return 0;
2228 }
2229 infoPtr->bAutoSize = TRUE;
2230
2231 if (wParam == SIZE_RESTORED)
2232 {
2233 infoPtr->uTotalWidth = LOWORD (lParam);
2234 infoPtr->uTotalHeight = HIWORD (lParam);
2235 } else {
2236// FIXME (treeview,"WM_SIZE flag %x %lx not handled\n", wParam, lParam);
2237 }
2238
2239 TREEVIEW_QueueRefresh (hwnd);
2240 return 0;
2241}
2242
2243
2244
2245static LRESULT
2246TREEVIEW_StyleChanged (HWND hwnd, WPARAM wParam, LPARAM lParam)
2247{
2248// TRACE (treeview,"(%x %lx)\n",wParam,lParam);
2249
2250 TREEVIEW_Refresh(hwnd);
2251
2252 return 0;
2253}
2254
2255static LRESULT
2256TREEVIEW_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
2257{
2258 TREEVIEW_INFO *infoPtr;
2259 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
2260 LOGFONTA logFont;
2261 TEXTMETRICA tm;
2262 HDC hdc;
2263
2264 TRACE("wnd %x, style %lx\n",hwnd,dwStyle);
2265 /* allocate memory for info structure */
2266 infoPtr = (TREEVIEW_INFO *) COMCTL32_Alloc (sizeof(TREEVIEW_INFO));
2267
2268 SetWindowLongA( hwnd, 0, (DWORD)infoPtr);
2269
2270 if (infoPtr == NULL) {
2271 ERR("could not allocate info memory!\n");
2272 return 0;
2273 }
2274
2275 if ((TREEVIEW_INFO*) GetWindowLongA( hwnd, 0) != infoPtr) {
2276 ERR("pointer assignment error!\n");
2277 return 0;
2278 }
2279
2280 hdc=GetDC (hwnd);
2281
2282 /* set default settings */
2283 infoPtr->uInternalStatus=0;
2284 infoPtr->uNumItems=0;
2285 infoPtr->clrBk = GetSysColor (COLOR_WINDOW);
2286 infoPtr->clrText = GetSysColor (COLOR_WINDOWTEXT);
2287 infoPtr->clrLine = GetSysColor (COLOR_WINDOWTEXT);
2288 infoPtr->clrInsertMark = GetSysColor (COLOR_BTNTEXT);
2289 infoPtr->cy = 0;
2290 infoPtr->cx = 0;
2291 infoPtr->uIndent = 15;
2292 infoPtr->himlNormal = NULL;
2293 infoPtr->himlState = NULL;
2294 infoPtr->uItemHeight = -1;
2295 GetTextMetricsA (hdc, &tm);
2296 infoPtr->hFont = GetStockObject (DEFAULT_GUI_FONT);
2297 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
2298 logFont.lfWeight=FW_BOLD;
2299 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
2300
2301 infoPtr->items = NULL;
2302 infoPtr->selectedItem=0;
2303 infoPtr->clrText=-1; /* use system color */
2304 infoPtr->dropItem=0;
2305 infoPtr->insertMarkItem=0;
2306 infoPtr->insertBeforeorAfter=0;
2307 infoPtr->pCallBackSort=NULL;
2308 infoPtr->uScrollTime = 300; /* milliseconds */
2309
2310 infoPtr->hwndToolTip=0;
2311 if (!(dwStyle & TVS_NOTOOLTIPS)) { /* Create tooltip control */
2312 TTTOOLINFOA ti;
2313
2314 infoPtr->hwndToolTip =
2315 CreateWindowExA (0, TOOLTIPS_CLASSA, NULL, 0,
2316 CW_USEDEFAULT, CW_USEDEFAULT,
2317 CW_USEDEFAULT, CW_USEDEFAULT,
2318 hwnd, 0, 0, 0);
2319
2320 /* Send NM_TOOLTIPSCREATED notification */
2321 if (infoPtr->hwndToolTip) {
2322 NMTOOLTIPSCREATED nmttc;
2323
2324 nmttc.hdr.hwndFrom = hwnd;
2325 nmttc.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2326 nmttc.hdr.code = NM_TOOLTIPSCREATED;
2327 nmttc.hwndToolTips = infoPtr->hwndToolTip;
2328
2329 SendMessageA (GetParent (hwnd), WM_NOTIFY,
2330 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmttc);
2331 }
2332
2333 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
2334 ti.cbSize = sizeof(TTTOOLINFOA);
2335 ti.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_TRANSPARENT ;
2336 ti.hwnd = hwnd;
2337 ti.uId = 0;
2338 ti.lpszText = "Test"; /* LPSTR_TEXTCALLBACK; */
2339 SetRectEmpty (&ti.rect);
2340
2341 SendMessageA (infoPtr->hwndToolTip, TTM_ADDTOOLA, 0, (LPARAM)&ti);
2342 }
2343
2344 // @@@PH 1999/11/05
2345 infoPtr->wpEditOrig = NULL; /* no subclass */
2346
2347 infoPtr->hwndEdit = CreateWindowExA (
2348 WS_EX_LEFT,
2349 "EDIT",
2350 0,
2351 WS_CHILD | WS_BORDER | ES_AUTOHSCROLL |
2352 ES_WANTRETURN | ES_LEFT,
2353 0, 0, 0, 0,
2354 hwnd,
2355 0,0,0); /* FIXME: (HMENU)IDTVEDIT,pcs->hInstance,0);*/
2356
2357 SendMessageA ( infoPtr->hwndEdit, WM_SETFONT, infoPtr->hFont, FALSE);
2358 infoPtr->wpEditOrig = (WNDPROC)SetWindowLongA (
2359 infoPtr->hwndEdit,
2360 GWL_WNDPROC,
2361 (LONG) TREEVIEW_Edit_SubclassProc);
2362
2363 if (dwStyle & TVS_CHECKBOXES) {
2364 HBITMAP hbmLoad;
2365 int nIndex;
2366
2367 infoPtr->himlState =
2368 ImageList_Create (16, 16,ILC_COLOR|ILC_MASK, 15, 1);
2369
2370 hbmLoad = LoadBitmapA (COMCTL32_hModule, MAKEINTRESOURCEA(IDT_CHECK));
2371 TRACE ("%x\n",hbmLoad);
2372 nIndex = ImageList_AddMasked (infoPtr->himlState, hbmLoad, CLR_DEFAULT);
2373 TRACE ("%d\n",nIndex);
2374 DeleteObject (hbmLoad);
2375 }
2376 ReleaseDC (hwnd, hdc);
2377 return 0;
2378}
2379
2380
2381
2382static LRESULT
2383TREEVIEW_Destroy (HWND hwnd)
2384{
2385 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2386
2387// TRACE (treeview,"\n");
2388
2389 TREEVIEW_RemoveTree (hwnd);
2390
2391 //@@@PH 1999/11/05 set infoPtr to NULL
2392 SetWindowLongA( hwnd, 0, (DWORD)NULL);
2393
2394 if (infoPtr->Timer & TV_REFRESH_TIMER_SET)
2395 KillTimer (hwnd, TV_REFRESH_TIMER);
2396 if (infoPtr->hwndToolTip)
2397 DestroyWindow (infoPtr->hwndToolTip);
2398
2399 COMCTL32_Free (infoPtr);
2400
2401 return 0;
2402}
2403
2404
2405static LRESULT
2406TREEVIEW_Paint (HWND hwnd, WPARAM wParam, LPARAM lParam)
2407{
2408 HDC hdc;
2409 PAINTSTRUCT ps;
2410
2411// TRACE (treeview,"\n");
2412 hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
2413 TREEVIEW_Refresh (hwnd);
2414 if(!wParam)
2415 EndPaint (hwnd, &ps);
2416// TRACE (treeview,"done\n");
2417
2418 return DefWindowProcA (hwnd, WM_PAINT, wParam, lParam);
2419}
2420
2421static LRESULT
2422TREEVIEW_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2423{
2424 TREEVIEW_SendSimpleNotify (hwnd, NM_SETFOCUS);
2425 InvalidateRect(hwnd, NULL, FALSE);
2426 return 0;
2427}
2428
2429static LRESULT
2430TREEVIEW_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
2431{
2432 TREEVIEW_SendSimpleNotify (hwnd, NM_KILLFOCUS);
2433 InvalidateRect(hwnd, NULL, FALSE);
2434 return 0;
2435}
2436
2437static LRESULT
2438TREEVIEW_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
2439{
2440 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2441 HBRUSH hBrush = CreateSolidBrush (infoPtr->clrBk);
2442 RECT rect;
2443
2444// TRACE (treeview,"\n");
2445 GetClientRect (hwnd, &rect);
2446 FillRect ((HDC)wParam, &rect, hBrush);
2447 DeleteObject (hBrush);
2448 return TRUE;
2449}
2450
2451
2452
2453
2454
2455
2456/* Notifications */
2457
2458
2459
2460
2461
2462static BOOL
2463TREEVIEW_SendSimpleNotify (HWND hwnd, UINT code)
2464{
2465 NMHDR nmhdr;
2466
2467// TRACE (treeview, "%x\n",code);
2468 nmhdr.hwndFrom = hwnd;
2469 nmhdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2470 nmhdr.code = code;
2471
2472 return (BOOL) SendMessageA (GetParent (hwnd), WM_NOTIFY,
2473 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
2474}
2475
2476
2477
2478static BOOL
2479TREEVIEW_SendTreeviewNotify (HWND hwnd, UINT code, UINT action,
2480 HTREEITEM oldItem, HTREEITEM newItem)
2481
2482{
2483 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2484 NMTREEVIEWA nmhdr;
2485 TREEVIEW_ITEM *wineItem;
2486
2487// TRACE (treeview,"code:%x action:%x olditem:%x newitem:%x\n",
2488// code,action,(INT)oldItem,(INT)newItem);
2489 nmhdr.hdr.hwndFrom = hwnd;
2490 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2491 nmhdr.hdr.code = code;
2492 nmhdr.action = action;
2493 if (oldItem) {
2494 wineItem=& infoPtr->items[(INT)oldItem];
2495 nmhdr.itemOld.mask = wineItem->mask;
2496 nmhdr.itemOld.hItem = wineItem->hItem;
2497 nmhdr.itemOld.state = wineItem->state;
2498 nmhdr.itemOld.stateMask = wineItem->stateMask;
2499 nmhdr.itemOld.iImage = wineItem->iImage;
2500 nmhdr.itemOld.pszText = wineItem->pszText;
2501 nmhdr.itemOld.cchTextMax= wineItem->cchTextMax;
2502 nmhdr.itemOld.iImage = wineItem->iImage;
2503 nmhdr.itemOld.iSelectedImage = wineItem->iSelectedImage;
2504 nmhdr.itemOld.cChildren = wineItem->cChildren;
2505 nmhdr.itemOld.lParam = wineItem->lParam;
2506 }
2507
2508 if (newItem) {
2509 wineItem=& infoPtr->items[(INT)newItem];
2510 nmhdr.itemNew.mask = wineItem->mask;
2511 nmhdr.itemNew.hItem = wineItem->hItem;
2512 nmhdr.itemNew.state = wineItem->state;
2513 nmhdr.itemNew.stateMask = wineItem->stateMask;
2514 nmhdr.itemNew.iImage = wineItem->iImage;
2515 nmhdr.itemNew.pszText = wineItem->pszText;
2516 nmhdr.itemNew.cchTextMax= wineItem->cchTextMax;
2517 nmhdr.itemNew.iImage = wineItem->iImage;
2518 nmhdr.itemNew.iSelectedImage = wineItem->iSelectedImage;
2519 nmhdr.itemNew.cChildren = wineItem->cChildren;
2520 nmhdr.itemNew.lParam = wineItem->lParam;
2521 }
2522
2523 nmhdr.ptDrag.x = 0;
2524 nmhdr.ptDrag.y = 0;
2525
2526 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2527 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2528
2529}
2530
2531static BOOL
2532TREEVIEW_SendTreeviewDnDNotify (HWND hwnd, UINT code, HTREEITEM dragItem,
2533 POINT pt)
2534{
2535 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2536 NMTREEVIEWA nmhdr;
2537 TREEVIEW_ITEM *wineItem;
2538
2539// TRACE (treeview,"code:%x dragitem:%x\n", code,(INT)dragItem);
2540
2541 nmhdr.hdr.hwndFrom = hwnd;
2542 nmhdr.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2543 nmhdr.hdr.code = code;
2544 nmhdr.action = 0;
2545 wineItem=& infoPtr->items[(INT)dragItem];
2546 nmhdr.itemNew.mask = wineItem->mask;
2547 nmhdr.itemNew.hItem = wineItem->hItem;
2548 nmhdr.itemNew.state = wineItem->state;
2549 nmhdr.itemNew.lParam = wineItem->lParam;
2550
2551 nmhdr.ptDrag.x = pt.x;
2552 nmhdr.ptDrag.y = pt.y;
2553
2554 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2555 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmhdr);
2556
2557}
2558
2559
2560
2561static BOOL
2562TREEVIEW_SendDispInfoNotify (HWND hwnd, TREEVIEW_ITEM *wineItem,
2563 UINT code, UINT what)
2564{
2565 NMTVDISPINFOA tvdi;
2566 BOOL retval;
2567 char *buf;
2568
2569// TRACE (treeview,"item %d, action %x, state %d\n",
2570// (INT)wineItem->hItem,
2571// what,
2572// (INT)wineItem->state);
2573
2574 tvdi.hdr.hwndFrom = hwnd;
2575 tvdi.hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2576 tvdi.hdr.code = code;
2577 tvdi.item.mask = what;
2578 tvdi.item.hItem = wineItem->hItem;
2579 tvdi.item.state = wineItem->state;
2580 tvdi.item.lParam = wineItem->lParam;
2581 tvdi.item.pszText = COMCTL32_Alloc (128*sizeof(char));
2582 tvdi.item.cchTextMax = 128;
2583 buf = tvdi.item.pszText;
2584
2585 retval=(BOOL)SendMessageA (
2586 GetParent(hwnd),
2587 WM_NOTIFY,
2588 (WPARAM)tvdi.hdr.idFrom,
2589 (LPARAM)&tvdi);
2590
2591 if (what & TVIF_TEXT) {
2592 wineItem->pszText = tvdi.item.pszText;
2593 if (buf==tvdi.item.pszText) {
2594 wineItem->cchTextMax = 128;
2595 } else {
2596// TRACE (treeview,"user-supplied buffer\n");
2597 COMCTL32_Free (buf);
2598 wineItem->cchTextMax = 0;
2599 }
2600 }
2601 if (what & TVIF_SELECTEDIMAGE)
2602 wineItem->iSelectedImage = tvdi.item.iSelectedImage;
2603 if (what & TVIF_IMAGE)
2604 wineItem->iImage = tvdi.item.iImage;
2605 if (what & TVIF_CHILDREN)
2606 wineItem->cChildren = tvdi.item.cChildren;
2607
2608 return retval;
2609}
2610
2611
2612
2613static BOOL
2614TREEVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
2615 RECT rc)
2616{
2617 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2618 NMTVCUSTOMDRAW nmcdhdr;
2619 LPNMCUSTOMDRAW nmcd;
2620
2621// TRACE (treeview,"drawstage:%lx hdc:%x\n", dwDrawStage, hdc);
2622
2623 nmcd= & nmcdhdr.nmcd;
2624 nmcd->hdr.hwndFrom = hwnd;
2625 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2626 nmcd->hdr.code = NM_CUSTOMDRAW;
2627 nmcd->dwDrawStage= dwDrawStage;
2628 nmcd->hdc = hdc;
2629 nmcd->rc.left = rc.left;
2630 nmcd->rc.right = rc.right;
2631 nmcd->rc.bottom = rc.bottom;
2632 nmcd->rc.top = rc.top;
2633 nmcd->dwItemSpec = 0;
2634 nmcd->uItemState = 0;
2635 nmcd->lItemlParam= 0;
2636 nmcdhdr.clrText = infoPtr->clrText;
2637 nmcdhdr.clrTextBk= infoPtr->clrBk;
2638 nmcdhdr.iLevel = 0;
2639
2640 return (BOOL)SendMessageA (GetParent (hwnd), WM_NOTIFY,
2641 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2642
2643}
2644
2645
2646
2647/* FIXME: need to find out when the flags in uItemState need to be set */
2648
2649static BOOL
2650TREEVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc,
2651 TREEVIEW_ITEM *wineItem, UINT uItemDrawState)
2652{
2653 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2654 NMTVCUSTOMDRAW nmcdhdr;
2655 LPNMCUSTOMDRAW nmcd;
2656 DWORD dwDrawStage,dwItemSpec;
2657 UINT uItemState;
2658 INT retval;
2659
2660 dwDrawStage=CDDS_ITEM | uItemDrawState;
2661 dwItemSpec=(DWORD)wineItem->hItem;
2662 uItemState=0;
2663 if (wineItem->hItem==infoPtr->selectedItem) uItemState|=CDIS_SELECTED;
2664 if (wineItem->hItem==infoPtr->focusItem) uItemState|=CDIS_FOCUS;
2665 if (wineItem->hItem==infoPtr->hotItem) uItemState|=CDIS_HOT;
2666
2667 nmcd= & nmcdhdr.nmcd;
2668 nmcd->hdr.hwndFrom = hwnd;
2669 nmcd->hdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
2670 nmcd->hdr.code = NM_CUSTOMDRAW;
2671 nmcd->dwDrawStage= dwDrawStage;
2672 nmcd->hdc = hdc;
2673 nmcd->rc.left = wineItem->rect.left;
2674 nmcd->rc.right = wineItem->rect.right;
2675 nmcd->rc.bottom = wineItem->rect.bottom;
2676 nmcd->rc.top = wineItem->rect.top;
2677 nmcd->dwItemSpec = dwItemSpec;
2678 nmcd->uItemState = uItemState;
2679 nmcd->lItemlParam= wineItem->lParam;
2680
2681 nmcdhdr.clrText = infoPtr->clrText;
2682 nmcdhdr.clrTextBk= infoPtr->clrBk;
2683 nmcdhdr.iLevel = wineItem->iLevel;
2684
2685// TRACE (treeview,"drawstage:%lx hdc:%x item:%lx, itemstate:%x\n",
2686// dwDrawStage, hdc, dwItemSpec, uItemState);
2687
2688 retval=SendMessageA (GetParent (hwnd), WM_NOTIFY,
2689 (WPARAM) GetWindowLongA( hwnd, GWL_ID), (LPARAM)&nmcdhdr);
2690
2691 infoPtr->clrText=nmcdhdr.clrText;
2692 infoPtr->clrBk =nmcdhdr.clrTextBk;
2693 return (BOOL) retval;
2694}
2695
2696
2697
2698/* Note:If the specified item is the child of a collapsed parent item,
2699 the parent's list of child items is (recursively) expanded to reveal the
2700 specified item. This is mentioned for TREEVIEW_SelectItem; don't
2701 know if it also applies here.
2702*/
2703
2704static LRESULT
2705TREEVIEW_Expand (HWND hwnd, WPARAM wParam, LPARAM lParam)
2706{
2707 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2708 TREEVIEW_ITEM *wineItem;
2709 UINT flag;
2710 INT expand;
2711
2712 flag = (UINT) wParam;
2713 expand = (INT) lParam;
2714
2715 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2716
2717 if (!wineItem)
2718 return 0;
2719 if (!wineItem->cChildren)
2720 return 0;
2721
2722// TRACE (treeview,"For (%s) flags:%x item:%d state:%d\n",
2723// wineItem->pszText,
2724// flag,
2725// expand,
2726// wineItem->state);
2727
2728 if (wineItem->cChildren==I_CHILDRENCALLBACK) {
2729// FIXME (treeview,"we don't handle I_CHILDRENCALLBACK yet\n");
2730 return 0;
2731 }
2732
2733 if (flag == TVE_TOGGLE) { /* FIXME: check exact behaviour here */
2734 flag &= ~TVE_TOGGLE; /* ie: bitwise ops or 'case' ops */
2735 if (wineItem->state & TVIS_EXPANDED)
2736 flag |= TVE_COLLAPSE;
2737 else
2738 flag |= TVE_EXPAND;
2739 }
2740
2741 switch (flag)
2742 {
2743 case TVE_COLLAPSERESET:
2744// TRACE(treeview, " case TVE_COLLAPSERESET\n");
2745 if (!wineItem->state & TVIS_EXPANDED)
2746 return 0;
2747
2748 wineItem->state &= ~(TVIS_EXPANDEDONCE | TVIS_EXPANDED);
2749 TREEVIEW_RemoveAllChildren (hwnd, wineItem);
2750 break;
2751
2752 case TVE_COLLAPSE:
2753// TRACE(treeview, " case TVE_COLLAPSE\n");
2754 if (!wineItem->state & TVIS_EXPANDED)
2755 return 0;
2756
2757 wineItem->state &= ~TVIS_EXPANDED;
2758 break;
2759
2760 case TVE_EXPAND:
2761// TRACE(treeview, " case TVE_EXPAND\n");
2762 if (wineItem->state & TVIS_EXPANDED)
2763 return 0;
2764
2765// TRACE(treeview, " is not expanded...\n");
2766
2767 if (!(wineItem->state & TVIS_EXPANDEDONCE))
2768 {
2769// TRACE(treeview, " and has never been expanded...\n");
2770 wineItem->state |= TVIS_EXPANDED;
2771
2772 /* this item has never been expanded */
2773 if (TREEVIEW_SendTreeviewNotify (
2774 hwnd,
2775 TVN_ITEMEXPANDING,
2776 TVE_EXPAND,
2777 0,
2778 (HTREEITEM)expand))
2779 {
2780// TRACE(treeview, " TVN_ITEMEXPANDING returned TRUE, exiting...\n");
2781 return FALSE;
2782 }
2783
2784 /* FIXME
2785 * Since the TVN_ITEMEXPANDING message may has caused the parent to
2786 * insert new items which in turn may have cause items placeholder
2787 * reallocation, I reassign the current item pointer so we have
2788 * something valid to work with...
2789 * However, this should not be necessary,
2790 * investigation required in TREEVIEW_InsertItemA
2791 */
2792 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand);
2793 if (! wineItem)
2794 {
2795// ERR(treeview,
2796// "Catastropic situation, cannot retreive item #%d\n",
2797// expand);
2798 return FALSE;
2799 }
2800
2801 wineItem->state |= TVIS_EXPANDEDONCE;
2802// TRACE(treeview, " TVN_ITEMEXPANDING sent...\n");
2803
2804 TREEVIEW_SendTreeviewNotify (
2805 hwnd,
2806 TVN_ITEMEXPANDED,
2807 TVE_EXPAND,
2808 0,
2809 (HTREEITEM)expand);
2810
2811// TRACE(treeview, " TVN_ITEMEXPANDED sent...\n");
2812
2813 }
2814 else
2815 {
2816 /* this item has already been expanded */
2817 wineItem->state |= TVIS_EXPANDED;
2818 }
2819 break;
2820
2821 case TVE_EXPANDPARTIAL:
2822// TRACE(treeview, " case TVE_EXPANDPARTIAL\n");
2823// FIXME (treeview, "TVE_EXPANDPARTIAL not implemented\n");
2824 wineItem->state ^=TVIS_EXPANDED;
2825 wineItem->state |=TVIS_EXPANDEDONCE;
2826 break;
2827 }
2828
2829// TRACE(treeview, "Exiting, Item %d state is now %d...\n",
2830// expand,
2831// wineItem->state);
2832
2833 TREEVIEW_QueueRefresh (hwnd);
2834 return TRUE;
2835}
2836
2837
2838
2839static TREEVIEW_ITEM *
2840TREEVIEW_HitTestPoint (HWND hwnd, POINT pt)
2841{
2842 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2843 TREEVIEW_ITEM *wineItem;
2844 RECT rect;
2845
2846 GetClientRect (hwnd, &rect);
2847
2848 if (!infoPtr->firstVisible) return NULL;
2849
2850 wineItem=&infoPtr->items [(INT)infoPtr->firstVisible];
2851
2852 while ((wineItem!=NULL) && (pt.y > wineItem->rect.bottom))
2853 wineItem=TREEVIEW_GetNextListItem (infoPtr,wineItem);
2854
2855 if (!wineItem)
2856 return NULL;
2857
2858 return wineItem;
2859}
2860
2861
2862
2863
2864static LRESULT
2865TREEVIEW_HitTest (HWND hwnd, LPARAM lParam)
2866{
2867 LPTVHITTESTINFO lpht=(LPTVHITTESTINFO) lParam;
2868 TREEVIEW_ITEM *wineItem;
2869 RECT rect;
2870 UINT status,x,y;
2871
2872 GetClientRect (hwnd, &rect);
2873 status=0;
2874 x=lpht->pt.x;
2875 y=lpht->pt.y;
2876 if (x < rect.left) status|=TVHT_TOLEFT;
2877 if (x > rect.right) status|=TVHT_TORIGHT;
2878 if (y < rect.top ) status|=TVHT_ABOVE;
2879 if (y > rect.bottom) status|=TVHT_BELOW;
2880
2881 if (status) {
2882 lpht->flags=status;
2883 return 0;
2884 }
2885
2886 wineItem=TREEVIEW_HitTestPoint (hwnd, lpht->pt);
2887 if (!wineItem) {
2888 lpht->flags=TVHT_NOWHERE;
2889 return 0;
2890 }
2891
2892 lpht->flags=0;
2893
2894 if (x < wineItem->expandBox.left) {
2895 lpht->flags |= TVHT_ONITEMINDENT;
2896 goto done;
2897 }
2898 if ( PtInRect ( &wineItem->expandBox, lpht->pt)) {
2899 lpht->flags |= TVHT_ONITEMBUTTON;
2900 goto done;
2901 }
2902 if ( PtInRect ( &wineItem->bitmap, lpht->pt)) {
2903 lpht->flags |= TVHT_ONITEMICON;
2904 goto done;
2905 }
2906 if ( PtInRect ( &wineItem->statebitmap, lpht->pt)) {
2907 lpht->flags |= TVHT_ONITEMSTATEICON;
2908 goto done;
2909 }
2910 if ( PtInRect ( &wineItem->text, lpht->pt)) {
2911 lpht->flags |= TVHT_ONITEMLABEL;
2912 goto done;
2913 }
2914
2915 lpht->flags|=TVHT_ONITEMRIGHT;
2916
2917
2918done:
2919 lpht->hItem=wineItem->hItem;
2920 TRACE ("(%ld,%ld):result %x\n",lpht->pt.x,lpht->pt.y,lpht->flags);
2921
2922 return (LRESULT) wineItem->hItem;
2923}
2924
2925LRESULT WINAPI
2926TREEVIEW_EndEditLabelNow (HWND hwnd, WPARAM wParam, LPARAM lParam)
2927{
2928 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
2929 TREEVIEW_ITEM *editedItem = TREEVIEW_ValidItem (infoPtr, infoPtr->editItem);
2930 BOOL bRevert = (BOOL)wParam;
2931 BOOL bReturn = ! bRevert;
2932
2933 if ( ! (BOOL)wParam ) /* wParam is set to true to cancel the edition */
2934 {
2935 if ( TREEVIEW_SendDispInfoNotify( /* return true to cancel edition */
2936 hwnd,
2937 editedItem,
2938 TVN_ENDLABELEDIT,
2939 0))
2940 {
2941 bRevert = TRUE;
2942 bReturn = FALSE;
2943 }
2944 }
2945
2946 if (bRevert == FALSE) /* Apply the changes */
2947 {
2948 char tmpText[1024];
2949 int iLength = GetWindowTextA(infoPtr->hwndEdit, tmpText, 1023);
2950 bReturn = FALSE;
2951
2952 if (iLength == 0)
2953 {
2954// ERR( treeview, "Problem retreiving new item label.");
2955 }
2956 else if (iLength >= 1023)
2957 {
2958// ERR( treeview,
2959// "Insuficient space to retrieve new item label, new label ignored.");
2960 }
2961 else
2962 {
2963 if (strcmp( tmpText, editedItem->pszText ) == 0)
2964 /* Do nothing if the label has not changed */
2965 bReturn = TRUE;
2966 else
2967 {
2968 LPSTR tmpLabel = COMCTL32_Alloc( iLength+1 );
2969
2970// if ( tmpLabel == NULL )
2971// ERR( treeview,
2972// "OutOfMemory, cannot allocate space for label");
2973// else
2974 {
2975 COMCTL32_Free(editedItem->pszText);
2976 editedItem->pszText = tmpLabel;
2977 lstrcpyA( editedItem->pszText, tmpText);
2978 bReturn = TRUE;
2979 }
2980 }
2981 }
2982
2983 ShowWindow(infoPtr->hwndEdit, SW_HIDE);
2984 EnableWindow(infoPtr->hwndEdit, FALSE);
2985 infoPtr->editItem = 0;
2986 }
2987
2988 return bReturn;
2989}
2990
2991
2992
2993static LRESULT
2994TREEVIEW_LButtonDoubleClick (HWND hwnd, WPARAM wParam, LPARAM lParam)
2995{
2996 TREEVIEW_ITEM *wineItem;
2997 POINT pt;
2998
2999// TRACE (treeview,"\n");
3000 pt.x = (INT)LOWORD(lParam);
3001 pt.y = (INT)HIWORD(lParam);
3002 SetFocus (hwnd);
3003
3004 wineItem=TREEVIEW_HitTestPoint (hwnd, pt);
3005 if (!wineItem) return 0;
3006// TRACE (treeview,"item %d \n",(INT)wineItem->hItem);
3007
3008 if (TREEVIEW_SendSimpleNotify (hwnd, NM_DBLCLK)!=TRUE) { /* FIXME!*/
3009 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) wineItem->hItem);
3010 }
3011 return TRUE;
3012}
3013
3014
3015static LRESULT
3016TREEVIEW_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
3017{
3018 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3019 INT iItem;
3020 TVHITTESTINFO ht;
3021
3022 ht.pt.x = (INT)LOWORD(lParam);
3023 ht.pt.y = (INT)HIWORD(lParam);
3024
3025 SetFocus (hwnd);
3026 iItem=TREEVIEW_HitTest (hwnd, (LPARAM) &ht);
3027// TRACE (treeview,"item %d \n",iItem);
3028
3029 if (ht.flags & TVHT_ONITEMBUTTON) {
3030 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) iItem);
3031 }
3032 else
3033 {
3034 infoPtr->uInternalStatus|=TV_LDRAG;
3035 }
3036
3037 return 0;
3038}
3039
3040static LRESULT
3041TREEVIEW_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
3042{
3043 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3044 INT iItem;
3045 TREEVIEW_ITEM *wineItem;
3046 TVHITTESTINFO ht;
3047
3048 ht.pt.x = (INT)LOWORD(lParam);
3049 ht.pt.y = (INT)HIWORD(lParam);
3050
3051 TRACE("\n");
3052
3053 /* Return true to cancel default behaviour */
3054 if ( TREEVIEW_SendSimpleNotify (hwnd, NM_CLICK) )
3055 return 0;
3056
3057 /* Get the item */
3058 iItem = TREEVIEW_HitTest (hwnd, (LPARAM) &ht);
3059 TRACE ("%d\n",iItem);
3060 if (!iItem)
3061 return 0;
3062
3063 wineItem = TREEVIEW_ValidItem(infoPtr, (HTREEITEM)iItem);
3064
3065 infoPtr->uInternalStatus &= ~(TV_LDRAG | TV_LDRAGGING);
3066
3067 /*
3068 * If the style allow editing and the node is already selected
3069 * and the click occured on the item label...
3070 */
3071 if ( ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_EDITLABELS ) &&
3072 ( wineItem->state & TVIS_SELECTED ) &&
3073 ( ht.flags & TVHT_ONITEMLABEL ))
3074 {
3075 if ( infoPtr->editItem == 0 ) /* If we are not curently editing */
3076 {
3077 if ( TREEVIEW_SendDispInfoNotify( /* Return true to cancel edition */
3078 hwnd,
3079 wineItem,
3080 TVN_BEGINLABELEDIT,
3081 0))
3082 {
3083 return 0;
3084 }
3085
3086 TRACE("Edit started for %s.\n", wineItem->pszText);
3087 infoPtr->editItem = wineItem->hItem;
3088
3089 SetWindowPos (
3090 infoPtr->hwndEdit,
3091 HWND_TOP,
3092 wineItem->text.left - 2,
3093 wineItem->text.top - 1,
3094 wineItem->text.right - wineItem->text.left + 20 ,
3095 wineItem->text.bottom - wineItem->text.top + 3,
3096 SWP_DRAWFRAME );
3097
3098 SetWindowTextA( infoPtr->hwndEdit, wineItem->pszText );
3099 SendMessageA ( infoPtr->hwndEdit, EM_SETSEL, 0, -1 );
3100 SetFocus ( infoPtr->hwndEdit);
3101 ShowWindow ( infoPtr->hwndEdit, SW_SHOW);
3102 }
3103 }
3104 else if ( infoPtr->editItem != 0 ) /* If we are curently editing */
3105 {
3106 TREEVIEW_EndEditLabelNow(hwnd, (WPARAM)FALSE, 0);
3107 }
3108 else if ( ht.flags & (TVHT_ONITEMLABEL | TVHT_ONITEMICON))
3109 {
3110 TREEVIEW_DoSelectItem ( hwnd, TVGN_CARET, (HTREEITEM)iItem, TVC_BYMOUSE);
3111 }
3112
3113 if (ht.flags & TVHT_ONITEMSTATEICON) {
3114 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
3115
3116
3117 if (dwStyle & TVS_CHECKBOXES) { /* TVS_CHECKBOXES requires _us_ */
3118 int state; /* to toggle the current state */
3119 state=1-(wineItem->state>>12);
3120 TRACE ("state:%x\n", state);
3121 wineItem->state&= ~TVIS_STATEIMAGEMASK;
3122 wineItem->state|=state<<12;
3123 TRACE ("state:%x\n", wineItem->state);
3124 TREEVIEW_QueueRefresh (hwnd);
3125 }
3126 }
3127 return 0;
3128}
3129
3130
3131static LRESULT
3132TREEVIEW_RButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
3133{
3134 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3135
3136// TRACE (treeview,"\n");
3137 infoPtr->uInternalStatus|=TV_RDRAG;
3138 return 0;
3139}
3140
3141static LRESULT
3142TREEVIEW_RButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
3143{
3144 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3145
3146// TRACE (treeview,"\n");
3147 if (TREEVIEW_SendSimpleNotify (hwnd, NM_RCLICK)) return 0;
3148 infoPtr->uInternalStatus&= ~(TV_RDRAG | TV_RDRAGGING);
3149 return 0;
3150}
3151
3152
3153static LRESULT
3154TREEVIEW_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
3155{
3156 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3157 TREEVIEW_ITEM *hotItem;
3158 POINT pt;
3159
3160 pt.x=(INT) LOWORD (lParam);
3161 pt.y=(INT) HIWORD (lParam);
3162 hotItem=TREEVIEW_HitTestPoint (hwnd, pt);
3163 if (!hotItem) return 0;
3164 infoPtr->focusItem=hotItem->hItem;
3165
3166 if ( GetWindowLongA( hwnd, GWL_STYLE) & TVS_DISABLEDRAGDROP) return 0;
3167
3168 if (infoPtr->uInternalStatus & TV_LDRAG) {
3169 TREEVIEW_SendTreeviewDnDNotify (hwnd, TVN_BEGINDRAG, hotItem->hItem, pt);
3170 infoPtr->uInternalStatus &= ~TV_LDRAG;
3171 infoPtr->uInternalStatus |= TV_LDRAGGING;
3172 infoPtr->dropItem=hotItem->hItem;
3173 return 0;
3174 }
3175
3176 if (infoPtr->uInternalStatus & TV_RDRAG) {
3177 TREEVIEW_SendTreeviewDnDNotify (hwnd, TVN_BEGINRDRAG, hotItem->hItem, pt);
3178 infoPtr->uInternalStatus &= ~TV_RDRAG;
3179 infoPtr->uInternalStatus |= TV_RDRAGGING;
3180 infoPtr->dropItem=hotItem->hItem;
3181 return 0;
3182 }
3183
3184 return 0;
3185}
3186
3187
3188static LRESULT
3189TREEVIEW_CreateDragImage (HWND hwnd, WPARAM wParam, LPARAM lParam)
3190{
3191 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3192 TREEVIEW_ITEM *dragItem;
3193 INT cx,cy;
3194 HDC hdc,htopdc;
3195 HWND hwtop;
3196 HBITMAP hbmp,hOldbmp;
3197 SIZE size;
3198 RECT rc;
3199 HFONT hOldFont;
3200 char *itemtxt;
3201
3202// TRACE (treeview,"\n");
3203 if (!(infoPtr->himlNormal)) return 0;
3204 dragItem=TREEVIEW_ValidItem (infoPtr, (HTREEITEM) lParam);
3205
3206 if (!dragItem) return 0;
3207
3208 if (dragItem->pszText==LPSTR_TEXTCALLBACKA) {
3209 TREEVIEW_SendDispInfoNotify (hwnd, dragItem, TVN_GETDISPINFO, TVIF_TEXT);
3210 }
3211 itemtxt=dragItem->pszText;
3212
3213 hwtop=GetDesktopWindow ();
3214 htopdc= GetDC (hwtop);
3215 hdc=CreateCompatibleDC (htopdc);
3216
3217 hOldFont=SelectObject (hdc, infoPtr->hFont);
3218 GetTextExtentPoint32A (hdc, itemtxt, lstrlenA (itemtxt), &size);
3219// TRACE (treeview,"%d %d %s %d\n",size.cx,size.cy,itemtxt,lstrlenA(itemtxt));
3220 hbmp=CreateCompatibleBitmap (htopdc, size.cx, size.cy);
3221 hOldbmp=SelectObject (hdc, hbmp);
3222
3223 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &cy);
3224 size.cx+=cx;
3225 if (cy>size.cy) size.cy=cy;
3226
3227 infoPtr->dragList=ImageList_Create (size.cx, size.cy, ILC_COLOR, 10, 10);
3228 ImageList_Draw (infoPtr->himlNormal, dragItem->iImage, hdc, 0, 0, ILD_NORMAL);
3229
3230/*
3231 ImageList_GetImageInfo (infoPtr->himlNormal, dragItem->hItem, &iminfo);
3232 ImageList_AddMasked (infoPtr->dragList, iminfo.hbmImage, CLR_DEFAULT);
3233*/
3234
3235/* draw item text */
3236
3237 SetRect (&rc, cx, 0, size.cx,size.cy);
3238 DrawTextA (hdc, itemtxt, lstrlenA (itemtxt), &rc, DT_LEFT);
3239 SelectObject (hdc, hOldFont);
3240 SelectObject (hdc, hOldbmp);
3241
3242 ImageList_Add (infoPtr->dragList, hbmp, 0);
3243
3244 DeleteDC (hdc);
3245 DeleteObject (hbmp);
3246 ReleaseDC (hwtop, htopdc);
3247
3248 return (LRESULT)infoPtr->dragList;
3249}
3250
3251
3252static LRESULT
3253TREEVIEW_DoSelectItem (HWND hwnd, INT action, HTREEITEM newSelect, INT cause)
3254
3255{
3256 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3257 TREEVIEW_ITEM *prevItem,*wineItem;
3258 INT prevSelect;
3259
3260 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)newSelect);
3261
3262// TRACE (treeview,"Entering item %d, flag %x, cause %x, state %d\n",
3263// (INT)newSelect,
3264// action,
3265// cause,
3266// wineItem->state);
3267
3268 if ( (wineItem) && (wineItem->parent))
3269 {
3270 /*
3271 * If the item has a collapse parent expand the parent so he
3272 * can expose the item
3273 */
3274 TREEVIEW_ITEM *parentItem = TREEVIEW_ValidItem (infoPtr, wineItem->parent);
3275 if ( !(parentItem->state & TVIS_EXPANDED))
3276 TREEVIEW_Expand (hwnd, TVE_EXPAND, (LPARAM) wineItem->parent);
3277 }
3278
3279 switch (action)
3280 {
3281 case TVGN_CARET:
3282 prevSelect=(INT)infoPtr->selectedItem;
3283
3284 if ((HTREEITEM)prevSelect==newSelect)
3285 return FALSE;
3286
3287 prevItem= TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect);
3288
3289 if (newSelect)
3290 if (TREEVIEW_SendTreeviewNotify(
3291 hwnd,
3292 TVN_SELCHANGING,
3293 cause,
3294 (HTREEITEM)prevSelect,
3295 (HTREEITEM)newSelect))
3296 return FALSE; /* FIXME: OK? */
3297
3298 if (prevItem)
3299 prevItem->state &= ~TVIS_SELECTED;
3300 if (wineItem)
3301 wineItem->state |= TVIS_SELECTED;
3302
3303 infoPtr->selectedItem=(HTREEITEM)newSelect;
3304
3305 TREEVIEW_SendTreeviewNotify(
3306 hwnd,
3307 TVN_SELCHANGED,
3308 cause,
3309 (HTREEITEM)prevSelect,
3310 (HTREEITEM)newSelect);
3311
3312 break;
3313
3314 case TVGN_DROPHILITE:
3315 prevItem= TREEVIEW_ValidItem (infoPtr, infoPtr->dropItem);
3316
3317 if (prevItem)
3318 prevItem->state &= ~TVIS_DROPHILITED;
3319
3320 infoPtr->dropItem=(HTREEITEM)newSelect;
3321
3322 if (wineItem)
3323 wineItem->state |=TVIS_DROPHILITED;
3324
3325 break;
3326
3327 case TVGN_FIRSTVISIBLE:
3328// FIXME (treeview, "FIRSTVISIBLE not implemented\n");
3329 break;
3330 }
3331
3332 TREEVIEW_QueueRefresh (hwnd);
3333
3334// TRACE (treeview,"Leaving state %d\n", wineItem->state);
3335 return TRUE;
3336}
3337
3338/* FIXME: handle NM_KILLFocus enzo */
3339static LRESULT
3340TREEVIEW_SelectItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
3341
3342{
3343 return TREEVIEW_DoSelectItem (hwnd, wParam, (HTREEITEM) lParam, TVC_UNKNOWN);
3344}
3345
3346
3347
3348
3349static LRESULT
3350TREEVIEW_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
3351
3352{
3353 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3354
3355// TRACE (treeview,"%x\n",infoPtr->hFont);
3356 return infoPtr->hFont;
3357}
3358
3359static LRESULT
3360TREEVIEW_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
3361
3362{
3363 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3364 TEXTMETRICA tm;
3365 LOGFONTA logFont;
3366 HFONT hFont, hOldFont;
3367 INT height;
3368 HDC hdc;
3369
3370// TRACE (treeview,"%x %lx\n",wParam, lParam);
3371
3372 infoPtr->hFont = (HFONT)wParam;
3373
3374 hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
3375
3376 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
3377 logFont.lfWeight=FW_BOLD;
3378 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
3379
3380 hdc = GetDC (0);
3381 hOldFont = SelectObject (hdc, hFont);
3382 GetTextMetricsA (hdc, &tm);
3383 height= tm.tmHeight + tm.tmExternalLeading;
3384 if (height>infoPtr->uRealItemHeight)
3385 infoPtr->uRealItemHeight=height;
3386 SelectObject (hdc, hOldFont);
3387 ReleaseDC (0, hdc);
3388
3389 if (lParam)
3390 TREEVIEW_QueueRefresh (hwnd);
3391
3392 return 0;
3393}
3394
3395
3396
3397static LRESULT
3398TREEVIEW_VScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
3399
3400{
3401 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3402 int maxHeight;
3403
3404// TRACE (treeview,"wp %x, lp %lx\n", wParam, lParam);
3405 if (!infoPtr->uInternalStatus & TV_VSCROLL) return FALSE;
3406
3407 switch (LOWORD (wParam)) {
3408 case SB_LINEUP:
3409 if (!infoPtr->cy) return FALSE;
3410 infoPtr->cy -= infoPtr->uRealItemHeight;
3411 if (infoPtr->cy < 0) infoPtr->cy=0;
3412 break;
3413 case SB_LINEDOWN:
3414 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3415 if (infoPtr->cy == maxHeight) return FALSE;
3416 infoPtr->cy += infoPtr->uRealItemHeight;
3417 if (infoPtr->cy > maxHeight)
3418 infoPtr->cy = maxHeight;
3419 break;
3420 case SB_PAGEUP:
3421 if (!infoPtr->cy) return FALSE;
3422 infoPtr->cy -= infoPtr->uVisibleHeight;
3423 if (infoPtr->cy < 0) infoPtr->cy=0;
3424 break;
3425 case SB_PAGEDOWN:
3426 maxHeight=infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3427 if (infoPtr->cy == maxHeight) return FALSE;
3428 infoPtr->cy += infoPtr->uVisibleHeight;
3429 if (infoPtr->cy > maxHeight)
3430 infoPtr->cy = maxHeight;
3431 break;
3432 case SB_THUMBTRACK:
3433 infoPtr->cy = HIWORD (wParam);
3434 break;
3435
3436 }
3437
3438 TREEVIEW_QueueRefresh (hwnd);
3439 return TRUE;
3440}
3441
3442static LRESULT
3443TREEVIEW_HScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
3444{
3445 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3446 int maxWidth;
3447
3448// TRACE (treeview,"wp %lx, lp %x\n", lParam, wParam);
3449
3450 if (!infoPtr->uInternalStatus & TV_HSCROLL) return FALSE;
3451
3452 switch (LOWORD (wParam)) {
3453 case SB_LINEUP:
3454 if (!infoPtr->cx) return FALSE;
3455 infoPtr->cx -= infoPtr->uRealItemHeight;
3456 if (infoPtr->cx < 0) infoPtr->cx=0;
3457 break;
3458 case SB_LINEDOWN:
3459 maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
3460 if (infoPtr->cx == maxWidth) return FALSE;
3461 infoPtr->cx += infoPtr->uRealItemHeight; /*FIXME */
3462 if (infoPtr->cx > maxWidth)
3463 infoPtr->cx = maxWidth;
3464 break;
3465 case SB_PAGEUP:
3466 if (!infoPtr->cx) return FALSE;
3467 infoPtr->cx -= infoPtr->uVisibleWidth;
3468 if (infoPtr->cx < 0) infoPtr->cx=0;
3469 break;
3470 case SB_PAGEDOWN:
3471 maxWidth=infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
3472 if (infoPtr->cx == maxWidth) return FALSE;
3473 infoPtr->cx += infoPtr->uVisibleWidth;
3474 if (infoPtr->cx > maxWidth)
3475 infoPtr->cx = maxWidth;
3476 break;
3477 case SB_THUMBTRACK:
3478 infoPtr->cx = HIWORD (wParam);
3479 break;
3480
3481 }
3482
3483 TREEVIEW_QueueRefresh (hwnd);
3484 return TRUE;
3485}
3486
3487
3488static LRESULT
3489TREEVIEW_KeyDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
3490{
3491 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3492 HTREEITEM hNewSelection = 0;
3493 INT scrollNeeds = -1;
3494 INT cyChangeNeeds = -1;
3495 INT prevSelect = (INT)infoPtr->selectedItem;
3496
3497 TREEVIEW_ITEM *prevItem =
3498 (prevSelect != 0 ) ?
3499 TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect) :
3500 NULL;
3501
3502 TREEVIEW_ITEM *newItem = NULL;
3503
3504// TRACE (treeview,"%x %lx\n",wParam, lParam);
3505
3506 if (prevSelect == 0)
3507 return FALSE;
3508
3509 switch (wParam) {
3510 case VK_UP:
3511 newItem=TREEVIEW_GetPrevListItem (infoPtr, prevItem);
3512
3513 if (!newItem)
3514 newItem=& infoPtr->items[(INT)infoPtr->TopRootItem];
3515
3516 hNewSelection = newItem->hItem;
3517
3518 if (! newItem->visible)
3519 scrollNeeds = SB_LINEUP;
3520
3521 break;
3522
3523 case VK_DOWN:
3524 newItem=TREEVIEW_GetNextListItem (infoPtr, prevItem);
3525
3526 if (!newItem)
3527 newItem=prevItem;
3528
3529 hNewSelection = newItem->hItem;
3530
3531 if (! newItem->visible)
3532 scrollNeeds = SB_LINEDOWN;
3533
3534 break;
3535
3536 case VK_HOME:
3537 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem];
3538 hNewSelection = newItem->hItem;
3539 cyChangeNeeds = 0;
3540 break;
3541
3542 case VK_END:
3543 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem];
3544 newItem = TREEVIEW_GetLastListItem (infoPtr, newItem);
3545 hNewSelection = newItem->hItem;
3546
3547 if (! newItem->visible)
3548 cyChangeNeeds = infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
3549
3550 break;
3551
3552 case VK_LEFT:
3553 if ( (prevItem->cChildren > 0) && (prevItem->state & TVIS_EXPANDED) )
3554 {
3555 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect );
3556 }
3557 else if ((INT)prevItem->parent)
3558 {
3559 newItem = (& infoPtr->items[(INT)prevItem->parent]);
3560 if (! newItem->visible)
3561 /* FIXME find a way to make this item the first visible... */
3562 newItem = NULL;
3563
3564 hNewSelection = newItem->hItem;
3565 }
3566
3567 break;
3568
3569 case VK_RIGHT:
3570 if ( ( prevItem->cChildren > 0) ||
3571 ( prevItem->cChildren == I_CHILDRENCALLBACK))
3572 {
3573 if (! (prevItem->state & TVIS_EXPANDED))
3574 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect );
3575 else
3576 {
3577 newItem = (& infoPtr->items[(INT)prevItem->firstChild]);
3578 hNewSelection = newItem->hItem;
3579 }
3580 }
3581
3582 break;
3583
3584 case VK_ADD:
3585 if (! (prevItem->state & TVIS_EXPANDED))
3586 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect );
3587 break;
3588
3589 case VK_SUBTRACT:
3590 if (prevItem->state & TVIS_EXPANDED)
3591 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect );
3592 break;
3593
3594 case VK_PRIOR:
3595
3596 newItem=TREEVIEW_GetListItem(
3597 infoPtr,
3598 prevItem,
3599 -1*(TREEVIEW_GetVisibleCount(hwnd,0,0)-3));
3600 if (!newItem)
3601 newItem=prevItem;
3602
3603 hNewSelection = newItem->hItem;
3604
3605 if (! newItem->visible)
3606 scrollNeeds = SB_PAGEUP;
3607
3608 break;
3609
3610 case VK_NEXT:
3611 newItem=TREEVIEW_GetListItem(
3612 infoPtr,
3613 prevItem,
3614 TREEVIEW_GetVisibleCount(hwnd,0,0)-3);
3615
3616 if (!newItem)
3617 newItem=prevItem;
3618
3619 hNewSelection = newItem->hItem;
3620
3621 if (! newItem->visible)
3622 scrollNeeds = SB_PAGEDOWN;
3623
3624 break;
3625
3626 case VK_BACK:
3627
3628 case VK_RETURN:
3629
3630 default:
3631// FIXME (treeview, "%x not implemented\n", wParam);
3632 break;
3633 }
3634
3635 if (hNewSelection)
3636 {
3637/*
3638 This works but does not send notification...
3639
3640 prevItem->state &= ~TVIS_SELECTED;
3641 newItem->state |= TVIS_SELECTED;
3642 infoPtr->selectedItem = hNewSelection;
3643 TREEVIEW_QueueRefresh (hwnd);
3644*/
3645
3646 if ( TREEVIEW_DoSelectItem(
3647 hwnd,
3648 TVGN_CARET,
3649 (HTREEITEM)hNewSelection,
3650 TVC_BYKEYBOARD))
3651 {
3652 /* If selection change is allowed for the new item, perform scrolling */
3653 if (scrollNeeds != -1)
3654 TREEVIEW_VScroll(hwnd, scrollNeeds, 0);
3655
3656 if (cyChangeNeeds != -1)
3657 infoPtr->cy = cyChangeNeeds;
3658
3659 /* FIXME: Something happen in the load the in the two weeks before
3660 april 1st 1999 which makes this SetFocus mandatory otherwise, the focus
3661 is lost... However the SetFocus should not be required...*/
3662
3663 SetFocus(hwnd);
3664 }
3665 }
3666
3667 return FALSE;
3668}
3669
3670static LRESULT
3671TREEVIEW_GetScrollTime (HWND hwnd)
3672{
3673 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3674 return infoPtr->uScrollTime;
3675}
3676
3677static LRESULT
3678TREEVIEW_SetScrollTime (HWND hwnd, UINT uScrollTime)
3679{
3680 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
3681 UINT uOldScrollTime = infoPtr->uScrollTime;
3682 infoPtr->uScrollTime = min (uScrollTime, 100);
3683 return uOldScrollTime;
3684}
3685
3686static LRESULT WINAPI
3687TREEVIEW_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3688{
3689 switch (uMsg) {
3690 case TVM_INSERTITEMA:
3691 return TREEVIEW_InsertItemA (hwnd, wParam, lParam);
3692
3693 case TVM_INSERTITEMW:
3694 return TREEVIEW_InsertItemW(hwnd,wParam,lParam);
3695
3696 case TVM_DELETEITEM:
3697 return TREEVIEW_DeleteItem (hwnd, wParam, lParam);
3698
3699 case TVM_EXPAND:
3700 return TREEVIEW_Expand (hwnd, wParam, lParam);
3701
3702 case TVM_GETITEMRECT:
3703 return TREEVIEW_GetItemRect (hwnd, wParam, lParam);
3704
3705 case TVM_GETCOUNT:
3706 return TREEVIEW_GetCount (hwnd, wParam, lParam);
3707
3708 case TVM_GETINDENT:
3709 return TREEVIEW_GetIndent (hwnd);
3710
3711 case TVM_SETINDENT:
3712 return TREEVIEW_SetIndent (hwnd, wParam);
3713
3714 case TVM_GETIMAGELIST:
3715 return TREEVIEW_GetImageList (hwnd, wParam, lParam);
3716
3717 case TVM_SETIMAGELIST:
3718 return TREEVIEW_SetImageList (hwnd, wParam, lParam);
3719
3720 case TVM_GETNEXTITEM:
3721 return TREEVIEW_GetNextItem (hwnd, wParam, lParam);
3722
3723 case TVM_SELECTITEM:
3724 return TREEVIEW_SelectItem (hwnd, wParam, lParam);
3725
3726 case TVM_GETITEMA:
3727 return TREEVIEW_GetItemA (hwnd, wParam, lParam);
3728
3729 case TVM_GETITEMW:
3730// FIXME (treeview, "Unimplemented msg TVM_GETITEMW\n");
3731 return 0;
3732
3733 case TVM_SETITEMA:
3734 return TREEVIEW_SetItemA (hwnd, wParam, lParam);
3735
3736 case TVM_SETITEMW:
3737// FIXME (treeview, "Unimplemented msg TVM_SETITEMW\n");
3738 return 0;
3739
3740 case TVM_EDITLABELA:
3741// FIXME (treeview, "Unimplemented msg TVM_EDITLABELA \n");
3742 return 0;
3743
3744 case TVM_EDITLABELW:
3745// FIXME (treeview, "Unimplemented msg TVM_EDITLABELW \n");
3746 return 0;
3747
3748 case TVM_GETEDITCONTROL:
3749 return TREEVIEW_GetEditControl (hwnd);
3750
3751 case TVM_GETVISIBLECOUNT:
3752 return TREEVIEW_GetVisibleCount (hwnd, wParam, lParam);
3753
3754 case TVM_HITTEST:
3755 return TREEVIEW_HitTest (hwnd, lParam);
3756
3757 case TVM_CREATEDRAGIMAGE:
3758 return TREEVIEW_CreateDragImage (hwnd, wParam, lParam);
3759
3760 case TVM_SORTCHILDREN:
3761 //@@@PH 1999/10/25 TREEVIEW_SortChildrenCB is wrong
3762 return TREEVIEW_SortChildren(hwnd, wParam, lParam);
3763
3764 case TVM_ENSUREVISIBLE:
3765// FIXME (treeview, "Unimplemented msg TVM_ENSUREVISIBLE\n");
3766 return 0;
3767
3768 case TVM_SORTCHILDRENCB:
3769 return TREEVIEW_SortChildrenCB(hwnd, wParam, lParam);
3770
3771 case TVM_ENDEDITLABELNOW:
3772 return TREEVIEW_EndEditLabelNow (hwnd, wParam, lParam);
3773
3774 case TVM_GETISEARCHSTRINGA:
3775// FIXME (treeview, "Unimplemented msg TVM_GETISEARCHSTRINGA\n");
3776 return 0;
3777
3778 case TVM_GETISEARCHSTRINGW:
3779// FIXME (treeview, "Unimplemented msg TVM_GETISEARCHSTRINGW\n");
3780 return 0;
3781
3782 case TVM_GETTOOLTIPS:
3783 return TREEVIEW_GetToolTips (hwnd);
3784
3785 case TVM_SETTOOLTIPS:
3786 return TREEVIEW_SetToolTips (hwnd, wParam);
3787
3788 case TVM_SETINSERTMARK:
3789 return TREEVIEW_SetInsertMark (hwnd,wParam, lParam);
3790
3791 case TVM_SETITEMHEIGHT:
3792 return TREEVIEW_SetItemHeight (hwnd, wParam);
3793
3794 case TVM_GETITEMHEIGHT:
3795 return TREEVIEW_GetItemHeight (hwnd);
3796
3797 case TVM_SETBKCOLOR:
3798 return TREEVIEW_SetBkColor (hwnd, wParam, lParam);
3799
3800 case TVM_SETTEXTCOLOR:
3801 return TREEVIEW_SetTextColor (hwnd, wParam, lParam);
3802
3803 case TVM_GETBKCOLOR:
3804 return TREEVIEW_GetBkColor (hwnd);
3805
3806 case TVM_GETTEXTCOLOR:
3807 return TREEVIEW_GetTextColor (hwnd);
3808
3809 case TVM_SETSCROLLTIME:
3810 return TREEVIEW_SetScrollTime (hwnd, (UINT)wParam);
3811
3812 case TVM_GETSCROLLTIME:
3813 return TREEVIEW_GetScrollTime (hwnd);
3814
3815 case TVM_GETITEMSTATE:
3816 return TREEVIEW_GetItemState (hwnd,wParam, lParam);
3817
3818 case TVM_GETLINECOLOR:
3819 return TREEVIEW_GetLineColor (hwnd,wParam, lParam);
3820
3821 case TVM_SETLINECOLOR:
3822 return TREEVIEW_SetLineColor (hwnd,wParam, lParam);
3823
3824 case TVM_SETINSERTMARKCOLOR:
3825 return TREEVIEW_SetInsertMarkColor (hwnd,wParam, lParam);
3826
3827 case TVM_GETINSERTMARKCOLOR:
3828 return TREEVIEW_GetInsertMarkColor (hwnd,wParam, lParam);
3829
3830 case TVM_GETUNICODEFORMAT:
3831// FIXME (treeview, "Unimplemented msg TVM_GETUNICODEFORMAT\n");
3832 return 0;
3833
3834 case WM_COMMAND:
3835 return TREEVIEW_Command (hwnd, wParam, lParam);
3836
3837 case WM_CREATE:
3838 return TREEVIEW_Create (hwnd, wParam, lParam);
3839
3840 case WM_DESTROY:
3841 return TREEVIEW_Destroy (hwnd);
3842
3843/* case WM_ENABLE: */
3844
3845 case WM_ERASEBKGND:
3846 return TREEVIEW_EraseBackground (hwnd, wParam, lParam);
3847
3848 case WM_GETDLGCODE:
3849 return DLGC_WANTARROWS | DLGC_WANTCHARS;
3850
3851 case WM_PAINT:
3852 return TREEVIEW_Paint (hwnd, wParam, lParam);
3853
3854 case WM_GETFONT:
3855 return TREEVIEW_GetFont (hwnd, wParam, lParam);
3856
3857 case WM_SETFONT:
3858 return TREEVIEW_SetFont (hwnd, wParam, lParam);
3859
3860 case WM_KEYDOWN:
3861 return TREEVIEW_KeyDown (hwnd, wParam, lParam);
3862
3863 case WM_SETFOCUS:
3864 return TREEVIEW_SetFocus (hwnd, wParam, lParam);
3865
3866 case WM_KILLFOCUS:
3867 return TREEVIEW_KillFocus (hwnd, wParam, lParam);
3868
3869 case WM_LBUTTONDOWN:
3870 return TREEVIEW_LButtonDown (hwnd, wParam, lParam);
3871
3872 case WM_LBUTTONUP:
3873 return TREEVIEW_LButtonUp (hwnd, wParam, lParam);
3874
3875 case WM_LBUTTONDBLCLK:
3876 return TREEVIEW_LButtonDoubleClick (hwnd, wParam, lParam);
3877
3878 case WM_RBUTTONDOWN:
3879 return TREEVIEW_RButtonDown (hwnd, wParam, lParam);
3880
3881 case WM_RBUTTONUP:
3882 return TREEVIEW_RButtonUp (hwnd, wParam, lParam);
3883
3884 case WM_MOUSEMOVE:
3885 return TREEVIEW_MouseMove (hwnd, wParam, lParam);
3886
3887 case WM_STYLECHANGED:
3888 return TREEVIEW_StyleChanged (hwnd, wParam, lParam);
3889
3890/* case WM_SYSCOLORCHANGE: */
3891/* case WM_SETREDRAW: */
3892
3893 case WM_TIMER:
3894 return TREEVIEW_HandleTimer (hwnd, wParam, lParam);
3895
3896 case WM_SIZE:
3897 return TREEVIEW_Size (hwnd, wParam,lParam);
3898
3899 case WM_HSCROLL:
3900 return TREEVIEW_HScroll (hwnd, wParam, lParam);
3901
3902 case WM_VSCROLL:
3903 return TREEVIEW_VScroll (hwnd, wParam, lParam);
3904
3905 case WM_DRAWITEM:
3906// printf ("drawItem\n");
3907 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
3908
3909 default:
3910// if (uMsg >= WM_USER)
3911// FIXME (treeview, "Unknown msg %04x wp=%08x lp=%08lx\n",
3912// uMsg, wParam, lParam);
3913 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
3914 }
3915 return 0;
3916}
3917
3918
3919VOID
3920TREEVIEW_Register (VOID)
3921{
3922 WNDCLASSA wndClass;
3923
3924// TRACE (treeview,"\n");
3925
3926//SvL: Don't check this now
3927// if (GlobalFindAtomA (WC_TREEVIEWA)) return;
3928
3929 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
3930 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
3931 wndClass.lpfnWndProc = (WNDPROC)TREEVIEW_WindowProc;
3932 wndClass.cbClsExtra = 0;
3933 wndClass.cbWndExtra = sizeof(TREEVIEW_INFO *);
3934 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
3935 wndClass.hbrBackground = 0;
3936 wndClass.lpszClassName = WC_TREEVIEWA;
3937
3938 RegisterClassA (&wndClass);
3939}
3940
3941
3942VOID
3943TREEVIEW_Unregister (VOID)
3944{
3945 if (GlobalFindAtomA (WC_TREEVIEWA))
3946 UnregisterClassA (WC_TREEVIEWA, (HINSTANCE)NULL);
3947}
3948
Note: See TracBrowser for help on using the repository browser.