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

Last change on this file since 2635 was 2635, checked in by cbratschi, 26 years ago

merged with WINE20000130

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