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

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

WM_SETREDRAW changes

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