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

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

added listview style, treeview rewrite started

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