Aros/Developer/Zune/CustomClasses

From Wikibooks, open books for an open world
Jump to navigation Jump to search
Navbar for the Aros wikibook
Aros User
Aros User Docs
Aros User FAQs
Aros User Applications
Aros User DOS Shell
Aros/User/AmigaLegacy
Aros Dev Docs
Aros Developer Docs
Porting Software from AmigaOS/SDL
For Zune Beginners
Zune .MUI Classes
For SDL Beginners
Aros Developer BuildSystem
Specific platforms
Aros x86 Complete System HCL
Aros x86 Audio/Video Support
Aros x86 Network Support
Aros Intel AMD x86 Installing
Aros Storage Support IDE SATA etc
Aros Poseidon USB Support
x86-64 Support
Motorola 68k Amiga Support
Linux and FreeBSD Support
Windows Mingw and MacOSX Support
Android Support
Arm Raspberry Pi Support
PPC Power Architecture
misc
Aros Public License

What is a Zune custom class?[edit | edit source]

A Zune custom class is a newly created Zune class based on an existing one. A custom class may provide improvements or changes to the one it's based upon, thus extending Zune.

Zune custom classes are identified by the suffix ".mcc".

AROS' Zune classes (including supplied custom classes) are located at SYS:Classes/Zune.

Mui Custom Classes (MCC) some of which are closed sources.

Examples of open sourced ones...

http://www.jens-langner.de/dev

Using custom classes[edit | edit source]

Here is an example how a private class is defined:

extern struct MUI_CustomClass *FPEditor_CLASS;

/*** Macros *****************************************************************/

#define FPEditorObject BOOPSIOBJMACRO_START(FPEditor_CLASS->mcc_Class)

Some custom classes are supplied with AROS. Others can be installed into AROS. Others can be loaded from disk.

Custom classes usage in your application is mostly straightforward (just like any built-in class). The only prerequisite might be including the appropriate #include-file.

For example: If you've been using the (built-in) "Text" class/object of Zune...

#include <proto/muimaster.h>
#include <libraries/mui.h>
...
   TextObject,
      MUIA_Text_Contents, "hello world",
...

...you may use the custom class "TextEditor" exactly the same way, just add the proper include-file and adjust the attribute (MUIA_...) to match the new class:

#include <proto/muimaster.h>
#include <libraries/mui.h>
#include <mui/TextEditor_mcc.h>
...
   TextEditorObject,
      MUIA_TextEditor_Contents, "hello world",
...

Another example is the "NListview"/"NList" class, which is an enhanced replacement of the (built-in) "Listview"/"List" class. In this case even the custom classes' attributes match the original classes' ones.

Of course it all depends on the way a custom class is built - it might introduce completely new attributes or method. In any case it is strongly recommended to obtain a custom classes' developer documentation of attributes and methods.

If you have a custom class,and this should have an extra attribute, which needs to trigger via a Notify-method. You simply need to forward the OM_SET message to your superclass.

struct TagItem *tags, *tag;

for
(
tags = message->ops_AttrList;
(tag = NextTagItem(&tags));
)
{
switch (tag->ti_Tag)
{
....
}
}

return DoSuperMethodA(CLASS, self, (Msg)message);

If you want the app to be able to check the attribute via a Notify that is setup at progstart. Than you want to set the attribute inside the class, and the app should react according to that notify.

References[edit | edit source]

BetterString[edit | edit source]

Can scrollback buffers be achieved with betterstring.mcc? Yes, simply subclass it and add an eventhandler with priority above zero, and react on the arrow up/down keys. My idea for an API would be a method a la MUIM_BetterString_Freeze, which would add the contents of the current buffer to the history. Normally one would then setup a notify to let MUIA_String_Acknowledge trigger this method. Additionally there should be a tag to force moving to a certain buffer.

If you do create a buffer-system, please let the Freeze-method verify that the buffer has changed, and only add it if so - there's nothing as irritating as the unix shell which keeps adding repeated commands to the history, so that one has to press arrow-up a zillion times before getting to the previous *different* command...

NList[edit | edit source]

It is more powerful, as it supports horizontal scroll, clickable titles, re-arranging of columns, re-layout of columns etc. - but most consider it more complex and not as fast plus it has a few flaws.

creating your list like so

MUIA_NList_Format, "BAR,BAR,BAR,",

That will give you a four column list, each column separated by a vertical bar. Add or remove 'BAR,' entries to the desired number of columns. If you have enabled the titles (a good idea for multi-column lists) then you should also ensure that your display hook sets the titles for each column.

For sorting you must supply MUIA_NList_CompareHook (or overload MUIM_NList_Compare) to get proper comparison. The default comparison method works only for single column lists with plain string pointers.

How to tell if a certain entry is in the visible part of the NList then? You can calculate the visible entries using: MUIA_NList_Horiz_DeltaFactor, MUIA_NList_Horiz_First & MUIA_NList_Horiz_Visible.

If you are using custom data structures:

  • Display method/hook is required.
  • Compare method/hook is required if you are using sorting.
  • Construct/Destruct is optional, to temporary copy these structures or whatever you want.

If Construct/Destruct are missing NList.mcc will pass entry which you inserted directly to f.e. Display/Compare/Destruct.

Procedure with variable amount of parameters in aros, and some damn macro... here is a valid and working procedures, resolves some problems with "End" macro, and implementation of DoSuperNew

IPTR NewObjectAROS( struct IClass *classPtr, STRPTR classID, ULONG tag1, ... )
{
AROS_SLOWSTACKTAGS_PRE(tag1)
retval = (IPTR) NewObject(classPtr, classID, AROS_SLOWSTACKTAGS_ARG(tag1));
AROS_SLOWSTACKTAGS_POST
}

IPTR DoSuperNew(struct IClass *cl, Object *obj, ULONG tag1, ...)
{
AROS_SLOWSTACKTAGS_PRE(tag1)
retval = (IPTR)DoSuperMethod(cl, obj, OM_NEW, AROS_SLOWSTACKTAGS_ARG(tag1));
AROS_SLOWSTACKTAGS_POST
}
IPTR DoSuperNew(Class *cl, Object *obj, Tag tag1, ...)
{
  AROS_SLOWSTACKTAGS_PRE(tag1)
  
  retval = DoSuperNewTagList(cl, obj, NULL, AROS_SLOWSTACKTAGS_ARG(tag1));

  AROS_SLOWSTACKTAGS_POST
}

or in a more portable manner

Object *DoSuperNew(struct IClass *cl, Object *obj, ...)
{
    Object *rc;
    va_list args;

    va_start(args, obj);

    rc = (Object *)DoSuperMethod(cl, obj, OM_NEW, va_arg(args, IPTR), NULL);

    va_end(args);

    return rc;
}
DMethod(my_listview, MUIM_NList_ReplaceSingle, "foo", MUIV_NList_Insert_Active, NOWRAP, ALIGN_LEFT); 
DoMethod(my_listview, MUIM_NList_Redraw, MUIV_NList_Redraw_Active);

I intentionally ignore __stackparm in the prototype because it has no meaning for PPC and x86-64 at the moment, and it never had it for i386 and m68k. When the preprocessor expands macros on i386 (or any other architecture which puts all arguments on stack). The code is turned into this:

IPTR DoSuperNew(Class *cl, Object *obj, Tag tag1, ...)
{
  IPTR retval;
  
  retval = DoSuperNewTagList(cl, obj, NULL, &tag1);

  return retval;
}

If you declare the function static, gcc's optimizer looks at this and decides that the function uses only its first tag1 argument. And calls like:

 DoSuperNew(cl,  o,  MUIA_Foo, MUIV_Foo, MUIA_Bar, MUIV_Bar, TAG_MORE, and more)

are turned into: DoSuperNew(cl, o, MUIA_Foo)

Which in fact cause undefined behavior. In most cases FindTagItem() browses the stack's contents until it hits zero longword occasionally appeared somewhere, so you notice almost nothing. In some cases this can cause memory-trashing and illegal address accesses.

Perhaps a more future-proof solution would be to use va_start() and va_end() macros. On architecture, we talk about va_list is simply a pointer to current argument (i. e. in our example it will be &tag1 right after va_start()).

IPTR DoSuperNew(Class *cl, Object *obj, Tag tag1, ...)
{
  IPTR retval;
  va_list args;
  va_start(args, tag1);
  
  retval = DoSuperNewTagList(cl, obj, NULL, args);

  va_end(args);
  return retval;
}
NList.mcc/NList.mcc
NList.mcc/MUIA_NList_Active
NList.mcc/MUIA_NList_ActiveObjectOnClick
NList.mcc/MUIA_NList_AdjustHeight
NList.mcc/MUIA_NList_AdjustWidth
NList.mcc/MUIA_NList_AutoCopyToClip
NList.mcc/MUIA_NList_AutoVisible
NList.mcc/MUIA_NList_ButtonClick
NList.mcc/MUIA_NList_ClickColumn
NList.mcc/MUIA_NList_Columns
NList.mcc/MUIA_NList_CompareHook
NList.mcc/MUIA_NList_CompareHook2
NList.mcc/MUIA_NList_ConstructHook
NList.mcc/MUIA_NList_ConstructHook2
NList.mcc/MUIA_NList_CopyColumnToClipHook
NList.mcc/MUIA_NList_CopyColumnToClipHook2
NList.mcc/MUIA_NList_CopyEntryToClipHook
NList.mcc/MUIA_NList_CopyEntryToClipHook2
NList.mcc/MUIA_NList_DefaultObjectOnClick
NList.mcc/MUIA_NList_DefClickColumn
NList.mcc/MUIA_NList_DestructHook
NList.mcc/MUIA_NList_DestructHook2
NList.mcc/MUIA_NList_DisplayHook
NList.mcc/MUIA_NList_DisplayHook2
NList.mcc/MUIA_NList_DisplayRecall
NList.mcc/MUIA_NList_DoubleClick
NList.mcc/MUIA_NList_DragColOnly
NList.mcc/MUIA_NList_DragSortable
NList.mcc/MUIA_NList_DragSortInsert
NList.mcc/MUIA_NList_DragType
NList.mcc/MUIA_NList_DropMark
NList.mcc/MUIA_NList_DropType
NList.mcc/MUIA_NList_Entries
NList.mcc/MUIA_NList_EntryClick
NList.mcc/MUIA_NList_EntryValueDependent
NList.mcc/MUIA_NList_Exports
NList.mcc/MUIA_NList_First
NList.mcc/MUIA_NList_ForcePen
NList.mcc/MUIA_NList_Format
NList.mcc/MUIA_NList_Horiz_DeltaFactor
NList.mcc/MUIA_NList_Horiz_Entries
NList.mcc/MUIA_NList_Horiz_First
NList.mcc/MUIA_NList_Horiz_Visible
NList.mcc/MUIA_NList_IgnoreSpecialChars
NList.mcc/MUIA_NList_Imports
NList.mcc/MUIA_NList_Input
NList.mcc/MUIA_NList_InsertPosition
NList.mcc/MUIA_NList_KeepActive
NList.mcc/MUIA_NList_KeyUpFocus
NList.mcc/MUIA_NList_KeyDownFocus
NList.mcc/MUIA_NList_KeyLeftFocus
NList.mcc/MUIA_NList_KeyRightFocus
NList.mcc/MUIA_NList_LineHeight
NList.mcc/MUIA_NList_MakeActive
NList.mcc/MUIA_NList_MinColSortable
NList.mcc/MUIA_NList_MinLineHeight
NList.mcc/MUIA_NList_MultiClick
NList.mcc/MUIA_NList_MultiClickAlone
NList.mcc/MUIA_NList_MultiSelect
NList.mcc/MUIA_NList_MultiTestHook
NList.mcc/MUIA_NList_Pool
NList.mcc/MUIA_NList_PoolPuddleSize
NList.mcc/MUIA_NList_PoolThreshSize
NList.mcc/MUIA_NList_PrivateData
NList.mcc/MUIA_NList_Prop_DeltaFactor
NList.mcc/MUIA_NList_Prop_Entries
NList.mcc/MUIA_NList_Prop_First
NList.mcc/MUIA_NList_Prop_Visible
NList.mcc/MUIA_NList_Quiet
NList.mcc/MUIA_NList_SelectChange
NList.mcc/MUIA_NList_ShowDropMarks
NList.mcc/MUIA_NList_SkipChars
NList.mcc/MUIA_NList_SortType
NList.mcc/MUIA_NList_SortType2
NList.mcc/MUIA_NList_SourceArray
NList.mcc/MUIA_NList_SourceInsert
NList.mcc/MUIA_NList_SourceString
NList.mcc/MUIA_NList_TabSize
NList.mcc/MUIA_NList_Title
NList.mcc/MUIA_NList_TitleClick
NList.mcc/MUIA_NList_TitleClick2
NList.mcc/MUIA_NList_TitleMark
NList.mcc/MUIA_NList_TitleMark2
NList.mcc/MUIA_NList_TitleSeparator
NList.mcc/MUIA_NList_TypeSelect
NList.mcc/MUIA_NList_Visible
NList.mcc/MUIA_NList_XXXBackground
NList.mcc/MUIA_NList_XXXPen
NList.mcc/MUIM_NList_Clear
NList.mcc/MUIM_NList_ColWidth
NList.mcc/MUIM_NList_ColToColumn
NList.mcc/MUIM_NList_ColumnToCol
NList.mcc/MUIM_NList_Compare
NList.mcc/MUIM_NList_Construct
NList.mcc/MUIM_NList_ContextMenuBuild
NList.mcc/MUIM_NList_CopyTo
NList.mcc/MUIM_NList_CopyToClip
NList.mcc/MUIM_NList_CreateImage
NList.mcc/MUIM_NList_DeleteImage
NList.mcc/MUIM_NList_Destruct
NList.mcc/MUIM_NList_Display
NList.mcc/MUIM_NList_DoMethod
NList.mcc/MUIM_NList_DropDraw
NList.mcc/MUIM_NList_DropEntryDrawErase
NList.mcc/MUIM_NList_DropType
NList.mcc/MUIM_NList_Exchange
NList.mcc/MUIM_NList_GetEntry
NList.mcc/MUIM_NList_GetEntryInfo
NList.mcc/MUIM_NList_GetPos
NList.mcc/MUIM_NList_GetSelectInfo
NList.mcc/MUIM_NList_Insert
NList.mcc/MUIM_NList_InsertSingle
NList.mcc/MUIM_NList_InsertSingleWrap
NList.mcc/MUIM_NList_InsertWrap
NList.mcc/MUIM_NList_Jump
NList.mcc/MUIM_NList_Move
NList.mcc/MUIM_NList_NextSelected
NList.mcc/MUIM_NList_PrevSelected
NList.mcc/MUIM_NList_Redraw
NList.mcc/MUIM_NList_RedrawEntry
NList.mcc/MUIM_NList_Remove
NList.mcc/MUIM_NList_ReplaceSingle
NList.mcc/MUIM_NList_Select
NList.mcc/MUIM_NList_SelectChange
NList.mcc/MUIM_NList_SetActive
NList.mcc/MUIM_NList_SetColumnCol
NList.mcc/MUIM_NList_Sort
NList.mcc/MUIM_NList_Sort2
NList.mcc/MUIM_NList_Sort3
NList.mcc/MUIM_NList_TestPos
NList.mcc/MUIM_NList_UseImage
NList.mcc

This MCC public custom class is very similar to the MUI's list class. It handles directly most attributes which are handled by Listview in the original couple List/Listview. The NListview exist anyway to provide a complete object with scrollbars, so you should use it as child of NListview. Anyway, you can use NList without NListview if you don't want any built-in scrollbar.

NOTE: NList class will not work with Listview without some conflicts, and NListview class can't use List as child but only NList or a NList subclass.

MUIM_NList_TestPos and MUIM_List_TestPos are similar but use a different struct to store data.
MUIM_List_TestPos works like with a List object.

NOTE: Avoid as possible to do many things in MUIM_Show and MUIM_Hide methods because when an object is in a virtual group, your object will receive them for each one of its moves !!!

Standard tags with NList special values :

MUIA_Background   has the same meaning than MUIA_NList_ListBackground but only at init.

MUIA_Font         is settable only at init. MUIV_NList_Font, MUIV_NList_Font_Little
                  and MUIV_NList_Font_Fixed are special values usable for it (settable in prefs)
                  but standard values are usable too.

MUIA_Frame        you can override the defaults frames of the classe by setting it, but it will
                  be overrided again by defaults if a set(obj,MUIA_NList_Input,bool) is made after.
                  if MUIA_NList_Input is TRUE then the default is MUIV_Frame_InputList, if FALSE
                  it's MUIV_Frame_ReadList.

MUIA_ContextMenu
MUIM_ContextMenuBuild
MUIM_ContextMenuChoice

MUIA_NList_Active -- [ISGN], LONG

        MUIV_NList_Active_Off
        MUIV_NList_Active_Top
        MUIV_NList_Active_Bottom
        MUIV_NList_Active_Up
        MUIV_NList_Active_Down
        MUIV_NList_Active_PageUp
        MUIV_NList_Active_PageDown

MUIA_NList_ActiveObjectOnClick -- [ISG], BOOL

    Default FALSE. If set to TRUE, the NList object will become the MUIA_Window_ActiveObject 
    of its window when you click on it. In addition, the active selected entries 
    will switch an inactive color (e.g. grey) in case the NList object isn't currently active. 
    As soon as the object is active it will then also receive all user keys pressed.

MUIA_NList_AdjustHeight -- [I..], BOOL

    Same function as List.mui/MUIA_List_AdjustHeight.

        Will adjust the nlist height if the nlist object is in a virtual
        group or if MUIA_NList_SourceInsert, MUIA_NList_SourceString,
        MUIA_NList_SourceArray or MUIA_List_SourceArray was used.

        When the object is in a virtual group, a re-layout of this one
        will be forced when the entries number of the NList object change,
        so all entries should always be visible.

    DEFAULT
        FALSE

MUIA_NList_AdjustWidth -- [I..], BOOL

    FUNCTION
        Same function as List.mui/MUIA_List_AdjustWidth.

        Will adjust the nlist width if the nlist object is in a virtual
        group or if MUIA_NList_SourceInsert, MUIA_NList_SourceString,
        MUIA_NList_SourceArray or MUIA_List_SourceArray was used.

    DEFAULT
        FALSE

NList.mcc/MUIA_NList_AutoClip

    NAME
        MUIA_NList_AutoClip -- [ISG], BOOL

    FUNCTION
        If set to TRUE and the NList object is in read-only (NoInput) mode and
        is set to select char-wide rather than by line, the selected content is
        immediately copied to the clipboard as soon as it is selected via the
        mouse.

MUIA_NList_AutoCopyToClip -- [IS.], BOOL

    FUNCTION
        If set to TRUE you can copy the selected area to the
        clipboard 0 with Amiga-C and Amiga-X (Amiga-X because
        i have seen that sometimes Amiga-C is a shortcut !).
        (works with both Right-Amiga and Left-Amiga keys)

        MUIA_NList_AutoCopyToClip == TRUE also requires that the NList object
        is either the window's active object (see MUIA_Window_ActiveObject) or
        the attached list object is window's default object (see
        MUIA_Window_DefaultObject). Otherwise nothing will ever be copied!

MUIA_NList_AutoVisible -- [ISG], BOOL

    FUNCTION
        Same function as List.mui/MUIA_List_AutoVisible.

        Seting this to TRUE, the NList object will automatically and
        always jump to show the active entry.

    DEFAULT
        FALSE

MUIA_NList_ButtonClick -- [..GN], LONG

    FUNCTION
        You'll get a notify on it each time the user
        clicks one of the buttons made by ESC O[...@<n>] or ESC o[...@<n>].

        The returned value is the <n> of the clicked image/object.
        (see MUIA_NList_DisplayHook for more).

        If you get that value later, it will still be <n> of the latest
        image/object clicked that you'll get.

MUIA_NList_ClickColumn -- [..G], LONG

    FUNCTION
        Same function as Listview.mui/MUIA_Listview_ClickColumn.

MUIA_NList_Columns -- [ISGN], BYTE *

    FUNCTION
        With this tag you can set/get the visible order of columns (as if changed
        by the user). It work for all columns in one time (use MUIM_NList_SetColumnCol
        if you want to exchange 2 columns).

        The value is a pointer on an BYTE array, each byte is for a column
        (in the visible order) and have the value of the display hook col
        which have to be displayed in it.

        The array must be ended with a -1 value.

MUIA_NList_CompareHook -- [IS.], struct Hook *

    FUNCTION
        Same function as List.mui/MUIA_List_CompareHook.

MUIA_NList_CompareHook2 -- [IS.], struct Hook *

    FUNCTION
        Same function as MUIA_NList_CompareHook but A2 will be the object
        and A1 a NList_CompareMessage struct pointer.

MUIA_NList_ConstructHook -- [IS.], struct Hook *

    FUNCTION
        Same function as List.mui/MUIA_List_ConstructHook.

        Think to finish lines entries on a \0 , \n and \r.
        The list will not display anything which come after
        a \n , \r or \0, so finish lines entries on a \0, \r
        and \n if you dont want to waste memory.

    SPECIAL INPUTS
        MUIV_NList_ConstructHook_String

        It's a built-in hook that copy a string entry.
        (so original string can be trash after)
        the MUIV_NList_DestructHook_String
        must be set, too if you use it.

MUIA_NList_ConstructHook2 -- [IS.], struct Hook *

    FUNCTION
        Same function as MUIA_NList_ConstructHook but A2 will be the object
        and A1 a NList_ConstructMessage struct pointer.

MUIA_NList_CopyColumnToClipHook -- [IS.], struct Hook *

    FUNCTION
        This hook will be called while a MUIM_NList_CopyToClip
        for each column string. You will get in entry
        a string given by your own MUIA_NList_DisplayHook/2, so
        you must not use the same buffer for both !

        You'll get the entry num in -1 element of the given array,
        elements 1 and 2 are the positions of the first selected
        char and the last+1.

        You must return the pointer of the string to copy to
        clipboard in element 0, a the string length in element 1.

        The builtin hook skip all ESC chars plus their next char
        (and [...] for ESC-P, ESC-I, ESC-O and ESC-o), and add a
        tab char between columns.

MUIA_NList_CopyColumnToClipHook2 -- [IS.], struct Hook *

    FUNCTION
        Same function as MUIA_NList_CopyColumnToClipHook but A2 will be the object
        and A1 a NList_CopyColumnToClipMessage struct pointer.

MUIA_NList_CopyEntryToClipHook -- [IS.], struct Hook *

    FUNCTION
        This work near like MUIA_NList_DisplayHook, except
        that it is not called when the NList object want to
        display its lines but when it want to copy them
        to clipboard (or other). See MUIM_NList_CopyToClip.

        You can return only one string pointer (only one
        column for copy), as element 0 of the array.

        The -1 element is the entry number only when
        you don't give a entry pointer to NList_CopyToClip method,
        else it's -1.

        Elements 1,2,3 and 4 of the given array are first column/pos
        and last column/pos which are selected.
        Elements 5 and 6 are 2, 1 or 0 when the 1th and 3rd pos are
        in the format preparse string, the special entry preparse string
        or in the normal string for that entry/columns.

        For column, -1 is the first and -2 the last, else it's its number.
        This is the number of displayed columns and not the corresponding
        entry in the array return by DisplayHook. Anyway, positions are
        calculated from strings returned by DisplayHook.

        For pos, -1 is left of column and -2 its end. The last pos should
        not be included.

        You should use MUIA_NList_CopyColumnToClipHook unless you don't
        want what is seen in the list to be copied.

MUIA_NList_CopyEntryToClipHook2 -- [IS.], struct Hook *

    FUNCTION
        Same function as MUIA_NList_CopyEntryToClipHook but A2 will be the object
        and A1 a NList_CopyEntryToClipMessage struct pointer.

MUIA_NList_DefaultObjectOnClick -- [ISG], BOOL

    FUNCTION
        If set to TRUE, the NList object will become the
        MUIA_Window_DefaultObject of its window when you
        click on it, so the user will be able to control
        the list with keys. The MUIA_Window_ActiveObject
        will be set to None, unless the current active
        object is the NList one itself or if it's the
        MUIA_NList_KeepActive one.

        There is a special meaning if you use both
        DefaultObjectOnClick and MUIA_NList_MakeActive.
        (see MUIA_NList_MakeActive)

    DEFAULT
        TRUE

MUIA_NList_DefClickColumn -- [ISG], LONG

    FUNCTION
        Same function as Listview.mui/MUIA_Listview_DefClickColumn.

MUIA_NList_DestructHook -- [IS.], struct Hook *

    FUNCTION
        Same function as List.mui/MUIA_List_DestructHook.

    SPECIAL INPUTS
        MUIV_NList_DestructHook_String

        It's a built-in hook that free the string entry
        previously allocated and copied by
        the MUIV_NList_ConstructHook_String built-in hook.

MUIA_NList_DestructHook2 -- [IS.], struct Hook *

    FUNCTION
        Same function as MUIA_NList_DestructHook but A2 will be the object
        and A1 a NList_DestructMessage struct pointer.

MUIA_NList_DisplayHook -- [IS.], struct Hook *

    FUNCTION
        Same function as List.mui/MUIA_List_DisplayHook.

        Do not modify the buffers you return in the hook anywhere
        else than in the hook when called by NList.
        (if you do so you MUST set MUIA_NList_DisplayRecall)

        You should return the same thing if it is called another
        time with the same inputs!
        The hook will be called with a pointer to the
        entry to be displayed in A1 and a pointer to
        a string array containing as many entries as
        your list may have cols in A2.
        You must fill this array with the strings that
        you want to display.
        The array is DISPLAY_ARRAY_MAX*2 large.
        In the DISPLAY_ARRAY_MAX+col element you can set a
        preparse string for the corresponding col element.
        Using it you'll be able to avoid copying the string in
        a buffer to add something in the beginning of the col
        string.

        The display hook also gets the position of the current entry
        as additional parameter. It is stored in the longword
        preceding the col array (don't forget it's a LONG).
        (setting that LONG value to -2 is another way to tell the object
        to not consider the return string pointer as valid next time
        he will want to use it, and he will recall the hook).

        When the hook function will be called to get the title strings,
        you'll get NULL in A1, and -1 as position of current entry.

        The hook function will be called each time a line (or a part of
        it) needs to be drawn (and when NList needs to compute length of
        columns contents).

        Here are the escape sequence known by the parsing of NList :
              (If you use C, ESC b can be written "\033b")

        \t          Tabulation. Go to the next tab boundary of the col.
                    tab positions are separated by 8 spaces by default.
        ESC -       Disable text engine, following chars will be printed
                    without further parsing.
        ESC u       Set the soft style to underline.
        ESC b       Set the soft style to bold.
        ESC i       Set the soft style to italic.
        ESC n       Set the soft style back to normal.
        ESC <n>     Use pen number n (2..9) as front pen. n must be a valid
                    DrawInfo pen as specified in "intuition/screens.h".
        ESC c       Center current line. only valid at the beginning.
        ESC r       Right justify current line. only valid at the beginning.
        ESC l       Left justify current line. only valid at the beginning.

        These ones are new or modified :

        ESC j       Justify left and right current line, but only at the beginning.
        ESC I[<s>]  Draw MUI image with specification <s>.
                    See Image.mui/MUIA_Image_Spec for image spec definition.
        ESC O[<p>]                     (ESC O[<s>|<width>|<height>,<minwidth>])
                    Draw the MUIM_NList_CreateImage at adress <p>.
                    (<p> should be an 8 hex digits number).
        ESC o[<n>]                     (ESC o[<s>|<width>|<height>,<minwidth>])
                    Draw the MUIM_NList_UseImage number <n>. If the <n> UseImage
                    don't exist or has been set to NULL, no image is drawn.
        ESC P[]     Use default front pen.
        ESC P[<n>]  Use pen number <n>. (it's a direct pen number, so you must
                    make MUI_ObtainPen and MUI_ReleasePen for it yourself,
                    best to do it is in Setup() and Cleanup() of a subclass).
        ESC T       Draw horizontal line on top of the entry for the col.
        ESC C       Draw horizontal line centered in the entry for the col.
        ESC B       Draw horizontal line on bottom of the entry for the col.
        ESC E       Draw horizontal line centered in the entry for the col,
                    but only on the left and right of the line contents.
        ESC t , ESC t[<n>] , ESC t[M<n>] , ESC t[I<n>]
                    Make the ESC C and ESC E horizontal line become thick and filled
                    with some color :
                    default is MPEN_FILL.
                    [<n>]  means than <n> is a direct pen color, like for ESC P[<n>]
                    [M<n>] means that <n> is MUI pen color number (MPEN_xxx ie 0..8)
                    [I<n>] means that <n> is Intuition dri pen number 0..11 (see
                            "intuition/screens.h")
        ESC t[N], ESC t[N<n>], ESC t[NM<n>], ESC t[NI<n>]
                    Make the ESC T, ESC C,ESC B, ESC E become a single black line,
                    or not black when using a <n>, M<n> or I<n> pen color.
                    ('N' is for Not thick ;)

        with ESC O[] and ESC o[], you can add [...@<n>] which will make the image/object
        act as a relverify button. When this "button" is released NList will notify
        MUIA_NList_ButtonClick with the value <n>.

        with ESC I[], ESC O[] and ESC o[], you can add [...|<width>] or
        [...|<width>|<height>] or [...|<width>|<height>,<minwidth>] or
        [...,<minwidth>] where :
          <width> will be the width in pixels of the image/object.
                  -1  means default image width unless <minwidth> is set.
                   0  means default image width.
          <height> will be the height in pixels of the image/object.
                  -1  means default image height (entry height is max).
                   0  means entry height.
          <minwidth> will be the min width in pixels before the next char/string/image.
                  when present, default height become entry height and
                  width become minwidth (if minwdith is bigger than image default
                  width), unless you set <width> and/or <height>.
          <minwidth> <width> and <height> must be a decimal number (%ld).

MUIA_NList_DisplayHook2 -- [IS.], struct Hook *

    FUNCTION
        Same function as MUIA_NList_DisplayHook but A2 will be the object
        and A1 a NList_DisplayMessage struct pointer.

MUIA_NList_DisplayRecall -- [.S.], BOOL

    FUNCTION
        If for some unusual reason you modify one of the buffer that
        your DisplayHook function usually return anywhere else than
        in the DisplayHook function when called by the NList object,
        you must set it to TRUE, so the object will know it.

MUIA_NList_DoubleClick -- [..GN], LONG

    FUNCTION
        You'll get a notify on it each time the user double
        clicks on an entry in the list, or on the title.

        The value is the entry number, which will be -1 when
        it's the title.

        You'll get a notify on it too when you press the 'return' key
        and the NList object is active or default.

        If you get() it, you'll get the last click position, which
        can be -2 if it was on nothing (ie not entry or title).

        For triple clicks and more, use MUIA_NList_MultiClick.

    NOTE
        Disabled for the title when MUIA_NList_TitleClick is used.

MUIA_NList_DragColOnly -- [ISG], LONG

    FUNCTION
        When set to a col number (displayhook col number, not the visible
        one), only the text of that col for the selected entry will
        be dragged instead of the visible part of the entry.

        Set it to -1 to come back to standard/default mode when you have
        changed it !

MUIA_NList_DragSortable -- [ISG], BOOL

    FUNCTION
        Same function as List.mui/MUIA_List_DragSortable.

        DragType will be MUIV_NList_DragType_Default unless you set it.

        No need for you to set MUIA_Dropable or MUIA_Draggable.

    DEFAULT
        FALSE

MUIA_NList_DragSortInsert -- [..GN], BOOL

    FUNCTION
        Same as MUIA_NList_InsertPosition but the notify is made only after
        a MUIA_NList_DragSortable move.

MUIA_NList_DragType -- [ISG], LONG

    SPECIAL INPUTS
        MUIV_NList_DragType_None        no drag
        MUIV_NList_DragType_Default     as set in prefs.
        MUIV_NList_DragType_Immediate   drag on borders and with qualifier, and
                                        immediate drag if non-multiselect mode.
        MUIV_NList_DragType_Borders     drag on borders and with qualifier.
        MUIV_NList_DragType_Qualifier   drag only using qualifier.

    FUNCTION
        Same function as Listview.mui/MUIA_Listview_DragType.

        If you want the user to be able to drag items out of
        your list, you must set this.
        Don't use MUIA_Draggable with NList or NListview.

MUIA_NList_DropMark -- [..G], LONG

    FUNCTION
        Same function as List.mui/MUIA_List_DropMark.

        After a successful drop-operation, this attribute holds
        the position where we should insert the new entry(ies).

MUIA_NList_DropType -- [..G], LONG

    FUNCTION
        Same function as MUIA_NList_DropMark but will return the
        current DropMark type instead of the DropMark entry number.

        After a successful drop operation, this attribute holds
        the type of dropmark which where drawn.

MUIA_NList_Entries -- [..GN], LONG

    FUNCTION
        Same function as List.mui/MUIA_List_Entries.

MUIA_NList_EntryClick -- [..GN], LONG

    FUNCTION
        You'll get a notify on it each time the user click
        on an entry in the list (on the title, use
        MUIA_NList_TitleClick for that).

        The value is the entry number.

        You'll get a notify on it too when you press the 'return' key
        and the NList object is active or default, but only if there
        is no notify asked on MUIA_NList_DoubleClick.

        If you get() it, you'll get the last click position, which
        can be -1 when on title and -2 if it was on nothing.

MUIA_NList_EntryValueDependent -- [ISG], BOOL

    FUNCTION
        If your display hook return different strings when the
        entry num value change for an identical entry pointer
        then you should set it.

    DEFAULT
        FALSE

MUIA_NList_Exports -- [ISG], LONG

    FUNCTION
        Tell the NList object what parts of it's state will have to
        be saved in MUIM_Export method (which is called by the
        MUIM_Application_Save method if the object has a ObjectID).

    SPECIAL INPUTS
        MUIV_NList_Exports_Active       save active entry number.
        MUIV_NList_Exports_Selected     save selected entries numbers.
        MUIV_NList_Exports_First        save first visible entry number.
        MUIV_NList_Exports_ColWidth     save widths of columns.
        MUIV_NList_Exports_ColOrder     save order of columns.
        MUIV_NList_Exports_Cols         save all about columns (width and order actually).
        MUIV_NList_Exports_All

    NOTE
        MUIV_NList_Exports_Selected can make a very long export (so a big program
        .cfg file) if the list has many selected entries. One long int
        (ie four bytes) is required for each selected entry...

        Active and First are always exported by the MUIM_Export method,
        having MUIV_NList_Exports_Active and MUIV_NList_Exports_First set or not.

    DEFAULT
        (MUIV_NList_Exports_Active | MUIV_NList_Exports_First | MUIV_NList_Exports_Cols)

MUIA_NList_First -- [ISGN], LONG

    SPECIAL INPUTS
        MUIV_NList_First_Top
        MUIV_NList_First_Bottom
        MUIV_NList_First_Up
        MUIV_NList_First_Down
        MUIV_NList_First_PageUp
        MUIV_NList_First_PageDown

    FUNCTION
        Get the number of the first visible entry.
        It can be set to change the first entry you want to be visible.

MUIA_NList_ForcePen -- [ISG], LONG

    SPECIAL INPUTS
        MUIV_NList_ForcePen_On
        MUIV_NList_ForcePen_Off
        MUIV_NList_ForcePen_Default

    FUNCTION
        Set the ForcePen mode, when on it force the 'selected pen' color
        in all the selected area. Else the color is forced only at the
        beginning of the area and can be changed by text escape sequences.

        The default is set by the user in the pref .mcp class.

        Getting in will give its current value.

