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

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

Added CVS tag to many files (comctl32 and headers) .

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