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

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

* empty log message *

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