MUIA_NList_Format -- [ISG], STRPTR

    FUNCTION
        NList is able to handle multi column lists. To define
        how many columns should be displayed and how they
        should be formatted, you specify a format string.

        This format string must contain one entry for each column
        you want to see. Entries are separated by commas, one
        entry is parsed via dos.library/ReadArgs().

        The template for a single entry looks like this:

        DELTA=D/N,PREPARSE=P/K,COL=C/N,BAR/S,TBAR/S,NOBAR=NB/S,
        SIMPLEBAR=SBAR/S,NOTITLEBUTTON=NOTB/S,
        WEIGHT=W/N,MINWIDTH=MIW/N,MAXWIDTH=MAW/N,
        COLWIDTH=CW/N,MINCOLWIDTH=MICW/N,MAXCOLWIDTH=MACW/N,
        PIXWIDTH=PW/N,MINPIXWIDTH=MIPW/N,MAXPIXWIDTH=MAPW/N,
        PARTCOLSUBST=PCS/K

    The first are similar to MUIA_List_Format ones :

        DELTA
           Space in pixel between this column and the next.
           the last displayed column ignores this setting.
           Defaults to 4.

        PREPARSE
           A preparse string for this column.

        COL
           This value adjusts the col number of the current column.
           Defaults to current column number (0,1,...)
           You can't use identical COL values for 2 or more columns.

        BAR
           Will draw a vertical bar between this and the next column.

        WEIGHT
           The weight of the column. As for MUI's group.

        MINWIDTH
           Minimum percentage of the list width for the current column.

        MAXWIDTH
           Maximum percentage of the list width for the current column.

        TBAR
           Will draw a vertical bar between this and the next column
           but only in the title (ignored if BAR is set).
           THIS IS A DEFAULT !

        NOBAR
           Don't draw a vertical bar between this and the next column at all.

        SIMPLEBAR
           Make te vertical bar a simple black one.

        NOTITLEBUTTON
           Will prevent the title of the column to act as a reverify
           button when you set MUIA_NList_TitleClick (or make a notify
           on it).

        COLWIDTH
           Wanted number of chars for the current column.
           You will get as PIXWIDTH with number*font_with.
           Possibly more than number chars will fit in the
           column if you use proportional font, anyway you
           are sure than number non-italic chars will fit.

        MINCOLWIDTH
           Minimum number of chars for the current column.

        MAXCOLWIDTH
           Maximum number of chars for the current column.

        PIXWIDTH
           Wanted number of chars for the current column.

        MINPIXWIDTH
           Minimum number of chars for the current column.

        MAXPIXWIDTH
           Maximum number of chars for the current column.

        PARTCOLSUBST
           If the partial column feature is turned on by the
           user (in his configuration) and the application
           developer has specified this option for a particular
           column, then a "..." text is displayed at the
           defined position if not all text fits into the
           column rather than showing a dotted vertical line
           at the end of the column. Possible values for
           this option are:

              DISABLED
                explicitly disables this feature for this
                column

              LEFT
                put "..." on the left side and strip text
                left aligned.

              CENTER
                put "..." at the center of the column and
                strip text on both sides around it.

              RIGHT
                put "..." on the right side and strip text
                right aligned.

        Note: You will have as many columns in your list as
              entries in the format string (i.e. number of
              commas + 1). Empty entries, e.g. with a format
              string of ",,,," are perfectly ok.

        MINPIXWIDTH, MAXPIXWIDTH, MINCOLWIDTH, MAXCOLWIDTH,
        MINWIDTH and MAXWIDTH will not be used if PIXWIDTH,
        or COLWIDTH is used.

        Only one of PIXWIDTH, COLWIDTH and WEIGHT will be
        used, the first find in this order.
        Biggest of MINPIXWIDTH, MINCOLWIDTH and MINWIDTH.
        Smallest of MAXPIXWIDTH, MAXCOLWIDTH and MAXWIDTH.
        If the min is bigger than the max the min will be used.

        Use PIX ones only for columns with images,
        and COL ones to be sure to get as many
        chars as wanted.

        All chars/images will be drawn for the last column
        always, specify some width for it anyway,
        as it will be used for centered and right aligned texts !

        Default values : WEIGHT=-1, MINWIDTH=5, MAXWIDTH=10000.

        Use MINWIDTH=0 if you don't use PIXWIDTH or COLWIDTH and
        don't want any min value.

        To get WEIGHT values as a percentage of the list
        width, choose them to have their total being 100.

        WEIGHT = -1 means that you want the column to have
        the width of the largest entry's column contents.
        MINWIDTH = -1 has the same meaning as for WEIGHT but for
        the min value.
        Default will be 100 for the last column, set it to -1 or
        -2 if you want to force it when more than one column, and
        to -2 to force it when only one column.

        Be aware that it can take long time to do that when there
        are many entries since this need a call to the dislpayhook,
        parse and find real length of all entries.
        Anyway using such stuff for one or more columns has the
        same overhead.

        The default list format is an empty string (""), this
        means an unformatted, single-column list.

    NOTE
        MUIA_NList_Format will not try to see if the new
        format is similar to previous one. It means that all
        column width will be re-computed (and all entries parsed
        if WEIGHT or MINWIDTH is -1), same for wrapping
        which will be recomputed for all entries.
        So, it's better to do it before inserting entries
        in order to do both.
        To clear, insert and set the format, the
        best is to set the format after the clear (fastest, no
        entry to parse) and before the insert.

    BUGS (FEATURE)
        Currently there is a maximum of 64 columns for a list.

MUIA_NList_Horiz_DeltaFactor -- [..GN], LONG

    FUNCTION
        Used for NListview. You can make a notification on it
        if you want to attach your own horizontal scrollbar
        and set the increment value of scrollbar's arrows :

        DoMethod(NLobj, MUIM_Notify, MUIA_NList_Horiz_DeltaFactor,MUIV_EveryTime,
          SBobj, 3, MUIM_Set,MUIA_Prop_DeltaFactor,MUIV_TriggerValue);

MUIA_NList_Horiz_Entries -- [..GN], LONG

    FUNCTION
        Used for NListview. You can make a notification on it
        in order to attach your own horizontal scrollbar :

        DoMethod(NLobj, MUIM_Notify, MUIA_NList_Horiz_Entries,MUIV_EveryTime,
          SBobj, 3, MUIM_Set,MUIA_Prop_Entries,MUIV_TriggerValue);

MUIA_NList_Horiz_First -- [.SGN], LONG

    FUNCTION
        Used for NListview. You can make a notification on it
        in order to attach your own horizontal scrollbar :

        DoMethod(NLobj, MUIM_Notify, MUIA_NList_Horiz_First,MUIV_EveryTime,
          SBobj, 3, MUIM_NoNotifySet,MUIA_Prop_First,MUIV_TriggerValue);
        DoMethod(SBobj, MUIM_Notify, MUIA_Prop_First,MUIV_EveryTime,
          NLobj, 3, MUIM_NoNotifySet,MUIA_NList_Horiz_First,MUIV_TriggerValue);

MUIA_NList_Horiz_Visible -- [..GN], LONG

    FUNCTION
        Used for NListview. You can make a notification on it
        in order to attach your own horizontal scrollbar :

        DoMethod(NLobj, MUIM_Notify, MUIA_NList_Horiz_Visible,MUIV_EveryTime,
          SBobj, 3, MUIM_NoNotifySet,MUIA_Prop_Visible,MUIV_TriggerValue);

MUIA_NList_IgnoreSpecialChars -- [ISG], const char *

    FUNCTION
        Used to let NList ignore a list of user definable characters during
        string parsing. Some Greek fonts need the 0xA0 character to display
        an Alpha characters. In this case the string "\xa0" should be supplied
        to make NList ignore this character and not treat 0xA0 as a "non
        breaking space".
        This string will *NOT* be copied by NList and must remain valid as long
        as the object exists!

    DEFAULT
        NULL

MUIA_NList_Imports -- [ISG], LONG

    FUNCTION
        Tell the NList object what parts of it's state must be loaded
        (and used) in MUIM_Import method (which is called by the
        MUIM_Application_Load method if the object has a ObjectID).

    SPECIAL INPUTS
        MUIV_NList_Imports_Active     load previous active entry number (and make it active).
        MUIV_NList_Imports_Selected   load previous selected entries numbers (and make them selected).
        MUIV_NList_Imports_First      load previous first visible entry number (and make it the first visible).
        MUIV_NList_Imports_ColWidth   load previous widths of columns (and set them).
        MUIV_NList_Imports_ColOrder   load previous order of columns (and set it).
        MUIV_NList_Imports_Cols       load all about columns (width and order actually).
        MUIV_NList_Imports_All

    DEFAULT
        (MUIV_NList_Imports_Active | MUIV_NList_Imports_First | MUIV_NList_Imports_Cols)

MUIA_NList_Input -- [ISG], BOOL

    FUNCTION
        Same function as NListview.mcc/MUIA_Listview_Input.

    DEFAULT
        TRUE

MUIA_NList_InsertPosition -- [..GN], LONG

    FUNCTION
        Same function as List.mui/MUIA_List_InsertPosition.

MUIA_NList_KeepActive -- [.S.], Obj *

    FUNCTION
        Useful when MUIA_NList_DefaultObjectOnClick to not
        have the specified object deactivated.
        A NListview object set it to it's NList child at
        creation time, so you should not have to use that tag.

MUIA_NList_KeyUpFocus -- [ISG], Object *

    FUNCTION
        Allows to specify an object that will be set as the new
        window's active object in case the user pressed the UP cursor key
        and the NList object itself doesn't have anything further to
        scroll up.

MUIA_NList_KeyDownFocus -- [ISG], Object *

    FUNCTION
        Allows to specify an object that will be set as the new
        window's active object in case the user pressed the DOWN cursor key
        and the NList object itself doesn't have anything further to
        scroll down.

MUIA_NList_KeyLeftFocus -- [ISG], Object *

    FUNCTION
        Allows to specify an object that will be set as the new
        window's active object in case the user pressed the LEFT cursor key
        and the NList object itself doesn't have anything further to
        scroll to the left.

MUIA_NList_KeyRightFocus -- [ISG], Object *

    FUNCTION
        Allows to specify a specific object that will be set as the new
        window's active object in case the user pressed the RIGHT cursor key
        and the NList object itself doesn't have anything further to
        scroll to the right.

MUIA_NList_LineHeight -- [..GN], LONG

    FUNCTION
        Get the current line height.

MUIA_NList_MakeActive -- [.S.], Obj *

    FUNCTION
        Use it if you want an object to be activated when you click
        in the list object.
        To be able to control the list with key,
        use MUIA_NList_DefaultObjectOnClick instead.

        Using both MUIA_NList_MakeActive and
        MUIA_NList_DefaultObjectOnClick then the specified object
        will be activated only if there is already an active one.

        The only object which should be set should be the NListview
        parent object of the current NList one.

MUIA_NList_MinColSortable -- [ISG], LONG

    FUNCTION
        Sets the number of the first visible column which
        can be sorted, ie exchanged with some other one.

        Default is 1, making the leftmost (0) column not sortable.

        Just set it to a big number (100 for example) to forbid
        the columns sorting.

MUIA_NList_MinLineHeight -- [IS.], LONG

    FUNCTION
        Same function as List.mui/MUIA_List_MinLineHeight.

        Sets the minimum line height for lists in pixels.

        If <= 0 then it's absolute value will replace the
        'Leading' value of prefs which is added to the
        font height.

        It seems that the original MUIA_List_MinLineHeight uses
        its positive value as a 'leading' one, which is not
        logical when I read its doc (!), so I do the
        change internally to get it works like with list...

MUIA_NList_MultiClick -- [..GN], LONG

    FUNCTION
        You'll get a notification on it each time the user
        multiclicks more than twice on an entry in the
        list, or on the title. You'll get the number of
        the click (3, 4, 5...) for each. Note that you'll
        not get MUIA_NList_MultiClick for a double click;
        you must use MUIA_NList_DoubleClick for that.
        The time between each click must be less or equal
        to the double click time set in Amiga Input prefs.

        To know on which entry the multiclick was made
        getting MUIA_NList_DoubleClick value.

        So you can make a notification on it.

    NOTE
        Disabled for the title when MUIA_NList_TitleClick is used.

MUIA_NList_MultiClickAlone -- [..GN], LONG

    FUNCTION
        You'll get a notification only for the final multiclick number,
        so if there are three clicks there will be only one multiclickalone
        notified, a little (max time between two clicks) after the third one.
        It is the major change with classic MUIA_NList_DoubleClick and
        MUIA_NList_MultiClick which do the notify for all clicks.

        The drawback is the unavoidable delay between the last click
        and the notification.

        You can know on which entry the multiclickalone was made
        getting MUIA_NList_DoubleClick value.

        A notification can be made on it.

MUIA_NList_MultiSelect -- (V7 ) [I..], LONG

    SPECIAL INPUTS
        MUIV_NList_MultiSelect_None
        MUIV_NList_MultiSelect_Default
        MUIV_NList_MultiSelect_Shifted
        MUIV_NList_MultiSelect_Always

    FUNCTION
        Same function as Listview.mui/MUIA_Listview_MultiSelect.

        < At the moment MultiSelect_Default is the same
        as MultiSelect_Shifted >

MUIA_NList_MultiTestHook -- [IS.], struct Hook *

    FUNCTION
        Same function as List.mui/MUIA_List_MultiTestHook.

MUIA_NList_Pool -- [I..], APTR

    FUNCTION
        Same function as List.mui/MUIA_List_Pool.

MUIA_NList_PoolPuddleSize -- [I..], ULONG

    FUNCTION
        Same function as List.mui/MUIA_List_PoolPuddleSize.

MUIA_NList_PoolThreshSize -- [I..], ULONG

    FUNCTION
        Same function as List.mui/MUIA_List_PoolThreshSize.

MUIA_NList_PrivateData -- [ISG], APTR

    FUNCTION
        It's private data of the object that is unused by NList.
        It can be used as wanted, as for MUIA_UserData.

MUIA_NList_Prop_DeltaFactor -- [..GN], LONG

    FUNCTION
        Used for NListview. You can make a notification on it
        in order to attach your own vertical scrollbar
        and set the increment value of scrollbar's arrows :

        DoMethod(NLobj, MUIM_Notify, MUIA_NList_Prop_DeltaFactor,MUIV_EveryTime,
          SBobj, 3, MUIM_Set,MUIA_Prop_DeltaFactor,MUIV_TriggerValue);

MUIA_NList_Prop_Entries -- [..GN], LONG

    FUNCTION
        Used for NListview. You can make a notification on it
        in order to attach your own vertical scrollbar :

        DoMethod(NLobj, MUIM_Notify, MUIA_NList_Prop_Entries,MUIV_EveryTime,
          SBobj, 3, MUIM_NoNotifySet,MUIA_Prop_Entries,MUIV_TriggerValue);

MUIA_NList_Prop_First -- [.SGN], LONG

    FUNCTION
        Used for NListview. You can make a notification on it
        in order to attach your own vertical scrollbar :

        DoMethod(NLobj, MUIM_Notify, MUIA_Prop_First,MUIV_EveryTime,
          SBobj, 3, MUIM_Set,MUIA_Prop_First,MUIV_TriggerValue);
        DoMethod(SBobj, MUIM_Notify, MUIA_Prop_First,MUIV_EveryTime,
          NLobj, 3, MUIM_Set,MUIA_Prop_First,MUIV_TriggerValue);

MUIA_NList_Prop_Visible -- [..GN], LONG

    FUNCTION
        Used for NListview. You can make a notification on it
        in order to attach your own vertical scrollbar :

        DoMethod(NLobj, MUIM_Notify, MUIA_NList_Prop_Visible,MUIV_EveryTime,
          SBobj, 3, MUIM_NoNotifySet,MUIA_Prop_Visible,MUIV_TriggerValue);

MUIA_NList_Quiet -- [.S.], BOOL

    FUNCTION
        Same function as List.mui/MUIA_List_Quiet.

        Consider using it when inserting or removing several entries
        one-by-one, it will go much faster.
        In all cases, all changes which can be done later are delayed.
        Quiet_Full mean that no notification caused by changes in the list will
        be made, while Quiet_Visual will do them (but delayed to after
        the Quiet_None).

    SPECIAL INPUTS
        MUIV_NList_Quiet_None       same as FALSE.
        MUIV_NList_Quiet_Full       all values but FALSE and MUIV_NList_Quiet_Visual (-2).
        MUIV_NList_Quiet_Visual

MUIA_NList_SelectChange -- [...N], BOOL

    FUNCTION
        Same function as Listview.mui/MUIA_Listview_SelectChange.

        A set(NLobj,MUIA_NList_SelectChange,TRUE) is made by NList
        whenever the selection state of one or more items in the
        list is changing.

    DEFAULT
        FALSE

MUIA_NList_ShowDropMarks -- [ISG], BOOL

    FUNCTION
        Same function as List.mui/MUIA_List_ShowDropMarks.

    DEFAULT
        FALSE

MUIA_NList_SkipChars -- [ISG], char *

    FUNCTION
        Same function as Floattext.mui/MUIA_Floattext_SkipChars.

MUIA_NList_SortType -- [ISGN], LONG

    FUNCTION
        This value will be set in the NList_CompareMessage struct
        of MUIA_NList_CompareHook2 hook function.

        It is set by MUIM_NList_Sort2 and MUIM_NList_Sort3 methods too.

    EXAMPLES
        See NList-Demo program.

MUIA_NList_SortType2 -- [ISGN], LONG

    FUNCTION
        This value will be set in the NList_CompareMessage struct
        of MUIA_NList_CompareHook2 hook function.

        It is set by MUIM_NList_Sort3 method, too.

    EXAMPLES
        See NList-Demo program.

MUIA_NList_SourceArray -- [I..], APTR

    FUNCTION
        Same function as List.mui/MUIA_List_SourceArray.

MUIA_NList_SourceInsert -- [I..], struct MUIP_NList_InsertWrap *

    FUNCTION
        Same as DoMethod(obj,MUIM_NList_InsertWrap,...)
        with ... same as the contents of the passed struct,
        but at init.

MUIA_NList_SourceString -- [I..], char *

    FUNCTION
        Same as
        DoMethod(obj,MUIM_List_Insert,string,-2,MUIV_NList_Insert_Bottom)
        but at init.

MUIA_NList_TabSize -- [ISG], ULONG

    FUNCTION
        Same function as Floattext.mui/MUIA_Floattext_TabSize.

        Set how many spaces is the tabulation.

        Default is 8.

MUIA_NList_Title -- [ISG], char *

    FUNCTION
        Same function as List.mui/MUIA_List_Title.

        The title will be redrawn each time you set it.

        When you use a display hook, its value is used as a BOOL/LONG
        which can have any value (just not NULL if you want to see it).

        The value returned by get() will be the same than the last one
        given in the set() or at init.

MUIA_NList_TitleClick -- [ISGN], LONG

    FUNCTION
        A notification is received each time the user
        clicks one the title (only if on a column, so not on the
        vertical bar column separator which is used to modify the
        column-width with mouse).

        The returned value is the col number (display hook col number).

        If you get that value later, it will still be the latest
        *title* click col received.

        If a notification on that tag is requested, or if you set it (with any
        value), the title will act as if each of its column titles were
        separated buttons, notifying that tag when they are released.

        Using MUIA_NList_TitleSeparator and BAR or TBAR for each
        column in the MUIA_NList_Format string will improve the
        (released) look for those title "buttons".

        There are no shortkeys for these custom buttons and never will be,
        so find another way to access the related material.

        Don't ask for customized frames for them :  they are not real
        MUI and separated buttons but directly handled by NList, and I
        consider it already sufficient.

    NOTE
        When you use MUIA_NList_TitleClick, you will not receive
        MUIA_NList_DoubleClick and MUIA_NList_MultiClick when clicking
        on the title any more.

    EXAMPLES
        See NList-Demo program.

MUIA_NList_TitleClick2 -- [ISGN], LONG

    FUNCTION
        Works like MUIA_NList_TitleClick but when the qualifier is pressed while clicking

    EXAMPLES
        See NList-Demo program.

MUIA_NList_TitleMark -- [ISG], LONG

    FUNCTION
        Draw a mark on the corresponding display hook column.

        The value give two informations :  the column and the type of mark.

        Usually set to the MUIA_NList_SortType value (which is set by
        MUIM_NList_Sort3, this one called from a MUIA_NList_TitleClick notify).

    SPECIAL INPUTS
        MUIV_NList_TitleMark_None
        MUIV_NList_TitleMark_Down   | col
        MUIV_NList_TitleMark_Up     | col
        MUIV_NList_TitleMark_Box    | col
        MUIV_NList_TitleMark_Circle | col

    EXAMPLES
        See NList-Demo program.

MUIA_NList_TitleMark2 -- [ISG], LONG

    FUNCTION
        Draw a secondary mark on the corresponding display hook column.

        The value give 2 informations :  the column and the type of mark.

        Usually set to the MUIA_NList_SortType2 value (which is set by
        MUIM_NList_Sort3, this one called from a MUIA_NList_TitleClick/2 notify).

    SPECIAL INPUTS
        MUIV_NList_TitleMark2_None
        MUIV_NList_TitleMark2_Down   | col
        MUIV_NList_TitleMark2_Up     | col
        MUIV_NList_TitleMark2_Box    | col
        MUIV_NList_TitleMark2_Circle | col

    EXAMPLES
        See NList-Demo program.

MUIA_NList_TitleSeparator -- [ISG], BOOL

    FUNCTION
        Setting it creates a horizontal bar between the
        title and the first visible entry (only when some title
        is visible).

    DEFAULT
        TRUE

MUIA_NList_TypeSelect -- [IS.], LONG

    SPECIAL INPUTS
        MUIV_NList_TypeSelect_Line
        MUIV_NList_TypeSelect_Char

    FUNCTION
        This tag offers a choice between the classic
        list selection by line and using a char precision
        selection.

        This should be used only for textviewer-like stuff,
        and never for standard lists.
        Anyway it's the only way to make direct copytoclip
        of a part of a line...

        Default is MUIV_NList_TypeSelect_Line of course.

MUIA_NList_Visible -- [..G], LONG

    FUNCTION
        Same function as List.mui/MUIA_List_Visible.

MUIA_NList_TitleBackground -- [ISG], LONG
MUIA_NList_ListBackground -- [ISG], LONG
MUIA_NList_SelectBackground -- [ISG], LONG
MUIA_NList_CursorBackground -- [ISG], LONG
MUIA_NList_UnselCurBackground -- [ISG], LONG

    FUNCTION
        All backgrounds of NList can be set with these attributes,
        look at Area.mui/MUIA_Background and Image.mui/MUIA_Image_Spec
        to see what kind of value can be used.
        Anyway, the defaults can be set with prefs and so do
        not set it yourself.

MUIA_NList_TitlePen -- [ISG], LONG
MUIA_NList_ListPen -- [ISG], LONG
MUIA_NList_SelectPen -- [ISG], LONG
MUIA_NList_CursorPen -- [ISG], LONG
MUIA_NList_UnselCurPen -- [ISG], LONG

    FUNCTION
        You can set all pens of NList with these attributes, their
        value must be of the type Pendisplay.mui/MUIA_Pendisplay_Spec.
        Look at Pendisplay.mui, Area.mui/MUIA_Background and
        Image.mui/MUIA_Image_Spec.

        Anyway, you can set the defaults with prefs and should
        not set it yourself.

MUIM_NList_Clear --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_Clear,);

    FUNCTION
        Same function as List.mui/MUIM_List_Clear.

MUIM_NList_ColWidth --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_ColWidth,LONG col,LONG width);

    FUNCTION
        Set a width for a col as if changed by the user with mouse, or
        reset it to its default size.
        Permit to get the user width of a col too.

    INPUTS
        col     number of the col (numbered as in display hook).

                special value :
              MUIV_NList_ColWidth_All     will set it for all columns.

        width   width to set (four is the minimum acceptable width).

                special values :
              MUIV_NList_ColWidth_Default reset to default.
              MUIV_NList_ColWidth_Get     set nothing, only return current.

    RESULT
        When a col is specified (ie not MUIV_NList_ColWidth_All), the current
        *user* width of the col will be returned :
        o -1 mean that the col has its default width, ie not set by the user
          or with this method.
        o 0  mean that the specified col is not valid.
          When MUIV_NList_ColWidth_All you'll get always 0.

MUIM_NList_ColToColumn --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_ColToColumn,LONG col);

    FUNCTION
        converts display hook col number to visible column number.

    INPUTS
        col     number of the col (numbered as in display hook).

    RESULT
        column number, -1 if no column use that col number.

MUIM_NList_ColumnToCol --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_ColumnToCol,LONG column);

    FUNCTION
        converts visible column number to display hook col number.

    INPUTS
        column   number of the column (visible).

    RESULT
        col number, -1 if the column is not valid.

MUIM_NList_Compare --

	SYNOPSIS
		DoMethod(obj,MUIM_NList_Compare,APTR entry1,APTR entry2,
        ULONG sort_type1,ULONG sort_type2);

	FUNCTION
		This method is called ONLY by NList.mcc when the application
        needs to compare two list entries, for example when MUIM_NList_Sort,
        MUIM_NList_Sort2, MUIM_NList_Sort3 are called. So, this method is
        only  useful  within  NList.mcc  subclass, function method should
        looks like normal MUIA_NList_CompareHook or MUIA_NList_CompareHook2 
        hook function. If your subclass will not override this method 
        NList.mcc implementation will be used and it will call 
        MUIA_NList_CompareHook or MUIA_NList_CompareHook2 hook in that case.

        When you are overriding this method you probably would like to override 
        MUIM_NList_Construct, MUIM_NList_Destruct and MUIM_NList_Display method 
        as well.

	INPUTS
		entry1     - First entry to compare.

		entry2     - Second entry to compare.

		sort_type1 - Sort type 1.

		sort_type2 - Sort type 2.

	RESULTS
        If entry1 > entry2 1, if entry1 ==  entry2  0  and  if  entry1  <
        entry2    -1.    i.e.    the    same    as    MUIA_NList_Compare,
        MUIA_NList_CompareHook2 or strcmp() alike functions.

	NOTE
        Do not call it by yourself! Method parameters
        structure might grow in the future! Be warned.

        Internal implementation of this method can use internal or passed
        arguments, so please do not cheat and if you do not override it, 
        pass the original arguments to super class.

MUIM_NList_Construct --

	SYNOPSIS
        DoMethod(obj,MUIM_NList_Construct,APTR entry,APTR pool);

    FUNCTION
        This method is called  ONLY  by  NList.mcc  when  application  is
        creating     new     entry     f.e.    when    MUIM_NList_Insert,
        MUIM_NList_InsertSingle or MUIM_NList_Replace is called. So, this
        method  is only useful within NList.mcc subclass, function method
        should   looks   like    normal    MUIA_NList_ConstructHook    or
        MUIA_NList_ConstructHook2  hook  function.  If your subclass will
        not override this method NList.mcc implementation will  be  used,
        and       it'll       call       MUIA_NList_ContructHook       or
		MUIA_NList_ConstructHook2 hook in that case.

        When, overriding this method, it is probably to override      
        MUIM_NList_Destruct, MUIM_NList_Compare and MUIM_NList_Display 
        methods as well.

	INPUTS
        entry - original entry pointer passed to  f.e.  MUIM_NList_Insert
				method. Equivalent of A1 register of
                MUIA_NList_ConstructHook.

		pool  - pool  header  pointer.  Equivalent  of  A2  register 
                of                             MUIA_NList_ConstructHook.

    RESULT
		New entry, similar as returned by one of construct hooks.

	NOTE
        Do not call it by yourself! Method parameters
        structure might grow in the future! Be warned.

        Internal implementation of this method can use internal or passed
        arguments,  so  please  do  not  cheat and  if  you  are  not
		overriding it, pass the original arguments to super class.

MUIM_NList_ContextMenuBuild --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_ContextMenuBuild, LONG mx, LONG my, LONG pos,
                                                LONG column, LONG flags,LONG ontop);

    FUNCTION
        Give possibilities to use MUIM_ContextMenuBuild builtin in NList
        and a custom context menu for a NList subclass.

        Here is how NList MUIM_ContextMenuBuild work :

        If MUIA_ContextMenu is NULL, NULL is returned (no menu).

        If MUIA_ContextMenu is none of special values, the supermethod is called.

        If MUIA_ContextMenu is MUIV_NList_ContextMenu_Never, MUIA_ContextMenu is
        set to NULL and NULL is returned.

        Else (it's a special value) MUIM_NList_ContextMenuBuild is called :

          If MUIM_NList_ContextMenuBuild return -1, NULL will be returned (no menu).

          If MUIM_NList_ContextMenuBuild return NULL, NList will return its own
          context menu, depending on prefs (it's the default case).

          If MUIM_NList_ContextMenuBuild return an menu object, NList will
          enable/disable its own menu entries in the menu if it found some,
          then return thqt object.

          2 special menuitems are recognised by NList, and are found by :
            DoMethod(MenuObj,MUIM_FindUData,MUIV_NList_Menu_Default_This)
          and
            DoMethod(MenuObj,MUIM_FindUData,MUIV_NList_Menu_Default_All)

        MUIA_ContextMenu special values are actually used :

          MUIV_NList_ContextMenu_Default   replaced by one of following.
          MUIV_NList_ContextMenu_TopOnly   only on title/top of list.
          MUIV_NList_ContextMenu_Always    always.
          MUIV_NList_ContextMenu_Never     never, replaced by NULL after.

          when using MUIV_NList_ContextMenu_TopOnly NList will set MUIA_ContextMenu
          NULL/non-NULL when the mouse move, which should permit to have
          the window menu avaible when the contents menu is not visible.

          Anyway actually (MUI 3.8) MUI has a bug/feature which make the
          MUIA_ContextMenu being looked at only when the mouse *enter*
          within the object bounds. MUIV_NList_ContextMenu_TopOnly stuff
          will be nicer when that MUI problem is fixed...

        Of course if you want NList to do what has to be done when a menu item
        has been selected, your MUIM_ContextMenuChoice should call the supermethod.

    INPUTS (for MUIM_NList_ContextMenuBuild)

        mx      current mouse x.
        my      current mouse y.
        pos     entry number returned by NList_TestPos.
        column  column returned by NList_TestPos.
        flags   flags returned by NList_TestPos.
        ontop   TRUE if mouse is on title/top of the list.

    RESULT
        NULL, -1 or a menustrip object.

    EXAMPLES
        To make a ContextMenu but have the NList one appear when the
        mouse in on title/top, just set MUIA_ContextMenu,MUIV_NList_ContextMenu_Always
        and make MUIM_NList_ContextMenuBuild return NULL when ontop in TRUE (else
        return your menustrip object). Call MUIM_ContextMenuChoice supermethod too.

        To make your own context menu which have the same menuitems as ones
        in NList context menu, set MUIA_ContextMenu,MUIV_NList_ContextMenu_Always
        and make MUIM_NList_ContextMenuBuild return always your menustrip object.
        Make 4 menuitems in your menustrip object which will be like these :
        { NM_ITEM ,  "Default Width: this" , 0 ,0 ,0 ,(APTR) MUIV_NList_Menu_DefWidth_This },
        { NM_ITEM ,  "Default Width: all"  , 0 ,0 ,0 ,(APTR) MUIV_NList_Menu_DefWidth_All },
        { NM_ITEM ,  "Default Order: this" , 0 ,0 ,0 ,(APTR) MUIV_NList_Menu_DefOrder_This },
        { NM_ITEM ,  "Default Order: all"  , 0 ,0 ,0 ,(APTR) MUIV_NList_Menu_DefOrder_All },
        They will be automatically enabled/disabled as needed by NList  :)
        Call MUIM_ContextMenuChoice supermethod too.

MUIM_NList_CopyTo --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_CopyTo, LONG pos, char *filename,
                                        APTR *result, APTR *entries);

    FUNCTION
        Do a copy to clipboard from some list entries or strings.

    INPUTS
        pos      entry number to be copied.
                 if MUIA_NList_CopyToClipHook is specified, it's what
                 it will return which will be copied instead of just
                 using the entry pointer as a string pointer.

                 special values :

            MUIV_NList_CopyTo_Active    copy list active entry
            MUIV_NList_CopyTo_Selected  copy list selected entries
            MUIV_NList_CopyTo_All       copy all list entries
            MUIV_NList_CopyTo_Entries   copy specified entries
            MUIV_NList_CopyTo_Entry     copy specified entry

            a "\n" will be inserted after each entry contents.

        filename name of the file to copy to. If NULL then the copy will be
                 done to a string (strptr).
        result   LONG pointer which fill be filled with MUIV_NLCT_Success if
                 no error occured while opening and writing in the file, else
                 it will be filled with MUIV_NLCT_OpenErr, MUIV_NLCT_WriteErr
                 or MUIV_NLCT_Failed (failed somewhere when making copy data).

                 if filename is NULL, result will be filled with a string pointer
                 to a string allocated by AllocVec(). Data will have been copied
                 in that string. You will have to free that string pointer yourself,
                 with a FreeVec(). If the returned string pointer is NULL then
                 the copy failed.
        entries  pointer to some entry, string, entries array or string array.
                 Its use depend on the pos value :
                 if MUIV_NList_CopyTo_Entry   then it's an entry pointer.
                 if MUIV_NList_CopyTo_Entries then it's an entry pointer
                                              array NULL terminated.
                 else :  not used, set to NULL.

    EXAMPLES
        LONG result = 0;
        DoMethod(obj,MUIM_NList_CopyTo, 5, "RAM:test.txt", &result, NULL, NULL);

          will copy the 5th entry to file RAM:test.txt, using
          MUIA_NList_CopyToClipHook if set.

        LONG result = 0;
        DoMethod(obj,MUIM_NList_CopyTo, MUIV_NList_CopyToClip_Selected,
                                            "PRT:", &result, NULL, NULL);
          will copy all selected entries to printer, using
          MUIA_NList_CopyToClipHook for each if set.

        char *strptr = NULL;
        DoMethod(obj,MUIM_NList_CopyTo, MUIV_NList_CopyTo_All,
                                            NULL, &strptr, NULL, NULL);
          will copy all list entries to the string returned in strptr.
          you must make a FreeVec(strptr) by yourself after.

MUIM_NList_CopyToClip --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_CopyToClip, LONG pos, ULONG clipnum,
                                            APTR *entries, struct Hook *hook);

    FUNCTION
        Do a copy to clipboard from some list entries or strings.

    INPUTS
        pos      entry number to be copied.
                 if MUIA_NList_CopyToClipHook is specified, it's what
                 it will return which will be copied instead of just
                 using the entry pointer as a string pointer.

                 special values :

            MUIV_NList_CopyToClip_Active    copy list active entry
            MUIV_NList_CopyToClip_Selected  copy list selected entries
            MUIV_NList_CopyToClip_All       copy all list entries
            MUIV_NList_CopyToClip_Entries   copy specified entries
            MUIV_NList_CopyToClip_Entry     copy specified entry
            MUIV_NList_CopyToClip_Strings   copy specified strings using hook
            MUIV_NList_CopyToClip_String    copy specified string using hook

            a "\n" will be insert after each entry contents, for all but
            MUIV_NList_CopyToClip_Strings and MUIV_NList_CopyToClip_String.

        clipnum  clipboard number to copy to.
        entries  pointer to some entry, string, entries array or string array.
                 Its use depend on the pos value :
                 if MUIV_NList_CopyToClip_Entry   then it's an entry pointer.
                 if MUIV_NList_CopyToClip_Entries then it's an entry pointer
                                                  array NULL terminated.
                 if MUIV_NList_CopyToClip_String  then it's a string pointer.
                 if MUIV_NList_CopyToClip_Strings then it's an string pointer
                                                  array NULL terminated.
                 else :  not used, set to NULL.
        hook     hook function which will be used (if not NULL) for
                 MUIV_NList_CopyToClip_Strings and
                 MUIV_NList_CopyToClip_String
                 instead of MUIA_NList_CopyToClipHook
                 Should be NULL most of time.

    EXAMPLES
        DoMethod(obj,MUIM_NList_CopyToClip, 5, 0, NULL, NULL);
          will copy the 5th entry to clipboard 0, using
          MUIA_NList_CopyToClipHook if set.

        DoMethod(obj,MUIM_NList_CopyToClip, MUIV_NList_CopyToClip_Selected,
                                            0, NULL, NULL);
          will copy all selected entries to clipboard 0, using
          MUIA_NList_CopyToClipHook for each if set.

        DoMethod(obj,MUIM_NList_CopyToClip, MUIV_NList_CopyToClip_String,
                                            0, "my string", NULL);
          will copy "my string" to clipboard 0.

    NOTE
        MUIV_NList_CopyToClip_Strings and MUIV_NList_CopyToClip_String
        are here to permit simple text copy to clipboard for non nlist
        object related stuff (anyway a NList object must be here to use
        them...). They can use their own hook instead of the nlist's if
        non NULL, anyway look at MUIA_NList_CopyToClipHook to see how
        this hook will be used.

