What is a Zune custom class?
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...
- Betterstring 11.15
- Date.mcc
- HTMLview 13.4
- Mailtext 19.9
- NList 20.121
- NListtree 18.28.
- NListview 19.76.
- NBitmap 15.6.
- NBalance 15.2.
- Speedbar 19.4.
- SpeedCFG 11.0.
- SpeedbarVirt 19.4.
- Speedbutton 19.4.
- TextEditor 15.27.
- TheBar 26.2.
- TheBarVirt 26.2.
- TheButton 26.2.
- TWFmultiLED.mcc 12.8
- URLText 19.7.
Using custom classes
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
BetterString
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
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, execpt 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) need to be drawn (and when NList need to compute lenght 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 reconized 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 actuallly 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
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
    diplayed 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, ©hook, 42 );
			DoMethod( lt_nodes, MUIM_Notify, MUIA_NListtree_Active, MUIV_EveryTime,
				lt_nodes, 3, MUIM_CallHook, ©hook, 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, ©kshook, 42 );
			DoMethod( lt_nodes, MUIM_Notify, MUIA_NListtree_Active, MUIV_EveryTime,
				lt_nodes, 3, MUIM_CallHook, ©kshook, 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
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
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
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
Creating a custom class
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
#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
/*
**       $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!