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

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

* empty log message *

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