MUIM_NList_CreateImage --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_CreateImage,Object *imgobj, ULONG flags);

    FUNCTION
        Same function as List.mui/MUIM_List_CreateImage.

        Any transparent color in the source Bitmap/Bodychunk
        object will work (except if flags is ~0L).

        MUIM_NList_CreateImage must be used in Setup() or after
        and MUIM_NList_DeleteImage, in Cleanup() or before,
        because the mri of the NList object must be valid.
        Setup() and Cleanup() are the best because MUI_ObtainPen()
        and MUI_ReleasePen() are used, and then pens will be
        released while iconification and will be re-obtained
        if the screen change.

        Take a look at MUIM_NList_UseImage which is far easier to
        use.

        Standard flags value is 0.

        If flags is ~0L then FillArea will not be set to FALSE on the object
        (for any other value, FillArea is set to FALSE)

        If flags is ~0L for a Bitmap/Bodychunk then it will be really the
        given object which will be drawn, as for non Bitmap/Bodychunk objects.

        The imgobj can (nearly) be any object, but take care of that :

        - the object should not test and use user inputs, the object
          should just be able to draw itself within the _left(obj),
          _top(obj), _width(obj) and height(obj) it will have when its
          Draw method is called.
        - the object class MUST NOT be Group or subclass of it.
        - the given imgobj must not be attached to any group object
          anywhere else, because a ADDMEMBER will be done with it.
        - Each imgobj can be used with one and only one NList object.
        - you can use the return pointer with ESC O[<ptr>] and ESC o[<num>].
        - the object will receive two tags just before its Draw method will
          be called : set(imgobj,MUIA_NLIMG_EntryCurrent,current_entry_number) and
          set(imgobj,MUIA_NLIMG_EntryHeight,height_of_each_entry_of_the_list)
          which are usefull in some case to draw things (see demo example).
        - a new stuff is to use it with ESC O[<ptr>;<tag>;<value>], in that case
          a set(imgobj,tag,value) will be done just before drawing it, so
          you can make an object which will draw different things when that tag
          value is changed. Setting this tag MUST NOT cause the item to be redrawn!
          <tag> and <value> must both be in hexadecimal (%lx).
        - If you use ;<tag>;<value> in one ESC sequence for an imgobj, you should
          use it everywhere you use that imgobj because there is no default for it.
        - The imgobj height will always be set to the entries height.
        - The mindefheight of imgobj will become the min height for entries.
        - Think it's still a new testing stuff...

        Note:
          Previously the object was disposed by NList at its end, actually a call
          to MUIM_NList_DeleteImage will REMMEMBER it, and so you have to dispose
          of it yourself afterwards !

        Look the demo program to see a way to use it...

    RESULT
        The result you get is a struct BitMapImage pointer which
        will exist between the MUIM_NList_CreateImage and
        MUIM_NList_DeleteImage, with a valid bitmap, width and
        height for the current screen.

        If you use it for a non Bitmap/Bodychunk object (or with flags
        set to ~0L) then the mask and imgbmp fields of the returned
        struct BitMapImage are not valid, and obtainpens is a pointer to
        the object.

        The only thing you should do with it is to include it in
        \33O[%08lx]. The result may be NULL in which case NList
        was unable to create the image, but the \33O[] combination
        simply draws nothing when receiving a NULL.

        ATTENTION:
        The returned pointer doesn't give the same structure than
        MUIM_List_CreateImage (in standard List class) would do :
        both are not compatible at all !

MUIM_NList_DeleteImage --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_DeleteImage,APTR listimg);

    FUNCTION
        Same function as List.mui/MUIM_List_DeleteImage.

        Delete the image pointer returned from MUIM_NList_CreateImage.
        Read explains in MUIM_NList_CreateImage.

MUIM_NList_Destruct --

	SYNOPSIS
		DoMethod(obj,MUIM_NList_Destruct,APTR entry,APTR pool);

    FUNCTION
        This method is called  ONLY  by  NList.mcc  when  application  is
        deleting  entry f.e. when MUIM_NList_Remove or MUIM_NList_Replace
        are called. So, this  method  is  only  useful  within  NList.mcc
        subclass,    function    method    should   looks   like   normal
        MUIA_NList_DestructHook    or    MUIA_NList_DestructHook2    hook
        function.   If  your  subclass  will  not  override  this  method
        NList.mcc  implementation  will   be   used,   and   it'll   call
        MUIA_NList_DestructHook  or MUIA_NList_DestructHook2 hook in that
        case.

        When  you  are  overriding  this   method   you   must   override
        MUIM_NList_Construct    and   probably   MUIM_NList_Compare   and
        MUIM_NList_Display method as well.

    INPUTS
		entry - entry pointer returned by MUIM_NList_Construct method.

		pool  - pool header pointer.

    RESULT
        Currently undefined. When overriding it completely, please return 
        0, if not, use the value returned by super class!

	NOTE
        Do not call it by yourself! Method parameters structure might    
        grow in the future! Be warned.

        Internal implementation of this method can use internal or passed
        arguments,  so  please  do  not  cheat  and  if  you  are  not
		overriding it, pass the original arguments to super class.

MUIM_NList_Display --

	SYNOPSIS
		DoMethod(obj,MUIM_NList_Display,APTR entry,ULONG entry_pos,
		    STRPTR *strings,STRPTR *preparses);

    FUNCTION
        This method is called  ONLY  by  NList.mcc  when  application  is
        displaying  entry  f.e.  when  MUI_Redraw(), MUIM_NList_Redraw or
        MUIM_NList_RedrawEntry are called. So, this method is only useful
        within  NList.mcc  subclass,  function  method  should looks like
        normal  MUIA_NList_DisplayHook  or  MUIA_NList_DisplayHook2  hook
        function.   If  your  subclass  will  not  override  this  method
        NList.mcc  implementation  will   be   used,   and   it will call
        MUIA_NList_DisplayHook  or  MUIA_NList_DisplayHook2  hook in that
        case.

    INPUTS
		entry - Entry  pointer  returned  by  f.e.  MUIM_NList_Construct,
				MUIA_NList_ConstructHook or MUIA_NList_ConstructHook2
				hooks.

		entry_pos - Entry position.

		strings   - Pointer to strings table.

		preparses - Pointer to preparse strings table.

    RESULT
        Currently undefined. If you are overriding it completely,  please
        return 0, if not, use the value returned by super class!

	NOTE
        Do not call it by yourself! Method parameters the structure might 
        grow in the future! Be warned.

        Internal implementation of this method can use internal or passed
        arguments,  so  please  do  not  cheat  and  if  you  are  not
		overriding it, pass the original arguments to super class.

MUIM_NList_DoMethod --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_DoMethod,LONG pos,
                      APTR DestObj,ULONG FollowParams,ULONG method,...);

    FUNCTION
        The given method will be executed for each selected entry, the
        active entry, all entries, or one specified entry of the NList
        object.

        Each DoMethod() can be done on the NList object, its _app object,
        a specified object, or the entry pointer if (and only if) it's
        an object.

        Following arguments can be automatically adjusted for each call
        using special values, like in the MUIM_Notify method (you must
        specified the numer of following argument too, as there will be
        copied in a temporary buffer - alloced in the stack).

    INPUTS
        pos -           the entry number for which you want to do the method.

          special values :
          MUIV_NList_DoMethod_Active    do it for the active entry.
          MUIV_NList_DoMethod_Selected  do it for all selected entries.
          MUIV_NList_DoMethod_All       do it

        DestObj -       the object on which the method will be done.

          special values :
          MUIV_NList_DoMethod_Entry     use entry pointer as target object for method.
          MUIV_NList_DoMethod_Self      use the NList object as target for method.
          MUIV_NList_DoMethod_App       use the _app(NList object) as target for method.

        FollowParams -  the number of following parameters (including "method").
                        (maximum 40 to prevent errors and stack overflow)

        method -        the method which will be done.

        ... -           the method parameters.

          special values :
          MUIV_NList_EntryValue         replaced by the "current" entry pointer.
          MUIV_NList_EntryPosValue      replaced by the "current" entry number.
          MUIV_NList_SelfValue          replaced by the NList object.
          MUIV_NList_AppValue           replaced by _app(NList object)

    NOTES
        Don't use this to do things on the NList object when a specific way
        to do it exists (don't use it to remove entries in the nlist object
        itself for example).

        When using it in a notification, MUIV_TriggerValue and MUIV_TriggerValue
        special values will be replaced by the notify superclass as usual.

    EXAMPLES
        Insert all entries from nlist L1 to nlist L2 :

        DoMethod(L1, MUIM_NList_DoMethod, MUIV_NList_DoMethod_All,
          L2, 3,
          MUIM_NList_InsertSingle, MUIV_NList_EntryValue, MUIV_NList_Insert_Bottom);

        (it would be better to make set(L2,MUIA_NList_Quiet,TRUE) before and
         set(L2,MUIA_NList_Quiet,FALSE) after when there are many entries...)

        If the entries of nlist L1 are objects (and only in that case), it can be done
          to call a method (MUIM_Foo,x) for each selected of them :

        DoMethod(L1, MUIM_NList_DoMethod, MUIV_NList_DoMethod_Selected,
          MUIV_NList_DoMethod_Entry, 2,
          MUIM_Foo,x);

MUIM_NList_DropDraw --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_DropDraw, LONG pos, LONG type,
                                          LONG minx,LONG maxx,LONG miny,LONG maxy);

    FUNCTION
        This method MUST NOT be called directly !

        It will be called by NList, and will draw the drop mark previously fixed
        (pos and type) by MUIM_NList_DropType within the minx, maxx, miny, maxy
        in the _rp(obj) rasport. Do draw outside of the given box because only 
        the corresponding NList entry will be refreshed to erase what is drawn in 
        that method.

        Calling the supermethod (so the builtin MUIM_NList_DropDraw method) will draw
        the standard dropmark specified by (type & MUIV_NList_DropType_Mask), so
        MUIV_NList_DropType_None,MUIV_NList_DropType_Above,MUIV_NList_DropType_Below
        or MUIV_NList_DropType_Onto.

        You can draw directly in the rastport (or a clone of it) in that method,
        because it will be called from the Draw method within the DragReport in
        Refresh mode.

MUIM_NList_DropEntryDrawErase --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_DropEntryDrawErase,LONG type,LONG drawpos,LONG erasepos);

    FUNCTION
        This method MUST NOT be called directly !

        It will be called by NList while the DragReport just before the redraw
        which will draw a new mark or erase the old one.

        This method can be used to change something so your displayhook will return
        something different for the marked entry, like changing its color or making
        it bold or italic.

        Don't call the superclass unless you know that the superclass uses it.

        You should return 0.

    INPUTS
        type has the same meaning as *type in MUIM_NList_DropType, it will be useless
        in most cases (and has no meaning at all for erasepos).

        drawpos is the entry number which will be draw with a dropmark, -1 mean none.

        erasepos is the entry number which is not any more the dropmark one, -1 mean none.

MUIM_NList_DropType --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_DropType, LONG *pos,LONG *type,
                                          LONG minx,LONG maxx,LONG miny,LONG maxy,
                                          LONG mousex,LONG mousey);

    FUNCTION
        This method MUST NOT be called directly !

        It will be called by NList while the DragReport, with default *pos and *type
        values depending on the drag pointer position that you can modify as you want.

        Default *type can be MUIV_NList_DropType_Above or MUIV_NList_DropType_Below.
        You can change it to any of MUIV_NList_DropType_None,MUIV_NList_DropType_Above,
        MUIV_NList_DropType_Below and MUIV_NList_DropType_Onto if you want, using
        the mouse position and the entry box.

        You can make your own *type value as long as you don't set it in
        MUIV_NList_DropType_Mask, and so draw what you want depending on that value
        in the MUIM_NList_DropDraw method.

        Note that any MUIV_NList_DropType_Below *type will be changed to
        MUIV_NList_DropType_Above with a *pos incremented by 1 just after the
        return of that method.

        If you change the *pos, the list will be scrolled to see it (if the value is
        correct).

        getting MUIA_NList_DropType or MUIA_NList_DropMark will return the same values
        as *pos and *type.

        If your subclass is a direct NList subclass, then there is no need to call
        the supermethod which has done nothing at all !

MUIM_NList_Exchange --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_Exchange,LONG pos1, LONG pos2);

    FUNCTION
        Same function as List.mui/MUIM_List_Exchange.

        Exchange two entries in a NList object.

    INPUTS
        pos1 - number of the first entry.
        pos2 - number of the second entry.

        MUIV_NList_Exchange_Top
        MUIV_NList_Exchange_Active
        MUIV_NList_Exchange_Bottom
        MUIV_NList_Exchange_Next      only valid for second parameter
        MUIV_NList_Exchange_Previous  only valid for second parameter

MUIM_NList_GetEntry --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_GetEntry,LONG pos, APTR *entry);

    FUNCTION
        Same function as List.mui/MUIM_List_GetEntry.

    SPECIAL INPUTS
        MUIV_NList_GetEntry_Active    give active entry (or NULL if none)

MUIM_NList_GetEntryInfo --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_GetEntryInfo,struct MUI_NList_GetEntryInfo *res);

    FUNCTION
        You get useful information about some entry from its number,
        or from the real line number which can be different when there
        is word wrap in the list.

    INPUTS
        res - pointer to a MUI_NList_GetEntryInfo struct :
              LONG pos;       number of entry you want info about */
              LONG line;      real line number */
              LONG entry_pos; entry number of returned entry ptr */
              APTR entry;     entry pointer */
              LONG wrapcol;   NOWRAP, WRAPCOLx, or WRAPPED|WRAPCOLx */
              LONG charpos;   start char number in string (unused if NOWRAP) */
              LONG charlen;   string length (unused if NOWRAP) */

              if pos is MUIV_NList_GetEntryInfo_Line then the method will
              use the line number to search infos, or else the line will 
              be set to its correct number for the value of pos.
              entry is the entry ptr, think that if it's a word wrapped
              entry then it come from the returned entry_pos entry.
              Think, too, that if wrapcol tell you that it's a WRAPPED entry,
              only the WRAPCOLx col is drawn, from the charpos position
              in the string returned by DisplayHook for the column and for
              entry_pos/entry.

MUIM_NList_GetPos --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_GetPos,APTR entry,LONG *pos);

    FUNCTION
        Give the (next) entry number which have the given entry number.
        It's the entry ptr which is stored in the list, ie the one returned
        by the ConstructHook if any.

    INPUTS
        entry - Entry ptr of the entry you want to get the pos.

        pos - a pointer to longword that will hold the next entry number
              of the given entry ptr. Must be set to MUIV_NList_GetPos_Start
              if you want to search from the beginning of the list.
              Is set to MUIV_NList_GetPos_End no more is found.

MUIM_NList_GetSelectInfo --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_GetSelectInfo,struct MUI_NList_GetSelectInfo *res);

    FUNCTION
        Useful information about selected entries state is provided.

    INPUTS
        res - pointer to a MUI_NList_GetSelectInfo struct :
        LONG start        num of first selected *REAL* entry/line (first of wrapped from which start is issued)
        LONG end          num of last selected *REAL* entry/line (first of wrapped from which start is issued)
        LONG num          not used
        LONG start_column column of start of selection in 'start' entry
        LONG end_column   column of end of selection in 'end' entry
        LONG start_pos    char pos of start of selection in 'start_column' entry
        LONG end_pos      char pos of end of selection in 'end_column' entry
        LONG vstart       num of first visually selected entry (ie can be the second or third line of a word wrap entry)
            LONG vend         num of last visually selected entry (ie can be the second or third line of a word wrap entry)
            LONG vnum         number of visually selected entries

    NOTE
        If no entry is selected, then start, end, vstart, vend are -1, vnum is 0.

        When start_column, end_column, start_pos, end_pos are -1 then the whole line/entry/column
        is selected.

        start_column, end_columb, start_pos and end_pos have the same meaning than
        parameters passed to the MUIA_NList_CopyEntryToClipHook.

        remember that in case of automatically added word wrapped entries, only
        the concerned column have any contents. You get that case for 'vstart'
        when 'start' is different, and for 'end' when 'vend' is different.

MUIM_NList_Insert --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_Insert,APTR *entries, LONG count, LONG pos, LONG flags);

    FUNCTION
        Same function as List.mui/MUIM_List_Insert.

        Entry (display) contents will be display until \0 , \n or \r.

        You can insert a multiline string with count==-2.

    INPUTS
        entries - pointer to an array of pointers to be inserted.
                  Warning: This is a pointer to a pointer.

                  It's a pointer to string if count==-2.

        count   - Number of elements to be inserted. If count==-1,
                  entries will be inserted until NULL pointer in
                  the entries array is found.

                  If count==-2 then entries must be a string pointer
                  which can be multiline with \n , \r or \r\n separators.
                  There will be as many entries inserted as lines in the string.
                  The end char is \0.

        pos     - New entries will be added in front of this entry.
                MUIV_NList_Insert_Top     insert as first entry.
                MUIV_NList_Insert_Active  insert in front of the active entry.
                MUIV_NList_Insert_Sorted  insert sorted (all entries will be
                                          sorted if necessary).
                MUIV_NList_Insert_Bottom  insert as last entry.

        flags   - Special flags for the insert operation or 0.
                MUIV_NList_Insert_Flag_Raw insert the entries without the automatic
                                           reordering of the columns. This could
                                           significantly accelerate the insertion 
                                           of entries very, but will not automatically
                                           change the width of a column.

MUIM_NList_InsertSingle --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_InsertSingle,APTR entry, LONG pos);

    FUNCTION
        Same function as List.mui/MUIM_List_InsertSingle.

    INPUTS
        entry   - item to insert.

        pos     - New entry will be added in front of this entry.
                MUIV_NList_Insert_Top     insert as first entry.
                MUIV_NList_Insert_Active  insert in front of the active entry.
                MUIV_NList_Insert_Sorted  insert sorted (all entries will be
                                          sorted if necessary).
                MUIV_NList_Insert_Bottom  insert as last entry.

MUIM_NList_InsertSingleWrap --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_InsertSingleWrap,
                      APTR entry, LONG pos, LONG wrapcol, LONG align);

    FUNCTION
        Same function as MUIM_NList_InsertSingle but permit word wrap
        and alignment for the entry.

    INPUTS
        entry   - item to insert.

        pos     - New entry will be added in front of this entry.
                MUIV_NList_Insert_Top     insert as first entry.
                MUIV_NList_Insert_Active  insert in front of the active entry.
                MUIV_NList_Insert_Sorted  insert sorted (all entries will be
                                          sorted if necessary).
                MUIV_NList_Insert_Bottom  insert as last entry.

        wrapcol - WRAPCOL0 to WRAPCOL6. You can't ask word wrap for an
                other col. NOWRAP if you don't want word wrap.
                So only one of (display hook) col 0 to 6 can be wrapped.

        align   - ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT or ALIGN_JUSTIFY.
                be aware that align will be used if there is no escape
                align sequence in the preparses or column entry string.

MUIM_NList_InsertWrap --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_InsertWrap, APTR *entries,
                      LONG count, LONG pos, LONG wrapcol, LONG align);

    FUNCTION
        Same function as MUIM_NList_Insert but permit word wrap and
        alignement for the entry.

    INPUTS
        entries - pointer to an array of pointers to be inserted.
                  Warning: This is a pointer to a pointer.

                  It's a pointer to string if count==-2.

        count   - Number of elements to be inserted. If count==-1,
                  entries will be inserted until NULL pointer in
                  the entries array is found.

                  If count==-2 then entries must be a string pointer
                  which can be multiline with \n , \r or \r\n separators.
                  As many entries inserted as lines in the string will be provided.
                  The end char is \0.

        pos     - New entry will be added in front of this entry.
                MUIV_NList_Insert_Top     insert as first entry.
                MUIV_NList_Insert_Active  insert in front of the active entry.
                MUIV_NList_Insert_Sorted  insert sorted (all entries will be
                                          sorted if necessary).
                MUIV_NList_Insert_Bottom  insert as last entry.

        wrapcol - WRAPCOL0 to WRAPCOL6. You can't ask word wrap for an
                other col. NOWRAP if you don't want word wrap.
                So only one of (display hook) col 0 to 6 can be wrapped.

        align   - ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT or ALIGN_JUSTIFY.
                be aware that align will be used if there is no escape
                align sequence in the preparses or column entry string.

MUIM_NList_Jump --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_Jump,LONG pos);

    FUNCTION
        Same function as List.mui/MUIM_List_Jump.

    INPUTS
        pos - Number of the entry that should be made visible.
              Use MUIV_NList_Jump_Active to jump to the active
              entry. And use MUIV_NList_Jump_Active_Center to
              make the active entry visible centered in the
              listview.

MUIM_NList_Move --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_Move,LONG from, LONG to);

    FUNCTION
        Same function as List.mui/MUIM_List_Move.

    INPUTS
        pos1 - number of the first entry.
        pos2 - number of the second entry.

        Possible special values :

        MUIV_NList_Move_Top
        MUIV_NList_Move_Active
        MUIV_NList_Move_Bottom
        MUIV_NList_Move_Next        only valid for second parameter
                                    if first one is not Move_Selected
        MUIV_NList_Move_Previous    only valid for second parameter
                                    if first one is not Move_Selected
        MUIV_NList_Move_Selected    only valid for first parameter

MUIM_NList_NextSelected --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_NextSelected,LONG *pos);

    FUNCTION
        Same function as List.mui/MUIM_List_NextSelected.

        In TypeSelect_Char mode you'll get all entries of the selected
        area, even the first and last which can be partially selected.

    INPUTS
        pos - a pointer to longword that will hold the number
              of the returned entry. Must be set to
              MUIV_NList_NextSelected_Start at start of iteration.
              Is set to MUIV_NList_NextSelected_End when iteration
              is finished.

MUIM_NList_PrevSelected --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_PrevSelected,LONG *pos);

    FUNCTION
        Work like MUIM_NList_NextSelected but give the previous selected entry.

        In TypeSelect_Char mode you'll get all the entries of the selected
        area, even the first and last which can be partially selected.

    INPUTS
        pos - a pointer to longword that will hold the number
              of the returned entry. Must be set to
              MUIV_NList_PrevSelected_Start at start of iteration.
              Is set to MUIV_NList_PrevSelected_End when iteration
              is finished.

MUIM_NList_Redraw --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_Redraw,LONG pos);

    FUNCTION
        Same function as List.mui/MUIM_List_Redraw.
        Redraw some entries or all.

    INPUTS
        pos - Number of the line to redraw. When the line is not
              currently visible, nothing will happen. Specials:
              MUIV_NList_Redraw_Active   redraw the active line (if any),
              MUIV_NList_Redraw_All      redraw all lines.
              MUIV_NList_Redraw_Title    redraw the title.

MUIM_NList_RedrawEntry --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_RedrawEntry,APTR entry);

    FUNCTION
        Redraw some entries, like MUIM_NList_Redraw, but using the entry
        pointer instead of the entry number.

    INPUTS
        entry - Enter the part of the entry (entries) to be redrawn.

MUIM_NList_Remove --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_Remove,LONG pos);

    FUNCTION
        Same function as List.mui/MUIM_List_Remove.

    INPUTS
        pos - number of the entries to be removed or one of
              MUIV_NList_Remove_First
              MUIV_NList_Remove_Active
              MUIV_NList_Remove_Selected
              MUIV_NList_Remove_Last
              When the active or a selected entry is removed,
              the following entry will become active.
              When the active is the removed and is the last,
              the new last become active.

MUIM_NList_ReplaceSingle --

    FUNCTION
        DoMethod(obj,MUIM_NList_ReplaceSingle,
                      APTR entry, LONG pos, LONG wrapcol, LONG align);

    FUNCTION
        Same function as MUIM_NList_InsertSingleWrap but replace an existing
        entry rather than inserting.
        It's better to do a direct replace than remove then insert it !

    INPUTS
        entry   - item to insert.

        pos     - position of the entry to be replaced
                MUIV_NList_Insert_Top     replace the first entry.
                MUIV_NList_Insert_Active  replace the active entry.
                MUIV_NList_Insert_Bottom  replace the last entry.
                Invalid positions will cause the replacement to fail!

        wrapcol - WRAPCOL0 to WRAPCOL6. You can't ask word wrap for an
                other col. NOWRAP if you don't want word wrap.
                So only one of (display hook) col 0 to 6 can be wrapped.

        align   - ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT or ALIGN_JUSTIFY.
                be aware that align will be used if there is no escape
                align sequence in the preparses or column entry string.

MUIM_NList_Select --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_Select,LONG pos, LONG seltype, LONG *state);

    FUNCTION
        Same function as List.mui/MUIM_List_Select when in TypeSelect_Line mode.

        In TypeSelect_Char mode, MUIV_NList_Select_Off will clear the selected
        area (don't look what is pos). MUIV_NList_Select_On will select the
        pos entry only (can be MUIV_NList_Select_Active or MUIV_NList_Select_All).
        MUIV_NList_Select_Ask will give the number off entry in the selected area.

    INPUTS

        pos     - Number of the entry or
                  MUIV_NList_Select_Active  for the active entry.
                  MUIV_NList_Select_All     for all entries.

        seltype - MUIV_NList_Select_Off     unselect entry.
                  MUIV_NList_Select_On      select entry.
                  MUIV_NList_Select_Toggle  toggle entry.
                  MUIV_NList_Select_Ask     just ask about the state.

        state   - Pointer to a longword. If not NULL, this will
                  be filled with the current selection state.

MUIM_NList_SelectChange -- Called on every selection change (V19.98)

    SYNOPSIS
        DoMethod(obj,MUIM_NList_SelectChange,LONG pos, LONG state, ULONG flags);

    FUNCTION
        This method cannot/should not be called. Its purpose is only to indicate
        selection state changes of entries in a more powerful form than
        MUIA_NList_SelectChange does.
        It is only called when you are in line mode ie. MUIA_NList_TypeSelect is
        set to MUIV_NList_TypeSelect_Line, which is the default.

        pos     - The position of the (un)selected entry. Can be
                  MUIV_NList_Active_Off or something.
        state   - The resulting state of the entry which can be MUIV_NList_Select_On,
                  MUIV_NList_Select_Off or MUIV_NList_Select_Active.
        flags   - Can be MUIV_NList_SelectChange_Flag_Multi for now which means
                  that the entry was selected while holding down the mouse button.

    INPUTS

MUIM_NList_SetActive -- make a specific entry the active one (v20.125)

    SYNOPSIS
        DoMethod(obj, MUIM_NList_SetActive, LONG pos, ULONG flags);

    FUNCTION
        This method is a replacement function for the old-style way of making an
        entry active via a simple set(obj, MUIA_NList_Active, pos) call. While the
        old method still works, this new function has the advantage that it allows
        to set an entry active together with making it immediately visible in the
        listview.
        Previously, a developer had to do a combination of a set() call to set
        MUIA_NList_Active and then immediately perform a MUIM_NList_Jump function
        call so that the entry becomes visible at the specific position. With this
        new function both operations are combined, potentially allowing future
        enhancements to be added via the additional 'flags' variable.

    INPUTS
        The parameter description is as followed:

        pos     - The position (int) of the entry which should be made the new
                  active entry. This can also be MUIV_NList_Active_XXXX values as
                  explained in the MUIA_NList_Active documentation. Furthermore,
                  pos might also be a perfect pointer to the entry directly in
                  case you have specified the correct flag.

        flags   - Can be a combination of the following flags:

                  MUIV_NList_SetActive_Entry:

                    the parameter 'pos' will be a pointer to the entry rather
                    than the position (int) of the entry to be made active. If
                    this flag is set NList will perform an internal GetPos()
                    operation to first obtain the position and then set
                    this entry active.

                  MUIV_NList_SetActive_Jump_Center:

                    Together with making the specified entry the new active one
                    the listview will also be scrolled so that the new entry
                    will be shown centered instead of having it simply visible.

MUIM_NList_SetColumnCol --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_SetColumnCol,LONG column,LONG col);

    FUNCTION
        set which displayhook col is at the visible column.

    INPUTS
        column  number of the column (visible).
                if MUIV_NList_SetColumnCol_Default then the given (diplayhook) col
                will come back to its default/original (from List_Format) position.

        col     col number (displayhook one).
                if MUIV_NList_SetColumnCol_Default then the given visible column
                will come back to its default/original (from List_Format) position.

                both set to MUIV_NList_SetColumnCol_Default make all columns
                come back to their default/original (from List_Format) position.

    RESULT
        None.

    NOTE
        MUIM_NList_SetColumnCol always exchanges the moved column with the column
        which was where it moved.

MUIM_NList_Sort --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_Sort);

    FUNCTION
        Same function as List.mui/MUIM_List_Sort.

MUIM_NList_Sort2 --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_Sort2,LONG sort_type, LONG sort_type_add);

    FUNCTION
        Same function as MUIM_NList_Sort but will set MUIA_NList_SortType
        before starting the sort.

        It is really useful only if you use MUIA_NList_CompareHook2 instead
        of classic MUIA_NList_CompareHook so your hook will be able to do
        different type of sort when NList_SortType change.

    INPUTS
        sort_type     - The new MUIA_NList_SortType value (see below).

        sort_type_add - If 0 then sort_type will be the new MUIA_NList_SortType,
                        else if current MUIA_NList_SortType & MUIV_NList_SortTypeValue_Mask
                        is same as sort_type then sort_type_add will be added to the
                        MUIA_NList_SortType value,
                        else sort_type will be the new MUIA_NList_SortType.

                        See examples for special values.

    EXAMPLES
        Often, this method will be used to sort multicolumn list in different
        ways when the user click on title buttons :

        DoMethod(list,MUIM_Notify,MUIA_NList_TitleClick, MUIV_EveryTime,
          list, 3, MUIM_NList_Sort2, MUIV_TriggerValue, MUIV_NList_SortTypeAdd_xxx);

        if MUIV_NList_SortTypeAdd_None    then the hook sort_type value will be the column
                                          number.
        if MUIV_NList_SortTypeAdd_2Values then the hook sort_type value will be a cycle of
                                          values which change on each click :
                                          o Column number  (first time)
                                          o Column number + MUIV_NList_SortTypeAdd_2Values
                                          o back to column number ...

        if MUIV_NList_SortTypeAdd_4Values then the hook sort_type value will be a cycle of
                                          values which change on each click :
                                          o Column number  (first time)
                                          o Column number + MUIV_NList_SortTypeAdd_4Values
                                          o Column number + MUIV_NList_SortTypeAdd_4Values*2
                                          o Column number + MUIV_NList_SortTypeAdd_4Values*3
                                          o back to column number ...
        See NList-Demo program.

MUIM_NList_Sort3 --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_Sort3,LONG sort_type, LONG sort_type_add, LONG which);

    FUNCTION
        Same function as MUIM_NList_Sort2 but will set MUIA_NList_SortType,
        MUIA_NList_SortType2 or both before starting the sort.

        When using MUIV_NList_Sort3_SortType_Both the method will change
        MUIA_NList_SortType exactly the same way as MUIM_NList_Sort2 would do
        it, then copy that value to MUIA_NList_SortType2.

        It is really useful only if you use MUIA_NList_CompareHook2 instead
        of classic MUIA_NList_CompareHook so your hook will be able to do
        a different type of sort when NList_SortType changes.

    INPUTS
        sort_type     - The new MUIA_NList_SortType/2 value.

        sort_type_add - If 0 then sort_type will be the new MUIA_NList_SortType/2,
                        else if current MUIA_NList_SortType/2 & MUIV_NList_SortTypeValue_Mask
                        is same as sort_type then sort_type_add will be added to the
                        MUIA_NList_SortType/2 value,
                        else sort_type will be the new MUIA_NList_SortType/2.

        which         - MUIV_NList_Sort3_SortType_1      set MUIA_NList_SortType value.
                        MUIV_NList_Sort3_SortType_2      set MUIA_NList_SortType2 value.
                        MUIV_NList_Sort3_SortType_Both   set MUIA_NList_SortType value
                                                         then copy it to MUIA_NList_SortType2.

    EXAMPLES
        See NList-Demo program.

MUIM_NList_TestPos --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_TestPos,LONG x, LONG y, struct MUI_NList_TestPos_Result *res);

    FUNCTION
        Find out which information of a list which is currently
        displayed at a certain position.

        You must give a pointer to a valid MUI_NList_TestPos_Result struct.

        Set x AND y to MUI_MAXMAX to get infos about the last click position !

        See NList_mcc.h to know what values will be set in the struct.

        Preset char_number to -2 in the struct to not get char_number and char_xoffset
        informations. It's useful if you don't need them because it will be
        faster for the method without finding them. The -2 value will stay valid
        for next call.

        You'll get char number from what you return from the DisplayHook if there is
        one, else from the beginning of the string/entry ptr.

        Be aware: if you use MUIM_List_TestPos you have to give a pointer to a
        struct MUI_List_TestPos_Result, and you will get same infos as using a List object.
        It wasn't done as before, making enforcer hits when trying to use NList
        or NFloattext with a Listview instead of a NListview (avoid it please, it's not
        done for it as Listview try to make many things itself, with possible conficts),
        because struct MUI_NList_TestPos_Result is bigger !!!

    NOTE
        column in the struct MUI_NList_TestPos_Result is the visible column number !

MUIM_NList_UseImage --

    SYNOPSIS
        DoMethod(obj,MUIM_NList_UseImage,Object *obj, ULONG imgnum, ULONG flags);

    FUNCTION
        To use MUIM_NList_CreateImage/MUIM_NList_DeleteImage
        as you should, make a NList subclass which calls them
        from Setup() and Cleanup(), and it's sometimes complicated.

        To avoid that, use MUIM_NList_UseImage. NList will
        store the Bitmap/Bodychunk object you give and will make
        CreateImage and DeleteImage itself !

        MUIM_NList_UseImage can use same object as MUIM_NList_CreateImage !

        NULL is a valid obj. It will erase any previously UseImage
        with the same imgnum.

        The imgnum you give is the number that you will use in
        \33o[<n>] sequence as the <n> number.
        MUIM_NList_UseImage will accept 0 <= imgnum < 8192, anyway
        use small value if you can because an array will be allocated
        with the biggest imgnum value as size to store the
        Bitmap/Bodychunk objects.

        DoMethod(obj,MUIM_NList_UseImage, NULL, MUIV_NList_UseImage_All, 0)
        will set NULL to all stored objects, so you willll be able to dispose 
        your Bitmap/Bodychunk objects if you want, without waiting for the 
        NList object dispose.

        flags is the same than for MUIM_NList_CreateImage (0 unless special case).

    RESULT
        TRUE if succeeded to store the obj (and allocate the array
        if needed), else FALSE.

        There is no way to know if the MUIM_NList_CreateImage
        needed to draw will succeed/has succeeded.

        ATTENTION:
        The given Bitmap/Bodychunk object MUST be valid until the
        NList object is disposed or you set another object (or NULL)
        at the same imgnum !
        The Bitmap/Bodychunk object can be shared with other NList
        object because NList just use it to get informations, anyway
        you mustn't change informations of that object. If you to do
        so, do a UseImage,NULL,x , change it then do UseImage,imgobj,x
        again.

/***************************************************************************

 NList.mcc - New List MUI Custom Class
 Registered MUI class, Serial Number: 1d51 0x9d510030 to 0x9d5100A0
                                           0x9d5100C0 to 0x9d5100FF

 Copyright (C) 1996-2001 by Gilles Masson
 Copyright (C) 2001-2006 by NList Open Source Team

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 NList classes Support Site:  http://www.sf.net/projects/nlist-classes

 $Id: NList-Demo3.c 43734 2012-01-28 14:26:37Z mazze $

***************************************************************************/

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <dos/dos.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/ports.h>
#include <exec/io.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <libraries/gadtools.h>
#include <libraries/asl.h>
#include <libraries/mui.h>
#include <workbench/workbench.h>
#include <intuition/intuition.h>
#include <intuition/classusr.h>
#include <graphics/gfxmacros.h>
#undef GetOutlinePen

