Aros/Developer/Docs/Libraries/GadTools

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

Introduction edit

  • V34 - OS1.3x Gadtools did not exist but gadtools13.library was around
  • V36 - OS2.0x First Introduction
  • V37 - OS2.04 NewLook rendering scheme
  • V39 - OS3.0x NewLook menus added - GT_GetGadgetAttrs() added -
  • V40 - OS3.1x Fixes


Until AmigaOS™ 2.0, there was no unified look and feel design standard — application developers had to write their own objects (buttons, requesters and menus), with Intuition providing minimal support. With AmigaOS™ 2.0 came gadtools.library, which provided standard widget sets, and the Interface Style Guide, which explained how applications could be laid out for consistency to the user.

you should refer to the GadTools Library chapter and Amiga list.

Gadtools is a deprecated interface as it is limited and restrictive (which does have its advantages in certain cases). Try just using BOOPSI gadgets which leads to our MUI version called Zune. BOOPSI is the underpinning for MUI, bgui and others.


Many of the GadTools functions use TagItem arrays or tag lists to pass information across the function interface. These tag-based functions come in two types, one that takes a pointer to an array of tag items and one that takes a variable number of tag item arguments directly in the function call. In general, the second form, often called the varargs form because the call takes a variable number of arguments, is provided for convenience and is internally converted to the first form.

All GadTools tags begin with a leading "GT". In general, they also have a two-letter mnemonic for the kind of gadget in question. For example, slider gadgets recognize tags such as "GTSL_Level"

For most gadgets, the NewGadget structure is used to specify its common attributes. Additional attributes that are unique to specific kinds of gadgets are specified as tags sent to the CreateGadget() function

The various GadTools gadget types require certain classes of IDCMP messages in order to work. Applications specify these IDCMP classes when the window is opened or later with ModifyIDCMP(). Each kind of GadTools gadget requires one or more of these IDCMP classes:

IDCMP_GADGETUP, IDCMP_GADGETDOWN, IDCMP_MOUSEMOVE, IDCMP_MOUSEBUTTONS and IDCMP_INTUITICKS. 

After closing the window, the gadgets allocated using CreateGadget() must be released.


A direct conversion of window coordinates to GadTools gadget coordinates. GaDTools user interfaces are easy to use except for gadget coordinates. Also need a draw rectangle function based on these coordinates to calibrate my drawing areas and erase rectangle coordinates.


There is a strict set of functions and operations that are permitted on GadTools gadgets.

Never selectively or forcibly refresh gadgets. The only gadget refresh that should ever be performed is the initial GT_RefreshWindow() after a window is opened with GadTools gadgets attached. It is also possible to add gadgets after the window is opened by calling AddGlist() and RefreshGlist() followed by GT_RefreshWindow(). These refresh functions should not be called at any other time.

GadTools gadgets may not overlap with each other, with other gadgets or with other elements. Doing this to modify the gadget’s appearance is not supported.

GadTools gadgets may not be selectively added or removed from a window. This has to do with the number of Intuition gadgets that each call to CreateGadget() produces and with refresh constraints.

Never use OnGadget() or OffGadget() or directly modify the GFLG_DISABLED Flags bit. The only approved way to disable or enable a gadget is to use GT_SetGadgetAttrs() and the GA_Disabled tag. Those kinds of GadTools gadgets that do not support GA_Disabled may not be disabled.

The application should never write into any of the fields of the Gadget structure or any of the structures that need it unless they are explicitly programmer fields (e.g. GadgetID and UserData) or if they are guaranteed meaningful

(LeftEdge, TopEdge, Width, Height, Flags). 

On occasion, the program is specifically invited to read a field, for example the StringInfo->Buffer field.

GadTools gadgets may not be made relative sized or relative positioned. This means that the gadget flags GFLG_RELWIDTH, GFLG_RELHEIGHT, GFLG_RELBOTTOM and GFLG_RELRIGHT may not be specified. The activation type of the gadget may not be modified (for example changing GACT_IMMEDIATE to GACT_RELVERIFY).


Gadgets edit

Gadget Type Description or Example Usage
Button Familiar action gadgets, such as "OK" or "Cancel".
String For text entry.
Integer For numeric entry.
Checkboxes For on/off items.
Mutually exclusive Radio buttons, select one choice among several.
Cycle Multiple-choice, pick one of a small number of choices.
Sliders To indicate a level within a range.
Scrollers To indicate a position in a list or area.
Listviews Scrolling lists of text.
Palette Color selection.
Text-display Read-only text.
Numeric-display Read-only numbers.


Modify edit

Create http://thomas-rapp.homepage.t-online.de/examples/gadtools.c


To change the flags and the body variables after the gadget is displayed, the program can call Intuition's NewModifyProp().

void NewModifyProp( struct Gadget *gadget, struct Window *window, struct Requester *requester, 
                    unsigned long flags, unsigned long horizPot, unsigned long vertPot,
                       unsigned long horizBody, unsigned long vertBody, long numGad );

The gadget's internal state will be recalculated and the imagery will be redisplayed to show the new state. When numGads (in the prototype above) is set to all ones, NewModifyProp() will only update those parts that have changed, which is much faster than removing the gadget, changing values, adding the gadget back and refreshing.

Each kind of GadTools gadget requires one or more of these IDCMP classes: IDCMP_GADGETUP, IDCMP_GADGETDOWN, IDCMP_MOUSEMOVE, IDCMP_MOUSEBUTTONS and IDCMP_INTUITICKS.

programs that use Gadgets always require notification about window refresh events. Even if the application performs no rendering of its own, it may not use the WFLG_NOCAREREFRESH window flag and must always set IDCMP_REFRESHWINDOW.

The attributes of a gadget are set up when the gadget is created. Some of these attributes can be changed later by using the GT_SetGadgetAttrs() function:

   void GT_SetGadgetAttrs (struct Gadget *gad, struct Window *win,
                           struct Requester *req, Tag tag1, ... )
   void GT_SetGadgetAttrsA(struct Gadget *gad, struct Window *win,
                           struct Requester *req, struct TagItem *taglist)


Button edit

Button gadgets (BUTTON_KIND) are perhaps the simplest kind of GadTools gadget.

Text-entry (STRING_KIND) and number-entry (INTEGER_KIND) gadgets are fairly typical Intuition string gadgets

Cycle gadgets (CYCLE_KIND) allow the user to choose exactly one option from among several


GadTools gadgets and menus need information about the screen on which they will appear. Before creating any GadTools gadgets or menus, the program must get this information using the GetVisualInfo() call.


Menus. GadTools fully supports Intuition's NewLook menus. NewLook menus can be added to an application by providing the

{WA_NewLookMenus, TRUE} tag to OpenWindowTags(),

and providing the

{GTMN_NewLookMenus, TRUE} tag to LayoutMenus(). 

These two tags will give your application NewLook menus. The pens used to render these menus are controllable by the user through the Palette prefs editor.

