fix restrict-qualified parameter aliasing.
[AROS.git] / workbench / classes / zune / nlist / nlisttree_mcc / NListtree.c
blob4507a321cd70ba0fba5cf25864be8ffb26cbcd51
1 /***************************************************************************
3 NListtree.mcc - New Listtree MUI Custom Class
4 Copyright (C) 1999-2001 by Carsten Scholling
5 Copyright (C) 2001-2014 NList Open Source Team
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 NList classes Support Site: http://www.sf.net/projects/nlist-classes
19 $Id$
21 ***************************************************************************/
23 /****** NListtree.mcc/--background-- *****************************************
25 * There are two possible entry-types in a NListtree class list:
26 * Leaves and nodes. Leaves are simple entries which have no special
27 * features except they are holding some data. Nodes are almost
28 * the same type, holding data too, but having a list attached
29 * where you can simply add other entries which can be again leaves
30 * or nodes.
32 * Every node is structured as follows:
34 * struct MUI_NListtree_TreeNode {
36 * struct MinNode tsn_Node;
37 * STRPTR tn_Name;
38 * UWORD tn_Flags;
39 * APTR tn_User;
40 * };
42 * It contains a name field tn_Name, flags tn_Flags and a pointer to
43 * user data tn_User.
45 * The tn_Flags field can hold the following flags:
47 * TNF_LIST The node contains a list where other nodes
48 * can be inserted.
50 * TNF_OPEN The list node is open, sub nodes are displayed.
52 * TNF_FROZEN The node doesn't react on doubleclick or
53 * open/close by the user.
55 * TNF_NOSIGN The indicator of list nodes isn't shown.
57 * TNF_SELECTED The entry is currently selected.
59 * These flags, except TNF_SELECTED, can be used in
60 * MUIM_NListtree_Insert at creation time. They will be passed to
61 * the newly created entry. Also you can do a quick check about the
62 * state and kind of each entry. But - NEVER EVER - modify any flag
63 * yourself or NListtree will crash. Be warned!
65 * *********************************************************************
66 * THE ABOVE STRUCT IS READ-ONLY!! NEVER CHANGE ANY ENTRY OF THIS
67 * STRUCTURE DIRECTLY NOR THINK ABOUT THE CONTENTS OF ANY PRIVATE
68 * FIELD OR YOU WILL DIE IN HELL!
69 * *********************************************************************
72 * You can create very complex tree structures. NListtree only uses
73 * one list which holds all information needed and has no extra
74 * display list like other list tree classes ;-)
76 * The tree nodes can be inserted and removed, sorted, moved, exchanged,
77 * renamed or multi selected. To sort you can also drag&drop them.
78 * Modifications can be made in relation to the whole tree, to only one
79 * level, to a sub-tree or to only one tree node.
81 * The user can control the listtree by the MUI keys, this means a node
82 * is opened with "Right" and closed with "Left". Check your MUI prefs
83 * for the specified keys.
85 * You can define which of the columns will react on double-clicking.
86 * The node toggles its status from open or closed and vice versa.
89 * Drag&Drop capabilities:
91 * If you set MUIA_NList_DragSortable to TRUE, the list tree will
92 * become active for Drag&Drop. This means you can drag and drop
93 * entries on the same list tree again. While dragging an indicator
94 * shows where to drop.
96 * Drag a Drop on Result
98 * leaf leaf Exchange leaves.
99 * node leaf Nothing happens.
100 * entry closed node Move entry, the compare hook is used.
101 * entry open node Move entry to defined position.
103 * You can not drop an entry on itself, nor can you drop an opened node on
104 * any of its members.
106 * To exchange data with other objects, you have to create your own
107 * subclass of NListtree class and react on the drag methods.
110 * Author: Carsten Scholling (c)1999-2000 email: cs@aphaso.de
112 ******************************************************************************
117 ** Includes
119 #include <string.h>
120 #include <stdlib.h>
121 #include <stdio.h>
123 #include <graphics/gfxmacros.h>
124 #undef GetOutlinePen
126 #include <libraries/gadtools.h>
127 #include <clib/alib_protos.h>
128 #include <clib/macros.h>
129 #include <proto/muimaster.h>
130 #include <proto/intuition.h>
131 #include <proto/graphics.h>
132 #include <proto/utility.h>
133 #include <proto/exec.h>
135 #include "private.h"
137 #include "NListtree.h"
138 #include "version.h"
139 #include "muiextra.h"
141 #define DATA_BUF_SIZE 4096
143 /*********************************************************************************************/
145 // stack definition (where is this used!?)
146 LONG __stack = 16384;
149 ** Small helpful macros...
151 #define DIFF(a,b) (MAX((a),(b))-MIN((a),(b)))
152 #define CLN(x) ((struct MUI_NListtree_ListNode *)(x))
153 #define CTN(x) ((struct MUI_NListtree_TreeNode *)(x))
156 ** Type definition for compare function.
159 void qsort2(struct MUI_NListtree_TreeNode **table, ULONG entries, struct NListtree_Data *data);
162 ** Some prototypes.
164 ULONG MultiTestFunc( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn, LONG seltype, LONG selflags );
166 struct TreeImage_Data
168 Object *obj;
169 LONG spec;
172 #if !defined(__MORPHOS__)
173 #ifdef __AROS__
174 static __attribute__ ((noinline)) Object * VARARGS68K DoSuperNew(struct IClass *cl, Object *obj, Tag tag1, ...)
176 AROS_SLOWSTACKTAGS_PRE_AS(tag1, Object *)
177 retval = (Object *)DoSuperMethod(cl, obj, OM_NEW, AROS_SLOWSTACKTAGS_ARG(tag1), NULL);
178 AROS_SLOWSTACKTAGS_POST
180 #else
181 static Object * VARARGS68K DoSuperNew(struct IClass *cl, Object *obj, ...)
183 Object *rc;
184 VA_LIST args;
186 ENTER();
188 VA_START(args, obj);
189 rc = (Object *)DoSuperMethod(cl, obj, OM_NEW, VA_ARG(args, ULONG), NULL);
190 VA_END(args);
192 RETURN(rc);
193 return rc;
195 #endif // __AROS__
196 #endif // !__MORPHOS__
198 /*****************************************************************************\
199 *******************************************************************************
201 ** Graphic and drawing functions.
203 *******************************************************************************
204 \*****************************************************************************/
207 ** Set A/B-Pen and DrawMode depending on OS version.
209 INLINE VOID MySetABPenDrMd( struct RastPort *rp, LONG apen, LONG bpen, UBYTE drmd )
211 if ( LIBVER( GfxBase ) >= 39 )
212 SetABPenDrMd( rp, apen, bpen, drmd );
213 else
215 SetAPen( rp, apen );
216 SetBPen( rp, bpen );
217 SetDrMd( rp, drmd );
223 ** Draw a simple line from l/t to r/b. All lines are pure horiz. or vert.!
225 INLINE VOID DrawLine( struct RastPort *rp, WORD l, WORD t, WORD r, WORD b )
227 Move( rp, l, t );
228 Draw( rp, r, b );
233 ** Draw windows line l/t to r/b. All
234 ** lines are pure horiz. or vert.!
236 INLINE VOID DrawLineDotted( struct RastPort *rp, WORD l, WORD t, WORD r, WORD b )
238 if ( l == r )
240 while( t <= b )
242 WritePixel( rp, l, t );
243 t += 2;
246 else
248 while( l <= r )
250 WritePixel( rp, l, t );
251 l += 2;
259 ** Draw a vertical bar.
261 INLINE VOID DrawTreeVertBar( struct TreeImage_Data *data, struct MyImage *im, WORD l, WORD t, UNUSED WORD r, WORD b )
263 struct RastPort *rp = (struct RastPort *)_rp( data->obj );
264 UWORD m = l + ( im->nltdata->MaxImageWidth - 1 ) / 2;
266 ENTER();
268 switch(im->nltdata->LineType)
270 case MUICFGV_NListtree_LineType_Disabled:
271 // nothing
272 break;
274 case MUICFGV_NListtree_LineType_Normal:
276 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Line] ) );
277 DrawLine( rp, m, t, m, b );
279 break;
281 case MUICFGV_NListtree_LineType_Dotted:
283 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Line] ) );
284 DrawLineDotted( rp, m, t, m, b );
286 break;
288 case MUICFGV_NListtree_LineType_Shadow:
290 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Shadow] ) );
291 DrawLine( rp, m+1, t, m+1, b );
292 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Line] ) );
293 DrawLine( rp, m, t, m, b );
295 break;
297 case MUICFGV_NListtree_LineType_Glow:
299 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Shadow] ) );
300 DrawLine( rp, m + 2, t, m + 2, b );
302 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Line] ) );
303 DrawLine( rp, m, t, m, b );
305 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Glow] ) );
306 DrawLine( rp, m - 1, t, m - 1, b );
307 DrawLine( rp, m+1, t, m+1, b );
309 break;
312 LEAVE();
317 ** Draw a vertical T bar.
319 INLINE VOID DrawTreeVertBarT( struct TreeImage_Data *data, struct MyImage *im, WORD l, WORD t, WORD r, WORD b )
321 struct RastPort *rp = (struct RastPort *)_rp( data->obj );
322 UWORD m = l + ( im->nltdata->MaxImageWidth - 1 ) / 2;
323 UWORD h = t + ( b - t ) / 2;
325 ENTER();
327 switch(im->nltdata->LineType)
329 case MUICFGV_NListtree_LineType_Disabled:
330 // nothing
331 break;
333 case MUICFGV_NListtree_LineType_Normal:
335 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Line] ) );
336 DrawLine( rp, m, t, m, b );
337 DrawLine( rp, m, h, r, h );
339 break;
341 case MUICFGV_NListtree_LineType_Dotted:
343 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Line] ) );
344 DrawLineDotted( rp, m, t, m, b );
345 DrawLineDotted( rp, m, h, m + (im->nltdata->MaxImageWidth-1)/2 + im->nltdata->IndentWidth, h );
347 break;
349 case MUICFGV_NListtree_LineType_Shadow:
351 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Shadow] ) );
352 DrawLine( rp, m+1, t, m+1, b );
353 DrawLine( rp, m+1, h + 1, r, h + 1 );
355 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Line] ) );
356 DrawLine( rp, m, t, m, b );
357 DrawLine( rp, m, h, r, h );
359 break;
361 case MUICFGV_NListtree_LineType_Glow:
363 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Shadow] ) );
364 DrawLine( rp, m + 2, t, m + 2, b );
365 DrawLine( rp, m + 3, h + 2, r, h + 2 );
367 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Glow] ) );
368 DrawLine( rp, m - 1, t, m - 1, b );
369 DrawLine( rp, m+1, t, m+1, b );
371 DrawLine( rp, m+1, h - 1, r, h - 1 );
372 DrawLine( rp, m+1, h + 1, r, h + 1 );
374 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Line] ) );
375 DrawLine( rp, m, t, m, b );
376 DrawLine( rp, m, h, r, h );
378 break;
381 LEAVE();
387 ** Draw a vertical end bar.
389 INLINE VOID DrawTreeVertBarEnd( struct TreeImage_Data *data, struct MyImage *im, WORD l, WORD t, WORD r, WORD b )
391 struct RastPort *rp = (struct RastPort *)_rp( data->obj );
392 UWORD m = l + ( im->nltdata->MaxImageWidth - 1 ) / 2;
393 UWORD h = t + ( b - t ) / 2;
395 ENTER();
397 switch(im->nltdata->LineType)
399 case MUICFGV_NListtree_LineType_Disabled:
400 // nothing
401 break;
403 case MUICFGV_NListtree_LineType_Normal:
405 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Line] ) );
406 DrawLine( rp, m, t, m, h );
407 DrawLine( rp, m, h, r, h );
409 break;
411 case MUICFGV_NListtree_LineType_Dotted:
413 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Line] ) );
414 DrawLineDotted( rp, m, t, m, h );
415 DrawLineDotted( rp, m, h, m + (im->nltdata->MaxImageWidth-1)/2 + im->nltdata->IndentWidth, h );
417 break;
419 case MUICFGV_NListtree_LineType_Shadow:
421 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Shadow] ) );
422 DrawLine( rp, m+1, t, m+1, h );
423 DrawLine( rp, m+1, h + 1, r, h + 1 );
425 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Line] ) );
426 DrawLine( rp, m, t, m, h );
427 DrawLine( rp, m, h, r, h );
429 break;
431 case MUICFGV_NListtree_LineType_Glow:
433 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Shadow] ) );
434 DrawLine( rp, m + 2, t, m + 2, h - 2 );
435 DrawLine( rp, m, h + 2, r, h + 2 );
437 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Glow] ) );
438 DrawLine( rp, m - 1, t, m - 1, h );
439 DrawLine( rp, m+1, h - 1, r, h - 1 );
441 DrawLine( rp, m+1, t, m+1, h );
442 DrawLine( rp, m - 1, h + 1, r, h + 1 );
444 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Line] ) );
445 DrawLine( rp, m , t, m, h );
446 DrawLine( rp, m, h, r, h );
448 break;
451 LEAVE();
456 ** Draw a horizontal bar.
458 INLINE VOID DrawTreeHorBar( struct TreeImage_Data *data, struct MyImage *im, WORD l, WORD t, WORD r, WORD b )
460 struct RastPort *rp = (struct RastPort *)_rp( data->obj );
461 UWORD h = t + ( b - t ) / 2;
463 ENTER();
465 switch(im->nltdata->LineType)
467 case MUICFGV_NListtree_LineType_Disabled:
468 // nothing
469 break;
471 case MUICFGV_NListtree_LineType_Normal:
473 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Line] ) );
474 DrawLine( rp, l-1, h, r+1, h );
476 break;
478 case MUICFGV_NListtree_LineType_Dotted:
480 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Line] ) );
481 DrawLineDotted( rp, l-1, h, r+1, h );
483 break;
485 case MUICFGV_NListtree_LineType_Shadow:
487 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Shadow] ) );
488 DrawLine( rp, l-1, h + 1, r+1, h + 1 );
490 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Line] ) );
491 DrawLine( rp, l-1, h, r+1, h );
493 break;
495 case MUICFGV_NListtree_LineType_Glow:
497 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Shadow] ) );
498 DrawLine( rp, l-1, h + 2, r, h + 2 );
500 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Glow] ) );
501 DrawLine( rp, l-1, h - 1, r, h - 1 );
502 DrawLine( rp, l-1, h + 1, r, h + 1 );
504 SetAPen( rp, MUIPEN( im->nltdata->Pen[PEN_Line] ) );
505 DrawLine( rp, l-1, h, r, h );
507 break;
510 LEAVE();
515 /*****************************************************************************\
516 *******************************************************************************
518 ** Tree image class functions.
520 *******************************************************************************
521 \*****************************************************************************/
524 ** Draw function for special tree image class.
526 IPTR TreeImage_Draw(struct IClass *cl, Object *obj, struct MUIP_Draw *msg)
528 struct TreeImage_Data *data = INST_DATA( cl, obj );
530 DoSuperMethodA( cl, obj, (Msg)msg);
532 if(isFlagSet(msg->flags, MADF_DRAWOBJECT) || isFlagSet(msg->flags, MADF_DRAWUPDATE))
534 struct MyImage *im;
535 WORD l, t, r, b;
537 D(DBF_DRAW, "DRAW SPEC: %ld - %ld/%ld/%ld/%ld", data->spec, _defwidth(obj), _defheight(obj), _minwidth(obj), _minheight(obj));
538 D(DBF_DRAW, "%ld/%ld/%ld/%ld", _left(obj), _top(obj), _right(obj), _bottom(obj));
540 im = (struct MyImage *)xget( obj, MUIA_UserData );
542 l = _left( obj );
543 t = _top( obj );
544 r = _right( obj );
545 b = _bottom( obj );
547 SetDrMd( _rp( obj ), JAM1 );
549 switch( data->spec )
551 case SPEC_Vert:
552 DrawTreeVertBar( data, im, l, t, r, b );
553 break;
555 case SPEC_VertT:
556 DrawTreeVertBarT( data, im, l, t, r, b );
557 break;
559 case SPEC_VertEnd:
560 DrawTreeVertBarEnd( data, im, l, t, r, b );
561 break;
563 case SPEC_Hor:
564 DrawTreeHorBar( data, im, l, t, r, b );
565 break;
567 default:
568 break;
572 msg->flags = 0;
574 return( 0 );
579 ** Special tree image class creation.
581 IPTR TreeImage_New(struct IClass *cl, Object *obj, struct opSet *msg)
583 struct TreeImage_Data *data;
585 if ( !( obj = (Object *)DoSuperMethodA( cl, obj, (Msg)msg) ) )
586 return( 0 );
588 ENTER();
590 data = INST_DATA( cl, obj );
592 data->obj = obj;
593 data->spec = 0;
595 RETURN(obj);
596 return (IPTR)obj;
601 ** Attribute setting function for special tree image class.
603 ULONG TreeImage_Set(struct IClass *cl, Object *obj, Msg msg)
605 struct TreeImage_Data *data = INST_DATA( cl, obj );
606 struct TagItem *tags, *tag;
608 for(tags = ((struct opSet *)msg)->ops_AttrList; (tag = (struct TagItem *)NextTagItem((APTR)&tags));)
610 switch( tag->ti_Tag )
612 case MUIA_TI_Spec:
613 data->spec = tag->ti_Data;
614 break;
618 D(DBF_IMAGES, "SET SPEC: %ld", data->spec);
620 return( 0 );
625 ** Dispatcher for the special tree image class.
628 DISPATCHER(TreeImage_Dispatcher)
630 switch( msg->MethodID )
632 case OM_NEW: return( TreeImage_New( cl, obj, (APTR)msg) );
633 case OM_SET: return( TreeImage_Set( cl, obj, (APTR)msg) );
634 case MUIM_Draw: return( TreeImage_Draw( cl, obj, (APTR)msg) );
637 return( DoSuperMethodA( cl, obj, msg) );
641 ** Dispatcher for the special tree image class no. 2.
642 ** Get the maximum width of images.
644 DISPATCHER(NodeImage_Dispatcher)
646 if ( msg->MethodID == MUIM_Show )
648 struct MyImage *im;
649 UWORD w, h;
651 im = (struct MyImage *)xget( obj, MUIA_UserData );
653 w = _defwidth( obj );
654 h = _defheight( obj );
656 if ( im->nltdata->MaxImageWidth < w )
657 im->nltdata->MaxImageWidth = w;
659 if ( im->nltdata->MaxImageHeight < h )
661 im->nltdata->MaxImageHeight = h;
663 if ( xget( obj, MUIA_NList_LineHeight ) < h )
664 nnset( im->nltdata->Obj, MUIA_NList_MinLineHeight, h );
667 D(DBF_IMAGES, "=====> DefWidth: %ld, DefHeight: %ld, MaxWidth: %ld", w, h, im->nltdata->MaxImageWidth);
670 return( DoSuperMethodA( cl, obj, (Msg)msg) );
673 /*****************************************************************************\
674 *******************************************************************************
676 ** Helpful handling functions.
678 *******************************************************************************
679 \*****************************************************************************/
681 /* MorphOS, OS4 and AROS support Alloc/FreeVecPooled internally */
682 #if defined(__amigaos3__)
684 #ifdef MYDEBUG
685 ULONG totalmem = 0;
686 #endif
689 ** Allocate pooled memory.
691 INLINE APTR AllocVecPooled( APTR mempool, ULONG size )
693 ULONG *mem;
695 if((mem = (ULONG *)AllocPooled(mempool, size + 4)))
697 #ifdef MYDEBUG
698 totalmem += size;
699 D(DBF_MEMORY, "0x%08lx = AllocPooled( mempool, %ld ) ==> total: %ld", mem, size + 4, totalmem);
700 #endif
702 *mem++ = size;
705 return( (APTR)mem );
710 ** Free previously allocated pool memory.
712 INLINE VOID FreeVecPooled( APTR mempool, APTR mem )
714 ULONG *m = (ULONG *)mem;
716 #ifdef MYDEBUG
717 totalmem -= m[-1];
718 D(DBF_MEMORY, " FreePooled( mempool, 0x%08lx, %ld ) ==> total: %ld", &m[-1], m[-1] + 4, totalmem);
719 #endif
721 FreePooled( mempool, &m[-1], m[-1] + 4 );
724 #endif /* !__MORPHOS__ && !__amigaos4__ */
726 #if !defined(__amigaos4__) && !defined(__AROS__)
727 struct Node *GetSucc(struct Node *node)
729 struct Node *result = NULL;
731 if(node != NULL && node->ln_Succ != NULL && node->ln_Succ->ln_Succ != NULL)
732 result = node->ln_Succ;
734 return result;
737 struct Node *GetPred(struct Node *node)
739 struct Node *result = NULL;
741 if(node != NULL && node->ln_Pred != NULL && node->ln_Pred->ln_Pred != NULL)
742 result = node->ln_Pred;
744 return result;
747 struct Node *GetHead(struct List *list)
749 struct Node *result = NULL;
751 if(list != NULL && IsListEmpty(list) == FALSE)
752 result = list->lh_Head;
754 return result;
757 struct Node *GetTail(struct List *list)
759 struct Node *result = NULL;
761 if(list != NULL && IsListEmpty(list) == FALSE)
762 result = list->lh_TailPred;
764 return result;
766 #endif // !__amigaos4__ && !__AROS__
768 /*****************************************************************************\
769 *******************************************************************************
771 ** Helpful object related functions.
773 *******************************************************************************
774 \*****************************************************************************/
776 #if 0 /* unused */
777 INLINE ULONG MyCallHookA(struct Hook *hook, struct NListtree_Data *data, struct NListtree_HookMessage *msg)
779 return(CallHookPkt(hook, data->Obj, msg));
781 #endif
783 #ifdef __AROS__
784 #define MyCallHook(hook, data, ...) \
785 ({ IPTR __args[] = { AROS_PP_VARIADIC_CAST2IPTR(__VA_ARGS__) }; \
786 CallHookPkt(hook, data->Obj, __args); })
787 #else
788 static IPTR STDARGS VARARGS68K MyCallHook(struct Hook *hook, struct NListtree_Data *data, ...)
790 IPTR ret;
791 VA_LIST va;
793 VA_START(va, data);
794 ret = CallHookPkt(hook, data->Obj, VA_ARG(va, APTR));
795 VA_END(va);
797 return ret;
799 #endif
802 ** Release a pen.
804 VOID RelPen( struct MUI_RenderInfo *mri, LONG *pen )
806 if ( *pen != -1 )
809 ** Only valid between Setup/Cleanup!
811 if ( mri )
813 MUI_ReleasePen( mri, *pen );
816 *pen = -1;
822 ** Relase pen if obtained and obtain a new pen.
824 VOID ObtPen( struct MUI_RenderInfo *mri, LONG *pen, struct MUI_PenSpec *ps )
827 ** Only valid between Setup/Cleanup!
829 if ( mri )
831 RelPen( mri, pen );
832 *pen = MUI_ObtainPen( mri, ps, 0 );
838 ** Fully clear and dispose an image for NList use.
840 VOID DisposeImage( struct NListtree_Data *data, ULONG nr )
842 if ( data->Image[nr].ListImage )
844 DoMethod( data->Obj, MUIM_NList_DeleteImage, data->Image[nr].ListImage );
845 data->Image[nr].ListImage = NULL;
847 if ( data->Image[nr].Image )
849 MUI_DisposeObject( data->Image[nr].Image );
850 data->Image[nr].Image = NULL;
857 ** Fully set up an image for NList use.
859 VOID SetupImage( struct NListtree_Data *data, struct MUI_ImageSpec *is, ULONG nr )
861 ENTER();
863 if ( is )
865 Object *rim;
867 data->Image[nr].nltdata = data;
868 data->MaxImageWidth = 0;
869 data->MaxImageHeight = 0;
871 if ( nr == IMAGE_Folder )
873 rim = MUI_NewObject( MUIC_Image, MUIA_Image_Spec, is, MUIA_UserData, &data->Image[nr], TAG_DONE );
875 else
877 rim = NewObject( data->CL_NodeImage->mcc_Class, NULL, MUIA_Image_Spec, is,
878 MUIA_Frame, MUIV_Frame_None,
879 MUIA_InnerBottom, 0,
880 MUIA_InnerLeft, 0,
881 MUIA_InnerRight, 0,
882 MUIA_InnerTop, 0,
883 MUIA_Weight, 0,
884 MUIA_UserData, &data->Image[nr], TAG_DONE );
887 if ( rim )
889 data->Image[nr].Image = rim;
890 data->Image[nr].ListImage = (Object *)DoMethod( data->Obj, MUIM_NList_CreateImage, rim, 0 );
892 LEAVE();
893 return;
897 LEAVE();
902 ** Activate Active/DoubleClick notification.
904 INLINE VOID ActivateNotify( struct NListtree_Data *data )
906 D(DBF_NOTIFY, "Activenotify: %lx",data);
907 if(isFlagClear(data->Flags, NLTF_ACTIVENOTIFY))
909 DoMethod(data->Obj, MUIM_Notify, MUIA_NList_Active, MUIV_EveryTime,
910 data->Obj, 2, MUIM_NListtree_GetListActive, 0);
912 DoMethod(data->Obj, MUIM_Notify, MUIA_NList_DoubleClick, MUIV_EveryTime,
913 data->Obj, 2, MUIM_NListtree_GetDoubleClick, MUIV_TriggerValue);
915 SET_FLAG(data->Flags, NLTF_ACTIVENOTIFY);
921 ** Deactivate Active/DoubleClick notification.
923 INLINE VOID DeactivateNotify( struct NListtree_Data *data )
925 D(DBF_NOTIFY, "Deactivenotify: %lx",data);
926 if(isFlagSet(data->Flags, NLTF_ACTIVENOTIFY))
928 DoMethod(data->Obj, MUIM_KillNotifyObj, MUIA_NList_DoubleClick, data->Obj);
929 DoMethod(data->Obj, MUIM_KillNotifyObj, MUIA_NList_Active, data->Obj);
931 if(isFlagClear(data->Flags, NLTF_SAFE_NOTIFIES))
933 // removing MUI notifies must be considered unsafe
934 // The solution is to trigger an artifical notification to let
935 // the object's superclass Notify.mui finally remove the killed
936 // notifies from above before
937 // NOTE: MUIA_NList_ListCompatibility is considered obsolete and
938 // currently obeyed during OM_NEW only. Hence it is safe to use
939 // this attribute for the trigger.
940 set(data->Obj, MUIA_NList_ListCompatibility, 0);
943 CLEAR_FLAG(data->Flags, NLTF_ACTIVENOTIFY);
950 #define MakeNotify( data, attr, val ) if ( !( data->Flags & NLTF_QUIET ) ) SetAttrs( data->Obj, MUIA_Group_Forward, FALSE, MUIA_NListtree_OnlyTrigger, TRUE, attr, val, TAG_DONE )
951 #define MakeSet( data, attr, val ) if ( !( data->Flags & NLTF_QUIET ) ) set( data->Obj, attr, val )
955 INLINE VOID MakeNotify( struct NListtree_Data *data, ULONG tag, APTR val )
957 if(isFlagClear(data->Flags, NLTF_QUIET))
959 SetAttrs( data->Obj, MUIA_Group_Forward, FALSE, MUIA_NListtree_OnlyTrigger, TRUE, tag, val, TAG_DONE );
963 INLINE VOID MakeSet( struct NListtree_Data *data, ULONG tag, APTR val )
965 if(isFlagClear(data->Flags, NLTF_QUIET))
967 set( data->Obj, tag, val );
969 else
971 SET_FLAG(data->Flags, NLTF_SETACTIVE);
976 /*****************************************************************************\
977 *******************************************************************************
979 ** List and table handling functions.
981 *******************************************************************************
982 \*****************************************************************************/
985 ** Create a table.
987 struct MUI_NListtree_TreeNode **NLCreateTable( struct NListtree_Data *data, struct Table *table, LONG numentrieswanted )
989 struct MUI_NListtree_TreeNode **newtable;
990 LONG oldtablesize;
993 ** Don't allocate less than one entry.
995 if ( numentrieswanted < 1 )
996 numentrieswanted = 1;
999 ** Round to next multiple of 64.
1001 oldtablesize = table->tb_Size;
1002 table->tb_Size = ( numentrieswanted + 63 ) & ~63;
1005 ** Allocate the table.
1007 if((newtable = (struct MUI_NListtree_TreeNode **)AllocVecPooled(data->TreePool, sizeof(struct MUI_NListtree_TreeNode *) * table->tb_Size)))
1010 ** If there is an old table given, copy it to the new table.
1012 if ( table->tb_Table )
1014 CopyMem( table->tb_Table, newtable, sizeof( struct MUI_NListtree_TreeNode * ) * oldtablesize );
1015 FreeVecPooled( data->TreePool, table->tb_Table );
1017 else
1018 oldtablesize = 0;
1021 ** Clear all the unused entries.
1023 memset( &newtable[oldtablesize], 0, ( table->tb_Size - oldtablesize ) * sizeof( struct MUI_NListtree_TreeNode * ) );
1024 table->tb_Table = newtable;
1027 return( newtable );
1032 ** Add an entry to a table.
1034 BOOL NLAddToTable( struct NListtree_Data *data, struct Table *table, struct MUI_NListtree_TreeNode *newentry )
1037 ** If the table is filled `to the brim', expand it.
1039 if ( ( table->tb_Entries + 1 ) > table->tb_Size )
1042 ** Allocate another list table.
1044 if ( !NLCreateTable( data, table, table->tb_Entries + 1 ) )
1045 return( FALSE );
1049 ** Add it to the end of the table.
1051 table->tb_Table[table->tb_Entries++] = newentry;
1053 return( TRUE );
1058 ** Find an entry in a table.
1060 LONG NLFindInTable( struct Table *table, struct MUI_NListtree_TreeNode *entry )
1062 LONG i;
1064 for( i = 0; i < table->tb_Entries; i++ )
1066 if ( table->tb_Table[i] == entry )
1068 return( i );
1072 return( -1 );
1078 ** Remove an entry from a table.
1080 VOID NLRemoveFromTable( struct NListtree_Data *data, struct Table *table, struct MUI_NListtree_TreeNode *entry )
1082 LONG i;
1084 if ( ( i = NLFindInTable( table, entry ) ) != -1 )
1086 if ( --table->tb_Entries == 0 )
1088 FreeVecPooled( data->TreePool, table->tb_Table );
1089 table->tb_Table = NULL;
1090 table->tb_Size = 0;
1091 table->tb_Current = -2;
1093 else
1095 LONG j;
1098 ** Remove the entry from the table.
1100 for( j = i; j <= table->tb_Entries; j++ )
1101 table->tb_Table[j] = table->tb_Table[j + 1];
1104 ** Clear the last entry and shrink the table.
1106 table->tb_Table[table->tb_Entries] = NULL;
1108 if ( table->tb_Current >= i )
1109 table->tb_Current--;
1116 /*****************************************************************************\
1117 *******************************************************************************
1119 ** Tree-List handling functions.
1121 *******************************************************************************
1122 \*****************************************************************************/
1125 ** Do a refresh, but only if not frozen. If so, set refresh flag.
1127 INLINE VOID DoRefresh( struct NListtree_Data *data )
1129 if(isFlagSet(data->Flags, NLTF_QUIET))
1131 SET_FLAG(data->Flags, NLTF_REFRESH);
1133 else
1135 DoMethod( data->Obj, MUIM_NList_Redraw, MUIV_NList_Redraw_All );
1141 ** Do only one quiet.
1143 INLINE ULONG DoQuiet( struct NListtree_Data *data, BOOL quiet )
1145 if ( quiet )
1147 SET_FLAG(data->Flags, NLTF_QUIET);
1149 if ( ++data->QuietCounter == 1 )
1150 nnset( data->Obj, MUIA_NList_Quiet, TRUE );
1152 else
1154 if ( --data->QuietCounter == 0 )
1156 nnset( data->Obj, MUIA_NList_Quiet, FALSE );
1157 CLEAR_FLAG(data->Flags, NLTF_QUIET);
1159 if(isFlagSet(data->Flags, NLTF_SETACTIVE))
1161 set( data->Obj, MUIA_NListtree_Active, data->ActiveNode );
1162 CLEAR_FLAG(data->Flags, NLTF_SETACTIVE);
1167 return( data->QuietCounter );
1172 ** Get the parent node to a given.
1174 INLINE struct MUI_NListtree_TreeNode *GetParent( struct MUI_NListtree_TreeNode *tn )
1176 return( tn ? tn->tn_Parent : NULL );
1181 ** Get the parent node to a given, but NOT the root list.
1183 struct MUI_NListtree_TreeNode *GetParentNotRoot( struct MUI_NListtree_TreeNode *tn )
1185 if((tn = GetParent(tn)))
1187 if ( GetParent( tn ) )
1189 return( tn );
1193 return( NULL );
1198 ** Check, if a given node is a child of another.
1200 struct MUI_NListtree_TreeNode *IsXChildOfY( struct MUI_NListtree_TreeNode *x, struct MUI_NListtree_TreeNode *y )
1204 if ( y == x )
1206 return( y );
1209 while((y = GetParentNotRoot(y)));
1211 return( NULL );
1216 ** Check, if a given node is a child of a list member.
1218 struct MUI_NListtree_TreeNode *IsXChildOfListMemberNotSelf( struct MUI_NListtree_TreeNode *entry, struct Table *table )
1220 LONG i;
1222 for( i = 0; i < table->tb_Entries; i++ )
1224 if ( entry != table->tb_Table[i] )
1226 if ( IsXChildOfY( table->tb_Table[i], entry ) )
1228 return( table->tb_Table[i] );
1233 return( NULL );
1237 struct MUI_NListtree_TreeNode *IsXChildOfListMember( struct MUI_NListtree_TreeNode *entry, struct Table *table )
1239 LONG i;
1241 for( i = 0; i < table->tb_Entries; i++ )
1243 if ( IsXChildOfY( table->tb_Table[i], entry ) )
1245 return( table->tb_Table[i] );
1249 return( NULL );
1254 /*****************************************************************************\
1255 *******************************************************************************
1257 ** Helpful tree handling functions.
1259 *******************************************************************************
1260 \*****************************************************************************/
1262 INLINE VOID RemoveNListEntry( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn, ULONG pos )
1264 D(DBF_LISTTREE, "Removed entry '%s' from pos %ld.", tn->tn_Name, tn->tn_NListEntry ? tn->tn_NListEntry->entpos : 999999);
1266 DoMethod( data->Obj, MUIM_NList_Remove, pos );
1267 tn->tn_NListEntry = NULL;
1271 INLINE VOID InsertNListEntry( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn, ULONG pos )
1273 struct MUI_NList_GetEntryInfo ei;
1275 DoMethod( data->Obj, MUIM_NList_InsertSingle, tn, pos );
1277 if(isFlagSet(data->Flags, NLTF_NLIST_DIRECT_ENTRY_SUPPORT))
1279 ei.pos = -3; ei.line = -2;
1280 DoMethod( data->Obj, MUIM_NList_GetEntryInfo, &ei );
1281 tn->tn_NListEntry = (struct NListEntry *)ei.entry;
1283 D(DBF_LISTTREE, "Inserted entry '%s' at pos %ld.", tn->tn_Name, tn->tn_NListEntry->entpos);
1287 INLINE VOID ReplaceNListEntry( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn, ULONG pos )
1289 struct MUI_NList_GetEntryInfo ei;
1291 DoMethod(data->Obj, MUIM_NList_ReplaceSingle, tn, pos, NOWRAP, ALIGN_LEFT);
1293 if(isFlagSet(data->Flags, NLTF_NLIST_DIRECT_ENTRY_SUPPORT))
1295 ei.pos = -3; ei.line = -2;
1296 DoMethod( data->Obj, MUIM_NList_GetEntryInfo, &ei );
1297 tn->tn_NListEntry = (struct NListEntry *)ei.entry;
1299 D(DBF_LISTTREE, "Replaced entry '%s' at pos %ld.", tn->tn_Name, tn->tn_NListEntry->entpos);
1305 ** Iterate through all entries recursive and get specified entry by pos.
1307 struct MUI_NListtree_TreeNode *GetEntryByTotalPos( struct MUI_NListtree_ListNode *ln, LONG pos, LONG *cpos, ULONG flags )
1309 struct MUI_NListtree_TreeNode *tn = CTN( (APTR)&ln->ln_List );
1311 if(isFlagSet(ln->ln_Flags, TNF_LIST))
1313 if(isFlagClear(flags, MUIV_NListtree_GetEntry_Flag_Visible) || isFlagSet(ln->ln_Flags, TNF_OPEN))
1315 while((tn = CTN(GetSucc((struct Node *)tn))))
1317 struct MUI_NListtree_TreeNode *rettn;
1319 if ( *cpos == pos )
1320 return( tn );
1322 if(isFlagClear(flags, MUIV_NListtree_GetEntry_Flag_Visible) || isFlagSet(tn->tn_IFlags, TNIF_VISIBLE))
1323 *cpos += 1;
1325 if(isFlagClear(flags, MUIV_NListtree_GetEntry_Flag_SameLevel))
1327 if((rettn = GetEntryByTotalPos(CLN(tn), pos, cpos, flags)))
1328 return( rettn );
1334 return( NULL );
1339 ** Iterate through all entries recursive and get the pos of the specified entry.
1341 BOOL GetEntryPos( struct MUI_NListtree_ListNode *ln, struct MUI_NListtree_TreeNode *stn, LONG *pos )
1343 struct MUI_NListtree_TreeNode *tn = CTN( (APTR)&ln->ln_List );
1345 while((tn = CTN(GetSucc((struct Node *)tn))))
1347 if ( stn == tn )
1348 return( TRUE );
1350 *pos += 1;
1352 if(isFlagSet(tn->tn_Flags, TNF_LIST))
1354 if ( GetEntryPos( CLN( tn ), stn, pos ) )
1355 return( TRUE );
1359 return( FALSE );
1363 /*************************************************************************
1364 Return the visual position (i.e. the position within the plain list)
1365 of the given TreeNode
1366 **************************************************************************/
1367 static LONG GetVisualPos(struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn)
1369 LONG pos = -1;
1371 ENTER();
1373 if(tn != CTN((APTR)&data->RootList) && tn != NULL)
1375 if(isFlagSet(data->Flags, NLTF_NLIST_DIRECT_ENTRY_SUPPORT))
1377 // respect visible nodes only
1378 if(isFlagSet(tn->tn_IFlags, TNIF_VISIBLE) && tn->tn_NListEntry != NULL)
1379 pos = (int)tn->tn_NListEntry->entpos;
1382 // respect visible nodes only
1383 if(pos == -1 && isFlagSet(tn->tn_IFlags, TNIF_VISIBLE))
1385 // result will be MUIV_NList_GetPos_End (-1) if not found.
1386 pos = MUIV_NList_GetPos_Start;
1387 DoMethod(data->Obj, MUIM_NList_GetPos, tn, &pos);
1391 RETURN(pos);
1392 return pos;
1395 /*************************************************************************
1396 Count the number of visual entries in a tree node (excluding the
1397 node itself). A invisible has also 0 entries. Returns also 0 if the
1398 entry is no list.
1399 **************************************************************************/
1400 static LONG GetVisualEntries( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn)
1402 LONG entries = 0;
1404 ENTER();
1406 /* Easy case */
1407 if(tn == CTN((APTR)&data->RootList))
1408 entries = xget(data->Obj, MUIA_NList_Entries);
1409 else if(isFlagSet(tn->tn_Flags, TNF_LIST) && isFlagSet(tn->tn_Flags, TNF_OPEN) && isFlagSet(tn->tn_IFlags, TNIF_VISIBLE))
1411 struct MUI_NListtree_TreeNode *tn2;
1413 tn2 = CTN(GetSucc((struct Node *)tn));
1414 if(tn2 != NULL && isFlagSet(tn2->tn_IFlags, TNIF_VISIBLE))
1416 return GetVisualPos(data,tn2) - GetVisualPos(data,tn) - 1;
1418 else
1420 /* Number of entries is number of the entries directly in this
1421 ** list and the number of the entries within the open nodes
1424 struct Table *tb = &CLN( tn )->ln_Table;
1425 int i;
1427 entries = tb->tb_Entries;
1429 for( i = 0; i < tb->tb_Entries; i++ )
1431 entries += GetVisualEntries(data, tb->tb_Table[i]);
1436 RETURN(entries);
1437 return entries;
1441 ** Count the number of visual entries in a tree node until a maximum of max.
1443 static BOOL GetVisualEntriesMax( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn, LONG pos, LONG *ent, LONG max )
1445 BOOL success = FALSE;
1447 ENTER();
1449 if(isFlagSet(tn->tn_Flags, TNF_OPEN))
1451 struct Table *tb = &CLN( tn )->ln_Table;
1452 LONG i;
1454 *ent += tb->tb_Entries;
1456 for( i = 0; ( i < tb->tb_Entries ) && ( *ent <= max ); i++ )
1458 if(GetVisualEntriesMax(data, tb->tb_Table[i], pos, ent, max))
1460 success = TRUE;
1461 break;
1466 RETURN(success);
1467 return success;
1471 /*************************************************************************
1472 Determine the visual position a node would have, if inserted after
1473 prevtn inside ln
1474 **************************************************************************/
1475 static LONG GetVisualInsertPos( struct NListtree_Data *data, struct MUI_NListtree_ListNode *ln, struct MUI_NListtree_TreeNode *prevtn )
1477 LONG ent;
1479 ENTER();
1481 if ((SIPTR)prevtn == INSERT_POS_HEAD)
1482 ent = GetVisualPos(data, CTN(ln)) + 1;
1483 else if ( (SIPTR)prevtn == INSERT_POS_TAIL )
1484 ent = GetVisualPos(data, CTN(ln)) + GetVisualEntries(data, CTN(ln)) + 1;
1485 else
1486 ent = GetVisualPos(data, CTN(prevtn)) + GetVisualEntries(data,CTN(prevtn)) + 1;
1488 RETURN(ent);
1489 return ent;
1492 struct MUI_NListtree_TreeNode *TreeNodeSelectAdd( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn )
1494 NLAddToTable( data, &data->SelectedTable, tn );
1496 D(DBF_LISTTREE, "Node 0x%08lx - %s selected (%ld nodes selected), Current: %ld", tn, tn->tn_Name, data->SelectedTable.tb_Entries, data->SelectedTable.tb_Current);
1498 return( tn );
1502 static void TreeNodeSelectRemove( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn )
1504 NLRemoveFromTable( data, &data->SelectedTable, tn );
1506 D(DBF_LISTTREE, "Node 0x%08lx - %s DEselected (%ld nodes selected), Current: %ld", tn, tn->tn_Name, data->SelectedTable.tb_Entries, data->SelectedTable.tb_Current);
1511 ** Change the selection state of one entry depending on supplied info.
1513 LONG TreeNodeSelectOne( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn, LONG seltype, LONG selflags, LONG *state )
1515 BOOL doselect = TRUE;
1516 LONG st, wassel = tn->tn_Flags;
1518 if ( seltype == MUIV_NListtree_Select_Toggle )
1520 if(isFlagSet(tn->tn_Flags, TNF_SELECTED))
1521 st = MUIV_NListtree_Select_Off;
1522 else
1523 st = MUIV_NListtree_Select_On;
1525 else
1526 st = seltype;
1528 if(isFlagClear(selflags, MUIV_NListtree_Select_Flag_Force))
1530 doselect = MultiTestFunc( data, tn, st, selflags );
1533 if ( doselect )
1535 if(isFlagSet(tn->tn_IFlags, TNIF_VISIBLE))
1537 if( st == MUIV_NListtree_Select_On && isFlagClear(wassel, TNF_SELECTED))
1538 DoMethod( data->Obj, MUIM_NList_Select, GetVisualPos( data, tn ), MUIV_NList_Select_On, NULL );
1540 else if(st == MUIV_NListtree_Select_Off && isFlagSet(wassel, TNF_SELECTED))
1541 DoMethod( data->Obj, MUIM_NList_Select, GetVisualPos( data, tn ), MUIV_NList_Select_Off, NULL );
1543 else
1545 switch ( st )
1547 case MUIV_NListtree_Select_On:
1548 SET_FLAG(tn->tn_Flags, TNF_SELECTED);
1549 break;
1551 case MUIV_NListtree_Select_Off:
1552 CLEAR_FLAG(tn->tn_Flags, TNF_SELECTED);
1553 break;
1557 if ( state )
1558 *state = st;
1561 return( st );
1566 ** Iterate through all entries recursive and let change flags (selected).
1568 VOID TreeNodeSelectAll( struct NListtree_Data *data, struct MUI_NListtree_ListNode *ln, LONG seltype, LONG selflags, LONG *state )
1570 LONG i;
1571 struct Table *tb = &ln->ln_Table;
1573 for( i = 0; i < tb->tb_Entries; i++ )
1575 TreeNodeSelectOne( data, tb->tb_Table[i], seltype, selflags, state );
1577 if(isFlagSet(tb->tb_Table[i]->tn_Flags, TNF_LIST))
1579 TreeNodeSelectAll( data, CLN( tb->tb_Table[i] ), seltype, selflags, state );
1587 ** Iterate through all entries recursive and let change flags (selected) of visible entries.
1589 VOID TreeNodeSelectVisible( struct NListtree_Data *data, struct MUI_NListtree_ListNode *ln, LONG seltype, LONG selflags, LONG *state )
1591 LONG i;
1592 struct Table *tb = &ln->ln_Table;
1594 for( i = 0; i < tb->tb_Entries; i++ )
1596 if(isFlagSet(tb->tb_Table[i]->tn_IFlags, TNIF_VISIBLE))
1598 TreeNodeSelectOne( data, tb->tb_Table[i], seltype, selflags, state );
1600 if(isFlagSet(tb->tb_Table[i]->tn_Flags, TNF_LIST))
1602 TreeNodeSelectAll( data, CLN( tb->tb_Table[i] ), seltype, selflags, state );
1611 ** Change the selection state depending on supplied info.
1613 LONG TreeNodeSelect( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn, LONG seltype, LONG selflags, LONG *state )
1615 if(isFlagSet(data->Flags, NLTF_AUTOSELECT_CHILDS))
1617 TreeNodeSelectAll( data, CLN( tn ), seltype, selflags, state );
1619 else
1621 TreeNodeSelectOne( data, tn, seltype, selflags, state );
1624 return( state ? *state : 0 );
1630 struct MUI_NListtree_TreeNode *GetInsertNodeSorted( struct NListtree_Data *data, struct MUI_NListtree_ListNode *li, struct MUI_NListtree_TreeNode *tn )
1632 struct MUI_NListtree_TreeNode *in, *in2 = NULL;
1635 ** <0 -> move to next
1636 ** >=0 -> insert here
1639 if((in = CTN(GetHead((struct List *)&li->ln_List))))
1641 while((LONG)DoMethod(data->Obj, MUIM_NListtree_Compare, in, tn, 0) < 0)
1643 in2 = in;
1645 if ( !( in = CTN(GetSucc( (struct Node *)in ) ) ) )
1647 break;
1652 if ( !in2 )
1654 in2 = CTN( INSERT_POS_HEAD );
1657 return( in2 );
1662 VOID RemoveTreeVisible( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn, LONG pos )
1664 if(isFlagSet(tn->tn_Flags, TNF_LIST) && ( tn = CTN( GetHead( (struct List *)&(CLN( tn ))->ln_List ) ) ) )
1668 if(isFlagSet(tn->tn_IFlags, TNIF_VISIBLE))
1670 D(DBF_LISTTREE, "Visible removing node \"%s\" at pos %ld ( %s | %s )", tn->tn_Name, pos, isFlagSet(tn->tn_Flags, TNF_SELECTED) ? "SEL" : "", isFlagSet(data->Flags, NLTF_QUALIFIER_LSHIFT) ? "LSHIFT" : "");
1672 if(isFlagSet(tn->tn_Flags, TNF_SELECTED))
1674 D(DBF_LISTTREE, "Unselecting node \"%s\" at pos %ld ( %s )", tn->tn_Name, pos, isFlagSet(data->Flags, NLTF_QUALIFIER_LSHIFT) ? "LSHIFT" : "");
1676 DoMethod( data->Obj, MUIM_NList_Select, pos, MUIV_NList_Select_Off, NULL );
1678 if(isFlagSet(data->Flags, NLTF_QUALIFIER_LSHIFT))
1679 SET_FLAG(tn->tn_Flags, TNF_SELECTED);
1682 CLEAR_FLAG(tn->tn_IFlags, TNIF_VISIBLE);
1683 RemoveNListEntry( data, tn, pos );
1686 if(isFlagSet(tn->tn_Flags, TNF_OPEN))
1688 RemoveTreeVisible( data, tn, pos );
1691 while((tn = CTN(GetSucc((struct Node *)tn))));
1696 VOID ReplaceTreeVisibleSort(struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn, LONG *pos)
1699 ** Determine that the node holds a list
1700 ** and the node is not open.
1702 if(isFlagSet(tn->tn_Flags, TNF_LIST) && isFlagSet(tn->tn_Flags, TNF_OPEN))
1704 if((tn = CTN(GetHead((struct List *)&(CLN(tn))->ln_List))))
1708 ReplaceNListEntry(data, tn, *pos);
1710 if(isFlagSet(tn->tn_Flags, TNF_SELECTED))
1712 DoMethod(data->Obj, MUIM_NList_Select, *pos, MUIV_NList_Select_On, NULL);
1715 if(*pos >= 0) *pos += 1;
1717 if(isFlagSet(tn->tn_Flags, TNF_OPEN))
1719 ReplaceTreeVisibleSort(data, tn, pos);
1722 while((tn = CTN(GetSucc((struct Node *)tn))));
1728 VOID RemoveTreeNodeVisible( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn, LONG *xpos )
1730 LONG pos;
1732 if(isFlagSet(tn->tn_IFlags, TNIF_VISIBLE))
1734 pos = GetVisualPos( data, tn );
1736 D(DBF_LISTTREE, "Visible removing node \"%s\" at pos %ld ( %s | %s )", tn->tn_Name, pos, isFlagSet(tn->tn_Flags, TNF_SELECTED) ? "SEL" : "", isFlagSet(data->Flags, NLTF_QUALIFIER_LSHIFT) ? "LSHIFT" : "");
1738 if(isFlagSet(tn->tn_Flags, TNF_SELECTED))
1740 D(DBF_LISTTREE, "Unselecting node \"%s\" at pos %ld ( %s )", tn->tn_Name, pos, isFlagSet(data->Flags, NLTF_QUALIFIER_LSHIFT) ? "LSHIFT" : "");
1742 DoMethod( data->Obj, MUIM_NList_Select, pos, MUIV_NList_Select_Off, NULL );
1744 if(isFlagSet(data->Flags, NLTF_QUALIFIER_LSHIFT))
1745 SET_FLAG(tn->tn_Flags, TNF_SELECTED);
1748 CLEAR_FLAG(tn->tn_IFlags, TNIF_VISIBLE);
1749 RemoveNListEntry( data, tn, pos );
1751 if ( xpos )
1752 *xpos = pos;
1754 if(isFlagSet(tn->tn_Flags, TNF_OPEN))
1756 RemoveTreeVisible( data, tn, pos );
1759 if ( pos > 0 ) DoMethod( data->Obj, MUIM_NList_Redraw, pos - 1 );
1764 VOID InsertTreeVisible( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn, LONG *pos )
1767 ** Determine that the node holds a list
1768 ** and the node is not open.
1770 if(isFlagSet(tn->tn_Flags, TNF_LIST))
1772 if((tn = CTN(GetHead((struct List *)&(CLN(tn))->ln_List))))
1776 if(isFlagClear(tn->tn_IFlags, TNIF_VISIBLE))
1778 D(DBF_LISTTREE, "Visible inserting node \"%s\" at pos %ld ( %s | %s )", tn->tn_Name, pos, isFlagSet(tn->tn_Flags, TNF_SELECTED) ? "SEL" : "", isFlagSet(data->Flags, NLTF_QUALIFIER_LSHIFT) ? "LSHIFT" : "");
1780 SET_FLAG(tn->tn_IFlags, TNIF_VISIBLE);
1781 InsertNListEntry( data, tn, *pos );
1783 if(isFlagSet(tn->tn_Flags, TNF_SELECTED))
1785 D(DBF_LISTTREE, " Selecting node \"%s\" at pos %ld ( %s )", tn->tn_Name, pos, isFlagSet(data->Flags, NLTF_QUALIFIER_LSHIFT) ? "LSHIFT" : "");
1787 DoMethod( data->Obj, MUIM_NList_Select, *pos, MUIV_NList_Select_On, NULL );
1791 if ( *pos >= 0 ) *pos += 1;
1793 if(isFlagSet(tn->tn_Flags, TNF_OPEN))
1795 InsertTreeVisible( data, tn, pos );
1798 while((tn = CTN(GetSucc((struct Node *)tn))));
1804 LONG InsertTreeNodeVisible( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn, struct MUI_NListtree_ListNode *ln, struct MUI_NListtree_TreeNode *prevtn )
1806 LONG pos = 0, temppos;
1808 if (isFlagSet(ln->ln_Flags, TNF_OPEN) && ((pos = GetVisualInsertPos( data, ln, prevtn)) != -1))
1810 SET_FLAG(tn->tn_IFlags, TNIF_VISIBLE);
1812 D(DBF_LISTTREE, "Visible inserting node 0x%lx into list 0x%lx after 0x%lx at pos %ld", tn, ln, prevtn, pos);
1814 InsertNListEntry( data, tn, pos );
1816 if(isFlagSet(tn->tn_Flags, TNF_SELECTED))
1818 D(DBF_LISTTREE, " Selecting node \"%s\" at pos %ld ( %s )", tn->tn_Name, pos, isFlagSet(data->Flags, NLTF_QUALIFIER_LSHIFT) ? "LSHIFT" : "");
1820 DoMethod( data->Obj, MUIM_NList_Select, pos, MUIV_NList_Select_On, NULL );
1823 temppos = pos + 1;
1825 if(isFlagSet(tn->tn_Flags, TNF_OPEN))
1827 InsertTreeVisible( data, tn, &temppos );
1830 if ( pos > 0 )
1831 DoMethod( data->Obj, MUIM_NList_Redraw, pos - 1 );
1833 else
1835 CLEAR_FLAG(tn->tn_IFlags, TNIF_VISIBLE);
1838 return( pos );
1843 VOID ShowTree(struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn)
1845 if(isFlagSet(tn->tn_Flags, TNF_OPEN))
1847 LONG first = xget(data->Obj, MUIA_NList_First);
1848 LONG visible = xget(data->Obj, MUIA_NList_Visible);
1849 LONG max;
1850 LONG pos;
1851 LONG a;
1852 LONG b;
1853 LONG treeentries = 0;
1854 LONG jmp;
1856 pos = GetVisualPos(data, tn);
1857 GetVisualEntriesMax(data, tn, pos, &treeentries, visible);
1859 a = pos - first;
1860 b = visible - a - 1;
1862 max = a + b;
1863 jmp = pos + MIN(max, treeentries);
1865 D(DBF_LISTTREE, "first: %ld, visible: %ld, pos: %ld, treeentries: %ld, a: %ld, b: %ld, max: %ld, jmp: %ld",
1866 first, visible, pos, treeentries, a, b, max, jmp);
1868 DoMethod(data->Obj, MUIM_NList_Jump, jmp);
1877 VOID ExpandTree( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn )
1880 ** Determine that the node holds a list
1882 if(isFlagSet(tn->tn_Flags, TNF_LIST))
1884 LONG i;
1886 struct Table *tb = &CLN( tn )->ln_Table;
1888 for( i = 0; i < tb->tb_Entries; i++ )
1890 if(isFlagSet(tb->tb_Table[i]->tn_Flags, TNF_LIST) && isFlagClear(tb->tb_Table[i]->tn_Flags, TNF_OPEN))
1892 if ( data->OpenHook )
1894 MyCallHook( data->OpenHook, data, MUIA_NListtree_OpenHook, tb->tb_Table[i] );
1897 D(DBF_LISTTREE, "Expanding node \"%s\"", tb->tb_Table[i]->tn_Name);
1899 SET_FLAG(tb->tb_Table[i]->tn_Flags, TNF_OPEN);
1902 CLEAR_FLAG(tb->tb_Table[i]->tn_IFlags, TNIF_VISIBLE);
1904 ExpandTree( data, tb->tb_Table[i] );
1910 VOID OpenTreeNode( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn )
1912 LONG entries, pos, spos=0;
1914 if(isFlagClear(tn->tn_Flags, TNF_OPEN))
1916 SET_FLAG(tn->tn_Flags, TNF_OPEN);
1918 if ( data->OpenHook )
1920 MyCallHook( data->OpenHook, data, MUIA_NListtree_OpenHook, tn );
1923 if(isFlagSet(tn->tn_IFlags, TNIF_VISIBLE))
1925 spos = pos = GetVisualPos( data, tn );
1926 entries = xget( data->Obj, MUIA_NList_Entries );
1928 pos++;
1930 if ( pos == entries )
1932 pos = MUIV_NList_Insert_Bottom;
1935 DeactivateNotify( data );
1938 if ( tb->tb_Entries > ( data->NumEntries / 4 ) )
1940 i = MUIV_NList_Insert_Bottom;
1942 DoMethod( data->Obj, MUIM_NList_Clear, 0 );
1944 CLEAR_FLAG(tn->tn_IFlags, TNIF_VISIBLE);
1945 InsertTreeVisible( data, CTN( &data->RootList ), &i );
1947 else
1950 InsertTreeVisible( data, tn, &pos );
1953 ActivateNotify( data );
1955 /* sba: the active note could be changed, but the notify calling was disabled */
1956 DoMethod(data->Obj, MUIM_NListtree_GetListActive, 0);
1959 DoMethod( data->Obj, MUIM_NList_Redraw, spos );
1964 VOID OpenTreeNodeExpand( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn )
1966 LONG entries, pos;
1968 pos = GetVisualPos( data, tn );
1969 entries = xget( data->Obj, MUIA_NList_Entries );
1971 pos++;
1973 if ( pos == entries )
1975 pos = MUIV_NList_Insert_Bottom;
1978 if(isFlagClear(tn->tn_Flags, TNF_OPEN))
1980 if ( data->OpenHook )
1982 MyCallHook( data->OpenHook, data, MUIA_NListtree_OpenHook, tn );
1985 D(DBF_LISTTREE, "Expanding node \"%s\"", tn->tn_Name);
1987 SET_FLAG(tn->tn_Flags, TNF_OPEN);
1989 ExpandTree( data, tn );
1990 InsertTreeVisible( data, tn, &pos );
1998 VOID OpenTreeNodeListExpand( struct NListtree_Data *data, struct MUI_NListtree_ListNode *ln )
2000 LONG i;
2001 struct Table *tb = &ln->ln_Table;
2003 if ( ln == &data->RootList )
2005 i = MUIV_NList_Insert_Bottom;
2007 DoMethod( data->Obj, MUIM_NList_Clear, 0 );
2009 ExpandTree( data, CTN( ln ) );
2010 InsertTreeVisible( data, CTN( ln ), &i );
2013 else if ( tb->tb_Entries > (LONG)( data->NumEntries / 4 ) )
2015 i = MUIV_NList_Insert_Bottom;
2017 DoMethod( data->Obj, MUIM_NList_Clear, 0 );
2019 ExpandTree( data, CTN( ln ) );
2020 InsertTreeVisible( data, CTN( &data->RootList ), &i );
2023 else
2025 DoMethod(data->Obj, MUIM_NList_Redraw, GetVisualPos(data, tb->tb_Table[0]));
2027 for( i = 0; i < tb->tb_Entries; i++ )
2029 OpenTreeNodeExpand( data, tb->tb_Table[i] );
2039 VOID CollapseTree( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn, BOOL clearvisible )
2042 ** Determine that the node holds a list
2044 if(isFlagSet(tn->tn_Flags, TNF_LIST))
2046 LONG i;
2048 struct Table *tb = &CLN( tn )->ln_Table;
2050 for( i = 0; i < tb->tb_Entries; i++ )
2052 if(isFlagSet(tb->tb_Table[i]->tn_Flags, TNF_OPEN))
2054 if ( data->CloseHook )
2056 MyCallHook( data->CloseHook, data, MUIA_NListtree_CloseHook, tb->tb_Table[i] );
2059 D(DBF_LISTTREE, "Collapsing node \"%s\"", tb->tb_Table[i]->tn_Name);
2061 CLEAR_FLAG(tb->tb_Table[i]->tn_Flags, TNF_OPEN);
2064 if ( clearvisible )
2065 CLEAR_FLAG(tb->tb_Table[i]->tn_IFlags, TNIF_VISIBLE);
2067 CollapseTree( data, tb->tb_Table[i], clearvisible );
2075 VOID CloseTreeNode( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn )
2077 LONG pos;
2079 if(isFlagSet(tn->tn_Flags, TNF_OPEN))
2081 pos = GetVisualPos( data, tn ) + 1;
2083 if ( data->CloseHook )
2085 MyCallHook( data->CloseHook, data, MUIA_NListtree_CloseHook, tn );
2088 CLEAR_FLAG(tn->tn_Flags, TNF_OPEN);
2090 DeactivateNotify( data );
2093 if ( tb->tb_Entries > ( data->NumEntries / 4 ) )
2095 i = MUIV_NList_Insert_Bottom;
2097 DoMethod( data->Obj, MUIM_NList_Clear, 0 );
2099 CLEAR_FLAG(tn->tn_IFlags, TNIF_VISIBLE);
2100 InsertTreeVisible( data, CTN( &data->RootList ), &i );
2102 else
2105 RemoveTreeVisible( data, tn, pos );
2108 ActivateNotify( data );
2110 /* sba: the active note could be changed, but the notify calling was disabled */
2111 DoMethod(data->Obj, MUIM_NListtree_GetListActive, 0);
2113 DoMethod( data->Obj, MUIM_NList_Redraw, pos - 1 );
2118 VOID CloseTreeNodeCollapse( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn )
2120 LONG pos;
2122 pos = GetVisualPos( data, tn ) + 1;
2124 if(isFlagSet(tn->tn_Flags, TNF_OPEN))
2126 if ( data->CloseHook )
2128 MyCallHook( data->CloseHook, data, MUIA_NListtree_CloseHook, tn );
2131 D(DBF_LISTTREE, "Collapsing node \"%s\"", tn->tn_Name);
2133 CLEAR_FLAG(tn->tn_Flags, TNF_OPEN);
2136 RemoveTreeVisible( data, tn, pos );
2137 CollapseTree( data, tn, FALSE );
2139 DoMethod( data->Obj, MUIM_NList_Redraw, pos - 1 );
2146 VOID CloseTreeNodeListCollapse( struct NListtree_Data *data, struct MUI_NListtree_ListNode *ln )
2148 LONG i;
2149 struct Table *tb = &ln->ln_Table;
2151 if ( ln == &data->RootList )
2153 i = MUIV_NList_Insert_Bottom;
2155 DoMethod( data->Obj, MUIM_NList_Clear, 0 );
2157 CollapseTree( data, CTN( ln ), TRUE );
2158 InsertTreeVisible( data, CTN( ln ), &i );
2161 else if(tb->tb_Entries > (LONG)(data->NumEntries / 4))
2163 i = MUIV_NList_Insert_Bottom;
2165 DoMethod( data->Obj, MUIM_NList_Clear, 0 );
2167 CollapseTree( data, CTN( ln ), TRUE );
2168 InsertTreeVisible( data, CTN( &data->RootList ), &i );
2171 else
2173 for( i = 0; i < tb->tb_Entries; i++ )
2175 CloseTreeNodeCollapse( data, tb->tb_Table[i] );
2182 VOID ActivateTreeNode(struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn)
2184 struct MUI_NListtree_TreeNode *tn2 = tn;
2185 ULONG jmppos;
2186 LONG newact;
2188 if(data->ActiveNode != NULL)
2190 switch(data->AutoVisible)
2192 case MUIV_NListtree_AutoVisible_Off:
2194 // nothing to do
2196 break;
2198 case MUIV_NListtree_AutoVisible_Normal:
2200 if(isFlagSet(tn2->tn_IFlags, TNIF_VISIBLE))
2202 jmppos = GetVisualPos(data, tn2);
2203 DoMethod(data->Obj, MUIM_NList_Jump, jmppos);
2206 break;
2208 case MUIV_NListtree_AutoVisible_FirstOpen:
2210 while(isFlagClear(tn2->tn_IFlags, TNIF_VISIBLE))
2211 tn2 = tn2->tn_Parent;
2213 jmppos = GetVisualPos(data, tn2);
2214 DoMethod(data->Obj, MUIM_NList_Jump, jmppos);
2216 break;
2218 case MUIV_NListtree_AutoVisible_Expand:
2220 while((tn2 = tn2->tn_Parent) != NULL)
2221 OpenTreeNode(data, tn2);
2223 jmppos = GetVisualPos(data, tn2);
2224 DoMethod(data->Obj, MUIM_NList_Jump, jmppos);
2226 break;
2230 if(tn != NULL)
2231 newact = GetVisualPos(data, tn);
2232 else
2233 newact = MUIV_NList_Active_Off;
2235 /* sba: set the new entry only if it really changes, otherwise we lose some
2236 MUIA_NList_Active notifications */
2238 D(DBF_LISTTREE, "ActivateTreeNode: %ld %ld",newact,xget(data->Obj,MUIA_NList_Active));
2239 if(newact != (LONG)xget(data->Obj,MUIA_NList_Active))
2240 set(data->Obj, MUIA_NList_Active, newact);
2244 VOID RemoveNode1( struct NListtree_Data *data, UNUSED struct MUI_NListtree_ListNode *li, struct MUI_NListtree_TreeNode *tn, LONG pos )
2246 ENTER();
2249 ** If deleted entry is active, then activate the next/previous node.
2251 if ( data->TempActiveNode == tn )
2254 ** Make sure that deleting the last entry in a
2255 ** list node causes the NEW last entry to be active!
2257 if ( !( data->TempActiveNode = CTN( GetSucc( (struct Node *)&tn->tn_Node ) ) ) )
2258 if ( !( data->TempActiveNode = CTN( GetPred( (struct Node *)&tn->tn_Node ) ) ) )
2259 data->TempActiveNode = GetParentNotRoot( tn );
2261 D(DBF_LISTTREE, "Would set active node to: %s - 0x%08lx", data->TempActiveNode ? data->TempActiveNode->tn_Name : (STRPTR)"NULL", data->TempActiveNode);
2264 D(DBF_LISTTREE, "Removing node: %s - 0x%08lx, pos: %ld", tn->tn_Name, tn, pos);
2267 ** Prevent calculating positions with practical
2268 ** deleted entries.
2270 if(isFlagSet(tn->tn_IFlags, TNIF_VISIBLE))
2272 CLEAR_FLAG(tn->tn_IFlags, TNIF_VISIBLE);
2274 RemoveNListEntry( data, tn, pos );
2278 ** Remove the node from the selected list.
2280 if(isFlagSet(tn->tn_Flags, TNF_SELECTED))
2281 TreeNodeSelectRemove( data, tn );
2283 LEAVE();
2286 VOID RemoveNode2( struct NListtree_Data *data, struct MUI_NListtree_ListNode *li, struct MUI_NListtree_TreeNode *tn )
2288 ENTER();
2290 Remove( (struct Node *)&tn->tn_Node );
2291 NLRemoveFromTable( data, &li->ln_Table, tn );
2294 ** Call internal/user supplied destruct function.
2296 DoMethod(data->Obj, MUIM_NListtree_Destruct, tn->tn_Name, tn->tn_User, data->TreePool, 0);
2299 ** Free all allocated memory.
2301 if(isFlagSet(tn->tn_IFlags, TNIF_ALLOCATED))
2303 if ( tn->tn_Name )
2304 FreeVecPooled( data->TreePool, tn->tn_Name );
2307 if(isFlagSet(tn->tn_Flags, TNF_LIST))
2309 if ( ( (struct MUI_NListtree_ListNode *)tn )->ln_Table.tb_Table )
2310 FreeVecPooled( data->TreePool, ( (struct MUI_NListtree_ListNode *)tn )->ln_Table.tb_Table );
2312 ( (struct MUI_NListtree_ListNode *)tn )->ln_Table.tb_Table = NULL;
2315 FreeVecPooled( data->TreePool, tn );
2318 ** Subtract one from the global number of entries.
2320 data->NumEntries--;
2322 LEAVE();
2327 VOID RemoveChildNodes( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn, LONG pos )
2329 struct MUI_NListtree_ListNode *ln = CLN( tn );
2331 ENTER();
2333 if(isFlagSet(tn->tn_Flags, TNF_LIST))
2335 while((tn = CTN(GetHead((struct List *)&ln->ln_List))))
2337 D(DBF_LISTTREE, "Removing node \"%s\", pos %ld", tn->tn_Name, pos);
2339 RemoveChildNodes( data, tn, pos + 1 );
2340 RemoveNode1( data, CLN( GetParent( tn ) ), tn, pos );
2341 RemoveNode2( data, CLN( GetParent( tn ) ), tn );
2345 LEAVE();
2350 VOID RemoveNodes( struct NListtree_Data *data, struct MUI_NListtree_ListNode *li, struct MUI_NListtree_TreeNode *tn, LONG pos )
2352 ENTER();
2354 RemoveChildNodes( data, tn, pos + 1 );
2355 RemoveNode1( data, li, tn, pos );
2356 RemoveNode2( data, li, tn );
2358 if(pos > 0)
2359 DoMethod(data->Obj, MUIM_NList_Redraw, pos - 1);
2361 LEAVE();
2366 VOID QuickRemoveNodes( struct NListtree_Data *data, struct MUI_NListtree_ListNode *li )
2368 struct MUI_NListtree_ListNode *ln = li;
2370 if(isFlagSet(li->ln_Flags, TNF_LIST))
2372 while((li = CLN(RemHead((struct List *)&ln->ln_List))))
2374 if(isFlagSet(li->ln_Flags, TNF_LIST))
2375 QuickRemoveNodes( data, li );
2377 if(isFlagSet(li->ln_Flags, TNF_SELECTED))
2379 TreeNodeSelectRemove( data, CTN( li ) );
2383 ** Call internal/user supplied destruct function.
2385 DoMethod(data->Obj, MUIM_NListtree_Destruct, li->ln_Name, li->ln_User, data->TreePool, 0);
2391 struct MUI_NListtree_TreeNode *FindTreeNodeByName( struct NListtree_Data *data, struct MUI_NListtree_ListNode *ln, STRPTR name, UWORD flags )
2393 struct MUI_NListtree_TreeNode *tn2, *tn;
2395 if(isFlagSet(flags, MUIV_NListtree_FindName_Flag_StartNode))
2396 tn = CTN( ln );
2397 else
2398 tn = CTN( GetHead( (struct List *)&ln->ln_List ) );
2401 if ( tn )
2405 if(isFlagSet(tn->tn_IFlags, TNIF_VISIBLE) || isFlagClear(flags, MUIV_NListtree_FindName_Flag_Visible))
2407 if(isFlagSet(tn->tn_Flags, TNF_SELECTED) || isFlagClear(flags, MUIV_NListtree_FindName_Flag_Selected))
2409 if ( !( (LONG)MyCallHook( data->FindNameHook, data, MUIA_NListtree_FindNameHook, name, tn->tn_Name, tn->tn_User, flags ) ) )
2411 return( tn );
2416 if(isFlagSet(tn->tn_Flags, TNF_LIST) && isFlagClear(flags, MUIV_NListtree_FindName_Flag_SameLevel))
2418 if((tn2 = FindTreeNodeByName(data, CLN(tn), name, (flags & ~MUIV_NListtree_FindName_Flag_StartNode))))
2420 return( tn2 );
2424 while((tn = CTN(GetSucc((struct Node *)&tn->tn_Node))));
2427 return( NULL );
2432 struct MUI_NListtree_TreeNode *FindTreeNodeByNameRev( struct NListtree_Data *data, struct MUI_NListtree_ListNode *ln, STRPTR name, UWORD flags )
2434 struct MUI_NListtree_TreeNode *tn;
2438 if(isFlagSet(flags, MUIV_NListtree_FindName_Flag_StartNode))
2439 tn = CTN( ln );
2440 else
2441 tn = CTN( GetTail( (struct List *)&ln->ln_List ) );
2443 if ( tn )
2447 if(isFlagSet(tn->tn_IFlags, TNIF_VISIBLE) || isFlagClear(flags, MUIV_NListtree_FindName_Flag_Visible))
2449 if(isFlagSet(tn->tn_Flags, TNF_SELECTED) || isFlagClear(flags, MUIV_NListtree_FindName_Flag_Selected))
2451 if ( !( (LONG)MyCallHook( data->FindNameHook, data, MUIA_NListtree_FindNameHook, name, tn->tn_Name, tn->tn_User, flags ) ) )
2453 return( tn );
2458 while((tn = CTN(GetPred((struct Node *)&tn->tn_Node))));
2460 if(isFlagClear(flags, MUIV_NListtree_FindName_Flag_SameLevel))
2462 ln = CLN( GetParent( CTN( ln ) ) );
2463 SET_FLAG(flags, MUIV_NListtree_FindName_Flag_StartNode);
2465 else
2466 ln = NULL;
2469 while ( ln );
2471 return( NULL );
2476 struct MUI_NListtree_TreeNode *FindTreeNodeByUserData( struct NListtree_Data *data, struct MUI_NListtree_ListNode *ln, STRPTR userdata, UWORD flags )
2478 struct MUI_NListtree_TreeNode *tn2, *tn;
2480 if(isFlagSet(flags, MUIV_NListtree_FindUserData_Flag_StartNode))
2481 tn = CTN( ln );
2482 else
2483 tn = CTN( GetHead( (struct List *)&ln->ln_List ) );
2486 if ( tn )
2490 if(isFlagSet(tn->tn_IFlags, TNIF_VISIBLE) || isFlagClear(flags, MUIV_NListtree_FindUserData_Flag_Visible))
2492 if(isFlagSet(tn->tn_Flags, TNF_SELECTED) || isFlagClear(flags, MUIV_NListtree_FindUserData_Flag_Selected))
2494 if ( !( (LONG)MyCallHook( data->FindUserDataHook, data, MUIA_NListtree_FindUserDataHook, userdata, tn->tn_User, tn->tn_Name, flags ) ) )
2496 return( tn );
2501 if(isFlagSet(tn->tn_Flags, TNF_LIST) && isFlagClear(flags, MUIV_NListtree_FindUserData_Flag_SameLevel))
2503 if((tn2 = FindTreeNodeByUserData(data, CLN(tn), userdata, (flags & ~MUIV_NListtree_FindUserData_Flag_StartNode))))
2505 return( tn2 );
2509 while((tn = CTN(GetSucc((struct Node *)&tn->tn_Node))));
2512 return( NULL );
2517 struct MUI_NListtree_TreeNode *FindTreeNodeByUserDataRev( struct NListtree_Data *data, struct MUI_NListtree_ListNode *ln, STRPTR userdata, UWORD flags )
2519 struct MUI_NListtree_TreeNode *tn;
2523 if(isFlagSet(flags, MUIV_NListtree_FindUserData_Flag_StartNode))
2524 tn = CTN( ln );
2525 else
2526 tn = CTN( GetTail( (struct List *)&ln->ln_List ) );
2528 if ( tn )
2532 if(isFlagSet(tn->tn_IFlags, TNIF_VISIBLE) || isFlagClear(flags, MUIV_NListtree_FindUserData_Flag_Visible))
2534 if(isFlagSet(tn->tn_Flags, TNF_SELECTED) || isFlagClear(flags, MUIV_NListtree_FindUserData_Flag_Selected))
2536 if ( !( (LONG)MyCallHook( data->FindUserDataHook, data, MUIA_NListtree_FindUserDataHook, userdata, tn->tn_User, tn->tn_Name, flags ) ) )
2538 return( tn );
2543 while((tn = CTN(GetPred((struct Node *)&tn->tn_Node))));
2545 if(isFlagClear(flags, MUIV_NListtree_FindUserData_Flag_SameLevel))
2547 ln = CLN( GetParent( CTN( ln ) ) );
2548 SET_FLAG(flags, MUIV_NListtree_FindUserData_Flag_StartNode);
2550 else
2551 ln = NULL;
2554 while ( ln );
2556 return( NULL );
2561 VOID InsertTreeNode( struct NListtree_Data *data, struct MUI_NListtree_ListNode *ln, struct MUI_NListtree_TreeNode *tn1, struct MUI_NListtree_TreeNode *tn2 )
2564 ** Give the entry a parent.
2566 tn1->tn_Parent = CTN( ln );
2569 ** Insert entry into list.
2571 if ( (IPTR)tn2 == (IPTR)INSERT_POS_HEAD )
2573 AddHead( (struct List *)&ln->ln_List, (struct Node *)&tn1->tn_Node );
2575 else if ( (IPTR)tn2 == (IPTR)INSERT_POS_TAIL )
2577 AddTail( (struct List *)&ln->ln_List, (struct Node *)&tn1->tn_Node );
2579 else
2581 Insert( (struct List *)&ln->ln_List, (struct Node *)&tn1->tn_Node, (struct Node *)&tn2->tn_Node );
2584 InsertTreeNodeVisible( data, tn1, ln, tn2 );
2585 NLAddToTable( data, &ln->ln_Table, tn1 );
2590 struct MUI_NListtree_TreeNode *DuplicateNode( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *nodetodup )
2592 struct MUI_NListtree_ListNode *new;
2593 APTR user = NULL;
2595 if((new = CLN(AllocVecPooled(data->TreePool, isFlagSet(nodetodup->tn_Flags, TNF_LIST) ? sizeof(struct MUI_NListtree_ListNode) : sizeof(struct MUI_NListtree_TreeNode)))) != NULL)
2597 if(isFlagSet(nodetodup->tn_Flags, TNF_LIST))
2598 NewList((struct List *)&new->ln_List);
2601 ** Should we duplicate the supplied node name?
2603 if(isFlagSet(data->Flags, NLTF_DUPNODENAMES))
2605 int len = strlen(nodetodup->tn_Name) + 1;
2607 if((new->ln_Name = (STRPTR)AllocVecPooled(data->TreePool, len)) != NULL)
2609 strlcpy(new->ln_Name, nodetodup->tn_Name, len);
2610 SET_FLAG(new->ln_IFlags, TNIF_ALLOCATED);
2613 else
2614 new->ln_Name = nodetodup->tn_Name;
2617 ** Create new user dats
2619 if(new->ln_Name != NULL)
2621 user = (APTR)DoMethod(data->Obj, MUIM_NListtree_Construct, nodetodup->tn_Name, nodetodup->tn_User, data->TreePool, MUIV_NListtree_ConstructHook_Flag_AutoCreate);
2623 if(user == NULL)
2626 ** Free all previously allocated memory if
2627 ** something failed before.
2629 if(isFlagSet(new->ln_IFlags, TNIF_ALLOCATED))
2630 FreeVecPooled(data->TreePool, new->ln_Name);
2632 DoMethod(data->Obj, MUIM_NListtree_Destruct, nodetodup->tn_Name, nodetodup->tn_User, data->TreePool, 0);
2634 FreeVecPooled(data->TreePool, new);
2635 new = NULL;
2637 else
2639 new->ln_User = user;
2640 new->ln_Flags = ( nodetodup->tn_Flags & ~TNF_SELECTED );
2643 ** Add one to the global number of entries
2645 data->NumEntries++;
2648 else
2650 FreeVecPooled(data->TreePool, new);
2651 new = NULL;
2655 return(CTN(new));
2660 struct MUI_NListtree_TreeNode *CreateParentStructure( struct NListtree_Data *data, ULONG method, struct MUI_NListtree_ListNode **destlist, struct MUI_NListtree_TreeNode **destentry, struct MUI_NListtree_TreeNode *nodetodup, UWORD cnt )
2662 struct MUI_NListtree_ListNode *prevnode, *newlist;
2664 if((prevnode = CLN(GetParentNotRoot(nodetodup))))
2665 *destlist = CLN( CreateParentStructure( data, method, destlist, destentry, CTN(prevnode), cnt + 1 ) );
2667 D(DBF_LISTTREE, "Adding node 0x%08lx - %s to node 0x%08lx - %s", nodetodup, nodetodup->tn_Name, *destlist, (*destlist)->ln_Name);
2670 ** Allocate memory for the new entry and
2671 ** initialize list structure for use.
2673 if ( ( method == MUIM_NListtree_Copy ) || cnt )
2675 newlist = CLN( DuplicateNode( data, nodetodup ) );
2677 else
2679 newlist = CLN(nodetodup);
2682 if ( newlist )
2685 ** Add the new created entry to the specified list.
2687 if ( cnt )
2690 ** Insert entry into list.
2692 InsertTreeNode( data, *destlist, CTN(newlist), *destentry );
2693 *destentry = CTN( INSERT_POS_TAIL );
2694 if(isFlagSet(nodetodup->tn_IFlags, TNIF_VISIBLE))
2695 SET_FLAG(newlist->ln_IFlags, TNIF_VISIBLE);
2696 else
2697 CLEAR_FLAG(newlist->ln_IFlags, TNIF_VISIBLE);
2701 return( CTN( newlist ) );
2706 struct MUI_NListtree_TreeNode *CreateChildStructure( struct NListtree_Data *data, struct MUI_NListtree_ListNode *listnode, struct MUI_NListtree_ListNode *nodetodup, struct MUI_NListtree_ListNode *orignode, ULONG cnt )
2708 struct MUI_NListtree_ListNode *new;
2710 if ( cnt > 0 )
2711 new = CLN(DuplicateNode( data, CTN(nodetodup)));
2712 else
2713 new = nodetodup;
2715 if ( new )
2718 ** Insert entry into list.
2720 InsertTreeNode( data, listnode, CTN(new), CTN( INSERT_POS_TAIL ) );
2722 if(isFlagSet(orignode->ln_Flags, TNF_LIST))
2724 if ( !IsListEmpty( &orignode->ln_List ) )
2726 struct MUI_NListtree_ListNode *ln = CLN( &orignode->ln_List );
2727 LONG i;
2729 for ( i = 0; i < orignode->ln_Table.tb_Entries; i++ )
2731 ln = CLN( GetSucc( (struct Node *)ln ) );
2733 CreateChildStructure( data, new, ln, ln, cnt + 1 );
2739 return(CTN(new));
2744 /*****************************************************************************\
2745 *******************************************************************************
2747 ** Graphical and render functions.
2749 *******************************************************************************
2750 \*****************************************************************************/
2752 static void InsertTreeImages( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn, struct MUI_NListtree_TreeNode *otn, UWORD cnt )
2754 struct MUI_NListtree_TreeNode *gp;
2756 if ( tn )
2758 LONG x1 = -1, x2 = 0;
2760 // we do a recursive call in case we find a
2761 // parent node for the current one.
2762 if((gp = GetParent(tn)))
2763 InsertTreeImages( data, gp, otn, cnt + 1 );
2765 x2 = data->MaxImageWidth;
2767 if ( GetSucc( (struct Node *)&tn->tn_Node ) )
2769 if(cnt == 0)
2771 if(isFlagClear(tn->tn_Flags, TNF_LIST))
2773 x1 = SPEC_VertT;
2776 else
2778 x1 = SPEC_Vert;
2781 else
2783 if(cnt == 0)
2785 if(isFlagClear(tn->tn_Flags, TNF_LIST))
2787 x1 = SPEC_VertEnd;
2790 else if ( gp )
2792 x1 = SPEC_Space;
2796 if ( ( x1 != -1 ) && x2 )
2798 char tmpbuf[DATA_BUF_SIZE];
2800 if ( x1 == SPEC_Space )
2801 otn->tn_Space += x2 + data->IndentWidth;
2803 if ( otn->tn_Space > 0 )
2805 snprintf(tmpbuf, DATA_BUF_SIZE, "\033O[%lx;%x;%d,%d]", (unsigned long)data->Image[IMAGE_Tree].ListImage, (unsigned int)MUIA_TI_Spec, (int)SPEC_Space, (int)otn->tn_Space );
2806 strncat(data->buf, tmpbuf, DATA_BUF_SIZE);
2808 otn->tn_ImagePos += otn->tn_Space;
2809 otn->tn_Space = 0;
2812 if ( x1 != SPEC_Space )
2814 x2 += data->IndentWidth;
2817 ** Should we draw the root tree? No? Just use space.
2819 if(isFlagSet(data->Flags, NLTF_NO_ROOT_TREE) && gp->tn_Parent == NULL)
2821 snprintf(tmpbuf, DATA_BUF_SIZE, "\033O[%lx;%x;%d,%d]", (unsigned long)data->Image[IMAGE_Tree].ListImage, (unsigned int)MUIA_TI_Spec, (int)SPEC_Space, (int)x2 );
2822 strncat(data->buf, tmpbuf, DATA_BUF_SIZE);
2824 otn->tn_ImagePos += x2;
2826 else
2828 // ensures proper text alignment with subnodes in
2829 // case the user selected an additional indentwidth
2830 if(data->IndentWidth > 0)
2831 x2 += 2;
2833 snprintf(tmpbuf, DATA_BUF_SIZE, "\033O[%lx;%x;%d,%d]", (unsigned long)data->Image[IMAGE_Tree].ListImage, (unsigned int)MUIA_TI_Spec, (int)x1, (int)x2 );
2834 strncat(data->buf, tmpbuf, DATA_BUF_SIZE);
2836 otn->tn_ImagePos += x2;
2843 static void InsertImage( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *otn )
2845 struct MUI_NListtree_ListNode *ln = CLN( otn );
2846 char tmpbuf[DATA_BUF_SIZE];
2847 LONG x1 = -1;
2849 InsertTreeImages( data, otn, otn, 0 );
2851 if((isFlagSet(otn->tn_Flags, TNF_LIST) && isFlagClear(otn->tn_Flags, TNF_NOSIGN)) && ( !IsListEmpty( &ln->ln_List ) || isFlagClear(data->Flags, NLTF_EMPTYNODES)))
2853 if(isFlagSet(otn->tn_Flags, TNF_OPEN))
2855 x1 = IMAGE_Open;
2857 else
2859 x1 = IMAGE_Closed;
2862 snprintf(tmpbuf, DATA_BUF_SIZE, "\033O[%lx]", (unsigned long)data->Image[x1].ListImage );
2863 strncat(data->buf, tmpbuf, DATA_BUF_SIZE);
2865 x1 = SPEC_Hor;
2867 // add some indent width
2868 if(data->IndentWidth > 0)
2870 snprintf(tmpbuf, DATA_BUF_SIZE, "\033O[%lx;%x;%d,%d]", (unsigned long)data->Image[IMAGE_Tree].ListImage, (unsigned int)MUIA_TI_Spec, (int)x1, (unsigned int)data->IndentWidth);
2871 strncat(data->buf, tmpbuf, DATA_BUF_SIZE);
2874 if(data->UseFolderImage == TRUE)
2876 snprintf(tmpbuf, DATA_BUF_SIZE, "\033O[%lx]\033O[%lx;%x;%d,%d]", (unsigned long)data->Image[IMAGE_Folder].ListImage, (unsigned long)data->Image[IMAGE_Tree].ListImage, (unsigned int)MUIA_TI_Spec, (unsigned int)SPEC_Space, 3);
2877 strncat(data->buf, tmpbuf, DATA_BUF_SIZE);
2883 static void DrawImages( struct MUI_NListtree_TreeNode *otn, struct MUI_NListtree_TreeNode *tn, struct NListtree_Data *data, UWORD cnt )
2885 if ( tn )
2887 struct MUI_NListtree_TreeNode *gp;
2889 if((gp = GetParent(tn)))
2890 DrawImages( otn, gp, data, cnt + 1 );
2892 if(cnt == 0)
2893 InsertImage( data, otn );
2899 /*****************************************************************************\
2900 *******************************************************************************
2902 ** General internal class related functions.
2904 *******************************************************************************
2905 \*****************************************************************************/
2907 ULONG MultiTestFunc( struct NListtree_Data *data, struct MUI_NListtree_TreeNode *tn, LONG seltype, LONG selflags )
2909 LONG currtype = isFlagSet(tn->tn_Flags, TNF_SELECTED) ? MUIV_NListtree_Select_On : MUIV_NListtree_Select_Off;
2910 BOOL doselect = TRUE;
2912 if(isFlagSet(data->Flags, NLTF_DRAGDROP))
2913 return( FALSE );
2915 if(isFlagSet(data->Flags, NLTF_NLIST_NO_SCM_SUPPORT))
2916 return( FALSE );
2918 if ( currtype != seltype )
2920 if ( data->MultiTestHook )
2922 doselect = (BOOL)MyCallHook( data->MultiTestHook, data, MUIA_NListtree_MultiTestHook, tn, seltype, selflags, currtype );
2925 if ( doselect )
2927 doselect = DoMethod( data->Obj, MUIM_NListtree_MultiTest, tn, seltype, selflags, currtype );
2933 if ( doselect )
2934 D(DBF_ALWAYS, "MULTITEST: 0x%08lx - %s", tn, tn->tn_Name);
2937 return( doselect );
2940 HOOKPROTONH(NList_MultiTestFunc, ULONG, Object *obj, struct MUI_NListtree_TreeNode *tn)
2942 struct NListtree_Data *data;
2943 ULONG ret = FALSE;
2945 data = (struct NListtree_Data *)xget( obj, MUIA_UserData );
2947 if(isFlagSet(data->Flags, NLTF_SELECT_METHOD))
2948 return( TRUE );
2950 if ( data->MultiSelect != MUIV_NListtree_MultiSelect_None )
2952 if ( ( data->MultiSelect == MUIV_NListtree_MultiSelect_Default ) ||
2953 ( data->MultiSelect == MUIV_NListtree_MultiSelect_Always ) ||
2954 ( ( data->MultiSelect == MUIV_NListtree_MultiSelect_Shifted ) && isFlagSet(data->Flags, NLTF_QUALIFIER_LSHIFT)))
2956 ret = MultiTestFunc( data, tn, MUIV_NListtree_Select_On, 0 );
2960 return( ret );
2962 MakeStaticHook(NList_MultiTestHook, NList_MultiTestFunc);
2964 HOOKPROTONHNO(_ConstructFunc, APTR, struct MUIP_NListtree_ConstructMessage *msg)
2966 APTR retdata;
2969 ** Allocate memory for the user field and
2970 ** copy the supplied string to the new
2971 ** allocated piece of memory.
2973 if ( msg->UserData )
2975 int len = strlen((STRPTR)msg->UserData ) + 1;
2977 if((retdata = AllocVecPooled(msg->MemPool, len)))
2979 strlcpy( (STRPTR)retdata, (STRPTR)msg->UserData, len );
2981 D(DBF_LISTTREE, "Internal CostructHook ==> Data: '%s'", (STRPTR)msg->UserData);
2983 return( retdata );
2987 return( NULL );
2989 MakeStaticHook(_ConstructHook, _ConstructFunc);
2991 HOOKPROTONHNO(_DestructFunc, ULONG, struct MUIP_NListtree_DestructMessage *msg)
2993 D(DBF_LISTTREE, "Internal DestructHook ==> Data: '%s'", (STRPTR)msg->UserData);
2996 ** Free the string memory.
2998 if ( msg->UserData )
3000 FreeVecPooled( msg->MemPool, msg->UserData );
3003 return( 0 );
3005 MakeStaticHook(_DestructHook, _DestructFunc);
3009 ** The internal compare hook functions.
3012 HOOKPROTONHNONP(_CompareFunc_Head, LONG) //struct MUIP_NListtree_CompareMessage *msg)
3014 return( 1 );
3016 MakeStaticHook(_CompareHook_Head, _CompareFunc_Head);
3018 HOOKPROTONHNONP(_CompareFunc_Tail, LONG) //struct MUIP_NListtree_CompareMessage *msg)
3020 return( -1 );
3022 MakeStaticHook(_CompareHook_Tail, _CompareFunc_Tail);
3024 HOOKPROTONHNO(_CompareFunc_LeavesTop, LONG, struct MUIP_NListtree_CompareMessage *msg)
3026 if(isFlagSet(msg->TreeNode1->tn_Flags, TNF_LIST) && isFlagSet(msg->TreeNode2->tn_Flags, TNF_LIST))
3028 return( Stricmp( msg->TreeNode1->tn_Name, msg->TreeNode2->tn_Name ) );
3030 else if(isFlagSet(msg->TreeNode1->tn_Flags, TNF_LIST))
3032 return( 1 );
3034 else if(isFlagSet(msg->TreeNode2->tn_Flags, TNF_LIST))
3036 return( -1 );
3038 else
3040 return( Stricmp( msg->TreeNode1->tn_Name, msg->TreeNode2->tn_Name ) );
3043 MakeStaticHook(_CompareHook_LeavesTop, _CompareFunc_LeavesTop);
3045 HOOKPROTONHNO(_CompareFunc_LeavesBottom, LONG, struct MUIP_NListtree_CompareMessage *msg)
3047 if(isFlagSet(msg->TreeNode1->tn_Flags, TNF_LIST) && isFlagSet(msg->TreeNode2->tn_Flags, TNF_LIST))
3049 return( Stricmp( msg->TreeNode1->tn_Name, msg->TreeNode2->tn_Name ) );
3051 else if(isFlagSet(msg->TreeNode1->tn_Flags, TNF_LIST))
3053 return( -1 );
3055 else if(isFlagSet(msg->TreeNode2->tn_Flags, TNF_LIST))
3057 return( 1 );
3059 else
3061 return( Stricmp( msg->TreeNode1->tn_Name, msg->TreeNode2->tn_Name ) );
3064 MakeStaticHook(_CompareHook_LeavesBottom, _CompareFunc_LeavesBottom);
3066 HOOKPROTONHNO(_CompareFunc_LeavesMixed, LONG, struct MUIP_NListtree_CompareMessage *msg)
3068 return( Stricmp( msg->TreeNode1->tn_Name, msg->TreeNode2->tn_Name ) );
3070 MakeStaticHook(_CompareHook_LeavesMixed, _CompareFunc_LeavesMixed);
3072 static void SortList( struct MUI_NListtree_ListNode *ln, struct NListtree_Data *data )
3074 if ( ln->ln_Table.tb_Entries > 1 )
3076 struct MUI_NListtree_TreeNode **localtable;
3077 LONG i;
3079 // let's start the quicksort algorithm to sort our entries.
3080 qsort2(ln->ln_Table.tb_Table, ln->ln_Table.tb_Entries, data);
3082 localtable = ln->ln_Table.tb_Table;
3084 NewList( (struct List *)&ln->ln_List );
3086 for( i = 0; i < ln->ln_Table.tb_Entries; i++ )
3088 AddTail( (struct List *)&ln->ln_List, (struct Node *)localtable[i] );
3093 struct MUI_NListtree_ListNode *ListNode_Sort( struct MUI_NListtree_ListNode *ln, struct NListtree_Data *data, ULONG flags )
3095 if(isFlagSet(flags, MUIV_NListtree_Sort_Flag_RecursiveAll) || isFlagSet(flags, MUIV_NListtree_Sort_Flag_RecursiveOpen))
3097 struct MUI_NListtree_ListNode *ln2 = CLN( &ln->ln_List );
3099 while((ln2 = CLN(GetSucc((struct Node *)ln2))))
3101 if(isFlagSet(ln2->ln_Flags, TNF_LIST))
3103 if(isFlagSet(ln2->ln_Flags, TNF_OPEN) || isFlagSet(flags, MUIV_NListtree_Sort_Flag_RecursiveAll))
3105 ListNode_Sort( ln2, data, flags );
3111 if(isFlagSet(ln->ln_Flags, TNF_LIST))
3112 SortList( ln, data );
3114 return( ln );
3117 HOOKPROTONHNO(_FindNameFunc_CaseSensitive, LONG, struct MUIP_NListtree_FindNameMessage *msg)
3119 return( strcmp( msg->Name, msg->NodeName ) );
3121 MakeStaticHook(_FindNameHook_CaseSensitive, _FindNameFunc_CaseSensitive);
3123 HOOKPROTONHNO(_FindNameFunc_CaseInsensitive, LONG, struct MUIP_NListtree_FindNameMessage *msg)
3125 return( Stricmp( msg->Name, msg->NodeName ) );
3127 MakeStaticHook(_FindNameHook_CaseInsensitive, _FindNameFunc_CaseInsensitive);
3129 HOOKPROTONHNO(_FindNameFunc_Part, LONG, struct MUIP_NListtree_FindNameMessage *msg)
3131 return( strncmp( msg->Name, msg->NodeName, strlen( msg->Name ) ) );
3133 MakeStaticHook(_FindNameHook_Part, _FindNameFunc_Part);
3135 HOOKPROTONHNO(_FindNameFunc_PartCaseInsensitive, LONG, struct MUIP_NListtree_FindNameMessage *msg)
3137 return( Strnicmp( msg->Name, msg->NodeName, strlen( msg->Name ) ) );
3139 MakeStaticHook(_FindNameHook_PartCaseInsensitive, _FindNameFunc_PartCaseInsensitive);
3141 HOOKPROTONHNO(_FindNameFunc_PointerCompare, LONG, struct MUIP_NListtree_FindNameMessage *msg)
3143 return( (LONG)( (SIPTR)msg->Name - (SIPTR)msg->NodeName ) );
3145 MakeStaticHook(_FindNameHook_PointerCompare, _FindNameFunc_PointerCompare);
3147 HOOKPROTONHNO(_FindUserDataFunc_CaseSensitive, LONG, struct MUIP_NListtree_FindUserDataMessage *msg)
3149 return( strcmp( (STRPTR)msg->User, (STRPTR)msg->UserData ) );
3151 MakeStaticHook(_FindUserDataHook_CaseSensitive, _FindUserDataFunc_CaseSensitive);
3153 HOOKPROTONHNO(_FindUserDataFunc_CaseInsensitive, LONG, struct MUIP_NListtree_FindUserDataMessage *msg)
3155 return( Stricmp( (STRPTR)msg->User, (STRPTR)msg->UserData ) );
3157 MakeStaticHook(_FindUserDataHook_CaseInsensitive, _FindUserDataFunc_CaseInsensitive);
3159 HOOKPROTONHNO(_FindUserDataFunc_Part, LONG, struct MUIP_NListtree_FindUserDataMessage *msg)
3161 return( strncmp( (STRPTR)msg->User, (STRPTR)msg->UserData, strlen( (STRPTR)msg->User ) ) );
3163 MakeStaticHook(_FindUserDataHook_Part, _FindUserDataFunc_Part);
3165 HOOKPROTONHNO(_FindUserDataFunc_PartCaseInsensitive, LONG, struct MUIP_NListtree_FindUserDataMessage *msg)
3167 return( Strnicmp( (STRPTR)msg->User, (STRPTR)msg->UserData, strlen( (STRPTR)msg->User ) ) );
3169 MakeStaticHook(_FindUserDataHook_PartCaseInsensitive, _FindUserDataFunc_PartCaseInsensitive);
3171 HOOKPROTONHNO(_FindUserDataFunc_PointerCompare, LONG, struct MUIP_NListtree_FindUserDataMessage *msg)
3173 return( (LONG)( (SIPTR)msg->User - (SIPTR)msg->UserData ) );
3175 MakeStaticHook(_FindUserDataHook_PointerCompare, _FindUserDataFunc_PointerCompare);
3178 /*****************************************************************************\
3179 *******************************************************************************
3181 ** General internal class related help functions.
3183 *******************************************************************************
3184 \*****************************************************************************/
3186 /****** NListtree.mcc/MUIA_NListtree_Active **********************************
3188 * NAME
3190 * MUIA_NListtree_Active -- [.SG], struct MUI_NListtree_TreeNode *
3193 * SPECIAL VALUES
3195 * MUIV_NListtree_Active_Off
3196 * MUIV_NListtree_Active_Parent
3197 * MUIV_NListtree_Active_First
3198 * MUIV_NListtree_Active_FirstVisible
3199 * MUIV_NListtree_Active_LastVisible
3202 * FUNCTION
3204 * Setting this attribute will move the cursor to the defined tree node
3205 * if it is visible. If the node is in an opened tree the listview is
3206 * scrolling into the visible area. Setting MUIV_NListtree_Active_Off will
3207 * vanish the cursor.
3209 * MUIV_NListtree_Active_First/FirstVisible/LastVisible are special values
3210 * for activating the lists first or the top/bottom visible entry.
3212 * See MUIA_NListtree_AutoVisible for special activation features.
3214 * If this attribute is read it returns the active tree node. The result
3215 * is MUIV_NListtree_Active_Off if there is no active entry.
3218 * NOTIFICATIONS
3220 * You can create a notification on MUIA_NListtree_Active. The
3221 * TriggerValue is the active tree node.
3224 * SEE ALSO
3226 * MUIA_NListtree_AutoVisible, MUIA_NList_First, MUIA_NList_Visible,
3227 * MUIA_NListtree_ActiveList
3229 ******************************************************************************
3233 /****** NListtree.mcc/MUIA_NListtree_ActiveList ******************************
3235 * NAME
3237 * MUIA_NListtree_ActiveList -- [..G], struct MUI_NListtree_TreeNode *
3240 * SPECIAL VALUES
3242 * MUIV_NListtree_ActiveList_Off
3245 * FUNCTION
3247 * If this attribute is read it returns the active list node. The
3248 * active list node is always the parent of the active entry.
3249 * The result is MUIV_NListtree_ActiveList_Off if there is no
3250 * active list (when there is no active entry).
3253 * NOTIFICATIONS
3255 * You can create notifications on MUIA_NListtree_ActiveList. The
3256 * TriggerValue is the active list node.
3259 * SEE ALSO
3261 * MUIA_NListtree_Active
3263 ******************************************************************************
3267 /****** NListtree.mcc/MUIA_NListtree_AutoVisible *****************************
3269 * NAME
3271 * MUIA_NListtree_AutoVisible -- [ISG], struct MUI_NListtree_TreeNode *
3274 * SPECIAL VALUES
3276 * MUIV_NListtree_AutoVisible_Off
3277 * MUIV_NListtree_AutoVisible_Normal
3278 * MUIV_NListtree_AutoVisible_FirstOpen
3279 * MUIV_NListtree_AutoVisible_Expand
3282 * FUNCTION
3284 * Set this to make your list automatically jump to the active
3285 * entry.
3287 * MUIV_NListtree_AutoVisible_Off:
3288 * The display does NOT scroll the active entry into the
3289 * visible area.
3291 * MUIV_NListtree_AutoVisible_Normal:
3292 * This will scroll the active entry into the visible area
3293 * if it is visible (entry is a member of an open node).
3294 * This is the default.
3296 * MUIV_NListtree_AutoVisible_FirstOpen:
3297 * Nodes are not opened, but the first open parent node of
3298 * the active entry is scrolled into the visible area if the
3299 * active entry is not visible.
3301 * MUIV_NListtree_AutoVisible_Expand:
3302 * All parent nodes are opened until the first open node is
3303 * reached and the active entry will be scrolled into the
3304 * visible area.
3307 * NOTIFICATIONS
3310 * SEE ALSO
3312 * MUIA_NListtree_Active, MUIA_NList_AutoVisible
3314 ******************************************************************************
3318 /****** NListtree.mcc/MUIA_NListtree_CloseHook *******************************
3320 * NAME
3322 * MUIA_NListtree_CloseHook -- [IS.], struct Hook *
3325 * SPECIAL VALUES
3328 * FUNCTION
3330 * The close hook is called after a list node is closed, then you can
3331 * change the list.
3333 * The close hook will be called with the hook in A0, the object in A2
3334 * and a MUIP_NListtree_CloseMessage struct in A1 (see nlisttree_mcc.h).
3336 * To remove the hook set this to NULL.
3339 * NOTIFICATION
3342 * SEE ALSO
3344 * MUIA_NListtree_Open, MUIA_NListtree_CloseHook
3347 ******************************************************************************
3351 /****** NListtree.mcc/MUIA_NListtree_CompareHook *****************************
3353 * NAME
3355 * MUIA_NListtree_CompareHook -- [IS.], struct Hook *
3358 * SPECIAL VALUES
3360 * MUIV_NListtree_CompareHook_Head
3361 * MUIV_NListtree_CompareHook_Tail
3362 * MUIV_NListtree_CompareHook_LeavesTop
3363 * MUIV_NListtree_CompareHook_LeavesMixed
3364 * MUIV_NListtree_CompareHook_LeavesBottom
3367 * FUNCTION
3369 * Set this attribute to your own hook if you want to sort the entries in
3370 * the list tree by your own way.
3372 * When you sort your list or parts of your list via MUIM_NListtree_Sort,
3373 * using the insert method with MUIV_NListtree_Insert_Sort or dropping an
3374 * entry on a closed node, this compare hook is called.
3376 * There are some builtin compare hooks available, called:
3378 * MUIV_NListtree_CompareHook_Head
3379 * Any entry is inserted at head of the list.
3381 * MUIV_NListtree_CompareHook_Tail
3382 * Any entry is inserted at tail of the list.
3384 * MUIV_NListtree_CompareHook_LeavesTop
3385 * Leaves are inserted at top of the list, nodes at bottom. They are
3386 * alphabetically sorted.
3388 * MUIV_NListtree_CompareHook_LeavesMixed
3389 * The entries are only alphabetically sorted.
3391 * MUIV_NListtree_CompareHook_LeavesBottom
3392 * Leaves are inserted at bottom of the list, nodes at top. They are
3393 * alphabetically sorted. This is default.
3395 * The hook will be called with the hook in A0, the object in A2 and
3396 * a MUIP_NListtree_CompareMessage struct in A1 (see nlisttree_mcc.h). You
3397 * should return something like:
3399 * <0 (TreeNode1 < TreeNode2)
3400 * 0 (TreeNode1 == TreeNode2)
3401 * >0 (TreeNode1 > TreeNode2)
3404 * NOTIFICATION
3407 * SEE ALSO
3409 * MUIA_NListtree_Insert, MUIM_DragDrop,
3410 * MUIA_NList_CompareHook
3413 ******************************************************************************
3417 /****** NListtree.mcc/MUIA_NListtree_ConstructHook ***************************
3419 * NAME
3421 * MUIA_NListtree_ConstructHook -- [IS.], struct Hook *
3424 * SPECIAL VALUES
3426 * MUIV_NListtree_ConstructHook_String
3428 * MUIV_NListtree_ConstructHook_Flag_AutoCreate
3429 * If using the KeepStructure feature in MUIM_NListtree_Move or
3430 * MUIM_NListtree_Copy, this flag will be set when calling your
3431 * construct hook. Then you can react if your hook is not simply
3432 * allocating memory.
3435 * FUNCTION
3437 * The construct hook is called whenever you add an entry to your
3438 * listtree. The pointer isn't inserted directly, the construct hook is
3439 * called and its result code is added.
3441 * When an entry shall be removed the corresponding destruct hook is
3442 * called.
3444 * The construct hook will be called with the hook in A0, the object in
3445 * A2 and a MUIP_NListtree_ConstructMessage struct in A1 (see
3446 * nlisttree_mcc.h).
3447 * The message holds a standard kick 3.x memory pool pointer. If you want,
3448 * you can use the exec or amiga.lib functions for allocating memory
3449 * within this pool, but this is only an option.
3451 * If the construct hook returns NULL, nothing will be added to the list.
3453 * There is a builtin construct hook available called
3454 * MUIV_NListtree_ConstructHook_String. This expects that the field
3455 * 'tn_User' in the treenode is a string pointer (STRPTR), which's
3456 * string is copied.
3457 * Of course you have to use MUIV_NListtree_DestructHook_String in
3458 * this case!
3460 * To remove the hook set this to NULL.
3462 * NEVER pass a NULL pointer when you have specified the internal string
3463 * construct/destruct hooks or NListtree will die!
3466 * NOTIFICATION
3469 * SEE ALSO
3471 * MUIA_NList_ConstructHook, MUIA_NListtree_DestructHook,
3472 * MUIA_NListtree_DisplayHook
3475 ******************************************************************************
3479 /****** NListtree.mcc/MUIA_NListtree_DestructHook ****************************
3481 * NAME
3483 * MUIA_NListtree_DestructHook -- [IS.], struct Hook *
3486 * SPECIAL VALUES
3488 * MUIV_NListtree_DestructHook_String
3491 * FUNCTION
3493 * Set up a destruct hook for your listtree. The destruct hook is called
3494 * whenevere you remove an entry from the listtree. Here you can free memory
3495 * which was allocated by the construct hook before.
3497 * The destruct hook will be called with the hook in A0, the object
3498 * in A2 and a MUIP_NListtree_DestructMessage struct in A1 (see
3499 * nlisttree_mcc.h).
3500 * The message holds a standard kick 3.x memory pool pointer. You must
3501 * use this pool when you have used it inside the construct hook to
3502 * allocate pooled memory.
3504 * There is a builtin destruct hook available called
3505 * MUIV_NListtree_DestructHook_String. This expects that the 'User' data
3506 * in the treenode is a string and you have used
3507 * MUIV_NListtree_ConstructHook_String in the construct hook!
3509 * To remove the hook set this to NULL.
3512 * NOTIFICATION
3515 * SEE ALSO
3517 * MUIA_NList_ConstructHook, MUIA_NListtree_ConstructHook,
3518 * MUIA_NListtree_DisplayHook
3521 ******************************************************************************
3525 /****** NListtree.mcc/MUIA_NListtree_DisplayHook *****************************
3527 * NAME
3529 * MUIA_NListtree_DisplayHook -- [IS.],
3532 * SPECIAL VALUES
3535 * FUNCTION
3537 * You have to supply a display hook to specify what should be shown in
3538 * the listview, otherwise only the name of the nodes is displayed.
3540 * The display hook will be called with the hook in A0, the object in
3541 * A2 and a MUIP_NListtree_DisplayMessage struct in A1 (see nlisttree_mcc.h).
3543 * The structure holds a pointer to a string array containing as many
3544 * entries as your listtree may have columns. You have to fill this
3545 * array with the strings you want to display. Check out that the array
3546 * pointer of the tree column is set to NULL, if the normal name of the
3547 * node should appear.
3548 * You can set a preparse string in Preparse for the corresponding col
3549 * element. Using it you'll be able to avoid copying the string in a
3550 * buffer to add something in the beginning of the col string.
3552 * The display hook also gets the position of the current entry as
3553 * additional parameter. It is stored in the longword preceding the col
3554 * array (don't forget it's a LONG).
3556 * You can set the array pointer of the tree column to a string, which is
3557 * diplayed instead of the node name. You can use this to mark nodes.
3559 * See MUIA_NList_Format for details about column handling.
3561 * To remove the hook and use the internal default display hook set this
3562 * to NULL.
3565 * NOTIFICATION
3568 * SEE ALSO
3570 * MUIA_NList_Format, MUIA_Text_Contents
3573 ******************************************************************************
3577 /****** NListtree.mcc/MUIA_NListtree_CopyToClipHook **************************
3579 * NAME
3581 * MUIA_NListtree_CopyToClipHook -- [IS.],
3584 * SPECIAL VALUES
3586 * MUIV_NListtree_CopyToClipHook_Default
3589 * FUNCTION
3591 * This thing works near like MUIA_NListtree_DisplayHook, but is
3592 * called when the NListtree object want to make a clipboard copy.
3594 * You can return only one string pointer. If you return NULL,
3595 * nothing will be copied. If you return -1, the entry will be
3596 * handled as a normal string and the name field is used.
3598 * The builtin hook skips all ESC sequences and adds a tab char
3599 * between columns.
3602 * NOTIFICATION
3605 * SEE ALSO
3607 * MUIM_NListtree_CopyToClip
3610 ******************************************************************************
3614 /****** NListtree.mcc/MUIA_NListtree_DoubleClick *****************************
3616 * NAME
3618 * MUIA_NListtree_DoubleClick -- [ISG], ULONG
3621 * SPECIAL VALUES
3623 * MUIV_NListtree_DoubleClick_Off
3624 * MUIV_NListtree_DoubleClick_All
3625 * MUIV_NListtree_DoubleClick_Tree
3626 * MUIV_NListtree_DoubleClick_NoTrigger
3629 * FUNCTION
3631 * A doubleclick opens a node if it was closed, it is closed if the node
3632 * was open. You have to set the column which should do this.
3634 * Normally only the column number is set here, but there are special
3635 * values:
3637 * MUIV_NListtree_DoubleClick_Off:
3638 * A doubleclick is not handled.
3640 * MUIV_NListtree_DoubleClick_All:
3641 * All columns react on doubleclick.
3643 * MUIV_NListtree_DoubleClick_Tree
3644 * Only a doubleclick on the defined tree column is recognized.
3646 * MUIV_NListtree_DoubleClick_NoTrigger:
3647 * A doubleclick is not handled and not triggered!
3650 * NOTIFICATION
3652 * The TriggerValue of the notification is the tree node you have double-
3653 * clicked, you can GetAttr() MUIA_NListtree_DoubleClick for the column
3654 * number. The struct 'MUI_NListtree_TreeNode *' is used for trigger.
3656 * The notification is done on leaves and on node columns, which are not
3657 * set in MUIA_NListtree_DoubleClick.
3659 * SEE ALSO
3662 ******************************************************************************
3666 /****** NListtree.mcc/MUIA_NListtree_DragDropSort ****************************
3668 * NAME
3670 * MUIA_NListtree_DragDropSort -- [IS.], BOOL
3673 * SPECIAL VALUES
3676 * FUNCTION
3678 * Setting this attribute to FALSE will disable the ability to sort the
3679 * list tree by drag & drop. Defaults to TRUE.
3682 * NOTIFICATION
3685 * SEE ALSO
3689 ******************************************************************************
3693 /****** NListtree.mcc/MUIA_NListtree_DupNodeName *****************************
3695 * NAME
3697 * MUIA_NListtree_DupNodeName -- [IS.], BOOL
3700 * SPECIAL VALUES
3703 * FUNCTION
3705 * If this attribute is set to FALSE the names of the node will not be
3706 * duplicated, only the string pointers are used. Be careful the strings
3707 * have to be valid everytime.
3710 * NOTIFICATION
3713 * SEE ALSO
3717 ******************************************************************************
3721 /****** NListtree.mcc/MUIA_NListtree_EmptyNodes ******************************
3723 * NAME
3725 * MUIA_NListtree_EmptyNodes -- [IS.], BOOL
3728 * SPECIAL VALUES
3731 * FUNCTION
3733 * Setting this attribute to TRUE will display all empty nodes as leaves,
3734 * this means no list indicator is shown. Nevertheless the entry is
3735 * handled like a node.
3738 * NOTIFICATION
3741 * SEE ALSO
3745 ******************************************************************************
3749 /****** NListtree.mcc/MUIA_NListtree_FindNameHook ****************************
3751 * NAME
3753 * MUIA_NListtree_FindNameHook -- [IS.],
3756 * SPECIAL VALUES
3758 * MUIV_NListtree_FindNameHook_CaseSensitive
3759 * Search for the complete string, case sensitive.
3761 * MUIV_NListtree_FindNameHook_CaseInsensitive
3762 * Search for the complete string, case insensitive.
3764 * MUIV_NListtree_FindNameHook_Part
3765 * Search for the first part of the string, case sensitive.
3767 * MUIV_NListtree_FindNameHook_PartCaseInsensitive
3768 * Search for the first part of the string, case insensitive.
3770 * MUIV_NListtree_FindNameHook_PointerCompare
3771 * Do only a pointer comparision. Note, that this is in fact
3772 * a pointer subtraction to fit into the rules. It returns
3773 * the difference of the two fields if no match.
3775 * FUNCTION
3777 * You can install a FindName hook to specify your own search
3778 * criteria.
3780 * The find name hook will be called with the hook in A0, the object in
3781 * A2 and a MUIP_NListtree_FindNameMessage struct in A1
3782 * (see nlisttree_mcc.h). It should return (ret != 0) for entries which
3783 * are not matching the pattern and a value of 0 if a match.
3785 * The find name message structure holds a pointer to a string
3786 * containing the name to search for and pointers to the name- and user-
3787 * field of the node which is currently processed.
3789 * The MUIV_NListtree_FindNameHook_CaseSensitive will be used as default.
3791 * NOTIFICATION
3794 * SEE ALSO
3796 * MUIM_NListtree_FindName, MUIM_NListtree_FindUserData,
3797 * MUIA_NListtree_FindUserDataHook
3799 ******************************************************************************
3803 /****** NListtree.mcc/MUIA_NListtree_FindUserDataHook ************************
3805 * NAME
3807 * MUIA_NListtree_FindUserDataHook -- [IS.],
3810 * SPECIAL VALUES
3812 * MUIV_NListtree_FindUserDataHook_CaseSensitive
3813 * Search for the complete string, case sensitive.
3815 * MUIV_NListtree_FindUserDataHook_CaseInsensitive
3816 * Search for the complete string, case insensitive.
3818 * MUIV_NListtree_FindUserDataHook_Part
3819 * Search for the first part of the string, case sensitive.
3821 * MUIV_NListtree_FindUserDataHook_PartCaseInsensitive
3822 * Search for the first part of the string, case insensitive.
3824 * MUIV_NListtree_FindUserDataHook_PointerCompare
3825 * Do only a pointer comparision. Note, that this is in fact
3826 * a pointer subtraction to fit into the rules. It returns
3827 * the difference of the two user fields if no match.
3830 * FUNCTION
3832 * You can install a FindUserData hook to specify your own search
3833 * criteria.
3835 * The find user data hook will be called with the hook in A0, the object
3836 * in A2 and a MUIP_NListtree_FindUserDataMessage struct in A1
3837 * (see nlisttree_mcc.h). It should return (ret != 0) for entries which
3838 * are not matching the pattern and a value of 0 if a match.
3840 * The find user data message structure holds a pointer to a string
3841 * containing the data to search for and pointers to the user- and name-
3842 * field of the node which is currently processed.
3844 * MUIV_NListtree_FindUserDataHook_CaseSensitive will be used as
3845 * default.
3847 * NOTIFICATION
3850 * SEE ALSO
3852 * MUIM_NListtree_FindName, MUIM_NListtree_FindUserData,
3853 * MUIA_NListtree_FindNameHook
3855 ******************************************************************************
3859 /****** NListtree.mcc/MUIA_NListtree_Format **********************************
3861 * NAME
3863 * MUIA_NListtree_Format -- [IS.], STRPTR
3866 * SPECIAL VALUES
3869 * FUNCTION
3871 * Same as MUIA_NList_Format, but one column is reserved for the tree
3872 * indicators and the names of the nodes.
3874 * For further detailed information see MUIA_NList_Format!
3877 * NOTIFICATION
3880 * SEE ALSO
3882 * MUIA_NList_Format, MUIA_NListtree_DisplayHook,
3883 * MUIA_Text_Contents
3886 ******************************************************************************
3890 /****** NListtree.mcc/MUIA_NListtree_MultiSelect *****************************
3892 * NAME
3894 * MUIA_NListtree_MultiSelect -- [I..],
3897 * SPECIAL VALUES
3899 * MUIV_NListtree_MultiSelect_None
3900 * MUIV_NListtree_MultiSelect_Default
3901 * MUIV_NListtree_MultiSelect_Shifted
3902 * MUIV_NListtree_MultiSelect_Always
3905 * FUNCTION
3907 * Four possibilities exist for a listviews multi select
3908 * capabilities:
3910 * MUIV_NListtree_MultiSelect_None:
3911 * The list tree cannot multiselect at all.
3913 * MUIV_NListtree_MultiSelect_Default:
3914 * The multi select type (with or without shift)
3915 * depends on the users preferences setting.
3917 * MUIV_NListtree_MultiSelect_Shifted:
3918 * Overrides the users prefs, multi selecting only
3919 * together with shift key.
3921 * MUIV_NListtree_MultiSelect_Always:
3922 * Overrides the users prefs, multi selecting
3923 * without shift key.
3926 * NOTIFICATION
3928 * NOTES
3930 * SEE ALSO
3932 * MUIA_NListtree_MultiTestHook, MUIM_NListtree_MultiSelect
3935 ******************************************************************************
3939 /****** NListtree.mcc/MUIA_NListtree_MultiTestHook ***************************
3941 * NAME
3943 * MUIA_NListtree_MultiTestHook -- [IS.], struct Hook *
3946 * SPECIAL VALUES
3949 * FUNCTION
3951 * If you plan to have a multi selecting list tree but not
3952 * all of your entries are actually multi selectable, you
3953 * can supply a MUIA_NListtree_MultiTestHook.
3955 * The multi test hook will be called with the hook in A0, the object
3956 * in A2 and a MUIP_NListtree_MultiTestMessage struct in A1 (see
3957 * nlisttree_mcc.h) and should return TRUE if the entry is multi
3958 * selectable, FALSE otherwise.
3960 * To remove the hook set this to NULL.
3963 * NOTIFICATION
3966 * SEE ALSO
3968 * MUIA_NListtree_ConstructHook, MUIA_NListtree_DestructHook
3971 ******************************************************************************
3975 /****** NListtree.mcc/MUIA_NListtree_OpenHook ********************************
3977 * NAME
3979 * MUIA_NListtree_OpenHook -- [IS.], struct Hook *
3982 * SPECIAL VALUES
3985 * FUNCTION
3987 * The open hook is called whenever a list node will be opened, so you
3988 * can change the list before the node is open.
3990 * The open hook will be called with the hook in A0, the object in A2
3991 * and a MUIP_NListtree_OpenMessage struct in A1 (see nlisttree_mcc.h).
3993 * To remove the hook set this to NULL.
3996 * NOTIFICATION
3999 * SEE ALSO
4001 * MUIA_NListtree_Open, MUIA_NListtree_CloseHook
4004 ******************************************************************************
4008 /****** NListtree.mcc/MUIA_NListtree_Quiet ***********************************
4010 * NAME
4012 * MUIA_NListtree_Quiet -- [.S.], QUIET
4015 * SPECIAL VALUES
4018 * FUNCTION
4020 * If you add/remove lots of entries to/from a listtree, this will cause
4021 * lots of screen action and slow down the operation. Setting
4022 * MUIA_NListtree_Quiet to TRUE will temporarily prevent the listtree from
4023 * being refreshed, this refresh will take place only once when you set
4024 * it back to FALSE again.
4026 * MUIA_NListtree_Quiet holds a nesting count to avoid trouble with
4027 * multiple setting/unsetting this attribute. You are encoraged to
4028 * always use TRUE/FALSE pairs here or you will went in trouble.
4030 * DO NOT USE MUIA_NList_Quiet here!
4033 * NOTIFICATION
4036 * SEE ALSO
4038 * MUIM_NListtree_Insert, MUIM_NListtree_Remove
4041 ******************************************************************************
4045 /****** NListtree.mcc/MUIA_NListtree_Title ***********************************
4047 * NAME
4049 * MUIA_NListtree_Title -- [IS.], BOOL
4052 * SPECIAL VALUES
4055 * FUNCTION
4057 * Specify a title for the current listtree.
4059 * For detailed information see MUIA_NList_Title!
4062 * NOTIFICATION
4065 * BUGS
4067 * The title should not be a string as for single column listviews. This
4068 * attribute can only be set to TRUE or FALSE.
4071 * SEE ALSO
4075 ******************************************************************************
4079 /****** NListtree.mcc/MUIA_NListtree_TreeColumn ******************************
4081 * NAME
4083 * MUIA_NListtree_TreeColumn -- [ISG], ULONG
4086 * SPECIAL VALUES
4088 * FUNCTION
4090 * Specify the column of the list tree, the node indicator and the name
4091 * of the node are displayed in.
4094 * NOTIFICATION
4097 * SEE ALSO
4099 * MUIA_NListtree_DisplayHook, MUIA_NListtree_Format
4102 ******************************************************************************
4106 /****** NListtree.mcc/MUIA_NListtree_ShowTree ********************************
4108 * NAME
4110 * MUIA_NListtree_ShowTree -- [ISG], ULONG
4113 * SPECIAL VALUES
4115 * FUNCTION
4117 * Specify FALSE here if you want the whole tree to be disappear.
4118 * Defaults to TRUE;
4120 * NOTIFICATION
4123 * SEE ALSO
4126 ******************************************************************************
4130 /****** NListtree.mcc/MUIA_NListtree_DropType ********************************
4132 * NAME
4134 * MUIA_NListtree_DropType -- [..G], ULONG
4137 * SPECIAL VALUES
4139 * MUIV_NListtree_DropType_None
4140 * MUIV_NListtree_DropType_Above
4141 * MUIV_NListtree_DropType_Below
4142 * MUIV_NListtree_DropType_Onto
4145 * FUNCTION
4147 * After a successful drop operation, this value holds the position
4148 * relative to the value of MUIA_NListtree_DropTarget/DropTargetPos.
4151 * NOTIFICATION
4154 * SEE ALSO
4156 * MUIA_NListtree_DropTarget, MUIA_NListtree_DropTargetPos
4159 ******************************************************************************
4163 /****** NListtree.mcc/MUIA_NListtree_DropTarget ******************************
4165 * NAME
4167 * MUIA_NListtree_DropTarget -- [..G], ULONG
4170 * SPECIAL VALUES
4172 * FUNCTION
4174 * After a successful drop operation, this value holds the entry where
4175 * the entry was dropped. The relative position (above etc.) can be
4176 * obtained by reading the attribute MUIA_NListtree_DropType.
4179 * NOTIFICATION
4182 * SEE ALSO
4184 * MUIA_NListtree_DropTargetPos, MUIA_NListtree_DropType
4187 ******************************************************************************
4191 /****** NListtree.mcc/MUIA_NListtree_DropTargetPos ***************************
4193 * NAME
4195 * MUIA_NListtree_DropTargetPos -- [..G], ULONG
4198 * SPECIAL VALUES
4200 * FUNCTION
4202 * After a successful drop operation, this value holds the integer
4203 * position of the entry where the dragged entry was dropped. The
4204 * entry itself can be obtained by reading MUIA_NListtree_DropTarget,
4205 * the relative position (above etc.) can be obtained by reading the
4206 * attribute MUIA_NListtree_DropType.
4209 * NOTIFICATION
4212 * SEE ALSO
4214 * MUIA_NListtree_DropTarget, MUIA_NListtree_DropType
4217 ******************************************************************************
4221 static VOID SetAttributes( struct NListtree_Data *data, struct opSet *msg, BOOL initial )
4223 struct MUI_NListtree_ListNode *actlist;
4224 struct MUI_NListtree_TreeNode *actnode;
4225 struct TagItem *tags, *tag;
4226 struct Hook *orgHook = NULL;
4227 BOOL intfunc, onlytrigger = FALSE;
4229 for(tags = msg->ops_AttrList; (tag = NextTagItem((APTR)&tags)); )
4231 intfunc = TRUE;
4233 switch( tag->ti_Tag )
4236 ** Configuration part.
4238 case MUIA_NListtree_IsMCP:
4239 SET_FLAG(data->Flags, NLTF_ISMCP);
4240 break;
4242 case MUICFG_NListtree_ImageSpecClosed:
4244 DisposeImage( data, IMAGE_Closed );
4245 SetupImage( data, (struct MUI_ImageSpec *)tag->ti_Data, IMAGE_Closed );
4246 DoRefresh( data );
4248 D(DBF_GETSET, "SET MUICFG_NListtree_ImageSpecClosed: '%s'", (STRPTR)tag->ti_Data);
4250 break;
4252 case MUICFG_NListtree_ImageSpecOpen:
4254 DisposeImage( data, IMAGE_Open );
4255 SetupImage( data, (struct MUI_ImageSpec *)tag->ti_Data, IMAGE_Open );
4256 DoRefresh( data );
4258 D(DBF_GETSET, "SET MUICFG_NListtree_ImageSpecOpen: '%s'", (STRPTR)tag->ti_Data);
4260 break;
4262 case MUICFG_NListtree_ImageSpecFolder:
4264 DisposeImage( data, IMAGE_Folder );
4265 SetupImage( data, (struct MUI_ImageSpec *)tag->ti_Data, IMAGE_Folder );
4266 DoRefresh( data );
4268 D(DBF_GETSET, "SET MUICFG_NListtree_ImageSpecFolder: '%s'", (STRPTR)tag->ti_Data);
4270 break;
4272 case MUICFG_NListtree_PenSpecLines:
4274 if( data->MRI )
4276 ObtPen( data->MRI, &data->Pen[PEN_Line], (struct MUI_PenSpec *)tag->ti_Data );
4277 DoRefresh( data );
4279 D(DBF_GETSET, "SET MUICFG_NListtree_PenSpecLines: %s", (STRPTR)tag->ti_Data);
4282 break;
4284 case MUICFG_NListtree_PenSpecShadow:
4286 if( data->MRI )
4288 ObtPen( data->MRI, &data->Pen[PEN_Shadow], (struct MUI_PenSpec *)tag->ti_Data );
4289 DoRefresh( data );
4291 D(DBF_GETSET, "SET MUICFG_NListtree_PenSpecShadow: %s", (STRPTR)tag->ti_Data);
4294 break;
4296 case MUICFG_NListtree_PenSpecGlow:
4298 if( data->MRI )
4300 ObtPen( data->MRI, &data->Pen[PEN_Glow], (struct MUI_PenSpec *)tag->ti_Data );
4301 DoRefresh( data );
4303 D(DBF_GETSET, "SET MUICFG_NListtree_PenSpecGlow: %s", (STRPTR)tag->ti_Data);
4306 break;
4308 case MUICFG_NListtree_IndentWidth:
4310 data->IndentWidth = (BYTE)tag->ti_Data;
4311 DoRefresh( data );
4313 D(DBF_GETSET, "SET MUICFG_NListtree_IndentWidth: %ld", tag->ti_Data);
4315 break;
4317 case MUICFG_NListtree_LineType:
4319 data->LineType = (ULONG)tag->ti_Data;
4320 DoRefresh( data );
4322 D(DBF_GETSET, "SET MUICFG_NListtree_LineType: %ld", tag->ti_Data);
4324 break;
4326 case MUICFG_NListtree_UseFolderImage:
4328 data->UseFolderImage = (BOOL)tag->ti_Data;
4329 DoRefresh(data);
4331 D(DBF_GETSET, "SET MUICFG_NListtree_UseFolderImage: %ld", tag->ti_Data);
4333 break;
4335 case MUICFG_NListtree_OpenAutoScroll:
4337 if ( (BOOL)tag->ti_Data )
4338 SET_FLAG(data->Flags, NLTF_OPENAUTOSCROLL);
4339 else
4340 CLEAR_FLAG(data->Flags, NLTF_OPENAUTOSCROLL);
4342 D(DBF_GETSET, "SET MUICFG_NListtree_OpenAutoScroll: %ld", tag->ti_Data);
4344 break;
4347 ** General part.
4349 case MUIA_NListtree_OnlyTrigger:
4351 onlytrigger = TRUE;
4352 D(DBF_GETSET, "SET MUIA_NListtree_OnlyTrigger");
4354 break;
4356 case MUIA_NList_Active:
4358 D(DBF_GETSET, "SET MUIA_NList_Active %ld%s",tag->ti_Data,isFlagSet(data->Flags, NLTF_ACTIVENOTIFY)?" notify activation set":"no notify set");
4360 break;
4362 case MUIA_NListtree_Active:
4364 D(DBF_GETSET, "SET MUIA_NListtree_Active");
4365 if((tag->ti_Data == (ULONG)MUIV_NListtree_Active_Off) ||
4366 (tag->ti_Data == (IPTR)&data->RootList) ||
4367 ((tag->ti_Data == (ULONG)MUIV_NListtree_Active_Parent) &&
4368 (data->ActiveNode == (ULONG)MUIV_NListtree_Active_Off))
4371 actnode = MUIV_NListtree_Active_Off;
4372 actlist = &data->RootList;
4374 else
4376 struct MUI_NListtree_TreeNode *tn;
4379 ** Parent of the active node.
4381 if(tag->ti_Data == (ULONG)MUIV_NListtree_Active_Parent)
4383 tag->ti_Data = (IPTR)GetParent( data->ActiveNode );
4387 ** First list entry (visible or not).
4389 if(tag->ti_Data == (ULONG)MUIV_NListtree_Active_First)
4390 tag->ti_Data = (IPTR)GetHead( (struct List *)&data->RootList.ln_List );
4393 ** First visible entry.
4395 if(tag->ti_Data == (ULONG)MUIV_NListtree_Active_FirstVisible)
4397 LONG firstvisible;
4399 firstvisible = xget( data->Obj, MUIA_NList_First );
4400 DoMethod( data->Obj, MUIM_NList_GetEntry, firstvisible, &tn );
4402 tag->ti_Data = (IPTR)tn;
4406 ** Last visible entry.
4408 if(tag->ti_Data == (ULONG)MUIV_NListtree_Active_LastVisible)
4410 LONG lastvisible;
4412 lastvisible = xget( data->Obj, MUIA_NList_First ) + xget( data->Obj, MUIA_NList_Visible ) - 1;
4413 DoMethod( data->Obj, MUIM_NList_GetEntry, lastvisible, &tn );
4415 tag->ti_Data = (IPTR)tn;
4418 if ( tag->ti_Data != (IPTR)&data->RootList )
4420 actnode = CTN( tag->ti_Data );
4421 actlist = CLN( GetParent( (CTN( tag->ti_Data) ) ) );
4422 } else
4424 /* Do nothing */
4425 return;
4430 ** With actnode and actlist we avoid ActiveNode ping-pong...
4432 if(!initial && (actnode != data->ActiveNode || isFlagSet(data->Flags, NLTF_SETACTIVE)))
4434 data->ActiveNode = actnode;
4435 data->ActiveNodeNum = xget( data->Obj, MUIA_NList_Active );
4438 if (!initial)
4441 ** For notification only.
4443 if (data->ActiveList != actlist)
4445 data->ActiveList = actlist;
4446 MakeNotify( data, MUIA_NListtree_ActiveList, actlist );
4451 if ( !onlytrigger )
4453 ActivateTreeNode( data, actnode );
4454 DoMethod( data->Obj, MUIM_NListtree_Active, data->ActiveNodeNum, data->ActiveNode );
4456 D(DBF_GETSET, "SET MUIA_NListtree_Active: %s - 0x%08lx - list: 0x%08lx rootlist: 0x%lx", actnode ? actnode->tn_Name : (STRPTR)"NULL", actnode, data->ActiveList, &data->RootList);
4458 else
4460 D(DBF_GETSET, "SET MUIA_NListtree_Active: TRIGGER: %s - 0x%08lx", actnode ? actnode->tn_Name : (STRPTR)"NULL", actnode);
4463 break;
4466 ** Dummy for notification.
4468 case MUIA_NListtree_ActiveList:
4469 D(DBF_GETSET, "SET MUIA_NListtree_ActiveList (dummy)");
4470 break;
4472 case MUIA_NListtree_AutoVisible:
4474 data->AutoVisible = (IPTR)tag->ti_Data;
4476 D(DBF_GETSET, "SET MUIA_NListtree_AutoVisible: %ld", tag->ti_Data);
4478 break;
4480 case MUIA_NListtree_CloseHook:
4482 data->CloseHook = (struct Hook *)tag->ti_Data;
4484 D(DBF_GETSET, "SET MUIA_NListtree_CloseHook: 0x%08lx", tag->ti_Data);
4486 break;
4488 case MUIA_NListtree_CompareHook:
4490 switch( tag->ti_Data )
4492 case MUIV_NListtree_CompareHook_Head:
4494 orgHook = &_CompareHook_Head;
4495 D(DBF_GETSET, "SET MUIA_NListtree_CompareHook: MUIV_NListtree_CompareHook_Head");
4497 break;
4499 case MUIV_NListtree_CompareHook_Tail:
4501 orgHook = &_CompareHook_Tail;
4502 D(DBF_GETSET, "SET MUIA_NListtree_CompareHook: MUIV_NListtree_CompareHook_Tail");
4504 break;
4506 case MUIV_NListtree_CompareHook_LeavesTop:
4508 orgHook = &_CompareHook_LeavesTop;
4509 D(DBF_GETSET, "SET MUIA_NListtree_CompareHook: MUIV_NListtree_CompareHook_LeavesTop");
4511 break;
4513 case MUIV_NListtree_CompareHook_LeavesMixed:
4515 orgHook = &_CompareHook_LeavesMixed;
4516 D(DBF_GETSET, "SET MUIA_NListtree_CompareHook: MUIV_NListtree_CompareHook_LeavesMixed");
4518 break;
4520 case MUIV_NListtree_CompareHook_LeavesBottom:
4522 orgHook = &_CompareHook_LeavesBottom;
4523 D(DBF_GETSET, "SET MUIA_NListtree_CompareHook: MUIV_NListtree_CompareHook_LeavesBottom");
4525 break;
4527 default:
4529 intfunc = FALSE;
4531 data->CompareHook = (struct Hook*)tag->ti_Data;
4533 D(DBF_GETSET, "SET MUIA_NListtree_CompareHook: 0x%08lx", tag->ti_Data);
4535 break;
4538 if(intfunc)
4540 /* The flags is quiet sensless because nobody asks for it expect in OM_NEW (which should be rewritten anywhy) */
4541 SET_FLAG(data->Flags, NLTF_INT_COMPAREHOOK);
4542 InitHook(&data->IntCompareHook, *orgHook, data);
4543 data->CompareHook = &data->IntCompareHook;
4545 else
4546 CLEAR_FLAG(data->Flags, NLTF_INT_COMPAREHOOK);
4548 break;
4550 case MUIA_NListtree_ConstructHook:
4553 ** If old hook is internal, remove complete
4554 ** hook with all memory allocated.
4556 if ( data->ConstructHook )
4558 if ( data->ConstructHook->h_Entry == (HOOKFUNC)_ConstructFunc )
4560 FreeVecPooled( data->MemoryPool, data->ConstructHook );
4561 data->ConstructHook = NULL;
4565 if(tag->ti_Data == (ULONG)MUIV_NListtree_ConstructHook_String)
4567 D(DBF_GETSET, "SET MUIA_NListtree_ConstructHook: MUIV_NListtree_ConstructHook_String");
4569 if((data->ConstructHook = AllocVecPooled(data->MemoryPool, sizeof(struct Hook))))
4571 SET_FLAG(data->Flags, NLTF_INT_CONSTRDESTRHOOK);
4573 InitHook(data->ConstructHook, _ConstructHook, data);
4575 else data->Error = TRUE;
4577 else
4579 data->ConstructHook = (struct Hook *)tag->ti_Data;
4581 D(DBF_GETSET, "SET MUIA_NListtree_ConstructHook: 0x%08lx", tag->ti_Data);
4584 break;
4586 case MUIA_NListtree_DestructHook:
4589 ** If old hook is internal, remove complete
4590 ** hook with all memory allocated.
4592 if ( data->DestructHook )
4594 if ( data->DestructHook->h_Entry == (HOOKFUNC)_DestructFunc )
4596 FreeVecPooled( data->MemoryPool, data->DestructHook );
4597 data->DestructHook = NULL;
4601 if(tag->ti_Data == (ULONG)MUIV_NListtree_DestructHook_String)
4603 D(DBF_GETSET, "SET MUIA_NListtree_DestructHook: MUIV_NListtree_DestructHook_String");
4605 if((data->DestructHook = AllocVecPooled(data->MemoryPool, sizeof(struct Hook))))
4607 SET_FLAG(data->Flags, NLTF_INT_CONSTRDESTRHOOK);
4609 InitHook(data->DestructHook, _DestructHook, data);
4611 else data->Error = TRUE;
4613 else
4615 data->DestructHook = (struct Hook *)tag->ti_Data;
4617 D(DBF_GETSET, "SET MUIA_NListtree_DestructHook: 0x%08lx", tag->ti_Data);
4620 break;
4622 case MUIA_NListtree_DisplayHook:
4624 if(tag->ti_Data != (ULONG)MUIV_NListtree_DisplayHook_Default)
4626 data->DisplayHook = (struct Hook *)tag->ti_Data;
4628 else
4629 data->DisplayHook = NULL;
4631 D(DBF_GETSET, "SET MUIA_NListtree_DisplayHook: 0x%08lx", tag->ti_Data);
4633 break;
4635 case MUIA_NListtree_CopyToClipHook:
4637 if ( tag->ti_Data == MUIV_NListtree_CopyToClipHook_Default )
4639 D(DBF_GETSET, "SET MUIA_NListtree_CopyToClipHook: MUIV_NListtree_CopyToClipHook_Default");
4641 data->CopyToClipHook = NULL;
4643 else
4645 data->CopyToClipHook = (struct Hook *)tag->ti_Data;
4647 D(DBF_GETSET, "SET MUIA_NListtree_CopyToClipHook: 0x%08lx", tag->ti_Data);
4650 break;
4652 case MUIA_NListtree_DoubleClick:
4654 if ( !onlytrigger )
4656 data->DoubleClick = (BYTE)tag->ti_Data;
4657 D(DBF_GETSET, "SET MUIA_NListtree_DoubleClick: 0x%08lx", tag->ti_Data);
4660 break;
4662 case MUIA_NListtree_DragDropSort:
4664 if ( (BOOL)tag->ti_Data )
4665 SET_FLAG(data->Flags, NLTF_DRAGDROPSORT);
4666 else
4667 CLEAR_FLAG(data->Flags, NLTF_DRAGDROPSORT);
4669 D(DBF_GETSET, "SET MUIA_NListtree_DragDropSort: %ld", tag->ti_Data);
4671 break;
4673 case MUIA_NListtree_DupNodeName:
4675 if ( (BOOL)tag->ti_Data )
4676 SET_FLAG(data->Flags, NLTF_DUPNODENAMES);
4677 else
4678 CLEAR_FLAG(data->Flags, NLTF_DUPNODENAMES);
4680 D(DBF_GETSET, "SET MUIA_NListtree_DupNodeName: %ld", tag->ti_Data);
4682 break;
4684 case MUIA_NListtree_EmptyNodes:
4686 if ( (BOOL)tag->ti_Data )
4687 SET_FLAG(data->Flags, NLTF_EMPTYNODES);
4688 else
4689 CLEAR_FLAG(data->Flags, NLTF_EMPTYNODES);
4691 if ( !initial )
4692 DoRefresh( data );
4694 D(DBF_GETSET, "SET MUIA_NListtree_EmptyNodes: %ld", tag->ti_Data);
4696 break;
4698 case MUIA_NListtree_FindNameHook:
4701 ** If old hook is internal, remove complete
4702 ** hook with all memory allocated.
4704 if ( data->FindNameHook )
4706 FreeVecPooled( data->MemoryPool, data->FindNameHook );
4707 data->FindNameHook = NULL;
4710 data->FindNameHook = AllocVecPooled( data->MemoryPool, sizeof( struct Hook ) );
4712 switch( tag->ti_Data )
4714 case MUIV_NListtree_FindNameHook_CaseSensitive:
4716 orgHook = &_FindNameHook_CaseSensitive;
4717 D(DBF_GETSET, "SET MUIA_NListtree_FindNameHook: MUIV_NListtree_FindNameHook_CaseSensitive");
4719 break;
4721 case MUIV_NListtree_FindNameHook_CaseInsensitive:
4723 orgHook = &_FindNameHook_CaseInsensitive;
4724 D(DBF_GETSET, "SET MUIA_NListtree_FindNameHook: MUIV_NListtree_FindNameHook_CaseInsensitive");
4726 break;
4728 case MUIV_NListtree_FindNameHook_Part:
4730 orgHook = &_FindNameHook_Part;
4731 D(DBF_GETSET, "SET MUIA_NListtree_FindNameHook: MUIV_NListtree_FindNameHook_Part");
4733 break;
4735 case MUIV_NListtree_FindNameHook_PartCaseInsensitive:
4737 orgHook = &_FindNameHook_PartCaseInsensitive;
4738 D(DBF_GETSET, "SET MUIA_NListtree_FindNameHook: MUIV_NListtree_FindNameHook_PartCaseInsensitive");
4740 break;
4742 case MUIV_NListtree_FindNameHook_PointerCompare:
4744 orgHook = &_FindNameHook_PointerCompare;
4745 D(DBF_GETSET, "SET MUIA_NListtree_FindNameHook: MUIV_NListtree_FindNameHook_PointerCompare");
4747 break;
4749 default:
4751 intfunc = FALSE;
4753 CopyMem( (APTR)tag->ti_Data, data->FindNameHook, sizeof( struct Hook ) );
4755 D(DBF_GETSET, "SET MUIA_NListtree_FindNameHook: 0x%08lx", tag->ti_Data);
4757 break;
4760 if(intfunc)
4762 InitHook(data->FindNameHook, *orgHook, data);
4765 break;
4767 case MUIA_NListtree_FindUserDataHook:
4770 ** If old hook is internal, remove complete
4771 ** hook with all memory allocated.
4773 if ( data->FindUserDataHook )
4775 FreeVecPooled( data->MemoryPool, data->FindUserDataHook );
4776 data->FindUserDataHook = NULL;
4779 data->FindUserDataHook = AllocVecPooled( data->MemoryPool, sizeof( struct Hook ) );
4781 switch( tag->ti_Data )
4783 case MUIV_NListtree_FindUserDataHook_CaseSensitive:
4785 orgHook = &_FindUserDataHook_CaseSensitive;
4786 D(DBF_GETSET, "SET MUIA_NListtree_FindUserDataHook: MUIV_NListtree_FindUserDataHook_CaseSensitive");
4788 break;
4790 case MUIV_NListtree_FindUserDataHook_CaseInsensitive:
4792 orgHook = &_FindUserDataHook_CaseInsensitive;
4793 D(DBF_GETSET, "SET MUIA_NListtree_FindUserDataHook: MUIV_NListtree_FindUserDataHook_CaseInsensitive");
4795 break;
4797 case MUIV_NListtree_FindUserDataHook_Part:
4799 orgHook = &_FindUserDataHook_Part;
4800 D(DBF_GETSET, "SET MUIA_NListtree_FindUserDataHook: MUIV_NListtree_FindUserDataHook_Part");
4802 break;
4804 case MUIV_NListtree_FindUserDataHook_PartCaseInsensitive:
4806 orgHook = &_FindUserDataHook_PartCaseInsensitive;
4807 D(DBF_GETSET, "SET MUIA_NListtree_FindUserDataHook: MUIV_NListtree_FindUserDataHook_PartCaseInsensitive");
4809 break;
4811 case MUIV_NListtree_FindUserDataHook_PointerCompare:
4813 orgHook = &_FindUserDataHook_PointerCompare;
4814 D(DBF_GETSET, "SET MUIA_NListtree_FindUserDataHook: MUIV_NListtree_FindUserDataHook_PointerCompare");
4816 break;
4818 default:
4820 intfunc = FALSE;
4822 CopyMem( (APTR)tag->ti_Data, data->FindUserDataHook, sizeof( struct Hook ) );
4824 D(DBF_GETSET, "SET MUIA_NListtree_FindUserDataHook: 0x%08lx", tag->ti_Data);
4826 break;
4829 if(intfunc)
4831 InitHook(data->FindUserDataHook, *orgHook, data);
4834 break;
4836 case MUIA_NListtree_Format:
4838 int len;
4841 ** If old data there, remove it.
4843 if ( data->Format )
4845 FreeVecPooled( data->MemoryPool, data->Format );
4846 data->Format = NULL;
4850 ** Save raw list format.
4852 len = strlen((STRPTR)tag->ti_Data) + 1;
4854 if((data->Format = AllocVecPooled( data->MemoryPool, len)))
4856 strlcpy( data->Format, (STRPTR)tag->ti_Data, len );
4858 if ( !initial )
4859 nnset( data->Obj, MUIA_NList_Format, data->Format );
4861 D(DBF_GETSET, "SET MUIA_NListtree_Format: %s", (STRPTR)tag->ti_Data);
4864 break;
4866 case MUIA_NListtree_MultiSelect:
4868 data->MultiSelect = (UBYTE)( tag->ti_Data & 0x00ff );
4871 if ( tag->ti_Data & MUIV_NListtree_MultiSelect_Flag_AutoSelectChilds )
4872 SET_FLAG(data->Flags, NLTF_AUTOSELECT_CHILDS);
4875 D(DBF_GETSET, "SET MUIA_NListtree_MultiSelect: 0x%08lx", tag->ti_Data);
4877 break;
4879 case MUIA_NListtree_MultiTestHook:
4881 data->MultiTestHook = (struct Hook *)tag->ti_Data;
4883 D(DBF_GETSET, "SET MUIA_NListtree_MultiTestHook: 0x%08lx", tag->ti_Data);
4885 break;
4887 case MUIA_NListtree_OpenHook:
4889 data->OpenHook = (struct Hook *)tag->ti_Data;
4891 D(DBF_GETSET, "SET MUIA_NListtree_OpenHook: 0x%08lx", tag->ti_Data);
4893 break;
4895 case MUIA_NListtree_Quiet:
4897 if ( !DoQuiet( data, (BOOL)tag->ti_Data ) )
4899 if(isFlagSet(data->Flags, NLTF_REFRESH))
4901 if(isFlagSet(data->Flags, NLTF_ISMCP))
4902 DoRefresh( data );
4904 CLEAR_FLAG(data->Flags, NLTF_REFRESH);
4908 D(DBF_GETSET, "SET MUIA_NListtree_Quiet: %ld - Counter = %ld", tag->ti_Data, data->QuietCounter);
4910 break;
4912 case MUICFG_NListtree_RememberStatus:
4914 if ( (BOOL)tag->ti_Data )
4915 SET_FLAG(data->Flags, NLTF_REMEMBER_STATUS);
4916 else
4917 CLEAR_FLAG(data->Flags, NLTF_REMEMBER_STATUS);
4919 D(DBF_GETSET, "SET MUICFG_NListtree_RememberStatus: %ld", tag->ti_Data);
4921 break;
4923 case MUIA_NListtree_Title:
4925 if ( tag->ti_Data )
4926 SET_FLAG(data->Flags, NLTF_TITLE);
4927 else
4928 CLEAR_FLAG(data->Flags, NLTF_TITLE);
4930 if ( !initial )
4931 nnset( data->Obj, MUIA_NList_Title, tag->ti_Data );
4933 D(DBF_GETSET, "SET MUIA_NListtree_Title: %ld", tag->ti_Data);
4935 break;
4937 case MUIA_NListtree_TreeColumn:
4939 data->TreeColumn = (UWORD)( tag->ti_Data & 0x00ff );
4941 if ( !initial )
4942 DoRefresh( data );
4944 D(DBF_GETSET, "SET MUIA_NListtree_TreeColumn: 0x%08lx", tag->ti_Data);
4946 break;
4948 case MUIA_NListtree_ShowTree:
4950 if(tag->ti_Data == (ULONG)MUIV_NListtree_ShowTree_Toggle)
4952 if(isFlagSet(data->Flags, NLTF_NO_TREE))
4953 CLEAR_FLAG(data->Flags, NLTF_NO_TREE);
4954 else
4955 SET_FLAG(data->Flags, NLTF_NO_TREE);
4957 else if ( !tag->ti_Data )
4958 SET_FLAG(data->Flags, NLTF_NO_TREE);
4959 else
4960 CLEAR_FLAG(data->Flags, NLTF_NO_TREE);
4962 if ( !initial )
4963 DoRefresh( data );
4965 D(DBF_GETSET, "SET MUIA_NListtree_ShowTree: 0x%08lx", tag->ti_Data);
4967 break;
4969 case MUIA_NListtree_NoRootTree:
4972 ** data->MRI is set in _Setup(). This makes sure, this tag is only
4973 ** used in the initial configuration.
4975 if ( tag->ti_Data && !data->MRI )
4977 SET_FLAG(data->Flags, NLTF_NO_ROOT_TREE);
4980 break;
4982 default:
4983 D(DBF_GETSET, "SET attribute 0x%08lx to 0x%08lx", tag->ti_Tag, tag->ti_Data);
4984 break;
4990 static BOOL GetAttributes( struct NListtree_Data *data, Msg msg)
4992 IPTR *store = ( (struct opGet *)msg)->opg_Storage;
4994 *store = 0;
4996 switch( ( (struct opGet *)msg)->opg_AttrID )
4998 case MUIA_Version:
4999 *store = LIB_VERSION;
5000 return( TRUE );
5002 case MUIA_Revision:
5003 *store = LIB_REVISION;
5004 return( TRUE );
5006 case MUIA_NListtree_Active:
5008 *store = (IPTR)data->ActiveNode;
5009 D(DBF_GETSET, "GET MUIA_NListtree_Active: 0x%08lx", *store);
5010 return( TRUE );
5012 case MUIA_NListtree_ActiveList:
5014 if ( data->ActiveList == &data->RootList )
5015 *store = (IPTR)MUIV_NListtree_ActiveList_Off;
5016 else
5017 *store = (IPTR)data->ActiveList;
5018 D(DBF_GETSET, "GET MUIA_NListtree_ActiveList: 0x%08lx",*store);
5019 return( TRUE );
5021 case MUIA_NListtree_DoubleClick:
5023 *store = (IPTR)data->LDClickColumn;
5024 D(DBF_GETSET, "GET MUIA_NListtree_DoubleClick: 0x%08lx", *store);
5025 return( TRUE );
5027 case MUIA_NListtree_TreeColumn:
5029 *store = (IPTR)data->TreeColumn;
5030 D(DBF_GETSET, "GET MUIA_NListtree_TreeColumn: 0x%08lx", *store);
5031 return( TRUE );
5033 case MUIA_NListtree_ShowTree:
5035 *store = (IPTR)isFlagClear(data->Flags, NLTF_NO_TREE);
5036 D(DBF_GETSET, "GET MUIA_NListtree_ShowTree: 0x%08lx", *store);
5037 return( TRUE );
5039 case MUIA_NListtree_AutoVisible:
5041 *store = (IPTR)data->AutoVisible;
5042 D(DBF_GETSET, "GET MUIA_NListtree_AutoVisible: 0x%08lx", *store);
5043 return( TRUE );
5045 case MUIA_NListtree_DropType:
5047 *store = (IPTR)data->DropType;
5048 return( TRUE );
5050 case MUIA_NListtree_DropTarget:
5052 *store = (IPTR)data->DropTarget;
5053 return( TRUE );
5055 case MUIA_NListtree_DropTargetPos:
5057 *store = (IPTR)data->DropTargetPos;
5058 return( TRUE );
5060 case MUIA_NListtree_SelectChange:
5062 D(DBF_GETSET, "GET MUIA_NListtree_SelectChange");
5063 return( TRUE );
5066 ** We ignore these tags ;-)
5068 case MUIA_NList_CompareHook:
5069 case MUIA_NList_ConstructHook:
5070 case MUIA_NList_DestructHook:
5071 case MUIA_NList_DisplayHook:
5072 case MUIA_NList_DragSortable:
5073 case MUIA_NList_DropMark:
5074 case MUIA_NList_Format:
5075 case MUIA_NList_MinLineHeight:
5076 case MUIA_NList_MultiTestHook:
5077 case MUIA_NList_Pool:
5078 case MUIA_NList_PoolPuddleSize:
5079 case MUIA_NList_PoolThreshSize:
5080 case MUIA_NList_ShowDropMarks:
5081 case MUIA_NList_SourceArray:
5082 case MUIA_NList_Title:
5083 return( FALSE );
5084 break;
5086 default:
5087 D(DBF_GETSET, "GET 0x%08lx", ( (struct opGet *)msg)->opg_AttrID);
5088 break;
5091 return( FALSE );
5096 /*****************************************************************************\
5097 *******************************************************************************
5099 ** Standard class related functions.
5101 *******************************************************************************
5102 \*****************************************************************************/
5104 IPTR _New(struct IClass *cl, Object *obj, struct opSet *msg)
5106 struct NListtree_Data ld;
5108 memset(&ld, 0, sizeof(struct NListtree_Data));
5111 ** Create new memory pool.
5113 #if defined(__amigaos4__)
5114 ld.MemoryPool = AllocSysObjectTags(ASOT_MEMPOOL, ASOPOOL_MFlags, MEMF_SHARED|MEMF_CLEAR,
5115 ASOPOOL_Puddle, 16384,
5116 ASOPOOL_Threshold, 8192,
5117 ASOPOOL_Name, "NListtree.mcc pool",
5118 ASOPOOL_LockMem, FALSE,
5119 TAG_DONE);
5120 #else
5121 ld.MemoryPool = CreatePool(MEMF_CLEAR, 16384, 8192);
5122 #endif
5123 if(ld.MemoryPool != NULL)
5125 #if defined(__amigaos4__)
5126 ld.TreePool = AllocSysObjectTags(ASOT_MEMPOOL, ASOPOOL_MFlags, MEMF_SHARED|MEMF_CLEAR,
5127 ASOPOOL_Puddle, 16384,
5128 ASOPOOL_Threshold, 4096,
5129 ASOPOOL_Name, "NListtree.mcc tree pool",
5130 ASOPOOL_LockMem, FALSE,
5131 TAG_DONE);
5132 #else
5133 ld.TreePool = CreatePool(MEMF_CLEAR, 16384, 4096);
5134 #endif
5135 if(ld.TreePool != NULL)
5137 ld.Format = NULL;
5138 ld.ActiveNode = CTN( MUIV_NListtree_Active_Off );
5139 ld.DoubleClick = MUIV_NListtree_DoubleClick_All;
5143 ** Default values!!!
5145 SET_FLAG(ld.Flags, NLTF_DUPNODENAMES);
5146 SET_FLAG(ld.Flags, NLTF_OPENAUTOSCROLL);
5147 SET_FLAG(ld.Flags, NLTF_DRAGDROPSORT);
5148 ld.AutoVisible = MUIV_NListtree_AutoVisible_Normal;
5150 /* data will be set below because we don't have the correct address yet...somebody really should rewrite this */
5151 InitHook(&ld.IntCompareHook, _CompareHook_LeavesBottom, NULL);
5153 SET_FLAG(ld.Flags, NLTF_INT_COMPAREHOOK);
5155 SetAttributes( &ld, msg, TRUE );
5158 ** If all hooks successfully installed, set up
5159 ** the class for use.
5162 ** Finally create the superclass.
5164 obj = (Object *)DoSuperNew( cl, obj,
5165 //$$$ MUIA_Listview_Input
5166 MUIA_NList_Input, TRUE,
5167 //$$$ MUIA_Listview_MultiSelect
5168 MUIA_NList_MultiSelect, ld.MultiSelect,
5169 ( ld.MultiSelect != 0 ) ? MUIA_NList_MultiTestHook : TAG_IGNORE, &NList_MultiTestHook,
5170 //$$$ MUIA_Listview_DragType
5171 MUIA_NList_DragType, isFlagSet(ld.Flags, NLTF_DRAGDROPSORT) ? MUIV_NList_DragType_Default : MUIV_NList_DragType_None,
5172 MUIA_NList_DragSortable, isFlagSet(ld.Flags, NLTF_DRAGDROPSORT) ? TRUE : FALSE,
5173 MUIA_NList_ShowDropMarks, isFlagSet(ld.Flags, NLTF_DRAGDROPSORT) ? TRUE : FALSE,
5174 //$$$ Remove
5175 MUIA_NList_EntryValueDependent, TRUE,
5176 isFlagSet(ld.Flags, NLTF_TITLE) ? MUIA_NList_Title : TAG_IGNORE, TRUE,
5177 ld.Format ? MUIA_NList_Format : TAG_IGNORE, ld.Format,
5178 //$$$ Not implemented
5179 MUIA_ContextMenu, MUIV_NList_ContextMenu_Always,
5180 TAG_MORE, msg->ops_AttrList );
5182 if ( obj )
5184 struct NListtree_Data *data = INST_DATA(cl, obj);
5185 struct Task *mytask;
5186 const char *taskname;
5187 IPTR ver=0, rev=0;
5189 CopyMem( &ld, data, sizeof( struct NListtree_Data ) );
5191 data->IntCompareHook.h_Data = data; /* now we have the correct address of data */
5193 if(isFlagSet(data->Flags, NLTF_INT_COMPAREHOOK))
5194 data->CompareHook = &data->IntCompareHook; /* and now we also have the correct address of the hook */
5196 DoSuperMethod(cl, obj, OM_GET, MUIA_Version, &ver);
5197 DoSuperMethod(cl, obj, OM_GET, MUIA_Revision, &rev);
5199 D(DBF_ALWAYS, "NList version: %ld.%ld", ver, rev);
5201 mytask = FindTask( NULL );
5203 if ( mytask->tc_Node.ln_Name )
5204 taskname = mytask->tc_Node.ln_Name;
5205 else
5206 taskname = "MUI Application";
5208 if ( ( ver < 20 ) || ( ( ver == 20 ) && ( rev < 130 ) ) )
5210 struct EasyStruct es;
5212 memset(&es,0,sizeof(es));
5213 es.es_StructSize = sizeof(struct EasyStruct);
5214 es.es_Title = (STRPTR)"Update information...";
5215 es.es_TextFormat = (STRPTR)"NListtree.mcc has detected that your version of\n"
5216 "NList.mcc which is used by task `%s'\n"
5217 "is outdated (V%ld.%ld). Please update at least to\n"
5218 "version 20.130, which is available at\n\n"
5219 "http://www.sf.net/projects/nlist-classes\n\n"
5220 "NListtree will terminate now to avoid problems...\n";
5221 es.es_GadgetFormat = (STRPTR)"Terminate";
5223 EasyRequest( NULL, &es, NULL, (IPTR)taskname, ver, rev );
5225 //CoerceMethod( cl, obj, OM_DISPOSE );
5226 return( 0 );
5229 SET_FLAG(data->Flags, NLTF_NLIST_DIRECT_ENTRY_SUPPORT);
5232 ** Save instance data in private NList data field.
5234 set( obj, MUIA_UserData, data );
5237 ** Instance data is now valid. Here we set
5238 ** up the default hooks.
5240 if(!data->FindNameHook)
5242 data->FindNameHook = AllocVecPooled( data->MemoryPool, sizeof( struct Hook ) );
5244 InitHook(data->FindNameHook, _FindNameHook_CaseInsensitive, data);
5247 if ( !data->FindUserDataHook )
5249 data->FindUserDataHook = AllocVecPooled( data->MemoryPool, sizeof( struct Hook ) );
5251 InitHook(data->FindUserDataHook, _FindUserDataHook_CaseInsensitive, data);
5254 data->buf = AllocVecPooled( data->MemoryPool, DATA_BUF_SIZE );
5255 data->Obj = obj;
5258 ** Here we initialize the root list and setting
5259 ** some important values to it.
5261 NewList( (struct List *)&data->RootList.ln_List );
5263 data->RootList.ln_Parent = NULL;
5264 SET_FLAG(data->RootList.ln_Flags, TNF_LIST);
5265 SET_FLAG(data->RootList.ln_Flags, TNF_OPEN);
5266 SET_FLAG(data->RootList.ln_IFlags, TNIF_VISIBLE);
5267 SET_FLAG(data->RootList.ln_IFlags, TNIF_ROOT);
5269 // Initialize Selected-Table.
5270 data->SelectedTable.tb_Current = -2;
5272 // check if removing MUI notifies is safe
5273 #if defined(__amigaos3__) || defined(__amigaos4__)
5274 if(LIB_VERSION_IS_AT_LEAST(MUIMasterBase, 20, 5824))
5276 // MUI4 for AmigaOS is safe for V20.5824+
5277 SET_FLAG(data->Flags, NLTF_SAFE_NOTIFIES);
5279 else if(LIB_VERSION_IS_AT_LEAST(MUIMasterBase, 20, 2346) && LIBREV(MUIMasterBase) < 5000)
5281 // MUI3.9 for AmigaOS is safe for V20.2346+
5282 SET_FLAG(data->Flags, NLTF_SAFE_NOTIFIES);
5284 else
5286 // MUI 3.8 and older version of MUI 3.9 or MUI4 are definitely unsafe
5287 CLEAR_FLAG(data->Flags, NLTF_SAFE_NOTIFIES);
5289 #else
5290 // MorphOS and AROS must be considered unsafe unless someone from the
5291 // MorphOS/AROS team confirms that removing notifies in nested OM_SET
5292 // calls is safe.
5293 CLEAR_FLAG(data->Flags, NLTF_SAFE_NOTIFIES);
5294 #endif
5296 // Setup spacial image class and tree image.
5297 if((data->CL_TreeImage = MUI_CreateCustomClass(NULL, (STRPTR)MUIC_Area, NULL, sizeof(struct TreeImage_Data ), ENTRY(TreeImage_Dispatcher))))
5299 if((data->CL_NodeImage = MUI_CreateCustomClass(NULL, (STRPTR)MUIC_Image, NULL, sizeof(struct TreeImage_Data), ENTRY(NodeImage_Dispatcher))))
5301 ActivateNotify( data );
5303 return( (IPTR)obj );
5310 CoerceMethod( cl, obj, OM_DISPOSE );
5312 return( 0 );
5316 IPTR _Dispose(struct IClass *cl, Object *obj, Msg msg)
5318 struct NListtree_Data *data = INST_DATA(cl, obj);
5319 ULONG ret;
5320 struct MUI_CustomClass *im1, *im2;
5321 APTR mempool, treepool;
5323 ENTER();
5326 ** Clear complete list without setting a new active entry.
5328 DoMethod( obj, MUIM_NListtree_Clear, NULL, 0 );
5330 im1 = data->CL_TreeImage;
5331 im2 = data->CL_NodeImage;
5332 mempool = data->MemoryPool;
5333 treepool = data->TreePool;
5335 ret = DoSuperMethodA(cl, obj, msg);
5337 if(treepool != NULL)
5339 #if defined(__amigaos4__)
5340 FreeSysObject(ASOT_MEMPOOL, treepool);
5341 #else
5342 DeletePool(treepool);
5343 #endif
5346 if(mempool != NULL)
5348 #if defined(__amigaos4__)
5349 FreeSysObject(ASOT_MEMPOOL, mempool);
5350 #else
5351 DeletePool(mempool);
5352 #endif
5356 ** Delete special image classes.
5358 if ( im1 )
5359 MUI_DeleteCustomClass( im1 );
5361 if ( im2 )
5362 MUI_DeleteCustomClass( im2 );
5364 RETURN(ret);
5365 return( ret );
5370 IPTR _Set(struct IClass *cl, Object *obj, struct opSet *msg)
5372 struct NListtree_Data *data = INST_DATA(cl, obj);
5374 SetAttributes(data, msg, FALSE);
5376 return DoSuperMethodA(cl, obj, (Msg)msg);
5380 IPTR _Get(struct IClass *cl, Object *obj, Msg msg)
5382 struct NListtree_Data *data = INST_DATA(cl, obj);
5384 if(GetAttributes(data, msg) == TRUE)
5385 return TRUE;
5387 return DoSuperMethodA(cl, obj, msg);
5391 IPTR _Setup(struct IClass *cl, Object *obj, struct MUIP_Setup *msg)
5393 struct NListtree_Data *data = INST_DATA(cl, obj);
5394 Object *pdobj, *idobj;
5395 SIPTR d;
5396 BOOL x;
5398 ENTER();
5400 if(!(DoSuperMethodA(cl, obj, (Msg)msg)))
5402 RETURN(FALSE);
5403 return FALSE;
5406 D(DBF_SETUP, "Before: cl_SubclassCount = %ld, cl_ObjectCount = %ld", cl->cl_SubclassCount, cl->cl_ObjectCount);
5409 ** Obtain pens (render info is valid after Setup()!
5411 data->MRI = msg->RenderInfo;
5415 ** These values are used for drawing the lines.
5417 data->Image[IMAGE_Tree].nltdata = data;
5418 data->Image[IMAGE_Tree].Image = NewObject( data->CL_TreeImage->mcc_Class, NULL, MUIA_FillArea, FALSE,
5419 MUIA_Frame, MUIV_Frame_None,
5420 MUIA_UserData, &data->Image[IMAGE_Tree],
5421 MUIA_InnerBottom, 0,
5422 MUIA_InnerLeft, 0,
5423 MUIA_InnerRight, 0,
5424 MUIA_InnerTop, 0,
5425 MUIA_Weight, 0,
5426 TAG_DONE);
5427 data->Image[IMAGE_Tree].ListImage = (Object *)DoMethod( obj, MUIM_NList_CreateImage, data->Image[IMAGE_Tree].Image, 0L );
5429 data->compositingActive = 0;
5430 #if defined(__amigaos4__)
5431 // check whether compositing is enabled on our screen
5432 GetScreenAttrs(_screen(obj), SA_Compositing, &data->compositingActive, TAG_DONE);
5433 #endif
5436 ** Get and set image config.
5438 if(isFlagClear(data->Flags, NLTF_ISMCP))
5441 ** Set up temporary objects.
5443 pdobj = MUI_NewObject( MUIC_Pendisplay, TAG_DONE );
5444 idobj = MUI_NewObject( MUIC_Imagedisplay, TAG_DONE );
5447 if ( DoMethod( obj, MUIM_GetConfigItem, MUICFG_NListtree_ImageSpecClosed, &d ) )
5449 SetupImage( data, (struct MUI_ImageSpec *)d, IMAGE_Closed );
5451 D(DBF_SETUP, "C-Closed node image: '%s'", (STRPTR)d);
5453 else if ( idobj )
5455 set( idobj, MUIA_Imagedisplay_Spec, MUICFGV_NListtree_ImageSpecClosed_Default );
5456 d = xget( idobj, MUIA_Imagedisplay_Spec );
5458 SetupImage( data, (struct MUI_ImageSpec *)d, IMAGE_Closed );
5460 D(DBF_SETUP, "Closed node image: '%s'", (STRPTR)d);
5464 if ( DoMethod( obj, MUIM_GetConfigItem, MUICFG_NListtree_ImageSpecOpen, &d ) )
5466 SetupImage( data, (struct MUI_ImageSpec *)d, IMAGE_Open );
5468 D(DBF_SETUP, "C-Open node image: '%s'", (STRPTR)d);
5470 else if ( idobj )
5472 set( idobj, MUIA_Imagedisplay_Spec, MUICFGV_NListtree_ImageSpecOpen_Default );
5473 d = xget( idobj, MUIA_Imagedisplay_Spec );
5475 SetupImage( data, (struct MUI_ImageSpec *)d, IMAGE_Open );
5477 D(DBF_SETUP, "Open node image: '%s'", (STRPTR)d);
5481 if ( DoMethod( obj, MUIM_GetConfigItem, MUICFG_NListtree_ImageSpecFolder, &d ) )
5483 SetupImage( data, (struct MUI_ImageSpec *)d, IMAGE_Folder );
5485 D(DBF_SETUP, "C-Folder image: '%s'", (STRPTR)d);
5487 else if ( idobj )
5489 set( idobj, MUIA_Imagedisplay_Spec, MUICFGV_NListtree_ImageSpecFolder_Default );
5490 d = xget( idobj, MUIA_Imagedisplay_Spec );
5492 SetupImage( data, (struct MUI_ImageSpec *)d, IMAGE_Folder );
5494 D(DBF_SETUP, "Folder image: '%s'", (STRPTR)d);
5498 ** Get and set line, shadow and draw pens
5500 if ( DoMethod( obj, MUIM_GetConfigItem, MUICFG_NListtree_PenSpecLines, &d ) )
5501 ObtPen( data->MRI, &data->Pen[PEN_Line], (struct MUI_PenSpec *)d );
5502 else if( pdobj )
5504 DoMethod( pdobj, MUIM_Pendisplay_SetMUIPen, MUICFGV_NListtree_PenSpecLines_Default );
5505 ObtPen( data->MRI, &data->Pen[PEN_Line], (struct MUI_PenSpec *)xget( pdobj, MUIA_Pendisplay_Spec ) );
5509 if ( DoMethod( obj, MUIM_GetConfigItem, MUICFG_NListtree_PenSpecShadow, &d ) )
5510 ObtPen( data->MRI, &data->Pen[PEN_Shadow], (struct MUI_PenSpec *)d );
5511 else if( pdobj )
5513 DoMethod( pdobj, MUIM_Pendisplay_SetMUIPen, MUICFGV_NListtree_PenSpecShadow_Default );
5514 ObtPen( data->MRI, &data->Pen[PEN_Shadow], (struct MUI_PenSpec *)xget( pdobj, MUIA_Pendisplay_Spec ) );
5518 if ( DoMethod( obj, MUIM_GetConfigItem, MUICFG_NListtree_PenSpecGlow, &d ) )
5519 ObtPen( data->MRI, &data->Pen[PEN_Glow], (struct MUI_PenSpec *)d );
5520 else if( pdobj )
5522 DoMethod( pdobj, MUIM_Pendisplay_SetMUIPen, MUICFGV_NListtree_PenSpecGlow_Default );
5523 ObtPen( data->MRI, &data->Pen[PEN_Glow], (struct MUI_PenSpec *)xget( pdobj, MUIA_Pendisplay_Spec ) );
5528 ** Set values
5530 if ( DoMethod( obj, MUIM_GetConfigItem, MUICFG_NListtree_LineType, &d ) )
5531 data->LineType = atoi( (STRPTR)d );
5532 else
5533 data->LineType = MUICFGV_NListtree_LineType_Default;
5536 if ( DoMethod( obj, MUIM_GetConfigItem, MUICFG_NListtree_IndentWidth, &d ) )
5537 data->IndentWidth = atoi( (STRPTR)d );
5538 else
5539 data->IndentWidth = MUICFGV_NListtree_IndentWidth_Default;
5541 if ( DoMethod( obj, MUIM_GetConfigItem, MUICFG_NListtree_RememberStatus, &d ) )
5542 x = atoi( (STRPTR)d );
5543 else
5544 x = MUICFGV_NListtree_RememberStatus_Default;
5546 if ( x )
5547 SET_FLAG(data->Flags, NLTF_REMEMBER_STATUS);
5548 else
5549 CLEAR_FLAG(data->Flags, NLTF_REMEMBER_STATUS);
5552 if ( DoMethod( obj, MUIM_GetConfigItem, MUICFG_NListtree_OpenAutoScroll, &d ) )
5553 x = atoi( (STRPTR)d );
5554 else
5555 x = MUICFGV_NListtree_OpenAutoScroll_Default;
5557 if ( x )
5558 SET_FLAG(data->Flags, NLTF_OPENAUTOSCROLL);
5559 else
5560 CLEAR_FLAG(data->Flags, NLTF_OPENAUTOSCROLL);
5562 if ( DoMethod( obj, MUIM_GetConfigItem, MUICFG_NListtree_UseFolderImage, &d ) )
5563 data->UseFolderImage = atoi( (STRPTR)d );
5564 else
5565 data->UseFolderImage = MUICFGV_NListtree_UseFolderImage_Default;
5569 ** Dispose temporary created objects.
5571 if( pdobj )
5572 MUI_DisposeObject( pdobj );
5574 if ( idobj )
5575 MUI_DisposeObject( idobj );
5579 D(DBF_SETUP, "After: cl_SubclassCount = %ld, cl_ObjectCount = %ld", cl->cl_SubclassCount, cl->cl_ObjectCount);
5581 DoRefresh( data );
5583 RETURN(TRUE);
5584 return TRUE;
5588 IPTR _Cleanup(struct IClass *cl, Object *obj, Msg msg)
5590 struct NListtree_Data *data = INST_DATA(cl, obj);
5591 UBYTE i;
5593 D(DBF_SETUP, "Before: cl_SubclassCount = %ld, cl_ObjectCount = %ld", cl->cl_SubclassCount, cl->cl_ObjectCount);
5596 ** Dispose images.
5598 for( i = 0; i < 4; i++ )
5599 DisposeImage( data, i );
5601 RelPen( data->MRI, &data->Pen[PEN_Line] );
5602 RelPen( data->MRI, &data->Pen[PEN_Shadow] );
5603 RelPen( data->MRI, &data->Pen[PEN_Glow] );
5605 data->MRI = NULL;
5607 D(DBF_SETUP, "After: cl_SubclassCount = %ld, cl_ObjectCount = %ld", cl->cl_SubclassCount, cl->cl_ObjectCount);
5609 return( DoSuperMethodA( cl, obj, msg) );
5613 IPTR _Show(struct IClass *cl, Object *obj, Msg msg)
5615 struct NListtree_Data *data = INST_DATA(cl, obj);
5617 if (!DoSuperMethodA( cl, obj, (Msg)msg))
5618 return 0;
5620 data->EHNode.ehn_Priority = 2;
5621 data->EHNode.ehn_Flags = 0;
5622 data->EHNode.ehn_Object = obj;
5623 data->EHNode.ehn_Class = cl;
5624 data->EHNode.ehn_Events = IDCMP_MOUSEBUTTONS | IDCMP_RAWKEY;
5625 DoMethod( _win( obj ), MUIM_Window_AddEventHandler, &data->EHNode );
5627 return 1;
5631 IPTR _Hide(struct IClass *cl, Object *obj, Msg msg)
5633 struct NListtree_Data *data = INST_DATA(cl, obj);
5635 DoMethod( _win( obj ), MUIM_Window_RemEventHandler, &data->EHNode );
5637 return DoSuperMethodA(cl, obj, msg);
5641 IPTR _AskMinMax(struct IClass *cl, Object *obj, struct MUIP_AskMinMax *msg)
5643 DoSuperMethodA( cl, obj, (Msg)msg);
5645 msg->MinMaxInfo->MinWidth += 20;
5646 msg->MinMaxInfo->DefWidth += 50;
5647 msg->MinMaxInfo->MaxWidth += MUI_MAXMAX;
5649 msg->MinMaxInfo->MinHeight += 20;
5650 msg->MinMaxInfo->DefHeight += 50;
5651 msg->MinMaxInfo->MaxHeight += MUI_MAXMAX;
5653 return( 0 );
5658 IPTR _Draw(struct IClass *cl, Object *obj, struct MUIP_Draw *msg)
5660 return( DoSuperMethodA( cl, obj, (Msg)msg) );
5664 IPTR _HandleEvent(struct IClass *cl, Object *obj, struct MUIP_HandleEvent *msg)
5666 #define _between( a, x, b ) ( ( x ) >= ( a ) && ( x ) <= ( b ) )
5667 #define _isinobject( x, y ) ( _between( _mleft( obj ), ( x ), _mright( obj ) ) && _between( _mtop( obj ), ( y ), _mbottom( obj ) ) )
5668 struct NListtree_Data *data = INST_DATA(cl, obj);
5669 IPTR ret = 0;
5671 if ( msg->muikey )
5673 struct MUI_NListtree_TreeNode *tn;
5675 switch ( msg->muikey )
5677 case MUIKEY_LEFT:
5679 BOOL changed = FALSE;
5681 if ( data->ActiveNode )
5683 if(isFlagSet(data->ActiveNode->tn_Flags, TNF_LIST) && isFlagSet(data->ActiveNode->tn_Flags, TNF_OPEN))
5685 DoMethod( obj, MUIM_NListtree_Close, MUIV_NListtree_Close_ListNode_Active, MUIV_NListtree_Close_TreeNode_Active, 0 );
5686 changed = TRUE;
5688 else if ( (IPTR)GetParent( data->ActiveNode ) != (IPTR)&data->RootList )
5690 set( obj, MUIA_NListtree_Active, GetParent( data->ActiveNode ) );
5691 changed = TRUE;
5694 else
5696 set( obj, MUIA_NListtree_Active, MUIV_NListtree_Active_LastVisible );
5697 changed = TRUE;
5700 if(changed)
5701 ret = MUI_EventHandlerRC_Eat;
5703 break;
5705 case MUIKEY_RIGHT:
5707 BOOL changed = FALSE;
5709 if ( data->ActiveNode )
5711 if(isFlagSet(data->ActiveNode->tn_Flags, TNF_LIST))
5713 if(isFlagClear(data->ActiveNode->tn_Flags, TNF_OPEN))
5715 DoMethod( obj, MUIM_NListtree_Open, MUIV_NListtree_Open_ListNode_Active, MUIV_NListtree_Open_TreeNode_Active, 0 );
5716 changed = TRUE;
5718 else if((tn = CTN(DoMethod(obj, MUIM_NListtree_GetEntry, data->ActiveNode, MUIV_NListtree_GetEntry_Position_Head, 0))))
5720 if(xget(obj, MUIA_NListtree_Active) != (IPTR)tn)
5722 set( obj, MUIA_NListtree_Active, tn );
5723 changed = TRUE;
5728 else
5730 set( obj, MUIA_NListtree_Active, MUIV_NListtree_Active_FirstVisible );
5731 changed = TRUE;
5734 if(changed)
5735 ret = MUI_EventHandlerRC_Eat;
5737 break;
5739 case MUIKEY_UP:
5740 break;
5742 case MUIKEY_DOWN:
5743 break;
5745 case MUIKEY_TOGGLE:
5746 break;
5750 if ( msg->imsg)
5752 WORD mx, my;
5756 ** We make this here, because the first act
5757 ** in the list tree may be selection.
5759 if(isFlagSet(msg->imsg->Qualifier, IEQUALIFIER_LSHIFT))
5761 SET_FLAG(data->Flags, NLTF_QUALIFIER_LSHIFT);
5763 else
5765 CLEAR_FLAG(data->Flags, NLTF_QUALIFIER_LSHIFT);
5768 if(isFlagSet(msg->imsg->Qualifier, IEQUALIFIER_CONTROL))
5770 SET_FLAG(data->Flags, NLTF_QUALIFIER_CONTROL);
5772 else
5774 CLEAR_FLAG(data->Flags, NLTF_QUALIFIER_CONTROL);
5777 mx = msg->imsg->MouseX;
5778 my = msg->imsg->MouseY;
5780 switch ( msg->imsg->Class )
5782 case IDCMP_MOUSEBUTTONS:
5784 D(DBF_INPUT, "mousebutton");
5785 if ( _isinobject( mx, my ) )
5787 struct MUI_NListtree_TreeNode *tn;
5788 struct MUI_NList_TestPos_Result tpres;
5790 D(DBF_INPUT, "inobject");
5792 switch( msg->imsg->Code )
5794 case SELECTDOWN:
5797 ** Get pointer to the selected node.
5798 ** Set active node and list in global
5799 ** data structure.
5801 DoMethod( obj, MUIM_NList_TestPos, mx, my, &tpres );
5803 if ( tpres.entry != -1 )
5806 ** When user changed the column positions,
5807 ** we use this to avoid trouble.
5809 //$$$ Remove is List used
5810 tpres.column = DoMethod( obj, MUIM_NList_ColumnToCol, tpres.column );
5812 DoMethod( obj, MUIM_NList_GetEntry, tpres.entry, &tn );
5815 ** Only react if node is not frozen.
5817 if(isFlagClear(tn->tn_Flags, TNF_FROZEN))
5819 STATIC UWORD lastclickentry = 0;
5822 ** If node is a list entry, open or close the node
5823 ** by simple click on the image depending on the
5824 ** current state.
5826 if(isFlagSet(tn->tn_Flags, TNF_LIST) &&
5827 tpres.column == data->TreeColumn &&
5828 tpres.xoffset >= tn->tn_ImagePos &&
5829 tpres.xoffset <= tn->tn_ImagePos + data->MaxImageWidth)
5832 ** Do not start dragging if user clicked on arrow-image.
5834 //SET_FLAG(data->Flags, NLTF_OVER_ARROW);
5835 //D(bug( "SETTING OVER_ARROW FLAG\n" ) );
5837 data->OpenCloseEntry = tn;
5840 ** NList should do nothing in case of arrow-click
5841 ** with LSHIFT qualifier..
5843 if(isFlagSet(data->Flags, NLTF_QUALIFIER_LSHIFT))
5844 ret = MUI_EventHandlerRC_Eat;
5848 ** We get the click time out of the intuimessage
5849 ** If double click, reset time values, if not, set values to current time.
5851 if(DoubleClick(data->LDClickTimeSecs, data->LDClickTimeMicros, msg->imsg->Seconds, msg->imsg->Micros) &&
5852 (tpres.entry == lastclickentry))
5855 ** Do not start dragging if user double clicked on an entry.
5857 //SET_FLAG(data->Flags, NLTF_OVER_ARROW);
5858 //D(bug( "SETTING OVER_ARROW FLAG\n" ) );
5861 ** Double clicked!! Check what we have to do...
5863 if ( ( data->DoubleClick != MUIV_NListtree_DoubleClick_Off ) && ( data->DoubleClick != MUIV_NListtree_DoubleClick_NoTrigger ) )
5865 //D(bug( "DoubleClick: %ld, TreeColumn: %ld, tpres.column: %ld\n", data->DoubleClick, data->TreeColumn, tpres.column ) );
5867 if ( ( ( data->DoubleClick == MUIV_NListtree_DoubleClick_Tree ) && ( tpres.column == data->TreeColumn ) ) ||
5868 ( data->DoubleClick == MUIV_NListtree_DoubleClick_All ) )
5870 data->OpenCloseEntry = tn;
5872 data->LDClickEntry = tpres.entry;
5873 data->LDClickColumn = tpres.column;
5875 //D(bug( "Double click detected on node 0x%08lx\n", tn ) );
5878 else
5880 data->LDClickEntry = -1;
5881 data->LDClickColumn = -1;
5884 data->LDClickTimeSecs = 0;
5885 data->LDClickTimeMicros = 0;
5887 else
5889 data->LDClickTimeSecs = msg->imsg->Seconds;
5890 data->LDClickTimeMicros = msg->imsg->Micros;
5893 lastclickentry = tpres.entry;
5896 break;
5899 case SELECTUP:
5902 ** Get pointer to the selected node.
5903 ** Set active node and list in global
5904 ** data structure.
5906 DoMethod( obj, MUIM_NList_TestPos, mx, my, &tpres );
5908 if ( tpres.entry != -1 )
5911 ** When user changed the column positions,
5912 ** we use this to avoid trouble.
5914 //$$$ Remove
5915 tpres.column = DoMethod( obj, MUIM_NList_ColumnToCol, tpres.column );
5917 DoMethod( obj, MUIM_NList_GetEntry, tpres.entry, &tn );
5919 D(DBF_INPUT, "Clicked on xoffset = %ld, col: %ld, impos = %ld, arrowwidth = %ld", tpres.xoffset, tpres.column, tn->tn_ImagePos, data->MaxImageWidth);
5921 if ( data->OpenCloseEntry )
5923 if(isFlagSet(data->OpenCloseEntry->tn_Flags, TNF_OPEN))
5924 DoMethod( obj, MUIM_NListtree_Close, GetParent( data->OpenCloseEntry ), data->OpenCloseEntry, 0 );
5925 else
5926 DoMethod( obj, MUIM_NListtree_Open, GetParent( data->OpenCloseEntry ), data->OpenCloseEntry, 0 );
5928 data->OpenCloseEntry = NULL;
5933 ** Delete over arrow flag when releasing mouse button.
5935 //CLEAR_FLAG(data->Flags, NLTF_OVER_ARROW);
5936 //D(bug( "RESETTING OVER_ARROW FLAG\n" ) );
5937 break;
5941 case MIDDLEDOWN:
5943 struct MUI_NList_TestPos_Result tpres;
5944 struct TimeVal tv;
5946 DoMethod( obj, MUIM_NList_TestPos, mx, my, &tpres );
5948 if ( tpres.entry != -1 )
5950 struct MUI_NListtree_TreeNode *tn;
5952 DoMethod( obj, MUIM_NList_GetEntry, tpres.entry, &tn );
5954 CurrentTime( &tv.Seconds, &tv.Microseconds );
5956 if ( DoubleClick( data->MDClickTime.Seconds, data->MDClickTime.Microseconds, tv.Seconds, tv.Microseconds ) &&
5957 ( tpres.entry == data->MDClickEntry ) )
5959 data->MDClickTime.Seconds = 0;
5960 data->MDClickTime.Microseconds = 0;
5961 data->MDClickEntry = -1;
5962 data->MDClickColumn = -1;
5964 else
5966 data->MDClickTime.Seconds = tv.Seconds;
5967 data->MDClickTime.Microseconds = tv.Microseconds;
5968 data->MDClickEntry = tpres.entry;
5969 data->MDClickColumn = tpres.column;
5973 break;
5975 case MIDDLEUP:
5976 break;
5981 break;
5983 case IDCMP_MOUSEMOVE:
5985 if ( _isinobject( mx, my ) )
5989 break;
5993 #if defined(__amigaos3__)
5994 // with MUI 3.8 the superclass does not get this method, hence we must forward it ourself.
5995 if(ret != MUI_EventHandlerRC_Eat && MUIMasterBase != NULL && MUIMasterBase->lib_Version <= 19)
5996 ret = DoSuperMethodA(cl, obj, (Msg)msg);
5997 #endif
5999 return( ret );
6005 IPTR _DragNDrop_DragQuery(struct IClass *cl, Object *obj, Msg msg)
6007 struct NListtree_Data *data = INST_DATA(cl, obj);
6008 struct MUIP_DragQuery *d = (struct MUIP_DragQuery *)msg;
6009 ULONG result;
6011 ENTER();
6013 if(d->obj == obj)
6015 //if(isFlagSet(data->Flags, NLTF_DRAGDROPSORT) && isFlagClear(data->Flags, NLTF_OVER_ARROW))
6016 if(isFlagSet(data->Flags, NLTF_DRAGDROPSORT))
6018 RETURN(MUIV_DragQuery_Accept);
6019 return MUIV_DragQuery_Accept;
6021 else
6023 RETURN(MUIV_DragQuery_Refuse);
6024 return MUIV_DragQuery_Refuse;
6028 result = DoSuperMethodA(cl, obj, msg);
6030 RETURN(result);
6031 return result;
6035 IPTR _DragNDrop_DragBegin(struct IClass *cl, Object *obj, Msg msg)
6037 struct NListtree_Data *data = INST_DATA(cl, obj);
6038 IPTR result;
6040 ENTER();
6043 ** If active entry is the only selected one, use it
6044 ** for drag&drop.
6047 if ( !data->SelectedTable.tb_Entries )
6049 data->TempSelected = TreeNodeSelectAdd( data, data->ActiveNode );
6053 SET_FLAG(data->Flags, NLTF_DRAGDROP);
6054 data->OldDropTarget = NULL;
6056 result = DoSuperMethodA(cl, obj, msg);
6058 RETURN(result);
6059 return result;
6063 #ifndef _between
6064 #define _between(a, x, b) ((x) >= (a) && (x) <= (b))
6065 #endif
6066 #ifndef _isinobject
6067 #define _isinobject(x, y) (_between(_mleft(obj), (x), _mright(obj)) && _between(_mtop(obj), (y), _mbottom(obj)))
6068 #endif
6069 IPTR _DragNDrop_DragReport(struct IClass *cl, Object *obj, Msg msg)
6071 struct MUIP_DragReport *d = (struct MUIP_DragReport *)msg;
6072 IPTR result;
6074 ENTER();
6076 if(_isinobject(d->x, d->y))
6077 result = DoSuperMethodA(cl, obj, msg);
6078 else
6079 result = MUIV_DragReport_Abort;
6081 RETURN(result);
6082 return result;
6086 IPTR _DragNDrop_DropType(struct IClass *cl, Object *obj, struct MUIP_NList_DropType *msg)
6088 struct NListtree_Data *data = INST_DATA(cl, obj);
6090 ENTER();
6092 DoMethod(obj, MUIM_NList_GetEntry, *msg->pos, &data->DropTarget);
6094 data->DropTargetPos = *msg->pos;
6096 if(IsXChildOfListMember(data->DropTarget, &data->SelectedTable) == NULL)
6098 if(msg->mousey <= msg->miny + 2)
6100 *msg->type = MUIV_NListtree_DropType_Above;
6102 else if(msg->mousey >= msg->maxy - 2)
6104 *msg->type = MUIV_NListtree_DropType_Below;
6105 *msg->pos -= 1;
6107 else
6109 *msg->type = MUIV_NListtree_DropType_Onto;
6112 else
6114 *msg->type = MUIV_NListtree_DropType_None;
6117 if(*msg->type == MUIV_NListtree_DropType_Onto && isFlagSet(data->DropTarget->tn_Flags, TNF_LIST))
6118 data->DropType = MUIV_NListtree_DropType_Sorted;
6119 else
6120 data->DropType = *msg->type;
6122 DoMethod(obj, MUIM_NListtree_DropType, &data->DropTargetPos, &data->DropType, msg->minx, msg->maxx, msg->miny, msg->maxy, msg->mousex, msg->mousey);
6124 if(*msg->type == MUIV_NListtree_DropType_Below && data->DropType != MUIV_NListtree_DropType_Below)
6125 *msg->pos += 1;
6127 if(data->DropType == MUIV_NListtree_DropType_Sorted)
6128 *msg->type = MUIV_NListtree_DropType_Onto;
6129 else
6130 *msg->type = data->DropType;
6132 D(DBF_DRAGDROP, "OPos: %ld, OType: %ld, Pos: %ld, Type: %ld", *msg->pos, *msg->type, data->DropTargetPos, data->DropType);
6134 if(isFlagSet(data->DropTarget->tn_Flags, TNF_LIST) && isFlagClear(data->DropTarget->tn_Flags, TNF_OPEN) && *msg->type == MUIV_NListtree_DropType_Onto)
6136 // Make sure the screen is currently not locked because of the current DnD action.
6137 // Opening the node now might lead to a deadlock, because the redraw might require
6138 // another lock. However, OS4's MUI is able to perform lockless DnD actions on true
6139 // color screens.
6140 if(data->compositingActive != 0 && _screen(obj)->LayerInfo.Lock.ss_Owner == NULL)
6142 // the current possible drop target is a closed list node
6143 if(data->OldDropTarget != data->DropTarget)
6145 D(DBF_DRAGDROP, "drop target changed, old='%s', new='%s'", data->OldDropTarget != NULL ? data->OldDropTarget->tn_Name : (STRPTR)"NULL", data->DropTarget ? data->DropTarget->tn_Name : (STRPTR)"NULL");
6146 // the possible drop target node has changed
6147 // remember the current time
6148 CurrentTime(&data->OpenDropListSecs, &data->OpenDropListMicros);
6150 else
6152 // no target change and we can drop something on the node
6153 // now check if the desired delay has passed
6154 ULONG secs;
6155 ULONG micros;
6156 ULONG diffSecs;
6158 // get the current system time
6159 CurrentTime(&secs, &micros);
6160 // calculate the difference to the last time
6161 diffSecs = secs - data->OpenDropListSecs;
6162 if(micros < data->OpenDropListMicros)
6164 diffSecs--;
6167 // open the node if the user held the mouse for at least one second
6168 // over the closed node
6169 if(diffSecs >= 1)
6171 D(DBF_DRAGDROP, "drop target same since one second '%s'", data->DropTarget ? data->DropTarget->tn_Name : (STRPTR)"NULL");
6172 // the time has passed, now open the list node
6173 DoMethod(obj, MUIM_NListtree_Open, GetParent(data->DropTarget), data->DropTarget, 0);
6174 // reset the start time
6175 data->OpenDropListSecs = secs;
6176 data->OpenDropListMicros = micros;
6182 data->OldDropTarget = data->DropTarget;
6184 LEAVE();
6185 return 0;
6189 IPTR _DragNDrop_NDropDraw(struct IClass *cl, Object *obj, struct MUIP_NListtree_DropDraw *msg)
6191 struct NListtree_Data *data = INST_DATA(cl, obj);
6192 struct RastPort *rp = _rp( obj );
6193 ULONG apen, bpen;
6194 UWORD *pens = _pens( obj );
6197 D(DBF_DRAGDROP, "OPos: %ld, OType: %ld, Pos: %ld, Type: %ld", msg->pos, msg->type,
6198 data->DropTargetPos, data->DropType);
6201 apen = GetAPen( rp );
6202 bpen = GetBPen( rp );
6204 MySetABPenDrMd( rp, pens[MPEN_SHINE], pens[MPEN_SHADOW], JAM1 );
6205 SetDrPt( rp, 0xF0F0 );
6207 switch ( data->DropType )
6209 case MUIV_NListtree_DropType_Above:
6211 Move( rp, msg->MinX, msg->MinY );
6212 Draw( rp, msg->MaxX, msg->MinY );
6214 MySetABPenDrMd( rp, MUIPEN( data->Pen[PEN_Shadow] ), MUIPEN( data->Pen[PEN_Shadow] ), JAM1 );
6215 SetDrPt( rp, 0x0F0F );
6217 Move( rp, msg->MinX, msg->MinY );
6218 Draw( rp, msg->MaxX, msg->MinY );
6220 break;
6222 case MUIV_NListtree_DropType_Below:
6223 Move( rp, msg->MinX, msg->MaxY );
6224 Draw( rp, msg->MaxX, msg->MaxY );
6226 Move( rp, msg->MinX, msg->MaxY );
6227 Draw( rp, msg->MaxX, msg->MaxY );
6229 MySetABPenDrMd( rp, MUIPEN( data->Pen[PEN_Shadow] ), MUIPEN( data->Pen[PEN_Shadow] ), JAM1 );
6230 SetDrPt( rp, 0x0F0F );
6232 Move( rp, msg->MinX, msg->MaxY );
6233 Draw( rp, msg->MaxX, msg->MaxY );
6235 Move( rp, msg->MinX, msg->MaxY );
6236 Draw( rp, msg->MaxX, msg->MaxY );
6237 break;
6239 case MUIV_NListtree_DropType_Onto:
6240 case MUIV_NListtree_DropType_Sorted:
6241 Move( rp, msg->MinX, msg->MinY + 1 );
6242 Draw( rp, msg->MaxX, msg->MinY + 1 );
6244 Move( rp, msg->MinX, msg->MaxY - 1 );
6245 Draw( rp, msg->MaxX, msg->MaxY - 1 );
6247 MySetABPenDrMd( rp, MUIPEN( data->Pen[PEN_Shadow] ), MUIPEN( data->Pen[PEN_Shadow] ), JAM1 );
6248 SetDrPt( rp, 0x0F0F );
6250 Move( rp, msg->MinX, msg->MinY + 1 );
6251 Draw( rp, msg->MaxX, msg->MinY + 1 );
6253 Move( rp, msg->MinX, msg->MaxY - 1 );
6254 Draw( rp, msg->MaxX, msg->MaxY - 1 );
6255 break;
6258 SetDrPt( rp, (UWORD)~0 );
6259 MySetABPenDrMd( rp, apen, bpen, JAM1 );
6261 return( 0 );
6265 //$$$
6266 IPTR _DragNDrop_DropDraw(struct IClass *cl, Object *obj, struct MUIP_NList_DropDraw *msg)
6268 struct NListtree_Data *data = INST_DATA(cl, obj);
6269 struct MUI_NListtree_TreeNode *drawtarget;
6271 D(DBF_DRAGDROP, "DropType: %ld, DropPos: %ld", msg->type, msg->pos);
6273 DoMethod( obj, MUIM_NList_GetEntry, msg->pos, &drawtarget );
6275 DoMethod( obj, MUIM_NListtree_DropDraw, data->DropTargetPos, data->DropType, msg->minx + drawtarget->tn_ImagePos, msg->maxx, msg->miny, msg->maxy );
6277 return( 0 );
6281 IPTR _DragNDrop_DragFinish(struct IClass *cl, Object *obj, Msg msg)
6283 struct NListtree_Data *data = INST_DATA(cl, obj);
6284 IPTR result;
6286 ENTER();
6288 CLEAR_FLAG(data->Flags, NLTF_DRAGDROP);
6290 result = DoSuperMethodA(cl, obj, msg);
6292 RETURN(result);
6293 return result;
6297 IPTR _DragNDrop_DragDrop(struct IClass *cl, Object *obj, UNUSED Msg msg)
6299 struct NListtree_Data *data = INST_DATA(cl, obj);
6300 struct MUI_NListtree_TreeNode *tn, *tn2, *dtn, *nexttn = NULL;
6301 struct MUI_NListtree_ListNode *ln = NULL;
6303 dtn = data->DropTarget;
6305 D(DBF_DRAGDROP, "MUIM_DragDrop");
6307 if ( data->SelectedTable.tb_Entries > 0 )
6309 struct MUI_NListtree_TreeNode *rettn;
6311 DoQuiet( data, TRUE );
6312 DeactivateNotify( data );
6313 data->IgnoreSelectionChange = 1;
6315 tn = (struct MUI_NListtree_TreeNode *)MUIV_NListtree_NextSelected_Start;
6317 for (;;)
6319 DoMethod( obj, MUIM_NListtree_NextSelected, &tn );
6321 if ( (IPTR)tn == (IPTR)MUIV_NListtree_NextSelected_End )
6322 break;
6324 if((rettn = IsXChildOfListMemberNotSelf(tn, &data->SelectedTable)))
6326 D(DBF_DRAGDROP, "Entry 0x%08lx - %s already inserted through node 0x%08lx - %s", tn, tn->tn_Name, rettn, rettn->tn_Name);
6328 else
6330 switch( data->DropType )
6332 case MUIV_NListtree_DropType_Above:
6333 D(DBF_DRAGDROP, "Inserting entry 0x%08lx - %s above L: %s, N: %s", tn, tn->tn_Name, dtn->tn_Parent->tn_Name, dtn->tn_Name);
6335 ln = CLN( GetParent( dtn ) );
6337 if ( !( tn2 = CTN( GetPred( (struct Node *)&dtn->tn_Node ) ) ) )
6338 tn2 = CTN( MUIV_NListtree_Move_NewTreeNode_Head );
6340 DoMethod( obj, MUIM_NListtree_Move, GetParent( tn ), tn, ln, tn2, 0 );
6342 break;
6345 case MUIV_NListtree_DropType_Below:
6346 D(DBF_DRAGDROP, "Inserting entry 0x%08lx below L: 0x%lx, N: 0x%lx", tn, dtn->tn_Parent, dtn);
6348 if ( !nexttn )
6350 if(isFlagSet(dtn->tn_Flags, TNF_LIST) && isFlagSet(dtn->tn_Flags, TNF_OPEN))
6352 ln = CLN( dtn );
6353 tn2 = MUIV_NListtree_Move_NewTreeNode_Head;
6355 else
6357 ln = CLN( GetParent( dtn ) );
6358 tn2 = dtn;
6361 else
6363 tn2 = nexttn;
6366 DoMethod( obj, MUIM_NListtree_Move, GetParent( tn ), tn, ln, tn2, 0 );
6368 break;
6371 case MUIV_NListtree_DropType_Onto:
6372 case MUIV_NListtree_DropType_Sorted:
6373 D(DBF_DRAGDROP, "Inserting entry 0x%08lx onto L: 0x%lx, N: 0x%lx", tn, dtn->tn_Parent, dtn);
6375 if(isFlagSet(dtn->tn_Flags, TNF_LIST))
6376 ln = CLN( dtn );
6377 else
6378 ln = CLN( GetParent( dtn ) );
6381 if ( data->SelectedTable.tb_Entries == 1 )
6383 if(isFlagClear(dtn->tn_Flags, TNF_LIST) && isFlagClear(tn->tn_Flags, TNF_LIST))
6385 tn2 = dtn;
6387 DoMethod( obj, MUIM_NListtree_Exchange, GetParent( tn ), tn,
6388 ln, tn2, 0 );
6392 if(isFlagSet(dtn->tn_Flags, TNF_LIST))
6394 tn2 = CTN(MUIV_NListtree_Move_NewTreeNode_Sorted);
6396 DoMethod( obj, MUIM_NListtree_Move, GetParent( tn ), tn, ln, tn2, 0 );
6399 break;
6402 nexttn = tn;
6406 data->IgnoreSelectionChange = 0;
6407 ActivateNotify( data );
6409 /* sba: the active node could be changed, but the notify calling was disabled */
6410 // data->ForceActiveNotify = 1;
6411 DoMethod(data->Obj, MUIM_NListtree_GetListActive, 0);
6413 DoQuiet( data, FALSE );
6417 ** If active entry moved, deselect him.
6420 if ( data->TempSelected )
6422 TreeNodeSelectRemove( data, data->TempSelected );
6423 data->TempSelected = NULL;
6427 CLEAR_FLAG(data->Flags, NLTF_DRAGDROP);
6429 return( 0 );
6433 IPTR _NList_Display(struct IClass *cl, Object *obj, struct MUIP_NList_Display *msg)
6435 struct NListtree_Data *data = INST_DATA(cl, obj);
6436 struct MUI_NListtree_TreeNode *tn = CTN(msg->entry);
6439 if ( !strcmp( "comp", tn->tn_Name ) )
6440 DEBUGBREAK;
6443 // invoke the display method, this may be overridden by subclassed instances
6444 DoMethod(obj, MUIM_NListtree_Display, tn, msg->entry_pos, msg->strings, msg->preparses);
6446 if(tn != NULL)
6448 D(DBF_DRAW, "render flags=%lx %s %s",tn->tn_Flags,isFlagSet(tn->tn_Flags, TNF_LIST)?" list":"",msg->strings[1]);
6450 if(msg->strings[data->TreeColumn] == NULL)
6452 msg->strings[data->TreeColumn] = tn->tn_Name;
6456 ** Reset image position. Will be updated inside DrawPos().
6458 tn->tn_ImagePos = 0;
6460 // NUL terminate the string
6461 data->buf[0] = '\0';
6462 if(isFlagClear(data->Flags, NLTF_NO_TREE))
6463 DrawImages(tn, tn, data, 0);
6465 if(msg->preparses[data->TreeColumn] != NULL)
6466 strlcat(data->buf, msg->preparses[data->TreeColumn], DATA_BUF_SIZE);
6468 strlcat(data->buf, msg->strings[data->TreeColumn], DATA_BUF_SIZE);
6470 D(DBF_DRAW, "%s - %s", isFlagSet(data->Flags, NLTF_QUIET) ? "QUIET" : "RUN", data->buf);
6472 msg->strings[data->TreeColumn] = data->buf;
6475 return (IPTR)tn;
6479 IPTR _NListtree_Construct(struct IClass *cl, Object *obj, struct MUIP_NListtree_Construct *msg)
6481 struct NListtree_Data *data = INST_DATA(cl, obj);
6482 IPTR result;
6484 // we just fallback to the construct hook, if any is set
6485 if(data->ConstructHook != NULL)
6486 result = (IPTR)MyCallHook(data->ConstructHook, data, MUIA_NListtree_ConstructHook, msg->Name, msg->UserData, msg->MemPool, msg->Flags);
6487 else
6488 result = (IPTR)msg->UserData;
6490 return result;
6494 IPTR _NListtree_Destruct(struct IClass *cl, Object *obj, struct MUIP_NListtree_Destruct *msg)
6496 struct NListtree_Data *data = INST_DATA(cl, obj);
6498 if(data->DestructHook != NULL)
6499 MyCallHook(data->DestructHook, data, MUIA_NListtree_DestructHook, msg->Name, msg->UserData, msg->MemPool, msg->Flags);
6501 return 0;
6505 IPTR _NListtree_Display(struct IClass *cl, Object *obj, struct MUIP_NListtree_Display *msg)
6507 struct NListtree_Data *data = INST_DATA(cl, obj);
6509 // we just fallback to the display hook, if any is set
6510 if(data->DisplayHook != NULL)
6511 MyCallHook(data->DisplayHook, data, MUIA_NListtree_DisplayHook, msg->TreeNode, msg->EntryPos, msg->Array, msg->Preparse);
6512 else
6513 msg->Array[data->TreeColumn] = NULL;
6515 return 0;
6519 IPTR _NListtree_Compare(struct IClass *cl, Object *obj, struct MUIP_NListtree_Compare *msg)
6521 struct NListtree_Data *data = INST_DATA(cl, obj);
6522 LONG cmp;
6524 // fall back to the compare hook if one is given, otherwise we assume node1 < node2
6525 if(data->CompareHook != NULL)
6526 cmp = (LONG)MyCallHook(data->CompareHook, data, MUIA_NListtree_CompareHook, msg->TreeNode1, msg->TreeNode2, 0);
6527 else
6528 cmp = -1;
6530 return cmp;
6534 //$$$
6535 IPTR _ContextMenuBuild(struct IClass *cl, Object *obj, struct MUIP_NList_ContextMenuBuild *msg)
6537 struct NListtree_Data *data = INST_DATA(cl, obj);
6539 STATIC struct NewMenu ContextMenu[] =
6542 ** Type Label Key Flg MX UserData
6543 ** ======== =============================== === === === ==============
6545 { NM_TITLE, (STRPTR)"NListtree", 0, 0, 0, NULL, },
6547 { NM_ITEM, (STRPTR)"Copy to clipboard", 0, 0, 0, NULL, },
6549 { NM_SUB, (STRPTR)"Unit 0", 0, 0, 0, (APTR)0, },
6550 { NM_SUB, (STRPTR)"Unit 1", 0, 0, 0, (APTR)1, },
6551 { NM_SUB, (STRPTR)"Unit 2", 0, 0, 0, (APTR)2, },
6552 { NM_SUB, (STRPTR)"Unit 3", 0, 0, 0, (APTR)3, },
6554 { NM_END, NULL, 0, 0, 0, NULL, }
6557 data->MenuChoice.pos = msg->pos;
6558 data->MenuChoice.col = msg->column;
6559 data->MenuChoice.ontop = msg->ontop;
6561 if ( !msg->ontop )
6562 return( (IPTR)MUI_MakeObject( MUIO_MenustripNM, ContextMenu, 0 ) );
6564 return( DoSuperMethodA( cl, obj, (Msg)msg) );
6568 //$$$
6569 IPTR _ContextMenuChoice(struct IClass *cl, Object *obj, struct MUIP_ContextMenuChoice *msg)
6571 struct NListtree_Data *data = INST_DATA(cl, obj);
6572 struct MUI_NListtree_TreeNode *tn;
6574 if ( !data->MenuChoice.ontop )
6576 DoMethod( obj, MUIM_NList_GetEntry, data->MenuChoice.pos, &tn );
6577 DoMethod( obj, MUIM_NListtree_CopyToClip, tn, data->MenuChoice.pos, muiUserData( msg->item ) );
6579 return( 0 );
6583 return( DoSuperMethodA( cl, obj, (Msg)msg) );
6588 /*****************************************************************************\
6589 *******************************************************************************
6591 ** Class methods.
6593 *******************************************************************************
6594 \*****************************************************************************/
6596 /****** NListtree.mcc/MUIM_NListtree_Open ***********************************
6598 * NAME
6600 * MUIM_NListtree_Open -- Open the specified tree node. (V1)
6603 * SYNOPSIS
6605 * DoMethod(obj, MUIM_NListtree_Open,
6606 * struct MUI_NListtree_TreeNode *listnode,
6607 * struct MUI_NListtree_TreeNode *treenode,
6608 * ULONG flags);
6611 * FUNCTION
6613 * Opens a node in the listtree. To open a child, which isn't displayed,
6614 * use 'MUIV_NListtree_Open_ListNode_Parent' to open all its parents, too.
6616 * Only nodes can be opened.
6619 * INPUTS
6621 * listnode - Specify the node which list is used to open the node.
6623 * MUIV_NListtree_Open_ListNode_Root
6624 * The root list is used.
6626 * MUIV_NListtree_Open_ListNode_Parent
6627 * Indicates, that all the parents of the node specified in
6628 * 'treenode' should be opened too.
6630 * MUIV_NListtree_Open_ListNode_Active
6631 * The list of the active node is used.
6633 * treenode - The node to open.
6635 * MUIV_NListtree_Open_TreeNode_Head
6636 * Opens the head node of the list.
6638 * MUIV_NListtree_Open_TreeNode_Tail
6639 * Opens the tail node of the list.
6641 * MUIV_NListtree_Open_TreeNode_Active
6642 * The active node will be opened.
6644 * MUIV_NListtree_Open_TreeNode_All:
6645 * All the nodes of the list are opened.
6648 * RESULT
6650 * EXAMPLE
6651 * // Open the active list.
6652 * DoMethod(obj, MUIM_NListtree_Open,
6653 * MUIV_NListtree_Open_ListNode_Active,
6654 * MUIV_NListtree_Open_TreeNode_Active, 0);
6657 * NOTES
6659 * BUGS
6661 * SEE ALSO
6662 * MUIM_NListtree_Close
6665 ******************************************************************************
6668 IPTR _NListtree_Open(struct IClass *cl, Object *obj, struct MUIP_NListtree_Open *msg)
6670 struct NListtree_Data *data = INST_DATA(cl, obj);
6671 struct MUI_NListtree_TreeNode *tn, *tn2;
6672 struct MUI_NListtree_ListNode *ln;
6673 BOOL openall = FALSE;
6675 //D(bug( "Node: 0x%08lx - 0x%08lx", msg->ListNode, msg->TreeNode ) );
6680 switch( (IPTR)msg->ListNode )
6682 case MUIV_NListtree_Open_ListNode_Root:
6683 ln = &data->RootList;
6684 break;
6686 case MUIV_NListtree_Open_ListNode_Parent:
6687 ln = &data->RootList;
6688 break;
6690 case MUIV_NListtree_Open_ListNode_Active:
6691 ln = data->ActiveList;
6692 break;
6694 default:
6695 ln = CLN( msg->ListNode );
6696 break;
6702 switch( (IPTR)msg->TreeNode )
6704 case MUIV_NListtree_Open_TreeNode_Head:
6705 tn = CTN( GetHead( (struct List *)&ln->ln_List ) );
6706 break;
6708 case MUIV_NListtree_Open_TreeNode_Tail:
6709 tn = CTN( GetTail( (struct List *)&ln->ln_List ) );
6710 break;
6712 case MUIV_NListtree_Open_TreeNode_Active:
6713 tn = data->ActiveNode;
6714 break;
6716 case MUIV_NListtree_Open_TreeNode_All:
6717 tn = CTN( ln ); // *** Dummy for check below.
6718 openall = TRUE;
6719 break;
6721 default:
6722 tn = msg->TreeNode;
6723 break;
6728 ** Determine if the node holds a list
6729 ** and the node is not open.
6731 if ( ln && tn )
6733 if(isFlagClear(tn->tn_Flags, TNF_LIST))
6734 tn = GetParentNotRoot( tn );
6736 if ( tn )
6738 if((isFlagSet(tn->tn_Flags, TNF_LIST) && isFlagClear(tn->tn_Flags, TNF_OPEN)) || openall)
6740 DeactivateNotify( data );
6741 DoQuiet( data, TRUE );
6743 //D(bug( "Node: 0x%08lx - %s%s", tn, tn->tn_Name, openall ? " (expand)" : "" ) );
6745 if ( openall )
6746 OpenTreeNodeListExpand( data, ln );
6747 else
6748 OpenTreeNode( data, tn );
6750 if ((IPTR)msg->ListNode == (IPTR)MUIV_NListtree_Open_ListNode_Parent)
6752 tn2 = tn;
6754 while((tn2 = GetParentNotRoot(tn2)))
6756 //D(bug( "Opening node: 0x%08lx - %s", tn2, tn2->tn_Name ) );
6758 OpenTreeNode( data, tn2 );
6762 if(isFlagSet(data->Flags, NLTF_OPENAUTOSCROLL) && !openall )
6763 ShowTree( data, tn );
6765 DoQuiet( data, FALSE );
6766 ActivateNotify( data );
6768 /* sba: the active note could be changed, but the notify calling was disabled */
6769 DoMethod(data->Obj, MUIM_NListtree_GetListActive, 0);
6774 return( 0 );
6779 /****** NListtree.mcc/MUIM_NListtree_Close ***********************************
6781 * NAME
6783 * MUIM_NListtree_Close -- Close the specified list node. (V1)
6786 * SYNOPSIS
6788 * DoMethod(obj, MUIM_NListtree_Close,
6789 * struct MUI_NListtree_TreeNode *listnode,
6790 * struct MUI_NListtree_TreeNode *treenode,
6791 * ULONG flags);
6794 * FUNCTION
6796 * Close a node or nodes of a listtree. It is checked if the tree node
6797 * is a node, not a leaf!
6799 * When the active entry was a child of the closed node, the closed node
6800 * will become active.
6803 * INPUTS
6805 * listnode - Specify the node which list is used to find the entry. The
6806 * search is started at the head of this list.
6808 * MUIV_NListtree_Close_ListNode_Root
6809 * The root list is used.
6811 * MUIV_NListtree_Close_ListNode_Parent
6812 * The list which is the parent of the active list is used.
6814 * MUIV_NListtree_Close_ListNode_Active
6815 * The list of the active node is used.
6818 * treenode - The node which should be closed. If there are children
6819 * of the node, they are also closed.
6821 * MUIV_NListtree_Close_TreeNode_Head
6822 * The head of the list defined in 'listnode' is closed.
6824 * MUIV_NListtree_Close_TreeNode_Tail:
6825 * Closes the tail of the list defined in 'listnode'.
6827 * MUIV_NListtree_Close_TreeNode_Active:
6828 * Closes the active node.
6830 * MUIV_NListtree_Close_TreeNode_All:
6831 * Closes all nodes of the list which is specified in
6832 * 'listnode'.
6835 * RESULT
6837 * EXAMPLE
6839 * // Close the active list.
6840 * DoMethod(obj, MUIM_NListtree_Close,
6841 * MUIV_NListtree_Close_ListNode_Active,
6842 * MUIV_NListtree_Close_TreeNode_Active, 0);
6845 * NOTES
6847 * BUGS
6849 * SEE ALSO
6850 * MUIM_NListtree_Open
6853 ******************************************************************************
6856 IPTR _NListtree_Close(struct IClass *cl, Object *obj, struct MUIP_NListtree_Close *msg)
6858 struct NListtree_Data *data = INST_DATA(cl, obj);
6859 struct MUI_NListtree_TreeNode *tn;
6860 struct MUI_NListtree_ListNode *ln;
6861 BOOL closeall = FALSE;
6866 switch( (IPTR)msg->ListNode )
6868 case MUIV_NListtree_Close_ListNode_Root:
6869 ln = &data->RootList;
6870 break;
6872 case MUIV_NListtree_Close_ListNode_Parent:
6873 ln = CLN( data->ActiveList->ln_Parent );
6874 break;
6876 case MUIV_NListtree_Close_ListNode_Active:
6877 ln = data->ActiveList;
6878 break;
6880 default:
6881 ln = CLN( msg->ListNode );
6882 break;
6888 switch( (IPTR)msg->TreeNode )
6890 case MUIV_NListtree_Close_TreeNode_Head:
6891 tn = CTN( GetHead( (struct List *)&ln->ln_List ) );
6892 break;
6894 case MUIV_NListtree_Close_TreeNode_Tail:
6895 tn = CTN( GetTail( (struct List *)&ln->ln_List ) );
6896 break;
6898 case MUIV_NListtree_Close_TreeNode_Active:
6899 tn = data->ActiveNode;
6900 break;
6902 case MUIV_NListtree_Close_TreeNode_All:
6903 tn = CTN( ln ); // *** Dummy for check below.
6904 closeall = TRUE;
6905 break;
6907 default:
6908 tn = msg->TreeNode;
6909 break;
6914 ** Determine if the node holds a list
6915 ** and the node is not open.
6917 if ( ln && tn )
6919 if((isFlagSet(tn->tn_Flags, TNF_LIST) && isFlagSet(tn->tn_Flags, TNF_OPEN)) || closeall )
6921 struct MUI_NListtree_TreeNode *temp = data->ActiveNode;
6923 DeactivateNotify( data );
6924 DoQuiet( data, TRUE );
6926 //D(bug( "Node: 0x%08lx - %s%s", tn, tn->tn_Name, closeall ? " (collapse)" : "" ) );
6928 if ( closeall )
6930 tn = CTN( ln );
6932 CloseTreeNodeListCollapse( data, ln );
6934 else
6936 if(isFlagSet(data->Flags, NLTF_REMEMBER_STATUS))
6937 CloseTreeNode( data, tn );
6938 else
6939 CloseTreeNodeCollapse( data, tn );
6942 DoQuiet( data, FALSE );
6943 ActivateNotify( data );
6945 if ( temp )
6947 if(isFlagSet(temp->tn_IFlags, TNIF_VISIBLE))
6948 set( obj, MUIA_NListtree_Active, temp );
6949 else
6950 set( obj, MUIA_NListtree_Active, tn );
6955 return( 0 );
6960 /****** NListtree.mcc/MUIM_NListtree_Insert **********************************
6962 * NAME
6964 * MUIM_NListtree_Insert -- Insert an entry at the specified position. (V1)
6967 * SYNOPSIS
6969 * struct MUI_NListtree_TreeNode *treenode =
6970 * DoMethod(obj, MUIM_NListtree_Insert,
6971 * STRPTR name, APTR userdata,
6972 * struct MUI_NListtree_TreeNode *listnode,
6973 * struct MUI_NListtree_TreeNode *prevtreenode,
6974 * ULONG flags);
6977 * FUNCTION
6979 * Insert an entry at the position, which is defined in 'listnode'
6980 * and 'prevtreenode'. Name contains the name of the entry as string
6981 * which is buffered. The user entry can be used as you like.
6984 * INPUTS
6986 * name/userdata - What the names say ;-)
6989 * listnode - Specify the node which list is used to insert
6990 * the entry.
6992 * MUIV_NListtree_Insert_ListNode_Root
6993 * Use the root list.
6995 * MUIV_NListtree_Insert_ListNode_Active
6996 * Use the list of the active node.
6998 * MUIV_NListtree_Insert_ListNode_ActiveFallback
6999 * Use the list of the active node. If no list is active,
7000 * an automatic fallback to the root list is done.
7002 * MUIV_NListtree_Insert_ListNode_LastInserted
7003 * Insert entry in the list the last entry was inserted.
7006 * prevtreenode - The node which is the predecessor of the node
7007 * to insert.
7009 * MUIV_NListtree_Insert_PrevNode_Head
7010 * The entry will be inserted at the head of the list.
7012 * MUIV_NListtree_Insert_PrevNode_Tail
7013 * The entry will be inserted at the tail of the list.
7015 * MUIV_NListtree_Insert_PrevNode_Active
7016 * The entry will be inserted after the active node of
7017 * the list. If no entry is active, the entry will be
7018 * inserted at the tail.
7020 * MUIV_NListtree_Insert_PrevNode_Sorted:
7021 * The entry will be inserted using the defined sort hook.
7023 * flags:
7025 * MUIV_NListtree_Insert_Flag_Active
7026 * The inserted entry will be set to active. This means the
7027 * cursor is moved to the newly inserted entry. If the entry
7028 * was inserted into a closed node, it will be opened.
7030 * MUIV_NListtree_Insert_Flag_NextNode
7031 * 'prevtreenode' is the successor, not the predecessor.
7034 * RESULT
7036 * A pointer to the newly inserted entry.
7039 * EXAMPLE
7041 * // Insert an entry after the active one and make it active.
7042 * DoMethod(obj, MUIM_NListtree_Insert, "Hello", NULL,
7043 * MUIV_NListtree_Insert_ListNode_Active,
7044 * MUIV_NListtree_Insert_PrevNode_Active,
7045 * MUIV_NListtree_Insert_Flag_Active);
7048 * NOTES
7050 * BUGS
7052 * Not implemented yet:
7053 * MUIV_NListtree_Insert_Flag_NextNode
7056 * SEE ALSO
7058 * MUIA_NListtree_ConstructHook, MUIA_NListtree_CompareHook
7061 ******************************************************************************
7064 IPTR _NListtree_Insert(struct IClass *cl, Object *obj, struct MUIP_NListtree_Insert *msg)
7066 struct NListtree_Data *data = INST_DATA(cl, obj);
7067 struct MUI_NListtree_TreeNode *tn = NULL;
7068 struct MUI_NListtree_ListNode *ln;
7069 APTR user;
7070 static const char *np = "*** NULL POINTER ***";
7072 D(DBF_LISTTREE, "MUIM_NListtree_Insert: name=%s flags=0x%lx listnode:0x%lx prevnode:0x%lx %ld",msg->Name,msg->Flags,msg->ListNode,msg->PrevNode,data->NumEntries);
7075 ** Construct new user data
7077 user = (APTR)DoMethod(obj, MUIM_NListtree_Construct, msg->Name, msg->User, data->TreePool, 0);
7080 ** Allocate memory for the new entry and, if
7081 ** list, initialize list structure for use.
7083 if(isFlagSet(msg->Flags, TNF_LIST))
7085 if((ln = CLN(AllocVecPooled(data->TreePool, sizeof(struct MUI_NListtree_ListNode)))))
7087 tn = CTN( ln );
7089 NewList( (struct List *)&ln->ln_List );
7092 else
7093 tn = CTN( AllocVecPooled( data->TreePool, sizeof( struct MUI_NListtree_TreeNode ) ) );
7097 ** If allocated memory successfully, set up all fields,
7098 ** get special list and node pointers if needed and add
7099 ** to a list.
7101 if ( tn )
7103 struct MUI_NListtree_ListNode *li;
7105 if ( !msg->Name )
7106 msg->Name = (char *)np;
7109 ** Should we duplicate the supplied node name?
7111 if(isFlagSet(data->Flags, NLTF_DUPNODENAMES))
7113 int len = strlen( msg->Name ) + 1;
7114 tn->tn_Name = (STRPTR)AllocVecPooled( data->TreePool, len );
7115 strlcpy( tn->tn_Name, msg->Name, len );
7116 SET_FLAG(tn->tn_IFlags, TNIF_ALLOCATED);
7118 else
7119 tn->tn_Name = msg->Name;
7121 if ( tn->tn_Name )
7123 tn->tn_User = user;
7124 tn->tn_Flags = msg->Flags;
7127 ** Check out which list to use.
7129 switch( (IPTR)msg->ListNode )
7131 case MUIV_NListtree_Insert_ListNode_Root:
7132 li = &data->RootList;
7133 break;
7135 case MUIV_NListtree_Insert_ListNode_Active:
7136 li = data->ActiveList;
7137 break;
7139 case MUIV_NListtree_Insert_ListNode_ActiveFallback:
7140 if ( !( li = data->ActiveList ) )
7141 li = &data->RootList;
7142 break;
7144 case MUIV_NListtree_Insert_ListNode_LastInserted:
7145 li = data->LastInsertedList;
7146 break;
7148 default:
7149 li = CLN( msg->ListNode );
7150 D(DBF_LISTTREE, "li = %p",li);
7151 break;
7154 if ( li )
7156 struct MUI_NListtree_TreeNode *in;
7159 ** If given list node is not a list, get parent
7160 ** of the given node to avoid trouble.
7162 if(isFlagClear(li->ln_Flags, TNF_LIST))
7163 li = CLN( GetParent( CTN( li ) ) );
7165 data->LastInsertedList = li;
7167 tn->tn_Parent = CTN( li );
7169 //DoQuiet( data, TRUE );
7170 //DeactivateNotify( data );
7173 ** Add the new created entry to the specified list.
7175 switch( (IPTR)msg->PrevNode )
7177 case MUIV_NListtree_Insert_PrevNode_Head:
7178 AddHead( (struct List *)&li->ln_List, (struct Node *)&tn->tn_Node );
7179 in = CTN( INSERT_POS_HEAD );
7180 break;
7182 case MUIV_NListtree_Insert_PrevNode_Tail:
7183 AddTail( (struct List *)&li->ln_List, (struct Node *)&tn->tn_Node );
7184 in = CTN( INSERT_POS_TAIL );
7185 break;
7187 case MUIV_NListtree_Insert_PrevNode_Active:
7188 if ( data->ActiveNode )
7190 if ( (APTR)li != (APTR)data->ActiveNode )
7192 Insert( (struct List *)&li->ln_List, (struct Node *)&tn->tn_Node, (struct Node *)&data->ActiveNode->tn_Node );
7193 in = data->ActiveNode;
7195 else
7197 AddHead( (struct List *)&li->ln_List, (struct Node *)&tn->tn_Node );
7198 in = CTN( INSERT_POS_HEAD );
7201 else
7203 AddTail( (struct List *)&li->ln_List, (struct Node *)&tn->tn_Node );
7204 in = CTN( INSERT_POS_TAIL );
7206 break;
7208 case MUIV_NListtree_Insert_PrevNode_Sorted:
7209 in = GetInsertNodeSorted( data, li, tn );
7211 if ( (IPTR)in == (IPTR)INSERT_POS_HEAD )
7213 AddHead( (struct List *)&li->ln_List, (struct Node *)&tn->tn_Node );
7215 else
7217 Insert( (struct List *)&li->ln_List, (struct Node *)&tn->tn_Node, (struct Node *)&in->tn_Node );
7219 break;
7221 default:
7222 Insert( (struct List *)&li->ln_List, (struct Node *)&tn->tn_Node, (struct Node *)&msg->PrevNode->tn_Node );
7223 in = msg->PrevNode;
7224 break;
7227 //D(bug( "Inserting entry 0x%08lx into list 0x%08lx (0x%08lx) after node 0x%08lx - '%s' User: 0x%08lx", tn, li, msg->ListNode, msg->PrevNode, ( (LONG)in == INSERT_POS_HEAD ) ? "HEAD" : ( (LONG)in == INSERT_POS_TAIL ) ? "TAIL" : in->tn_Name, msg->User ) );
7230 /* Special AmiTradeCenter Debug (Enforcer Hits!!)
7232 UBYTE *x = (UBYTE *)user + 28;
7233 UBYTE *lix = (UBYTE *)li->ln_User + 28;
7234 UBYTE *inx = (UBYTE *)in->tn_User + 28;
7236 char *name = (char *)x;
7237 char *liname = (char *)lix;
7238 char *inname = (char *)inx;
7240 D(bug( "Inserting '%s' into list '%s' after node '%s' at pos %ld (%s %s)\n",
7241 name,
7242 ( (LONG)msg->ListNode == MUIV_NListtree_Insert_ListNode_Root ) ? "ROOT" : ( (LONG)msg->ListNode == MUIV_NListtree_Insert_ListNode_Active ) ? "ACTIVE" : liname,
7243 ( (LONG)in == INSERT_POS_HEAD ) ? "HEAD" : ( (LONG)in == INSERT_POS_TAIL ) ? "TAIL" : inname,
7244 ( li->ln_Flags & TNF_OPEN ) ? GetVisualInsertPos( data, li, in ) : -1, ( tn->tn_Flags & TNF_OPEN ) ? "TNF_OPEN" : "", ( tn->tn_Flags & TNF_LIST ) ? "TNF_LIST" : "" ) );
7246 D(bug( "Inserting entry 0x%08lx - '%s' into list 0x%08lx (0x%08lx) - '%s' after node 0x%08lx (0x%08lx) - '%s'\n",
7247 tn, tn->tn_Name, li, msg->ListNode, li->ln_Name, in, msg->PrevNode, ( (LONG)in == INSERT_POS_HEAD ) ? "HEAD" : ( (LONG)in == INSERT_POS_TAIL ) ? "TAIL" : in->tn_Name ) );
7251 InsertTreeNodeVisible( data, tn, li, in );
7252 NLAddToTable( data, &li->ln_Table, tn );
7255 ** Make sure, that the inserted node is visible by opening
7256 ** all parents (if it should be set active).
7258 if(isFlagSet(msg->Flags, MUIV_NListtree_Insert_Flag_Active))
7260 if(isFlagClear(tn->tn_IFlags, TNIF_VISIBLE))
7261 DoMethod( obj, MUIM_NListtree_Open, MUIV_NListtree_Open_ListNode_Parent, tn, 0 );
7263 set( obj, MUIA_NListtree_Active, tn );
7267 ** Add one to the global number of entries
7268 ** and the number of entries in list.
7270 data->NumEntries++;
7273 if(isFlagSet(tn->tn_IFlags, TNIF_VISIBLE))
7274 DoRefresh( data );
7276 //ActivateNotify( data );
7277 //DoQuiet( data, FALSE );
7279 D(DBF_LISTTREE, "Result: 0x%lx %ld",tn,data->NumEntries);
7281 return( (IPTR)tn );
7285 ** Free memory if failed to allocate
7286 ** name space.
7288 FreeVecPooled( data->TreePool, tn );
7292 DoMethod(obj, MUIM_NListtree_Destruct, msg->Name, user, data->TreePool, 0);
7294 return(0);
7299 /****** NListtree.mcc/MUIM_NListtree_InsertStruct ****************************
7301 * NAME
7303 * MUIM_NListtree_InsertStruct -- Insert a structure such as a path
7304 * using a delimiter. (V1)
7307 * SYNOPSIS
7309 * struct MUI_NListtree_TreeNode *treenode =
7310 * DoMethod(obj, MUIM_NListtree_InsertStruct,
7311 * STRPTR name, APTR userdata,
7312 * STRPTR delimiter, ULONG flags);
7315 * FUNCTION
7317 * Insert a structure into the list such as a path or
7318 * something similar (like ListtreeName.mcc does). The name is
7319 * splitted using the supplied delimiter. For each name part a
7320 * new tree entry is generated. If you have Images/aphaso/Image.mbr,
7321 * the structure will be build es follows:
7323 * + Images
7324 * + aphaso
7325 * - Image.mbr
7327 * If a part of the structure is already present, it will be used to
7328 * insert.
7331 * INPUTS
7333 * name - Data containing (must not) one or more delimiters as
7334 * specified in delimiter (Images/aphaso/Image.mbr for
7335 * example).
7337 * userdata - Your personal data.
7339 * delimiter - The delimiter(s) used in the name field (":/" or
7340 * something).
7342 * flags:
7344 * Use normal insert flags here (see there).
7346 * In addition you can supply
7347 * MUIV_NListtree_InsertStruct_Flag_AllowDuplicates if you want the
7348 * last entry, Image.mbr in the above example, to occur multiple
7349 * times even if the name is the same.
7352 * RESULT
7354 * A pointer to the last instance of newly inserted entries.
7357 * EXAMPLE
7359 * // Insert a directory path.
7360 * path = MyGetPath( lock );
7362 * DoMethod(obj, MUIM_NListtree_InsertStruct,
7363 * path, NULL, ":/", 0);
7366 * NOTES
7368 * BUGS
7370 * SEE ALSO
7372 * MUIA_NListtree_Insert
7375 ******************************************************************************
7379 ** Returns tokens delimited by delimiter on each call.
7381 INLINE STRPTR mystrtok( STRPTR string, STRPTR buf, ULONG bufsize, STRPTR delimiter )
7383 STRPTR str, del;
7385 str = string;
7387 while( *str )
7389 del = delimiter;
7391 while( *del )
7393 if ( *str == *del )
7395 strncpy( buf, string, MIN( (LONG)bufsize - 1, ( str - string ) ) );
7396 buf[MIN( (LONG)bufsize - 1, ( str - string ) )] = 0;
7398 return( &str[1] );
7401 del++;
7404 str++;
7407 strncpy( buf, string, MIN( (LONG)bufsize - 1, ( str - string ) ) );
7408 buf[MIN( (LONG)bufsize - 1, ( str - string ) )] = 0;
7410 return( str );
7415 IPTR _NListtree_InsertStruct(struct IClass *cl, Object *obj, struct MUIP_NListtree_InsertStruct *msg)
7417 struct MUI_NListtree_TreeNode *temp, *lasttn = CTN( MUIV_NListtree_Insert_ListNode_Root );
7418 struct NListtree_Data *data = INST_DATA(cl, obj);
7419 STRPTR p, token;
7420 ULONG len;
7421 static const char *np = "*** NULL POINTER ***";
7423 if ( !msg->Name )
7424 msg->Name = (char *)np;
7426 if((token = AllocVecPooled(data->MemoryPool, len = (strlen(msg->Name) + 1))))
7428 p = msg->Name;
7430 while( 1 )
7432 p = mystrtok( p, token, len, msg->Delimiter );
7434 if ( ( !*p && isFlagSet(msg->Flags, MUIV_NListtree_InsertStruct_Flag_AllowDuplicates) ) ||
7435 !( temp = CTN( DoMethod( obj, MUIM_NListtree_FindName, lasttn, token, MUIV_NListtree_FindName_Flag_SameLevel ) ) ) )
7437 lasttn = CTN( DoMethod( obj, MUIM_NListtree_Insert, token, msg->User,
7438 lasttn, MUIV_NListtree_Insert_PrevNode_Tail, *p ? TNF_LIST | msg->Flags : msg->Flags ) );
7440 else
7442 lasttn = temp;
7445 if ( !*p ) break;
7448 FreeVecPooled( data->MemoryPool, token );
7451 return( (IPTR)lasttn );
7456 /****** NListtree.mcc/MUIM_NListtree_Remove **********************************
7458 * NAME
7460 * MUIM_NListtree_Remove -- Remove the specified entry(ies). (V1)
7463 * SYNOPSIS
7465 * DoMethod(obj, MUIM_NListtree_Remove,
7466 * struct MUI_NListtree_TreeNode *listnode,
7467 * struct MUI_NListtree_TreeNode *treenode,
7468 * ULONG flags);
7471 * FUNCTION
7473 * Removes a node or nodes from the listtree. When the active entry
7474 * is removed, the successor will become active.
7477 * INPUTS
7479 * listnode - Specify the node which list is used to find the entry
7480 * which should be removed. The search is started at the
7481 * begin of this list.
7483 * MUIV_NListtree_Remove_ListNode_Root
7484 * The root list is used.
7486 * MUIV_NListtree_Remove_ListNode_Active
7487 * The list of the active node is used.
7490 * treenode - The node which should be removed. If there are children
7491 * of this node, they are also removed.
7493 * MUIV_NListtree_Remove_TreeNode_Head
7494 * The head of the list defined in 'listnode' is removed.
7496 * MUIV_NListtree_Remove_TreeNode_Tail
7497 * The tail of the list defined in 'listnode' is removed.
7499 * MUIV_NListtree_Remove_TreeNode_Active
7500 * Removes the active node.
7502 * MUIV_NListtree_Remove_TreeNode_All
7503 * All nodes of the list which is specified in 'listnode',
7504 * are removed. Other nodes of parent lists are not
7505 * affected.
7507 * MUIV_NListtree_Remove_TreeNode_Selected
7508 * All selected nodes are removed.
7510 * RESULT
7512 * EXAMPLE
7514 * // Remove the active entry if delete is pressed!
7515 * DoMethod(bt_delete, MUIM_Notify, MUIA_Pressed, FALSE,
7516 * lt_list, 4, MUIM_NListtree_Remove,
7517 * MUIV_NListtree_Remove_ListNode_Active,
7518 * MUIV_NListtree_Remove_TreeNode_Active, 0);
7521 * NOTES
7523 * BUGS
7525 * SEE ALSO
7527 * MUIM_NListtree_Insert, MUIA_NListtree_DestructHook,
7528 * MUIM_NList_Active
7531 ******************************************************************************
7534 IPTR _NListtree_Remove(struct IClass *cl, Object *obj, struct MUIP_NListtree_Remove *msg)
7536 struct NListtree_Data *data = INST_DATA(cl, obj);
7537 struct MUI_NListtree_ListNode *li;
7538 struct MUI_NListtree_TreeNode *tn;
7539 LONG pos;
7541 ENTER();
7543 D(DBF_LISTTREE, "NList Remove listnode: 0x%lx treenode: 0x%lx",msg->ListNode,msg->TreeNode);
7545 DeactivateNotify( data );
7548 ** Removed, because of problems when deleting entries in a loop (all selected)
7550 //DoQuiet( data, TRUE );
7552 data->TempActiveNode = data->ActiveNode;
7557 switch( (IPTR)msg->ListNode )
7559 case MUIV_NListtree_Remove_ListNode_Root:
7560 li = &data->RootList;
7561 break;
7563 case MUIV_NListtree_Remove_ListNode_Active:
7564 li = data->ActiveList;
7565 break;
7567 default:
7568 li = CLN( msg->ListNode );
7569 break;
7575 if ( li )
7577 switch( (IPTR)msg->TreeNode )
7579 case MUIV_NListtree_Remove_TreeNode_Head:
7580 tn = CTN( GetHead( (struct List *)&li->ln_List ) );
7581 break;
7583 case MUIV_NListtree_Remove_TreeNode_Tail:
7584 tn = CTN( GetTail( (struct List *)&li->ln_List ) );
7585 break;
7587 case MUIV_NListtree_Remove_TreeNode_Active:
7588 tn = data->ActiveNode;
7589 break;
7591 case MUIV_NListtree_Remove_TreeNode_All:
7593 pos = GetVisualPos( data, CTN( GetHead( (struct List *)&li->ln_List ) ) );
7595 // make sure we are quiet, and the selection change
7596 // is not propagated
7597 DoQuiet( data, TRUE );
7598 data->IgnoreSelectionChange = 1;
7600 while((tn = CTN( GetHead((struct List *)&li->ln_List))))
7601 RemoveNodes( data, li, tn, pos );
7603 // reactive selection list
7604 data->IgnoreSelectionChange = 0;
7605 DoQuiet(data, FALSE);
7607 tn = NULL;
7609 break;
7611 case MUIV_NListtree_Remove_TreeNode_Selected:
7613 if(data->SelectedTable.tb_Entries > 0)
7615 // make sure we are quiet, and the selection change
7616 // is not propagated
7617 DoQuiet( data, TRUE );
7618 data->IgnoreSelectionChange = 1;
7622 tn = data->SelectedTable.tb_Table[0];
7623 pos = GetVisualPos( data, tn );
7624 RemoveNodes( data, CLN( tn->tn_Parent ), tn, pos );
7626 while(data->SelectedTable.tb_Entries > 0);
7628 // reactive selection list
7629 data->IgnoreSelectionChange = 0;
7631 if(data->TempActiveNode != NULL &&
7632 NLFindInTable(&data->SelectedTable, data->TempActiveNode) == -1)
7634 TreeNodeSelectAdd(data, data->TempActiveNode);
7635 SET_FLAG(data->TempActiveNode->tn_Flags, TNF_SELECTED);
7637 MakeNotify(data, MUIA_NListtree_SelectChange, (APTR)TRUE);
7640 DoQuiet( data, FALSE );
7643 tn = NULL;
7645 break;
7647 default:
7648 tn = msg->TreeNode;
7649 break;
7652 if ( tn )
7654 BOOL dorefresh = FALSE;
7656 pos = GetVisualPos( data, tn );
7658 D(DBF_LISTTREE, "Node: 0x%08lx - Name: %s - pos: %ld", tn, tn->tn_Name, pos);
7660 if(isFlagSet(tn->tn_IFlags, TNIF_VISIBLE))
7661 dorefresh = TRUE;
7663 RemoveNodes( data, li, tn, pos );
7665 if ( dorefresh )
7666 DoRefresh( data );
7668 D(DBF_LISTTREE, "Activenode: 0x%lx Trmpactivenode: 0x%lx",data->ActiveNode,data->TempActiveNode);
7670 /* sba: Notification is deactivated so we get not informed if the active node changed,
7671 ** do this by hand now
7673 if (data->TempActiveNode != data->ActiveNode)
7675 nnset(data->Obj, MUIA_NListtree_Active, data->TempActiveNode);
7676 data->ForceActiveNotify = 1;
7682 if(isFlagClear(msg->Flags, MUIV_NListtree_Remove_Flag_NoActive))
7684 if ( data->TempActiveNode == tn )
7685 data->TempActiveNode = NULL;
7687 D(bug( "Set Active node: 0x%8lx\n",data->TempActiveNode) );
7689 MakeSet( data, MUIA_NListtree_Active, data->TempActiveNode );
7691 if ( data->TempActiveNode && ( data->MultiSelect != MUIV_NListtree_MultiSelect_None ) )
7693 TreeNodeSelect( data, data->TempActiveNode, MUIV_NListtree_Select_On, 0, 0 );
7697 data->TempActiveNode = NULL;
7700 ** Removed, because of problems when deleting entries in a loop (all selected)
7702 //DoQuiet( data, FALSE );
7703 ActivateNotify( data );
7705 /* sba: the active note could be changed, but the notify calling was disabled */
7706 DoMethod(data->Obj, MUIM_NListtree_GetListActive, 0);
7708 RETURN(0);
7709 return( 0 );
7714 /****** NListtree.mcc/MUIM_NListtree_Clear ***********************************
7716 * NAME
7718 * MUIM_NListtree_Clear -- Clear the complete listview. (V1)
7721 * SYNOPSIS
7723 * DoMethod(obj, MUIM_NListtree_Clear, NULL, 0)
7726 * FUNCTION
7728 * Clear the complete listview, calling destruct hook for each entry.
7731 * INPUTS
7733 * RESULT
7735 * EXAMPLE
7737 * // Clear the listview!
7738 * DoMethod( nlisttree, MUIM_NListtree_Clear, NULL, 0 );
7741 * NOTES
7743 * For now, when using this method, you MUST supply NULL for the list
7744 * node and 0 for flags for future compatibility.
7745 * This will definitely change!
7748 * BUGS
7750 * SEE ALSO
7752 * MUIM_NListtree_Remove, MUIA_NListtree_DestructHook,
7755 ******************************************************************************
7758 IPTR _NListtree_Clear(struct IClass *cl, Object *obj, UNUSED struct MUIP_NListtree_Clear *msg)
7760 struct NListtree_Data *data = INST_DATA(cl, obj);
7761 struct MUI_NListtree_ListNode *ln = NULL;
7763 ENTER();
7765 ln = &data->RootList;
7771 switch( (ULONG)msg->ListNode )
7773 case MUIV_NListtree_Clear_ListNode_Root:
7774 ln = &data->RootList;
7775 break;
7777 case MUIV_NListtree_Clear_ListNode_Active:
7778 ln = data->ActiveList;
7779 break;
7781 default:
7782 ln = CLN( msg->ListNode );
7783 break;
7788 if ( ln )
7791 ** Quick clear the NList object, call the destruct hook for
7792 ** each entry (QuickRemoveNodes()), delete the tree pool and
7793 ** allocate it new, reset the root list and delete the table
7794 ** memory pointer which refers to the old pool. Then initialize
7795 ** active node and list.
7797 DoMethod( obj, MUIM_NList_Clear, 0 );
7799 QuickRemoveNodes( data, ln );
7801 if(data->TreePool != NULL)
7803 #if defined(__amigaos4__)
7804 FreeSysObject(ASOT_MEMPOOL, data->TreePool);
7805 #else
7806 DeletePool(data->TreePool);
7807 #endif
7810 #if defined(__amigaos4__)
7811 data->TreePool = AllocSysObjectTags(ASOT_MEMPOOL, ASOPOOL_MFlags, MEMF_SHARED|MEMF_CLEAR,
7812 ASOPOOL_Puddle, 16384,
7813 ASOPOOL_Threshold, 4096,
7814 ASOPOOL_Name, "NListtree.mcc tree pool",
7815 ASOPOOL_LockMem, FALSE,
7816 TAG_DONE);
7817 #else
7818 data->TreePool = CreatePool(MEMF_CLEAR, 16384, 4096);
7819 #endif
7821 NewList( (struct List *)&data->RootList.ln_List );
7822 data->RootList.ln_Table.tb_Table = NULL;
7823 data->RootList.ln_Table.tb_Entries = 0;
7824 data->RootList.ln_Table.tb_Size = 0;
7825 data->NumEntries = 0;
7827 data->ActiveNode = MUIV_NListtree_Active_Off;
7828 data->ActiveList = &data->RootList;
7832 RETURN(0);
7833 return( 0 );
7838 /****** NListtree.mcc/MUIM_NListtree_Exchange ********************************
7840 * NAME
7842 * MUIM_NListtree_Exchange -- Exchanges two tree nodes. (V1)
7845 * SYNOPSIS
7847 * DoMethod(obj, MUIM_NListtree_Exchange,
7848 * struct MUI_NListtree_TreeNode *listnode1,
7849 * struct MUI_NListtree_TreeNode *treenode1,
7850 * struct MUI_NListtree_TreeNode *listnode2,
7851 * struct MUI_NListtree_TreeNode *treenode2,
7852 * ULONG flags);
7855 * FUNCTION
7857 * Exchange two tree nodes.
7860 * INPUTS
7862 * listnode1 - Specify the list node of the entry which
7863 * should be exchanged.
7865 * MUIV_NListtree_Exchange_ListNode1_Root
7866 * The root list is used.
7868 * MUIV_NListtree_Exchange_ListNode1_Active
7869 * The active list (the list of the active node) is used.
7871 * treenode1 - Specify the node which should be exchanged.
7873 * MUIV_NListtree_Exchange_TreeNode1_Head
7874 * The head of the list defined in 'listnode1' is
7875 * exchanged.
7877 * MUIV_NListtree_Exchange_TreeNode1_Tail
7878 * The tail of the list defined in 'listnode1' is
7879 * exchanged.
7881 * MUIV_NListtree_Exchange_TreeNode1_Active
7882 * The active node is exchanged.
7884 * listnode2 - Specify the second list node which is used for exchange.
7886 * MUIV_NListtree_Exchange_ListNode2_Root
7887 * The root list.
7889 * MUIV_NListtree_Exchange_ListNode2_Active
7890 * The list of the active node.
7892 * treenode2 - This node is the second entry which is exchanged.
7894 * MUIV_NListtree_Exchange_TreeNode2_Head
7895 * The node 'treenode1' is exchanged with the head of the
7896 * list defined in 'listnode2'.
7898 * MUIV_NListtree_Exchange_TreeNode2_Tail
7899 * The node 'treenode1' is exchanged with the tail of the
7900 * list defined in 'ln2'.
7902 * MUIV_NListtree_Exchange_TreeNode2_Active:
7903 * The node 'treenode1' is exchanged with the active node.
7905 * MUIV_NListtree_Exchange_TreeNode2_Up:
7906 * The node 'treenode1' is exchanged with the entry
7907 * previous to the one specified in 'treenode1'.
7909 * MUIV_NListtree_Exchange_TreeNode2_Down:
7910 * The node 'treenode1' is exchanged with the entry next
7911 * (the successor) to the one specified in 'treenode1'.
7914 * RESULT
7916 * EXAMPLE
7918 * // Exchange the active entry with the successor.
7919 * DoMethod(obj,
7920 * MUIV_NListtree_Exchange_ListNode1_Active,
7921 * MUIV_NListtree_Exchange_TreeNode1_Active,
7922 * MUIV_NListtree_Exchange_ListNode2_Active,
7923 * MUIV_NListtree_Exchange_TreeNode2_Down,
7924 * 0);
7927 * NOTES
7929 * BUGS
7931 * SEE ALSO
7933 * MUIM_NListtree_Move, MUIM_NListtree_Insert,
7934 * MUIM_NListtree_Remove
7937 ******************************************************************************
7940 IPTR _NListtree_Exchange(struct IClass *cl, Object *obj, struct MUIP_NListtree_Exchange *msg)
7942 struct NListtree_Data *data = INST_DATA(cl, obj);
7943 struct MUI_NListtree_ListNode *ln1, *ln2;
7944 struct MUI_NListtree_TreeNode *tn1, *tn2;
7945 struct Node *insnode1, *insnode2;
7946 LONG pos1, pos2;
7949 ** Handle all special events.
7951 switch( (IPTR)msg->ListNode1 )
7953 case MUIV_NListtree_Exchange_ListNode1_Root:
7954 ln1 = &data->RootList;
7955 break;
7957 case MUIV_NListtree_Exchange_ListNode1_Active:
7958 ln1 = data->ActiveList;
7959 break;
7961 default:
7962 ln1 = CLN( msg->ListNode1 );
7963 break;
7966 switch( (IPTR)msg->TreeNode1 )
7968 case MUIV_NListtree_Exchange_TreeNode1_Head:
7969 tn1 = CTN( GetHead( (struct List *)&ln1->ln_List ) );
7970 break;
7972 case MUIV_NListtree_Exchange_TreeNode1_Tail:
7973 tn1 = CTN( GetTail( (struct List *)&ln1->ln_List ) );
7974 break;
7976 case MUIV_NListtree_Exchange_TreeNode1_Active:
7977 tn1 = data->ActiveNode;
7978 break;
7980 default:
7981 tn1 = msg->TreeNode1;
7982 break;
7985 switch( (IPTR)msg->ListNode2 )
7987 case MUIV_NListtree_Exchange_ListNode2_Root:
7988 ln2 = &data->RootList;
7989 break;
7991 case MUIV_NListtree_Exchange_ListNode2_Active:
7992 ln2 = data->ActiveList;
7993 break;
7995 default:
7996 ln2 = CLN( msg->ListNode2 );
7997 break;
8000 switch( (IPTR)msg->TreeNode2 )
8002 case MUIV_NListtree_Exchange_TreeNode2_Head:
8003 tn2 = CTN( GetHead( (struct List *)&ln1->ln_List ) );
8004 break;
8006 case MUIV_NListtree_Exchange_TreeNode2_Tail:
8007 tn2 = CTN( GetTail( (struct List *)&ln1->ln_List ) );
8008 break;
8010 case MUIV_NListtree_Exchange_TreeNode2_Active:
8011 tn2 = data->ActiveNode;
8012 break;
8014 case MUIV_NListtree_Exchange_TreeNode2_Up:
8015 if ( !( tn2 = CTN( GetPred( (struct Node *)&tn1->tn_Node ) ) ) )
8016 tn2 = CTN( tn1->tn_Node.mln_Pred );
8017 break;
8019 case MUIV_NListtree_Exchange_TreeNode2_Down:
8020 if ( !( tn2 = CTN( GetSucc( (struct Node *)&tn1->tn_Node ) ) ) )
8021 tn2 = CTN( tn1->tn_Node.mln_Succ );
8022 break;
8024 default:
8025 tn2 = msg->TreeNode2;
8026 break;
8030 if ( tn1 != tn2 )
8032 DoQuiet( data, TRUE );
8035 ** Get the nodes where to re-insert the removed nodes.
8036 ** If no previsous node available, then Insert() assumes
8037 ** AddHead() when "insnodeX" is NULL.
8039 insnode1 = GetPred( (struct Node *)tn1 );
8040 insnode2 = GetPred( (struct Node *)tn2 );
8042 if ( insnode1 == (struct Node *)tn2 )
8043 insnode1 = GetPred( insnode1 );
8045 if ( insnode2 == (struct Node *)tn1 )
8046 insnode2 = GetPred( insnode2 );
8048 //D(bug( "Node1: 0x%08lx - %s, Node2: 0x%08lx - %s", tn1, tn1->tn_Name, tn2, tn2->tn_Name ) );
8051 ** Remove entry 1.
8053 NLRemoveFromTable( data, &ln1->ln_Table, tn1 );
8054 RemoveTreeNodeVisible( data, tn1, &pos1 );
8055 Remove( (struct Node *)&tn1->tn_Node );
8058 ** Remove entry 2.
8060 NLRemoveFromTable( data, &ln2->ln_Table, tn2 );
8061 RemoveTreeNodeVisible( data, tn2, &pos2 );
8062 Remove( (struct Node *)&tn2->tn_Node );
8066 ** Set new parent entries and visibility.
8068 tn1->tn_Parent = CTN( ln2 );
8069 tn2->tn_Parent = CTN( ln1 );
8072 ** Insert first entry in the list.
8074 if ( !insnode2 )
8076 AddHead( (struct List *)&ln2->ln_List, (struct Node *)tn1 );
8077 InsertTreeNodeVisible( data, tn1, ln2, CTN( INSERT_POS_HEAD ) );
8078 NLAddToTable( data, &ln2->ln_Table, tn1 );
8080 else
8082 Insert( (struct List *)&ln2->ln_List, (struct Node *)tn1, insnode2 );
8083 InsertTreeNodeVisible( data, tn1, ln2, CTN( insnode2 ) );
8084 NLAddToTable( data, &ln2->ln_Table, tn1 );
8088 ** Insert second entry in the list.
8090 if ( !insnode1 )
8092 if ( !insnode2 && ( pos1 > pos2 ) )
8094 Insert( (struct List *)&ln1->ln_List, (struct Node *)tn2, (struct Node *)tn1 );
8095 InsertTreeNodeVisible( data, tn2, ln1, tn1 );
8096 NLAddToTable( data, &ln1->ln_Table, tn2 );
8098 else
8100 AddHead( (struct List *)&ln1->ln_List, (struct Node *)tn2 );
8101 InsertTreeNodeVisible( data, tn2, ln1, CTN( INSERT_POS_HEAD ) );
8102 NLAddToTable( data, &ln1->ln_Table, tn2 );
8105 else
8107 Insert( (struct List *)&ln1->ln_List, (struct Node *)tn2, insnode1 );
8108 InsertTreeNodeVisible( data, tn2, ln1, CTN( insnode1 ) );
8109 NLAddToTable( data, &ln1->ln_Table, tn2 );
8112 DoRefresh( data );
8114 if ( tn1 == data->ActiveNode )
8115 nnset( obj, MUIA_NListtree_Active, tn1 );
8116 else if ( tn2 == data->ActiveNode )
8117 nnset( obj, MUIA_NListtree_Active, tn2 );
8119 DoQuiet( data, FALSE );
8122 return( 0 );
8127 /****** NListtree.mcc/MUIM_NListtree_Move ************************************
8129 * NAME
8131 * MUIM_NListtree_Move -- Move an entry to the specified position. (V1)
8134 * SYNOPSIS
8136 * DoMethod(obj, MUIM_NListtree_Move,
8137 * struct MUI_NListtree_TreeNode *oldlistnode,
8138 * struct MUI_NListtree_TreeNode *oldtreenode,
8139 * struct MUI_NListtree_TreeNode *newlistnode,
8140 * struct MUI_NListtree_TreeNode *newtreenode,
8141 * ULONG flags);
8144 * FUNCTION
8146 * Move an entry to the position after a defined node.
8149 * INPUTS
8151 * oldlistnode - Specify the node which list is used to find the
8152 * entry. The search is started at the head of this
8153 * list.
8155 * MUIV_NListtree_Move_OldListNode_Root
8156 * The root list is used as the starting point.
8158 * MUIV_NListtree_Move_OldListNode_Active
8159 * The active list (the list of the active node) is used as
8160 * the starting point.
8162 * oldtreenode - Specify the node which should be moved.
8164 * MUIV_NListtree_Move_OldTreeNode_Head
8165 * The head of the list defined in 'oldlistnode' is moved.
8167 * MUIV_NListtree_Move_OldTreeNode_Tail
8168 * The tail of the list defined in 'oldlistnode' is moved.
8170 * MUIV_NListtree_Move_OldTreeNode_Active
8171 * The active node is moved.
8173 * newlistnode - Specify the node which list is used to find the
8174 * entry. The search is started at the head of this
8175 * list.
8177 * MUIV_NListtree_Move_NewListNode_Root
8178 * The root list.
8180 * MUIV_NListtree_Move_NewListNode_Active
8181 * The list of the active node.
8183 * newtreenode - This node is the predecessor of the entry which is
8184 * inserted.
8186 * MUIV_NListtree_Move_NewTreeNode_Head
8187 * The node is moved to the head of the list defined in
8188 * 'newlistnode'.
8190 * MUIV_NListtree_Move_NewTreeNode_Tail
8191 * The node is moved to the tail of the list defined in
8192 * 'newlistnode'.
8194 * MUIV_NListtree_Move_NewTreeNode_Active:
8195 * The node is moved to one entry after the active node.
8197 * MUIV_NListtree_Move_NewTreeNode_Sorted:
8198 * The node is moved to the list using the sort hook.
8200 * flags - Some flags to adjust moving.
8202 * MUIV_NListtree_Move_Flag_KeepStructure
8203 * The full tree structure from the selected entry to
8204 * the root list is moved (created at destination).
8207 * RESULT
8209 * EXAMPLE
8211 * // Move an entry to the head of another list-node.
8212 * DoMethod(obj,
8213 * MUIV_NListtree_Move_OldListNode_Active,
8214 * MUIV_NListtree_Move_OldTreeNode_Active,
8215 * somelistmode,
8216 * MUIV_NListtree_Move_NewTreeNode_Head,
8217 * 0);
8220 * NOTES
8222 * BUGS
8224 * SEE ALSO
8226 * MUIM_NListtree_Insert, MUIM_NListtree_Remove,
8227 * MUIM_NListtree_Exchange, MUIA_NListtree_CompareHook,
8228 * MUIM_NListtree_Copy
8230 ******************************************************************************
8233 IPTR _NListtree_Move(struct IClass *cl, Object *obj, struct MUIP_NListtree_Move *msg)
8235 struct NListtree_Data *data = INST_DATA(cl, obj);
8236 struct MUI_NListtree_ListNode *ln1, *ln2;
8237 struct MUI_NListtree_TreeNode *tn1, *tn2;
8239 D(DBF_LISTTREE, "MUIM_NListtree_Move");
8242 ** Handle all special events.
8244 switch( (IPTR)msg->OldListNode )
8246 case MUIV_NListtree_Move_OldListNode_Root:
8247 ln1 = &data->RootList;
8248 break;
8250 case MUIV_NListtree_Move_OldListNode_Active:
8251 ln1 = data->ActiveList;
8252 break;
8254 default:
8255 ln1 = CLN( msg->OldListNode );
8256 break;
8259 switch( (IPTR)msg->OldTreeNode )
8261 case MUIV_NListtree_Move_OldTreeNode_Head:
8262 tn1 = CTN( GetHead( (struct List *)&ln1->ln_List ) );
8263 break;
8265 case MUIV_NListtree_Move_OldTreeNode_Tail:
8266 tn1 = CTN( GetTail( (struct List *)&ln1->ln_List ) );
8267 break;
8269 case MUIV_NListtree_Move_OldTreeNode_Active:
8270 tn1 = data->ActiveNode;
8271 break;
8273 default:
8274 tn1 = msg->OldTreeNode;
8275 break;
8278 switch( (IPTR)msg->NewListNode )
8280 case MUIV_NListtree_Move_NewListNode_Root:
8281 ln2 = &data->RootList;
8282 break;
8284 case MUIV_NListtree_Move_NewListNode_Active:
8285 ln2 = data->ActiveList;
8286 break;
8288 default:
8289 ln2 = CLN( msg->NewListNode );
8290 break;
8293 switch( (IPTR)msg->NewTreeNode )
8295 case MUIV_NListtree_Move_NewTreeNode_Head:
8296 tn2 = CTN( INSERT_POS_HEAD );
8297 break;
8299 case MUIV_NListtree_Move_NewTreeNode_Tail:
8300 tn2 = CTN( INSERT_POS_TAIL );
8301 break;
8303 case MUIV_NListtree_Move_NewTreeNode_Active:
8304 tn2 = data->ActiveNode;
8305 break;
8307 case MUIV_NListtree_Move_NewTreeNode_Sorted:
8308 tn2 = GetInsertNodeSorted( data, ln2, tn1 );
8309 break;
8311 default:
8312 tn2 = msg->NewTreeNode;
8313 break;
8317 if ( tn1 != tn2 )
8319 DoQuiet( data, TRUE );
8321 //D(bug( "1: L: %s, N: %s - 2: L: %s, N: %s\n", ln1->ln_Name, tn1->tn_Name, ln2->ln_Name, ( (ULONG)tn2 == INSERT_POS_TAIL ) ? "TAIL" : ( (ULONG)tn2 == INSERT_POS_HEAD ) ? "HEAD" : tn2->tn_Name ) );
8324 ** Remove the entry visible and from list.
8326 NLRemoveFromTable( data, &ln1->ln_Table, tn1 );
8327 RemoveTreeNodeVisible( data, tn1, NULL );
8328 Remove( (struct Node *)&tn1->tn_Node );
8332 ** Create structure identical to source.
8334 if(isFlagSet(msg->Flags, MUIV_NListtree_Move_Flag_KeepStructure))
8336 tn1 = CTN( CreateParentStructure( data, msg->MethodID, &ln2, &tn2, tn1, 0 ) );
8339 if ( tn1 )
8342 ** Insert entry into list.
8344 InsertTreeNode( data, ln2, tn1, tn2 );
8347 DoRefresh( data );
8349 if ( tn1 == data->ActiveNode )
8350 nnset( obj, MUIA_NListtree_Active, tn1 );
8352 DoQuiet( data, FALSE );
8355 D(DBF_LISTTREE, "MUIM_NListtree_Move End");
8357 return( 0 );
8362 /****** NListtree.mcc/MUIM_NListtree_Copy ************************************
8364 * NAME
8366 * MUIM_NListtree_Copy -- Copy an entry (create it) to the spec. pos. (V1)
8369 * SYNOPSIS
8371 * DoMethod(obj, MUIM_NListtree_Copy,
8372 * struct MUI_NListtree_TreeNode *srclistnode,
8373 * struct MUI_NListtree_TreeNode *srctreenode,
8374 * struct MUI_NListtree_TreeNode *destlistnode,
8375 * struct MUI_NListtree_TreeNode *desttreenode,
8376 * ULONG flags);
8379 * FUNCTION
8381 * Copy an entry to the position after a defined node. The complete
8382 * child structure will be copied.
8385 * INPUTS
8387 * srclistnode - Specify the node which list is used to find the
8388 * entry. The search is started at the head of this
8389 * list.
8391 * MUIV_NListtree_Copy_SourceListNode_Root
8392 * The root list is used as the starting point.
8394 * MUIV_NListtree_Copy_SourceListNode_Active
8395 * The active list (the list of the active node) is used as
8396 * the starting point.
8398 * srctreenode - Specifies the node which should be copied.
8400 * MUIV_NListtree_Copy_SourceTreeNode_Head
8401 * The head of the list defined in 'srclistnode' is copied.
8403 * MUIV_NListtree_Copy_SourceTreeNode_Tail
8404 * The tail of the list defined in 'srclistnode' is copied.
8406 * MUIV_NListtree_Copy_SourceTreeNode_Active
8407 * The active node is copied.
8409 * destlistnode - Specify the node which list is used to find the
8410 * entry. The search is started at the head of this
8411 * list.
8413 * MUIV_NListtree_Copy_DestListNode_Root
8414 * The root list.
8416 * MUIV_NListtree_Copy_DestListNode_Active
8417 * The list of the active node.
8419 * desttreenode - This node is the predecessor of the entry which is
8420 * inserted.
8422 * MUIV_NListtree_Copy_DestTreeNode_Head
8423 * The node is copied to the head of the list defined in
8424 * 'destlistnode'.
8426 * MUIV_NListtree_Copy_DestTreeNode_Tail
8427 * The node is copied to the tail of the list defined in
8428 * 'destlistnode'.
8430 * MUIV_NListtree_Copy_DestTreeNode_Active:
8431 * The node is copied to one entry after the active node.
8433 * MUIV_NListtree_Copy_DestTreeNode_Sorted:
8434 * The node is copied to the list using the sort hook.
8436 * flags - Some flags to adjust moving.
8438 * MUIV_NListtree_Copy_Flag_KeepStructure
8439 * The full tree structure from the selected entry to
8440 * the root list is copied (created) at destination.
8443 * RESULT
8445 * EXAMPLE
8447 * // Copy the active entry to the head of
8448 * // another list node.
8449 * DoMethod(obj,
8450 * MUIV_NListtree_Copy_SourceListNode_Active,
8451 * MUIV_NListtree_Copy_SourceTreeNode_Active,
8452 * anylistnode,
8453 * MUIV_NListtree_Copy_DestTreeNode_Head,
8454 * 0);
8457 * NOTES
8459 * BUGS
8461 * SEE ALSO
8463 * MUIM_NListtree_Insert, MUIM_NListtree_Remove,
8464 * MUIM_NListtree_Exchange, MUIA_NListtree_CompareHook,
8465 * MUIM_NListtree_Move
8468 ******************************************************************************
8471 IPTR _NListtree_Copy(struct IClass *cl, Object *obj, struct MUIP_NListtree_Copy *msg)
8473 struct NListtree_Data *data = INST_DATA(cl, obj);
8474 struct MUI_NListtree_ListNode *ln1, *ln2;
8475 struct MUI_NListtree_TreeNode *tn1, *tn2;
8479 ** Handle all special events.
8481 switch( (IPTR)msg->SourceListNode )
8483 case MUIV_NListtree_Copy_SourceListNode_Root:
8484 ln1 = &data->RootList;
8485 break;
8487 case MUIV_NListtree_Copy_SourceListNode_Active:
8488 ln1 = data->ActiveList;
8489 break;
8491 default:
8492 ln1 = CLN( msg->SourceListNode );
8493 break;
8496 switch( (IPTR)msg->SourceTreeNode )
8498 case MUIV_NListtree_Copy_SourceTreeNode_Head:
8499 tn1 = CTN( GetHead( (struct List *)&ln1->ln_List ) );
8500 break;
8502 case MUIV_NListtree_Copy_SourceTreeNode_Tail:
8503 tn1 = CTN( GetTail( (struct List *)&ln1->ln_List ) );
8504 break;
8506 case MUIV_NListtree_Copy_SourceTreeNode_Active:
8507 tn1 = data->ActiveNode;
8508 break;
8510 default:
8511 tn1 = msg->SourceTreeNode;
8512 break;
8515 switch( (IPTR)msg->DestListNode )
8517 case MUIV_NListtree_Copy_DestListNode_Root:
8518 ln2 = &data->RootList;
8519 break;
8521 case MUIV_NListtree_Copy_DestListNode_Active:
8522 ln2 = data->ActiveList;
8523 break;
8525 default:
8526 ln2 = CLN( msg->DestListNode );
8527 break;
8530 switch( (IPTR)msg->DestTreeNode )
8532 case MUIV_NListtree_Copy_DestTreeNode_Head:
8533 tn2 = CTN( INSERT_POS_HEAD );
8534 break;
8536 case MUIV_NListtree_Copy_DestTreeNode_Tail:
8537 tn2 = CTN( INSERT_POS_TAIL );
8538 break;
8540 case MUIV_NListtree_Copy_DestTreeNode_Active:
8541 tn2 = data->ActiveNode;
8542 break;
8544 case MUIV_NListtree_Copy_DestTreeNode_Sorted:
8545 tn2 = GetInsertNodeSorted( data, ln2, tn1 );
8546 break;
8548 default:
8549 tn2 = msg->DestTreeNode;
8550 break;
8554 if ( tn1 != tn2 )
8556 struct MUI_NListtree_TreeNode *savetn1 = tn1;
8558 //D(bug( "1: L: %s, N: %s - 2: L: %s, N: %s\n", ln1->ln_Name, tn1->tn_Name, ln2->ln_Name, ( (ULONG)tn2 == INSERT_POS_TAIL ) ? "TAIL" : tn2->tn_Name ) );
8561 ** Create structure identical to source.
8563 if(isFlagSet(msg->Flags, MUIV_NListtree_Copy_Flag_KeepStructure))
8565 tn1 = CTN( CreateParentStructure( data, msg->MethodID, &ln2, &tn2, tn1, 0 ) );
8567 else
8569 tn1 = DuplicateNode(data, tn1);
8572 tn1 = CreateChildStructure( data, ln2, CLN( tn1 ), CLN( savetn1 ), 0 );
8574 DoRefresh( data );
8577 if ( tn1 == data->ActiveNode )
8578 nnset( obj, MUIA_NListtree_Active, tn1 );
8582 return( 0 );
8587 /****** NListtree.mcc/MUIM_NListtree_Rename **********************************
8589 * NAME
8591 * MUIM_NListtree_Rename -- Rename the specified node. (V1)
8594 * SYNOPSIS
8596 * struct MUI_NListtree_TreeNode *treenode =
8597 * DoMethod(obj, MUIM_NListtree_Rename,
8598 * struct MUI_NListtree_TreeNode *treenode,
8599 * STRPTR newname, ULONG flags);
8602 * FUNCTION
8604 * Rename the specified node.
8606 * If you want to rename the tn_User field (see flags below), the construct
8607 * and destruct hooks are used!
8608 * If you have not specified these hooks, only the pointers will be copied.
8611 * INPUTS
8613 * treenode - Specifies the node which should be renamed.
8615 * MUIV_NListtree_Rename_TreeNode_Active:
8616 * Rename the active tree node.
8618 * newname - The new name or pointer.
8620 * flags:
8622 * MUIV_NListtree_Rename_Flag_User
8623 * The tn_User field is renamed.
8625 * MUIV_NListtree_Rename_Flag_NoRefresh
8626 * The list entry will not be refreshed.
8629 * RESULT
8631 * Returns the pointer of the renamed tree node.
8634 * EXAMPLE
8636 * // Rename the active tree node.
8637 * DoMethod(obj, MUIM_NListtree_Rename,
8638 * MUIV_NListtree_Rename_TreeNode_Active,
8639 * "Very new name", 0);
8642 * NOTES
8644 * BUGS
8646 * SEE ALSO
8648 * MUIA_NListtree_ConstructHook, MUIA_NListtree_DestructHook
8651 ******************************************************************************
8654 IPTR _NListtree_Rename(struct IClass *cl, Object *obj, struct MUIP_NListtree_Rename *msg)
8656 struct NListtree_Data *data = INST_DATA(cl, obj);
8657 struct MUI_NListtree_TreeNode *tn;
8661 ** Handle special events.
8663 if ( (IPTR)msg->TreeNode == (IPTR)MUIV_NListtree_Rename_TreeNode_Active )
8664 tn = data->ActiveNode;
8665 else
8666 tn = msg->TreeNode;
8669 ** User wants to rename the user field instead of name field.
8671 if(isFlagSet(msg->Flags, MUIV_NListtree_Rename_Flag_User))
8673 //D(bug( "Node: 0x%08lx - %s - Renaming user field\n", tn, tn->tn_Name ) );
8675 DoMethod(obj, MUIM_NListtree_Destruct, tn->tn_Name, tn->tn_User, data->TreePool, 0);
8678 ** Construct new user data
8680 tn->tn_User = (APTR)DoMethod(obj, MUIM_NListtree_Construct, tn->tn_Name, msg->NewName, data->TreePool, 0);
8682 else
8684 //D(bug( "Node: 0x%08lx - %s - Renaming name field from \"%s\" to \"%s\"\n", tn, tn->tn_Name, tn->tn_Name, msg->NewName ) );
8687 ** Should we duplicate the supplied node name?
8689 if(isFlagSet(data->Flags, NLTF_DUPNODENAMES))
8691 int len = strlen( msg->NewName ) + 1;
8693 FreeVecPooled( data->TreePool, tn->tn_Name );
8695 tn->tn_Name = (STRPTR)AllocVecPooled( data->TreePool, len );
8696 strlcpy( tn->tn_Name, msg->NewName, len );
8697 SET_FLAG(tn->tn_IFlags, TNIF_ALLOCATED);
8699 else
8700 tn->tn_Name = msg->NewName;
8703 if(isFlagClear(msg->Flags, MUIV_NListtree_Rename_Flag_NoRefresh) && isFlagSet(tn->tn_IFlags, TNIF_VISIBLE))
8704 DoMethod( obj, MUIM_NList_Redraw, GetVisualPos( data, tn ) );
8706 return( (IPTR)tn );
8711 /****** NListtree.mcc/MUIM_NListtree_FindName ********************************
8713 * NAME
8715 * MUIM_NListtree_FindName -- Find node using name match. (V1)
8718 * SYNOPSIS
8720 * struct MUI_NListtree_TreeNode *treenode =
8721 * DoMethod(obj, MUIM_NListtree_FindName,
8722 * struct MUI_NListtree_TreeNode *listnode,
8723 * STRPTR name, ULONG flags);
8726 * FUNCTION
8728 * Find a node which name matches the specified one using the list node as
8729 * start point..
8732 * INPUTS
8733 * listnode - Specify the node which list is used to find the name.
8735 * MUIV_NListtree_FindName_ListNode_Root
8736 * Use the root list as the base list.
8738 * MUIV_NListtree_FindName_ListNode_Active
8739 * Use the list of the active node as the base.
8741 * name - Specify the name of the node to find. But you can search
8742 * for anything in tn_Name or tn_User field here by simply
8743 * supplying the searched data and handling it in your
8744 * own FindNameHook.
8746 * flags:
8748 * MUIV_NListtree_FindName_Flag_SameLevel
8749 * Only nodes on the same level are affected.
8751 * MUIV_NListtree_FindName_Flag_Visible
8752 * The node is only returned if it is visible (only visible
8753 * entries are checked).
8755 * MUIV_NListtree_FindName_Flag_Activate
8756 * If found, the entry will be activated.
8758 * MUIV_NListtree_FindName_Flag_Selected
8759 * Find only selected nodes.
8761 * MUIV_NListtree_FindName_Flag_StartNode
8762 * The specified entry in listnode is the start point for
8763 * search and must not be a list node. It can also be a
8764 * normal entry.
8766 * RESULT
8768 * Returns the found node if available, NULL otherwise.
8771 * EXAMPLE
8773 * // Find 2nd node by name.
8774 * struct MUI_NListtree_TreeNode *treenode =
8775 * DoMethod(obj, MUIM_NListtree_FindName,
8776 * listnode, "2nd node",
8777 * MUIV_NListtree_FindName_SameLevel|
8778 * MUIV_NListtree_FindName_Visible);
8780 * if ( treenode == NULL )
8782 * PrintToUser( "No matching entry found." );
8786 * NOTES
8788 * BUGS
8790 * SEE ALSO
8792 * MUIM_NListtree_FindUserData, MUIM_NListtree_GetEntry,
8793 * MUIA_NListtree_FindNameHook
8796 ******************************************************************************
8799 IPTR _NListtree_FindName(struct IClass *cl, Object *obj, struct MUIP_NListtree_FindName *msg)
8801 struct NListtree_Data *data = INST_DATA(cl, obj);
8802 struct MUI_NListtree_ListNode *ln;
8803 struct MUI_NListtree_TreeNode *tn;
8807 ** Handle special events.
8809 switch( (IPTR)msg->ListNode )
8811 case MUIV_NListtree_FindName_ListNode_Root:
8812 ln = &data->RootList;
8813 break;
8815 case MUIV_NListtree_FindName_ListNode_Active:
8816 ln = data->ActiveList;
8817 break;
8819 default:
8820 ln = CLN( msg->ListNode );
8821 break;
8824 //D(bug( "StartNode: 0x%08lx - %s - Searching for \"%s\"\n", ln, ln->ln_Name, msg->Name ) );
8826 if(isFlagSet(msg->Flags, MUIV_NListtree_FindName_Flag_Reverse))
8828 if((tn = FindTreeNodeByNameRev(data, ln, msg->Name, msg->Flags)))
8829 if(isFlagSet(msg->Flags, MUIV_NListtree_FindName_Flag_Activate))
8830 nnset( obj, MUIA_NListtree_Active, tn );
8832 else
8834 if((tn = FindTreeNodeByName(data, ln, msg->Name, msg->Flags)))
8835 if(isFlagSet(msg->Flags, MUIV_NListtree_FindName_Flag_Activate))
8836 nnset( obj, MUIA_NListtree_Active, tn );
8839 return( (IPTR)tn );
8844 /****** NListtree.mcc/MUIM_NListtree_FindUserData ****************************
8846 * NAME
8848 * MUIM_NListtree_FindUserData -- Find node upon user data. (V1)
8851 * SYNOPSIS
8853 * struct MUI_NListtree_TreeNode *treenode =
8854 * DoMethod(obj, MUIM_NListtree_FindUserData,
8855 * struct MUI_NListtree_TreeNode *listnode,
8856 * APTR userdata, ULONG flags);
8859 * FUNCTION
8861 * Find a node which user data matches the specified one using the list
8862 * node as start point..
8863 * This method is designed as a second possibility for searching.
8864 * Because you are able to search for anything, you may set special
8865 * hooks for searching two different fields in two different hooks with
8866 * these two methods.
8869 * INPUTS
8870 * listnode - Specify the node which list is used to find the user data.
8872 * MUIV_NListtree_FindUserData_ListNode_Root
8873 * Use the root list as the base list.
8875 * MUIV_NListtree_FindUserData_ListNode_Active
8876 * Use the list of the active node as the base.
8878 * userdata - Specify the user data of the node to find. You can search
8879 * for anything in tn_Name or tn_User field here by simply
8880 * supplying the searched data and handling it in your
8881 * own FindUserDataHook.
8883 * flags:
8885 * MUIV_NListtree_FindUserData_Flag_SameLevel
8886 * Only nodes on the same level are affected.
8888 * MUIV_NListtree_FindUserData_Flag_Visible
8889 * The node is only returned if it is visible (only visible
8890 * entries are checked).
8892 * MUIV_NListtree_FindUserData_Flag_Activate
8893 * If found, the entry will be activated.
8895 * MUIV_NListtree_FindUserData_Flag_Selected
8896 * Find only selected nodes.
8898 * MUIV_NListtree_FindUserData_Flag_StartNode
8899 * The specified entry in listnode is the start point for
8900 * search and must not be a list node. It can also be a
8901 * normal entry.
8903 * RESULT
8905 * Returns the found node if available, NULL otherwise.
8908 * EXAMPLE
8910 * // Find node by user data.
8911 * struct MUI_NListtree_TreeNode *treenode =
8912 * DoMethod(obj, MUIM_NListtree_FindUserData,
8913 * listnode, "my data",
8914 * MUIV_NListtree_FindUserData_SameLevel|
8915 * MUIV_NListtree_FindUserData_Visible);
8917 * if ( treenode == NULL )
8919 * PrintToUser( "No matching entry found." );
8923 * NOTES
8925 * BUGS
8927 * SEE ALSO
8929 * MUIM_NListtree_FindName, MUIM_NListtree_GetEntry,
8930 * MUIA_NListtree_FindUserDataHook
8933 ******************************************************************************
8936 IPTR _NListtree_FindUserData(struct IClass *cl, Object *obj, struct MUIP_NListtree_FindUserData *msg)
8938 struct NListtree_Data *data = INST_DATA(cl, obj);
8939 struct MUI_NListtree_ListNode *ln;
8940 struct MUI_NListtree_TreeNode *tn;
8944 ** Handle special events.
8946 switch( (IPTR)msg->ListNode )
8948 case MUIV_NListtree_FindUserData_ListNode_Root:
8949 ln = &data->RootList;
8950 break;
8952 case MUIV_NListtree_FindUserData_ListNode_Active:
8953 ln = data->ActiveList;
8954 break;
8956 default:
8957 ln = CLN( msg->ListNode );
8958 break;
8961 //D(bug( "StartNode: 0x%08lx - %s - Searching for \"%s\"\n", ln, ln->ln_Name, (STRPTR)msg->User ) );
8963 if(isFlagSet(msg->Flags, MUIV_NListtree_FindUserData_Flag_Reverse))
8965 if((tn = FindTreeNodeByUserDataRev(data, ln, msg->User, msg->Flags)))
8966 if(isFlagSet(msg->Flags, MUIV_NListtree_FindUserData_Flag_Activate))
8967 nnset( obj, MUIA_NListtree_Active, tn );
8969 else
8971 if((tn = FindTreeNodeByUserData(data, ln, msg->User, msg->Flags)))
8972 if(isFlagSet(msg->Flags, MUIV_NListtree_FindUserData_Flag_Activate))
8973 nnset( obj, MUIA_NListtree_Active, tn );
8976 return( (IPTR)tn );
8981 /****** NListtree.mcc/MUIM_NListtree_GetEntry ********************************
8983 * NAME
8985 * MUIM_NListtree_GetEntry -- Get another node in relation to this. (V1)
8988 * SYNOPSIS
8990 * struct MUI_NListtree_TreeNode *rettreenode =
8991 * DoMethod(obj, MUIM_NListtree_GetEntry,
8992 * struct MUI_NListtree_TreeNode *treenode,
8993 * LONG pos, ULONG flags);
8996 * FUNCTION
8998 * Get another node in relation to the specified list or node.
9001 * INPUTS
9003 * treenode - Define the node which is used to find another one.
9004 * This can also be a list node, if the position is
9005 * related to a list.
9007 * MUIV_NListtree_GetEntry_ListNode_Root
9008 * The root list is used.
9010 * MUIV_NListtree_GetEntry_ListNode_Active:
9011 * The list with the active entry is used.
9013 * pos - The relative position of the node 'treenode'.
9015 * MUIV_NListtree_GetEntry_Position_Head
9016 * The head of the list is returned.
9018 * MUIV_NListtree_GetEntry_Position_Tail
9019 * The tail of the list is returned.
9021 * MUIV_NListtree_GetEntry_Position_Active
9022 * The active node is returned. If there is no active entry,
9023 * NULL is returned.
9025 * MUIV_NListtree_GetEntry_Position_Next
9026 * The node next to the specified node is returned. Returns NULL
9027 * if there is no next entry.
9029 * MUIV_NListtree_GetEntry_Position_Previous
9030 * The node right before the specified node is returned.
9031 * Returns NULL if there is no previous entry (if 'treenode'
9032 * is the head of the list.
9034 * MUIV_NListtree_GetEntry_Position_Parent
9035 * The list node of the specified 'treenode' is returned.
9037 * flags:
9039 * MUIV_NListtree_GetEntry_Flag_SameLevel:
9040 * Only nodes in the same level are affected.
9042 * MUIV_NListtree_GetEntry_Flag_Visible:
9043 * The position is counted on visible entries only.
9046 * RESULT
9048 * Returns the requested node if available, NULL otherwise.
9051 * EXAMPLE
9053 * // Get the next entry.
9054 * struct MUI_NListtree_TreeNode *treenode =
9055 * DoMethod(obj, MUIM_NListtree_GetEntry, treenode,
9056 * MUIV_NListtree_GetEntry_Position_Next, 0);
9058 * if ( treenode )
9060 * PrintToUser( "Next entry found!" );
9064 * NOTES
9066 * BUGS
9068 * SEE ALSO
9070 * MUIM_NList_GetEntry
9073 ******************************************************************************
9076 IPTR _NListtree_GetEntry(struct IClass *cl, Object *obj, struct MUIP_NListtree_GetEntry *msg)
9078 struct NListtree_Data *data = INST_DATA(cl, obj);
9079 struct MUI_NListtree_TreeNode *tn = NULL;
9080 struct MUI_NListtree_ListNode *ln;
9081 LONG pos = 0;
9084 ** Handle special events.
9086 switch( (IPTR)msg->Node )
9088 case MUIV_NListtree_GetEntry_ListNode_Root:
9089 ln = &data->RootList;
9090 break;
9092 case MUIV_NListtree_GetEntry_ListNode_Active:
9093 ln = data->ActiveList;
9094 break;
9096 case -1:
9097 ln = data->ActiveList;
9098 break;
9100 default:
9101 ln = CLN( msg->Node );
9102 break;
9105 switch( (IPTR)(SIPTR)msg->Position )
9107 case MUIV_NListtree_GetEntry_Position_Head:
9109 if(isFlagSet(ln->ln_Flags, TNF_LIST))
9110 tn = CTN( GetHead( (struct List *)&ln->ln_List ) );
9111 break;
9113 case MUIV_NListtree_GetEntry_Position_Tail:
9115 if(isFlagSet(ln->ln_Flags, TNF_LIST))
9116 tn = CTN( GetTail( (struct List *)&ln->ln_List ) );
9117 break;
9119 case MUIV_NListtree_GetEntry_Position_Active:
9121 tn = data->ActiveNode;
9122 break;
9124 case MUIV_NListtree_GetEntry_Position_Next:
9126 tn = CTN( GetSucc( (struct Node *)&ln->ln_Node ) );
9127 break;
9129 case MUIV_NListtree_GetEntry_Position_Previous:
9131 tn = CTN( GetPred( (struct Node *)&ln->ln_Node ) );
9132 break;
9134 case MUIV_NListtree_GetEntry_Position_Parent:
9136 tn = GetParent( CTN( ln ) );
9137 break;
9139 case MUIV_NListtree_GetEntry_Position_Root:
9141 tn = CTN( (APTR)&data->RootList );
9142 break;
9144 default:
9145 tn = GetEntryByTotalPos( ln, msg->Position, &pos, msg->Flags );
9146 break;
9149 //D(bug( "ListNode: 0x%08lx - Pos: 0x%08lx, Flags: 0x%08lx ==> Entry: 0x%08lx\n", msg->Node, msg->Position, msg->Flags, tn ) );
9151 return( (IPTR)tn );
9156 /****** NListtree.mcc/MUIM_NListtree_GetNr ***********************************
9158 * NAME
9160 * MUIM_NListtree_GetNr -- Get the position number of a tree node. (V1)
9163 * SYNOPSIS
9165 * ULONG number = DoMethod(obj, MUIM_NListtree_GetNr,
9166 * struct MUI_NListtree_TreeNode *treenode, ULONG flags);
9169 * FUNCTION
9171 * Get the position number of the specified tree node.
9174 * INPUTS
9176 * treenode - Specify the node to count the position of.
9178 * MUIV_NListtree_GetNr_TreeNode_Active:
9179 * The position is counted related to the active node.
9181 * MUIV_NListtree_GetNr_TreeNode_Root:
9182 * The position is counted related to the root list.
9184 * flags:
9186 * MUIV_NListtree_GetNr_Flag_CountAll
9187 * Returns the number of all entries.
9189 * MUIV_NListtree_GetNr_Flag_CountLevel
9190 * Returns the number of entries of the list the
9191 * specified node is in.
9193 * MUIV_NListtree_GetNr_Flag_CountList
9194 * Returns the number of entries in the specified
9195 * treenode if it holds other entries/is a list.
9197 * MUIV_NListtree_GetNr_Flag_ListEmpty
9198 * Returns TRUE if the specified list node is empty.
9200 * MUIV_NListtree_GetNr_Flag_Visible
9201 * Returns the position number of an visible entry. -1 if the
9202 * entry is invisible. The position is counted on visible entries
9203 * only.
9206 * RESULT
9208 * EXAMPLE
9210 * // Check if the active (list) node is empty.
9211 * ULONG empty = DoMethod(obj, MUIM_NListtree_GetNr,
9212 * MUIV_NListtree_GetNr_TreeNode_Active,
9213 * MUIV_NListtree_GetNr_Flag_ListEmpty);
9215 * if ( empty == TRUE )
9217 * AddThousandEntries();
9220 * NOTES
9222 * BUGS
9224 * SEE ALSO
9226 * MUIM_NListtree_GetEntry
9228 ******************************************************************************
9231 IPTR _NListtree_GetNr(struct IClass *cl, Object *obj, struct MUIP_NListtree_GetNr *msg)
9233 struct NListtree_Data *data = INST_DATA(cl, obj);
9234 struct MUI_NListtree_TreeNode *tn;
9235 struct MUI_NListtree_ListNode *pln;
9236 struct MUI_NListtree_ListNode *ln;
9237 IPTR ret = 0;
9238 LONG pos = 0;
9240 D(DBF_LISTTREE, "GetNr: NListtree entries %ld",data->NumEntries);
9243 ** Handle special events.
9245 if ( (IPTR)msg->TreeNode == (IPTR)MUIV_NListtree_GetNr_TreeNode_Active )
9246 tn = data->ActiveNode;
9247 else if ( (IPTR)msg->TreeNode == (IPTR)MUIV_NListtree_GetNr_TreeNode_Root )
9248 tn = CTN((APTR)&data->RootList);
9249 else
9250 tn = msg->TreeNode;
9252 ln = CLN( tn );
9253 pln = CLN( GetParent( tn ) );
9255 if(isFlagSet(msg->Flags, MUIV_NListtree_GetNr_Flag_ListEmpty))
9257 if(isFlagSet(tn->tn_Flags, TNF_LIST))
9258 ret = IsListEmpty( (&ln->ln_List) );
9261 else if(isFlagSet(msg->Flags, MUIV_NListtree_GetNr_Flag_CountList))
9263 if(isFlagSet(tn->tn_Flags, TNF_LIST))
9264 ret = ln->ln_Table.tb_Entries;
9267 else if(pln && isFlagSet(msg->Flags, MUIV_NListtree_GetNr_Flag_CountLevel))
9269 ret = pln->ln_Table.tb_Entries;
9272 else if(isFlagSet(msg->Flags, MUIV_NListtree_GetNr_Flag_CountAll))
9274 ret = data->NumEntries;
9277 else if(isFlagSet(msg->Flags, MUIV_NListtree_GetNr_Flag_Visible))
9279 ret = (IPTR)GetVisualPos( data, tn );
9282 else
9284 ret = (IPTR)-1;
9286 if ( GetEntryPos( &data->RootList, tn, &pos ) )
9287 ret = pos;
9290 //D(bug( "Node: 0x%08lx - %s - Flags: 0x%08lx ==> Nr: %ld\n", tn, tn->tn_Name, msg->Flags, ret ) );
9292 return( (IPTR)ret );
9297 /****** NListtree.mcc/MUIM_NListtree_Sort ************************************
9299 * NAME
9301 * MUIM_NListtree_Sort -- Sort the specified list node. (V1)
9304 * SYNOPSIS
9306 * DoMethod(obj, MUIM_NListtree_Sort,
9307 * struct MUI_NListtree_TreeNode *listnode,
9308 * ULONG flags);
9311 * FUNCTION
9313 * Sort the specified list node using the sort hook.
9316 * INPUTS
9318 * listnode - List node to sort.
9320 * MUIV_NListtree_Sort_ListNode_Root
9321 * Sort the root list.
9323 * MUIV_NListtree_Sort_ListNode_Active
9324 * Sort the list node of the active entry.
9326 * MUIV_NListtree_Sort_TreeNode_Active
9327 * Sorts the childs of the active entry if a list.
9329 * flags - Control the part where sorting is done.
9331 * MUIV_NListtree_Sort_Flag_RecursiveOpen
9332 * Sort the list recursive. All open child nodes of the
9333 * node specified in 'listnode' will be sorted too.
9335 * MUIV_NListtree_Sort_Flag_RecursiveAll
9336 * Sort the list recursive with ALL child nodes of the
9337 * node specified in 'listnode'.
9339 * RESULT
9341 * EXAMPLE
9343 * // Sort the list of the active node.
9344 * DoMethod(obj, MUIM_NListtree_Sort,
9345 * MUIV_NListtree_Sort_ListNode_Active, 0);
9347 * NOTES
9349 * BUGS
9351 * SEE ALSO
9353 * MUIA_NListtree_SortHook
9355 ******************************************************************************
9358 IPTR _NListtree_Sort(struct IClass *cl, Object *obj, struct MUIP_NListtree_Sort *msg)
9360 struct NListtree_Data *data = INST_DATA(cl, obj);
9361 struct MUI_NListtree_ListNode *ln;
9362 LONG pos;
9365 ** Handle special events.
9367 switch( (IPTR)msg->ListNode )
9369 case MUIV_NListtree_Sort_ListNode_Active:
9370 ln = data->ActiveList;
9371 break;
9373 case MUIV_NListtree_Sort_ListNode_Root:
9374 ln = &data->RootList;
9375 break;
9377 case MUIV_NListtree_Sort_TreeNode_Active:
9378 ln = data->ActiveList;
9380 if ( data->ActiveNode )
9382 if(isFlagSet(data->ActiveNode->tn_Flags, TNF_LIST))
9383 ln = CLN( data->ActiveNode );
9385 break;
9387 default:
9388 ln = CLN( msg->ListNode );
9389 break;
9392 pos = GetVisualPos( data, CTN( ln ) ) + 1;
9394 DoQuiet( data, TRUE );
9395 DeactivateNotify( data );
9397 ListNode_Sort( ln, data, msg->Flags );
9398 ReplaceTreeVisibleSort( data, CTN( ln ), &pos );
9400 ActivateNotify( data );
9401 DoQuiet( data, FALSE );
9403 /* sba: the active note could be changed, but the notify calling was disabled */
9404 DoMethod(data->Obj, MUIM_NListtree_GetListActive, 0);
9406 /* nnset( obj, MUIA_NListtree_Active, CTN( data->ActiveNode ) );*/
9408 return( 0 );
9413 /****** NListtree.mcc/MUIM_NListtree_TestPos *********************************
9415 * NAME
9417 * MUIM_NListtree_TestPos -- Get information about entry at x/y pos. (V1)
9420 * SYNOPSIS
9422 * DoMethod(obj, MUIM_NListtree_TestPos, LONG xpos, LONG ypos,
9423 * struct MUI_NListtree_TestPos_Result *testposresult);
9426 * FUNCTION
9428 * Find out some information about the currently displayed entry at a
9429 * certain position (x/y-pos).
9431 * This is very useful for Drag&Drop operations.
9434 * INPUTS
9436 * xpos - X-position.
9437 * ypos - Y-position.
9438 * testposresult - Pointer to a valid MUI_NListtree_TestPos_Result
9439 * structure.
9442 * RESULT
9444 * tpr_TreeNode - The tree node under the requested position or NULL
9445 * if there is no entry displayed.
9447 * The tpr_Type field contains detailed information about the relative
9448 * position:
9450 * MUIV_NListtree_TestPos_Result_Above
9451 * MUIV_NListtree_TestPos_Result_Below
9452 * MUIV_NListtree_TestPos_Result_Onto
9453 * MUIV_NListtree_TestPos_Result_Sorted
9455 * tpr_Column - The column unter the specified position or -1 if
9456 * no valid column.
9459 * EXAMPLE
9461 * // Entry under the cursor?
9462 * struct MUI_NListtree_TestPos_Result tpres;
9464 * DoMethod(obj, MUIM_NListtree_TestPos, msg->imsg->MouseX,
9465 * msg->imsg->MouseY, &tpres);
9467 * if ( tpres.tpr_Entry != NULL )
9469 * // Do something very special here...
9473 * NOTES
9475 * BUGS
9477 * SEE ALSO
9479 * MUIM_NList_TestPos
9482 ******************************************************************************
9485 IPTR _NListtree_TestPos( UNUSED struct IClass *cl, Object *obj, struct MUIP_NListtree_TestPos *msg)
9487 struct MUI_NListtree_TestPos_Result *res = (struct MUI_NListtree_TestPos_Result *)msg->Result;
9488 struct MUI_NList_TestPos_Result lres;
9490 lres.char_number = -2;
9492 DoMethod( obj, MUIM_NList_TestPos, msg->X, msg->Y, &lres );
9494 if ( lres.entry != -1 )
9496 DoMethod( obj, MUIM_NList_GetEntry, lres.entry, &res->tpr_TreeNode );
9498 if ( lres.yoffset < -3 ) res->tpr_Type = MUIV_NListtree_TestPos_Result_Above;
9499 else if ( lres.yoffset > 3 ) res->tpr_Type = MUIV_NListtree_TestPos_Result_Below;
9500 else res->tpr_Type = MUIV_NListtree_TestPos_Result_Onto;
9502 res->tpr_ListEntry = lres.entry;
9503 res->tpr_ListFlags = lres.flags;
9504 res->tpr_Column = lres.column;
9506 else
9508 res->tpr_TreeNode = NULL;
9509 res->tpr_Type = 0;
9511 res->tpr_ListEntry = -1;
9512 res->tpr_ListFlags = 0;
9513 res->tpr_Column = -1;
9516 //D(bug( "X: %ld, Y: %ld ==> Node: 0x%08lx - %s - YOffset: %ld, Type: 0x%08lx\n", msg->X, msg->Y, res->tpr_TreeNode, res->tpr_TreeNode->tn_Name, lres.yoffset, res->tpr_Type ) );
9519 return( 0 );
9524 /****** NListtree.mcc/MUIM_NListtree_Redraw **********************************
9526 * NAME
9528 * MUIM_NListtree_Redraw -- Redraw the specified tree node. (V1)
9531 * SYNOPSIS
9533 * DoMethod(obj, MUIM_NListtree_Redraw,
9534 * struct MUI_NListtree_TreeNode *treenode, ULONG flags);
9537 * FUNCTION
9539 * Redraw the specified entry. See special values for completeness.
9542 * INPUTS
9544 * treenode - The tree node to be redrawn.
9546 * MUIV_NListtree_Redraw_Active
9547 * Redraw the active entry.
9549 * MUIV_NListtree_Redraw_All
9550 * Redraw the complete visible tree.
9553 * flags:
9555 * MUIV_NListtree_Redraw_Flag_Nr
9556 * The data specified in 'treenode' is the entry number,
9557 * not the tree node itself.
9560 * RESULT
9562 * EXAMPLE
9564 * // Redraw the active entry.
9565 * DoMethod(obj, MUIM_NListtree_Redraw,
9566 * MUIV_NListtree_Redraw_Active, 0);
9569 * NOTES
9571 * BUGS
9573 * SEE ALSO
9575 * MUIM_NList_TestPos
9578 ******************************************************************************
9581 IPTR _NListtree_Redraw(struct IClass *cl, Object *obj, struct MUIP_NListtree_Redraw *msg)
9583 struct NListtree_Data *data = INST_DATA(cl, obj);
9585 D(DBF_DRAW, "redraw treenode %08lx flags %08lx", msg->TreeNode, msg->Flags);
9587 if(((IPTR)msg->TreeNode != (IPTR)MUIV_NListtree_Redraw_Active) && ((IPTR)msg->TreeNode != (IPTR)MUIV_NListtree_Redraw_All) && isFlagClear(msg->Flags, MUIV_NListtree_Redraw_Flag_Nr))
9589 LONG pos = GetVisualPos(data, msg->TreeNode);
9591 D(DBF_DRAW, "treenode %08lx has visual position %ld", msg->TreeNode, pos);
9592 // redraw the given node only if it is visible
9593 if(pos != -1)
9594 DoMethod(obj, MUIM_NList_Redraw, pos);
9596 else
9598 D(DBF_DRAW, "EXTERNAL REDRAW REQUESTED!");
9599 DoMethod(obj, MUIM_NList_Redraw, (IPTR)msg->TreeNode);
9602 return(0);
9607 /****** NListtree.mcc/MUIM_NListtree_Select **********************************
9609 * NAME
9611 * MUIM_NListtree_Select -- Select the specified tree node. (V1)
9614 * SYNOPSIS
9616 * DoMethod(obj, MUIM_NListtree_Select,
9617 * struct MUI_NListtree_TreeNode *treenode, LONG seltype,
9618 * LONG selflags, LONG *state);
9621 * FUNCTION
9623 * Select or unselect a tree entry or ask an entry about its state.
9624 * See special values for completeness.
9627 * INPUTS
9629 * treenode - The tree node to be selected/unselected/asked.
9631 * MUIV_NListtree_Select_Active For the active entry.
9632 * MUIV_NListtree_Select_All For all entries.
9633 * MUIV_NListtree_Select_Visible For all visible entries.
9635 * seltype - Type of selection/unselection/ask
9637 * MUIV_NListtree_Select_Off Unselect entry.
9638 * MUIV_NListtree_Select_On Select entry.
9639 * MUIV_NListtree_Select_Toggle Toggle entries state.
9640 * MUIV_NListtree_Select_Ask Just ask about the state.
9642 * selflags - Some kind of specials.
9644 * MUIV_NListtree_Select_Flag_Force
9645 * Adding this flag to seltype forces the selection by
9646 * bypassing the multi test hook.
9648 * state - Pointer to a longword. If not NULL, it will be filled
9649 * with the current selection state of the entry.
9652 * RESULT
9654 * EXAMPLE
9656 * // Select the active entry.
9657 * LONG retstate;
9659 * DoMethod(obj, MUIM_NListtree_Select,
9660 * MUIV_NListtree_Select_Active, MUIV_NListtree_Select_On,
9661 * 0, &retstate);
9663 * // We must check this, because the multi test hook may
9664 * // cancel our selection.
9665 * if (retstate == MUIV_NListtree_Select_On) {
9666 * ...
9670 * NOTES
9672 * If ( treenode == MUIV_NListtree_Select_All ) and
9673 * ( seltype == MUIV_NListtree_Select_Ask ), state will be filled
9674 * with the total number of selected entries.
9676 * NEW for final 18.6:
9677 * If (treenode == MUIV_NListtree_Select_Active ) and
9678 * ( seltype == MUIV_NListtree_Select_Ask ), state will be the
9679 * active entry, if any, or NULL.
9681 * If only the active entry is selected, has a cursor mark (see
9682 * MUIM_NListtree_NextSelected for that), you will receive 0 as
9683 * the number of selected entries.
9686 * BUGS
9688 * SEE ALSO
9690 * MUIA_NListtree_MultiTestHook
9693 ******************************************************************************
9696 IPTR _NListtree_Select(struct IClass *cl, Object *obj, struct MUIP_NListtree_Select *msg)
9698 struct NListtree_Data *data = INST_DATA(cl, obj);
9699 LONG state = 0;
9701 ENTER();
9703 SET_FLAG(data->Flags, NLTF_SELECT_METHOD);
9706 ** Handle special events.
9708 switch( (IPTR)msg->TreeNode )
9710 case MUIV_NListtree_Select_Active:
9711 if ( msg->SelType == MUIV_NListtree_Select_Ask )
9713 state = (LONG)(SIPTR)data->ActiveNode;
9715 else
9717 if ( data->ActiveNode )
9719 TreeNodeSelect( data, data->ActiveNode, msg->SelType, msg->SelFlags, &state );
9722 break;
9724 case MUIV_NListtree_Select_All:
9726 if ( msg->SelType == MUIV_NListtree_Select_Ask )
9728 state = data->SelectedTable.tb_Entries;
9730 else
9732 TreeNodeSelectAll( data, &data->RootList, msg->SelType, msg->SelFlags, &state );
9734 break;
9736 case MUIV_NListtree_Select_Visible:
9737 TreeNodeSelectVisible( data, &data->RootList, msg->SelType, msg->SelFlags, &state );
9738 break;
9740 default:
9741 TreeNodeSelect( data, msg->TreeNode, msg->SelType, msg->SelFlags, &state );
9742 break;
9745 if ( msg->State )
9747 *msg->State = state;
9750 CLEAR_FLAG(data->Flags, NLTF_SELECT_METHOD);
9752 RETURN(state);
9753 return( (IPTR)state );
9758 /****** NListtree.mcc/MUIM_NListtree_NextSelected ****************************
9760 * NAME
9762 * MUIM_NListtree_NextSelected -- Get next selected tree node. (V1)
9765 * SYNOPSIS
9767 * DoMethod(obj, MUIM_NListtree_NextSelected,
9768 * struct MUI_NListtree_TreeNode **treenode);
9771 * FUNCTION
9773 * Iterate through the selected entries of a tree. This method steps
9774 * through the contents of a (multi select) list tree and returns
9775 * every entry that is currently selected. When no entry is selected
9776 * but an entry is active, only the active entry will be returned.
9778 * This behaviour will result in not returning the active entry when
9779 * you have some other selected entries somewhere in your list. Since
9780 * the active entry just acts as some kind of cursor mark, this seems
9781 * to be the only sensible possibility to handle multi selection
9782 * together with keyboard control.
9785 * INPUTS
9787 * treenode - A pointer to a pointer of struct MUI_NListtree_TreeNode
9788 * that will hold the returned entry. Must be set to
9789 * MUIV_NListtree_NextSelected_Start at start of iteration
9790 * and is set to MUIV_NListtree_NextSelected_End when
9791 * iteration is finished.
9793 * MUIV_NListtree_NextSelected_Start Set this to start iteration.
9794 * MUIV_NListtree_NextSelected_End Will be set to this, if
9795 * last selected entry reached.
9798 * RESULT
9800 * EXAMPLE
9802 * // Iterate through a list
9803 * struct MUI_NListtree_TreeNode *treenode;
9805 * treenode = MUIV_NListtree_NextSelected_Start;
9807 * for (;;)
9809 * DoMethod(listtree, MUIM_NListtree_NextSelected, &treenode);
9811 * if (treenode==MUIV_NListtree_NextSelected_End)
9812 * break;
9814 * printf("selected: %s\n", treenode->tn_Name);
9818 * NOTES
9820 * BUGS
9822 * SEE ALSO
9824 * MUIM_NListtree_PrevSelected, MUIM_NListtree_Select
9827 ******************************************************************************
9830 IPTR _NListtree_NextSelected(struct IClass *cl, Object *obj, struct MUIP_NListtree_NextSelected *msg)
9832 struct NListtree_Data *data = INST_DATA(cl, obj);
9833 LONG curr = data->SelectedTable.tb_Current;
9835 //D(bug( "TreeNode: 0x%08lx ", *msg->TreeNode ) );
9837 if ( (IPTR)*msg->TreeNode == (IPTR)MUIV_NListtree_NextSelected_Start )
9838 curr = 0;
9839 else
9840 curr++;
9842 if ( ( curr > -1 ) && data->SelectedTable.tb_Entries )
9844 if ( curr < data->SelectedTable.tb_Entries )
9846 data->SelectedTable.tb_Current = curr;
9847 *msg->TreeNode = data->SelectedTable.tb_Table[curr];
9849 else if(((IPTR)*msg->TreeNode == (IPTR)MUIV_NListtree_NextSelected_Start) &&
9850 (data->ActiveNode != MUIV_NListtree_Active_Off))
9852 *msg->TreeNode = data->ActiveNode;
9854 else
9856 *msg->TreeNode = CTN( MUIV_NListtree_NextSelected_End );
9859 else
9861 *msg->TreeNode = CTN( MUIV_NListtree_NextSelected_End );
9864 //D(bugn( "==> Entry: 0x%08lx\n", *msg->TreeNode ) );
9866 return( 0 );
9870 /****** NListtree.mcc/MUIM_NListtree_PrevSelected ****************************
9872 * NAME
9874 * MUIM_NListtree_PrevSelected -- Get previous selected tree node. (V1)
9877 * SYNOPSIS
9879 * DoMethod(obj, MUIM_NListtree_PrevSelected,
9880 * struct MUI_NListtree_TreeNode **treenode);
9883 * FUNCTION
9885 * Iterate reverse through the selected entries of a tree. This method
9886 * steps through the contents of a (multi select) list tree and returns
9887 * every entry that is currently selected. When no entry is selected
9888 * but an entry is active, only the active entry will be returned.
9890 * This behaviour will result in not returning the active entry when
9891 * you have some other selected entries somewhere in your list. Since
9892 * the active entry just acts as some kind of cursor mark, this seems
9893 * to be the only sensible possibility to handle multi selection
9894 * together with keyboard control.
9897 * INPUTS
9899 * treenode - A pointer to a pointer of struct MUI_NListtree_TreeNode
9900 * that will hold the returned entry. Must be set to
9901 * MUIV_NListtree_PrevSelected_Start at start of iteration
9902 * an the end and is set to MUIV_NListtree_PrevSelected_End
9903 * when first selected entry is reached and iteration is
9904 * finished.
9906 * MUIV_NListtree_PrevSelected_Start Set this to start iteration.
9907 * MUIV_NListtree_PrevSelected_End Will be set to this, if
9908 * last selected entry reached.
9911 * RESULT
9913 * EXAMPLE
9915 * // Iterate through a list (reverse)
9916 * struct MUI_NListtree_TreeNode *treenode;
9918 * treenode = MUIV_NListtree_PrevSelected_Start;
9920 * for (;;)
9922 * DoMethod(listtree, MUIM_NListtree_PrevSelected, &treenode);
9924 * if (treenode==MUIV_NListtree_PrevSelected_End)
9925 * break;
9927 * printf("selected: %s\n", treenode->tn_Name);
9931 * NOTES
9933 * BUGS
9935 * SEE ALSO
9937 * MUIM_NListtree_NextSelected, MUIM_NListtree_Select
9940 ******************************************************************************
9944 IPTR _NListtree_PrevSelected(struct IClass *cl, Object *obj, struct MUIP_NListtree_PrevSelected *msg)
9946 struct NListtree_Data *data = INST_DATA(cl, obj);
9947 LONG curr = data->SelectedTable.tb_Current;
9949 //D(bug( "TreeNode: 0x%08lx ", *msg->TreeNode ) );
9951 if((IPTR)*msg->TreeNode == (IPTR)MUIV_NListtree_PrevSelected_Start)
9952 curr = data->SelectedTable.tb_Entries;
9954 curr--;
9956 if ( curr < data->SelectedTable.tb_Entries )
9958 if ( curr > -1 )
9960 data->SelectedTable.tb_Current = curr;
9961 *msg->TreeNode = data->SelectedTable.tb_Table[curr];
9963 else if(((IPTR)*msg->TreeNode == (IPTR)MUIV_NListtree_NextSelected_Start) &&
9964 (data->ActiveNode != MUIV_NListtree_Active_Off))
9966 *msg->TreeNode = data->ActiveNode;
9968 else
9970 *msg->TreeNode = CTN( MUIV_NListtree_PrevSelected_End );
9973 else
9975 *msg->TreeNode = CTN( MUIV_NListtree_PrevSelected_End );
9978 //D(bugn( "==> Entry: 0x%08lx\n", *msg->TreeNode ) );
9980 return( 0 );
9985 /****** NListtree.mcc/MUIM_NListtree_CopyToClip ******************************
9987 * NAME
9989 * MUIM_NListtree_CopyToClip -- Called for every clipboard copy action. (V1)
9992 * SYNOPSIS
9994 * DoMethodA(obj, MUIM_NListtree_CopyToClip,
9995 * struct MUIP_NListtree_CopyToClip *ctcmessage);
9998 * FUNCTION
10000 * Do a copy to clipboard from an entry/entry content.
10003 * INPUTS
10005 * TreeNode - Tree node to copy contents from. Use
10006 * MUIV_NListtree_CopyToClip_Active to copy the
10007 * active entry.
10009 * Pos - Entry position.
10011 * Unit - Clipboard unit to copy entry contents to.
10014 * RESULT
10016 * EXAMPLE
10018 * NOTES
10020 * BUGS
10022 * SEE ALSO
10024 * MUIA_NListtree_CopyToClipHook
10027 ******************************************************************************
10030 IPTR _NListtree_CopyToClip(struct IClass *cl, Object *obj, struct MUIP_NListtree_CopyToClip *msg)
10032 struct NListtree_Data *data = INST_DATA(cl, obj);
10034 // make sure anything is selected at all or calling CopyToClip doesn't make
10035 // much sense
10036 if(msg->TreeNode != NULL && msg->TreeNode->tn_Name != NULL)
10038 STRPTR string = NULL;
10039 BOOL alloc = FALSE;
10041 if(data->CopyToClipHook != NULL)
10043 if((SIPTR)(string = (STRPTR)MyCallHook(data->CopyToClipHook, data, MUIA_NListtree_CopyToClipHook, msg->TreeNode, msg->Pos, msg->Unit)) == (SIPTR)MUIV_NListtree_CopyToClip_Active)
10044 string = msg->TreeNode->tn_Name;
10046 else
10048 STRPTR str;
10050 string = msg->TreeNode->tn_Name;
10051 if((str = AllocVecPooled(data->MemoryPool, strlen(string) + 1)) != NULL)
10053 STRPTR s = string;
10055 alloc = TRUE;
10056 string = str;
10058 // copy the string and remove all escape sequences
10059 while(*s != '\0')
10061 if(*s == 0x1b)
10063 s += 2;
10065 if(*s == '[')
10066 while(++*s != ']');
10068 s++;
10071 *str++ = *s++;
10076 if(string != NULL)
10078 //D(bug( "String: %s, Unit: %ld, pos: %ld\n", string, msg->Unit, msg->Pos ) );
10080 StringToClipboard(msg->Unit, string);
10082 if(alloc == TRUE)
10083 FreeVecPooled(data->MemoryPool, string);
10087 return(0);
10092 /****** NListtree.mcc/MUIM_NListtree_MultiTest *******************************
10094 * NAME
10096 * MUIM_NListtree_MultiTest -- Called for every selection. (V1)
10099 * SYNOPSIS
10101 * DoMethodA(obj, MUIM_NListtree_MultiTest,
10102 * struct MUIP_NListtree_MultiTest *multimessage);
10105 * FUNCTION
10107 * This method must not be called directly. It will be called by
10108 * NListtree just before multiselection. You can overload it and
10109 * return TRUE or FALSE whether you want the entry to be multi-
10110 * selectable or not.
10113 * INPUTS
10115 * RESULT
10117 * EXAMPLE
10119 * NOTES
10121 * BUGS
10123 * SEE ALSO
10125 * MUIM_NListtree_Select, MUIA_NListtree_MultiTest
10128 ******************************************************************************
10133 /****** NListtree.mcc/MUIM_NListtree_Active **********************************
10135 * NAME
10137 * MUIM_NListtree_Active -- Called for every active change. (V1)
10140 * SYNOPSIS
10142 * DoMethodA(obj, MUIM_NListtree_Active,
10143 * struct MUIP_NListtree_Active *activemessage);
10146 * FUNCTION
10148 * This method must not be called directly. It will be called by
10149 * NListtree if the active entry changes. This is an addition to
10150 * MUIA_NListtree_Active
10153 * INPUTS
10155 * RESULT
10157 * EXAMPLE
10159 * NOTES
10161 * BUGS
10163 * SEE ALSO
10165 * MUIA_NListtree_Active
10168 ******************************************************************************
10173 /****** NListtree.mcc/MUIM_NListtree_DoubleClick *****************************
10175 * NAME
10177 * MUIM_NListtree_DoubleClick -- Called for every double click. (V1)
10180 * SYNOPSIS
10182 * DoMethodA(obj, MUIM_NListtree_DoubleClick,
10183 * struct MUIP_NListtree_DoubleClick *doubleclickmsg);
10186 * FUNCTION
10188 * This method must not be called directly. It will be called by
10189 * NListtree if an double click event occurs. This is an addition to
10190 * MUIA_NListtree_DoubleClick
10193 * INPUTS
10195 * RESULT
10197 * EXAMPLE
10199 * NOTES
10201 * BUGS
10203 * SEE ALSO
10205 * MUIA_NListtree_DoubleClick
10208 ******************************************************************************
10213 /****** NListtree.mcc/MUIM_NListtree_DropType ********************************
10215 * NAME
10217 * MUIM_NListtree_DropType --
10220 * SYNOPSIS
10222 * DoMethod(obj, MUIM_NListtree_DropType, LONG *pos, LONG *type,
10223 * LONG minx, LONG maxx, LONG miny, LONG maxy,
10224 * LONG mousex, LONG mousey);
10227 * FUNCTION
10229 * This method MUST NOT be called directly !
10231 * It will be called by NListree while the DragReport, with
10232 * default *pos and *type values depending on the drag pointer
10233 * position that you can modify as you want.
10235 * For further information see method MUIM_NList_DropDraw.
10238 * INPUTS
10240 * RESULT
10242 * EXAMPLE
10244 * NOTES
10246 * BUGS
10248 * SEE ALSO
10250 * MUIM_NList_DropType
10253 ******************************************************************************
10258 /****** NListtree.mcc/MUIM_NListtree_DropDraw ********************************
10260 * NAME
10262 * MUIM_NListtree_DropDraw --
10265 * SYNOPSIS
10267 * DoMethod(obj, MUIM_NListtree_DropDraw, LONG pos, LONG type,
10268 * LONG minx, LONG maxx, LONG miny, LONG maxy);
10271 * FUNCTION
10273 * This method MUST NOT be called directly!
10275 * It will be called by NListtree, and will draw the drop mark
10276 * previously fixed (pos and type) by MUIM_NListtree_DropType
10277 * within the minx, maxx, miny, maxy in the _rp(obj) rasport.
10279 * For further information see method MUIM_NList_DropDraw.
10282 * INPUTS
10284 * RESULT
10286 * EXAMPLE
10288 * NOTES
10290 * BUGS
10292 * SEE ALSO
10294 * MUIM_NList_DropDraw
10297 ******************************************************************************
10304 /****i* NListtree.mcc/MUIM_NListtree_GetListActive ***************************
10306 * NAME
10308 * MUIM_NListtree_GetListActive -- Set the active list in data structure. (V1)
10311 * SYNOPSIS
10313 * DoMethod(obj, MUIM_NListtree_GetListActive, 0);
10316 * FUNCTION
10318 * Set current active list in the internal data structure depending on the
10319 * currently active entry.
10322 * INPUTS
10324 * RESULT
10326 * data->ActiveList will be set to data->ActiveEntry->tn_Parent.
10329 * EXAMPLE
10331 * DoMethod(obj, MUIM_NListtree_GetListActive, 0);
10334 * NOTES
10336 * Only internal used function for notification of MUIA_NList_Active.
10339 * BUGS
10341 * SEE ALSO
10343 * MUIA_NList_Active
10346 ******************************************************************************
10349 IPTR _NListtree_GetListActive(struct IClass *cl, Object *obj, UNUSED struct MUIP_NListtree_GetListActive *msg)
10351 struct NListtree_Data *data = INST_DATA(cl, obj);
10352 struct MUI_NListtree_TreeNode *tn;
10355 ** Get pointer to the selected node.
10356 ** Set active node in global
10357 ** data structure.
10359 DoMethod( obj, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &tn );
10361 D(DBF_LISTTREE, "Got Active notify from NList 0x%08lx - %s (0x%08lx - Name: %s) force=%ld", tn, (tn != NULL && tn->tn_Name != NULL) ? tn->tn_Name : (STRPTR)"NULL", data->ActiveNode, (data->ActiveNode != NULL && data->ActiveNode->tn_Name != NULL) ? data->ActiveNode->tn_Name : (STRPTR)"NULL", data->ForceActiveNotify);
10363 if ( tn != data->ActiveNode || data->ForceActiveNotify)
10365 //DoMethod( obj, MUIM_NListtree_Active, tn, pos );
10367 //MakeNotify( data, MUIA_NListtree_Active, tn );
10368 MakeSet( data, MUIA_NListtree_Active, tn );
10369 data->ForceActiveNotify = 0;
10372 return( 0 );
10376 IPTR _NListtree_GetDoubleClick(struct IClass *cl, Object *obj, UNUSED struct MUIP_NListtree_GetListActive *msg)
10378 struct NListtree_Data *data = INST_DATA(cl, obj);
10380 ENTER();
10382 if ( data->DoubleClick != MUIV_NListtree_DoubleClick_NoTrigger )
10384 struct MUI_NListtree_TreeNode *tn;
10387 ** Get pointer to the selected node.
10389 DoMethod( obj, MUIM_NList_GetEntry, data->LDClickEntry, &tn );
10391 if ( (SIPTR)tn != -1 )
10393 DoMethod( obj, MUIM_NListtree_DoubleClick, tn, data->LDClickEntry, data->LDClickColumn );
10394 MakeNotify( data, MUIA_NListtree_DoubleClick, tn );
10395 //DoMethod( obj, MUIM_Set, MUIA_NListtree_DoubleClick, tn );
10399 RETURN(0);
10400 return( 0 );
10405 /****i* NListtree.mcc/MUIM_NListtree_Data ************************************
10407 * NAME
10409 * MUIM_NListtree_Data -- Get/Set some internal data. (V1)
10412 * SYNOPSIS
10414 * DoMethod(obj, MUIM_NListtree_Data, dataqual, set);
10417 * FUNCTION
10419 * Get some internal data or set if "set" is != NULL.
10422 * INPUTS
10424 * dataqual:
10425 * MUIV_NListtree_Data_MemPool
10426 * MUIV_NListtree_Data_VersInfo (not implemented)
10427 * MUIV_NListtree_Data_Sample (not implemented)
10430 * RESULT
10432 * The requested data.
10435 * EXAMPLE
10437 * result = DoMethod(obj, MUIM_NListtree_Data,
10438 * MUIV_NListtree_Data_MemPool, NULL);
10441 * NOTES
10443 * BUGS
10445 * SEE ALSO
10447 ******************************************************************************
10450 IPTR _NListtree_Data(struct IClass *cl, Object *obj, struct MUIP_NListtree_Data *msg)
10452 struct NListtree_Data *data = INST_DATA(cl, obj);
10454 switch( msg->ID )
10456 case MUIV_NListtree_Data_MemPool:
10457 return( (IPTR)data->MemoryPool );
10459 case MUIV_NListtree_Data_VersInfo:
10460 case MUIV_NListtree_Data_Sample:
10461 default:
10462 break;
10465 return( 0 );
10470 IPTR _NListtree_SelectChange(struct IClass *cl, Object *obj, struct MUIP_NList_SelectChange *msg)
10472 struct NListtree_Data *data = INST_DATA(cl, obj);
10473 struct MUI_NListtree_TreeNode *tn;
10475 D(DBF_LISTTREE, "NList selection change: Entry %ld changed to %ld%s", msg->pos, msg->state,
10476 isFlagSet(msg->flags, MUIV_NList_SelectChange_Flag_Multi) ? " while holding down mouse button" : "");
10478 if (data->IgnoreSelectionChange)
10480 D(DBF_LISTTREE, " which is ignored");
10481 return 0;
10484 DoMethod( obj, MUIM_NList_GetEntry, msg->pos, &tn );
10486 if ( msg->state == MUIV_NList_Select_Active )
10488 if ( tn != data->ActiveNode )
10491 ** !! Setting this NOT makes problems with getting the active entry
10492 ** in applications. Handle carefully if changed/removed !!
10494 //MakeNotify( data, MUIA_NListtree_Active, tn );
10495 //data->ActiveNode = tn;
10497 /* sba: Changed to not notify, because the new active element is not drawn
10498 ** here (current NList restriction) a MUIA_NList_Active trigger
10499 ** will follow and we will use this for the notification
10501 nnset( obj, MUIA_NListtree_Active, tn );
10503 /* sba: the MUIA_NList_Notification only notifies if neccessary, but as the
10504 ** notifications stayed out we set a flag to force it
10506 data->ForceActiveNotify = 1;
10510 else if ( msg->state == MUIV_NList_Select_On )
10512 if ( NLFindInTable( &data->SelectedTable, tn ) == -1 )
10514 TreeNodeSelectAdd( data, tn );
10515 SET_FLAG(tn->tn_Flags, TNF_SELECTED);
10517 MakeNotify( data, MUIA_NListtree_SelectChange, (APTR)TRUE );
10521 else if ( msg->state == MUIV_NList_Select_Off )
10523 if ( NLFindInTable( &data->SelectedTable, tn ) != -1 )
10525 TreeNodeSelectRemove( data, tn );
10526 CLEAR_FLAG(tn->tn_Flags, TNF_SELECTED);
10528 MakeNotify( data, MUIA_NListtree_SelectChange, (APTR)TRUE );
10532 return( 0 );
10537 /****i* NListtree.mcc/_Dispatcher ******************************************
10539 * NAME
10541 * _Dispatcher -- Call methods depending on the supplied MethodID (V1)
10544 * SYNOPSIS
10546 * FUNCTION
10548 * INPUTS
10550 * RESULT
10552 * EXAMPLE
10554 * NOTES
10556 * BUGS
10558 * SEE ALSO
10560 ******************************************************************************
10564 DISPATCHER(_Dispatcher)
10566 switch( msg->MethodID )
10569 ** Base class methods.
10571 case OM_NEW: return( _New ( cl, obj, (APTR)msg) );
10572 case OM_DISPOSE: return( _Dispose ( cl, obj, (APTR)msg) );
10573 case OM_SET: return( _Set ( cl, obj, (APTR)msg) );
10574 case OM_GET: return( _Get ( cl, obj, (APTR)msg) );
10577 ** MUI base class methods.
10579 case MUIM_Setup: return( _Setup ( cl, obj, (APTR)msg) );
10580 case MUIM_Cleanup: return( _Cleanup ( cl, obj, (APTR)msg) );
10581 case MUIM_Show: return( _Show ( cl, obj, (APTR)msg) );
10582 case MUIM_Hide: return( _Hide ( cl, obj, (APTR)msg) );
10583 case MUIM_Draw: return( _Draw ( cl, obj, (APTR)msg) );
10584 case MUIM_AskMinMax: return( _AskMinMax ( cl, obj, (APTR)msg) );
10585 case MUIM_HandleEvent: return( _HandleEvent ( cl, obj, (APTR)msg) );
10588 ** MUI/NList drag&drop methods.
10590 case MUIM_DragQuery: return( _DragNDrop_DragQuery ( cl, obj, (APTR)msg) );
10591 case MUIM_DragBegin: return( _DragNDrop_DragBegin ( cl, obj, (APTR)msg) );
10592 case MUIM_DragReport: return( _DragNDrop_DragReport ( cl, obj, (APTR)msg) );
10593 case MUIM_DragFinish: return( _DragNDrop_DragFinish ( cl, obj, (APTR)msg) );
10594 case MUIM_DragDrop: return( _DragNDrop_DragDrop ( cl, obj, (APTR)msg) );
10595 case MUIM_NList_DropType: return( _DragNDrop_DropType ( cl, obj, (APTR)msg) );
10596 case MUIM_NList_DropDraw: return( _DragNDrop_DropDraw ( cl, obj, (APTR)msg) );
10597 case MUIM_NListtree_DropDraw: return( _DragNDrop_NDropDraw ( cl, obj, (APTR)msg) );
10599 case MUIM_NList_Display: return( _NList_Display(cl, obj, (APTR)msg) );
10602 ** Specials.
10604 case MUIM_NList_ContextMenuBuild: return( _ContextMenuBuild ( cl, obj, (APTR)msg) );
10605 case MUIM_ContextMenuChoice: return( _ContextMenuChoice ( cl, obj, (APTR)msg) );
10609 ** NListtree methods sorted by kind.
10611 case MUIM_NListtree_Open: return( _NListtree_Open ( cl, obj, (APTR)msg) );
10612 case MUIM_NListtree_Close: return( _NListtree_Close ( cl, obj, (APTR)msg) );
10614 case MUIM_NListtree_Insert: return( _NListtree_Insert ( cl, obj, (APTR)msg) );
10615 case MUIM_NListtree_InsertStruct: return( _NListtree_InsertStruct ( cl, obj, (APTR)msg) );
10616 case MUIM_NListtree_Remove: return( _NListtree_Remove ( cl, obj, (APTR)msg) );
10617 case MUIM_NListtree_Clear: return( _NListtree_Clear ( cl, obj, (APTR)msg) );
10619 case MUIM_NListtree_Move: return( _NListtree_Move ( cl, obj, (APTR)msg) );
10620 case MUIM_NListtree_Copy: return( _NListtree_Copy ( cl, obj, (APTR)msg) );
10621 case MUIM_NListtree_Rename: return( _NListtree_Rename ( cl, obj, (APTR)msg) );
10622 case MUIM_NListtree_Exchange: return( _NListtree_Exchange ( cl, obj, (APTR)msg) );
10624 case MUIM_NListtree_FindName: return( _NListtree_FindName ( cl, obj, (APTR)msg) );
10625 case MUIM_NListtree_FindUserData: return( _NListtree_FindUserData ( cl, obj, (APTR)msg) );
10627 case MUIM_NListtree_GetEntry: return( _NListtree_GetEntry ( cl, obj, (APTR)msg) );
10628 case MUIM_NListtree_GetNr: return( _NListtree_GetNr ( cl, obj, (APTR)msg) );
10630 case MUIM_NListtree_Sort: return( _NListtree_Sort ( cl, obj, (APTR)msg) );
10631 case MUIM_NListtree_Redraw: return( _NListtree_Redraw ( cl, obj, (APTR)msg) );
10632 case MUIM_NListtree_TestPos: return( _NListtree_TestPos ( cl, obj, (APTR)msg) );
10634 case MUIM_NListtree_Select: return( _NListtree_Select ( cl, obj, (APTR)msg) );
10635 case MUIM_NListtree_NextSelected: return( _NListtree_NextSelected ( cl, obj, (APTR)msg) );
10636 case MUIM_NListtree_PrevSelected: return( _NListtree_PrevSelected ( cl, obj, (APTR)msg) );
10638 case MUIM_NListtree_CopyToClip: return( _NListtree_CopyToClip ( cl, obj, (APTR)msg) );
10640 case MUIM_NListtree_Construct: return( _NListtree_Construct ( cl, obj, (APTR)msg) );
10641 case MUIM_NListtree_Destruct: return( _NListtree_Destruct ( cl, obj, (APTR)msg) );
10642 case MUIM_NListtree_Display: return( _NListtree_Display ( cl, obj, (APTR)msg) );
10643 case MUIM_NListtree_Compare: return( _NListtree_Compare ( cl, obj, (APTR)msg) );
10646 ** Methods, user can use for info or overload
10647 ** to control NListtree.
10649 case MUIM_NListtree_Active: return( TRUE );
10650 case MUIM_NListtree_DoubleClick: return( TRUE );
10651 case MUIM_NListtree_MultiTest: return( TRUE );
10652 case MUIM_NListtree_DropType: return( TRUE );
10656 ** Internal methods.
10658 case MUIM_NListtree_GetListActive: return( _NListtree_GetListActive ( cl, obj, (APTR)msg) );
10659 case MUIM_NListtree_GetDoubleClick: return( _NListtree_GetDoubleClick ( cl, obj, (APTR)msg) );
10660 case MUIM_NListtree_Data: return( _NListtree_Data ( cl, obj, (APTR)msg) );
10662 case MUIM_NList_SelectChange: return( _NListtree_SelectChange ( cl, obj, (APTR)msg) );
10664 #ifdef MYDEBUG
10665 case MUIM_NList_Remove:
10667 ULONG rc;
10668 D(DBF_LISTTREE, "MUIM_NList_Remove");
10669 rc = DoSuperMethodA(cl, obj, msg);
10670 D(DBF_LISTTREE, "MUIM_NList_Remove_End");
10671 return rc;
10673 #endif
10676 case MUIM_NList_UseImage:
10678 ULONG res;
10680 res = DoSuperMethodA(cl, obj, msg);
10682 D(bug( "USEIMAGE ==> result: 0x%08lx obj: 0x%08lx, imgnum: %ld, flags: 0x%08lx\n", res, m->obj, m->imgnum, m->flags ) );
10684 return( res );
10687 case MUIM_NList_CreateImage:
10689 struct MUIP_NList_UseImage *m = (struct MUIP_NList_UseImage *)msg;
10690 ULONG res;
10692 res = DoSuperMethodA(cl, obj, msg);
10694 D(bug( "CREATEIMAGE ==> result: 0x%08lx obj: 0x%08lx, flags: 0x%08lx\n", res, m->obj, m->flags ) );
10696 return( res );
10701 return( DoSuperMethodA( cl, obj, msg) );