#if !defined(__amigaos4__)
#include <clib/alib_protos.h>
#endif

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/gadtools.h>
#include <proto/graphics.h>
#include <proto/utility.h>
#include <proto/asl.h>
#include <proto/intuition.h>

extern struct Library *MUIMasterBase;

#include <mui/NListview_mcc.h>
#include <mui/NFloattext_mcc.h>

#include "NList-Demo3.h"

#include <proto/muimaster.h>

#include "SDI_hook.h"

/* *********************************************** */

struct MUI_CustomClass *NLI_Class = NULL;

/* *********************************************** */

struct NLIData
{
  LONG special;
  LONG EntryCurrent;
  LONG EntryHeight;
};

/* *********************************************** */

IPTR mNLI_Draw(struct IClass *cl,Object *obj,struct MUIP_Draw *msg)
{
  register struct NLIData *data = INST_DATA(cl,obj);
  DoSuperMethodA(cl,obj,(Msg) msg);
  if ((msg->flags & MADF_DRAWOBJECT) || (msg->flags & MADF_DRAWUPDATE))
  { WORD x1,x2,x3,x4,x5,y1,y2,y3,y4,y5;
    y1 = _top(obj);
    y2 = _bottom(obj);
    x1 = _left(obj);
    x2 = _right(obj);
    if ((data->special == 0) || (data->special == 1))
    {
      y3 = (y1+y2)/2;
      x3 = (x1+x2)/2;
      SetAPen(_rp(obj),_pens(obj)[MPEN_MARK]);
      SetBPen(_rp(obj),_pens(obj)[MPEN_SHADOW]);
      SetDrMd(_rp(obj),JAM2);
      SetDrPt(_rp(obj),(UWORD) ~0);
      if      (data->special == 0)
      { Move(_rp(obj), x3-2, y1+1);
        Draw(_rp(obj), x3-2, y2-1);
        Move(_rp(obj), x3, y1+1);
        Draw(_rp(obj), x3, y2-1);
        Move(_rp(obj), x3+2, y1+1);
        Draw(_rp(obj), x3+2, y2-1);
      }
      else if (data->special == 1)
      { Move(_rp(obj), x1, y3-2);
        Draw(_rp(obj), x2, y3-2);
        Move(_rp(obj), x1, y3);
        Draw(_rp(obj), x2, y3);
        Move(_rp(obj), x1, y3+2);
        Draw(_rp(obj), x2, y3+2);
      }
      SetAPen(_rp(obj),_pens(obj)[MPEN_SHADOW]);
      Move(_rp(obj), x1, y2-1);
      Draw(_rp(obj), x1, y1+1);
      Draw(_rp(obj), x2, y1+1);
      SetAPen(_rp(obj),_pens(obj)[MPEN_SHINE]);
      Draw(_rp(obj), x2, y2-1);
      Draw(_rp(obj), x1, y2-1);
      SetDrMd(_rp(obj),JAM1);
    }
    else if (((x2 - x1) >= 10) && ((y2 - y1) >= 8))   /* and special==2 to 9 */
    {
      y3 = (y1+y2)/2;
      x3 = x1 + 1;
      x2--;
      SetAPen(_rp(obj),_pens(obj)[MPEN_SHADOW]);
      SetDrMd(_rp(obj),JAM1);

      y4 = y1;
      x4 = x3 + 2;
      y5 = y2;
      x5 = x2-6;
      if ((data->EntryHeight & 1) && (data->EntryCurrent & 1))
        y4++;
      if ((y4 & 1) != (y3 & 1))
        x4--;
      if (data->special > 5)
        x5 = x2;
      if (data->special & 1)
        y5 = y3;
      while (y4 <= y5)
      { WritePixel(_rp(obj), x3, y4);
        y4 += 2;
      }
      if (data->special <= 7)
      {
        while (x4 <= x5)
        { WritePixel(_rp(obj), x4, y3);
          x4 += 2;
        }
      }
      if (data->special <= 5)
      {
        Move(_rp(obj), x2-6, y3);
        Draw(_rp(obj), x2-6, y3-3);
        Draw(_rp(obj),   x2, y3-3);
        Draw(_rp(obj),   x2, y3+3);
        Draw(_rp(obj), x2-6, y3+3);
        Draw(_rp(obj), x2-6, y3);
        Move(_rp(obj), x2-4, y3);
        Draw(_rp(obj), x2-2, y3);
        if ((data->special == 2) || (data->special == 3))
        { Move(_rp(obj), x2-3, y3-1);
          Draw(_rp(obj), x2-3, y3+1);
        }
      }
    }
  }
  msg->flags = 0;
  return(0);
}

IPTR mNLI_New(struct IClass *cl,Object *obj,struct opSet *msg)
{
  register struct NLIData *data;
  if (!(obj = (Object *)DoSuperMethodA(cl,obj,(Msg) msg)))
    return(0);
  data = INST_DATA(cl,obj);
  data->special = 0;
  return((IPTR) obj);
}

IPTR mNLI_AskMinMax(struct IClass *cl,Object *obj,struct MUIP_AskMinMax *msg)
{
  DoSuperMethodA(cl,obj,(Msg) msg);
  msg->MinMaxInfo->MinWidth  += 8;
  msg->MinMaxInfo->DefWidth  += 18; /* the only width def value really used by NList object */
  msg->MinMaxInfo->MaxWidth  += MUI_MAXMAX;
  msg->MinMaxInfo->MinHeight += 7;  /* the only height def value really used by NList object */
  msg->MinMaxInfo->DefHeight += 12;
  msg->MinMaxInfo->MaxHeight += MUI_MAXMAX;
  return(0);
}

IPTR mNLI_Set(struct IClass *cl,Object *obj,Msg msg)
{
  register struct NLIData *data = INST_DATA(cl,obj);
  struct TagItem *tags,*tag;

  for(tags=((struct opSet *)msg)->ops_AttrList; (tag=(struct TagItem *)NextTagItem((APTR)&tags)); )
  {
    switch (tag->ti_Tag)
    {
      case MUIA_NLIMG_EntryCurrent:
        data->EntryCurrent = tag->ti_Data;
        break;
      case MUIA_NLIMG_EntryHeight:
        data->EntryHeight = tag->ti_Data;
        break;
      case MUIA_NLIMG_Spec:
        data->special = tag->ti_Data;
        break;
    }
  }
  return (0);
}

DISPATCHER(NLI_Dispatcher)
{
  switch (msg->MethodID)
  {
    case OM_NEW         : return (      mNLI_New(cl,obj,(APTR)msg));
    case OM_SET         : return (      mNLI_Set(cl,obj,(APTR)msg));
    case MUIM_AskMinMax : return (mNLI_AskMinMax(cl,obj,(APTR)msg));
    case MUIM_Draw      : return (     mNLI_Draw(cl,obj,(APTR)msg));
  }

  return(DoSuperMethodA(cl,obj,msg));
}

struct MUI_CustomClass *NLI_Create(void)
{
  NLI_Class = MUI_CreateCustomClass(NULL, (STRPTR)MUIC_Area, NULL, sizeof(struct NLIData), ENTRY(NLI_Dispatcher));

  return (NLI_Class);
}

void NLI_Delete(void)
{
  if (NLI_Class)
    MUI_DeleteCustomClass(NLI_Class);
  NLI_Class = NULL;
}

NListtree[edit | edit source]

NListtree.mcc/MUIA_NListtree_Active
NListtree.mcc/MUIA_NListtree_ActiveList
NListtree.mcc/MUIA_NListtree_AutoVisible
NListtree.mcc/MUIA_NListtree_CloseHook
NListtree.mcc/MUIA_NListtree_CompareHook
NListtree.mcc/MUIA_NListtree_ConstructHook
NListtree.mcc/MUIA_NListtree_CopyToClipHook
NListtree.mcc/MUIA_NListtree_DestructHook
NListtree.mcc/MUIA_NListtree_DisplayHook
NListtree.mcc/MUIA_NListtree_DoubleClick
NListtree.mcc/MUIA_NListtree_DragDropSort
NListtree.mcc/MUIA_NListtree_DropTarget
NListtree.mcc/MUIA_NListtree_DropTargetPos
NListtree.mcc/MUIA_NListtree_DropType
NListtree.mcc/MUIA_NListtree_DupNodeName
NListtree.mcc/MUIA_NListtree_EmptyNodes
NListtree.mcc/MUIA_NListtree_FindNameHook
NListtree.mcc/MUIA_NListtree_FindUserDataHook
NListtree.mcc/MUIA_NListtree_Format
NListtree.mcc/MUIA_NListtree_MultiSelect
NListtree.mcc/MUIA_NListtree_MultiTestHook
NListtree.mcc/MUIA_NListtree_OpenHook
NListtree.mcc/MUIA_NListtree_Quiet
NListtree.mcc/MUIA_NListtree_ShowTree
NListtree.mcc/MUIA_NListtree_Title
NListtree.mcc/MUIA_NListtree_TreeColumn
NListtree.mcc/MUIM_NListtree_Active
NListtree.mcc/MUIM_NListtree_Clear
NListtree.mcc/MUIM_NListtree_Close
NListtree.mcc/MUIM_NListtree_Compare
NListtree.mcc/MUIM_NListtree_Construct
NListtree.mcc/MUIM_NListtree_Copy
NListtree.mcc/MUIM_NListtree_CopyToClip
NListtree.mcc/MUIM_NListtree_Destruct
NListtree.mcc/MUIM_NListtree_Display
NListtree.mcc/MUIM_NListtree_DoubleClick
NListtree.mcc/MUIM_NListtree_DropDraw
NListtree.mcc/MUIM_NListtree_DropType
NListtree.mcc/MUIM_NListtree_Exchange
NListtree.mcc/MUIM_NListtree_FindName
NListtree.mcc/MUIM_NListtree_FindUserData
NListtree.mcc/MUIM_NListtree_GetEntry
NListtree.mcc/MUIM_NListtree_GetNr
NListtree.mcc/MUIM_NListtree_Insert
NListtree.mcc/MUIM_NListtree_InsertStruct
NListtree.mcc/MUIM_NListtree_Move
NListtree.mcc/MUIM_NListtree_MultiTest
NListtree.mcc/MUIM_NListtree_NextSelected
NListtree.mcc/MUIM_NListtree_Open
NListtree.mcc/MUIM_NListtree_PrevSelected
NListtree.mcc/MUIM_NListtree_Redraw
NListtree.mcc/MUIM_NListtree_Remove
NListtree.mcc/MUIM_NListtree_Rename
NListtree.mcc/MUIM_NListtree_Select
NListtree.mcc/MUIM_NListtree_Sort
NListtree.mcc/MUIM_NListtree_TestPos
NListtree.mcc/

    There are two possible entry-types in a NListtree class list:
    Leaves and nodes. Leaves are simple entries which have no special
    features except they are holding some data. Nodes are almost
    the same type, holding data too, but having a list attached
    where you can simply add other entries which can be again leaves
    or nodes.

    Every node is structured as follows:

        struct MUI_NListtree_TreeNode {

            struct    MinNode    tn_Node;
            STRPTR    tn_Name;
            UWORD    tn_Flags;
            APTR    tn_User;
        };

    It contains a name field tn_Name, flags tn_Flags and a pointer to
    user data tn_User.

    The tn_Flags field can hold the following flags:

        TNF_LIST        The node contains a list where other nodes
                        can be inserted.

        TNF_OPEN        The list node is open, sub nodes are displayed.

        TNF_FROZEN      The node doesn't react on doubleclick or
                        open/close by the user.

        TNF_NOSIGN      The indicator of list nodes isn't shown.

        TNF_SELECTED    The entry is currently selected.

    These flags, except TNF_SELECTED, can be used in
    MUIM_NListtree_Insert at creation time. They will be passed to
    the newly created entry. Also you can do a quick check about the
    state and kind of each entry. But DO NOT EVER modify any flag
    yourself or NListtree will crash. Be warned!

    *********************************************************************
        THE ABOVE STRUCT IS READ-ONLY!! NEVER CHANGE ANY ENTRY OF THIS
        STRUCTURE DIRECTLY NOR THINK ABOUT THE CONTENTS OF ANY PRIVATE
                        FIELD OR YOU WILL DIE IN HELL!
    *********************************************************************

    You can create very complex tree structures. NListtree only uses
    one list which holds all information needed and has no extra
    display list like other list tree classes ;-)

    The tree nodes can be inserted and removed, sorted, moved, exchanged,
    renamed  or multi  selected.  To sort you can also  drag&drop  them.
    Modifications can be made in relation to the whole tree, to only one
    level, to a sub-tree or to only one tree node.

    The user can control the listtree by the MUI keys, this means a node
    is opened with "Right" and closed with "Left". Check your MUI prefs
    for the specified keys.

    You can define which of the columns will react on double-clicking.
    The node toggles its status from open or closed and vice versa.

    Drag&Drop capabilities:

    If you set MUIA_NList_DragSortable to TRUE, the list tree will
    become active for Drag&Drop. This means you can drag and drop
    entries on the same list tree again. While dragging an indicator
    shows where to drop.

        Drag a    Drop on        Result

        leaf    leaf         Exchange leaves.
        node    leaf         Nothing happens.
        entry   closed node  Move entry, the compare hook is used.
        entry   open node    Move entry to defined position.

    You can not drop an entry on itself, nor can you drop an opened node on
    any of its members.

    To exchange data with other objects, you have to create your own
    subclass of NListtree class and react on the drag methods.

MUIA_NListtree_Active -- [.SG], struct MUI_NListtree_TreeNode *

   SPECIAL VALUES

        MUIV_NListtree_Active_Off
        MUIV_NListtree_Active_Parent
        MUIV_NListtree_Active_First
        MUIV_NListtree_Active_FirstVisible
        MUIV_NListtree_Active_LastVisible

   FUNCTION

    Setting this attribute will move the cursor to the defined tree node
    if it is visible. If the node is in an opened tree the listview is
    scrolling into the visible area. Setting MUIV_NListtree_Active_Off will
    vanish the cursor.

    MUIV_NListtree_Active_First/FirstVisible/LastVisible are special values
    for activating the lists first or the top/bottom visible entry.

    See MUIA_NListtree_AutoVisible for special activation features.

    If this attribute is read it returns the active tree node. The result
    is MUIV_NListtree_Active_Off if there is no active entry.

   NOTIFICATIONS

    You can create a notification on MUIA_NListtree_Active. The
    TriggerValue is the active tree node.

MUIA_NListtree_ActiveList -- [..G], struct MUI_NListtree_TreeNode *

   SPECIAL VALUES

        MUIV_NListtree_ActiveList_Off

   FUNCTION

    If this attribute is read it returns the active list node. The
    active list node is always the parent of the active entry.
    The result is MUIV_NListtree_ActiveList_Off if there is no
    active list (when there is no active entry).

   NOTIFICATIONS

    You can create notifications on MUIA_NListtree_ActiveList. The
    TriggerValue is the active list node.

MUIA_NListtree_AutoVisible -- [ISG], struct MUI_NListtree_TreeNode *

   SPECIAL VALUES

        MUIV_NListtree_AutoVisible_Off
        MUIV_NListtree_AutoVisible_Normal
        MUIV_NListtree_AutoVisible_FirstOpen
        MUIV_NListtree_AutoVisible_Expand

   FUNCTION

    Set this to make your list automatically jump to the active
    entry.

        MUIV_NListtree_AutoVisible_Off:
            The display does NOT scroll the active entry into the
            visible area.

        MUIV_NListtree_AutoVisible_Normal:
            This will scroll the active entry into the visible area
            if it is visible (entry is a member of an open node).
            This is the default.

        MUIV_NListtree_AutoVisible_FirstOpen:
            Nodes are not opened, but the first open parent node of
            the active entry is scrolled into the visible area if the
            active entry is not visible.

        MUIV_NListtree_AutoVisible_Expand:
            All parent nodes are opened until the first open node is
            reached and the active entry will be scrolled into the
            visible area.

MUIA_NListtree_CloseHook -- [IS.], struct Hook *

   SPECIAL VALUES

   FUNCTION

    The close hook is called after a list node is closed, then the list
    can be changed.
    The close hook will be called with the hook in A0, the object in A2
    and a MUIP_NListtree_CloseMessage struct in A1 (see nlisttree_mcc.h).

    To remove the hook set this to NULL.

MUIA_NListtree_CompareHook -- [IS.], struct Hook *

   SPECIAL VALUES

        MUIV_NListtree_CompareHook_Head
        MUIV_NListtree_CompareHook_Tail
        MUIV_NListtree_CompareHook_LeavesTop
        MUIV_NListtree_CompareHook_LeavesMixed
        MUIV_NListtree_CompareHook_LeavesBottom

   FUNCTION

    Set this attribute to your own hook in order to sort the entries in
    the list tree by your own way.

    When you sort your list or parts of your list via MUIM_NListtree_Sort,
    using the insert method with MUIV_NListtree_Insert_Sort or dropping an
    entry on a closed node, this compare hook is called.

    There are some builtin compare hooks available, called:

        MUIV_NListtree_CompareHook_Head
            Any entry is inserted at the head of the list.

        MUIV_NListtree_CompareHook_Tail
            Any entry is inserted at the tail of the list.

        MUIV_NListtree_CompareHook_LeavesTop
            Leaves are inserted at the top of the list, nodes at bottom. They are
            alphabetically sorted.

        MUIV_NListtree_CompareHook_LeavesMixed
            The entries are only alphabetically sorted.

        MUIV_NListtree_CompareHook_LeavesBottom
            Leaves are inserted at bottom of the list, nodes at top. They are
            alphabetically sorted. This is default.

    The hook will be called with the hook in A0, the object in A2 and
    a MUIP_NListtree_CompareMessage struct in A1 (see nlisttree_mcc.h). You
    should return something like:

        <0    (TreeNode1 <  TreeNode2)
         0    (TreeNode1 == TreeNode2)
        >0    (TreeNode1 >  TreeNode2)

MUIA_NListtree_ConstructHook -- [IS.], struct Hook *

   SPECIAL VALUES

        MUIV_NListtree_ConstructHook_String

        MUIV_NListtree_ConstructHook_Flag_AutoCreate
            If using the KeepStructure feature in MUIM_NListtree_Move or
            MUIM_NListtree_Copy, this flag will be set when calling your
            construct hook. Then you can react if your hook is not simply
            allocating memory.

   FUNCTION

    The construct hook is called whenever you add an entry to your
    listtree. The pointer isn't inserted directly, the construct hook is
    called and its result code is added.

    When an entry shall be removed the corresponding destruct hook is
    called.

    The construct hook will be called with the hook in A0, the object in
    A2 and a MUIP_NListtree_ConstructMessage struct in A1 (see
    nlisttree_mcc.h).
    The message holds a standard kick 3.x memory pool pointer. If you want,
    you can use the exec or amiga.lib functions for allocating memory
    within this pool, but this is only an option.

    If the construct hook returns NULL, nothing will be added to the list.

    There is a builtin construct hook available called
    MUIV_NListtree_ConstructHook_String. This expects that the field
    'tn_User' in the treenode is a string pointer (STRPTR), whose
    string is copied.
    MUIV_NListtree_DestructHook_String must be used in this case!

    To remove the hook set this to NULL.

    NEVER pass a NULL pointer when you have specified the internal string
    construct/destruct hooks or NListtree will die!

MUIA_NListtree_CopyToClipHook -- [IS.],

   SPECIAL VALUES

        MUIV_NListtree_CopyToClipHook_Default

   FUNCTION

        This works similarly to MUIA_NListtree_DisplayHook, but is
        called when the NListtree object want to make a clipboard copy.

        You can return only one string pointer. If you return NULL,
        nothing will be copied. If you return -1, the entry will be
        handled as a normal string and the name field is used.

        The built-in hook skips all ESC sequences and adds a tab char
        between columns.

MUIA_NListtree_DestructHook -- [IS.], struct Hook *

   SPECIAL VALUES

        MUIV_NListtree_DestructHook_String

   FUNCTION

    Set up a destruct hook for your listtree. The destruct hook is called
    whenevere you remove an entry from the listtree. Here you can free memory
    which was allocated by the construct hook before.

    The destruct hook will be called with the hook in A0, the object
    in A2 and a MUIP_NListtree_DestructMessage struct in A1 (see
    nlisttree_mcc.h).
    The message holds a standard kick 3.x memory pool pointer. This pool must
    be used when you have used it inside the construct hook to
    allocate pooled memory.

    There is a built-in destruct hook available called
    MUIV_NListtree_DestructHook_String. This expects that the 'User' data
    in the treenode is a string and you have used
    MUIV_NListtree_ConstructHook_String in the construct hook!

    To remove the hook set this to NULL.

MUIA_NListtree_DisplayHook -- [IS.],

   SPECIAL VALUES

   FUNCTION

    You have to supply a display hook to specify what should be shown in
    the listview, otherwise only the name of the nodes is displayed.

    The display hook will be called with the hook in A0, the object in
    A2 and a MUIP_NListtree_DisplayMessage struct in A1 (see nlisttree_mcc.h).

    The structure holds a pointer to a string array containing as many
    entries as your listtree may have columns. You have to fill this
    array with the strings you want to display. Check out that the array
    pointer of the tree column is set to NULL, if the normal name of the
    node should appear.
    You can set a preparse string in Preparse for the corresponding col
    element. Using it you'll be able to avoid copying the string in a
    buffer to add something in the beginning of the col string.

    The display hook also gets the position of the current entry as
    additional parameter. It is stored in the longword preceding the col
    array (don't forget it's a LONG).

    You can set the array pointer of the tree column to a string, which is
    displayed instead of the node name. You can use this to mark nodes.

    See MUIA_NList_Format for details about column handling.

    To remove the hook and use the internal default display hook set this
    to NULL.

MUIA_NListtree_DoubleClick -- [ISG], ULONG

   SPECIAL VALUES

        MUIV_NListtree_DoubleClick_Off
        MUIV_NListtree_DoubleClick_All
        MUIV_NListtree_DoubleClick_Tree
        MUIV_NListtree_DoubleClick_NoTrigger

   FUNCTION

    A doubleclick opens a node if it was closed, it is closed if the node
    was open. You have to set the column which should do this.

    Normally only the column number is set here, but there are special
    values:

        MUIV_NListtree_DoubleClick_Off:
            A doubleclick is not handled.

        MUIV_NListtree_DoubleClick_All:
            All columns react on doubleclick.

        MUIV_NListtree_DoubleClick_Tree
            Only a doubleclick on the defined tree column is recognized.

        MUIV_NListtree_DoubleClick_NoTrigger:
            A doubleclick is not handled and not triggered!

   NOTIFICATION

    The TriggerValue of the notification is the tree node you have double-
    clicked, you can GetAttr() MUIA_NListtree_DoubleClick for the column
    number. The struct 'MUI_NListtree_TreeNode *'is used for trigger.

    The notification is done on leaves and on node columns, which are not
    set in MUIA_NListtree_DoubleClick.

MUIA_NListtree_DragDropSort -- [IS.], BOOL

   SPECIAL VALUES

   FUNCTION

    Setting this attribute to FALSE will disable the ability to sort the
    list tree by drag & drop. Defaults to TRUE.

MUIA_NListtree_DropTarget -- [..G], ULONG

   SPECIAL VALUES

   FUNCTION

    After a successful drop operation, this value holds the entry where
    the entry was dropped. The relative position (above etc.) can be
    obtained by reading the attribute MUIA_NListtree_DropType.

MUIA_NListtree_DropTargetPos -- [..G], ULONG

   SPECIAL VALUES

   FUNCTION

    After a successful drop operation, this value holds the integer
    position of the entry where the dragged entry was dropped. The
    entry itself can be obtained by reading MUIA_NListtree_DropTarget,
    the relative position (above etc.) can be obtained by reading the
    attribute MUIA_NListtree_DropType.

MUIA_NListtree_DropType -- [..G], ULONG

   SPECIAL VALUES

        MUIV_NListtree_DropType_None
        MUIV_NListtree_DropType_Above
        MUIV_NListtree_DropType_Below
        MUIV_NListtree_DropType_Onto

   FUNCTION

    After a successful drop operation, this value holds the position
    relative to the value of MUIA_NListtree_DropTarget/DropTargetPos.

   NOTIFICATION

MUIA_NListtree_DupNodeName -- [IS.], BOOL

   SPECIAL VALUES

   FUNCTION

    If this attribute is set to FALSE the names of the node will not be
    duplicated, only the string pointers are used. Be careful the strings
    have to be valid every time.

   NOTIFICATION

MUIA_NListtree_EmptyNodes -- [IS.], BOOL

   SPECIAL VALUES

   FUNCTION

    Setting this attribute to TRUE will display all empty nodes as leaves,
    this means no list indicator is shown. Nevertheless the entry is
    handled like a node.

   NOTIFICATION

MUIA_NListtree_FindNameHook -- [IS.],

   SPECIAL VALUES

        MUIV_NListtree_FindNameHook_CaseSensitive
            Search for the complete string, case sensitive.

        MUIV_NListtree_FindNameHook_CaseInsensitive
            Search for the complete string, case insensitive.

        MUIV_NListtree_FindNameHook_Part
            Search for the first part of the string, case sensitive.

        MUIV_NListtree_FindNameHook_PartCaseInsensitive
            Search for the first part of the string, case insensitive.

        MUIV_NListtree_FindNameHook_PointerCompare
            Do only a pointer comparison. This is a pointer subtraction
            to fit into the rules. It returns the difference (~0) of the 
            two fields if there is no match.

   FUNCTION

    You can install a FindName hook to specify your own search
    criteria.

    The find name hook will be called with the hook in A0, the object in
    A2 and a MUIP_NListtree_FindNameMessage struct in A1
    (see nlisttree_mcc.h). It should return ~ 0 for entries which are
    not matching the pattern and a value of 0 if a match.

    The find name message structure holds a pointer to a string
    containing the name to search for and pointers to the name- and user-
    field of the node which is currently processed.

    The MUIV_NListtree_FindNameHook_CaseSensitive will be used as default.

   NOTIFICATION

MUIA_NListtree_FindUserDataHook -- [IS.],

   SPECIAL VALUES

        MUIV_NListtree_FindUserDataHook_CaseSensitive
            Search for the complete string, case sensitive.

        MUIV_NListtree_FindUserDataHook_CaseInsensitive
            Search for the complete string, case insensitive.

        MUIV_NListtree_FindUserDataHook_Part
            Search for the first part of the string, case sensitive.

        MUIV_NListtree_FindUserDataHook_PartCaseInsensitive
            Search for the first part of the string, case insensitive.

        MUIV_NListtree_FindUserDataHook_PointerCompare
            Do only a pointer comparison. This is in fact
            a pointer subtraction to fit into the rules. It returns
            the difference (~0) of the two user fields if there is no match.

   FUNCTION

    You can install a FindUserData hook to specify your own search
    criteria.

    The find user data hook will be called with the hook in A0, the object
    in A2 and a MUIP_NListtree_FindUserDataMessage struct in A1
    (see nlisttree_mcc.h). It should return ~ 0 for entries which are
    not matching the pattern and a value of 0 if a match.

    The find user data message structure holds a pointer to a string
    containing the data to search for and pointers to the user- and name-
    field of the node which is currently processed.

    MUIV_NListtree_FindUserDataHook_CaseSensitive will be used as default.

   NOTIFICATION

MUIA_NListtree_Format -- [IS.], STRPTR

   SPECIAL VALUES

   FUNCTION

    Same as MUIA_NList_Format, but one column is reserved for the tree
    indicators and the names of the nodes.

    For further detailed information see MUIA_NList_Format!

   NOTIFICATION

MUIA_NListtree_MultiSelect -- [I..],

   SPECIAL VALUES

        MUIV_NListtree_MultiSelect_None
        MUIV_NListtree_MultiSelect_Default
        MUIV_NListtree_MultiSelect_Shifted
        MUIV_NListtree_MultiSelect_Always

   FUNCTION

    Four possibilities exist for a listviews multi select
    capabilities:

        MUIV_NListtree_MultiSelect_None:
            The list tree cannot multiselect at all.

        MUIV_NListtree_MultiSelect_Default:
            The multi select type (with or without shift)
            depends on the users preferences setting.

        MUIV_NListtree_MultiSelect_Shifted:
            Overrides the users prefs, multi selecting only
            together with shift key.

        MUIV_NListtree_MultiSelect_Always:
            Overrides the users prefs, multi-selecting
            without shift key.

   NOTIFICATION

MUIA_NListtree_MultiTestHook -- [IS.], struct Hook *

   SPECIAL VALUES

   FUNCTION

    If you plan to have a multi-selecting list tree but not
    all of your entries are actually multi-selectable, you
    can supply a MUIA_NListtree_MultiTestHook.

    The multi-test hook will be called with the hook in A0, the object
    in A2 and a MUIP_NListtree_MultiTestMessage struct in A1 (see
    nlisttree_mcc.h) and should return TRUE if the entry is multi-
    selectable, FALSE otherwise.

    To remove the hook set this to NULL.

   NOTIFICATION

MUIA_NListtree_OpenHook -- [IS.], struct Hook *

   SPECIAL VALUES

   FUNCTION

    The open hook is called whenever a list node will be opened, so you
    can change the list before the node is open.

    The open hook will be called with the hook in A0, the object in A2
    and a MUIP_NListtree_OpenMessage struct in A1 (see nlisttree_mcc.h).

    To remove the hook set this to NULL.

   NOTIFICATION

MUIA_NListtree_Quiet -- [.S.], QUIET

   SPECIAL VALUES

   FUNCTION

    If you add/remove lots of entries to/from a listtree, this will cause
    lots of screen action and slow down the operation. Setting
    MUIA_NListtree_Quiet to TRUE will temporarily prevent the listtree from
    being refreshed, this refresh will take place only once when you set
    it back to FALSE again.

    MUIA_NListtree_Quiet holds a nesting count to avoid trouble with
    multiple setting/unsetting this attribute. You are encouraged to
    always use TRUE/FALSE pairs here or you will have difficulty.

    DO NOT USE MUIA_NList_Quiet here!

   NOTIFICATION

MUIA_NListtree_ShowTree -- [ISG], ULONG

   SPECIAL VALUES

   FUNCTION

    Specify FALSE here if you want the whole tree to be disappear.
    Defaults to TRUE;

   NOTIFICATION

MUIA_NListtree_Title -- [IS.], BOOL

   SPECIAL VALUES

   FUNCTION

    Specify a title for the current listtree.

    For detailed information see MUIA_NList_Title!

   NOTIFICATION

    BUGS

    The title should not be a string as for single column listviews. This
    attribute can only be set to TRUE or FALSE.

MUIA_NListtree_TreeColumn -- [ISG], ULONG

   SPECIAL VALUES

   FUNCTION

    Specify the column of the list tree, the node indicator and the name
    of the node are displayed in.

   NOTIFICATION
MUIM_NListtree_Active -- Called for every active change. (V1)

   SYNOPSIS

    DoMethodA(obj, MUIM_NListtree_Active,
        struct MUIP_NListtree_Active *activemessage);

   FUNCTION

    This method must not be called directly. It will be called by
    NListtree if the active entry changes. This is an addition to
    MUIA_NListtree_Active

   INPUTS

   RESULT

   EXAMPLE

   NOTES

   BUGS

MUIM_NListtree_Clear -- Clear the complete listview. (V1)

   SYNOPSIS

    DoMethod(obj, MUIM_NListtree_Clear, NULL, 0)

   FUNCTION

    Clear the complete listview, calling destruct hook for each entry.

   INPUTS

   RESULT

   EXAMPLE

        // Clear the listview!
        DoMethod( nlisttree, MUIM_NListtree_Clear, NULL, 0 );

   NOTES

    For now, when using this method, you must supply NULL for the list
    node and 0 for flags for future compatibility.
    This will change!

   BUGS

MUIM_NListtree_Close -- Close the specified list node. (V1)

   SYNOPSIS

    DoMethod(obj, MUIM_NListtree_Close,
        struct MUI_NListtree_TreeNode *listnode,
        struct MUI_NListtree_TreeNode *treenode,
        ULONG flags);

   FUNCTION

    Close a node or nodes of a listtree. It is checked if the tree node
    is a node, not a leaf!

    When the active entry was a child of the closed node, the closed node
    will become active.

   INPUTS

    listnode -    Specify the node which list is used to find the entry. The
                search is started at the head of this list.

        MUIV_NListtree_Close_ListNode_Root
            The root list is used.

        MUIV_NListtree_Close_ListNode_Parent
            The list which is the parent of the active list is used.

        MUIV_NListtree_Close_ListNode_Active
            The list of the active node is used.

    treenode -    The node which should be closed. If there are children
                of the node, they are also closed.

        MUIV_NListtree_Close_TreeNode_Head
            The head of the list defined in 'listnode' is closed.

        MUIV_NListtree_Close_TreeNode_Tail:
            Closes the tail of the list defined in 'listnode'.

        MUIV_NListtree_Close_TreeNode_Active:
            Closes the active node.

        MUIV_NListtree_Close_TreeNode_All:
            Closes all nodes of the list which is specified in
            'listnode'.

   RESULT

   EXAMPLE

        // Close the active list.
        DoMethod(obj, MUIM_NListtree_Close,
            MUIV_NListtree_Close_ListNode_Active,
            MUIV_NListtree_Close_TreeNode_Active, 0);

   NOTES

   BUGS

MUIM_NListtree_Compare -- Compare two nodes

   SYNOPSIS

    DoMethod(obj, MUIM_NListtree_Compare,
        struct MUI_NListtree_TreeNode *TreeNode1,
        struct MUI_NListtree_TreeNode *TreeNode2,
        ULONG SortType);

   FUNCTION

    Compares the two given treenodes. You should return something like:

        <0    (TreeNode1 <  TreeNode2)
         0    (TreeNode1 == TreeNode2)
        >0    (TreeNode1 >  TreeNode2)

   NOTIFICATION

MUIM_NListtree_Construct -- Create a new treenode

   SYNOPSIS

    DoMethod(obj, MUIM_NListtree_Construct,
        STRPTR Name,
        APTR UserData,
        APTR MemPool,
        ULONG Flags);

   FUNCTION

    This method is called whenever a new treenode is to be added to the
    listtree. See MUIA_NListtree_ConstructHook for more details.

    If the method returns NULL, nothing will be added to the list.

   NOTIFICATION

MUIM_NListtree_Copy -- Copy an entry (create it) to the spec. pos. (V1)

   SYNOPSIS

    DoMethod(obj, MUIM_NListtree_Copy,
        struct MUI_NListtree_TreeNode *srclistnode,
        struct MUI_NListtree_TreeNode *srctreenode,
        struct MUI_NListtree_TreeNode *destlistnode,
        struct MUI_NListtree_TreeNode *desttreenode,
        ULONG flags);

   FUNCTION

    Copy an entry to the position after a defined node. The complete
    child structure will be copied.

   INPUTS

    srclistnode -    Specify the node which list is used to find the
                    entry. The search is started at the head of this
                    list.

        MUIV_NListtree_Copy_SourceListNode_Root
            The root list is used as the starting point.

        MUIV_NListtree_Copy_SourceListNode_Active
            The active list (the list of the active node) is used as
            the starting point.

    srctreenode -    Specifies the node which should be copied.

        MUIV_NListtree_Copy_SourceTreeNode_Head
            The head of the list defined in 'srclistnode' is copied.

        MUIV_NListtree_Copy_SourceTreeNode_Tail
            The tail of the list defined in 'srclistnode' is copied.

        MUIV_NListtree_Copy_SourceTreeNode_Active
            The active node is copied.

    destlistnode -    Specify the node which list is used to find the
                    entry. The search is started at the head of this
                    list.

        MUIV_NListtree_Copy_DestListNode_Root
            The root list.

        MUIV_NListtree_Copy_DestListNode_Active
            The list of the active node.

    desttreenode -    This node is the predecessor of the entry which is
                    inserted.

        MUIV_NListtree_Copy_DestTreeNode_Head
            The node is copied to the head of the list defined in
            'destlistnode'.

        MUIV_NListtree_Copy_DestTreeNode_Tail
            The node is copied to the tail of the list defined in
            'destlistnode'.

        MUIV_NListtree_Copy_DestTreeNode_Active:
            The node is copied to one entry after the active node.

        MUIV_NListtree_Copy_DestTreeNode_Sorted:
            The node is copied to the list using the sort hook.

    flags -        Some flags to adjust moving.

        MUIV_NListtree_Copy_Flag_KeepStructure
            The full tree structure from the selected entry to
            the root list is copied (created) at the destination.

   RESULT

   EXAMPLE

        // Copy the active entry to the head of
        // another list node.
        DoMethod(obj,
            MUIV_NListtree_Copy_SourceListNode_Active,
            MUIV_NListtree_Copy_SourceTreeNode_Active,
            anylistnode,
            MUIV_NListtree_Copy_DestTreeNode_Head,
            0);

   NOTES

   BUGS