You can now put an arbitrary command string in the right-hand side of a menu, where the Amiga-key equivalent normally goes. To do this, point the NewMenu.nm_CommKey field at the string (e.g., "Shift-Alt-F1), and set the new NM_COMMANDSTRING flag in NewMenu.nm_Flags.

GT_GetGadgetAttrs(). GadTools now has a GT_GetGadgetAttrsA() function which retrieves attributes of the specified gadget, according to the attributes chosen in the tag list. For each entry in the tag list, ti_Tag identifies the attribute, and ti_Data is a pointer to the long variable where you wish the result to be stored.

     LONG top = 0;
     LONG selected = 0;
     LONG result;
     result = GT_GetGadgetAttrs(listview_gad, win, NULL,
                                GTLV_Top, &top,
                                GTLV_Selected, &selected,
                                TAG_DONE);
     if (result != 2)
     {
         printf( "Something's wrong!" );
     }


String edit

Most regular Intuition string gadgets which default to FALSE


Listviews edit

Listviews. GadTools listviews

The disappearance of the display box at the bottom of the scrolling list area. Instead of showing the selected item in the display box, the selected item remains highlighted within the scrolling list. This was done to prepare listviews for multi-select support. Multi-selection requires a highlighting scheme as a display box would not work. The removal of the display box has a slight impact on the size of the listview.

GTLV_CallBack. This tag allows a callback hook to be provided to gadtools for listview handling. Currently, the hook only gets called to render an individual item. Every time GadTools wishes to render an item in a listview, it invokes the call back function, which can do custom rendering. This allows GadTools listviews to be used to scroll complex items such as graphics and images.

Listviews can now be disabled using {GA_Disabled, TRUE}.


Palettes edit

Palettes. GadTools palette gadgets no longer display a box filled with the selected color. The selected color is instead denoted by a box drawn around the color square in the main palette area. This change slightly impacts the size of palette gadgets.

Another change which can affect the size of the palette gadgets is the smarter layout of the color squares. An attempt is now made to keep the color squares as square as possible, based on the aspect ratio information obtained from the gfx database. As many color squares as possible are put on the screen, until things get too small in which case the upper colors are thrown away. The GTPA_ColorTable tag was added in support of sparce color tables. It lets you define arbitrary pens to be used to fill-in the color squares of the palette gadget.

The GTPA_NumColors tag lets you define the exact number of colors to display in the palette gadget. Under V37, the GTPA_Depth tag played the same role. The problem with GTPA_Depth is that only multiples of 2 in number of colors can be specified. GTPA_NumColors allows any number of colors.


Menus edit

http://thomas-rapp.homepage.t-online.de/examples/gtmenu.c

To set up GadTools menus

GetVisualInfo() and FreeVisualInfo()    CreateContext()


The underscore character, `_' is the recommended marker-symbol. So, for example, to mark the letter "F" as the keyboard equivalent for a button labelled "Select Font...", create the gadget text:

ng.ng_GadgetText = "Select _Font...";


List edit

http://thomas-rapp.homepage.t-online.de/examples/lv.c

When CreateGadget() is called multiple times (for each gadget), each new gadget is automatically linked to the previous gadget's NextGadget field, thus creating a gadget list. Second, if one of the gadget creations fails (usually due to low memory, but other causes are possible), then for the next call to CreateGadget(), next_gad will be NULL and CreateGadget() will fail immediately. This means that the program can perform several successive calls to CreateGadget() and only have to check for failure at the end.

can not use GadTools scroller gadgets in window borders


Scroll edit

http://thomas-rapp.homepage.t-online.de/examples/scroll.c http://thomas-rapp.homepage.t-online.de/examples/iconify.c

allocating an object containing the imageclass and then using this to draw the graphic into the button


Examples edit


/*
    Copyright © 1995-2007, The AROS Development Team. All rights reserved.
    $Id: calculator.c 27035 2007-10-07 19:33:35Z mazze $
*/

#include <intuition/intuition.h>
#include <libraries/gadtools.h>
#include <libraries/locale.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/gadtools.h>
#include <proto/locale.h>
#include <proto/alib.h>

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <math.h>

#define ARG_TEMPLATE "PUBSCREEN,TAPE/K"

enum {ARG_PUBSCREEN,ARG_TAPE,NUM_ARGS};

#define MAX_VAL_LEN 13

#define INNER_SPACING_X 4
#define INNER_SPACING_Y 4

#define BUTTON_SPACING_X 4
#define BUTTON_SPACING_Y 4

#define BUTTON_LED_SPACING 4

#define NUM_BUTTONS 20
#define NUM_BUTTON_COLS 5
#define NUM_BUTTON_ROWS 4

#define BUTTON_EXTRA_WIDTH 8
#define BUTTON_EXTRA_HEIGHT 4

#define LED_EXTRA_HEIGHT 4

enum
{
    STATE_LEFTVAL, STATE_OP, STATE_RIGHTVAL, STATE_EQU
};

enum
{
    BTYPE_0,
    BTYPE_1,
    BTYPE_2,
    BTYPE_3,
    BTYPE_4,
    BTYPE_5,
    BTYPE_6,
    BTYPE_7,
    BTYPE_8,
    BTYPE_9,
    BTYPE_COMMA,
    BTYPE_BS,
    BTYPE_CA,
    BTYPE_CE,
    BTYPE_MUL,
    BTYPE_DIV,
    BTYPE_SUB,
    BTYPE_ADD,
    BTYPE_SIGN,
    BTYPE_EQU,
    
    BTYPE_LED
};

struct ButtonInfo
{
    char *text;
    WORD type;
    char key1;
    char key2;
};

static struct ButtonInfo bi[NUM_BUTTONS] =
{
    {"7"	,BTYPE_7	, '7'	, 0	},
    {"8"	,BTYPE_8	, '8'	, 0	},
    {"9"	,BTYPE_9	, '9'	, 0	},
    {"CA"	,BTYPE_CA	, 'A'	, 127	},
    {"CE"	,BTYPE_CE	, 'E'	, 0	},
    
    {"4"	,BTYPE_4	, '4'	, 0	},
    {"5"	,BTYPE_5	, '5'	, 0	},
    {"6"	,BTYPE_6	, '6'	, 0	},
    {"×"	,BTYPE_MUL	, '*'	, 'X'	},
    {":"	,BTYPE_DIV	, '/'	, ':'	},
    
    {"1"	,BTYPE_1	, '1'	, 0	},
    {"2"	,BTYPE_2	, '2'	, 0	},
    {"3"	,BTYPE_3	, '3'	, 0	},
    {"+"	,BTYPE_ADD	, '+'	, 0	},
    {"-"	,BTYPE_SUB	, '-'	, 0	},
    
    {"0"	,BTYPE_0	, '0'	, 0	},
    {"."	,BTYPE_COMMA	, '.'	, ','	},
    {"«"	,BTYPE_BS	, 8  	, 0	},
    {"±"	,BTYPE_SIGN	, 'S'	, 0	},
    {"="	,BTYPE_EQU	, '='	, 13	}
};


struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Library *GadToolsBase;
#ifndef __MORPHOS__
struct LocaleBase *LocaleBase;
#else
struct Library *LocaleBase;
#endif

static struct Screen *scr;
static struct DrawInfo *dri;
static struct Gadget *gadlist, *gad[NUM_BUTTONS + 2];
static struct Window *win;
static struct RDArgs *MyArgs;
static APTR vi;
static BPTR tapefh;

static WORD win_borderleft,win_bordertop;
static WORD buttonwidth,buttonheight,ledheight;
static WORD inner_winwidth,inner_winheight;
static WORD vallen,state,operation;

static BOOL dotape;

static double leftval,rightval;

static char comma,*pubscrname;
static char ledstring[256],visledstring[256],
				tempstring[256],tapename[256];

static char *deftapename = "RAW:%ld/%ld/%ld/%ld/Calculator Tape/INACTIVE/SCREEN%s";

UBYTE version[] = "$VER: Calculator 1.3 (07.10.2007) © AROS Dev Team";

static IPTR Args[NUM_ARGS];

static void Cleanup(char *msg)
{
    WORD rc;
    
    if (msg)
    {
	printf("Calculator: %s\n",msg);
	rc = RETURN_WARN;
    } else {
	rc = RETURN_OK;
    }
    
    if (tapefh) Close(tapefh);
    
    if (win) CloseWindow(win);
    
    if (gadlist) FreeGadgets(gadlist);
    
    if (vi) FreeVisualInfo(vi);
    if (dri) FreeScreenDrawInfo(scr,dri);
    if (scr) UnlockPubScreen(0,scr);
    
    if (MyArgs) FreeArgs(MyArgs);
    
    if (LocaleBase) CloseLibrary((struct Library *)LocaleBase);
    if (GadToolsBase) CloseLibrary(GadToolsBase);
    if (GfxBase) CloseLibrary((struct Library *)GfxBase);
    if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
    
    exit (rc);
}

static void DosError(void)
{
    Fault(IoErr(),0,tempstring,255);
    Cleanup(tempstring);
}

static void OpenLibs(void)
{
    if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",39)))
    {
	Cleanup("Can't open intuition.library V39!");
    }
    
    if (!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",39)))
    {
	Cleanup("Can't open graphics.library V39!");
    }
    
    if (!(GadToolsBase = OpenLibrary("gadtools.library",39)))
    {
	Cleanup("Can't open gadtools.library V39!");
    }
    
    LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",39);
}

static void GetArguments(void)
{
    if (!(MyArgs = ReadArgs(ARG_TEMPLATE,(IPTR *)Args,0)))
    {
	DosError();
    }
    
    pubscrname = (char *)Args[ARG_PUBSCREEN];
    
    if (Args[ARG_TAPE])
    {
	strcpy(tapename,(char *)Args[ARG_TAPE]);
	dotape = TRUE;
    }
}

static void DoLocale(void)
{
    struct Locale *loc;
    
    comma = '.';
    
    if ((loc = OpenLocale(0)))
    {
    	comma = loc->loc_DecimalPoint[0];
    	CloseLocale(loc);
    }
    
    bi[16].text[0] = comma;
}

static void GetVisual(void)
{
    if (pubscrname) scr = LockPubScreen(pubscrname);
    
    if (!scr)
    {
	if (!(scr = LockPubScreen(0)))
	{
	    Cleanup("Can't lock screen!");
	}
    }
    
    if (!(dri = GetScreenDrawInfo(scr)))
    {
	Cleanup("Can't get drawinfo!");
    }
    
    if (!(vi = GetVisualInfo(scr,0)))
    {
	Cleanup("Can't get visual info!");
    }
    
    win_borderleft = scr->WBorLeft;

    /* SDuvan: was scr->WBorTop + scr->Font->ta_YSize + 1 */
    win_bordertop = scr->WBorTop + dri->dri_Font->tf_YSize + 1;

}

static void InitGUI(void)
{
    static struct RastPort temprp;
    
    WORD i,len;
    
    InitRastPort(&temprp);
    SetFont(&temprp,dri->dri_Font);
    
    buttonheight = dri->dri_Font->tf_YSize + BUTTON_EXTRA_HEIGHT;
    
    for(i = 0;i < NUM_BUTTONS;i++)
    {
	len = TextLength(&temprp,bi[i].text,strlen(bi[i].text));
	if (len > buttonwidth) buttonwidth = len;
    }
    
    buttonwidth += BUTTON_EXTRA_WIDTH;
    
    ledheight = dri->dri_Font->tf_YSize + LED_EXTRA_HEIGHT;
    
    inner_winwidth = buttonwidth * NUM_BUTTON_COLS +
	BUTTON_SPACING_X * (NUM_BUTTON_COLS - 1) + 
	INNER_SPACING_X * 2;
    
    inner_winheight = buttonheight * NUM_BUTTON_ROWS +
	BUTTON_SPACING_Y * (NUM_BUTTON_ROWS - 1) +
	BUTTON_LED_SPACING +
	ledheight +
	INNER_SPACING_Y * 2;
    
#ifdef __AROS__
    DeinitRastPort(&temprp);
#endif
    strcpy(ledstring,"0");
}

static void MakeGadgets(void)
{
    struct Gadget *mygad = 0;
    struct NewGadget ng = {0};
    WORD col,row,i;
    
    ng.ng_VisualInfo = vi;
    
    mygad = CreateContext(&gadlist);
    
    ng.ng_GadgetID = BTYPE_LED;
    
    ng.ng_LeftEdge = win_borderleft + INNER_SPACING_X;
    ng.ng_TopEdge  = win_bordertop + INNER_SPACING_Y;
    ng.ng_Width = inner_winwidth - INNER_SPACING_X * 2;
    ng.ng_Height = ledheight;
    
    mygad = gad[BTYPE_LED] = CreateGadget(TEXT_KIND,
					  mygad,
					  &ng,
					  GTTX_Text, (IPTR) ledstring,
					  GTTX_CopyText,TRUE,
					  GTTX_Border,TRUE,
					  GTTX_Justification,GTJ_RIGHT,
					  TAG_DONE);
    
    i = 0;
    
    ng.ng_TopEdge = win_bordertop +
	INNER_SPACING_Y + 
	ledheight +
	BUTTON_LED_SPACING;
    
    ng.ng_Width = buttonwidth;
    ng.ng_Height = buttonheight;
    
    for(row = 0; row < NUM_BUTTON_ROWS; row++)
    {
	for(col = 0; col < NUM_BUTTON_COLS; col++, i++)
	{
	    ng.ng_GadgetID = bi[i].type;
	    
	    ng.ng_LeftEdge = win_borderleft +
		INNER_SPACING_X +
		col * (buttonwidth + BUTTON_SPACING_X);
	    
	    ng.ng_GadgetText = bi[i].text;
	    
	    mygad = gad[bi[i].type] = CreateGadgetA(BUTTON_KIND,
						    mygad,
						    &ng,
						    0);
	    
	} /* for(col = 0;col < NUM_BUTTON_COLS; col++) */
	
	ng.ng_TopEdge += buttonheight + BUTTON_SPACING_Y;
	
    } /* for(row = 0; row < NUM_BUTTON_ROWS; row++) */
    
    if (!mygad)
    {
	Cleanup("Can't create gadgets!");
    }
    
}

static void MakeWin(void)
{
    win = OpenWindowTags(0,WA_PubScreen,(IPTR)scr,
			 WA_Left,scr->MouseX,
			 WA_Top,scr->MouseY,
			 WA_InnerWidth,inner_winwidth,
			 WA_InnerHeight,inner_winheight,
			 WA_AutoAdjust,TRUE,
			 WA_Title,(IPTR)"Calculator",
			 WA_CloseGadget,TRUE,
			 WA_DepthGadget,TRUE,
			 WA_DragBar,TRUE,
			 WA_Activate,TRUE,
			 WA_SimpleRefresh,TRUE,
			 WA_IDCMP,IDCMP_CLOSEWINDOW |
			 IDCMP_GADGETUP |
			 IDCMP_VANILLAKEY |
			 IDCMP_RAWKEY |
			 IDCMP_REFRESHWINDOW,
			 WA_Gadgets,(IPTR)gadlist,
			 TAG_DONE);

    if (!win) Cleanup("Can't open window!");
    
    GT_RefreshWindow(win,0);
    
    ScreenToFront(win->WScreen);
}

static void OpenTape(void)
{
    struct List *l;
    struct PubScreenNode *psn;
    char *scrname = "";
    WORD x,y,w,h;
    
    if (!(tapename[0]))
    {
	l = LockPubScreenList();
	
	psn = (struct PubScreenNode *)l->lh_Head;
	
	while (psn->psn_Node.ln_Succ)
	{
	    if (psn->psn_Screen == scr)
	    {
		if (psn->psn_Node.ln_Name)
		{
		    scrname = psn->psn_Node.ln_Name;
		}
		break;
	    }
	    psn = (struct PubScreenNode *)psn->psn_Node.ln_Succ;
	}
	
	UnlockPubScreenList();
	
	w = win->Width * 5 / 4;
	h = win->Height;
	
	x = win->LeftEdge;
	y = win->TopEdge;
	
	if (x > (scr->Width - (x + w)))
	{
	    x -= w;
	} else {
	    x += win->Width;
	}
	sprintf(tapename,deftapename,x,y,w,h,scrname);
    }
    
    if (!(tapefh = Open(tapename,MODE_NEWFILE)))
    {
	DisplayBeep(scr);
    }
}

static double GetValue(void)
{
    double val;
    char c = 0,*sp;
    
    sp = strchr(ledstring,comma);
    if (sp)
    {
	c = *sp;
	*sp = '.';
    }
    
    val = strtod(ledstring,0);
    
    if (sp) *sp = c;
    
    return val;
}

static void GetLeftValue(void)
{	
    leftval = GetValue();
}

static void GetRightValue(void)
{
    rightval = GetValue();
}

static void LeftValToLED(void)
{
    char *sp;
    
    sprintf(ledstring,"%f",leftval);
    
    sp = strchr(ledstring,'.');
    if (!sp) sp = strchr(ledstring,',');
    if (sp) *sp = comma;	
}

static char *DoOperation(void)
{
    char *matherr = 0;
    
    switch (operation)
    {
    case BTYPE_ADD:
	leftval += rightval;
	break;
	
    case BTYPE_SUB:
	leftval -= rightval;
	break;
	
    case BTYPE_MUL:
	leftval *= rightval;
	break;
	
    case BTYPE_DIV:
	if (rightval == 0.0)
	{
	    matherr = "Division by zero!";
	} else {
	    leftval /= rightval;
	}
	break;
    }
    
    if (leftval > 9999999999999.0) // because of MAX_VAL_LEN
    {
	matherr = "Buffer overflow!";
    }

    if (!matherr) LeftValToLED();
    
    return matherr;
}

static void RefreshLED(void)
{
    strcpy(visledstring,ledstring);
    
    if ((ledstring[0] == ',') ||
	(ledstring[0] == '\0') ||
	((ledstring[0] >= '0') && (ledstring[0] <= '9')))
    {
	visledstring[0] = '\0';
	
	if ((ledstring[0] == ',') ||
	    (ledstring[0] == '.') ||
	    (ledstring[0] == '\0'))
	{
	    strcpy(visledstring,"0");
	}
	strcat(visledstring,ledstring);
    }
    
    GT_SetGadgetAttrs(gad[BTYPE_LED],
		      win,
		      0,
		      GTTX_Text,(IPTR)visledstring,
		      TAG_DONE);
}

static void HandleButton(WORD type)
{
    char *matherr = 0;
    WORD checklen;
    BOOL refresh_led = FALSE;
    
    switch(type)
    {
    case BTYPE_0:
    case BTYPE_1:
    case BTYPE_2:
    case BTYPE_3:
    case BTYPE_4:
    case BTYPE_5:
    case BTYPE_6:
    case BTYPE_7:
    case BTYPE_8:
    case BTYPE_9:
	checklen = vallen;
	if ((strchr(ledstring,comma))) checklen--;
	if ((strchr(ledstring,'-'))) checklen--;
	
	if (checklen < MAX_VAL_LEN)
	{
	    if (state == STATE_OP)
	    {
		state = STATE_RIGHTVAL;
	    } else if (state == STATE_EQU)
	    {
		state = STATE_LEFTVAL;
	    }
	    
	    if ((vallen > 0) || (type != BTYPE_0))
	    {
		ledstring[vallen++] = type + '0';
	    }
	    ledstring[vallen] = '\0';
	    
	    refresh_led = TRUE;
	    
	} /* if (vallen < MAX_VAL_LEN) */
	break;
	
    case BTYPE_COMMA:
	if (!strchr(ledstring,comma))
	{
	    if (state == STATE_OP)
	    {
		state = STATE_RIGHTVAL;
	    } else if (state == STATE_EQU)
	    {
		state = STATE_LEFTVAL;
	    }
	    
	    ledstring[vallen++] = comma;
	    ledstring[vallen] = '\0';
	    
	    refresh_led = TRUE;
	    
	} /* if (!strchr(ledstring,comma)) */
	break;
	
    case BTYPE_CA:
	vallen = 0;
	leftval = 0.0;
	rightval = 0.0;
	operation = BTYPE_ADD;
	
	state = STATE_LEFTVAL;
	
	strcpy(ledstring,"0");
	refresh_led = TRUE;
	
	if (tapefh) FPutC(tapefh, '\n');
	break;
	
    case BTYPE_CE:
	vallen = 0;
	strcpy(ledstring,"0");
	refresh_led = TRUE;
	
	switch (state)
	{
	case STATE_LEFTVAL:
	    leftval = 0.0;
	    break;
	    
	case STATE_OP:
	case STATE_RIGHTVAL:
	    rightval = 0.0;
	    break;
	}
	break;
	
    case BTYPE_BS:
	if (vallen)
	{
	    ledstring[--vallen] = '\0';
	    if (vallen == 0) strcpy(ledstring,"0");				
	    refresh_led = TRUE;
	}
	break;
	
    case BTYPE_SIGN:
	switch(state)
	{
	case STATE_LEFTVAL:
	case STATE_RIGHTVAL:
	    if (ledstring[0] == '-')
	    {
		strcpy(ledstring,&ledstring[1]);
	    } else {
		strcpy(tempstring,ledstring);
		strcpy(ledstring,"-");
		strcat(ledstring,tempstring);
	    }
	    refresh_led = TRUE;
	    break;
	    
	case STATE_EQU:
	    leftval = -leftval;
	    LeftValToLED();
	    refresh_led = TRUE;
	    break;
	}
	break;
	
    case BTYPE_ADD:
    case BTYPE_SUB:
    case BTYPE_MUL:
    case BTYPE_DIV:
	switch(state)
	{
	case STATE_LEFTVAL:
	case STATE_EQU:
	    GetLeftValue();
	    rightval = leftval;
	    
	    state = STATE_OP;
	    vallen = 0;
	    strcpy(ledstring,"0");
	    
	    if (tapefh)
	    {
		FPutC(tapefh, '\t');
		FPuts(tapefh, visledstring);
		FPutC(tapefh, '\n');
	        Flush(tapefh);
	    }
	    break;

	case STATE_OP:
	    break;
	    
	case STATE_RIGHTVAL:
	    GetRightValue();
	    matherr = DoOperation();
	    state = STATE_OP;
	    vallen = 0;				
	    refresh_led = TRUE;
	    
	    if (tapefh)
	    {
		FPuts(tapefh,
				(operation == BTYPE_ADD) ? "+" :
				(operation == BTYPE_SUB) ? "-" :
				(operation == BTYPE_DIV) ? ":" :
				"×");
		FPutC(tapefh, '\t');
		FPuts(tapefh, visledstring);
		FPutC(tapefh, '\n');
		Flush(tapefh);
	    }
	    break;
	    
	} /* switch(state) */
	
	operation = type;
	break;
	
    case BTYPE_EQU:
	if (state == STATE_LEFTVAL)
	{
	    GetLeftValue();
	    if (tapefh)
	    {
		FPutC(tapefh, '\t');
		FPuts(tapefh, visledstring);
		FPutC(tapefh, '\n');
		Flush(tapefh);
	    }
	}	
	else if (state == STATE_RIGHTVAL)
	{
	    GetRightValue();
	    if (tapefh)
	    {
		FPuts(tapefh, 
				(operation == BTYPE_ADD) ? "+" :
				(operation == BTYPE_SUB) ? "-" :
				(operation == BTYPE_DIV) ? ":" :
				"×");
		FPutC(tapefh, '\t');
		FPuts(tapefh, visledstring);
		FPutC(tapefh, '\n');
		Flush(tapefh);
	    }
	}
	
	matherr = DoOperation();
	state = STATE_EQU;
	
	vallen = 0;
	
	if (!matherr)
	{
	    RefreshLED();
	    if (tapefh)
	    {
		FPuts(tapefh, "=\t");
		FPuts(tapefh, visledstring);
		FPutC(tapefh, '\n');
		Flush(tapefh);
	    }
	} else {
	    refresh_led = TRUE;
	}
	break;
	
    } /* switch(type) */
    
    if (matherr)
    {
	leftval = rightval = 0.0;
	state = STATE_LEFTVAL;
	operation = BTYPE_ADD;
	vallen = 0;
	strcpy(ledstring,matherr);
	refresh_led = TRUE;
    }
    
    if (refresh_led) RefreshLED();
    
}

static void HandleAll(void)
{
    struct IntuiMessage *msg;
    WORD icode,i;
    ULONG signals;
    
    BOOL quitme = FALSE;
    
    if (dotape) OpenTape();

    while(!quitme)
    {
	signals = Wait(1L << win->UserPort->mp_SigBit | SIGBREAKF_CTRL_C);

	if (signals & (1L << win->UserPort->mp_SigBit))
	{
	    while ((msg = (struct IntuiMessage *)GetMsg(win->UserPort)))
	    {
	        switch(msg->Class)
	        {
	        case IDCMP_CLOSEWINDOW:
		    quitme = TRUE;
		    break;
		
	        case IDCMP_REFRESHWINDOW:
		    GT_BeginRefresh(win);
		    GT_EndRefresh(win,TRUE);
		    break;
		
	        case IDCMP_GADGETUP:
		    HandleButton(((struct Gadget *)msg->IAddress)->GadgetID);
		    break;
		
	        case IDCMP_VANILLAKEY:
		    icode = toupper(msg->Code);
		
		    for(i = 0;i < NUM_BUTTONS;i++)
		    {
		        if ((icode == bi[i].key1) ||
			    (icode == bi[i].key2))
		        {
			    icode = bi[i].type;
			    break;
		        }
		    }
		    if (i < NUM_BUTTONS)
		    {
		        HandleButton(icode);
		    } else if (icode == 27)
		    {
		        quitme = TRUE;
		    }
		    break;
		
	        } /* switch(msg->Class) */
	    
	        ReplyMsg((struct Message *)msg);
	    } /* while ((msg = (struct IntuiMessage *)GetMsg(win->UserPort))) */
	} /* if(signals & (1L << win->UserPort->mp_SigBit)) */
	if (signals & SIGBREAKF_CTRL_C)
	    quitme = TRUE;

    } /* while(!quitme) */
}

int main(void)
{
    OpenLibs();
    GetArguments();
    DoLocale();
    GetVisual();
    InitGUI();
    MakeGadgets();
    MakeWin();
    HandleAll();
    Cleanup(0);
    return 0;
}




/* Menus for LiteBench */

#ifdef WB_1.3
/* 
 * Workbench 1.3 style menus (obsolete)
 * 
 * Workbench		
 *   Open	
 *   Close
 *   Duplicate
 *   Rename
 *   Info
 *   Discard
 * 
 * Disk
 *   Empty Disk
 *   Initialize
 *
 *  Special
 *    Clean up
 *    Last error
 *    Redraw
 *    Snapshot
 *    Version
*/
struct NewMenu mynewmenu[] =
    {
        { NM_TITLE, "Workbench",          0, 0, 0, 0, },
        {  NM_ITEM,   "Open"              0  0, 0, 0, },
        {  NM_ITEM,   "Close",    	  0, 0, 0, 0, },
        {  NM_ITEM,   "Duplicate",        0, 0, 0, 0, },
        {  NM_ITEM,   "Rename",           0, 0, 0, 0, },
        {  NM_ITEM,   "Info",             0, 0, 0, 0, },
        {  NM_ITEM,   "Discard",          0, 0, 0, 0, },
        
        { NM_TITLE, "Disk",               0, 0, 0, 0, },
        {   NM_ITEM,  "Empty Disk",       0, 0, 0, 0, },
        {   NM_ITEM,  "Initialize",       0, 0, 0, 0, },

        { NM_TITLE, "Special",            0, 0, 0, 0, },
        {   NM_ITEM, "Clean Up",          0, 0, 0, 0, },
        {   NM_ITEM, "Last Error"         0, 0, 0, 0, },
        {   NM_ITEM, "Redraw",            0, 0, 0, 0, },
        {   NM_ITEM, "Snapshot",          0, 0, 0, 0, },
        {   NM_ITEM, "Version",           0, 0, 0, 0, },
        
        {   NM_END, NULL,              0, 0, 0, 0, },
    };

#endif /* WB_1.3 */

#ifdef LITEBENCH
/* simplified menus for a minimal workbench program */
struct NewMenu mynewmenu[] =
    {
        { NM_TITLE, "Icon",          0, 0, 0, 0, },
        {   NM_ITEM, "Open",             "O", 0, 0, 0, },
        {   NM_ITEM, "Copy",             "C", 0, 0, 0, },
        {   NM_ITEM, "Rename...",        "R", 0, 0, 0, },
        {   NM_ITEM, "Information...",   "I", 0, 0, 0, },
        {   NM_ITEM, "Snapshot",         "S", 0, 0, 0, },
        {   NM_ITEM, "Unsnapshot",       "U", 0, 0, 0, },
        {   NM_ITEM, "Leave out",        "L", 0, 0, 0, },
        {   NM_ITEM, "Put away",         "P", 0, 0, 0, },
        {   NM_ITEM, NM_BARLABEL,          0, 0, 0, 0, },
        {   NM_ITEM, "Delete...",          0, 0, 0, 0, },
        {   NM_ITEM, "Format...",          0, 0, 0, 0, },
        {   NM_ITEM, "Empty trash",        0, 0, 0, 0, },

        { NM_TITLE, "Window",             0, 0, 0, 0, },
        {   NM_ITEM,  "New drawer",        "N", 0, 0, 0, },
        {   NM_ITEM,  "Open parent",       "K", 0, 0, 0, },
        {   NM_ITEM,  "Close",               0, 0, 0, 0, },
        {   NM_ITEM,  "Update",              0, 0, 0, 0, }, 
        {   NM_ITEM,  "Select contents",   "A", 0, 0, 0, },

        {   NM_ITEM, "Clean up by",        0, 0, 0, 0, },
        {     NM_SUB,   "Column",        ".", 0, 0, 0, },
        {     NM_SUB,   NM_BARLABEL,       0, 0, 0, 0, },
        {     NM_SUB,   "Name",            0, (CHECKIT), 0, 0, },
        {     NM_SUB,   "Date",            0, (CHECKIT), 0, 0, },
        {     NM_SUB,   "Size",            0, (CHECKIT), 0, 0, },
        {     NM_SUB,   "Type",            0, (CHECKIT), 0, 0, },

        {   NM_ITEM, "Resize to fit",      0, 0, 0, 0, },
 
        {   NM_ITEM, "Snapshot",           0, 0, 0, 0, },
        {     NM_SUB,  "Window",            0, 0, 0, 0, },
        {     NM_SUB,  "All",               0, 0, 0, 0, },

        {   NM_ITEM, "Show",                0, 0, 0, 0, },
        {     NM_SUB, "Only icons",       "-", 0, 0, 0, },
        {     NM_SUB, "All files",        "+", 0, 0, 0, },

        {   NM_ITEM, "View by",             0, 0, 0, 0, },
        {     NM_SUB,   "Icon",           "1", 0, 0, 0, },
        {     NM_SUB, NM_BARLABEL,         0 , 0, 0, 0, },
        {     NM_SUB, "Name",             "2", 0, 0, 0, },
        {     NM_SUB, "Date",             "3", 0, 0, 0, },
        {     NM_SUB, "Size",             "4", 0, 0, 0, },
        {     NM_SUB, "Type",             "5", 0, 0, 0, },

		{ NM_TITLE, "Special"			0, 0, 0, 0, },
		{   NM_ITEM, "New Shell..."		"W",0,0,0, },
		{   NM_ITEM, "Icon Editor..."   "Y",0,0,0, },
 		{   NM_ITEM, NM_BARLABEL,		  0, 0, 0, 0, },
        {   NM_ITEM, "Quit Litebench", "Q", 0, 0, 0, },  
         
        {   NM_END, NULL,              0, 0, 0, 0, },
    };

#endif /* LITEBENCH */

#ifdef WB_3.x
/*  Workbench 3.x compatible menu strips, same keyboard shortcuts, etc.
 * *
 *  Workbench
 *  x Backdrop [a]B	 
 *  Enter Command [a]E	 
 *  Redraw all		 
 *  Update all		 
 *  Last Message	
 *  About...		
 *  Quit [a]Q	
 *
 * Window
 *  New drawer [a]N
 *  Open parent [a]K
 *  Close
 *  Update
 *  Select Contents [a]A
 *  Clear selection [a]Z
 *  Clean up by >>
 *                 Column [a]. {period}
 *                 -------------------
 *                 Name
 *                 Date
 *                 Size
 *                 Type
 *  Resize to fit
 *  Snapshot    >>
 *                 Window
 *                 All
 *  Show        >>
 *                 Only icons [a] - {minus}
 *                 All files  [a] + {plus}
 *  View by     >>
 *                 Icon       [a] 1 {one}
 *                 ------------------
 *                 Name       [a] 2 {two}
 *                 Date       [a] 3 {three}
 *                 Size       [a] 4 {four}
 *                 Type       [a] 5 {five}
 *
 * Icons
 *  Open [a]O
 *  Copy [a]C
 *  Rename... [a]R
 *  Information... a[I]
 *  Snapshot [a]S
 *  Unsnapshot [a]U
 *  Leave out [a]L
 *  Put away a[P]
 *  -------------------
 *  Delete....
 *  Format....
 *  Empty Trash
 *
 * Tools
 *   ResetWB
 *
 */
struct NewMenu mynewmenu[] =
    {
        { NM_TITLE, "Workbench",          0, 0, 0, 0, },
        {  NM_ITEM,   "Backdrop",         "B", (CHECKIT|CHECKED), 0, 0, },
        {  NM_ITEM,   "Enter command",    "E", 0, 0, 0, },
        {  NM_ITEM,   "Redraw all",         0, 0, 0, 0, },
        {  NM_ITEM,   "Update all",         0, 0, 0, 0, },
        {  NM_ITEM,   "Last message",       0, 0, 0, 0, },
        {  NM_ITEM,   "About...",           0, 0, 0, 0, },
        {  NM_ITEM,   "Quit",             "Q", 0, 0, 0, },
        
        { NM_TITLE, "Window",             0, 0, 0, 0, },
        {   NM_ITEM,  "New drawer",        "N", 0, 0, 0, },
        {   NM_ITEM,  "Open parent",       "K", 0, 0, 0, },
        {   NM_ITEM,  "Close",               0, 0, 0, 0, },
        {   NM_ITEM,  "Update",              0, 0, 0, 0, }, 
        {   NM_ITEM,  "Select contents",   "A", 0, 0, 0, },

        {   NM_ITEM, "Clean up by",        0, 0, 0, 0, },
        {     NM_SUB,   "Column",        ".", 0, 0, 0, },
        {     NM_SUB,   NM_BARLABEL,       0, 0, 0, 0, },
        {     NM_SUB,   "Name",            0, (CHECKIT), 0, 0, },
        {     NM_SUB,   "Date",            0, (CHECKIT), 0, 0, },
        {     NM_SUB,   "Size",            0, (CHECKIT), 0, 0, },
        {     NM_SUB,   "Type",            0, (CHECKIT), 0, 0, },

        {   NM_ITEM, "Resize to fit",      0, 0, 0, 0, },
 
        {   NM_ITEM, "Snapshot",           0, 0, 0, 0, },
        {     NM_SUB,  "Window",            0, 0, 0, 0, },
        {     NM_SUB,  "All",               0, 0, 0, 0, },

        {   NM_ITEM, "Show",                0, 0, 0, 0, },
        {     NM_SUB, "Only icons",       "-", 0, 0, 0, },
        {     NM_SUB, "All files",        "+", 0, 0, 0, },

        {   NM_ITEM, "View by",             0, 0, 0, 0, },
        {     NM_SUB,   "Icon",           "1", 0, 0, 0, },
        {     NM_SUB, NM_BARLABEL,         0 , 0, 0, 0, },
        {     NM_SUB, "Name",             "2", 0, 0, 0, },
        {     NM_SUB, "Date",             "3", 0, 0, 0, },
        {     NM_SUB, "Size",             "4", 0, 0, 0, },
        {     NM_SUB, "Type",             "5", 0, 0, 0, },

        {   NM_ITEM, NM_BARLABEL,           0, 0, 0, 0, },
        {   NM_ITEM, "Find...",           "F", 0, 0, 0, },

        { NM_TITLE, "Icons",               0, 0, 0, 0, },
        {   NM_ITEM, "Open",             "O", 0, 0, 0, },
        {   NM_ITEM, "Copy",             "C", 0, 0, 0, },
        {   NM_ITEM, "Rename...",        "R", 0, 0, 0, },
        {   NM_ITEM, "Information...",   "I", 0, 0, 0, },
        {   NM_ITEM, "Snapshot",         "S", 0, 0, 0, },
        {   NM_ITEM, "Unsnapshot",       "U", 0, 0, 0, },
        {   NM_ITEM, "Leave out",        "L", 0, 0, 0, },
        {   NM_ITEM, "Put away",         "P", 0, 0, 0, },
        {   NM_ITEM, NM_BARLABEL,          0, 0, 0, 0, },
        {   NM_ITEM, "Delete...",          0, 0, 0, 0, },
        {   NM_ITEM, "Format...",          0, 0, 0, 0, },
        {   NM_ITEM, "Empty trash",        0, 0, 0, 0, },

        { NM_TITLE, "Tools",           0, 0, 0, 0, },
        {   NM_ITEM, "ResetWB",        0, 0, 0, 0, },
        
        {   NM_END, NULL,              0, 0, 0, 0, },
    };
#endif /* WB_3.x */

#ifdef AROSbench /* enhanced WB_3.x style for AROS */
struct NewMenu mynewmenu[] =
    {
	{ NM_TITLE, "AROSbench",	    0, 0, 0, 0, },
        {  NM_ITEM,   "Backdrop",      "B", (CHECKIT|CHECKED), 0, 0, },
        {  NM_ITEM,   "Enter command",    "E", 0, 0, 0, },
	{  NM_ITEM,   "New Shell",        "W", 0, 0, 0, },
        {  NM_ITEM,   "Redraw all",         0, 0, 0, 0, },
        {  NM_ITEM,   "Update all",         0, 0, 0, 0, },
        {  NM_ITEM,   "Last message",       0, 0, 0, 0, },
        {  NM_ITEM,   "About AROSbench..."  0, 0, 0, 0, },
	{  NM_ITEM,   "Quit AROSbench",	  "Q", 0, 0, 0, },
	{  NM_ITEM,   NM_BARLABEL,          0, 0, 0, 0, },
	{  NM_ITEM,   "Shutdown AROS...",   0, 0, 0, 0, },

        { NM_TITLE, "Window",             0, 0, 0, 0, },
        {   NM_ITEM,  "New drawer",     "N", 0, 0, 0, },
        {   NM_ITEM,  "Open parent",    "K", 0, 0, 0, },
        {   NM_ITEM,  "Close",            0, 0, 0, 0, },
        {   NM_ITEM,  "Update",           0, 0, 0, 0, }, 
        {   NM_ITEM,  "Select contents","A", 0, 0, 0, },

        {   NM_ITEM, "Clean up by",        0, 0, 0, 0, },
        {     NM_SUB,   "Column",        ".", 0, 0, 0, },
        {     NM_SUB,   NM_BARLABEL,       0, 0, 0, 0, },
        {     NM_SUB,   "Name",            0, (CHECKIT), 0, 0, },
        {     NM_SUB,   "Date",            0, (CHECKIT), 0, 0, },
        {     NM_SUB,   "Size",            0, (CHECKIT), 0, 0, },
        {     NM_SUB,   "Type",            0, (CHECKIT), 0, 0, },

        {   NM_ITEM, "Resize to fit",      0, 0, 0, 0, },
 
        {   NM_ITEM, "Snapshot",           0, 0, 0, 0, },
        {     NM_SUB,  "Window",           0, 0, 0, 0, },
        {     NM_SUB,  "All",              0, 0, 0, 0, },

        {   NM_ITEM, "Show",                0, 0, 0, 0, },
        {     NM_SUB, "Only icons",       "-", 0, 0, 0, },
        {     NM_SUB, "All files",        "+", 0, 0, 0, },

        {   NM_ITEM, "View by",             0, 0, 0, 0, },
        {     NM_SUB, "Icon",             "1", 0, 0, 0, },
        {     NM_SUB, NM_BARLABEL,         0 , 0, 0, 0, },
        {     NM_SUB, "Name",             "2", 0, 0, 0, },
        {     NM_SUB, "Date",             "3", 0, 0, 0, },
        {     NM_SUB, "Size",             "4", 0, 0, 0, },
        {     NM_SUB, "Type",             "5", 0, 0, 0, },

        {   NM_ITEM, NM_BARLABEL,           0, 0, 0, 0, },
        {   NM_ITEM, "Find...",           "F", 0, 0, 0, },

        { NM_TITLE, "Icons",               0, 0, 0, 0, },
        {   NM_ITEM, "Open",             "O", 0, 0, 0, },
        {   NM_ITEM, "Copy",             "C", 0, 0, 0, },
        {   NM_ITEM, "Rename...",        "R", 0, 0, 0, },
        {   NM_ITEM, "Information...",   "I", 0, 0, 0, },
        {   NM_ITEM, "Snapshot",         "S", 0, 0, 0, },
        {   NM_ITEM, "Unsnapshot",       "U", 0, 0, 0, },
        {   NM_ITEM, "Leave out",        "L", 0, 0, 0, },
        {   NM_ITEM, "Put away",         "P", 0, 0, 0, },
        {   NM_ITEM, NM_BARLABEL,          0, 0, 0, 0, },
        {   NM_ITEM, "Delete...",          0, 0, 0, 0, },
        {   NM_ITEM, "Format...",          0, 0, 0, 0, },
        {   NM_ITEM, "Empty trash",        0, 0, 0, 0, },

	{ NM_TITLE, "QuickAccess",	   0, 0, 0, 0, },
	{   NM_ITEM,  "WBstartup files",   0, 0, 0, 0, },
	{   NM_ITEM,  "System preferences",  0, 0, 0, 0, },
	{   NM_ITEM,  "System scripts",    0, 0, 0, 0, },
	{   NM_ITEM,  "System tools",      0, 0, 0, 0, },
	{   NM_ITEM,  "System utilities" , 0, 0, 0, 0, },
	{   NM_ITEM,  "System fonts", 	   0, 0, 0, 0, },
	{   NM_ITEM,  "System deficons",   0, 0, 0, 0, },
	{   NM_ITEM,  "System temporary files",   0, 0, 0, 0, },
	{   NM_ITEM,  "Trashcan", 	   0, 0, 0, 0, },
		

        { NM_TITLE, "Tools",           0, 0, 0, 0, },
        {   NM_END, NULL,              0, 0, 0, 0, },
    };

#endif /* AROSbench */
/* gadtoolsmenu.c*/

#define INTUI_V36_NAMES_ONLY

#include <exec/types.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <libraries/gadtools.h>

#include <proto/exec.h>
#include <proto/gadtools.h>
#include <proto/intuition.h>

#include <stdio.h>

struct Library *GadToolsBase;
struct IntuitionBase *IntuitionBase;

struct NewMenu mynewmenu[] =
    {
        { NM_TITLE, "Project",    0 , 0, 0, 0,},
        {  NM_ITEM, "Open...",   "O", 0, 0, 0,},
        {  NM_ITEM, "Save",      "S", 0, 0, 0,},
        {  NM_ITEM, NM_BARLABEL,  0 , 0, 0, 0,},
        {  NM_ITEM, "Print",      0 , 0, 0, 0,},
        {   NM_SUB, "Draft",      0 , 0, 0, 0,},
        {   NM_SUB, "NLQ",        0 , 0, 0, 0,},
        {  NM_ITEM, NM_BARLABEL,  0 , 0, 0, 0,},
        {  NM_ITEM, "Quit...",   "Q", 0, 0, 0,},

        { NM_TITLE, "Edit",       0 , 0, 0, 0,},
        {  NM_ITEM, "Cut",       "X", 0, 0, 0,},
        {  NM_ITEM, "Copy",      "C", 0, 0, 0,},
        {  NM_ITEM, "Paste",     "V", 0, 0, 0,},
        {  NM_ITEM, NM_BARLABEL,  0 , 0, 0, 0,},
        {  NM_ITEM, "Undo",      "Z", 0, 0, 0,},

        {   NM_END, NULL,         0 , 0, 0, 0,},
    };

/* Watch the menus and wait for the user to select the close gadget or quit from the menus. */
VOID handle_window_events(struct Window *win, struct Menu *menuStrip)
{
struct IntuiMessage *msg;
SHORT done;
UWORD menuNumber;
UWORD menuNum;
UWORD itemNum;
UWORD subNum;
struct MenuItem *item;

done = FALSE;
while (FALSE == done)
    {
    /* we only have one signal bit, so we do not have to check which
    ** bit broke the Wait().
    */
    Wait(1L << win->UserPort->mp_SigBit);

    while ( (FALSE == done) &&
            (NULL != (msg = (struct IntuiMessage *)GetMsg(win->UserPort))))
        {
        switch (msg->Class)
            {
            case IDCMP_CLOSEWINDOW:
                done = TRUE;
                break;
            case IDCMP_MENUPICK:
                menuNumber = msg->Code;
                while ((menuNumber != MENUNULL) && (!done))
                    {
                    item = ItemAddress(menuStrip, menuNumber);

                    /* process the item here! */
                    menuNum = MENUNUM(menuNumber);
                    itemNum = ITEMNUM(menuNumber);
                    subNum  = SUBNUM(menuNumber);

                    /* stop if quit is selected. */
                    if ((menuNum == 0) && (itemNum == 5))
                        done = TRUE;

                    menuNumber = item->NextSelect;
                    }
                break;
            }
        ReplyMsg((struct Message *)msg);
        }
    }
}

/*
** Open all of the required libraries and set-up the menus.
*/
VOID main(int argc, char *argv[])
{
struct Window *win;
APTR *my_VisualInfo;
struct Menu *menuStrip;

/* Open the Intuition Library */
IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 37);
if (IntuitionBase != NULL)
    {
    /* Open the gadtools Library */
    GadToolsBase = OpenLibrary("gadtools.library", 37);
    if (GadToolsBase != NULL)
        {
        if (NULL != (win = OpenWindowTags(NULL,
                            WA_Width,  400,       WA_Activate,    TRUE,
                            WA_Height, 100,       WA_CloseGadget, TRUE,
                            WA_Title,  "Menu Test Window",
                            WA_IDCMP,  IDCMP_CLOSEWINDOW | IDCMP_MENUPICK,
                            TAG_END)))
            {
            if (NULL != (my_VisualInfo = GetVisualInfo(win->WScreen, TAG_END)))
                {
                if (NULL != (menuStrip = CreateMenus(mynewmenu, TAG_END)))
                    {
                    if (LayoutMenus(menuStrip, my_VisualInfo, TAG_END))
                        {
                        if (SetMenuStrip(win, menuStrip))
                            {
                            handle_window_events(win,menuStrip);

                            ClearMenuStrip(win);
                            }
                        FreeMenus(menuStrip);
                        }
                    }
                FreeVisualInfo(my_VisualInfo);
                }
            CloseWindow(win);
            }
        CloseLibrary((struct Library *)GadToolsBase);
        }
    CloseLibrary((struct Library *)IntuitionBase);
    }
}

Coder's Clinic 3



   CCCC    OOOO   DDDD   EEEEEE    CCCC  L      IIIII N    N IIIII  CCCC
  C    C  O    O  D   D  E        C    C L        I   NN   N   I   C    C
 C       O      O D    D EEE     C       L        I   N NN N   I  C
  C    C  O    O  D   D  E        C    C L        I   N   NN   I   C    C
   CCCC    OOOO   DDDD   EEEEEE    CCCC  LLLLLL IIIII N    N IIIII  CCCC
--------------------------------------------------------------------------
CODE CLINIC #3                                        I LUV GADGETS!!!  


        As promised, We will add a gadget to our window. First we have to
        get some info on how to do this.

        GADGETS:Two types of gadgets.

        *FIRST TYPE OF GADGET:System                 
        System gadgets are those that you see in the windows and screens
        that you open. And we are  not going to go much further than that.
        
        *SECOND TYPE OF GADGET:Application
        Application gadgets are the ones in which you create and 
                use in your own programs. They can be placed at any 
                location inside the window and can use any image. 
                There are four basic types of application gadgets.

        [1] Boolean    : OK buttons ect...                 
        [2] Proportion : Sound level ect...
        [3] String     : Enter your name ect...                 
        [4] Custom     : New gadgets.
        
       
      *****--------------------------------------------------       
      * N *   I STRONGLY SUGGEST INVESTING IN THE COMPLETE  |
      * O *   SET OF AMIGA ROM KERNEL MANUALS... AT THE     |
      * T *   VERY LEAST YOU SHOULD TRY TO GET THE LIBRARIES|       
      * E *   MANUAL ...THERE ARE MANY EXAMPLES/EXPLANATIONS|       
      *****--------------------------------------------------
                 To create a gadget you simply fill in a Gadget structure. 
        (see fig.�1). You may also use the Gadtools Library to create 
        gadgets (which we will), As you can see the Gadget structure has 
        many items 
        and to cover all these would     struct Gadget                   
        consume a great deal of text    {                                
        as suggested before get the        struct Gadget *NextGadget     
        ROM Kernel manual:Libraries        WORD LeftEdge, TopEdge;       
        (at the very least) as there       WORD Width, Height;           
        is detailed information on all     UWORD Flags;                  
        structures the amiga programmer    UWORD Activation;             
        needs to understand.               UWORD GadgetType;             
                                           APTR GadgetRender;            
        OK lets do something different     APTR SelectRender;            
        like use the Gadtools Library      struct IntuiText *GadgetText; 
        to put some gadgets up on the      LONG MutualExclude;           
        window and let us know which one   APTR SpecialInfo;             
        we selected.                       UWORD GadgetID;               
                                           APTR UserData;                
        Now that we know about the       };                              
        Intuistion gadgets lets take a               FIG. 1              
        look at the Gadtools gadgets.
        
        There are 12 types of gadgets that the Gadtools library supports
        and they are:
        
       Button                 
       String             
       Integer            
       Checkboxes              
       Mutually exclusive 
       Cycle              
       Sliders            
       Scrollers          
       Listviews          
       Palette            
       Text-display       
       Numeric-display    
       
       With all of these types of gads what couldnt you do? And as a real
       bonus there are several GUI buiders on aminet, just look in dev/gui
       and you will see several I personally like GadToolBox by Jan van den
       Baard. These programs take a great deal of coding off of your back 
       and allow you to work on the inner workings of your own program.
       
       Lets take a look a the structure used to create a gadtools gadget:
       
                struct NewGadget                       
                {                                      
                        WORD ng_LeftEdge,ng_TopEdge;  
                        WORD ng_Width,ng_Height;      
                        UBYTE *ng_GadgetText;         
                        struct TextAttr *ng_TextAttr; 
                        UWORD ng_GadgetID;             
                        ULONG ng_Flags;                
                        APTR  ng_VisualInfo;           
                        APTR  ng_UserData;             
                };                                     
                               FIG 2                 
                
                If you compare the Gadget (fig 1) and the NewGadget (fig 2)
        structures you will see some common items.
       
       The way you create a gadget using gadtools is the CreateGadget()
       function, its prototype is:
        
        struct Gadget *CreateGadget(ULONG kind,
                                    struct Gadget *prevgad,
                                    struct NewGadget *newgad,
                                    struct TagItem *taglist);
       so to create a single button gadget we would do it like this:
       
       ng.ng_TextAttr   = &Topaz80;
       ng,ng_VisualInfo = vi;
       ng.ng_LeftEdge   = 10;
       ng.ng_TopEdge    = 10;
       ng.ng_Width      = 60;
       ng.ng_Height     = 12;
       ng.ng_GadgetText = "CLICK";
       ng.ng_GadgetID   = 1;
       ng.ng_Flags      = 0;
       gad = CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);
                                            _____________________________
       If you look at fig 2 you will        []hello__________________[][]
       see that we have filled the          |                           |
       structure and then made a call       |  CLICK  QUIT            |
       to CreateGadget(). The nice          |                           |
       thing is that if you were to         |                           | 
       add another gadget you now only      |                           |
       fill in the items that will          |                           |
       change, an example of this           |                           |
       is given below. Lets add a           |___________________________|
       gadget that has "QUIT" inside                     
       it.                                             FIG 4             
       
       ng.LeftEdge      =80;
       ng.ng_GadgetText ="QUIT";
       ng.ng_GadgetID   =2;
       gad = CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

       and now we would have two gadgets that would look like fig�4
       
       
       The example program was created using the example from the ROM 
       Kernel Manual:Libraries in the chapter Gadtools Library pg.383-385.
       
       I would also like to mention that this layout was written by me and 
       not by a GUI builder... and this is the GUI that we will use to 
       create our AddressBook program.
       
       There are several new items to this code and alot of it you will not
       understand, I will try to clear up any questions in the next issue
       as we will go line by line of this code and explain what is going
       on... 
       
      *****-------------------------  *****-------------------------       
      * N *   ALL CODE IS INTENDED |  * N *   I COMPILED THIS CODE |
      * O *   FOR VERSION 2.0 OR   |  * O *   WITH SAS/C V6.0 AND  |
      * T *   ABOVE...             |  * T *   HAD NO ERRORS OR     |       
      * E *                        |  * E *   WARNINGS             |       
      *****-------------------------  *****-------------------------

//.C..C.O.D.E..............................................................

#include <exec/types.h>
#include <intuition/intuition.h>
#include <intuition/gadgetclass.h>
#include <libraries/gadtools.h>
#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/gadtools_protos.h>
#include <stdio.h>



VOID process_window_events(struct Window *);  VOID gadtoolsWindow(VOID);
VOID Do_Gad(struct Window *mywin,struct Gadget *gad,UWORD code);  BOOL
terminated = FALSE;  struct TextAttr Topaz80 = { "topaz.font",8,0,0,};

struct Library *IntuitionBase; struct Library *GadToolsBase;

void main(void) {
        if ((IntuitionBase = OpenLibrary("intuition.library",37))!=NULL)
           {
           if ((GadToolsBase = OpenLibrary("gadtools.library",37))!=NULL)
              {
              gadtoolsWindow();
              
              CloseLibrary(GadToolsBase);
              }
           CloseLibrary(IntuitionBase);
           } }

VOID gadtoolsWindow(VOID) { struct Screen *mysc; struct Window *mywin;
struct Gadget *glist, *gad; struct NewGadget ng; void   *vi;

glist = NULL;

if ((mysc = LockPubScreen(NULL)) != NULL)
   {
   if ((vi = GetVisualInfo(mysc, TAG_END)) != NULL)
      {
      gad = CreateContext(&glist);
      
      ng.ng_TextAttr    =&Topaz80;
      ng.ng_VisualInfo  =vi;
      
      ng.ng_LeftEdge    =300;
      ng.ng_TopEdge     =2+mysc->WBorTop+(mysc->Font->ta_YSize+1);
      ng.ng_Width       =16;
      ng.ng_Height      =12;
      ng.ng_GadgetText  ="A";
      ng.ng_GadgetID    =1;
      ng.ng_Flags       =0;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge    +=18 ;
      ng.ng_GadgetText  ="B";
      ng.ng_GadgetID    =2;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge    +=18 ;
      ng.ng_GadgetText  ="C";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge    +=18 ;
      ng.ng_GadgetText  ="D";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);      

      ng.ng_LeftEdge    +=18 ;
      ng.ng_GadgetText  ="E";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge    =300;
      ng.ng_TopEdge     +=14;
      ng.ng_GadgetText  ="F";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge    +=18 ;
      ng.ng_GadgetText  ="G";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge    +=18 ;
      ng.ng_GadgetText  ="H";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge    +=18 ;
      ng.ng_GadgetText  ="I";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge    +=18 ;
      ng.ng_GadgetText  ="J";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge    =300;
      ng.ng_TopEdge     +=14;
      ng.ng_GadgetText  ="K";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge    +=18 ;
      ng.ng_GadgetText  ="L";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge    +=18 ;
      ng.ng_GadgetText  ="M";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge    +=18 ;
      ng.ng_GadgetText  ="N";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge    +=18 ;
      ng.ng_GadgetText  ="O";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge    =300;
      ng.ng_TopEdge     +=14;
      ng.ng_GadgetText  ="P";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge    +=18 ;
      ng.ng_GadgetText  ="Q";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge    +=18 ;
      ng.ng_GadgetText  ="R";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge    +=18 ;
      ng.ng_GadgetText  ="S";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge    +=18 ;
      ng.ng_GadgetText  ="T";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge    =300;
      ng.ng_TopEdge     +=14;
      ng.ng_GadgetText  ="U";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge    +=18 ;
      ng.ng_GadgetText  ="V";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge    +=18 ;
      ng.ng_GadgetText  ="W";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge    +=18 ;
      ng.ng_GadgetText  ="X";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge    +=18 ;
      ng.ng_GadgetText  ="Y";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge    =300;
      ng.ng_TopEdge     +=14;
      ng.ng_GadgetText  ="Z";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

      ng.ng_LeftEdge     +=18;
      ng.ng_GadgetText  ="?";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);


      ng.ng_LeftEdge    +=18 ;
      ng.ng_Width       =54;
      ng.ng_GadgetText  ="ADD";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);      

      ng.ng_TopEdge    +=14;
      ng.ng_Width       =54;
      ng.ng_GadgetText  ="QUIT";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);    

      ng.ng_LeftEdge    =10;
      ng.ng_TopEdge     =2+mysc->WBorTop+(mysc->Font->ta_YSize+1);
      ng.ng_Width       =180;
      ng.ng_Height       =12;
      ng.ng_GadgetText  ="BOOL 1";
      ng.ng_GadgetID    ++;
      gad= CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);




      if (gad != NULL)
         {
         if ((mywin = OpenWindowTags(NULL,
                WA_Title,  "PhoneBook V1.0",
                WA_Gadgets, glist,      WA_AutoAdjust, TRUE,
                WA_Width, 400,          WA_InnerHeight, 100,
                WA_DragBar, TRUE,       WA_DepthGadget, TRUE,
                WA_Activate, TRUE,      WA_CloseGadget, TRUE,
                WA_IDCMP, IDCMP_CLOSEWINDOW | 
                          IDCMP_REFRESHWINDOW | 
                          BUTTONIDCMP,
                WA_PubScreen, mysc,
                TAG_END)) != NULL)
                  {
                  GT_RefreshWindow(mywin,NULL);
                  
                  process_window_events(mywin);
                  
                  CloseWindow(mywin);
                  
                  }
         }
        FreeGadgets(glist);
        FreeVisualInfo(vi);
        }
      UnlockPubScreen(NULL,mysc);
      } }

VOID process_window_events(struct Window *mywin) { struct IntuiMessage
*imsg; ULONG  class; UWORD  code; struct Gadget *gad;


while (!terminated)
        {
        Wait(1<< mywin->UserPort->mp_SigBit);
        while ((!terminated) && (imsg = GT_GetIMsg(mywin->UserPort)))
           {
           gad = (struct Gadget *)imsg->IAddress;
           class=imsg->Class;
           code =imsg->Code;
           
           switch (class)
              {
              case IDCMP_GADGETUP:
                                  Do_Gad(mywin,gad,code);
                                  break;
      
              case IDCMP_CLOSEWINDOW:
                                  terminated = TRUE;
                                  break;
              case IDCMP_REFRESHWINDOW:
                                  GT_BeginRefresh(mywin);
                                  GT_EndRefresh(mywin,TRUE);
                                  break;
              }
              GT_ReplyIMsg(imsg);
       }
   } } VOID Do_Gad(struct Window *mywin,struct Gadget *gad,UWORD code) {
switch(gad->GadgetID)
        {
        case 1:printf("A\n");
               break;
        case 2:printf("B\n");
               break;
        case 3:printf("C\n");
               break;
        case 4:printf("D\n");
               break;
        case 5:printf("E\n");
               break;
        case 6:printf("F\n");
               break;
        case 7:printf("G\n");
               break;
        case 8:printf("H\n");
               break;
        case 9:printf("I\n");
               break;
        case 10:printf("J\n");
               break;
        case 11:printf("K\n");
               break;
        case 12:printf("L\n");
               break;
        case 13:printf("M\n");
               break;
        case 14:printf("N\n");
               break;
        case 15:printf("O\n");
               break;
        case 16:printf("P\n");
               break;
        case 17:printf("Q\n");
               break;
        case 18:printf("R\n");
               break;
        case 19:printf("S\n");
               break;
        case 20:printf("T\n");
               break;
        case 21:printf("U\n");
               break;
        case 22:printf("V\n");
               break;
        case 23:printf("W\n");
               break;
        case 24:printf("X\n");
               break;
        case 25:printf("Y\n");
               break;
        case 26:printf("Z\n");
               break;
        case 29:printf("TERMINATE\n");
                terminated = TRUE;
                break;
        }  }


// End C Code

References edit

Some code relies on AOS implementation of gadtools library which uses fake (non-boopsi) gadgets where especially the more complex ones (listview) have most gadget (input) handling done in the GT_GetImsg/GT_FitlerImsg() funcs. In AROS gadtools library uses real boopsi gadgets and therefore behaves differently.

struct Gadget *CreateGadgetA(ULONG kind, struct Gadget *previous, struct NewGadget *ng, struct TagItem *taglist) 
void FreeGadgets(struct Gadget *glist)
void GT_SetGadgetAttrsA(struct Gadget *gad, struct Window *win, struct Requester *req, struct TagItem *tagList) 
struct Menu *CreateMenusA(struct NewMenu *newmenu, struct TagItem *tagList) 
void FreeMenus(struct Menu *menu) 
BOOL LayoutMenuItemsA(struct MenuItem *menuitem, APTR vi, struct TagItem *tagList) 
BOOL LayoutMenusA(struct Menu *menu, APTR vi, struct TagItem *tagList) 
struct IntuiMessage *GT_GetIMsg(struct MsgPort *intuiport) 
void GT_ReplyIMsg(struct IntuiMessage *imsg) 
void GT_RefreshWindow(struct Window *win, struct Requester *req) 
void GT_BeginRefresh(struct Window *win) 
void GT_EndRefresh(struct Window *win, BOOL complete) 
struct IntuiMessage *GT_FilterIMsg(struct IntuiMessage *imsg)
struct IntuiMessage *GT_PostFilterIMsg(struct IntuiMessage *modimsg) 
struct Gadget *CreateContext(struct Gadget **glistpointer) 
void DrawBevelBoxA(struct RastPort *rport, WORD left, WORD top, WORD width, WORD height, struct TagItem *taglist) 
APTR GetVisualInfoA(struct Screen *screen, struct TagItem *tagList) 
void FreeVisualInfo(APTR vi)

LONG GT_GetGadgetAttrsA(struct Gadget *gad, struct Window *win, struct Requester *req, struct TagItem *taglist) 

The first few items in each option can be altered after being created.

GA_Immediate and GA_RelVerify are tags, GACT_IMMEDIATE and GACT_RELVERIFY are flags used for the Activation field of struct Gadget.

CreateGadgetA Taglists

GT_Underscore - Indicates the symbol that precedes the character in the gadget label to be underscored. This can be to indicate keyboard equivalents for gadgets (note that GadTools does not process the keys - just displays the underscore).

BUTTON_OPTION (action buttons):

GA_Disabled (BOOL) - Set to TRUE to disable gadget, FALSE otherwise (default FALSE).

GA_Immediate (BOOL) - Hear IDCMP_GADGETDOWN events from button gadget (default FALSE). 

CHECKBOX_OPTION (on/off items):

GA_Disabled (BOOL) - Set to TRUE to disable gadget, FALSE otherwise (default FALSE).
GTCB_Checked (BOOL) - Initial state of checkbox (default FALSE)

GTCB_Scaled (BOOL) - If true, then checkbox imagery will be scaled to fit the gadget's width & height.  Otherwise, a fixed size of CHECKBOXWIDTH by CHECKBOXHEIGHT will be used. (default FALSE)

CYCLEOPTION (multiple state selections):

GA_Disabled (BOOL) - Set to TRUE to disable gadget, FALSE otherwise (default FALSE). 
GTCY_Labels (STRPTR *) - Pointer to NULL-terminated array of strings that are the choices offered by the cycle gadget. This tag is required. 
GTCY_Active (UWORD) - The ordinal number (counting from zero) of the initially active choice of a cycle gadget (default zero).

INTEGER_OPTION (numeric entry):

GA_Disabled (BOOL) - Set to TRUE to disable gadget, FALSE otherwise (default FALSE). 
GTIN_Number (LONG) - The initial contents of the integer gadget (default 0).

GA_Immediate (BOOL) - Hear IDCMP_GADGETDOWN events from integer gadget (default FALSE). 
GA_TabCycle (BOOL) - Set to TRUE so that pressing  or will activate the next or previous such gadget. (default TRUE).
GTIN_MaxChars (UWORD) - The maximum number of digits that the integer gadget is to hold (defaults to 10). 
GTIN_EditHook (struct Hook *) - Hook to use as a custom integer gadget edit hook (StringExtend->EditHook) for this gadget. GadTools will allocate the StringExtend->WorkBuffer for you. (default NULL). 
STRINGA_ExitHelp (BOOL) - Set to TRUE to have the help-key cause an exit from the integer gadget.  You will then receive an IDCMP_GADGETUP event with Code = 0x5F (rawkey for help). (default FALSE) 
STRINGA_Justification - Controls the justification of the contents of an integer gadget.  Choose one of STRINGLEFT, STRINGRIGHT, or STRINGCENTER (defaults to STRINGLEFT). 
STRINGA_ReplaceMode (BOOL) - If TRUE, this integer gadget is in replace-mode (default FALSE (insert-mode)). 

LISTVIEW_OPTION (scrolling list):

GA_Disabled (BOOL) - Set to TRUE to disable gadget, FALSE otherwise (default FALSE). 
GTLV_Top (WORD) - Top item visible in the listview.  This value will be made reasonable if out-of-range (default 0). 
GTLV_Labels (struct List *) - List of nodes whose ln_Name fields are to be displayed in the listview. 
GTLV_Selected (UWORD) - Ordinal number of currently selected item, or 0 to have no current selection (default 0).

GTLV_MakeVisible (WORD) - Number of an item that should be forced within the visible area of the listview by doing minimal scrolling. This tag overrides GTLV_Top. 
GTLV_ReadOnly (BOOL) - If TRUE, then listview is read-only (default FALSE). 
GTLV_ScrollWidth (UWORD) - Width of scroll bar for listview. Must be greater than zero (default 16). 
GTLV_ShowSelected (struct Gadget *) - NULL to have the currently selected item displayed beneath the listview under V37 or with a highlight bar in V39. If not NULL, this is a pointer to an already-created GadTools STRING_KIND gadget to have an editable display of the currently selected item. If the tag is not present, the currently selected item will not be displayed. 
LAYOUTA_Spacing (UWORD) - Extra space to place between lines of listview (default 0). 
GTLV_ItemHeight (UWORD) - The exact height of an item. This is normally useful for listviews that use the GTLV_CallBack 	    rendering hook (defaults to ng->ng_TextAttr->ta_YSize). 
GTLV_CallBack (struct Hook *) - Callback hook for various listview operations. Only callback supported is for custom rendering of individual items in the listview. The call back hook is called with:
		A0 - struct Hook *
		A1 - struct LVDrawMsg *
		A2 - struct Node *
The callback hook *must* check the lvdm_MethodID field of the message and only do processing if it equals LV_DRAW. If any other value is passed, the callback hook must return LVCB_UNKNOWN 
GTLV_MaxPen (UWORD) - The maximum pen number used by rendering in a custom rendering callback hook. This is used to optimize the rendering and scrolling of the listview display (default being the maximum pen number used by all of TEXTPEN, BACKGROUNDPEN, FILLPEN, TEXTFILLPEN, and BLOCKPEN. 

MX_OPTION (mutually exclusive, radio buttons):

GA_Disabled (BOOL) - Set to TRUE to disable gadget, FALSE otherwise (default FALSE).
GTMX_Active (UWORD) - The ordinal number (counting from zero) of the initially active choice of an mx gadget (default 0).

GTMX_Labels (STRPTR *) - Pointer to a NULL-terminated array of strings which are to be the labels beside each choice in a set of mutually exclusive gadgets. This tag is required 
GTMX_Spacing (UWORD) - The amount of space between each choice of a set of mutually exclusive gadgets.  This amount is added  to the font height to produce the vertical shift between choices (default 1). 
GTMX_Scaled (BOOL) - If true, then mx gadget imagery will be scaled to fit the gadget's width & height.  Otherwise, a fixed size of MXWIDTH by MXHEIGHT will be used. When setting this tag to TRUE, should typically set the height of the gadget to be (ng.ng_TextAttr->ta_YSize + 1). (default FALSE.) 
GTMX_TitlePlace - One of PLACETEXT_LEFT, PLACETEXT_RIGHT, PLACETEXT_ABOVE, or PLACETEXT_BELOW, indicating where the title of the gadget is to be displayed. Without this tag, the NewGadget.ng_GadgetText field is ignored for MX_OPTION gadgets.

LAYOUTA_Spacing - FOR COMPATIBILITY ONLY.  Use GTMX_Spacing instead. The number of extra pixels to insert between each choice of a mutually exclusive gadget.  This is added to the present gadget image height (9) to produce the true spacing between choices. (default FontHeight-8, which is zero for 8-point font users). 

NUMBER_OPTION (read-only numeric):

GTNM_Number (LONG) - A signed long integer to be displayed as a read-only number (default 0).

GTNM_Border (BOOL) - If TRUE, this flag asks for a recessed border to be placed around the gadget. 
GTNM_FrontPen (UBYTE) - The pen to use when rendering the number (default DrawInfo->dri_Pens[TEXTPEN]). 
GTNM_BackPen (UBYTE) - The pen to use when rendering the background of the number (defaults to leaving the background untouched). 
GTNM_Justification (UBYTE) - Determines how the number is rendered within the gadget box. GTJ_LEFT will make the rendering be flush with the left side of the gadget, GTJ_RIGHT will make it flush with the right side, and GTJ_CENTER will center the number within the gadget box. (default GTJ_LEFT). 
GTNM_Format (STRPTR) - C-Style formatting string to apply on the number before display. Be sure to use the 'l' (long) modifier. This string is processed using exec.library/RawDoFmt(), so refer to that function for details. (default "%ld") 
GTNM_MaxNumberLen (ULONG) - Maximum number of bytes that can be generated by applying the GTNM_Format formatting string to the number (excluding the NULL terminator). (default 10). 
GTNM_Clipped (BOOL) - Determine whether text should be clipped to the gadget dimensions (defaults to FALSE for gadgets without borders, TRUE for gadgets with borders). 

PALETTE_OPTION (color selection):

GA_Disabled (BOOL) - Set to TRUE to disable gadget, FALSE otherwise (default FALSE). 
GTPA_Color (UBYTE) - Initially selected color of the palette. This number is a pen number, and not the ordinal color number within the palette gadget itself. (default 1). 
GTPA_ColorOffset (UBYTE) - First color to use in palette (default 0).
GTPA_ColorTable (UBYTE *) - Pointer to a table of pen numbers indicating  which colors should be used and edited by the palette gadget. This array must contain as many entries as there are colors displayed in the palette gadget. The array provided with this tag must remain valid for the life of the gadget or until a new table is provided. (default NULL, which causes a 1-to-1 mapping of pen numbers).

GTPA_Depth (UWORD) - Number of bitplanes in the palette (default 1). 
GTPA_IndicatorWidth (UWORD) - The desired width of the current-color indicator, if you want one to the left of the palette. 
GTPA_IndicatorHeight (UWORD) - The desired height of the current-color indicator, if you want one above the palette. 
GTPA_NumColors (UWORD) - Number of colors to display in the palette gadget. This override GTPA_Depth and allows numbers which are not powers of 2. (default 2) 

SCROLLER_OPTION (for scrolling through areas or lists):

GA_Disabled (BOOL) - Set to TRUE to disable gadget, FALSE otherwise (default FALSE). 
GTSC_Top (WORD) - Top visible in area scroller represents (default 0). 
GTSC_Total (WORD) - Total in area scroller represents (default 0). 
GTSC_Visible (WORD) - Number visible in scroller (default 2).

GA_RelVerify (BOOL) - Hear every IDCMP_GADGETUP event from scroller (default FALSE). 
GA_Immediate (BOOL) - Hear every IDCMP_GADGETDOWN event from scroller (default FALSE). 
GTSC_Arrows (UWORD) - Asks for arrows to be attached to the scroller. The value supplied will be taken as the width of each arrow button for a horizontal scroller, or the height of each button for a vertical scroller (the other dimension will match the whole scroller).

PGA_Freedom - Whether scroller is horizontal or vertical. Choose LORIENT_VERT or LORIENT_HORIZ (default LORIENT_HORIZ).

SLIDER_OPTION (to indicate level or intensity):

GA_Disabled (BOOL) - Set to TRUE to disable gadget, FALSE otherwise (default FALSE). 
GTSL_Min (WORD) - Minimum level for slider (default 0).  
GTSL_Max (WORD) - Maximum level for slider (default 15). 
GTSL_Level (WORD) - Current level of slider (default 0).

GA_RelVerify (BOOL) - If you want to hear each slider IDCMP_GADGETUP event (default FALSE). 
GA_Immediate (BOOL) - If you want to hear each slider IDCMP_GADGETDOWN event (default FALSE). 
GTSL_MaxLevelLen (UWORD) - Maximum length in characters of level string when rendered beside slider (default 2). 
GTSL_LevelFormat (STRPTR) - C-Style formatting string for slider level.  Be sure to use the 'l' (long)  modifier.  This string is processed using exec.library/RawDoFmt(), so refer to that function for details. (default "%ld"). 
GTSL_LevelPlace - One of PLACETEXT_LEFT, PLACETEXT_RIGHT, PLACETEXT_ABOVE, or PLACETEXT_BELOW, indicating where the level indicator is to go relative to slider (default to PLACETEXT_LEFT). 
GTSL_DispFunc ( LONG (*function)(struct Gadget *, WORD) ) - To calculate level to be displayed.  A number-of-colors slider might want to set the slider up to think depth, and have a (1 << n) function here. No Default  Your function must take a pointer to gadget as the first parameter, the level (a WORD) as the second, and return the result as a LONG. 
GTSL_MaxPixelLen (ULONG) - Indicates the maximum pixel size used up by the level display for any value of the slider. This is mostly useful when dealing with proportional fonts. (default FontWidth*MaxLevelLen). 
GTSL_Justification (UBYTE) - Determines how the level display is to be justified within its alotted space. Choose one of GTJ_LEFT, GTJ_RIGHT, or GTJ_CENTER (default GTJ_LEFT).

PGA_Freedom - Set to LORIENT_VERT or LORIENT_HORIZ to have a vertical or horizontal slider (defaults to LORIENT_HORIZ). 

STRING_OPTION (text-entry):

GA_Disabled (BOOL) - Set to TRUE to disable gadget, FALSE otherwise (default FALSE). 
GTST_String (STRPTR) - The initial contents of the string gadget, or NULL (default) if string is to start empty. 
GA_Immediate (BOOL) - Hear IDCMP_GADGETDOWN events from string gadget (default FALSE). 
GA_TabCycle (BOOL) - Set to TRUE so that pressing  or will activate the next or previous such gadget. (defaults to TRUE, unlike regular Intuition string gadgets which default FALSE).
GTST_MaxChars (UWORD) - The maximum number of characters that the string gadget is to hold. 
GTST_EditHook (struct Hook *) - Hook to use as a custom string gadget edit hook (StringExtend->EditHook) for this gadget. GadTools will allocate the StringExtend->WorkBuffer for you. (default NULL).
STRINGA_ExitHelp (BOOL) - Set to TRUE to have the help-key cause an exit from the string gadget.  You will then receive an IDCMP_GADGETUP event with Code = 0x5F (rawkey for help).
STRINGA_Justification - Controls the justification of the contents of a string gadget.  Choose one of STRINGLEFT, STRINGRIGHT, or STRINGCENTER (default STRINGLEFT). 
STRINGA_ReplaceMode (BOOL) - If TRUE, this string gadget is in replace-mode (defaults to FALSE (insert-mode)). 

TEXT_OPTION (read-only text):

GTTX_Text - Pointer to a NULL terminated string to be displayed, as a read-only text-display gadget, or NULL. (default NULL)

GTTX_CopyText (BOOL) -	This flag instructs the text-display gadget to copy the supplied text string, instead of using only pointer to the string.  This only works for the initial value of GTTX_Text set at CreateGadget() time.  If you subsequently change GTTX_Text, the new text will be referenced by pointer, not copied.  Do not use this tag with a NULL GTTX_Text. 
GTTX_Border (BOOL) - If TRUE, this flag asks for a recessed border to be placed around the gadget. 
GTTX_FrontPen (UBYTE) - The pen to use when rendering the text (default DrawInfo->dri_Pens[TEXTPEN]). 
GTTX_BackPen (UBYTE) - The pen to use when rendering the background of the text (defaults to leaving the background untouched).
GTTX_Justification (UBYTE) - Determines how the text is rendered within the gadget box. GTJ_LEFT will make the rendering be flush with the left side of the gadget, GTJ_RIGHT will make it flush with the right side, and GTJ_CENTER will center the text within the gadget box. (default GTJ_LEFT).
GTTX_Clipped (BOOL) - Determine whether text should be clipped to the gadget dimensions (defaults to FALSE for gadgets without borders, TRUE for gadgets with borders). 

LayoutGadgetTags

GTMN_Menu (struct Menu *) - Pointer to the Menu structure whose FirstItem is the MenuItem supplied. If the menu items are such that they need to be columnized or shifted, the Menu structure is needed to perform the complete calculation. For the following tags, please see the description under LayoutMenusA().  Their behavior is identical when used in LayoutMenuItemsA(). 
	    GTMN_TextAttr
	    GTMN_NewLookMenus
	    GTMN_Checkmark
	    GTMN_AmigaKey
	    GTMN_FrontPen

Trying to manually open gadtools in the console code (for menus). I need it to be opened manually, because it *will* fail for the boot shell (see below), so I need to handle the case where it's not available. It seems to me that auto-opening non-resident libraries during boot is a really bad idea... Will lots of stuff break if that's turned off? Alternatively, is there a method to prevent auto-opening on a case by case basis? IIRC you just need to declare the base pointer manually. This will prevent from getting it (and associated library opening code) from libautoinit. With programs it works. I think it works with residents. The autoinit code is linked in by the libbase variable. E.g. the autoinit code defined the global libbase variable of a library. If you define 'struct Library *GadToolsBase' somewhere in your code as a global variable the autoinit code won't be linked in. Please, only use it when really needed and put proper comments why it is needed. The specific case here is avoiding duplicating a bunch of menu-layout code from gadtools in the console code to add menus to the console windows without requiring gadtools to be linked into the kernel. It means the boot shell won't get the menu, but I think that's a fair enough trade off vs. making things really messy.

And it's only called in when global library bases are used at all, which shouldn't be the case with romable code, should it? That's something I didn't think about. Do I mess up stuff if I declare a global GadToolsBase, or are bss properly handled? If it messes things up, are there alternative ways of preventing the auto-opening? (committed a basic menu structure for the console handler that uses a global GadToolsBase).

It's non-optimal, actually, since on m68k the only 'know to always exist' memory for the .bss is in Chip RAM, which is both precious and dog slow (due to contention with video and audio operations). For this usage it's probably fine, but if you can find a way to allocate it in a structure that the console handler passes around (con_base?) and dereference it from there, it's probably a better way to do. AllocMem() memory allocates from the highest priority first. See rom/devs/filesys/AmberRAM/handler.h's 'struct Handler', and the macros that immediately follow it for an example of how to do this. The console handler does already put lots of stuff in it's handler data structure, so if there is a way I can suppress auto-opening without a global variable, it's trivial enough to put it in there.

Is there a good reference somewhere on all the things I need to take care of during a NEWWINDOWSIZE event? You probably know this already, but NEWWINDOWSIZE doesn't block until ReplyMsg() like SIZEVERIFY.

Endian issues

There may be method structs in the code which uses WORD for some of the (coord) fields and then when calling the method it does something like gDoClassMethod(... , (x << 16) | (y & 0xffff), ...). This relies on big endianess and therefore fails on x86.