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

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

disable last fix, cause must be somewhere else

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