MUIM_NListtree_CopyToClip -- Called for every clipboard copy action. (V1)

   SYNOPSIS

    DoMethodA(obj, MUIM_NListtree_CopyToClip,
        struct MUIP_NListtree_CopyToClip *ctcmessage);

   FUNCTION

    Do a copy to clipboard from an entry/entry content.

   INPUTS

        TreeNode    - Tree node to copy contents from. Use
                     MUIV_NListtree_CopyToClip_Active to copy the
                      active entry.

        Pos            - Entry position.

        Unit        - Clipboard unit to copy entry contents to.

   RESULT

   EXAMPLE

   NOTES

   BUGS

MUIN_NListtree_Destruct -- Free a new treenode

   SYNOPSIS

    DoMethod(obj, MUIM_NListtree_Destruct,
        STRPTR Name,
        APTR UserData,
        APTR MemPool,
        ULONG Flags);

   FUNCTION

    This method is called whenever a new treenode is to be removed from the
    listtree. See MUIA_NListtree_DestructHook for more details.

   NOTIFICATION

MUIN_NListtree_Display -- Display a treenode

   SYNOPSIS

    DoMethod(obj, MUIM_NListtree_Dispose,
        struct MUI_NListtree_TreeNode *TreeNode,
        LONG EntryPos,
        STRPTR *Array,
        STRPTR *Preparse);

   FUNCTION

    This method is called whenever a new treenode is to be displayed in the
    listtree. See MUIA_NListtree_DisplayHook for more details.

   NOTIFICATION

MUIM_NListtree_DoubleClick -- Called for every double click. (V1)

   SYNOPSIS

    DoMethodA(obj, MUIM_NListtree_DoubleClick,
        struct MUIP_NListtree_DoubleClick *doubleclickmsg);

   FUNCTION

    This method must not be called directly. It will be called by
    NListtree if an double click event occurs. This is an addition to
    MUIA_NListtree_DoubleClick

   INPUTS

   RESULT

   EXAMPLE

   NOTES

   BUGS

MUIM_NListtree_DropDraw --

   SYNOPSIS

    DoMethod(obj, MUIM_NListtree_DropDraw, LONG pos, LONG type,
        LONG minx, LONG maxx, LONG miny, LONG maxy);

   FUNCTION

        This method must not be called directly!

       It will be called by NListtree, and will draw the drop mark
        previously fixed (pos and type) by MUIM_NListtree_DropType
        within the minx, maxx, miny, maxy in the _rp(obj) rasport.

        For further information see method MUIM_NList_DropDraw.

   INPUTS

   RESULT

   EXAMPLE

   NOTES

   BUGS

MUIM_NListtree_DropType --

   SYNOPSIS

    DoMethod(obj, MUIM_NListtree_DropType, LONG *pos, LONG *type,
        LONG minx, LONG maxx, LONG miny, LONG maxy,
        LONG mousex, LONG mousey);

   FUNCTION

        This method MUST NOT be called directly !

        It will be called by NListreet while the DragReport, with
        default *pos and *type values depending on the drag pointer
        position that you can modify as you want.

        For further information see method MUIM_NList_DropDraw.

   INPUTS

   RESULT

   EXAMPLE

   NOTES

   BUGS

MUIM_NListtree_Exchange -- Exchanges two tree nodes. (V1)

   SYNOPSIS

    DoMethod(obj, MUIM_NListtree_Exchange,
        struct MUI_NListtree_TreeNode *listnode1,
        struct MUI_NListtree_TreeNode *treenode1,
        struct MUI_NListtree_TreeNode *listnode2,
        struct MUI_NListtree_TreeNode *treenode2,
        ULONG flags);

   FUNCTION

    Exchange two tree nodes.

   INPUTS

    listnode1 -    Specify the list node of the entry which
                should be exchanged.

        MUIV_NListtree_Exchange_ListNode1_Root
            The root list is used.

        MUIV_NListtree_Exchange_ListNode1_Active
            The active list (the list of the active node) is used.

    treenode1 -    Specify the node which should be exchanged.

        MUIV_NListtree_Exchange_TreeNode1_Head
            The head of the list defined in 'listnode1' is
            exchanged.

        MUIV_NListtree_Exchange_TreeNode1_Tail
            The tail of the list defined in 'listnode1' is
            exchanged.

        MUIV_NListtree_Exchange_TreeNode1_Active
            The active node is exchanged.

    listnode2 -    Specify the second list node which is used for exchange.

        MUIV_NListtree_Exchange_ListNode2_Root
            The root list.

        MUIV_NListtree_Exchange_ListNode2_Active
            The list of the active node.

    treenode2 -    This node is the second entry which is exchanged.

        MUIV_NListtree_Exchange_TreeNode2_Head
            The node 'treenode1' is exchanged with the head of the
            list defined in 'listnode2'.

        MUIV_NListtree_Exchange_TreeNode2_Tail
            The node 'treenode1' is exchanged with the tail of the
            list defined in 'ln2'.

        MUIV_NListtree_Exchange_TreeNode2_Active:
            The node 'treenode1' is exchanged with the active node.

        MUIV_NListtree_Exchange_TreeNode2_Up:
            The node 'treenode1' is exchanged with the entry
            previous to the one specified in 'treenode1'.

        MUIV_NListtree_Exchange_TreeNode2_Down:
            The node 'treenode1' is exchanged with the entry next
            (the successor) to the one specified in 'treenode1'.

   RESULT

   EXAMPLE

        // Exchange the active entry with the successor.
        DoMethod(obj,
            MUIV_NListtree_Exchange_ListNode1_Active,
            MUIV_NListtree_Exchange_TreeNode1_Active,
            MUIV_NListtree_Exchange_ListNode2_Active,
            MUIV_NListtree_Exchange_TreeNode2_Down,
            0);

   NOTES

   BUGS

MUIM_NListtree_FindName -- Find node using name match. (V1)

   SYNOPSIS

    struct MUI_NListtree_TreeNode *treenode =
        DoMethod(obj, MUIM_NListtree_FindName,
            struct MUI_NListtree_TreeNode *listnode,
            STRPTR name, ULONG flags);

   FUNCTION

    Find a node which name matches the specified one using the list node as
    start point..

   INPUTS
    listnode -    Specify the node which list is used to find the name.

        MUIV_NListtree_FindName_ListNode_Root
            Use the root list as the base list.

        MUIV_NListtree_FindName_ListNode_Active
            Use the list of the active node as the base.

    name -        Specify the name of the node to find. But you can search
                for anything in tn_Name or tn_User field here by simply
                supplying the searched data and handling it in your
                own FindNameHook.

    flags:

        MUIV_NListtree_FindName_Flag_SameLevel
            Only nodes on the same level are affected.

        MUIV_NListtree_FindName_Flag_Visible
            The node is only returned if it is visible (only visible
            entries are checked).

        MUIV_NListtree_FindName_Flag_Activate
            If found, the entry will be activated.

        MUIV_NListtree_FindName_Flag_Selected
            Find only selected nodes.

        MUIV_NListtree_FindName_Flag_StartNode
            The specified entry in listnode is the start point for
            search and must not be a list node. It can also be a
            normal entry.

   RESULT

    Returns the found node if available, NULL otherwise.

   EXAMPLE

        // Find 2nd node by name.
        struct MUI_NListtree_TreeNode *treenode =
            DoMethod(obj, MUIM_NListtree_FindName,
                listnode, "2nd node",
                MUIV_NListtree_FindName_SameLevel|
                MUIV_NListtree_FindName_Visible);

        if ( treenode == NULL )
        {
            PrintToUser( "No matching entry found." );
        }

   NOTES

MUIM_NListtree_FindUserData -- Find node upon user data. (V1)

   SYNOPSIS

    struct MUI_NListtree_TreeNode *treenode =
        DoMethod(obj, MUIM_NListtree_FindUserData,
            struct MUI_NListtree_TreeNode *listnode,
            APTR userdata, ULONG flags);

   FUNCTION

    Find a node which user data matches the specified one using the list
    node as start point..
    This method is designed as a second possibility for searching.
    Because you are able to search for anything, you may set special
    hooks for searching two different fields in two different hooks with
    these two methods.

   INPUTS
    listnode -    Specify the node which list is used to find the user data.

        MUIV_NListtree_FindUserData_ListNode_Root
            Use the root list as the base list.

        MUIV_NListtree_FindUserData_ListNode_Active
            Use the list of the active node as the base.

    userdata -    Specify the user data of the node to find. You can search
                for anything in tn_Name or tn_User field here by simply
                supplying the searched data and handling it in your
                own FindUserDataHook.

    flags:

        MUIV_NListtree_FindUserData_Flag_SameLevel
            Only nodes on the same level are affected.

        MUIV_NListtree_FindUserData_Flag_Visible
            The node is only returned if it is visible (only visible
            entries are checked).

        MUIV_NListtree_FindUserData_Flag_Activate
            If found, the entry will be activated.

        MUIV_NListtree_FindUserData_Flag_Selected
            Find only selected nodes.

        MUIV_NListtree_FindUserData_Flag_StartNode
            The specified entry in listnode is the start point for
            search and must not be a list node. It can also be a
            normal entry.

   RESULT

    Returns the found node if available, NULL otherwise.

   EXAMPLE

        // Find node by user data.
        struct MUI_NListtree_TreeNode *treenode =
            DoMethod(obj, MUIM_NListtree_FindUserData,
                listnode, "my data",
                MUIV_NListtree_FindUserData_SameLevel|
                MUIV_NListtree_FindUserData_Visible);

        if ( treenode == NULL )
        {
            PrintToUser( "No matching entry found." );
        }

   NOTES

   BUGS

MUIM_NListtree_GetEntry -- Get another node in relation to this. (V1)

   SYNOPSIS

    struct MUI_NListtree_TreeNode *rettreenode =
        DoMethod(obj, MUIM_NListtree_GetEntry,
            struct MUI_NListtree_TreeNode *treenode,
            LONG pos, ULONG flags);

   FUNCTION

    Get another node in relation to the specified list or node.

   INPUTS

    treenode -    Define the node which is used to find another one.
                This can also be a list node, if the position is
                related to a list.

        MUIV_NListtree_GetEntry_ListNode_Root
            The root list is used.

        MUIV_NListtree_GetEntry_ListNode_Active:
            The list with the active entry is used.

    pos -    The relative position of the node 'treenode'.

        MUIV_NListtree_GetEntry_Position_Head
            The head of the list is returned.

        MUIV_NListtree_GetEntry_Position_Tail
            The tail of the list is returned.

        MUIV_NListtree_GetEntry_Position_Active
            The active node is returned. If there is no active entry,
            NULL is returned.

        MUIV_NListtree_GetEntry_Position_Next
            The node next to the specified node is returned. Returns NULL
            if there is no next entry.

        MUIV_NListtree_GetEntry_Position_Previous
            The node right before the specified node is returned.
            Returns NULL if there is no previous entry (if 'treenode'
            is the head of the list.

        MUIV_NListtree_GetEntry_Position_Parent
            The list node of the specified 'treenode' is returned.

    flags:

        MUIV_NListtree_GetEntry_Flag_SameLevel:
            Only nodes in the same level are affected.

        MUIV_NListtree_GetEntry_Flag_Visible:
            The position is counted on visible entries only.

   RESULT

    Returns the requested node if available, NULL otherwise.

   EXAMPLE

        // Get the next entry.
        struct MUI_NListtree_TreeNode *treenode =
            DoMethod(obj, MUIM_NListtree_GetEntry, treenode,
            MUIV_NListtree_GetEntry_Position_Next, 0);

        if ( treenode != NULL )
        {
            PrintToUser( "Next entry found!" );
        }

   NOTES

   BUGS

MUIM_NListtree_GetNr -- Get the position number of a tree node. (V1)

   SYNOPSIS

    ULONG number = DoMethod(obj, MUIM_NListtree_GetNr,
        struct MUI_NListtree_TreeNode *treenode, ULONG flags);

   FUNCTION

    Get the position number of the specified tree node.

   INPUTS

    treenode -    Specify the node to count the position of.

        MUIV_NListtree_GetNr_TreeNode_Active:
            The position is counted related to the active node.

    flags:

        MUIV_NListtree_GetNr_Flag_CountAll
            Returns the number of all entries.

        MUIV_NListtree_GetNr_Flag_CountLevel
            Returns the number of entries of the list the
            specified node is in.

        MUIV_NListtree_GetNr_Flag_CountList
            Returns the number of the entries of the active list node
            (the specified node is in).

        MUIV_NListtree_GetNr_Flag_ListEmpty
            Returns TRUE if the specified list node is empty.

        MUIV_NListtree_GetNr_Flag_Visible
            Returns the position number of an visible entry. -1 if the
            entry is invisible. The position is counted on visible entries
            only.

   RESULT

   EXAMPLE

        // Check if the active (list) node is empty.
        ULONG empty = DoMethod(obj, MUIM_NListtree_GetNr,
            MUIV_NListtree_GetNr_TreeNode_Active,
            MUIV_NListtree_GetNr_Flag_ListEmpty);

        if ( empty == TRUE )
        {
            AddThousandEntries();
        }

   NOTES

   BUGS

MUIM_NListtree_Insert -- Insert an entry at the specified position. (V1)

   SYNOPSIS

    struct MUI_NListtree_TreeNode *treenode =
        DoMethod(obj, MUIM_NListtree_Insert,
            STRPTR name, APTR userdata,
            struct MUI_NListtree_TreeNode *listnode,
            struct MUI_NListtree_TreeNode *prevtreenode,
            ULONG flags);

   FUNCTION

    Insert an entry at the position, which is defined in 'listnode'
    and 'prevtreenode'. The name contains the name of the entry as string
    which is buffered. The user entry can be used as you like.

   INPUTS

    name/userdata - What the names say ;-)

    listnode -        Specify the node which list is used to insert
                    the entry.

        MUIV_NListtree_Insert_ListNode_Root
            Use the root list.

        MUIV_NListtree_Insert_ListNode_Active
            Use the list of the active node.

        MUIV_NListtree_Insert_ListNode_ActiveFallback
            Use the list of the active node. If no list is active,
            an automatic fallback to the root list is done.

        MUIV_NListtree_Insert_ListNode_LastInserted
            Insert entry in the list the last entry was inserted.

    prevtreenode -    The node which is the predecessor of the node
                    to insert.

        MUIV_NListtree_Insert_PrevNode_Head
            The entry will be inserted at the head of the list.

        MUIV_NListtree_Insert_PrevNode_Tail
            The entry will be inserted at the tail of the list.

        MUIV_NListtree_Insert_PrevNode_Active
            The entry will be inserted after the active node of
            the list. If no entry is active, the entry will be
            inserted at the tail.

        MUIV_NListtree_Insert_PrevNode_Sorted:
            The entry will be inserted using the defined sort hook.

    flags:

        MUIV_NListtree_Insert_Flag_Active
            The inserted entry will be set to active. This means the
            cursor is moved to the newly inserted entry. If the entry
            was inserted into a closed node, it will be opened.

        MUIV_NListtree_Insert_Flag_NextNode
            'prevtreenode' is the successor, not the predecessor.

   RESULT

    A pointer to the newly inserted entry.

   EXAMPLE

        // Insert an entry after the active one and make it active.
        DoMethod(obj, MUIM_NListtree_Insert, "Hello", NULL,
            MUIV_NListtree_Insert_ListNode_Active,
            MUIV_NListtree_Insert_PrevNode_Active,
            MUIV_NListtree_Insert_Flag_Active);

   NOTES

   BUGS

    Not implemented yet:
        MUIV_NListtree_Insert_Flag_NextNode

MUIM_NListtree_InsertStruct -- Insert a structure such as a path using a delimiter. (V1)

   SYNOPSIS

    struct MUI_NListtree_TreeNode *treenode =
        DoMethod(obj, MUIM_NListtree_InsertStruct,
            STRPTR name, APTR userdata,
            STRPTR delimiter, ULONG flags);

   FUNCTION

    Insert a structure into the list such as a path or
    something similar (like ListtreeName.mcc does). The name is
    split using the supplied delimiter. For each name part a
    new tree entry is generated. If you have Images/aphaso/Image.mbr,
    the structure will be build as follows:

        + Images
          + aphaso
            - Image.mbr

    If a part of the structure is already present, it will be used to
    insert.

   INPUTS

    name -        Data containing (must not) one or more delimiters as
                specified in delimiter (Images/aphaso/Image.mbr for
                example).

    userdata -    Your personal data.

    delimiter -    The delimiter(s) used in the name field (":/" or
                something).

    flags:

        Use normal insert flags here (see there).

   RESULT

    A pointer to the last instance of newly inserted entries.

   EXAMPLE

        // Insert a directory path.
       path = MyGetPath( lock );

        DoMethod(obj, MUIM_NListtree_InsertStruct,
            path, NULL, ":/", 0);

   NOTES

   BUGS

MUIM_NListtree_Move -- Move an entry to the specified position. (V1)

   SYNOPSIS

    DoMethod(obj, MUIM_NListtree_Move,
        struct MUI_NListtree_TreeNode *oldlistnode,
        struct MUI_NListtree_TreeNode *oldtreenode,
        struct MUI_NListtree_TreeNode *newlistnode,
        struct MUI_NListtree_TreeNode *newtreenode,
        ULONG flags);

   FUNCTION

    Move an entry to the position after a defined node.

   INPUTS

    oldlistnode -    Specify the node which list is used to find the
                    entry. The search is started at the head of this
                    list.

        MUIV_NListtree_Move_OldListNode_Root
            The root list is used as the starting point.

        MUIV_NListtree_Move_OldListNode_Active
            The active list (the list of the active node) is used as
            the starting point.

    oldtreenode -    Specify the node which should be moved.

        MUIV_NListtree_Move_OldTreeNode_Head
            The head of the list defined in 'oldlistnode' is moved.

        MUIV_NListtree_Move_OldTreeNode_Tail
            The tail of the list defined in 'oldlistnode' is moved.

        MUIV_NListtree_Move_OldTreeNode_Active
            The active node is moved.

    newlistnode -    Specify the node which list is used to find the
                    entry. The search is started at the head of this
                    list.

        MUIV_NListtree_Move_NewListNode_Root
            The root list.

        MUIV_NListtree_Move_NewListNode_Active
            The list of the active node.

    newtreenode -    This node is the predecessor of the entry which is
                    inserted.

        MUIV_NListtree_Move_NewTreeNode_Head
            The node is moved to the head of the list defined in
            'newlistnode'.

        MUIV_NListtree_Move_NewTreeNode_Tail
            The node is moved to the tail of the list defined in
            'newlistnode'.

        MUIV_NListtree_Move_NewTreeNode_Active:
            The node is moved to one entry after the active node.

        MUIV_NListtree_Move_NewTreeNode_Sorted:
            The node is moved to the list using the sort hook.

    flags -        Some flags to adjust moving.

        MUIV_NListtree_Move_Flag_KeepStructure
            The full tree structure from the selected entry to
            the root list is moved (created at destination).

   RESULT

   EXAMPLE

        // Move an entry to the head of another list-node.
        DoMethod(obj,
            MUIV_NListtree_Move_OldListNode_Active,
            MUIV_NListtree_Move_OldTreeNode_Active,
            somelistmode,
            MUIV_NListtree_Move_NewTreeNode_Head,
            0);

   NOTES

   BUGS

MUIM_NListtree_MultiTest -- Called for every selection. (V1)

   SYNOPSIS

    DoMethodA(obj, MUIM_NListtree_MultiTest,
        struct MUIP_NListtree_MultiTest *multimessage);

   FUNCTION

    This method must not be called directly. It will be called by
    NListtree just before multiselection. You can overload it and
    return TRUE or FALSE whether you want the entry to be multi-
    selectable or not.

   INPUTS

   RESULT

   EXAMPLE

   NOTES

   BUGS

MUIM_NListtree_NextSelected -- Get next selected tree node. (V1)

   SYNOPSIS

    DoMethod(obj, MUIM_NListtree_NextSelected,
        struct MUI_NListtree_TreeNode **treenode);

   FUNCTION

    Iterate through the selected entries of a tree. This method steps
    through the contents of a (multi select) list tree and returns
    every entry that is currently selected. When no entry is selected
    but an entry is active, only the active entry will be returned.

    This behaviour will result in not returning the active entry when
    you have some other selected entries somewhere in your list. Since
    the active entry just acts as some kind of cursor mark, this seems
    to be the only sensible possibility to handle multi selection
    together with keyboard control.

   INPUTS

    treenode -  A pointer to a pointer of struct MUI_NListtree_TreeNode
                that will hold the returned entry. Must be set to
                MUIV_NListtree_NextSelected_Start at start of iteration
                and is set to MUIV_NListtree_NextSelected_End when
                iteration is finished.

        MUIV_NListtree_NextSelected_Start    Set this to start iteration.
        MUIV_NListtree_NextSelected_End        Will be set to this, if
                                            last selected entry reached.

   RESULT

   EXAMPLE

    // Iterate through a list
    struct MUI_NListtree_TreeNode *treenode;

    treenode = MUIV_NListtree_NextSelected_Start;

    for (;;)
    {
        DoMethod(listtree, MUIM_NListtree_NextSelected, &treenode);

        if (treenode==MUIV_NListtree_NextSelected_End)
            break;

        printf("selected: %s\n", treenode->tn_Name);
    }

   NOTES

   BUGS

MUIM_NListtree_Open -- Open the specified tree node. (V1)

   SYNOPSIS

    DoMethod(obj, MUIM_NListtree_Open,
        struct MUI_NListtree_TreeNode *listnode,
        struct MUI_NListtree_TreeNode *treenode,
        ULONG flags);

   FUNCTION

    Opens a node in the listtree. To open a child, which isn't displayed,
    use 'MUIV_NListtree_Open_ListNode_Parent' to open all its parents, too.

    Only nodes can be opened.

   INPUTS

    listnode -    Specify the node which list is used to open the node.

        MUIV_NListtree_Open_ListNode_Root
            The root list is used.

        MUIV_NListtree_Open_ListNode_Parent
            Indicates, that all the parents of the node specified in
            'treenode' should be opened too.

        MUIV_NListtree_Open_ListNode_Active
            The list of the active node is used.

    treenode -    The node to open.

        MUIV_NListtree_Open_TreeNode_Head
            Opens the head node of the list.

        MUIV_NListtree_Open_TreeNode_Tail
            Opens the tail node of the list.

        MUIV_NListtree_Open_TreeNode_Active
            The active node will be opened.

        MUIV_NListtree_Open_TreeNode_All:
            All the nodes of the list are opened.

   RESULT

   EXAMPLE
        // Open the active list.
        DoMethod(obj, MUIM_NListtree_Open,
            MUIV_NListtree_Open_ListNode_Active,
            MUIV_NListtree_Open_TreeNode_Active, 0);

   NOTES

   BUGS

MUIM_NListtree_PrevSelected -- Get previously selected tree node. (V1)

   SYNOPSIS

    DoMethod(obj, MUIM_NListtree_PrevSelected,
        struct MUI_NListtree_TreeNode **treenode);

   FUNCTION

    Iterate reverse through the selected entries of a tree. This method
    steps through the contents of a (multi-select) list tree and returns
    every entry that is currently selected. When no entry is selected
    but an entry is active, only the active entry will be returned.

    This behaviour will result in not returning the active entry when
    you have some other selected entries somewhere in your list. Since
    the active entry just acts as some kind of cursor mark, this seems
    to be the only sensible possibility to handle multi selection
    together with keyboard control.

   INPUTS

    treenode -  A pointer to a pointer of struct MUI_NListtree_TreeNode
                that will hold the returned entry. Must be set to
                MUIV_NListtree_PrevSelected_Start at start of iteration
                an the end and is set to MUIV_NListtree_PrevSelected_End
                when first selected entry is reached and iteration is
                finished.

        MUIV_NListtree_PrevSelected_Start    Set this to start iteration.
        MUIV_NListtree_PrevSelected_End        Will be set to this, if
                                            last selected entry reached.

   RESULT

   EXAMPLE

    // Iterate through a list (reverse)
    struct MUI_NListtree_TreeNode *treenode;

    treenode = MUIV_NListtree_PrevSelected_Start;

    for (;;)
    {
        DoMethod(listtree, MUIM_NListtree_PrevSelected, &treenode);

        if (treenode==MUIV_NListtree_PrevSelected_End)
            break;

        printf("selected: %s\n", treenode->tn_Name);
    }

   NOTES

   BUGS

MUIM_NListtree_Redraw -- Redraw the specified tree node. (V1)

   SYNOPSIS

    DoMethod(obj, MUIM_NListtree_Redraw,
        struct MUI_NListtree_TreeNode *treenode, ULONG flags);

   FUNCTION

    Redraw the specified entry. See special values for completeness.

   INPUTS

    treenode -    The tree node to be redrawn.

        MUIV_NListtree_Redraw_Active
            Redraw the active entry.

        MUIV_NListtree_Redraw_All
            Redraw the complete visible tree.

    flags:

        MUIV_NListtree_Redraw_Flag_Nr
            The data specified in 'treenode' is the entry number,
            not the tree node itself.

   RESULT

   EXAMPLE

        // Redraw the active entry.
        DoMethod(obj, MUIM_NListtree_Redraw,
            MUIV_NListtree_Redraw_Active, 0);

   NOTES

   BUGS

MUIM_NListtree_Remove -- Remove the specified entry(ies). (V1)

   SYNOPSIS

    DoMethod(obj, MUIM_NListtree_Remove,
        struct MUI_NListtree_TreeNode *listnode,
        struct MUI_NListtree_TreeNode *treenode,
        ULONG flags);

   FUNCTION

    Removes a node or nodes from the listtree. When the active entry
    is removed, the successor will become active.

   INPUTS

    listnode -    Specify the node which list is used to find the entry
                which should be removed. The search is started at the
                begin of this list.

        MUIV_NListtree_Remove_ListNode_Root
            The root list is used.

        MUIV_NListtree_Remove_ListNode_Active
            The list of the active node is used.

    treenode -    The node which should be removed. If there are children
                of this node, they are also removed.

        MUIV_NListtree_Remove_TreeNode_Head
            The head of the list defined in 'listnode' is removed.

        MUIV_NListtree_Remove_TreeNode_Tail
            The tail of the list defined in 'listnode' is removed.

        MUIV_NListtree_Remove_TreeNode_Active
            Removes the active node.

        MUIV_NListtree_Remove_TreeNode_All
            All nodes of the list which is specified in 'listnode',
            are removed. Other nodes of parent lists are not
            affected.

        MUIV_NListtree_Remove_TreeNode_Selected
            All selected nodes are removed.

   RESULT

   EXAMPLE

        // Remove the active entry if delete is pressed!
        DoMethod(bt_delete, MUIM_Notify, MUIA_Pressed, FALSE,
            lt_list, 4, MUIM_NListtree_Remove,
            MUIV_NListtree_Remove_ListNode_Active,
            MUIV_NListtree_Remove_TreeNode_Active, 0);

   NOTES

   BUGS

MUIM_NListtree_Rename -- Rename the specified node. (V1)

   SYNOPSIS

    struct MUI_NListtree_TreeNode *treenode =
        DoMethod(obj, MUIM_NListtree_Rename,
            struct MUI_NListtree_TreeNode *treenode,
            STRPTR newname, ULONG flags);

   FUNCTION

    Rename the specified node.

    If you want to rename the tn_User field (see flags below), the construct
    and destruct hooks are used!
    If you have not specified these hooks, only the pointers will be copied.

   INPUTS

    treenode -    Specifies the node which should be renamed.

        MUIV_NListtree_Rename_TreeNode_Active:
            Rename the active tree node.

    newname -    The new name or pointer.

    flags:

        MUIV_NListtree_Rename_Flag_User
            The tn_User field is renamed.

        MUIV_NListtree_Rename_Flag_NoRefresh
            The list entry will not be refreshed.

   RESULT

    Returns the pointer of the renamed tree node.

   EXAMPLE

        // Rename the active tree node.
        DoMethod(obj, MUIM_NListtree_Rename,
            MUIV_NListtree_Rename_TreeNode_Active,
            "Very new name", 0);

   NOTES

   BUGS

MUIM_NListtree_Select -- Select the specified tree node. (V1)

   SYNOPSIS

    DoMethod(obj, MUIM_NListtree_Select,
        struct MUI_NListtree_TreeNode *treenode, LONG seltype,
        LONG selflags, LONG *state);

   FUNCTION

    Select or unselect a tree entry or ask an entry about its state.
    See special values for completeness.

   INPUTS

    treenode -    The tree node to be selected/unselected/asked.

        MUIV_NListtree_Select_Active    For the active entry.
        MUIV_NListtree_Select_All        For all entries.
        MUIV_NListtree_Select_Visible    For all visible entries.

    seltype -    Type of selection/unselection/ask

        MUIV_NListtree_Select_Off        Unselect entry.
        MUIV_NListtree_Select_On        Select entry.
        MUIV_NListtree_Select_Toggle    Toggle entries state.
        MUIV_NListtree_Select_Ask        Just ask about the state.

    selflags -    Some kind of specials.

        MUIV_NListtree_Select_Flag_Force
            Adding this flag to seltype forces the selection by
            bypassing the multi test hook.

    state -        Pointer to a longword. If not NULL, it will be filled
                with the current selection state of the entry.

   RESULT

   EXAMPLE

        // Select the active entry.
        LONG retstate;

        DoMethod(obj, MUIM_NListtree_Select,
            MUIV_NListtree_Select_Active, MUIV_NListtree_Select_On,
            0, &retstate);

        // We must check this, because the multi-test hook may
        // cancel our selection.
        if (retstate == MUIV_NListtree_Select_On) {
            ...
        }

   NOTES

    If ( treenode == MUIV_NListtree_Select_All ) and
    ( seltype == MUIV_NListtree_Select_Ask ), state will be filled
    with the total number of selected entries.

    NEW for final 18.6:
    If (treenode == MUIV_NListtree_Select_Active ) and
    ( seltype == MUIV_NListtree_Select_Ask ), state will be the
    active entry, if any, or NULL.

    If only the active entry is selected, has a cursor mark (see
    MUIM_NListtree_NextSelected for that), you will receive 0 as
    the number of selected entries.

   BUGS

MUIM_NListtree_Sort -- Sort the specified list node. (V1)

   SYNOPSIS

    DoMethod(obj, MUIM_NListtree_Sort,
        struct MUI_NListtree_TreeNode *listnode,
        ULONG flags);

   FUNCTION

    Sort the specified list node using the sort hook.

   INPUTS

    listnode -    List node to sort.

        MUIV_NListtree_Sort_ListNode_Root
            Sort the root list.

        MUIV_NListtree_Sort_ListNode_Active
            Sort the list node of the active entry.

        MUIV_NListtree_Sort_TreeNode_Active
            Sorts the children of the active entry if a list.

    flags -        Control the part where sorting is done.

        MUIV_NListtree_Sort_Flag_RecursiveOpen
            Sort the list recursive. All open child nodes of the
            node specified in 'listnode' will be sorted too.

        MUIV_NListtree_Sort_Flag_RecursiveAll
            Sort the list recursive with ALL child nodes of the
            node specified in 'listnode'.

   RESULT

   EXAMPLE

        // Sort the list of the active node.
        DoMethod(obj, MUIM_NListtree_Sort,
            MUIV_NListtree_Sort_ListNode_Active, 0);

   NOTES

   BUGS

MUIM_NListtree_TestPos -- Get information about entry at x/y pos. (V1)

   SYNOPSIS

    DoMethod(obj, MUIM_NListtree_TestPos, LONG xpos, LONG ypos,
        struct MUI_NListtree_TestPos_Result *testposresult);

   FUNCTION

    Find out some information about the currently displayed entry at a
    certain position (x/y-pos).

    This is very useful for Drag&Drop operations.

   INPUTS

    xpos -            X-position.
    ypos -            Y-position.
    testposresult -    Pointer to a valid MUI_NListtree_TestPos_Result
                    structure.

   RESULT

    tpr_TreeNode -    The tree node under the requested position or NULL
                    if there is no entry displayed.

    The tpr_Type field contains detailed information about the relative
    position:

        MUIV_NListtree_TestPos_Result_Above
        MUIV_NListtree_TestPos_Result_Below
        MUIV_NListtree_TestPos_Result_Onto
        MUIV_NListtree_TestPos_Result_Sorted

    tpr_Column -    The column unter the specified position or -1 if
                    no valid column.

   EXAMPLE

        // Entry under the cursor?
        struct MUI_NListtree_TestPos_Result tpres;

        DoMethod(obj, MUIM_NListtree_TestPos, msg->imsg->MouseX,
            msg->imsg->MouseY, &tpres);

        if ( tpres.tpr_Entry != NULL )
        {
            // Do something special here...
        }

   NOTES

   BUGS

/***************************************************************************

 NListtree.mcc - New Listtree MUI Custom Class
 Copyright (C) 1999-2001 by Carsten Scholling
 Copyright (C) 2001-2006 by NList Open Source Team

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 NList classes Support Site:  http://www.sf.net/projects/nlist-classes

 $Id: NListtree-Demo.c 43734 2012-01-28 14:26:37Z mazze $

***************************************************************************/

#if defined(__AROS__)
#define MUI_OBSOLETE 1
#endif

/*
**	Includes
*/
#include <proto/muimaster.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/utility.h>

#if !defined(__amigaos4__)
#include <clib/alib_protos.h>
#endif

#include <exec/memory.h>
#include <exec/types.h>

#include <mui/NListtree_mcc.h>
#include <mui/NListview_mcc.h>
#include <mui/NList_mcc.h>

#include <string.h>
#include <stdio.h>
#include <time.h>

#ifdef MYDEBUG
 #define bug kprintf
 #define D(x)
 void kprintf( UBYTE *fmt, ... );
#else
 #define bug
 #define D(x)
#endif

#ifndef MAKE_ID
#define MAKE_ID(a,b,c,d) ((ULONG) (a)<<24 | (ULONG) (b)<<16 | (ULONG) (c)<<8 | (ULONG) (d))
#endif

#include "SDI_hook.h"

#ifndef MUIA_Slider_Level
#define MUIA_Slider_Level                   0x8042ae3a /* V4  isg LONG              */
#endif

/*
**	Do not use stack sizes below 8KB!!
*/
LONG __stack = 16384;

/*
**	MUI library base.
*/
struct Library *MUIMasterBase = NULL;

#if defined(__amigaos4__)
struct Library *IntuitionBase = NULL;
#else
struct IntuitionBase *IntuitionBase = NULL;
#endif

#if defined(__amigaos4__)
struct IntuitionIFace *IIntuition = NULL;
struct MUIMasterIFace *IMUIMaster = NULL;
#endif

struct MUI_NListtree_TreeNode *tntest;

/*
**	MUI objects.
*/
STATIC APTR		app, window,lt_nodes,
				tx_info1,	tx_info2,	tx_info3,
				sl_treecol,	st_string,
				bt_open,	bt_close,	bt_expand,	bt_collapse,
				bt_insert,	bt_remove,	bt_exchange,bt_rename,
				bt_move,	bt_copy,	bt_moveks,	bt_copyks,
				bt_find,	bt_parent,	bt_sort,	bt_getnr,
				bt_redraw,	bt_selected,bt_showtree,bt_seltogg,
				bt_test,	bt_test2,	bt_test3,	bt_test4;

/*
**	Sample tree structure.
*/
struct SampleArray
{
	const char *name;
	ULONG flags;
};

STATIC const struct SampleArray sa[] =
{
	{ "comp", TNF_LIST | TNF_OPEN },
	{	 "sys", TNF_LIST | TNF_OPEN },
	{		 "amiga", TNF_LIST | TNF_OPEN },
	{			 "misc", 0x8000 },
	{		 "mac", TNF_LIST },
	{			 "system", 0x8000 },

	{"de", TNF_LIST | TNF_OPEN },
	{	 "comm", TNF_LIST },
	{		 "software", TNF_LIST },
	{			 "ums", 0x8000 },
	{	 "comp", TNF_LIST | TNF_OPEN },
	{		 "sys", TNF_LIST | TNF_OPEN },
	{			 "amiga", TNF_LIST },
	{				 "misc", 0x8000 },
	{				 "tech", 0x8000 },
	{			 "amiga", 0x8000 },

	{"sort test", TNF_LIST | TNF_OPEN },
	{	 "a", 0 },
	{	 "x", TNF_LIST },
	{	 "v", 0 },
	{	 "g", TNF_LIST },
	{	 "h", 0 },
	{	 "k", TNF_LIST },
	{	 "u", 0 },
	{	 "i", TNF_LIST },
	{	 "t", 0 },
	{	 "e", TNF_LIST },
	{	 "q", 0 },
	{	 "s", TNF_LIST },
	{	 "c", 0 },
	{	 "f", TNF_LIST },
	{	 "p", 0 },
	{	 "l", TNF_LIST },
	{	 "z", 0 },
	{	 "w", TNF_LIST },
	{	 "b", 0 },
	{	 "o", TNF_LIST },
	{	 "d", 0 },
	{	 "m", TNF_LIST },
	{	 "r", 0 },
	{	 "y", TNF_LIST },
	{	 "n", 0 },
	{	 "j", TNF_LIST },

	{"m", TNF_LIST },
	{	 "i", TNF_LIST },
	{		 "c", TNF_LIST },
	{			 "h", TNF_LIST },
	{				 "e", TNF_LIST },
	{					 "l", TNF_LIST },
	{						 "a", TNF_LIST },
	{							 "n", TNF_LIST },
	{								 "g", TNF_LIST },
	{									 "e", TNF_LIST },
	{										 "l", TNF_LIST },
	{											 "o", 0 },

	{"end", TNF_LIST },
	{	 "of", TNF_LIST },
	{		 "tree", 0 },

	{ "Sort Test 2", TNF_LIST },

	{ NULL, 0 }
};

/*
**	This function draws the sample tree structure.
*/
STATIC VOID DrawSampleTree( Object *ltobj )
{
	struct MUI_NListtree_TreeNode *tn1, *tn2, *tn3;
	char txt[128];
	WORD i = 0, j;

	tn1 = (struct MUI_NListtree_TreeNode *)DoMethod( ltobj, MUIM_NListtree_Insert, sa[i].name, (IPTR)sa[i].flags, MUIV_NListtree_Insert_ListNode_Root, MUIV_NListtree_Insert_PrevNode_Tail, sa[i].flags ); i++;
	tn2 = (struct MUI_NListtree_TreeNode *)DoMethod( ltobj, MUIM_NListtree_Insert, sa[i].name, (IPTR)sa[i].flags, tn1, MUIV_NListtree_Insert_PrevNode_Tail, sa[i].flags ); i++;
	tn1 = (struct MUI_NListtree_TreeNode *)DoMethod( ltobj, MUIM_NListtree_Insert, sa[i].name, (IPTR)sa[i].flags, tn2, MUIV_NListtree_Insert_PrevNode_Tail, sa[i].flags ); i++;
	tn1 = (struct MUI_NListtree_TreeNode *)DoMethod( ltobj, MUIM_NListtree_Insert, sa[i].name, (IPTR)sa[i].flags, tn1, MUIV_NListtree_Insert_PrevNode_Tail, sa[i].flags ); i++;
	tn1 = (struct MUI_NListtree_TreeNode *)DoMethod( ltobj, MUIM_NListtree_Insert, sa[i].name, (IPTR)sa[i].flags, tn2, MUIV_NListtree_Insert_PrevNode_Tail, sa[i].flags ); i++;
	tntest = tn1 = (struct MUI_NListtree_TreeNode *)DoMethod( ltobj, MUIM_NListtree_Insert, sa[i].name, (IPTR)sa[i].flags, tn1, MUIV_NListtree_Insert_PrevNode_Tail, sa[i].flags ); i++;

	tn1 = (struct MUI_NListtree_TreeNode *)DoMethod( ltobj, MUIM_NListtree_Insert, sa[i].name, (IPTR)sa[i].flags, MUIV_NListtree_Insert_ListNode_Root, MUIV_NListtree_Insert_PrevNode_Tail, sa[i].flags ); i++;
	tn2 = (struct MUI_NListtree_TreeNode *)DoMethod( ltobj, MUIM_NListtree_Insert, sa[i].name, (IPTR)sa[i].flags, tn1, MUIV_NListtree_Insert_PrevNode_Tail, sa[i].flags ); i++;
	tn2 = (struct MUI_NListtree_TreeNode *)DoMethod( ltobj, MUIM_NListtree_Insert, sa[i].name, (IPTR)sa[i].flags, tn2, MUIV_NListtree_Insert_PrevNode_Tail, sa[i].flags ); i++;
	tn2 = (struct MUI_NListtree_TreeNode *)DoMethod( ltobj, MUIM_NListtree_Insert, sa[i].name, (IPTR)sa[i].flags, tn2, MUIV_NListtree_Insert_PrevNode_Tail, sa[i].flags ); i++;
	tn3 = (struct MUI_NListtree_TreeNode *)DoMethod( ltobj, MUIM_NListtree_Insert, sa[i].name, (IPTR)sa[i].flags, tn1, MUIV_NListtree_Insert_PrevNode_Tail, sa[i].flags ); i++;
	tn1 = (struct MUI_NListtree_TreeNode *)DoMethod( ltobj, MUIM_NListtree_Insert, sa[i].name, (IPTR)sa[i].flags, tn3, MUIV_NListtree_Insert_PrevNode_Tail, sa[i].flags ); i++;
	tn2 = (struct MUI_NListtree_TreeNode *)DoMethod( ltobj, MUIM_NListtree_Insert, sa[i].name, (IPTR)sa[i].flags, tn1, MUIV_NListtree_Insert_PrevNode_Tail, sa[i].flags ); i++;
	tn3 = (struct MUI_NListtree_TreeNode *)DoMethod( ltobj, MUIM_NListtree_Insert, sa[i].name, (IPTR)sa[i].flags, tn2, MUIV_NListtree_Insert_PrevNode_Tail, sa[i].flags ); i++;
	tn3 = (struct MUI_NListtree_TreeNode *)DoMethod( ltobj, MUIM_NListtree_Insert, sa[i].name, (IPTR)sa[i].flags, tn2, MUIV_NListtree_Insert_PrevNode_Tail, sa[i].flags ); i++;
	tn3 = (struct MUI_NListtree_TreeNode *)DoMethod( ltobj, MUIM_NListtree_Insert, sa[i].name, (IPTR)sa[i].flags, tn1, MUIV_NListtree_Insert_PrevNode_Tail, sa[i].flags ); i++;

	tn1 = (struct MUI_NListtree_TreeNode *)DoMethod( ltobj, MUIM_NListtree_Insert, sa[i].name, (IPTR)sa[i].flags, MUIV_NListtree_Insert_ListNode_Root, MUIV_NListtree_Insert_PrevNode_Tail, sa[i].flags ); i++;

	for( j = 0; j < 26; j++ )
	{
		DoMethod( ltobj, MUIM_NListtree_Insert, sa[i].name, (IPTR)sa[i].flags, tn1, MUIV_NListtree_Insert_PrevNode_Tail, sa[i].flags ); i++;
	}

	tn1 = (struct MUI_NListtree_TreeNode *)DoMethod( ltobj, MUIM_NListtree_Insert, sa[i].name, (IPTR)sa[i].flags, MUIV_NListtree_Insert_ListNode_Root, MUIV_NListtree_Insert_PrevNode_Tail, sa[i].flags ); i++;

	for( j = 0; j < 11; j++ )
	{
		tn1 = (struct MUI_NListtree_TreeNode *)DoMethod( ltobj, MUIM_NListtree_Insert, sa[i].name, (IPTR)sa[i].flags, tn1, MUIV_NListtree_Insert_PrevNode_Tail, sa[i].flags ); i++;
	}

	tn1 = (struct MUI_NListtree_TreeNode *)DoMethod( ltobj, MUIM_NListtree_Insert, sa[i].name, (IPTR)sa[i].flags, MUIV_NListtree_Insert_ListNode_Root, MUIV_NListtree_Insert_PrevNode_Tail, sa[i].flags ); i++;
	tn1 = (struct MUI_NListtree_TreeNode *)DoMethod( ltobj, MUIM_NListtree_Insert, sa[i].name, (IPTR)sa[i].flags, tn1, MUIV_NListtree_Insert_PrevNode_Tail, sa[i].flags ); i++;
	tn1 = (struct MUI_NListtree_TreeNode *)DoMethod( ltobj, MUIM_NListtree_Insert, sa[i].name, (IPTR)sa[i].flags, tn1, MUIV_NListtree_Insert_PrevNode_Tail, sa[i].flags ); i++;

	tn1 = (struct MUI_NListtree_TreeNode *)DoMethod( ltobj, MUIM_NListtree_Insert, sa[i].name, (IPTR)sa[i].flags, MUIV_NListtree_Insert_ListNode_Root, MUIV_NListtree_Insert_PrevNode_Tail, sa[i].flags ); i++;

	for( i = 0; i < 2500; i++ )
	{
		if ( i % 2 )	snprintf( txt, sizeof(txt), "Sort Entry %d", i + 1 );
		else			snprintf( txt, sizeof(txt), "Entry Sort %d", i + 1 );

		tn2 = (struct MUI_NListtree_TreeNode *)DoMethod( ltobj, MUIM_NListtree_Insert, txt, 0, ( i % 5 ) ? tn2 : tn1, MUIV_NListtree_Insert_PrevNode_Tail, ( i % 5 ) ? TNF_LIST : 0 );
	}

	DoMethod( ltobj, MUIM_NListtree_InsertStruct, "This/is/a/very/long/test/for/Blafasel_InsertStruct", 0, "/", 0 );
	DoMethod( ltobj, MUIM_NListtree_InsertStruct, "This/is/another/very/long/test/for/Blafasel_InsertStruct", 0, "/", 0 );
}

static struct MUI_NListtree_TreeNode *GetParent( Object *obj, struct MUI_NListtree_TreeNode *tn )
{
	if ( tn != NULL )
	{
		return( (struct MUI_NListtree_TreeNode *)DoMethod( obj, MUIM_NListtree_GetEntry, MUIV_NListtree_GetEntry_ListNode_Root, MUIV_NListtree_GetEntry_Position_Parent, 0 ) );
	}

	return( NULL );
}

static struct MUI_NListtree_TreeNode *GetParentNotRoot( Object *obj, struct MUI_NListtree_TreeNode *tn )
{
	if((tn = GetParent( obj, tn)))
	{
		if ( GetParent( obj, tn ) )
		{
			return( tn );
		}
	}

	return( NULL );
}

struct MUI_NListtree_TreeNode *IsXChildOfY( Object *obj, struct MUI_NListtree_TreeNode *x, struct MUI_NListtree_TreeNode *y )
{
	do
	{
		if ( y == x )
		{
			return( y );
		}
	}
	while((y = GetParentNotRoot( obj, y)));

	return( NULL );
}

/*
**	Allocates memory for each entry we create.
*/
HOOKPROTONHNO(confunc, SIPTR, struct MUIP_NListtree_ConstructMessage *msg)
{
	struct SampleArray *sa;

	/*
	**	Allocate needed piece of memory for the new entry.
	*/
	if((sa = (struct SampleArray *)AllocVec( sizeof( struct SampleArray) + strlen( msg->Name ) + 1, MEMF_CLEAR)))
	{
		/*
		**	Save the user data field right after the
		**	array structure.
		*/
		strcpy( (STRPTR)&sa[1], msg->Name );
		sa->name = (STRPTR)&sa[1];

		sa->flags = (IPTR)msg->UserData;
	}

	return( (SIPTR)sa );
}
MakeStaticHook(conhook, confunc);

/*
**	Free memory we just allocated above.
*/
HOOKPROTONHNO(desfunc, LONG, struct MUIP_NListtree_DestructMessage *msg)
{
	if ( msg->UserData != NULL )
	{
		FreeVec( msg->UserData );
		msg->UserData = NULL;
	}

	return( 0 );
}
MakeStaticHook(deshook, desfunc);

/*
**	Compare hook function.
*/
HOOKPROTONHNO(compfunc, LONG, struct MUIP_NListtree_CompareMessage *msg)
{
	return( stricmp( msg->TreeNode1->tn_Name, msg->TreeNode2->tn_Name ) );
}
MakeStaticHook(comphook, compfunc);

/*
**	MultiTest hook function.
*/
HOOKPROTONHNO(mtfunc, LONG, struct MUIP_NListtree_MultiTestMessage *msg)
{
	if ( msg->TreeNode->tn_Flags & TNF_LIST )
		return( FALSE );

	return( TRUE );
}
MakeStaticHook(mthook, mtfunc);

/*
**	Format the entry data for displaying.
*/
HOOKPROTONHNO(dspfunc, LONG, struct MUIP_NListtree_DisplayMessage *msg)
{
	STATIC CONST_STRPTR t1 = "Newsgroups", t2 = "Flags", t3 = "subscribed", t4 = "\0", t5 = "Count";
	STATIC char buf[10];

	if ( msg->TreeNode != NULL )
	{
		/*
		**	The user data is a pointer to a SampleArray struct.
		*/
		struct SampleArray *a = (struct SampleArray *)msg->TreeNode->tn_User;

		snprintf( buf, sizeof(buf), "%3d", (unsigned int)(IPTR)msg->Array[-1] );

		*msg->Array++	= msg->TreeNode->tn_Name;
		*msg->Array++	= (STRPTR)(( a->flags & 0x8000 ) ? t3 : t4);
		*msg->Array++	= buf;
	}
	else
	{
		*msg->Array++	= (STRPTR)t1;
		*msg->Array++	= (STRPTR)t2;
		*msg->Array++	= (STRPTR)t5;

		*msg->Preparse++	= (STRPTR)"\033b\033u";
		*msg->Preparse++	= (STRPTR)"\033b\033u";
		*msg->Preparse++	= (STRPTR)"\033b\033u";
	}

	return( 0 );
}
MakeStaticHook(dsphook, dspfunc);

/*
**	Insert a new entry which name is given in
**	the string gadget.
*/
HOOKPROTONHNP(insertfunc, LONG, Object *obj)
{
	STRPTR x = NULL;

	/*
	**	Get user string.
	*/
	get( st_string, MUIA_String_Contents, &x );

	/*
	**	Insert the new entry after
	**	the active entry.
	*/
	DoMethod( obj, MUIM_NListtree_Insert, x, 0, MUIV_NListtree_Insert_ListNode_Active,
		MUIV_NListtree_Insert_PrevNode_Active, MUIV_NListtree_Insert_Flag_Active );

	return( 0 );
}
MakeStaticHook(inserthook, insertfunc);

/*
**	Exchange two entries.
*/
HOOKPROTONH(exchangefunc, LONG, Object *obj, ULONG **para)
{
	STATIC struct MUI_NListtree_TreeNode *tn1, *tn2;
	STATIC LONG exchcnt = 0;

	if ( ( exchcnt == 0 ) && ( (IPTR)*para == 42 ) )
	{
		get( obj, MUIA_NListtree_Active, &tn1 );

		if ( tn1 != MUIV_NListtree_Active_Off )
		{
			nnset( tx_info3, MUIA_Text_Contents, "Select entry to exchange selected entry with." );

			exchcnt++;
		}
	}

	else if ( exchcnt == 1 )
	{
		get( obj, MUIA_NListtree_Active, &tn2 );

		if ( ( tn2 != MUIV_NListtree_Active_Off ) && ( tn1 != tn2 ) )
		{
			if ( !IsXChildOfY( obj, tn1, tn2 ) && !IsXChildOfY( obj, tn1, tn2 ) )
			{
				struct MUI_NListtree_ListNode *ln1;

				if((ln1 = (struct MUI_NListtree_ListNode *)DoMethod( obj, MUIM_NListtree_GetEntry, tn1, MUIV_NListtree_GetEntry_Position_Parent, 0)))
				{
					DoMethod( obj, MUIM_NListtree_Exchange, ln1, tn1, MUIV_NListtree_Exchange_ListNode2_Active, MUIV_NListtree_Exchange_TreeNode2_Active, 0 );

					nnset( tx_info3, MUIA_Text_Contents, "Entries successfully exchanged!" );
				}
				else
					nnset( tx_info3, MUIA_Text_Contents, "Something went wrong! Try again to select." );
			}
			else
				nnset( tx_info3, MUIA_Text_Contents, "You can not exchange with childs!" );
		}
		else
			nnset( tx_info3, MUIA_Text_Contents, "You should not exchange an entry with itself!" );

		exchcnt = 0;
	}

	return( 0 );
}
MakeStaticHook(exchangehook, exchangefunc);

/*
**	Rename the selected entry with the name is given in
**	the string gadget.
*/
HOOKPROTONHNP(renamefunc, LONG, Object *obj)
{
	struct MUI_NListtree_TreeNode *tn = NULL;
	STRPTR x = NULL;

	/*
	**	Get user string.
	*/
	get( st_string, MUIA_String_Contents, &x );
	get( obj, MUIA_NListtree_Active, &tn );

	/*
	**	Insert the new entry sorted (compare hook)
	**	into the active list node.
	*/
	DoMethod( obj, MUIM_NListtree_Rename, tn,
		x, 0 );

	return( 0 );
}
MakeStaticHook(renamehook, renamefunc);

/*
**	Insert a new entry which name is given in
**	the string gadget.
*/
HOOKPROTONH(movefunc, LONG, Object *obj, ULONG **para)
{
	STATIC struct MUI_NListtree_TreeNode *tn1, *tn2;
	STATIC LONG movecnt = 0;

	if ( ( movecnt == 0 ) && ( (IPTR)*para == 42 ) )
	{
		get( obj, MUIA_NListtree_Active, &tn1 );

		if ( tn1 != MUIV_NListtree_Active_Off )
		{
			nnset( tx_info3, MUIA_Text_Contents, "Select entry to insert after by simple click." );

			movecnt++;
		}
	}

	else if ( movecnt == 1 )
	{
		get( obj, MUIA_NListtree_Active, &tn2 );

		if ( ( tn2 != MUIV_NListtree_Active_Off ) && ( tn1 != tn2 ) )
		{
			if ( !IsXChildOfY( obj, tn1, tn2 ) && !IsXChildOfY( obj, tn1, tn2 ) )
			{
				struct MUI_NListtree_ListNode *ln1;

				if((ln1 = (struct MUI_NListtree_ListNode *)DoMethod( obj, MUIM_NListtree_GetEntry, tn1, MUIV_NListtree_GetEntry_Position_Parent, 0)))
				{
					DoMethod( obj, MUIM_NListtree_Move, ln1, tn1, MUIV_NListtree_Move_NewListNode_Active, tn2, 0 );

					nnset( tx_info3, MUIA_Text_Contents, "Entry successfully moved!" );
				}
				else
					nnset( tx_info3, MUIA_Text_Contents, "Something went wrong! Try again to select destination." );
			}
			else
				nnset( tx_info3, MUIA_Text_Contents, "You can not move childs!" );
		}
		else
			nnset( tx_info3, MUIA_Text_Contents, "You should not move an entry to itself!" );

		movecnt = 0;
	}

	return( 0 );
}
MakeStaticHook(movehook, movefunc);

/*
**	Insert a new entry which name is given in
**	the string gadget.
*/
HOOKPROTONH(copyfunc, LONG, Object *obj, ULONG **para)
{
	STATIC struct MUI_NListtree_TreeNode *tn1, *tn2;
	STATIC LONG copycnt = 0;

	if ( ( copycnt == 0 ) && ( (IPTR)*para == 42 ) )
	{
		get( obj, MUIA_NListtree_Active, &tn1 );

		if ( tn1 != MUIV_NListtree_Active_Off )
		{
			nnset( tx_info3, MUIA_Text_Contents, "Select entry to insert after by simple click." );

			copycnt++;
		}
	}

	else if ( copycnt == 1 )
	{
		get( obj, MUIA_NListtree_Active, &tn2 );

		if ( ( tn2 != MUIV_NListtree_Active_Off ) && ( tn1 != tn2 ) )
		{
			struct MUI_NListtree_ListNode *ln1;

			if((ln1 = (struct MUI_NListtree_ListNode *)DoMethod( obj, MUIM_NListtree_GetEntry, tn1, MUIV_NListtree_GetEntry_Position_Parent, 0)))
			{
				DoMethod( obj, MUIM_NListtree_Copy, ln1, tn1, MUIV_NListtree_Copy_DestListNode_Active, tn2, 0 );

				nnset( tx_info3, MUIA_Text_Contents, "Entry successfully copied!" );
			}
			else
				nnset( tx_info3, MUIA_Text_Contents, "Something went wrong! Try again to select destination." );
		}
		else
			nnset( tx_info3, MUIA_Text_Contents, "You should not copy an entry to itself!" );

		copycnt = 0;
	}

	return( 0 );
}
MakeStaticHook(copyhook, copyfunc);

/*
**	Move KeepStructure
*/
HOOKPROTONH(moveksfunc, LONG, Object *obj, ULONG **para)
{
	STATIC struct MUI_NListtree_TreeNode *tn1, *tn2;
	STATIC LONG movekscnt = 0;

	if ( ( movekscnt == 0 ) && ( (IPTR)*para == 42 ) )
	{
		get( obj, MUIA_NListtree_Active, &tn1 );

		if ( tn1 != MUIV_NListtree_Active_Off )
		{
			nnset( tx_info3, MUIA_Text_Contents, "Select entry to make KeepStructure move with." );

			movekscnt++;
		}
	}

	else if ( movekscnt == 1 )
	{
		get( obj, MUIA_NListtree_Active, &tn2 );

		if ( ( tn2 != MUIV_NListtree_Active_Off ) && ( tn1 != tn2 ) )
		{
			struct MUI_NListtree_ListNode *ln1;

			if((ln1 = (struct MUI_NListtree_ListNode *)DoMethod( obj, MUIM_NListtree_GetEntry, tn1, MUIV_NListtree_GetEntry_Position_Parent, 0)))
			{
				DoMethod( obj, MUIM_NListtree_Move, ln1, tn1, MUIV_NListtree_Move_NewListNode_Active, tn2, MUIV_NListtree_Move_Flag_KeepStructure );

				nnset( tx_info3, MUIA_Text_Contents, "Entry successfully moved (structure kept)" );
			}
			else
				nnset( tx_info3, MUIA_Text_Contents, "Something went wrong! Try again to select destination." );
		}
		else
			nnset( tx_info3, MUIA_Text_Contents, "You should not move an entry to itself!" );

		movekscnt = 0;
	}

	return( 0 );
}
MakeStaticHook(movekshook, moveksfunc);

/*
**	Copy KeepStructure
*/
HOOKPROTONH(copyksfunc, LONG, Object *obj, ULONG **para)
{
	STATIC struct MUI_NListtree_TreeNode *tn1, *tn2;
	STATIC LONG copykscnt = 0;

	if ( ( copykscnt == 0 ) && ( (IPTR)*para == 42 ) )
	{
		get( obj, MUIA_NListtree_Active, &tn1 );

		if ( tn1 != MUIV_NListtree_Active_Off )
		{
			nnset( tx_info3, MUIA_Text_Contents, "Select entry to make KeepStructure copy with." );

			copykscnt++;
		}
	}

	else if ( copykscnt == 1 )
	{
		get( obj, MUIA_NListtree_Active, &tn2 );

		if ( ( tn2 != MUIV_NListtree_Active_Off ) && ( tn1 != tn2 ) )
		{
			struct MUI_NListtree_ListNode *ln1;

			if((ln1 = (struct MUI_NListtree_ListNode *)DoMethod( obj, MUIM_NListtree_GetEntry, tn1, MUIV_NListtree_GetEntry_Position_Parent, 0)))
			{
				DoMethod( obj, MUIM_NListtree_Copy, ln1, tn1, MUIV_NListtree_Copy_DestListNode_Active, tn2, MUIV_NListtree_Copy_Flag_KeepStructure );

				nnset( tx_info3, MUIA_Text_Contents, "Entry successfully copied (structure kept)" );
			}
			else
				nnset( tx_info3, MUIA_Text_Contents, "Something went wrong! Try again to select destination." );
		}
		else
			nnset( tx_info3, MUIA_Text_Contents, "You should not copy an entry to itself!" );

		copykscnt = 0;
	}

	return( 0 );
}
MakeStaticHook(copykshook, copyksfunc);

HOOKPROTONHNO(fudf, LONG, struct MUIP_NListtree_FindUserDataMessage *msg)
{
	nnset( tx_info1, MUIA_Text_Contents, "FindUserData Hook passed!" );
	return( strncmp( (STRPTR)msg->User, (STRPTR)msg->UserData, strlen( (STRPTR)msg->User ) ) );
}
MakeStaticHook(fudh, fudf);

/*
**	Find the specified tree node by name.
*/
HOOKPROTONHNP(findnamefunc, LONG, Object *obj)
{
	struct MUI_NListtree_TreeNode *tn;
	STRPTR x = NULL;

	/*
	**	Let us see, which string the user wants to search for...
	*/
	get( st_string, MUIA_String_Contents, &x );

	/*
	**	Is it somewhere in the tree?
	*/
	if((tn = (struct MUI_NListtree_TreeNode *)DoMethod(obj, MUIM_NListtree_FindUserData, MUIV_NListtree_FindUserData_ListNode_Root, x, MUIV_NListtree_FindUserData_Flag_Activate)))
	{
		/*
		**	Found! Inform the user.
		*/
		nnset( tx_info3, MUIA_Text_Contents, "Found your node!" );
	}
	else
	{
		/*
		**	Not found. Inform the user.
		*/
		nnset( tx_info3, MUIA_Text_Contents, "NOT found specified node!" );
	}

	return( 0 );
}
MakeStaticHook(findnamehook, findnamefunc);

/*
**	Sort the active list.
*/
HOOKPROTONHNP(sortfunc, LONG, Object *obj)
{
	clock_t start, end;
	LONG lastactive = 0;

	get( obj, MUIA_NListtree_Active, &lastactive );
	set( obj, MUIA_NListtree_Active, MUIV_NListtree_Active_Off );

	start = clock();
	DoMethod( obj, MUIM_NListtree_Sort, lastactive, 0 );
	end = clock();

	set( obj, MUIA_NListtree_Active, lastactive );

	DoMethod( tx_info3, MUIM_SetAsString, MUIA_Text_Contents, "Sort took %ld.%03lds", ( end - start ) / CLOCKS_PER_SEC, ( end - start ) % CLOCKS_PER_SEC );

	return( 0 );
}
MakeStaticHook(sorthook, sortfunc);

/*
**	Find the specified tree node by name.
*/
HOOKPROTONHNP(getnrfunc, LONG, Object *obj)
{
	LONG temp, temp2;

	temp = DoMethod( obj, MUIM_NListtree_GetNr,
		MUIV_NListtree_GetNr_TreeNode_Active, MUIV_NListtree_GetNr_Flag_CountLevel );

	if ( temp == 1 )
		DoMethod( tx_info1, MUIM_SetAsString, MUIA_Text_Contents, "1 entry in parent node." );
	else
		DoMethod( tx_info1, MUIM_SetAsString, MUIA_Text_Contents, "%ld entries in parent node.", temp );

	temp = DoMethod( obj, MUIM_NListtree_GetNr,
		MUIV_NListtree_GetNr_TreeNode_Active, MUIV_NListtree_GetNr_Flag_CountAll );

	if ( temp == 1 )
		DoMethod( tx_info2, MUIM_SetAsString, MUIA_Text_Contents, "1 entry total." );
	else
		DoMethod( tx_info2, MUIM_SetAsString, MUIA_Text_Contents, "%ld entries total.", temp );

	temp = DoMethod( obj, MUIM_NListtree_GetNr,
		MUIV_NListtree_GetNr_TreeNode_Active, 0 );

	temp2 = DoMethod( obj, MUIM_NListtree_GetNr,
		MUIV_NListtree_GetNr_TreeNode_Active, MUIV_NListtree_GetNr_Flag_Visible );

	DoMethod( tx_info3, MUIM_SetAsString, MUIA_Text_Contents, "Active entry pos: %ld (visible: %ld).", temp, temp2 );

	return( 0 );
}
MakeStaticHook(getnrhook, getnrfunc);

/*
**	Find the specified tree node by name.
*/
HOOKPROTONHNP(numselfunc, LONG, Object *obj)
{
	LONG temp = 0;

	DoMethod( obj, MUIM_NListtree_Select, MUIV_NListtree_Select_All,
		MUIV_NListtree_Select_Ask, 0, &temp );

	if ( temp == 1 )
		DoMethod( tx_info1, MUIM_SetAsString, MUIA_Text_Contents, "1 node selected." );
	else
		DoMethod( tx_info1, MUIM_SetAsString, MUIA_Text_Contents, "%ld nodes selected.", temp );

	{
		struct MUI_NListtree_TreeNode *tn;

		tn = (struct MUI_NListtree_TreeNode *)MUIV_NListtree_NextSelected_Start;

		for (;;)
		{
			DoMethod( obj, MUIM_NListtree_NextSelected, &tn );

			if ( (IPTR)tn == (IPTR)MUIV_NListtree_NextSelected_End )
				break;

			D(bug( "Next TreeNode: 0x%08lx - %s\n", tn, tn->tn_Name ) );
		}

		D(bug( "\n" ) );

		tn = (struct MUI_NListtree_TreeNode *)MUIV_NListtree_PrevSelected_Start;

		for (;;)
		{
			DoMethod( obj, MUIM_NListtree_PrevSelected, &tn );

			if ( (IPTR)tn == (IPTR)MUIV_NListtree_PrevSelected_End )
				break;

			D(bug( "Prev TreeNode: 0x%08lx - %s\n", tn, tn->tn_Name ) );
		}
	}

	return( 0 );
}
MakeStaticHook(numselhook, numselfunc);

/*
**	Test func
*/
HOOKPROTONHNP(testfunc, LONG, Object *obj)
{
	SIPTR id;
	ULONG num;

	id = MUIV_NListtree_NextSelected_Start;

	for(;;)
	{
		DoMethod( obj, MUIM_NListtree_NextSelected, &id );

		if(id == (SIPTR)MUIV_NListtree_NextSelected_End )
			break;

		//GetAttr( MUIA_List_Entries, obj, &num );

		num = DoMethod( obj, MUIM_NListtree_GetNr,
				MUIV_NListtree_GetNr_TreeNode_Active, MUIV_NListtree_GetNr_Flag_CountAll );

		if ( num > 1 )
			DoMethod( obj, MUIM_NListtree_Remove, MUIV_NListtree_Remove_ListNode_Active, id, 0 );
		else
			break;
	}

	return( 0 );
}
MakeStaticHook(testhook, testfunc);

#if defined(__amigaos4__)
#define GETINTERFACE(iface, base)	(iface = (APTR)GetInterface((struct Library *)(base), "main", 1L, NULL))
#define DROPINTERFACE(iface)			(DropInterface((struct Interface *)iface), iface = NULL)
#else
#define GETINTERFACE(iface, base)	TRUE
#define DROPINTERFACE(iface)
#endif

/*
**	Main
*/
int main(UNUSED int argc, UNUSED char *argv[])
{
	ULONG signals;
	static const char *const UsedClasses[] = { 
		"NList.mcc",
		"NListtree.mcc",
		"NListviews.mcc",
		NULL
	};

	/*
	**	Is MUI V19 available?
	*/
	if((IntuitionBase = (APTR)OpenLibrary("intuition.library", 36)) &&
		GETINTERFACE(IIntuition, IntuitionBase))
	if((MUIMasterBase = OpenLibrary("muimaster.library", 19)) &&
		GETINTERFACE(IMUIMaster, MUIMasterBase))
	{
		/*
		**	Create application object.
		*/
		app = ApplicationObject,
			MUIA_Application_Title,       "NListtree-Demo",
			MUIA_Application_Version,     "$VER: NListtree-Demo 1.0 (" __DATE__ ")",
			MUIA_Application_Copyright,   "Copyright (C) 2001-2006 by NList Open Source Team",
			MUIA_Application_Author,      "NList Open Source Team",
			MUIA_Application_Description, "Demonstration program for MUI class NListtree.mcc",
			MUIA_Application_Base,        "NLISTTREEDEMO",
			MUIA_Application_UsedClasses, UsedClasses,

			/*
			**	Build the window.
			*/
			SubWindow, window = WindowObject,
				MUIA_Window_Title,			"NListtree-Demo",
				MUIA_Window_ID,				MAKE_ID( 'N', 'L', 'T', 'R' ),
				MUIA_Window_AppWindow,		TRUE,
				WindowContents,				VGroup,

					/*
					**	Create a NListview embedded NListtree object
					*/
					Child, NListviewObject,
						MUIA_ShortHelp,			"The NListtree object...",
						MUIA_NListview_NList,	lt_nodes = NListtreeObject,
							InputListFrame,
							MUIA_CycleChain,				TRUE,
							MUIA_NList_MinLineHeight,		18,
							MUIA_NListtree_MultiSelect,		MUIV_NListtree_MultiSelect_Shifted,
							MUIA_NListtree_MultiTestHook,	&mthook,
							MUIA_NListtree_DisplayHook,		&dsphook,
							MUIA_NListtree_ConstructHook,	&conhook,
							MUIA_NListtree_DestructHook,	&deshook,	/* This is the same as MUIV_NListtree_CompareHook_LeavesMixed. */
							MUIA_NListtree_CompareHook,		&comphook,
							MUIA_NListtree_DoubleClick,		MUIV_NListtree_DoubleClick_Tree,
							MUIA_NListtree_EmptyNodes,		FALSE,
							MUIA_NListtree_TreeColumn,		0,
							MUIA_NListtree_DragDropSort,	TRUE,
							MUIA_NListtree_Title,			TRUE,
							MUIA_NListtree_Format,			",,",
							MUIA_NListtree_FindUserDataHook,&fudh,
							//MUIA_NListtree_NoRootTree,		TRUE,
						End,
					End,

					/*
					**	Build some controls.
					*/
					Child, tx_info1 = TextObject,
						MUIA_Background, MUII_TextBack,
						TextFrame,
					End,

					Child, tx_info2 = TextObject,
						MUIA_Background, MUII_TextBack,
						TextFrame,
					End,

					Child, tx_info3 = TextObject,
						MUIA_Background, MUII_TextBack,
						TextFrame,
					End,

					Child, ColGroup( 2 ),
						Child, FreeKeyLabel( "TreeCol:", 'c' ),
						Child, sl_treecol	= Slider( 0, 2, 0 ),
					End,

					Child, HGroup,
						Child, st_string = StringObject,
							StringFrame,
							MUIA_String_MaxLen, 50,
						End,
					End,

					Child, ColGroup( 4 ),
						Child, bt_open		= KeyButton( "Open",		'o' ),
						Child, bt_close		= KeyButton( "Close",		'c' ),
						Child, bt_expand	= KeyButton( "Expand",		'e' ),
						Child, bt_collapse	= KeyButton( "Collapse",	'a' ),

						Child, bt_insert	= KeyButton( "Insert",		'i' ),
						Child, bt_remove	= KeyButton( "Remove",		'r' ),
						Child, bt_exchange	= KeyButton( "Exchange",	'x' ),
						Child, bt_rename	= KeyButton( "Rename",		'r' ),

						Child, bt_move		= KeyButton( "Move",		'm' ),
						Child, bt_copy		= KeyButton( "Copy",		'y' ),
						Child, bt_moveks	= KeyButton( "Move KS",		'v' ),
						Child, bt_copyks	= KeyButton( "Copy KS",		'k' ),

						Child, bt_find		= KeyButton( "FindName",	'f' ),
						Child, bt_parent	= KeyButton( "Parent",		'p' ),
						Child, bt_sort		= KeyButton( "Sort",		's' ),
						Child, bt_getnr		= KeyButton( "GetNr",		'n' ),

						Child, bt_redraw	= KeyButton( "Redraw",		'w' ),
						Child, bt_selected	= KeyButton( "Selected",	'd' ),
						Child, bt_seltogg	= KeyButton( "Sel Togg",	't' ),
						Child, bt_showtree	= KeyButton( "Show tree",	'h' ),

						Child, bt_test		= KeyButton( "Test", ' ' ),
						Child, bt_test2		= KeyButton( "Test2", ' ' ),
						Child, bt_test3		= KeyButton( "Test3", ' ' ),
						Child, bt_test4		= KeyButton( "Test4", ' ' ),
					End,

				End,

			End,
		End;

		if( app )
		{
			/*
			**	generate notifications
			*/
			DoMethod( window, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
				app, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);

			/*
			**	open/close/expand/collapse
			*/
			DoMethod( bt_open, MUIM_Notify, MUIA_Pressed, FALSE,
				lt_nodes, 4, MUIM_NListtree_Open, MUIV_NListtree_Open_ListNode_Active, MUIV_NListtree_Open_TreeNode_Active, 0 );

			DoMethod( bt_close, MUIM_Notify, MUIA_Pressed, FALSE,
				lt_nodes, 4, MUIM_NListtree_Close, MUIV_NListtree_Close_ListNode_Active, MUIV_NListtree_Close_TreeNode_Active, 0 );

			DoMethod( bt_expand, MUIM_Notify, MUIA_Pressed, FALSE,
				lt_nodes, 4, MUIM_NListtree_Open, MUIV_NListtree_Open_ListNode_Root, MUIV_NListtree_Open_TreeNode_All, 0 );

			DoMethod( bt_collapse, MUIM_Notify, MUIA_Pressed, FALSE,
				lt_nodes, 4, MUIM_NListtree_Close, MUIV_NListtree_Close_ListNode_Root, MUIV_NListtree_Close_TreeNode_All, 0 );

			/*
			**	insert/remove/exchange/rename
			*/
			DoMethod( bt_insert, MUIM_Notify, MUIA_Pressed, FALSE,
				lt_nodes, 2, MUIM_CallHook, &inserthook );

			DoMethod( bt_remove, MUIM_Notify, MUIA_Pressed, FALSE,
				lt_nodes, 4, MUIM_NListtree_Remove, MUIV_NListtree_Remove_ListNode_Root, MUIV_NListtree_Remove_TreeNode_Selected, 0 );

			DoMethod( bt_exchange, MUIM_Notify, MUIA_Pressed, FALSE,
				lt_nodes, 3, MUIM_CallHook, &exchangehook, 42 );

			DoMethod( lt_nodes, MUIM_Notify, MUIA_NListtree_Active, MUIV_EveryTime,
				lt_nodes, 3, MUIM_CallHook, &exchangehook, 0 );

			DoMethod( bt_rename, MUIM_Notify, MUIA_Pressed, FALSE,
				lt_nodes, 2, MUIM_CallHook, &renamehook );

			/*
			**	move/copy/moveks/copyks
			*/
			DoMethod( bt_move, MUIM_Notify, MUIA_Pressed, FALSE,
				lt_nodes, 3, MUIM_CallHook, &movehook, 42 );

			DoMethod( lt_nodes, MUIM_Notify, MUIA_NListtree_Active, MUIV_EveryTime,
				lt_nodes, 3, MUIM_CallHook, &movehook, 0 );

			DoMethod( bt_copy, MUIM_Notify, MUIA_Pressed, FALSE,
				lt_nodes, 3, MUIM_CallHook, &copyhook, 42 );

			DoMethod( lt_nodes, MUIM_Notify, MUIA_NListtree_Active, MUIV_EveryTime,
				lt_nodes, 3, MUIM_CallHook, &copyhook, 0 );

			DoMethod( bt_moveks, MUIM_Notify, MUIA_Pressed, FALSE,
				lt_nodes, 3, MUIM_CallHook, &movekshook, 42 );

			DoMethod( lt_nodes, MUIM_Notify, MUIA_NListtree_Active, MUIV_EveryTime,
				lt_nodes, 3, MUIM_CallHook, &movekshook, 0 );

			DoMethod( bt_copyks, MUIM_Notify, MUIA_Pressed, FALSE,
				lt_nodes, 3, MUIM_CallHook, &copykshook, 42 );

			DoMethod( lt_nodes, MUIM_Notify, MUIA_NListtree_Active, MUIV_EveryTime,
				lt_nodes, 3, MUIM_CallHook, &copykshook, 0 );

			/*
			**	find/parent/sort/getnr
			*/
			DoMethod( bt_find, MUIM_Notify, MUIA_Pressed, FALSE,
				lt_nodes, 2, MUIM_CallHook, &findnamehook );

			DoMethod( bt_parent, MUIM_Notify, MUIA_Pressed, FALSE,
				lt_nodes, 3, MUIM_Set, MUIA_NListtree_Active, MUIV_NListtree_Active_Parent );

			DoMethod( bt_sort, MUIM_Notify, MUIA_Pressed, FALSE,
				lt_nodes, 2, MUIM_CallHook, &sorthook );

			/*
			DoMethod( bt_sort, MUIM_Notify, MUIA_Pressed, FALSE,
				lt_nodes, 3, MUIM_NListtree_Sort, MUIV_NListtree_Sort_TreeNode_Active, 0 );
			*/

			DoMethod( bt_getnr, MUIM_Notify, MUIA_Pressed, FALSE,
				lt_nodes, 2, MUIM_CallHook, &getnrhook );

			/*
			**	redraw/selected/seltogg/showtree
			*/
			DoMethod( bt_redraw, MUIM_Notify, MUIA_Pressed, FALSE,
				lt_nodes, 3, MUIM_NListtree_Redraw, MUIV_NListtree_Redraw_All );

			DoMethod( bt_selected, MUIM_Notify, MUIA_Pressed, FALSE,
				lt_nodes, 2, MUIM_CallHook, &numselhook );

			DoMethod( bt_seltogg, MUIM_Notify, MUIA_Pressed, FALSE,
				lt_nodes, 5, MUIM_NListtree_Select, MUIV_NListtree_Select_All, MUIV_NListtree_Select_Toggle, 0, NULL );

			DoMethod( bt_showtree, MUIM_Notify, MUIA_Pressed, FALSE,
				lt_nodes, 3, MUIM_Set, MUIA_NListtree_ShowTree, MUIV_NListtree_ShowTree_Toggle );

			/*
			**	misc
			*/
			DoMethod( sl_treecol, MUIM_Notify, MUIA_Slider_Level, MUIV_EveryTime,
				lt_nodes, 3, MUIM_Set, MUIA_NListtree_TreeColumn, MUIV_TriggerValue );

			DoMethod( lt_nodes, MUIM_Notify, MUIA_NListtree_Active, MUIV_EveryTime,
				tx_info1, 4, MUIM_SetAsString, MUIA_Text_Contents, "Active node: 0x%08lx", MUIV_TriggerValue );

			DoMethod( lt_nodes, MUIM_Notify, MUIA_NListtree_ActiveList, MUIV_EveryTime,
				tx_info2, 4, MUIM_SetAsString, MUIA_Text_Contents, "Active list: 0x%08lx", MUIV_TriggerValue );

			DoMethod( lt_nodes, MUIM_Notify, MUIA_NListtree_DoubleClick, MUIV_EveryTime,
				tx_info3, 4, MUIM_SetAsString, MUIA_Text_Contents, "Double clicked on node: 0x%08lx", MUIV_TriggerValue );

			DoMethod( lt_nodes, MUIM_Notify, MUIA_NListtree_SelectChange, TRUE,
				tx_info3, 3, MUIM_SetAsString, MUIA_Text_Contents, "Selection state changed" );

			/*
			**	test
			*/
			DoMethod( bt_test, MUIM_Notify, MUIA_Pressed, FALSE,
				lt_nodes, 2, MUIM_CallHook, &testhook );

			/*
			**	Open the window.
			**
			*/
			set( window, MUIA_Window_Open, TRUE );

			/*
			**	Set the tree into quiet state.
			*/
			set( lt_nodes, MUIA_NListtree_Quiet, TRUE );

			/*
			**	Insert sample nodes.
			*/
			DrawSampleTree( lt_nodes );

			/*
			**	Set the tree back to normal state.
			*/
			set( lt_nodes, MUIA_NListtree_Quiet, FALSE );

			/*
			**	Minimal input loop.
			*/
			while((LONG)DoMethod( app, MUIM_Application_NewInput, &signals ) != (LONG)MUIV_Application_ReturnID_Quit )
			{
				if ( signals )
				{
					signals = Wait( signals | SIGBREAKF_CTRL_C );

					if ( signals & SIGBREAKF_CTRL_C )
						break;
				}
			}

			/*
			**	Clear the list.
			*/
			DoMethod( lt_nodes, MUIM_NListtree_Clear, NULL, 0 );

			/*
			**	Close the window.
			*/
			set( window, MUIA_Window_Open, FALSE );

			/*
			**	Shutdown
			*/
			MUI_DisposeObject( app );
		}
		else
			printf( "Failed to create Application.\n" );
	}

	if(MUIMasterBase)
  {
    DROPINTERFACE(IMUIMaster);
		CloseLibrary(MUIMasterBase);
  }

	if(IntuitionBase)
  {
    DROPINTERFACE(IIntuition);
		CloseLibrary((struct Library *)IntuitionBase);
  }

	return( 0 );
}

NListview[edit | edit source]

NListview.mcc/NListview.mcc
NListview.mcc/MUIA_NListview_Horiz_ScrollBar
NListview.mcc/MUIA_NListview_HSB_Height
NListview.mcc/MUIA_NListview_NList
NListview.mcc/MUIA_NListview_Vert_ScrollBar
NListview.mcc/MUIA_NListview_VSB_Width
NListview.mcc/

That MCC public custom class give scrollers for a NList public custom class to make NList/NListview work near the same way as List/Listview. Most things that were handled by Listview are now handled by NList, so NListview is quite simple, anyway it's very easier to use NList with NListview than without.

Anyway, use NList without NListview if you don't want to get attached scrollers (or want to attach your own scrollers to NList - see Demo).

Note: NListview class can't use List as child but only NList, NFloattext, or a NList subclass, and NList class will not work with Listview without some conflict.

MUIA_NListview_Horiz_ScrollBar -- [ISG], Object *

    SPECIAL INPUTS
        MUIV_NListview_HSB_Always      1
        MUIV_NListview_HSB_Auto        2
        MUIV_NListview_HSB_FullAuto    3
        MUIV_NListview_HSB_None        4
        MUIV_NListview_HSB_Default     5

    SPECIAL SPECIAL INPUTS
        MUIV_NListview_HSB_On          0x0300
        MUIV_NListview_HSB_Off         0x0100

    FUNCTION
        With it you can tell if you want the scrollbar to be here
        always, never, automatic (not at start and appear forever if
        needed) or full automatic (appear and disappear when needed).

        Never is interesting if you want only one scrollbar of both
        or if you want to attach your own one only for one scrollbar.

        With Auto and FullAuto modes, scrollbars will not appear at
        first draw of the window. If you want it to appear when the
        window will be opened, you can set after creation time (not
        at init) MUIA_NListview_Horiz_ScrollBar
        to (MUIV_NListview_HSB_XXX|MUIV_NListview_HSB_On) where XXX
        is Default, FullAuto ...

        MUIV_NListview_HSB_On, MUIV_NListview_HSB_Off are used by the
        NList object to make scrollbars appear/disappear.

        The default is set by prefs. When prefs have not been set
        it is MUIV_NListview_HSB_Auto.

MUIA_NListview_HSB_Height -- [..G], LONG

    FUNCTION
        Return the height of the horizontal scrollbar.

        Return 0 when no horizontal scrollbar is visible.

MUIA_NListview_NList -- [I.G], Object *

    FUNCTION
        Same function as Listview.mui/MUIA_Listview_List.

        Every NListview needs a NList (or subclass) object as child.
        Specify it here.

        If none is specified, NListview will create a NList object
        as child, giving it the same taglist as itself.
        It's the only case where NList tags given to NListview will be
        taken into account.

        As every other child, it will be disposed of when its parent object is disposed.

MUIA_NListview_Vert_ScrollBar -- [ISG], Object *

    SPECIAL INPUTS
        MUIV_NListview_VSB_Always      1
        MUIV_NListview_VSB_Auto        2
        MUIV_NListview_VSB_FullAuto    3
        MUIV_NListview_VSB_None        4
        MUIV_NListview_VSB_Default     5
        MUIV_NListview_VSB_Left        6

    SPECIAL SPECIAL INPUTS
        MUIV_NListview_VSB_On          0x0030
        MUIV_NListview_VSB_Off         0x0010

    FUNCTION
        Same as MUIA_NListview_Horiz_ScrollBar but for vertical
        scrollbar.

        The default is set by prefs. When prefs have not been set
        it is MUIV_NListview_VSB_Always.

MUIA_NListview_VSB_Width -- [..G], LONG

    FUNCTION
        Return the width of the vertical scrollbar.

        Return 0 when no vertical scrollbar is visible.

    SEE ALSO
        MUIA_NListview_HSB_Height

NFloattext[edit | edit source]

NFloattext.mcc/NFloattext.mcc
NFloattext.mcc/MUIA_NFloattext_Align
NFloattext.mcc/MUIA_NFloattext_Justify
NFloattext.mcc/MUIA_NFloattext_SkipChars
NFloattext.mcc/MUIA_NFloattext_TabSize
NFloattext.mcc/MUIA_NFloattext_Text
NFloattext.mcc/MUIM_NFloattext_GetEntry

NFloattext class is a subclass of NList class that takes a big text string as input and splits it up into several lines to be displayed. Formatting capabilities include paragraphs an justified text with word wrap. That MCC public custom class  work near the same way as Floattext.

All you can do with NFloattext can be done directly using NList and its word wrap capabilities. NFloattext is here to give easy use and transition from Floattext.

Now NList package provide a Floattext.mui replacement which use directly this class. Unfortunately the replacement Floattext.mui have to have the same major release number than original Floattext.mui to be accepted by MUI, so it will have to be update with each new MUI release.

By default, MUIA_NList_Input is FALSE and MUIA_NList_TypeSelect is MUIV_NList_TypeSelect_Char, allowing char selection and copy to clipboard. If MUIA_NList_Input is set to TRUE, then MUIA_NList_TypeSelect default to MUIV_NList_TypeSelect_Line as usual.

NFloattext does not copy the string text, so it needs to copy the string line to a buffer when you do a MUIM_NFloattext_GetEntry or MUIM_List_GetEntry, so the return pointer will be invalid after next GetEntry call (the new one will be valid of course).

Using the old MUIA_Floattext_Text from standard Floatext class instead of MUIA_NFloattext_Text will make NFloattext copy the text like in Floattext class.

Note that MUIM_NList_GetEntry work as describe in NList, so as NFloattext use word wrap entries, you should use better MUIM_NFloattext_GetEntry or MUIM_List_GetEntry. Or use MUIM_NList_GetEntryInfo and MUIM_NList_GetEntry.

MUIA_NFloattext_Align -- [ISG], LONG

    SPECIAL INPUTS
        ALIGN_LEFT
        ALIGN_CENTER
        ALIGN_RIGHT
        ALIGN_JUSTIFY

    FUNCTION
        Indicate what alignment you want.
        It can be done with an escape alignment sequence
        in the Format preparse string or in the text string
        (for each linefeed separated lines) itself.

        setting it will set MUIA_NFloattext_Justify to
        TRUE if ALIGN_JUSTIFY, else to FALSE.

MUIA_NFloattext_Justify -- [ISG], BOOL

    FUNCTION
        Same as Floattext.mui/MUIA_Floattext_Justify.

        if TRUE, MUIA_NFloattext_Align will be set to
        ALIGN_JUSTIFY, else to ALIGN_LEFT.

MUIA_NFloattext_SkipChars -- [ISG], char *

    FUNCTION
        Same as NList.mcc/MUIA_NList_SkipChars
        and Floattext.mui/MUIA_Floattext_SkipChars.

MUIA_NFloattext_TabSize -- [ISG], LONG

    FUNCTION
        Same as NList.mcc/MUIA_NList_TabSize
        and Floattext.mui/MUIA_Floattext_TabSize.

        Tab size defaults to 8.

MUIA_NFloattext_Text -- [ISG], STRPTR

    FUNCTION
        Same as Floattext.mui/MUIA_Floattext_Text.

        String of characters to be displayed as floattext.
        This string may contain linefeeds or carriage returns to mark
        the end of paragraphs or tab characters for indention.

        NFloattext will automatically format the text according
        to the width of the NFloattext object. If a word
        won't fit into the current line, it will be wrapped.

        NFloattext don't copies the string into a private buffer
        as Floattext do it, so you need to keep your text in
        memory, but it uses less memory.

        If you want NFloattext to copy the text, just use
        MUIA_Floattext_Text which will do it for compatibility.

        Setting MUIA_NFloattext_Text to NULL means to clear
        the current text.

        Please note that justification and word wrap is a
        complicated operation and may take a considerable
        amount of time, especially with long texts on slow
        machines.

MUIM_NFloattext_GetEntry --

    SYNOPSIS
        DoMethod(obj,MUIM_NFloattext_GetEntry,LONG pos, APTR *entry);

    FUNCTION
        Same function as List.mui/MUIM_List_GetEntry.

        You'll get pointer to a null terminated string buffer which
        is a copy of the asked visible entry.

        Unlike with Floattext, the returned string will be valid only
        until next MUIM_NFloattext_GetEntry/MUIM_List_GetEntry call
        if the entry was word wrapped.
        I'll try to make it stay valid when using MUIM_List_GetEntry
        only if someone report me some compatibility problem because
        doing that will use more memory.

NBalance[edit | edit source]

NBalance.mcc/NBalance.mcc
NBalance.mcc/MUIA_NBalance_Pointer
This MCC public custom class is derived from the MUI standard balance class which handles the dragging/resizing of vertical and horizontal groups.

In contrast to the standard MUI balance class, however, it adds some features such as displaying a mouse pointer as soon as the mouse is above a dragable NBalance object.

MUIA_NBalance_Pointer -- [ISG.], LONG

    INPUTS
        MUIV_NBalance_Pointer_Off
        MUIV_NBalance_Pointer_Standard (default)

    FUNCTION
        Allows to set the mouse pointer that should be displayed when
        the mouse is found to be above a NBalance object. Per default
        a standard horizontal or vertical size pointer is displayed as
        soon as the mouse is above a dragable NBalance object.

NBitmap[edit | edit source]

Creating a custom class[edit | edit source]

Most likely, when creating a custom class, the existing classes functionality will be extended, like providing a new appearance, handling keys, etc. Zune provides an interface to do so. The newly created class can be "private" to your application, or "public" and thus available to other applications like any existing (built-in or public custom) class.

To create you own custom class...

available on Aminet - look for DisKo

If you want to make your new custom class publicly available, e. g. to be included in AROS, it is necessary to register a class base address / class ID - to avoid conflicts with other developers developing a public custom class.

Typical MCC[edit | edit source]

#include "system.h"
#include "MCCname_mcc.h"
#include "MCCname_mcp.h"
#include <proto/date.h>
#include <proto/utility.h>
#include <proto/intuition.h>
#include <dos/dos.h>
#include <proto/dos.h>
#include <libraries/locale.h>
#include <proto/locale.h>
#include <libraries/mui.h>
#include <proto/muimaster.h>

#define CLASS			MUIC_?
#define SUPERCLASS		MUIC_?
#define VERSION		        number
#define REVISION		0
#define VERSIONSTR	        "number"
#define AUTHOR			"name"
#define COPYRIGHT		"year"
#define EXPORT_IMPORT_VERSION	1

/* further defines if needed */

Example[edit | edit source]

/*
**       $Filename: ZuneARC.c $
**       $Release: 1 $
**       $Revision: 1.3 $
**       $Date: 20/05/2010 $
**
**       (C) Copyright 2009, 2010 Yannick Erb
**       AROS Public License
*/

/*----------------------------------------------------------------------------*/
/*    Main include                                                            */
/*----------------------------------------------------------------------------*/

#include "ZuneARC.h"

/*----------------------------------------------------------------------------*/
/*    Menu                                                                    */
/*----------------------------------------------------------------------------*/

#define NMABOUT_ID 200L
#define NMCONF_ID 201L
struct NewMenu Menu[] =
{
   {NM_TITLE, "Project"           ,   0,0,0,(APTR)0},
   {NM_ITEM , "About..."          , "?",0,0,(APTR)NMABOUT_ID},
   {NM_ITEM , "Edit Configuration", "C",0,0,(APTR)NMCONF_ID},
   {NM_ITEM , NM_BARLABEL         ,   0,0,0,(APTR)0},
   {NM_ITEM , "QUIT"              , "Q",0,0,(APTR)MUIV_Application_ReturnID_Quit},
   {NM_END  , NULL                ,   0,0,0,(APTR)0},
};

/*----------------------------------------------------------------------------*/
/*    Main program                                                            */
/*----------------------------------------------------------------------------*/

int main(int argc, char **argv)
{

BOOL Running = TRUE;
ULONG Signals;
char *CurrentArcName;
   
   if (MUIMasterBase = OpenLibrary("muimaster.library", MUIMASTER_VMIN))
   {
      if (MakeMUIApp())
      {

         CurrentArcName = malloc(256+1);
         strncpy(CurrentArcName,"",256);
         set(Win, MUIA_Window_Open, TRUE);
         strncpy(CurrentArcName,"",256);
         
         set(Button2,MUIA_Disabled,TRUE);
         set(Button3,MUIA_Disabled,TRUE);
         set(Button4,MUIA_Disabled,TRUE);
         set(Button5,MUIA_Disabled,TRUE);
         
         // Read the configuration file 
         if (readconf())
         {
            MUI_Request(App,Win,0,"Error message","OK",
                        "Error in Configuration file",
                        TAG_DONE);            
            exit(1);
         }

         if (argc>1)
         {
            // started from Shell with an argument
            strcpy(CurrentArcName,argv[1]);
         }
         else if(argc == 0)
         {
            // started from WB
            struct WBStartup *wbmsg;
            struct WBArg *wbarg;

            wbmsg = (struct WBStartup *)argv;
            wbarg = wbmsg->sm_ArgList;
            
            wbarg++; // We only want to now the Name and Path of first parameter
            
            if ( (wbmsg->sm_NumArgs>1) && (wbarg->wa_Lock) && (*wbarg->wa_Name) )
            {
               NameFromLock(wbarg->wa_Lock,CurrentArcName,256);
               AddPart(CurrentArcName,wbarg->wa_Name,256);
            }
         }
         
         if (strcmp(CurrentArcName,"")!=0)
         {    
            set(ArcName,MUIA_Text_Contents,CurrentArcName);
            DoMethod(ArcList,MUIM_NList_Clear);
            if((ArcType = ArchiveType(CurrentArcName))<NbType)
            { 
               ReadArchiveContent(CurrentArcName);
               if (strncmp(archivers[arctypes[ArcType].Archiver].ExtractSingle,"#",1)==0)
                   set(Button2,MUIA_Disabled,TRUE);
               else set(Button2,MUIA_Disabled,FALSE);
               if (strncmp(archivers[arctypes[ArcType].Archiver].ExtractAll,"#",1)==0)
                   set(Button3,MUIA_Disabled,TRUE);
               else set(Button3,MUIA_Disabled,FALSE);
               if (strncmp(archivers[arctypes[ArcType].Archiver].Remove,"#",1)==0)
                   set(Button4,MUIA_Disabled,TRUE);
               else set(Button4,MUIA_Disabled,FALSE);                                          
               if (strncmp(archivers[arctypes[ArcType].Archiver].Add,"#",1)==0)
                   set(Button5,MUIA_Disabled,TRUE);
               else set(Button5,MUIA_Disabled,FALSE);
            }
            else
            {
               if (strcmp(CurrentArcName,"")!=0)
                  MUI_Request(App,Win,0,"Error message","OK",
                              strcat(CurrentArcName,"\nis not a known archive type"),
                              TAG_DONE);
               set(ArcName,MUIA_Text_Contents,"");
               set(Button2,MUIA_Disabled,TRUE);
               set(Button3,MUIA_Disabled,TRUE);
               set(Button4,MUIA_Disabled,TRUE);
               set(Button5,MUIA_Disabled,TRUE);
            }         
         }

         while (Running)
         {
            switch(DoMethod(App, MUIM_Application_Input, &Signals))
            {
               case MUIV_Application_ReturnID_Quit:
                  Running = FALSE;                          /* break the loop */
                  break;

               case NMCONF_ID:
                  Execute("SYS:Tools/Editor ZuneARC.cfg",NULL,NULL);
                  MUI_Request(App,Win,0,"Configuration file change","OK",
                              "In order to make the configuration change effective\nyou have to quit and restart ZuneARC",
                              TAG_DONE);                   
                  break;
                  
               case NMABOUT_ID:
                  MUI_Request(App,Win,0,"About...","OK",
                              "\33cZuneARC\nVersion 1.3\n\nYannick Erb\nMay. 2010",
                              TAG_DONE);                  
                  break;
                  
               case EXTSEL:
                  ExtractSelected(CurrentArcName);
                  break;

               case EXTALL:
                  ExtractAll(CurrentArcName);
                  break;
               
               case DELSEL:
                  RemoveSelected(CurrentArcName);
                  DoMethod(ArcList,MUIM_NList_Clear);
                  ReadArchiveContent(CurrentArcName);
                  break;

               case ADDFIL:
                  AddFile(CurrentArcName);
                  DoMethod(ArcList,MUIM_NList_Clear);
                  ReadArchiveContent(CurrentArcName);
                  break;
                  
               case CREATE:              
                  strcpy(CurrentArcName,CreateArchive());
                  set(ArcName,MUIA_Text_Contents,CurrentArcName);
                  DoMethod(ArcList,MUIM_NList_Clear);
                  if((ArcType = ArchiveType(CurrentArcName))<NbType)
                  { 
                     ReadArchiveContent(CurrentArcName);
                     if (strncmp(archivers[arctypes[ArcType].Archiver].ExtractSingle,"#",1)==0)
                         set(Button2,MUIA_Disabled,TRUE);
                     else set(Button2,MUIA_Disabled,FALSE);
                     if (strncmp(archivers[arctypes[ArcType].Archiver].ExtractAll,"#",1)==0)
                         set(Button3,MUIA_Disabled,TRUE);
                     else set(Button3,MUIA_Disabled,FALSE);
                     if (strncmp(archivers[arctypes[ArcType].Archiver].Remove,"#",1)==0)
                         set(Button4,MUIA_Disabled,TRUE);
                     else set(Button4,MUIA_Disabled,FALSE);                                          
                     if (strncmp(archivers[arctypes[ArcType].Archiver].Add,"#",1)==0)
                         set(Button5,MUIA_Disabled,TRUE);
                     else set(Button5,MUIA_Disabled,FALSE);
                  }
                  else
                  {
                     if (strcmp(CurrentArcName,"")!=0)
                        MUI_Request(App,Win,0,"Error message","OK",
                                    strcat(CurrentArcName,"\nis not a known archive type"),
                                    TAG_DONE);
                     set(ArcName,MUIA_String_Contents,"");
                     set(Button2,MUIA_Disabled,TRUE);
                     set(Button3,MUIA_Disabled,TRUE);
                     set(Button4,MUIA_Disabled,TRUE);
                     set(Button5,MUIA_Disabled,TRUE);
                  }
                  break;
                  
               case OPENID:
                  strcpy(CurrentArcName,getfilename(Win,"Select Archive to Open",FALSE,FALSE,"#?","SYS:"));
                  set(ArcName,MUIA_Text_Contents,CurrentArcName);
                  DoMethod(ArcList,MUIM_NList_Clear);
                  if((ArcType = ArchiveType(CurrentArcName))<NbType)
                  { 
                     ReadArchiveContent(CurrentArcName);
                     if (strncmp(archivers[arctypes[ArcType].Archiver].ExtractSingle,"#",1)==0)
                         set(Button2,MUIA_Disabled,TRUE);
                     else set(Button2,MUIA_Disabled,FALSE);
                     if (strncmp(archivers[arctypes[ArcType].Archiver].ExtractAll,"#",1)==0)
                         set(Button3,MUIA_Disabled,TRUE);
                     else set(Button3,MUIA_Disabled,FALSE);
                     if (strncmp(archivers[arctypes[ArcType].Archiver].Remove,"#",1)==0)
                         set(Button4,MUIA_Disabled,TRUE);
                     else set(Button4,MUIA_Disabled,FALSE);                                          
                     if (strncmp(archivers[arctypes[ArcType].Archiver].Add,"#",1)==0)
                         set(Button5,MUIA_Disabled,TRUE);
                     else set(Button5,MUIA_Disabled,FALSE);
                  }
                  else
                  {
                     if (strcmp(CurrentArcName,"")!=0)
                        MUI_Request(App,Win,0,"Error message","OK",
                                    strcat(CurrentArcName,"\nis not a known archive type"),
                                    TAG_DONE);
                     set(ArcName,MUIA_Text_Contents,"");
                     set(Button2,MUIA_Disabled,TRUE);
                     set(Button3,MUIA_Disabled,TRUE);
                     set(Button4,MUIA_Disabled,TRUE);
                     set(Button5,MUIA_Disabled,TRUE);
                  }
                  break;
               
               default:
                  break; 
            }
            if (Running && Signals) Wait(Signals);
         }
         set(Win, MUIA_Window_Open, FALSE);

         MUI_DisposeObject(App);
      }
      CloseLibrary(MUIMasterBase);
   }
   return(0);
}

/*----------------------------------------------------------------------------*/
/*    MakeMUIApp - creates the user interface                                 */
/*----------------------------------------------------------------------------*/

static BOOL MakeMUIApp(void)
{

static struct Hook ListConstructHook;
static struct Hook ListDestructHook;
static struct Hook ListDisplayHook;
static struct Hook VListConstructHook;
static struct Hook VListDestructHook;
static struct Hook VListDisplayHook;
ListConstructHook.h_Entry = (HOOKFUNC)ListConst;
ListDestructHook.h_Entry = (HOOKFUNC)ListDest;
ListDisplayHook.h_Entry = (HOOKFUNC)ListDispl;
VListConstructHook.h_Entry = (HOOKFUNC)VListConst;
VListDestructHook.h_Entry = (HOOKFUNC)VListDest;
VListDisplayHook.h_Entry = (HOOKFUNC)VListDispl;

   if (!(App = ApplicationObject,
      MUIA_Application_Title,       "ZuneARC",
      MUIA_Application_Version,     "$VER: ZuneARC 1.3 (20.05.10)",
      MUIA_Application_Copyright,   "© 2009 Yannick Erb",
      MUIA_Application_Author,      "Yannick Erb",
      MUIA_Application_Description, "Zune Archivers Front-End",
      MUIA_Application_Base,        "ZARCC",
      MUIA_Application_Menustrip,   MUI_MakeObject(MUIO_MenustripNM,Menu,0),

      SubWindow, Win = WindowObject,
         MUIA_Window_Title, "ZuneARC",
         MUIA_Window_ID, MAKEID('Z','A','R','C'),
         MUIA_Window_Width , MUIV_Window_Width_Screen(50),
         MUIA_Window_Height, MUIV_Window_Height_Screen(50),

         WindowContents, VGroup,
            Child, HGroup, 
               MUIA_Group_Spacing, 20, 
               MUIA_Group_SameWidth, TRUE,
               Child, VGroup,
                  Child, Button0 = MakeButton("PROGDIR:Icons/Open.png", 'o', "\33uO\33npen Archive"),
                  Child, KeyLabel2("\33c\33uO\33npen",'\0'),
               End,            
               Child, VGroup,
                  Child, Button1 = MakeButton("PROGDIR:Icons/Create.png", 'c', "\33uC\33nreate New Archive"),
                  Child, KeyLabel2("\33c\33uC\33nreate New",'\0'),
               End,
               Child, VGroup,
                  Child, Button2 = MakeButton("PROGDIR:Icons/ExtractSel.png", 's',"Extract \33uS\33nelected"),
                  Child, KeyLabel2("\33cExtract \33uS\33nel.",'\0'),
               End,
                Child, VGroup,
                  Child, Button3 = MakeButton("PROGDIR:Icons/ExtractALL.png", 'e',"\33uE\33nxtract All"),
                  Child, KeyLabel2("\33c\33uE\33nxtract All",'\0'),
               End,
                Child, VGroup,
                  Child, Button4 = MakeButton("PROGDIR:Icons/Remove.png", 'r',"\33uR\33nemove files from archive"),
                  Child, KeyLabel2("\33c\33uR\33nemove Sel.",'\0'),
               End,
                Child,VGroup,
                  Child, Button5 = MakeButton("PROGDIR:Icons/Add.png", 'a',"\33uA\33ndd files to archive"),
                  Child, KeyLabel2("\33c\33uA\33ndd files",'\0'),
               End,        
               Child, RectangleObject, End,
            End,

            Child, BalanceObject, End,
          
            Child, HGroup, MUIA_Group_SameHeight, TRUE,  
               Child, KeyLabel2(" Archive :",'\0'),
               Child, ArcName = TextObject,
                         MUIA_Frame, MUIV_Frame_Text,
	       End,
            End,   
           
            Child, NListviewObject,      
               MUIA_NListview_NList, ArcList = NListObject,
                  MUIA_NList_MultiSelect, MUIV_NList_MultiSelect_Default,
                  MUIA_NList_ConstructHook, (IPTR)&ListConstructHook,
                  MUIA_NList_DestructHook, (IPTR)&ListDestructHook,
                  MUIA_NList_DisplayHook, (IPTR)&ListDisplayHook,
                  MUIA_NList_Format, "BAR,P=\33r BAR,P=\33r BAR,BAR",
                  MUIA_NList_Title, TRUE,
               End,
            End,

            Child, BalanceObject, End,
                        
            Child, cmdtext = GaugeObject,
                    MUIA_Gauge_Horiz, TRUE,
                    MUIA_FixHeightTxt, " ",
                    MUIA_Frame, MUIV_Frame_Gauge,
            End,
            
         End,
      End, 
      
      SubWindow, SelAdd = WindowObject,
         MUIA_Window_Title, "Select files to ADD",
         MUIA_Window_ID, MAKEID('Z','A','R','1'),
         MUIA_Window_Width , MUIV_Window_Width_Screen(50),
         MUIA_Window_Height, MUIV_Window_Height_Screen(50),

         WindowContents, VGroup,
            Child, HGroup,
               Child, VGroup,
                  Child, HGroup,
                     Child, KeyLabel2("Base Directory :",'\0'),
                     Child, SelAdd_CD = TextObject,
                        MUIA_Frame, MUIV_Frame_Text,
                     End,   
                  End,
               
                  Child, HGroup,
                     Child, NListviewObject,
                        MUIA_Weight, 30,
                        MUIA_NListview_NList, SelAdd_VolList = NListObject,
                           MUIA_NList_ConstructHook, (IPTR)&VListConstructHook,
                           MUIA_NList_DestructHook, (IPTR)&VListDestructHook,
                           MUIA_NList_DisplayHook, (IPTR)&VListDisplayHook,
                           MUIA_Frame, MUIV_Frame_InputList,             
                        End,   
                     End,
                     Child, ListviewObject,
                        MUIA_Listview_List, SelAdd_DirList = DirlistObject,
                           MUIA_Dirlist_Directory, "",
                           MUIA_Dirlist_DrawersOnly, TRUE,
                           MUIA_Frame, MUIV_Frame_InputList,           
                        End,   
                     End,
                  End,
               End,   
             
               Child, NListviewObject,      
                  MUIA_NListview_NList, SelAdd_List = NListObject,
                     MUIA_NList_MultiSelect, MUIV_NList_MultiSelect_Default,
                     MUIA_NList_ConstructHook, (IPTR)&ListConstructHook,
                     MUIA_NList_DestructHook, (IPTR)&ListDestructHook,
                     MUIA_NList_DisplayHook, (IPTR)&ListDisplayHook,
                     MUIA_NList_Format, "COL=0 BAR,COL=1 P=\33r BAR,COL=3 BAR",
                     MUIA_NList_Title, TRUE,
                  End,
               End,
            End,   
            Child, HGroup, 
               MUIA_Group_Spacing, 50, 
               MUIA_Group_SameWidth, TRUE,
               Child, SelAdd_OK     = CoolImageIDButton("ARCHIVE",COOL_SAVEIMAGE_ID),
               Child, SelAdd_PAR    = CoolImageIDButton("PARENT",COOL_SWITCHIMAGE_ID),
               Child, SelAdd_CANCEL = CoolImageIDButton("CANCEL",COOL_CANCELIMAGE_ID),
            End,
         End,
      End, 
   End)) return(FALSE);

   /* the 'end program' flag */

   DoMethod(Win, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
      App, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
      
   /* Buttons that are handled by the main event loop */

   DoMethod(Button0, MUIM_Notify, MUIA_Pressed, FALSE,
      App, 2, MUIM_Application_ReturnID, OPENID);

   DoMethod(Button1, MUIM_Notify, MUIA_Pressed, FALSE,
      App, 2, MUIM_Application_ReturnID, CREATE);

   DoMethod(Button2, MUIM_Notify, MUIA_Pressed, FALSE,
      App, 2, MUIM_Application_ReturnID, EXTSEL);

   DoMethod(Button3, MUIM_Notify, MUIA_Pressed, FALSE,
      App, 2, MUIM_Application_ReturnID, EXTALL);

   DoMethod(Button4, MUIM_Notify, MUIA_Pressed, FALSE,
      App, 2, MUIM_Application_ReturnID, DELSEL);

   DoMethod(Button5, MUIM_Notify, MUIA_Pressed, FALSE,
      App, 2, MUIM_Application_ReturnID, ADDFIL);

   /* PopASL, archive changed event.*/

   DoMethod(ArcName, MUIM_Notify, MUIA_Popasl_Active, FALSE,
      App, 2, MUIM_Application_ReturnID, NEWARC);
   
   /* Events from the SelAdd window */
      
   DoMethod(SelAdd, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
      App, 2, MUIM_Application_ReturnID, QUITSELADD);
   
   DoMethod(SelAdd_CANCEL, MUIM_Notify, MUIA_Pressed, FALSE,
      App, 2, MUIM_Application_ReturnID, QUITSELADD);
      
   DoMethod(SelAdd_OK, MUIM_Notify, MUIA_Pressed, FALSE,
      App, 2, MUIM_Application_ReturnID, SELADDOK);

   DoMethod(SelAdd_List, MUIM_Notify, MUIA_Listview_DoubleClick, TRUE,
      App, 2, MUIM_Application_ReturnID, SELADDDC);

   DoMethod(SelAdd_VolList, MUIM_Notify, MUIA_Listview_DoubleClick, TRUE,
      App, 2, MUIM_Application_ReturnID, SELADDVOLL);
      
   DoMethod(SelAdd_DirList, MUIM_Notify, MUIA_Listview_DoubleClick, TRUE,
      App, 2, MUIM_Application_ReturnID, SELADDDIRL);

   DoMethod(SelAdd_PAR, MUIM_Notify, MUIA_Pressed, FALSE,
      App, 2, MUIM_Application_ReturnID, SELADDPAR);
   return(TRUE);
}

/*----------------------------------------------------------------------------*/
/*    MakeButton                                                              */
/*----------------------------------------------------------------------------*/

static APTR MakeButton(UBYTE *Image, UBYTE Key, UBYTE *Help)
{
   return(MUI_NewObject("Dtpic.mui",
                        MUIA_Dtpic_Name,Image,
                        MUIA_InputMode, MUIV_InputMode_RelVerify,
                        MUIA_ControlChar, Key,
                        MUIA_Background, MUII_ButtonBack,
                        MUIA_ShortHelp, Help,
                        ImageButtonFrame,
                        TAG_DONE));
}

/*----------------------------------------------------------------------------*/
/*    List construct Hook                                                     */
/*----------------------------------------------------------------------------*/

AROS_UFH3(APTR, ListConst,
  AROS_UFHA(struct Hook *, h, A0),
  AROS_UFHA(APTR, pool, A2),
  AROS_UFHA(struct FileRecord *, entry, A1));
{
   AROS_USERFUNC_INIT
   
   struct FileRecord *new;
   if (new=AllocPooled(pool,sizeof(struct FileRecord))) 
   {
      *new = *entry;
   }      
   return(new);
   
   AROS_USERFUNC_EXIT
}
  
/*----------------------------------------------------------------------------*/
/*    List destruct Hook                                                      */
/*----------------------------------------------------------------------------*/

AROS_UFH3(void, ListDest,
  AROS_UFHA(struct Hook *, h, A0),
  AROS_UFHA(APTR, pool, A2),
  AROS_UFHA(struct FileRecord *, entry, A1));
{
   AROS_USERFUNC_INIT
   
   FreePooled(pool, entry, sizeof(struct FileRecord));

   AROS_USERFUNC_EXIT
}

/*----------------------------------------------------------------------------*/
/*    List display Hook                                                       */
/*----------------------------------------------------------------------------*/

AROS_UFH3(LONG, ListDispl,
  AROS_UFHA(struct Hook *, h, A0),
  AROS_UFHA(char **, array, A2),
  AROS_UFHA(struct FileRecord *, entry, A1))
{
   AROS_USERFUNC_INIT
   
   static char buf1[256],buf2[16],buf3[16],buf4[64];
   
   strcpy(buf1,"\33b");
   strcpy(buf2,"\33b");
   strcpy(buf3,"\33b");
   strcpy(buf4,"\33b");

   if(entry)
   {  
      if (strcmp(entry->Size,"DIR")==0)
      {
         *array++ = strcat(buf1,entry->Name);
         *array++ = strcat(buf2,entry->Size);
         *array++ = strcat(buf3,entry->CSize);
         *array   = strcat(buf4,entry->Date);
      }
      else
      {
         *array++ = entry->Name;
         *array++ = entry->Size;
         *array++ = entry->CSize;
         *array   = entry->Date;
      }
   }
   else
   {
      *array++ = "Name";
      *array++ = "File Size";
      *array++ = "Arch Size";
      *array   = "Date";
   }

   return(0);
   
   AROS_USERFUNC_EXIT
}

/*----------------------------------------------------------------------------*/
/*    VList construct Hook                                                    */
/*----------------------------------------------------------------------------*/

AROS_UFH3(APTR, VListConst,
  AROS_UFHA(struct Hook *, h, A0),
  AROS_UFHA(APTR, pool, A2),
  AROS_UFHA(char *, entry, A1));
{
   AROS_USERFUNC_INIT
   
   char *new;
   if (new=AllocPooled(pool,32)) 
   {
      strcpy(new,entry);
   }      
   return(new);
   
   AROS_USERFUNC_EXIT
}
  
/*----------------------------------------------------------------------------*/
/*    VList destruct Hook                                                     */
/*----------------------------------------------------------------------------*/

AROS_UFH3(void, VListDest,
  AROS_UFHA(struct Hook *, h, A0),
  AROS_UFHA(APTR, pool, A2),
  AROS_UFHA(char *, entry, A1));
{
   AROS_USERFUNC_INIT
   
   FreePooled(pool, entry, 32);

   AROS_USERFUNC_EXIT
}

/*----------------------------------------------------------------------------*/
/*    VList display Hook                                                      */
/*----------------------------------------------------------------------------*/

AROS_UFH3(LONG, VListDispl,
  AROS_UFHA(struct Hook *, h, A0),
  AROS_UFHA(char **, array, A2),
  AROS_UFHA(char *, entry, A1))
{
   AROS_USERFUNC_INIT

   if (entry)
   {      
      strcpy(*array,entry);
   }
   else
   {
      *array   = "Volume";
   }

   return(0);
   
   AROS_USERFUNC_EXIT
}

/*----------------------------------------------------------------------------*/
/*    int ArchiveType(char *ArcFile)                                          */
/*    Returns the Archive type of the file              		      */
/*----------------------------------------------------------------------------*/

int ArchiveType(char *ArcFile)
{
   int extlen, i, type = 0;
   
   while(type<NbType) 
   {
     extlen = strlen(arctypes[type].Extension);
     for(i=0;i<extlen;i++)
     {
        if (toupper(arctypes[type].Extension[i])!=toupper(ArcFile[strlen(ArcFile)-extlen+i])) break;
     }
     if (i==extlen) break;
     type++;
   }
   
   return(type);
}

/*----------------------------------------------------------------------------*/
/*    ReadArchiveContent(char *ArcFile)                                       */
/*    Reads the archive content and display it in the List		      */
/*----------------------------------------------------------------------------*/

void ReadArchiveContent(char *ArcFile)
{
   struct FileRecord rec;
   FILE *cf;
   char line[1024];
   char CurrentReading[512];
   int EntryType[30];
   int EntryMSpa[30];
   int NbLine = 0,CurrentLine = 0, NbEntriesContentLine = 0, i = 0, j = 0, k = 0;
   
   // clear display list
   DoMethod(ArcList,MUIM_NList_Clear);
   
   // generate tmp file containing the entries list
   Runextcmd(archivers[arctypes[ArcType].Archiver].ListContent,ArcFile,"","","",TRUE);
   
   // decode ContentFmt from config file (only first letter is kept)
   while(archivers[arctypes[ArcType].Archiver].ContentFmt[i] != '\0')
   {
      if(archivers[arctypes[ArcType].Archiver].ContentFmt[i++] == ' ')
      {
        EntryType[NbEntriesContentLine] = (int)archivers[arctypes[ArcType].Archiver].ContentFmt[i-5];
		EntryMSpa[NbEntriesContentLine] = atoi(&archivers[arctypes[ArcType].Archiver].ContentFmt[i-3]);
        NbEntriesContentLine++;
      }
   }   
   EntryType[NbEntriesContentLine] = (int)archivers[arctypes[ArcType].Archiver].ContentFmt[i-4];
   EntryMSpa[NbEntriesContentLine] = atoi(&archivers[arctypes[ArcType].Archiver].ContentFmt[i-2]);       
   
   // decode tmp file
   if((cf = fopen("T:ZuneARC.tmp","r"))!=NULL)
   {
      // count total number of line in file
      while(fgets(line,512,cf)!=NULL) NbLine++;
      rewind(cf);
	  
      while(fgets(line,512,cf)!=NULL)
      {
         CurrentLine++;
		 
         if((CurrentLine > archivers[arctypes[ArcType].Archiver].ContentHeader) // skip header
            && (CurrentLine < NbLine-archivers[arctypes[ArcType].Archiver].ContentFooter+1)) // and footer
         {
         
            strcpy(rec.Name,"");
            strcpy(rec.Size,"");
            strcpy(rec.CSize,"");
            strcpy(rec.Date,"");
            
            // Read entries
            j = 0;
            for(i=0;i<NbEntriesContentLine+1;i++)
            {
               k = 0;
			   // skip initial spaces and tabs
               while(line[j]==' ' || line[j]=='\t')
			   {
			     j++;
				 k++;
			   }
			   // if number of spaces (k) is bigger than the maximum allowed consecutive spaces than we're jumping to next entry
			   if (EntryMSpa[i] > 0 && k > EntryMSpa[i]) i++;			   
			   k = 0;
			   // read entry till space or tab or EOL encountered
               while(line[j]!=' ' && line[j]!='\t' && line[j]!='\0' && line[j]!='\n')
               {
                  CurrentReading[k++] = line[j++];
               }
               CurrentReading[k] = '\0';
                
               switch(EntryType[i])
               {
                  case 'N':
                     if(strcmp(rec.Name,"")!=0) strcat(rec.Name," ");
                     strcpy(rec.Name,strcat(rec.Name,CurrentReading));
                     break;

                  case 'C':
                     strcat(rec.CSize,CurrentReading);
                     break;
                     
                  case 'S':
                     strcat(rec.Size,CurrentReading);
                     break;
                     
                  case 'D':
                     if(strcmp(rec.Date,"")!=0) strcat(rec.Date," ");
                     strcat(rec.Date,CurrentReading);
                     break;

                  default:
                     break;
               }
            }
            if ((atoi(rec.Size)==0) && (rec.Name[strlen(rec.Name)-1]=='/')) 
            {
               strcpy(rec.Size,"DIR");
            }                   
            DoMethod(ArcList,MUIM_NList_InsertSingle,(IPTR)&rec, MUIV_NList_Insert_Bottom); 
         }
      }   
      fclose(cf);
      //DeleteFile("T:ZuneARC.tmp");
   }
   else
   {
      MUI_Request(App,Win,0,"Error message","OK",
         "Temporary file was not created\nthere is either an error in the archive\nor in configuration file.",
         TAG_DONE);
   }
}

/*-------------------------------------------------------------------------------------*/
/*    void Runextcmd(char * fmt,char *arch,char *file,char *dest, char *base,BOOL out) */
/*    Formats and run the external command string                     	               */
/*-------------------------------------------------------------------------------------*/

void Runextcmd(char * fmt,char *arch,char *file,char *dest, char *base, BOOL out)
{
   char cmd[1024];
   char tmp[512];
   char display[1024];
   int i = 0,j = 0;
   FILE *sf;
   
   strncpy(display,"\0332",1024);
   strncpy(cmd,"",1024);
   strncpy(tmp,"",512);
   
   sf = fopen("T:ZuneARC.script","w");
   
   while (fmt[i]!='\0')
   {
      if(fmt[i]==';')  // Command Section finished
      {
         i++;
         cmd[j] = '\0';
         if(out) strcat(cmd," >T:ZuneARC.tmp");
         //printf("%s\n",cmd);         
         fprintf(sf,"%s\n",cmd);
         j = 0;
         strncpy(cmd,"",512);
      }
      if(fmt[i]!='%') 
      {
         cmd[j++] = fmt[i++];
      }
      else
      {  
         if (fmt[i+1]=='%') i++;
            else strcpy(tmp,"\"");
         if(strncmp(&fmt[i],"%arch",5)==0) strcat(tmp,arch);
         if(strncmp(&fmt[i],"%file",5)==0) strcat(tmp,file);
         if(strncmp(&fmt[i],"%dest",5)==0) strcat(tmp,dest);
         if(strncmp(&fmt[i],"%base",5)==0) strcat(tmp,base);
         if (fmt[i-1]!='%') strcat(tmp,"\"");
          
         strcat(cmd,tmp);
         j = j+strlen(tmp);
         i = i+5;        
      }         
   }
   cmd[j]='\0';
   if(out) strcat(cmd," >T:ZuneARC.tmp");
   //printf("%s\n",cmd);     
   fprintf(sf,"%s\n",cmd);
   fclose(sf);
   
   set(cmdtext,MUIA_Gauge_InfoText,strcat(display,cmd));
   BPTR scriptfile = Open("T:ZuneARC.script",MODE_OLDFILE);

   struct TagItem tags[] = {
   	                   {SYS_Input, (IPTR)NULL},
   	                   {SYS_Output, (IPTR)NULL},
   	                   {SYS_Error, (IPTR)NULL},
                       	   {SYS_ScriptInput, (IPTR)scriptfile},
   	                   {SYS_UserShell, TRUE},
   	                   {TAG_DONE, 0}
                           };
   
   SystemTagList("",tags);

   
}

/*----------------------------------------------------------------------------*/
/*    int readconf(void)                                                      */
/*    Reads the configuration file and store the information		      */
/*----------------------------------------------------------------------------*/

int readconf(void)
{
   FILE *cf;
   char line[256];
   char tmparc[10];
   int i,j,k,l;
   
   NbArc = 0;
   NbType = 0;   
   
   if((cf=fopen("PROGDIR:ZuneARC.cfg","r")) == NULL)
   {
      MUI_Request(App,Win,0,"Error message","OK",
                  "Can't open configuration file\nZuneARC.cfg shall be placed in\nsame directpry as ZuneARC.",
                  TAG_DONE);
   }
   else
   {
      while(fgets(line,128,cf)!=NULL)
      {
         if(strncmp(line,"CmdName",7)==0) NbArc++;
         if(strncmp(line,"ArcType",7)==0) NbType++;
      }
   }

   archivers = malloc(NbArc * sizeof(struct Archivers));
   arctypes = malloc(NbType * sizeof(struct ArcTypes));
   
   rewind(cf);
   
   j = 0;
   while(fgets(line,256,cf)!=NULL)
   {
      if(strncmp(line,"CmdName",7)==0)
      {
         j++;
         strcpy(archivers[j-1].CmdName,readconfline(line));
      }
      if(strncmp(line,"ExtractSingle",13)==0)
         strcpy(archivers[j-1].ExtractSingle,readconfline(line));
      if(strncmp(line,"ExtractAll",10)==0)
         strcpy(archivers[j-1].ExtractAll,readconfline(line));
      if(strncmp(line,"ListContent",11)==0)
         strcpy(archivers[j-1].ListContent,readconfline(line));
      if(strncmp(line,"ContentHeader",13)==0)
         archivers[j-1].ContentHeader=atoi(readconfline(line));
      if(strncmp(line,"ContentFooter",13)==0)
         archivers[j-1].ContentFooter=atoi(readconfline(line));
      if(strncmp(line,"ContentFmt",10)==0)
         strcpy(archivers[j-1].ContentFmt,readconfline(line));
      if(strncmp(line,"PreAdd",6)==0)
         strcpy(archivers[j-1].PreAdd,readconfline(line));
      if(strncmp(line,"Add",3)==0)
         strcpy(archivers[j-1].Add,readconfline(line));
      if(strncmp(line,"PostAdd",7)==0)
         strcpy(archivers[j-1].PostAdd,readconfline(line));
      if(strncmp(line,"PreRemove",9)==0)
         strcpy(archivers[j-1].PreRemove,readconfline(line));
      if(strncmp(line,"Remove",6)==0)
         strcpy(archivers[j-1].Remove,readconfline(line));
      if(strncmp(line,"PostRemove",10)==0)
         strcpy(archivers[j-1].PostRemove,readconfline(line));
	  if(strncmp(line,"Create",6)==0)
         strcpy(archivers[j-1].Create,readconfline(line));
   }

   rewind(cf);
   
   j = 0;
   while(fgets(line,256,cf)!=NULL)
   {
      if(strncmp(line,"ArcType",7)==0)
      {
         i = 0;
         k = 0;
         while(line[i++]!=',');
         while(line[i++]==' ');
         i--;
         while(line[i++]!=',') arctypes[j].Extension[k++]=line[i-1];
         arctypes[j].Extension[k] = '\0';
         while(line[i++]==' ');
         i--;
         k = 0;
         while(line[i++]!=',') tmparc[k++]=line[i-1];
         tmparc[k] = '\0';
         l = 0;
         while((strcmp(tmparc,archivers[l].CmdName)!=0) && (l<NbArc)) l++; 
         arctypes[j].Archiver = l;
         j++;                 
      }
   }
   
   fclose(cf);
   return(0);
}

/*----------------------------------------------------------------------------*/
/*    char *readconfline(char *line)                                          */
/*    Reads one configuration file and sends back the content 		      */
/*----------------------------------------------------------------------------*/

char *readconfline(char *line)
{
   static char info[256];
   int i = 0;
   int k = 0;

   while(line[i++]!=',');
   while(line[i++]==' ');
   i--;
   while(line[i++]!=',') info[k++]=line[i-1];
   info[k] = '\0';
   
   return info;
}

/*----------------------------------------------------------------------------*/
/*    char *CreateArchive()                                                   */
/*    Creates a new archive file                             		      */
/*----------------------------------------------------------------------------*/
char *CreateArchive()
{
   char *FileToAdd;
   static char ArcName[128];
   char *res = NULL;
   char filter[16] = "#?.";
   int extlen;
   char arcsel[128]="";
   int i,j = 0;
   int TmpArcType[16];
   
   strncpy(ArcName,"",128);
   res = ArcName;
   
   for(i=0;i<NbType;i++)
   {
      if(archivers[arctypes[i].Archiver].Create[0]!='#')
      {
         if (arcsel[0]!='\0') strcat(arcsel,"|");
         strcat(arcsel,arctypes[i].Extension);
         TmpArcType[j++] = i;
      }
   }

   
   strcat(arcsel,"|CANCEL");
   i = MUI_Request(App,Win,0,"Archive Type Selection",arcsel,
       "Select the type of archive you want to create",
       TAG_DONE);
   
   if(i)
   {
      ArcType = TmpArcType[i-1];        
      extlen = strlen(arctypes[ArcType].Extension);
      strcat(filter,arctypes[ArcType].Extension);

      strcpy(ArcName,getfilename(Win,"New Archive Name",FALSE,FALSE,filter,"SYS:"));
      // Append Extension if forgotten
      if (strcmp(ArcName,"")!=0)
      {
         if (strcmp(arctypes[ArcType].Extension,&ArcName[strlen(ArcName)-extlen])!=0)
         {
            strcat(ArcName,".");
            strcat(ArcName,arctypes[ArcType].Extension);
         }
   
         Runextcmd(archivers[arctypes[ArcType].Archiver].Create,ArcName,"","","",FALSE);
         res = ArcName;
      }   
   }      
   return(res);
}

/*----------------------------------------------------------------------------*/
/*    void ExtractSelected(char *Archive)                                     */
/*    Extract Selected files from archive                    		      */
/*----------------------------------------------------------------------------*/
void ExtractSelected(char *Archive)
{
   struct FileRecord *CurrentEntry;
   LONG id = MUIV_NList_NextSelected_Start;
   char *Destination;
      
   Destination = getfilename(Win,"Select Destination directory",FALSE,TRUE,"#?",Archive);
   
   if(strcmp(Destination,"")!=0)
   {
      for(;;)
      {
         DoMethod(ArcList,MUIM_NList_NextSelected,&id);
         if(id==MUIV_NList_NextSelected_End) break;
         
         DoMethod(ArcList,MUIM_NList_GetEntry,id,&CurrentEntry);
         
         Runextcmd(archivers[arctypes[ArcType].Archiver].ExtractSingle,
                   Archive,CurrentEntry->Name,
                   Destination,"",FALSE);
      }
   }
   else
   {
      MUI_Request(App,Win,0,"Error message","OK","No destination selected",TAG_DONE);
   }
}

/*----------------------------------------------------------------------------*/
/*    void ExtractAll(char *Archive)                                          */
/*    Extract All files from current Archive                  		      */
/*----------------------------------------------------------------------------*/
void ExtractAll(char *Archive)
{
   char *Destination;
      
   Destination = getfilename(Win,"Select Destination directory",FALSE,TRUE,"#?",Archive);
   
   if(strcmp(Destination,"")!=0)
   {
      Runextcmd(archivers[arctypes[ArcType].Archiver].ExtractAll,
                Archive,"",Destination,"",FALSE);
   }
   else
   {
      MUI_Request(App,Win,0,"Error message","OK","No destination selected",TAG_DONE);
   }
}

/*----------------------------------------------------------------------------*/
/*    void RemoveSelected(char *Archive)                                      */
/*    Delete Selected files from Archive                    		      */
/*----------------------------------------------------------------------------*/
void RemoveSelected(char *Archive)
{
   struct FileRecord *CurrentEntry;
   LONG id = MUIV_NList_NextSelected_Start;
   int Nselect = 0,x = 0; 
   
   if(strcmp(Archive,"")!=0)
   {
      for(;;)
      {
         set(cmdtext,MUIA_Gauge_Current,++x);
         DoMethod(ArcList,MUIM_NList_NextSelected,&id);
         if(id==MUIV_NList_NextSelected_End) break;
         Nselect++;
      }
      id = MUIV_NList_NextSelected_Start;
      set(cmdtext,MUIA_Gauge_Max,Nselect);
      // Remove pre command
      if (strlen(archivers[arctypes[ArcType].Archiver].PreRemove)>0)
         Runextcmd(archivers[arctypes[ArcType].Archiver].PreRemove,
                   Archive,"","","",FALSE);
      // Remove command (loop)
      for(;;)
      {
         set(cmdtext,MUIA_Gauge_Current,++x);
         DoMethod(ArcList,MUIM_NList_NextSelected,&id);
         if(id==MUIV_NList_NextSelected_End) break;
         
         DoMethod(ArcList,MUIM_NList_GetEntry,id,&CurrentEntry);
         
         Runextcmd(archivers[arctypes[ArcType].Archiver].Remove,
                   Archive,CurrentEntry->Name,"","",FALSE);
      }
      // Remove post command
      if (strlen(archivers[arctypes[ArcType].Archiver].PostRemove)>0)
         Runextcmd(archivers[arctypes[ArcType].Archiver].PostRemove,
                Archive,"","","",FALSE); 
      set(cmdtext,MUIA_Gauge_Current,0);
   }
   else
   {
      MUI_Request(App,Win,0,"Error message","OK","No archive selected",TAG_DONE);
   }
}

/*----------------------------------------------------------------------------*/
/*    void AddFile(char *Archive)                                             */
/*    Add files to current Archive                       		      */
/*----------------------------------------------------------------------------*/
void AddFile(char *Archive)
{   
   static char Base[128] = "SYS:";
   char vol[32];
   char *tmp;
   char test[32];
   BOOL Running = TRUE;
   ULONG Signals;
   struct FileRecord *CurrentEntry;
   LONG id = MUIV_NList_NextSelected_Start;
   int Nselect = 0,x,y;
   struct DosList *dl, *actdl;
   
   // Get list of Volumes and file in VolList
   DoMethod(SelAdd_VolList, MUIM_List_Clear);
   dl = LockDosList(LDF_READ | LDF_VOLUMES | LDF_ASSIGNS | LDF_DEVICES);
   actdl = dl;
   while(actdl = NextDosEntry(actdl, LDF_DEVICES))
   {
      strncpy(vol, actdl->dol_Ext.dol_AROS.dol_DevName, sizeof(vol));
      vol[sizeof(vol)-2] = '\0';
      strcat(vol,":");     
      DoMethod(SelAdd_VolList,MUIM_List_InsertSingle, vol, MUIV_List_Insert_Bottom);
   } 
   actdl = dl;
   while(actdl = NextDosEntry(actdl, LDF_VOLUMES))
   {
      strncpy(vol, actdl->dol_Ext.dol_AROS.dol_DevName, sizeof(vol));
      vol[sizeof(vol)-2] = '\0';
      strcat(vol,":");
      DoMethod(SelAdd_VolList,MUIM_List_InsertSingle, vol, MUIV_List_Insert_Bottom);
   } 
   actdl = dl;
   while(actdl = NextDosEntry(actdl, LDF_ASSIGNS))
   {
      strncpy(vol, actdl->dol_Ext.dol_AROS.dol_DevName, sizeof(vol));
      vol[sizeof(vol)-2] = '\0';
      strcat(vol,":");
      DoMethod(SelAdd_VolList,MUIM_List_InsertSingle, vol, MUIV_List_Insert_Bottom);
   }
   UnLockDosList(LDF_READ | LDF_VOLUMES | LDF_ASSIGNS | LDF_DEVICES);
   
   //strcpy(Base,"SYS:");
   set(SelAdd_DirList,MUIA_Dirlist_Directory,Base);
   set(SelAdd_CD,MUIA_Text_Contents,Base);   
   DoMethod(SelAdd_List,MUIM_NList_Clear);
   AddInSelAddList(Base,"",MUIV_NList_Insert_Sorted);
             
   set(SelAdd, MUIA_Window_Open, TRUE);
   
   while (Running)
   {
      switch(DoMethod(App, MUIM_Application_Input, &Signals))
      {
         case QUITSELADD:
            Running = FALSE;                          /* break the loop */
            set(SelAdd, MUIA_Window_Open, FALSE);
            break;
            
         case SELADDVOLL:
            DoMethod(SelAdd_VolList,MUIM_List_GetEntry,MUIV_List_GetEntry_Active,&tmp);
            sprintf(Base,"%s",tmp);            
            set(SelAdd_DirList,MUIA_List_Quiet,TRUE);
            set(SelAdd_DirList,MUIA_Dirlist_Directory,Base);
            set(SelAdd_DirList,MUIA_List_Quiet,FALSE);
            set(SelAdd_CD,MUIA_Text_Contents,Base);   
            DoMethod(SelAdd_List,MUIM_NList_Clear);
            AddInSelAddList(Base,"",MUIV_NList_Insert_Sorted);            
            break;
            
         case SELADDPAR:
            x=0;
            y=0;
            while(Base[x++]!='\0') if((Base[x]=='/') || (Base[x]==':')) y=x;
            if (Base[y]=='/') Base[y]='\0';
            if (Base[y]==':') Base[y+1]='\0';
            set(SelAdd_DirList,MUIA_List_Quiet,TRUE);
            set(SelAdd_DirList,MUIA_Dirlist_Directory,Base);
            set(SelAdd_DirList,MUIA_List_Quiet,FALSE);
            set(SelAdd_CD,MUIA_Text_Contents,Base);   
            DoMethod(SelAdd_List,MUIM_NList_Clear);
            AddInSelAddList(Base,"",MUIV_NList_Insert_Sorted);            
            break;
         
         case SELADDDIRL:
            strcpy(tmp,"");
            strcpy(tmp,(APTR)XGET(SelAdd_DirList,MUIA_Dirlist_Path));
            if (tmp) strcpy(Base,tmp);
            set(SelAdd_DirList,MUIA_List_Quiet,TRUE);
            set(SelAdd_DirList,MUIA_Dirlist_Directory,Base);
            set(SelAdd_DirList,MUIA_List_Quiet,FALSE);
            set(SelAdd_CD,MUIA_Text_Contents,Base);   
            DoMethod(SelAdd_List,MUIM_NList_Clear);
            AddInSelAddList(Base,"",MUIV_NList_Insert_Sorted);            
            break;
         
         case SELADDOK:
            x = 0;
            set(SelAdd, MUIA_Window_Open, FALSE);
            for(;;)
            {
               set(cmdtext,MUIA_Gauge_Current,++x);
               DoMethod(SelAdd_List,MUIM_NList_NextSelected,&id);
               if(id==MUIV_NList_NextSelected_End) break;
               Nselect++;
            }
            id = MUIV_NList_NextSelected_Start;
            set(cmdtext,MUIA_Gauge_Max,Nselect);
            // Add pre command
            if (strlen(archivers[arctypes[ArcType].Archiver].PreAdd)>0)
               Runextcmd(archivers[arctypes[ArcType].Archiver].PreAdd,
                         Archive,"","",Base,FALSE);
            // Add command (loop)
            for(;;)
            {
               set(cmdtext,MUIA_Gauge_Current,++x);
               DoMethod(SelAdd_List,MUIM_NList_NextSelected,&id);
               if(id==MUIV_NList_NextSelected_End) break;
         
               DoMethod(SelAdd_List,MUIM_NList_GetEntry,id,&CurrentEntry);
         
               Runextcmd(archivers[arctypes[ArcType].Archiver].Add,
                         Archive,CurrentEntry->Name,"",Base,FALSE);
            }
            // Add post command
            if (strlen(archivers[arctypes[ArcType].Archiver].PostAdd)>0)
            Runextcmd(archivers[arctypes[ArcType].Archiver].PostAdd,
                      Archive,"","",Base,FALSE); 
                                 
            set(cmdtext,MUIA_Gauge_Current,0);
            Running = FALSE;
            break;
            
         case SELADDDC:                               /* Double click on an entry */
            /*Get the active entry*/
            DoMethod(SelAdd_List,MUIM_NList_GetEntry,MUIV_NList_GetEntry_Active,&CurrentEntry);  
            /*If active entry is a directory explode it*/
            if (strncmp(CurrentEntry->Size,"DIR",3)==0)
            {               
               char Dir[128];
               char Path[128];
               if(Base[(strlen(Base)-1)]==':')sprintf(Dir,"%s%s",Base,CurrentEntry->Name);
                  else sprintf(Dir,"%s/%s",Base,CurrentEntry->Name);
               sprintf(Path,"%s/",CurrentEntry->Name);
               AddInSelAddList(Dir,Path,MUIV_NList_Insert_Sorted);
               DoMethod(SelAdd_List,MUIM_NList_Remove,MUIV_NList_Remove_Active);
	    }
	    break;
               
      }
      if (Running && Signals) Wait(Signals);
   }
   
}

/*----------------------------------------------------------------------------*/
/*    void AddInSelAddList(char *Dir,char *Path, LONG Position)               */
/*    Add files from DIR to Add List including Path in front of File Name     */
/*----------------------------------------------------------------------------*/
void AddInSelAddList(char *Dir, char *Path, LONG Position)
{
   BPTR BaseDirLock;
   struct FileInfoBlock *fib;
   BOOL success = FALSE;
   struct DateTime dt;
   char datebuffer[LEN_DATSTRING];
   char timebuffer[LEN_DATSTRING];
   struct FileRecord rec;
   
   set(SelAdd_List,MUIA_NList_Quiet,TRUE);
   BaseDirLock = Lock(Dir,ACCESS_READ);
   if (BaseDirLock)
   {
      fib = AllocDosObject(DOS_FIB, NULL);
      if (fib)
      {
         success = Examine(BaseDirLock, fib);
         if (success && fib->fib_DirEntryType > 0)
         {
            for (;;)
            {
               BOOL ok;
            
               ok = ExNext(BaseDirLock,fib);
               if (!ok)
               {
                  if (IoErr() == ERROR_NO_MORE_ENTRIES) break;
                  success = FALSE;
                  continue;
               }
            
               dt.dat_Stamp = fib->fib_Date;
               dt.dat_Format = FORMAT_DOS;
               dt.dat_Flags = 0;
               dt.dat_StrDay = NULL;
               dt.dat_StrDate = datebuffer;
               dt.dat_StrTime = timebuffer;
            
               DateToStr(&dt);
            
               sprintf(rec.Name,"%s%s",Path,fib->fib_FileName);
               if (fib->fib_DirEntryType>0) sprintf(rec.Size,"%s","DIR");
                  else sprintf(rec.Size,"%d",fib->fib_Size);
               sprintf(rec.CSize,"");
               sprintf(rec.Date,"%s %s",datebuffer,timebuffer);
            
               DoMethod(SelAdd_List,MUIM_NList_InsertSingle,&rec, Position);
            }
         }
      }   
      UnLock(BaseDirLock);
   }
   set(SelAdd_List,MUIA_NList_Quiet,FALSE);
}

/*----------------------------------------------------------------------------*/
/*    char *getfilename(Object *win, char *title, BOOL save,                  */
/*                       BOOL drawers, char *pattern, char *inidrawer)        */
/*    open ASL FileRequester and get selection                		      */
/*----------------------------------------------------------------------------*/
char *getfilename(Object *win, char *title, BOOL save, BOOL drawers, char *pattern, char *inidrawer)
{
   char inipath[256], *eip;
   static char buf[1024];
   struct FileRequester *req;
   struct Window *w;
   Object *app = (Object *)XGET(win,MUIA_ApplicationObject);
   char *res = NULL;
   int x;

   strcpy(inipath,inidrawer);
   eip = PathPart(inipath);
   eip[0]='\0';
   
   strncpy(buf,"",1024);
   res = buf;
   get(win,MUIA_Window_Window,&w);

   if(req=MUI_AllocAslRequestTags(ASL_FileRequest,
      ASLFR_Window, w,
      ASLFR_TitleText, title,
      ASLFR_InitialPattern , pattern,
      ASLFR_InitialDrawer  , inipath,
      ASLFR_DoSaveMode     , save,
      ASLFR_DoMultiSelect  , FALSE,
      ASLFR_DrawersOnly    , drawers,
      ASLFR_SetSortDrawers , ASLFRSORTDRAWERS_First,
      ASLFR_DoPatterns     , TRUE,
      ASLFR_RejectIcons    , TRUE,
      ASLFR_UserData       , app,
      TAG_DONE))
   {
      set(app,MUIA_Application_Sleep,TRUE);
      if (MUI_AslRequestTags(req,TAG_DONE))
      {
         res = buf;
         stccpy(buf,req->fr_Drawer,sizeof(buf));
         if(!drawers)
            if (*req->fr_Drawer) AddPart(buf,req->fr_File,sizeof(buf));
	    else strcat(buf,req->fr_File);
      }
      MUI_FreeAslRequest(req);
      set(app,MUIA_Application_Sleep,FALSE);
   }
   return(res);
}

fixed the bug in NFloattext.mcc which caused the class to ignore MUIA_Font (together with the rest of taglist). If you write your own varargs stub which uses AROS_SLOWSTACKTAGS macros inside itself, DO NOT declare it static!