#include "microdot.h"

#include <proto/graphics.h>
#include <intuition/sghooks.h>
#include <devices/conunit.h>
#include <proto/gadtools.h>
#include <intuition/gadgetclass.h>
#include <intuition/imageclass.h>
#include <dos/dostags.h>
#include <proto/commodities.h>

#include <proto/keymap.h>

#include "ogre.h"

#include <constructor.h>

/*#define GetIMsg(p) (struct IntuiMessage*)GetMsg(p)*/

/* use lib version */
//#undef memcpy

/*void __stdargs sprintf( char *, char *, ... );*/

#define getrawkeycode ogregetrawkeycode
#define makebevelborder ogremakebevelborder

#include <constructor.h>
static char *undobuffer;

ALLOCSTATIC( undobuffer, 8192, 0 )

struct ogwin {
	void	*pool;			/* Memory Pool */
	ULONG	flags, idcmp;	/* NewWindow Flags & IDCMP */
	char	*title;			/* Window Title */
	struct 	Screen *scr;	/* Screen to open on */
	struct	MinList	groups;	/* Groups */
	struct	TextFont *font;	/* Screen Font */
	struct	TextAttr *fnta;	/* Screen Font as TextAttr */
	struct  TextFont *used_font;
	struct  TextAttr *used_fnta;
	struct  TextAttr *lvfnta;
	struct  TextFont *lvfont;
	ULONG	fontxsize;		/* Maximum fontxsize of current used font */
	UWORD	pens[9];		/* Draw Pens */
	UBYTE	usesgadtools;	/* Set if uses gadtools */
	UBYTE	hascursorlv;	/* Cursor key controllable Listview ID */
	UWORD	screenx, screeny; 	/* Size of Screen */
	struct  oggroup *currentg;	/* Current Group */
	struct	Window *w;			/* ptr to Window, if open */
	UWORD	windowx, windowy;	/* Suggested Window Size */
	UWORD	windowxoffs, windowyoffs;
	struct 	Gadget *glist;		/* Gadget List */
	char	*string_workbuffer;
	struct  Gadget *gtglist;
	struct	Gadget *gtlastg;
	struct  VisualInfo *vi;
	struct	DrawInfo *dri;
	BOOL	has_down;
	BOOL	windowlocked;
	void 	*windowlock;
	struct  ogobj *helpgad;
	struct	TextAttr underline_fnta;	/* Underlined font */
	struct	IntuiMessage cim;	/* Copy of current IntuiMessage */
};

struct oggroup {
	struct	MinNode	n;		/* Link Node */
	UWORD	x, y, xs, ys;	/* Coordinates and size */
	UBYTE	py;				/* Virtual Position */
	UBYTE	ycl;			/* Anger Layout ;-) */
	UBYTE   keepsize;
	UBYTE   frame;
	UBYTE	ogp;			/* Special Pos Flags */
	UBYTE	objoffsx, objoffsy;	/* Object Offsets for frame */
	UBYTE	__pad;
	char	*title;
	struct	MinList	obj;	/* List of objects in Group */
};

struct ogobj {
	struct	MinNode	n;		/* Link Node */
	UWORD	x, y, xs, ys;
	UBYTE	py;				/* Virtual Position */
	UBYTE	type;			/* Type of Object */
	UBYTE	keepsize;
	UBYTE	shortcut;
	UWORD	rxs, rys;
	UWORD	id;				/* GadgetID */
	char	*title;
	UWORD	maxchars;		/* String/Integer */
	UWORD	xchars, ychars;	/* String/Int/LV */
	UBYTE	isgadtools;		/* Set if from Gadtools */
	UBYTE	flags;
	ULONG	disable;		/* Enable Flag */
	char	*defaultstring;	/* String */
	ULONG	defaultvalue;	/* rest */
	char	**entries;
	struct  IntuiText *it_t; /* Title IText */
	struct	IntuiText *it_c; /* Contents IText */
	struct	Image	*im;
	struct  Gadget *g;		/* Gadget */
	struct 	Gadget *img;	/* Image Gadget of ListView */
	struct  Gadget *scroll; /* Scroller of ListView */
	struct  Gadget *bordg;  /* Border of ListView */
	struct  List *l;		/* Listview List */
	WORD	top;
	UWORD	num;
	long	minval, maxval;
	struct	Border *b_f;	/* Framing Border */
	struct  Border *b_b; 	/* Box Border */
	UBYTE	on_esc, on_enter;
	LONG    oldxp;
};


#ifdef MDV20
#define ISV37 1
#define ISV39 2
#else
#define ISV37 isv37
#define ISV39 isv39
#endif

#undef GetIMsg

static struct IntuiMessage *GetIMsg( struct MsgPort *p )
{
	return( ( ISV37 ) ? GT_GetIMsg( p ) : ( struct IntuiMessage * ) GetMsg( p ) );
}

static void ReplyIMsg( struct IntuiMessage *m )
{
	( ISV37 ) ? GT_ReplyIMsg( m ) : ReplyMsg( m );
}

#define OGALLOC(og,size) LibAllocPooled(og->pool,size)

static void calcfontxsize( struct ogwin *ogw )
{
	UWORD *fontdata = ogw->used_font->tf_CharSpace;
	int fc = ogw->used_font->tf_HiChar - ogw->used_font->tf_LoChar + 1;
	int maxs = 0;
	int c;

	if( ! ( ogw->used_font->tf_Flags & FPF_PROPORTIONAL ) )
	{
		ogw->fontxsize = ogw->used_font->tf_XSize;
		return;
	}

	for( c = 0; c < fc; c++ )
	{
		if( fontdata[ c ] > maxs )
			maxs = fontdata[ c ];
	}
	ogw->fontxsize = ( maxs + ogw->used_font->tf_XSize + ogw->used_font->tf_XSize ) / 3;

}


static int getrawkeycode( char ch )
{
	int c;
	UBYTE cmp[4];
	UBYTE *dead;
	static struct KeyMap conkeymap;

	if( ISV37 )
	{
		c = MapANSI( &ch, 1, cmp, 1, NULL );
		if( c > 0 )
		{
			c = cmp[0];
			if( cmp[1] & ( IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT ) )
				c |= 0x80;
			return( c );
		}
		return( 0 );
	}

	if( !conkeymap.km_LoKeyMapTypes )
	{
		struct IOStdReq confakereq;

		memset( &confakereq, 0, sizeof( confakereq ) );
		/* Init Console Base */
		confakereq.io_Message.mn_ReplyPort = CreatePort( NULL, NULL );
		OpenDevice( "console.device", CONU_LIBRARY, &confakereq, 0 );
		/*ConsoleDevice = confakereq.io_Device;*/
		confakereq.io_Data = &conkeymap;
		confakereq.io_Length = sizeof( conkeymap );
		confakereq.io_Command = CD_ASKDEFAULTKEYMAP;
		DoIO( &confakereq );
		CloseDevice( &confakereq );
		DeletePort( confakereq.io_Message.mn_ReplyPort );
	}

	for( c = 0; c < 64; c++ )
	{

		/*if( ( conkeymap.km_LoKeyMapTypes[c] & KC_VANILLA ) != KC_VANILLA )
			continue;*/
		if( conkeymap.km_LoKeyMapTypes[c] & KCF_STRING )
			continue;

		if( conkeymap.km_LoKeyMapTypes[c] & KCF_DEAD )
		{
			int pn, d, offs;
			UBYTE *dp;

			memcpy( &dead, &conkeymap.km_LoKeyMap[c], 4 );

			pn = ( conkeymap.km_LoKeyMapTypes[ c ] & 7 ) + 1;
			dp = dead;

			for( d = 0; d < pn; d++ )
			{
				switch( *dead++ )
				{
					case 0:
						if( *dead++ == ch )
							return( d ? ( c | 0x80 ) : c );
						break;

					case DPF_MOD:
						offs = *dead++;
						if( dp[ offs ] == ch )
							return( d ? ( c | 0x80 ) : c );
						break;

					case DPF_DEAD:
						dead++;
						break;
				}
			}
		
		}
		else
		{
			memcpy( cmp, &conkeymap.km_LoKeyMap[c], 4 );
			if( cmp[3] == ch )
			{
				return( c );
			}
			if( cmp[2] == ch )
			{
				return( c | 0x80 );
			}
		}
	}

	return( 0 );
}


static ULONG textfit( struct ogwin *ogw, char *txt, UWORD space )
{
	struct TextExtent tex;
	struct RastPort rp;

	if( !txt || !txt[0] )
		return( 0 );

	if( !ISV37 )
	{
		return( (ULONG) min( strlen( txt ), space / ( ogw->used_font->tf_XSize ) ) );
	}

	/* Clone Rastport */
	rp = ogw->scr->RastPort;
	if( ISV39 )
		SetABPenDrMd( &rp, 1, 0, JAM1 );
	else
	{
		SetAPen( &rp, 1 );
		SetDrMd( &rp, JAM1 );
	}
	SetFont( &rp, ogw->used_font );
	return( TextFit( &rp, txt, strlen( txt ), &tex, NULL, 1, space, ogw->used_font->tf_YSize + 1 ) );
}

int ogreTextFit( struct TextFont *tf, char *txt, UWORD space )
{
	struct TextExtent tex;
	struct RastPort rp;

	if( !txt || !txt[0] )
		return( 0 );

	if( !ISV37 )
	{
		return( ( int ) min( strlen( txt ), space / ( tf->tf_XSize ) ) );
	}

	InitRastPort( &rp );
	SetFont( &rp, tf );
	return( ( int ) TextFit( &rp, txt, strlen( txt ), &tex, NULL, 1, space, tf->tf_YSize ) );
}

void ogreExitWindow( struct ogwin *og )
{
	if( !og )
		return;
	if( og->w )
		CloseWindow( og->w );
	if( og->usesgadtools && og->gtglist )
		FreeGadgets( og->gtglist );
	if( og->dri )
		FreeScreenDrawInfo( og->scr, og->dri );
	if( og->vi )
		FreeVisualInfo( og->vi );
	if( og->pool )
		LibDeletePool( og->pool );
	/*FreeMem( og, sizeof( *og ) );*/
}

extern struct TextFont *listfont;
extern struct TextAttr realfontta;

void * ogreInitWindow(	struct Screen *scr,
						ULONG flags,
					   	ULONG idcmp,
						char  *title)
{
	struct ogwin *og;
	struct DrawInfo *dri;
	APTR pool;

	pool = LibCreatePool( MEMF_CLEAR | MEMF_PUBLIC, 8192, 2048 );
	if( !pool )
		return( NULL );

	og = LibAllocPooled( pool, sizeof( *og ) );
	if( !og )
		return( NULL );
	NewList( (struct List *) &og->groups );
	og->pool = pool;

	og->flags = flags;
	og->idcmp = idcmp;
	og->title = title;
	og->scr	  = scr;
	og->fnta  = og->used_fnta  = scr->Font;
	og->screenx = scr->Width;
	og->screeny = scr->Height;

	/* Init Pens, 1.3 Style */
	if( !ISV37 )
	{
		og->font = og->used_font = OpenFont( og->used_fnta );
		if( og->used_font )
			CloseFont( og->used_font );
		/* Font won't go away since OpenScreen() opened it */

		og->pens[ DETAILPEN ] = scr->DetailPen;
		og->pens[ BLOCKPEN ]  = scr->BlockPen;
		og->pens[ TEXTPEN ]   = 1;
		og->pens[ SHINEPEN ]  = 1;
		og->pens[ SHADOWPEN ] = 2;
		og->pens[ FILLPEN ]	  = 3;
		og->pens[ FILLTEXTPEN ] = 2;
		og->pens[ BACKGROUNDPEN ] = 0;
		og->pens[ HIGHLIGHTTEXTPEN ] = 3;

	}
	/* 2.0, obtain Pens via DrawInfo */
	else
	{
		og->dri = dri = GetScreenDrawInfo( scr );
		if( !dri )
		{
			ogreExitWindow( og );
			return( NULL );
		}
		og->font = og->used_font = dri->dri_Font;
		memcpy( og->pens, dri->dri_Pens, 9 * 2 );
	}

	calcfontxsize( og );

	/* Init LV fonts */
	if( !( og->used_font->tf_Flags & FPF_PROPORTIONAL ) ) 
	{
		og->lvfont = og->used_font;
		og->lvfnta = og->used_fnta;
	}
	else
	{
		og->lvfont = listfont;
		og->lvfnta = &realfontta;
	}

	return( og );
}

void ogreAddGroup(	struct ogwin *ogwin,
					UBYTE py,
					UBYTE frame,
					char *title )
{
	struct oggroup *ogg;

	ogg = OGALLOC( ogwin, sizeof( *ogg ) );
	if( !ogg )
		return;

	ogg->py = ogg->ycl = py & 0x7f;
	ogg->ogp = py & OGGP_EXPANDSTRING;
	ogg->frame = frame;
	ogg->title = title;

	NewList( (struct List *) &ogg->obj );

	/* Add to Group list */
	AddTail( (struct List*) &ogwin->groups, (struct Node *) ogg );
	ogwin->currentg = ogg;

}

void ogreAddButton(	struct ogwin *ogwin,
					UBYTE py,
					UBYTE shortcut,
					char *title,
					UWORD id )
{
	struct ogobj *obj;

	if( !ogwin->currentg )
		return;

	obj = OGALLOC( ogwin, sizeof( *obj ) );
	if( !obj )
		return;

	ogwin->idcmp |= IDCMP_GADGETUP;

	obj->type = OGOBJ_BUTTON;
	obj->py	= py & 31;
	obj->on_esc = py & OGB_ONESC;
	obj->on_enter = py & OGB_ONENTER;
	obj->keepsize = py & OGGP_KEEPSIZE;
	obj->shortcut = shortcut;
	obj->title = title;
	obj->id	= id;

	AddTail( (struct List *) &ogwin->currentg->obj, (struct Node *) obj );
}

void ogreAddFuelGauge(	struct ogwin *ogwin,
					UBYTE py,
					UWORD id,
					ULONG maxval )
{
	struct ogobj *obj;

	if( !ogwin->currentg )
		return;

	obj = OGALLOC( ogwin, sizeof( *obj ) );
	if( !obj )
		return;

	obj->type = OGOBJ_FUELGAUGE;
	obj->py	= py;
	obj->id	= id;
	obj->maxval = max( 1, maxval );

	AddTail( (struct List *) &ogwin->currentg->obj, (struct Node *) obj );
}

void ogreAddCheckbox(	struct ogwin *ogwin,
					UBYTE py,
					UBYTE shortcut,
					char *title,
					UWORD id,
					int val )
{
	struct ogobj *obj;

	if( !ogwin->currentg )
		return;

	obj = OGALLOC( ogwin, sizeof( *obj ) );
	if( !obj )
		return;

	ogwin->idcmp |= IDCMP_GADGETDOWN;

	obj->type = OGOBJ_CHECKBOX;
	obj->py	= py;
	obj->shortcut = shortcut;
	obj->title = title;
	obj->id	= id;
	obj->defaultvalue = val;

	AddTail( (struct List *) &ogwin->currentg->obj, (struct Node *) obj );
}

void ogreAddString(	struct ogwin *ogwin,
					UBYTE py,
					UBYTE shortcut,
					char *title,
					UWORD id,
					char *value,
					UWORD viewx,
					UWORD maxchars )
{
	struct ogobj *obj;

	if( !ogwin->currentg )
		return;

	obj = OGALLOC( ogwin, sizeof( *obj ) );
	if( !obj )
		return;

	ogwin->idcmp |= IDCMP_GADGETUP;

	obj->type = OGOBJ_STRING;
	obj->py	= py;
	obj->shortcut = shortcut;
	obj->title = title;
	obj->id	= id;
	obj->defaultstring = value;
	obj->xchars = viewx;
	obj->maxchars = maxchars & 0x7fff;

	obj->top = maxchars & OGSF_NONEXTACT;

	AddTail( (struct List *) &ogwin->currentg->obj, (struct Node *) obj );
}

void ogreAddList(	struct ogwin *ogwin,
					UBYTE py,
					UBYTE shortcut,
					char *title,
					UWORD id,
					UWORD viewx,
					UWORD viewy,
					UWORD flags,
					struct List *l )
{
	struct ogobj *obj;

	if( !ogwin->currentg )
		return;

	obj = OGALLOC( ogwin, sizeof( *obj ) );
	if( !obj )
		return;

	ogwin->idcmp |= IDCMP_GADGETUP | IDCMP_GADGETDOWN | IDCMP_INTUITICKS | IDCMP_MOUSEMOVE | IDCMP_MOUSEBUTTONS;

	obj->type = OGOBJ_LIST;
	obj->shortcut = shortcut;
	if( obj->shortcut == 0xff )
		ogwin->hascursorlv = id;
	obj->title = title;
	obj->py	= py;
	obj->id	= id;
	obj->xchars = viewx;
	obj->ychars = viewy;
	obj->flags = flags;
	obj->l = l;
	obj->defaultvalue = -1;

	AddTail( (struct List *) &ogwin->currentg->obj, (struct Node *) obj );
}

void ogreAddCycle(	struct ogwin *ogwin,
					UBYTE py,
					UBYTE shortcut,
					char *title,
					UWORD id,
					char **entries,
					UWORD viewx,
					UWORD current )
{
	struct ogobj *obj;
	char **entp;

	if( !ogwin->currentg )
		return;

	obj = OGALLOC( ogwin, sizeof( *obj ) );
	if( !obj )
		return;

	ogwin->idcmp |= IDCMP_GADGETUP;

	obj->type = OGOBJ_CYCLE;
	obj->num = py & OGGP_CYCLERIGHT;
	obj->py	= py & 0x7f;
	obj->shortcut = shortcut;
	obj->title = title;
	obj->id	= id;
	obj->entries = entries;
	obj->xchars = viewx;
	obj->defaultvalue = current;
	entp = entries;
	while( *entp++ )
		obj->num++;

	AddTail( (struct List *) &ogwin->currentg->obj, (struct Node *) obj );
}

void ogreAddInteger(	struct ogwin *ogwin,
					UBYTE py,
					UBYTE shortcut,
					char *title,
					UWORD id,
					LONG value,
					LONG minval,
					LONG maxval,
					UWORD viewx,
					UWORD maxchars )
{
	struct ogobj *obj;

	if( !ogwin->currentg )
		return;

	obj = OGALLOC( ogwin, sizeof( *obj ) );
	if( !obj )
		return;

	ogwin->idcmp |= IDCMP_GADGETUP;

	obj->type = OGOBJ_INTEGER;
	obj->py	= py;
	obj->shortcut = shortcut;
	obj->title = title;
	obj->id	= id;
	obj->defaultvalue = value;
	obj->xchars = viewx;
	obj->maxchars = maxchars & 0x7fff;
	obj->top = maxchars & OGSF_NONEXTACT;
	obj->minval = minval;
	obj->maxval = maxval;

	AddTail( (struct List *) &ogwin->currentg->obj, (struct Node *) obj );
}

void ogreAddText(	struct ogwin *ogwin,
					UBYTE py,
					char *title,
					UWORD id,
					char *value,
					UWORD viewx,
					UBYTE frame )
{
	struct ogobj *obj;

	if( !ogwin->currentg )
		return;

	obj = OGALLOC( ogwin, sizeof( *obj ) );
	if( !obj )
		return;

	obj->type = OGOBJ_TEXT;
	obj->py	= py;
	obj->title = title;
	obj->id	= id;
	obj->defaultstring = value;
	obj->xchars = viewx;
	obj->ychars = frame;

	AddTail( (struct List *) &ogwin->currentg->obj, (struct Node *) obj );
}

void ogreAddPensel(	struct ogwin *ogwin,
					UBYTE py,
					UBYTE shortcut,
					char *title,
					UWORD id,
					ULONG value,
					UWORD viewx )
{
	struct ogobj *obj;

	if( !ogwin->currentg )
		return;

	/* Unter 1.3 Integer erzeugen */
	if( !ISV37 )
	{
		ogreAddInteger( ogwin, py, shortcut, title, id, value, 0, ( 1 << ogwin->scr->RastPort.BitMap->Depth ) - 1, viewx, 4 );
		return;
	}

	obj = OGALLOC( ogwin, sizeof( *obj ) );
	if( !obj )
		return;

	obj->type = OGOBJ_PENSEL;
	obj->py	= py;
	obj->shortcut = shortcut;
	obj->title = title;
	obj->id	= id;
	obj->defaultvalue = value;
	obj->xchars = viewx;

	AddTail( (struct List *) &ogwin->currentg->obj, (struct Node *) obj );
}


/* Attach two Border lists */
static void __inline attachborder( struct Border *from, struct Border *to )
{
	while( to->NextBorder )
		to = to->NextBorder;

	to->NextBorder = from;
}

/* Attach two IText lists */
static void __inline attachitext( struct IntuiText *from, struct IntuiText *to )
{
	while( to->NextText )
		to = to->NextText;

	to->NextText = from;
}

static struct ogobj * __inline findobj( struct ogwin *ogw, UWORD id )
{
	struct ogobj *obj;
	struct oggroup *ogg;

	for( ogg = (struct oggroup *) ogw->groups.mlh_Head; ogg->n.mln_Succ; ogg = (struct oggroup *) ogg->n.mln_Succ )
	{
		for( obj = (struct ogobj *) ogg->obj.mlh_Head; obj->n.mln_Succ; obj = (struct ogobj *) obj->n.mln_Succ )
		{
			if( obj->id == id )
				return( obj );
		}
	}
	return( NULL );
}


/* Return length of Text */
static int textlen( struct ogwin *ogw, char *txt )
{
	char tmp[ 256 ], *p;
	struct IntuiText it;

	if( !txt || !txt[0] )
		return( 0 );

	strcpy( tmp, txt );
	p = strchr( tmp, '_' );
	if( p )
		strcpy( p, &p[1] );

	it.IText = tmp;
	it.ITextFont = ogw->used_fnta;

	return( IntuiTextLength( &it ) );
}

/* Return static length of Text */
static int stextlen( struct ogwin *ogw, char *txt )
{
	char tmp[ 256 ], *p;

	if( !txt || !txt[0] )
		return( 0 );

	strcpy( tmp, txt );
	p = strchr( tmp, '_' );
	if( p )
		strcpy( p, &p[1] );

	return( ( int ) ( strlen( tmp ) * ogw->fontxsize ) );
}

/* Make IText */
static struct IntuiText *makeitext( struct ogwin *ogw, char *txt, int leftedge, int topedge )
{
	struct IntuiText *it = OGALLOC( ogw, sizeof( *it ) );
	struct IntuiText *it2;
	char *p;
	int baroffset, ch;

	if( !it )
		return( NULL );

	it->ITextFont = ogw->used_fnta;
	it->LeftEdge  = leftedge;
	it->TopEdge   = topedge;

	p = strchr( txt, '_' );

	if( p )
	{
		p = OGALLOC( ogw, strlen( txt ) + 1 );
		if( !p )
			return( NULL );
		strcpy( p, txt );
		txt = strchr( p, '_' );
		*txt = 0;
		ch = txt[1];
		it->IText = p;
		baroffset = IntuiTextLength( it );
		strcpy( txt, &txt[1] );
		txt = p;

		it2 = OGALLOC( ogw, sizeof( *it2 ) );
		if( !it2 )
			return( NULL );

		it2->LeftEdge  = baroffset + leftedge;
		ogw->underline_fnta           = *ogw->used_fnta;
		ogw->underline_fnta.ta_Style |= FSF_UNDERLINED;
		it2->ITextFont = &ogw->underline_fnta;
		it2->IText     = OGALLOC( ogw, 2 );
		*it2->IText    = ch;
		it2->TopEdge   = topedge;
		it2->FrontPen  = ogw->pens[ TEXTPEN ];
		it->NextText   = it2;
	}
	it->IText 		= txt;
	it->FrontPen 	= ogw->pens[ TEXTPEN ];
	it->DrawMode	= JAM2;
	return( it );
}

static struct IntuiText *makeitextnu( struct ogwin *ogw, char *txt, int leftedge, int topedge )
{
	struct IntuiText *it = OGALLOC( ogw, sizeof( *it ) );

	if( !it )
		return( NULL );

	it->ITextFont = ogw->used_fnta;
	it->LeftEdge  = leftedge;
	it->TopEdge   = topedge;
	it->IText 		= txt;
	it->FrontPen 	= ogw->pens[ TEXTPEN ];
	it->DrawMode	= JAM2;
	return( it );
}

/* Center IText inside Box */
static void centeritext( struct IntuiText *it, int bx )
{
	int txtlen = IntuiTextLength( it );
	int offs = ( bx - txtlen ) / 2;

	it->LeftEdge += offs;

	if( it->NextText )
		it->NextText->LeftEdge += offs;

}


/* Calculate nominal size of an object */
static void calcobject( struct ogwin *ogw, struct ogobj *obj )
{
	switch( obj->type )
	{
		case OGOBJ_BUTTON:
			obj->xs = obj->rxs = textlen( ogw, obj->title ) + 8;
			obj->ys = obj->rys = ogw->used_font->tf_YSize + 4;
			return;

		case OGOBJ_FUELGAUGE:
			obj->xs = obj->rxs = textlen( ogw, "00%" ) + 8;
			obj->ys = obj->rys = ogw->used_font->tf_YSize + 4;
			return;

		case OGOBJ_CHECKBOX:
			obj->xs = obj->rxs = stextlen( ogw, obj->title ) + 44;
			obj->ys = obj->rys = ogw->used_font->tf_YSize + 4;
			return;

		case OGOBJ_STRING:
		case OGOBJ_INTEGER:
			obj->xs = obj->rxs = stextlen( ogw, obj->title ) + ( ogw->used_font->tf_XSize * obj->xchars ) + 16;
			obj->ys = obj->rys = ogw->used_font->tf_YSize + 4;
			return;

		case OGOBJ_TEXT:
			obj->xs = obj->rxs = stextlen( ogw, obj->title ) + ( ogw->used_font->tf_XSize * obj->xchars ) + 20;
			obj->ys = obj->rys = ogw->used_font->tf_YSize + 4;
			return;

		case OGOBJ_PENSEL:
			obj->xs = obj->rxs = stextlen( ogw, obj->title ) + ( ogw->used_font->tf_XSize * obj->xchars ) + 42;
			obj->ys = obj->rys = ogw->used_font->tf_YSize + 4;
			return;

		case OGOBJ_CYCLE:
			obj->xs = obj->rxs = stextlen( ogw, obj->title ) + ( ogw->used_font->tf_XSize * obj->xchars ) + 32;
			obj->ys = obj->rys = ogw->used_font->tf_YSize + 4;
			return;

		case OGOBJ_LIST:
			obj->xs = obj->rxs = textlen( ogw, obj->title ) + ( ogw->lvfont->tf_XSize * obj->xchars ) + 24;
			obj->ys = obj->rys = ( ( ogw->lvfont->tf_YSize + 1 ) * obj->ychars ) + 5;
			if( obj->title )
				obj->ys += ogw->used_font->tf_YSize + 1;
			return;


	}

}

/* Add gadget to end of list */
static void attachgad( struct Gadget *which, struct Gadget *to )
{
	while( to->NextGadget )
		to = to->NextGadget;

	to->NextGadget = which;
}


/* Calculate Size of all Objects in a group */
static void calcgroupobjs( struct ogwin *ogw, struct oggroup *grp )
{
	struct ogobj *obj;

	for( obj = (struct ogobj *) grp->obj.mlh_Head;
		 obj->n.mln_Succ;
		 obj = (struct ogobj *) obj->n.mln_Succ )
	{
		calcobject( ogw, obj );
	}
}

/* Extend a list of rects to fill Area */
static void filllist( struct ogwin *ogw, struct MinList *ml,
					  int destx, int desty )
{
	struct ogobj *obj;
	int maxgx, maxobj;
	int maxy = 0;
	int c, d;
	int counter;
	int offs, accuoffs;
	BOOL found, run2;
	UWORD xexarray[64];
	UBYTE xextypearray[64];
	int xexcount = 0;

	for( c = 0; ; c++ )
	{
		found = FALSE;
		maxgx = 0;
		maxobj = 0;
		counter = 0;

		/* Find all objects of this Y position */
		for( obj = (struct ogobj *) ml->mlh_Head;
			 obj->n.mln_Succ;
			 obj = (struct ogobj *) obj->n.mln_Succ )
		{
			if( obj->py != c )
				continue;
			found = TRUE;

			counter++;

			if( obj->xs > maxobj )
				maxobj = obj->xs;

			if( obj->x + obj->xs > maxgx )
				maxgx = obj->x + obj->xs;

			if( obj->y + obj->ys > maxy )
				maxy = obj->y + obj->ys;

		}
		if( !found )
			break;

		/* Maxgx is current maximum X */
		offs = destx - maxgx;

		if( counter > xexcount )
			xexcount = 0;

		/* got to distribute offs pixels */
		run2 = FALSE;

		while( offs > 0 )
		{
			accuoffs = 0;
			counter = 0;
			for( obj = (struct ogobj *) ml->mlh_Head;
				 obj->n.mln_Succ;
				 obj = (struct ogobj *) obj->n.mln_Succ )
			{
				if( obj->py != c )
					continue;

				obj->x += accuoffs;
				if( obj->xs < maxobj && offs > 0 && !obj->keepsize )
				{
					d = min( maxobj - obj->xs, offs );
					if( !run2 && c && xexcount && ( xextypearray[ counter ] == obj->type ) )
						d = min( d, xexarray[ counter ] - obj->xs );

					obj->xs 	+= d;
					accuoffs 	+= d;
					offs 		-= d;
				}
				counter++;
			}
			if( offs < counter )
				break;

			maxobj += max( 1, offs / counter );
			run2 = TRUE;
		}

		/* Save sizes for vertical cloning */
		counter = 0;
		for( obj = (struct ogobj *) ml->mlh_Head;
			 obj->n.mln_Succ;
			 obj = (struct ogobj *) obj->n.mln_Succ )
		{
			if( obj->py != c )
				continue;

			xexarray[ counter ] = obj->xs;
			xextypearray[ counter ] = obj->type;
			counter++;
		}
		xexcount = counter;
	}

	if( !c )
		return;

	/* Now for the Y expand */
	offs = ( desty - maxy ) / c;

	for( obj = (struct ogobj *) ml->mlh_Head;
		 obj->n.mln_Succ;
		 obj = (struct ogobj *) obj->n.mln_Succ )
	{
		obj->y += ( offs * obj->py );
		obj->ys += offs;
	}

}


/* Layout a list of rects */
static void layoutlist( struct ogwin *ogw, struct MinList *ml, int *gxp, int *gyp, int objspace )
{
	struct ogobj *obj;
	int maxy, maxx = 0;
	int x, y = 0;
	int c;
	BOOL found;

	/* First perform best fit layout */
	for( c = 0; ; c++ )
	{
		found = FALSE;
		x = 0;
		maxy = 0;

		/* Find all objects of this Y position */

		for( obj = (struct ogobj *) ml->mlh_Head;
			 obj->n.mln_Succ;
			 obj = (struct ogobj *) obj->n.mln_Succ )
		{
			if( obj->py != c )
				continue;
			found = TRUE;

			if( obj->ys > maxy )
				maxy = obj->ys;

			obj->x = x;
			obj->y = y;
			x += obj->xs;
			if( x > maxx )
				maxx = x;
			x+= objspace;

		}
		y+= maxy + objspace;
		if( !found )
			break;

		/* Now expand all Y objects to maxy */
		for( obj = (struct ogobj *) ml->mlh_Head;
			 obj->n.mln_Succ;
			 obj = (struct ogobj *) obj->n.mln_Succ )
		{
			if( obj->py != c )
				continue;
			obj->ys = maxy;
		}
	}
	y -= objspace + 1;
	*gxp = maxx;
	*gyp = y;

}

/* Calculate Offset for Frame */
static void layoutgroupframe( struct ogwin *ogw, struct oggroup *grp )
{
	int left = 8, right = 8, top = 4, bottom = 2;

	if( grp->title )
	{
		bottom += 2;
		top += ogw->used_font->tf_YSize - 2;
	}

	grp->objoffsx = left;
	grp->objoffsy = top;
	grp->xs += left + right;
	grp->ys += top + bottom;
}

/* Order Groups */
static void layoutgroups( struct ogwin *ogw )
{
	struct oggroup *grp;
	int x = 0, y = 0;
	/*int maxpx = ogw->screenx - ogw->scr->WBorLeft - ogw->scr->WBorRight - 4;*/

	layoutlist( ogw, &ogw->groups, &x, &y, 4 );
	filllist( ogw, &ogw->groups, x, y );

	for( grp = (struct oggroup *) ogw->groups.mlh_Head;
		 grp->n.mln_Succ;
		 grp = (struct oggroup *) grp->n.mln_Succ )
	{
		filllist( ogw, &grp->obj, grp->xs - grp->objoffsx - 8, grp->ys - grp->objoffsy - 4 );
	}

	ogw->windowx = x + 4;
	ogw->windowy = y;
}

/* Create Bevel Border */
static struct Border *makebevelborder( struct ogwin *ogw, int xs, int ys, BOOL recessed )
{
	struct Border *b1, *b2;
	UWORD  *vec1;
	UWORD  *vec2;

	xs--; ys--;

	/* First Part */

	b1 = OGALLOC( ogw, sizeof( *b1 ) );
	if( !b1 )
		return( NULL );
	vec1 = OGALLOC( ogw, 10 * 2 );
	if( !vec1 )
		return( NULL );
	b1->XY = vec1;
	b1->Count = 5;
	b1->FrontPen = ogw->pens[ ( recessed ) ? SHADOWPEN : SHINEPEN ];
	
	/* Start Upper Right! */
	vec1[0] = xs-1;
	vec1[1] = 0;

	vec1[2] = 0;
	vec1[3] = 0;

	vec1[4] = 0;
	vec1[5] = ys;

	vec1[6] = 1;
	vec1[7] = ys-1;

	vec1[8] = 1;
	vec1[9] = 1;

	/* Second Part */

	b2 = OGALLOC( ogw, sizeof( *b2 ) );
	if( !b1 )
		return( NULL );
	vec2 = OGALLOC( ogw, 10 * 2 );
	if( !vec2 )
		return( NULL );
	b2->XY = vec2;
	b2->Count = 5;
	b2->FrontPen = ogw->pens[ ( recessed ) ? SHINEPEN : SHADOWPEN ];
	b1->NextBorder = b2;
	
	/* Start Lower Left! */
	vec2[0] = 1;
	vec2[1] = ys;

	vec2[2] = xs;
	vec2[3] = ys;

	vec2[4] = xs;
	vec2[5] = 0;

	vec2[6] = xs-1;
	vec2[7] = 1;

	vec2[8] = xs-1;
	vec2[9] = ys-1;

	return( b1 );
}

/* Create Checkbox Border with Mark */
static struct Border *makecheckborder( struct ogwin *ogw, int xs, int ys, BOOL active )
{
	struct Border *b0, *b1, *b2, *b3;
	UWORD  *vec1;

	b3 = makebevelborder( ogw, xs, ys, FALSE );
	if( !b3 )
		return( NULL );

	xs--; ys--;

	b0 = OGALLOC( ogw, sizeof( *b0 ) );
	if( !b0 )
		return( NULL );
	b1 = OGALLOC( ogw, sizeof( *b1 ) );
	if( !b1 )
		return( NULL );
	b2 = OGALLOC( ogw, sizeof( *b2 ) );
	if( !b2 )
		return( NULL );

	vec1 = OGALLOC( ogw, 10 * 2 );
	if( !vec1 )
		return( NULL );

	b1->XY = vec1;
	b1->Count = 5;
	b1->FrontPen = ogw->pens[ ( active ) ? TEXTPEN : 0 ];
	
	vec1[0] = 7;
	vec1[1] = ys / 2;

	vec1[2] = 11;
	vec1[3] = ys - 2;

	vec1[4] = 12;
	vec1[5] = ys - 2;

	vec1[6] = 19;
	vec1[7] = 2;

	vec1[8] = 21;
	vec1[9] = 2;

	b1->NextBorder = b2;

	*b2 = *b1;
	b2->LeftEdge++;
	b2->NextBorder = b3;

	*b0 = *b1;
	b0->LeftEdge--;
	b0->NextBorder = b1;

	return( b0 );

}

/* Create Arrow Border */
static struct Border *makearrowborder( struct ogwin *ogw, int xs, int ys, BOOL up )
{
	struct Border *b0, *b1, *b2;
	UWORD *vec1;

	b0 = makebevelborder( ogw, xs, ys, FALSE );
	if( !b0 )
		return( NULL );
	xs--; ys--;

	b1 = OGALLOC( ogw, sizeof( *b1 ) );
	if( !b1 )
		return( NULL );

	vec1 = OGALLOC( ogw, 6 * 2 );
	if( !vec1 )
		return( NULL );

	b1->XY = vec1;
	b1->Count = 3;
	b1->FrontPen = ogw->pens[ TEXTPEN ];
	
	if( up )
	{
		vec1[0] = 3;
		vec1[1] = ys - 2;

		vec1[2] = xs / 2;
		vec1[3] = 2;

		vec1[4] = xs-4;
		vec1[5] = ys - 2;
	}
	else
	{
		vec1[0] = 3;
		vec1[1] = 2;

		vec1[2] = xs / 2;
		vec1[3] = ys - 2;

		vec1[4] = xs-4;
		vec1[5] = 2;
	}

	b1->NextBorder = b0;

	b2 = OGALLOC( ogw, sizeof( *b2 ) );
	if( !b2 )
		return( NULL );
	*b2 = *b1;
	b2->LeftEdge++;
	b2->NextBorder = b1;

	return( b2 );
}

/* Create Cycle Border */
static struct Border *makecycleborder( struct ogwin *ogw, int xs, int ys )
{
	struct Border *b0, *b1;
	UWORD  *vec1;
	int offs = max( 0, ( ys - 14 ) / 2 );

	b0 = makebevelborder( ogw, xs, ys, FALSE );
	if( !b0 )
		return( NULL );
	xs--; ys--;

	/* First Line */
	b1 = OGALLOC( ogw, sizeof( *b1 ) );
	if( !b1 )
		return( NULL );
	vec1 = OGALLOC( ogw, 4 * 2 );
	if( !vec1 )
		return( NULL );
	b1->XY = vec1;
	b1->Count = 2;
	b1->FrontPen = ogw->pens[ SHADOWPEN ];
	
	/* Start Upper Right! */
	vec1[0] = 20;
	vec1[1] = 2;

	vec1[2] = 20;
	vec1[3] = ys-2;

	b1->NextBorder = b0;
	b0 = b1;

	/* Second Line */
	b1 = OGALLOC( ogw, sizeof( *b1 ) );
	if( !b1 )
		return( NULL );
	*b1 = *b0;
	b1->Count = 2;
	b1->FrontPen = ogw->pens[ SHINEPEN ];
	b1->LeftEdge++;
	
	b1->NextBorder = b0;
	b0 = b1;

	/* Pfeil */
	b1 = OGALLOC( ogw, sizeof( *b1 ) );
	if( !b1 )
		return( NULL );
	vec1 = OGALLOC( ogw, 20 * 2 );
	if( !vec1 )
		return( NULL );
	b1->XY = vec1;
	b1->Count = 10;
	b1->FrontPen = ogw->pens[ TEXTPEN ];
	
	/* Start Upper Right! */
	vec1[0] = 13;
	vec1[1] = 2;

	vec1[2] = 7;
	vec1[3] = 2;

	vec1[4] = 6;
	vec1[5] = 3;

	vec1[6] = 6;
	vec1[7] = ys-3;

	vec1[8] = 7;
	vec1[9] = 3;

	vec1[10] = 7;
	vec1[11] = ys-2;

	vec1[12] = 13;
	vec1[13] = ys-2;

	vec1[14] = 13;
	vec1[15] = ys-3-offs;

	vec1[16] = 14;
	vec1[17] = ys-3-offs;

	vec1[18] = 14;
	vec1[19] = ys-3;

	b1->NextBorder = b0;
	b0 = b1;

	/* Pfeil 2 */
	b1 = OGALLOC( ogw, sizeof( *b1 ) );
	if( !b1 )
		return( NULL );
	vec1 = OGALLOC( ogw, 16 * 2 );
	if( !vec1 )
		return( NULL );
	b1->XY = vec1;
	b1->Count = 8;
	b1->FrontPen = ogw->pens[ TEXTPEN ];
	
	vec1[0] = 13;
	vec1[1] = 3;

	vec1[2] = 13;
	vec1[3] = 6 + offs;

	vec1[4] = 11;
	vec1[5] = 4 + offs;

	vec1[6] = 16;
	vec1[7] = 4 + offs;

	vec1[8] = 15;
	vec1[9] = 5 + offs;

	vec1[10] = 13;
	vec1[11] = 5 + offs;

	vec1[12] = 14;
	vec1[13] = 6 + offs;

	vec1[14] = 14;
	vec1[15] = 3;

	b1->NextBorder = b0;
	/*b0 = b1;*/

	return( b1 );
}

/* Create String Border */
static struct Border *makestringborder( struct ogwin *ogw, int xs, int ys, BOOL recessed )
{
	struct Border *b1, *b2;
	UWORD  *vec1;
	UWORD  *vec2;

	xs--;
	ys--;

	/* First Part */

	b1 = OGALLOC( ogw, sizeof( *b1 ) );
	if( !b1 )
		return( NULL );
	vec1 = OGALLOC( ogw, 20 * 2 );
	if( !vec1 )
		return( NULL );
	b1->XY = vec1;
	b1->Count = 10;
	b1->FrontPen = ogw->pens[ ( recessed ) ? SHADOWPEN : SHINEPEN ];
	
	/* Start Lower Left */
	vec1[0] = 3;
	vec1[1] = ys-1;

	vec1[2] = xs-2;
	vec1[3] = ys-1;

	vec1[4] = xs-2;
	vec1[5] = 2;

	vec1[6] = xs-3;
	vec1[7] = ys-1;

	vec1[8] = xs-3;
	vec1[9] = 2;

	vec1[10] = xs-1;	
	/*vec1[11] = 0;

	vec1[12] = 0;
	vec1[13] = 0;

	vec1[14] = 0;*/
	vec1[15] = ys;

	vec1[16] = 1;
	vec1[17] = ys-1;

	vec1[18] = 1;
	vec1[19] = 1;

	/* Second Part */

	b2 = OGALLOC( ogw, sizeof( *b2 ) );
	if( !b1 )
		return( NULL );
	vec2 = OGALLOC( ogw, 20 * 2 );
	if( !vec2 )
		return( NULL );
	b2->XY = vec2;
	b2->Count = 10;
	b2->FrontPen = ogw->pens[ ( recessed ) ? SHINEPEN : SHADOWPEN ];
	b1->NextBorder = b2;
	
	/* Start Upper Right! */
	vec2[0] = xs;
	/*vec2[1] = 0;*/

	vec2[2] = xs;
	vec2[3] = ys;

	vec2[4] = xs-1;
	vec2[5] = 1;

	vec2[6] = xs-1;
	vec2[7] = ys;

	vec2[8] = 1;
	vec2[9] = ys;

	vec2[10] = 2;
	vec2[11] = ys-1;

	vec2[12] = 2;
	vec2[13] = 1;

	vec2[14] = 3;
	vec2[15] = ys-2;

	vec2[16] = 3;
	vec2[17] = 1;

	vec2[18] = xs-3;
	vec2[19] = 1;

	return( b1 );
}


/* Create Frame Border */
static struct Border *makeframeborder( struct ogwin *ogw, struct oggroup *ogg )
{
	struct Border *b;
	int offs;

	if( ogg->frame == OGFRAME_BEVEL)
	{
		b = makebevelborder( ogw, ogg->xs, ogg->ys, TRUE );
		return( b );
	}
	else
	{	
		if( ogg->title )
			offs = ogw->used_font->tf_YSize / 2;
		else
			offs = 0;
		b = makestringborder( ogw, ogg->xs, ogg->ys - offs, TRUE );
		b->TopEdge += offs;
		b->NextBorder->TopEdge += offs;
		return( b );
	}
}

static void posgad( struct Gadget *g, struct ogwin *ogw, struct oggroup *ogg, struct ogobj *obj, int justify )
{
	g->LeftEdge = ogg->x + obj->x + ogw->windowxoffs + ogg->objoffsx;
	g->TopEdge	= ogg->y + obj->y + ogw->windowyoffs + ogg->objoffsy;

	switch( justify )
	{
		case OGPOS_EXPAND:
			g->Width 	= obj->xs;
			g->Height 	= obj->ys;
			break;

		case OGPOS_EXPAND_X:
			g->Width 	= obj->xs;
			g->Height 	= obj->rys;
			g->TopEdge += ( obj->ys - obj->rys ) / 2;
			break;

		case OGPOS_CENTER:
			g->Width	= obj->rxs;
			g->Height	= obj->rys;
			g->LeftEdge += ( obj->xs - obj->rxs ) / 2;
			break;

		case OGPOS_LEFT:
			g->Width	= obj->rxs;
			g->Height	= obj->rys;
			g->TopEdge += ( obj->ys - obj->rys ) / 2;
			break;

		case OGPOS_RIGHT:
			g->Width	= obj->rxs;
			g->Height	= obj->rys;
			g->LeftEdge += ( obj->xs - obj->rxs );
			g->TopEdge += ( obj->ys - obj->rys ) / 2;
			break;
	}
}

static void posnewgad( struct NewGadget *ng, struct ogwin *ogw, struct oggroup *ogg, struct ogobj *obj, int justify )
{
	memset( ng, 0, sizeof( *ng ) );
	ng->ng_VisualInfo = ogw->vi;
	ng->ng_TextAttr = ogw->used_fnta;
	posgad( (struct Gadget *)(((LONG)ng)-4), ogw, ogg, obj, justify );
}


static void makecycletext( struct ogwin *ogw, struct ogobj *obj )
{
	int current = obj->defaultvalue;
	int l;

	if( !obj->defaultstring )
		obj->defaultstring = OGALLOC( ogw, 128 );

	if( !obj->it_c )
		return;

	obj->it_c->NextText = NULL;
	obj->it_c->IText = obj->defaultstring;
	memset( obj->defaultstring, ' ', 127 );

	if( current < 0 )
		current = obj->defaultvalue = obj->num - 1;
	if( current >= obj->num )
		current = obj->defaultvalue = 0;

	memcpy( obj->defaultstring, obj->entries[ obj->defaultvalue ], min( 128, strlen( obj->entries[ obj->defaultvalue ] ) ) );
	l = textfit( ogw, obj->defaultstring, obj->g->Width - 32 );
	obj->defaultstring[ l ] = 0;

	obj->g->GadgetText = obj->it_c;

	if( obj->it_t )
	{
		obj->it_c->NextText = obj->it_t;
	}

}

static struct Process *clipproc;

static void __saveds clipprochandler( void )
{
	struct IFFHandle *ifh;
	struct StoredProperty *sp;
	struct Library *IFFParseBase;
	struct Library *CxBase;

	IFFParseBase = OldOpenLibrary( "iffparse.library" );
	if( !IFFParseBase )
	{
		clipproc = NULL;
		return;
	}
	CxBase = OldOpenLibrary( "commodities.library" );
	if( !CxBase )
	{
		CloseLibrary( IFFParseBase );
		clipproc = NULL;
		return;
	}
	
	for(;;)
	{
		ULONG sig = Wait( SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D );

		if( sig & SIGBREAKF_CTRL_C )
			break;

		ifh = AllocIFF();
		if( !ifh )
		{
			continue;
		}

		ifh->iff_Stream = OpenClipboard( 0 );
		if( !ifh->iff_Stream )
		{
			FreeIFF( ifh );
			continue;
		}

		InitIFFasClip( ifh );
		OpenIFF( ifh, IFFF_READ );

		PropChunk( ifh, MAKE_ID('F','T','X','T'), MAKE_ID('C','H','R','S') );
		StopOnExit( ifh, MAKE_ID('F','T','X','T'), MAKE_ID('C','H','R','S') );
		ParseIFF( ifh, IFFPARSE_SCAN );

		sp = FindProp( ifh, MAKE_ID('F','T','X','T'), MAKE_ID('C','H','R','S') );

		if( sp && sp->sp_Size )
		{
			char *p;
			char line[ 256 ];
			struct InputEvent *ie;

			memset( line, 0, 256 );
			memcpy( line, sp->sp_Data, min( sp->sp_Size, 255 ) );

			p = strchr( line, '\n' );
			if( p )
				*p = 0;

			while( ( p = strchr( line, '\t' ) ) )
				*p = 32;

			strrev( line );
			ie = InvertString( line, NULL );
			AddIEvents( ie );
			FreeIEvents( ie );
		}

		CloseIFF( ifh );
		CloseClipboard( ifh->iff_Stream );
		FreeIFF( ifh );

	}
	CloseLibrary( IFFParseBase );
	CloseLibrary( CxBase );
	clipproc = NULL;
}

CONSTRUCTOR_P(initclipproc,31000)
{
	if( SysBase->LibNode.lib_Version < 36 )
		return( 0 );

	clipproc = CreateNewProcTags(
		NP_Entry, clipprochandler,
		NP_Name, "MicroDot Ogre Clipboard Server",
		NP_StackSize, 3000,
		NP_Priority, 5,
		NP_CopyVars, FALSE,
		NP_WindowPtr, -1,
		TAG_DONE
	);
	return( 0 );
}

DESTRUCTOR_P(delclipbproc,31000)
{
	while( clipproc )
	{
		Signal( clipproc, SIGBREAKF_CTRL_C );
		Delay( 10 );
	}
}

static ULONG __asm __saveds stringhookfunc(
	register __a1 ULONG *cmd,
	register __a2 struct SGWork *sgw )
{
	if( *cmd != SGH_KEY )
		return( 0 );

	if( ( sgw->IEvent->ie_Class == IECLASS_RAWKEY ) &&
		( sgw->IEvent->ie_Qualifier & IEQUALIFIER_LCOMMAND ) )
	{
		sgw->Actions = SGA_END | SGA_REUSE;
		sgw->Code = 0x70;
	}
	else if( ( sgw->IEvent->ie_Class == IECLASS_RAWKEY ) &&
		( sgw->IEvent->ie_Code == 0x34 ) &&
		( sgw->IEvent->ie_Qualifier & IEQUALIFIER_RCOMMAND ) )
	{
		if( clipproc )
		{
			Signal( clipproc, SIGBREAKF_CTRL_D );
			sgw->Actions &= ~SGA_USE;
		}
	}
	return( -1 );
}

static struct Hook stringhook = { 0,0, stringhookfunc };

static struct ogrevn *getentry( struct ogobj *obj, int num )
{
	struct ogrevn *vn = (struct ogrevn *) obj->l->lh_Head;

	while( vn->n.mln_Succ )
	{
		if( !num-- )
			return( vn );
		vn = (struct ogrevn * ) vn->n.mln_Succ;
	}
	return( NULL );
}

static int getnumentries( struct ogobj *obj )
{
	struct ogrevn *vn = (struct ogrevn *) obj->l->lh_Head;
	int num = 0;

	while( vn->n.mln_Succ )
	{
		num++;
		vn = (struct ogrevn * ) vn->n.mln_Succ;
	}
	return( num );
}

static int getfirstselentry( struct ogobj *obj )
{
	struct ogrevn *vn = (struct ogrevn *) obj->l->lh_Head;
	int num = 0;

	while( vn->n.mln_Succ )
	{
		if( vn->sel )
			return( num );
		num++;
		vn = (struct ogrevn * ) vn->n.mln_Succ;
	}
	return( -1 );
}

void FindScrollerValues( UWORD total, UWORD displayable, UWORD top, WORD overlap, UWORD *body, UWORD *pot )
{
	UWORD hidden;

	hidden = max( total-displayable, 0 );

	if( top > hidden )
		top = hidden;
	
	*body = ( hidden > 0 ) ? ( UWORD ) ( ( ( ULONG ) ( displayable - overlap ) * MAXBODY ) / ( total - overlap ) ) : MAXBODY;
	*pot  = ( hidden > 0 ) ? ( UWORD ) ( ( ( ULONG ) top * MAXPOT ) / hidden ) : 0;

}

UWORD FindScrollerTop( UWORD total, UWORD displayable, UWORD pot )
{
	UWORD top, hidden;

	hidden = max( total - displayable, 0 );
	top = ( ( ( ULONG ) hidden * pot ) + ( MAXPOT / 2 ) ) >> 16;
	return( top );

}



/* Make List of IntuiTexts for Listview */
static void makelisttexts( struct ogwin *ogw, struct ogobj *obj )
{
	int c;
	int y = 3;
	struct ogrevn *vn;
	struct IntuiText *it, *it2 = obj->it_t;
	struct Image *im, *im2 = NULL;
	char *p;
	struct Border *bf = NULL;

	if( !obj->it_c )
	{
		obj->defaultstring = OGALLOC( ogw, ( obj->xchars * 5 ) * obj->ychars );
		if( !obj->defaultstring )
			return;

		for( c = 0; c < obj->ychars; c++ )
		{
			it = OGALLOC( ogw, sizeof( *it ) );
			if( !it )
				return;
			it->LeftEdge = 4;
			it->TopEdge = y;
			it->DrawMode = JAM1;
			it->FrontPen = ogw->pens[ TEXTPEN ];
			it->ITextFont = ogw->lvfnta;
			it->IText	= &obj->defaultstring[ c * ( obj->xchars * 5 ) ];
			it->NextText = it2;
			it2 = it;

			im = OGALLOC( ogw, sizeof( *im ) );
			if( !im )
				return;
			im->LeftEdge = 2;
			im->TopEdge = y - 1;
			im->Width = obj->xs - 20;
			im->Height = ogw->lvfont->tf_YSize + 2;
			im->PlaneOnOff = 0;
			im->Depth = ogw->scr->RastPort.BitMap->Depth;
			im->NextImage = im2;
			im2 = im;

			y += ogw->lvfont->tf_YSize + 1;

		}
		obj->it_c = it;
		obj->im = im;
	}

	for( it = obj->it_c, im = obj->im, c = obj->ychars - 1; c >= 0 && it && im; it = it->NextText, im = im->NextImage, c-- )
	{
			vn = getentry( obj, c + obj->top );
			if( !vn )
			{
				p = "";
				y = 0;
			}
			else
			{
				p = vn->txt;
				y = ( obj->xs - 24 ) / ogw->lvfont->tf_XSize;
				memcpy( it->IText, p, y );
			}

			if( c + obj->top == obj->defaultvalue )
			{
				bf = obj->b_f;

				if( bf )
				{
					bf->TopEdge = it->TopEdge - 1;
					bf->NextBorder->TopEdge = it->TopEdge - 1;
				}

			}
		
			it->IText[ y ] = 0;

			if( vn && vn->sel )
				im->PlaneOnOff = ogw->pens[ FILLPEN ];
			else
				im->PlaneOnOff = 0;

	}

	/*if( obj->it_t )
		attachitext( obj->it_t, obj->it_c );*/
	obj->g->GadgetText = obj->it_c;
	obj->g->GadgetRender = obj->im;

	/* Build Border */
	if( bf )
	{
		bf->NextBorder->NextBorder= obj->b_b;
		obj->bordg->GadgetRender = bf;
	}
	else
		obj->bordg->GadgetRender = obj->b_b;

}

static void setlistscroller( struct ogwin *ogw, struct ogobj *obj )
{
	UWORD pot, body;
	struct PropInfo *pi;

	obj->num = getnumentries( obj );
	FindScrollerValues( obj->num, obj->ychars, obj->top, 0, &body, &pot );
	if( obj->scroll )
	{
		pi = obj->scroll->SpecialInfo;
		if( ogw->w )
		{
			if( pi->VertBody != body || pi->VertPot != pot )
				NewModifyProp( obj->scroll, ogw->w, NULL, pi->Flags, 
					0, pot, 0, body, 1 );
		}
		else
		{
			pi->VertBody = body;
			pi->VertPot  = pot;
		}
	}

}


/* Calc Fuel Image size */
static int makefuelimage( struct ogwin *ogw, struct ogobj *obj )
{
	ULONG xp, perc;
	LONG v1, v2;

	if( obj->defaultvalue > obj->maxval )
		obj->defaultvalue = obj->maxval;

	v1 = obj->defaultvalue;
	v2 = obj->maxval;

	if( v2 > 1000000 )
	{
		v1 = ( v1 + 9 ) / 10;
		v2 = ( v2 + 9 ) / 10;
	}

	perc = ( obj->defaultvalue * 100 ) / obj->maxval;
	xp = ( v1 * ( ( ULONG ) obj->xchars ) ) / v2;

	/* Size & Position Images */
	obj->im->Width = xp;
	obj->im->NextImage->Width = obj->xchars - xp;
	obj->im->NextImage->LeftEdge = obj->im->LeftEdge + xp;

	sprintf( obj->defaultstring, "%ld%%", perc );
	obj->it_c->LeftEdge = 0;
	centeritext(  obj->it_c, obj->xs );

	if( xp != obj->oldxp )
	{
		obj->oldxp = xp;
		return( -1 );
	}
	return( 0 );
}

/* Init Gadtools */
static void initgt( struct ogwin *ogw )
{
	if( ogw->gtlastg )
		return;

	ogw->vi = GetVisualInfo( ogw->scr, TAG_DONE );
	ogw->gtlastg = CreateContext( &ogw->gtglist );
}


static struct Gadget *makeobj( struct ogwin *ogw,
							   struct oggroup *ogg,
							   struct ogobj *obj )
{
	struct Gadget *g, *g2;
	struct IntuiText *it;
	int xs, ys;
	struct StringInfo *si;
	struct Border *b;
	struct StringExtend *sex;
	struct Image *autoknobimage;
	struct PropInfo *pi;
	struct Image *im;
	struct NewGadget ng;
	char *p;
	int c;

	g = OGALLOC( ogw, sizeof( *g ) );
	if( !g )
		return( NULL );

	obj->g = g;
	g->UserData = obj;

	if( obj->shortcut && obj->shortcut != 0xff && obj->shortcut != 0x5f )
		obj->shortcut = getrawkeycode( obj->shortcut );

	switch( obj->type )
	{
		case OGOBJ_BUTTON:
			if( obj->shortcut == 0x5f )
				ogw->helpgad = obj;
			/* Let Gadtools create the Gadget */
			if( ISV37 )
			{
				initgt( ogw );
				posnewgad( &ng, ogw, ogg, obj, OGPOS_EXPAND_X );
				ng.ng_GadgetID = obj->id;
				ng.ng_UserData = obj;
				ng.ng_Flags	   = PLACETEXT_IN;
				if( obj->title )
					ng.ng_GadgetText = obj->title;

				obj->g = ogw->gtlastg = CreateGadget( BUTTON_KIND, ogw->gtlastg, &ng, GT_Underscore, '_', GA_Disabled, obj->disable, TAG_DONE );
				obj->isgadtools = ogw->usesgadtools = 1;

				return( NULL );
			}

			posgad( g, ogw, ogg, obj, OGPOS_EXPAND_X );
			g->Flags		= GFLG_GADGHCOMP;
			if( obj->disable )
				g->Flags |= GFLG_DISABLED;
			g->Activation	= GACT_RELVERIFY;
			g->GadgetType 	= BOOLGADGET;
			g->GadgetID 	= obj->id;
			g->GadgetRender = makebevelborder( ogw, g->Width, g->Height, FALSE );
			if( obj->title )
			{
				it = makeitext( ogw, obj->title, 0, 2 );
				centeritext( it, obj->xs );
				g->GadgetText = it;
			}
			break;

		case OGOBJ_CHECKBOX:
			/* Let Gadtools create the Gadget */
			if( ISV39 )
			{
				initgt( ogw );
				xs = stextlen( ogw, obj->title );
				posnewgad( &ng, ogw, ogg, obj, OGPOS_RIGHT );
				ng.ng_LeftEdge += ( ng.ng_Width - 26 );
				ng.ng_Width		= 26;
				/*ng.ng_Width -= xs + 8;
				ng.ng_LeftEdge += xs + 8;
				ng.ng_Width	   = min( 26, ng.ng_Width );*/
				ng.ng_GadgetID = obj->id;
				ng.ng_UserData = obj;
				ng.ng_Flags	   = PLACETEXT_LEFT;
				if( obj->title )
					ng.ng_GadgetText = obj->title;

				obj->g = ogw->gtlastg = CreateGadget( CHECKBOX_KIND, ogw->gtlastg, &ng, GT_Underscore, '_', GTCB_Checked, obj->defaultvalue, GTCB_Scaled, TRUE, GA_Disabled, obj->disable, TAG_DONE );
				obj->isgadtools = ogw->usesgadtools = 1;

				return( NULL );
			}
			ys = ogw->used_font->tf_YSize + 4;
			xs = stextlen( ogw, obj->title );
			posgad( g, ogw, ogg, obj, OGPOS_RIGHT );
			g->LeftEdge += g->Width - 30;
			g->Width     = 30;
			/*g->Height		= ys;*/
			g->Flags		= GFLG_GADGHIMAGE;
			if( obj->disable )
				g->Flags |= GFLG_DISABLED;
			g->Activation	= GACT_IMMEDIATE | GACT_TOGGLESELECT;
			g->GadgetType 	= GTYP_BOOLGADGET;
			g->GadgetID 	= obj->id;
			g->GadgetRender = makecheckborder( ogw, 30, ys, FALSE );
			g->SelectRender = makecheckborder( ogw, 30, ys, TRUE );
			if( obj->title )
			{
				it = makeitext( ogw, obj->title, - textlen( ogw, obj->title ) - 10 , 2 );
				g->GadgetText = it;
			}
			if( obj->defaultvalue )
				g->Flags |= GFLG_SELECTED;
			break;

		case OGOBJ_TEXT:
			xs = stextlen( ogw, obj->title );
			posgad( g, ogw, ogg, obj, OGPOS_RIGHT );
			g->Width    -= xs + 8;
			g->LeftEdge += xs + 8;
			g->Flags	 = GFLG_GADGHNONE;
			if( obj->disable )
				g->Flags |= GFLG_DISABLED;
			g->GadgetType = GTYP_BOOLGADGET;
			g->GadgetID   = obj->id;
			if( obj->ychars )
			{
				b = g->GadgetRender = makebevelborder( ogw, g->Width, g->Height, TRUE );
				/*b->TopEdge = b->NextBorder->TopEdge = -2;
				b->LeftEdge= b->NextBorder->LeftEdge = -4;*/
			}
			if( obj->title )
			{
				obj->it_t = it = makeitext( ogw, obj->title, - textlen( ogw, obj->title ) - 8, 2 );
				g->GadgetText = it;
			}
			p = obj->defaultstring;
			obj->defaultstring = OGALLOC( ogw, 256 );
			if( p )
				strcpy( obj->defaultstring, p );
			obj->it_c = it = makeitextnu( ogw, obj->defaultstring, 8, 2 );
			/*obj->it_c->DrawMode = JAM2;*/
			attachitext( it, g->GadgetText );

			break;

		case OGOBJ_CYCLE:
			xs = stextlen( ogw, obj->title );
			/* Let Gadtools create the Gadget */
			if( ISV37 )
			{
				initgt( ogw );
				posnewgad( &ng, ogw, ogg, obj, obj->num ? OGPOS_EXPAND_X : OGPOS_RIGHT );
				ng.ng_Width -= xs + 8;
				ng.ng_LeftEdge += xs + 8;
				ng.ng_GadgetID = obj->id;
				ng.ng_UserData = obj;
				ng.ng_Flags	   = PLACETEXT_LEFT;
				if( obj->title )
					ng.ng_GadgetText = obj->title;

				obj->g = ogw->gtlastg = CreateGadget( CYCLE_KIND, ogw->gtlastg, &ng,
					GT_Underscore, '_', 
					GTCY_Labels, obj->entries,
					GTCY_Active, obj->defaultvalue,
					GA_Disabled, obj->disable,
					TAG_DONE
				);
				obj->isgadtools = ogw->usesgadtools = 1;

				return( NULL );
			}
			posgad( g, ogw, ogg, obj, obj->num ? OGPOS_EXPAND_X : OGPOS_RIGHT );
			g->Width -= xs + 8;
			g->LeftEdge += xs + 8;
			g->Activation	= GACT_RELVERIFY;
			g->Flags		= GFLG_GADGHCOMP;
			if( obj->disable )
				g->Flags |= GFLG_DISABLED;
			g->GadgetType 	= GTYP_BOOLGADGET;
			g->GadgetID 	= obj->id;
			b = g->GadgetRender = makecycleborder( ogw, g->Width, g->Height );
			if( obj->title )
			{
				obj->it_t = makeitext( ogw, obj->title, -xs - 8, 2 );
			}
			obj->it_c = makeitext( ogw, "", 28, 2 );
			makecycletext( ogw, obj );
			break;

		case OGOBJ_LIST:
			posgad( g, ogw, ogg, obj, OGPOS_EXPAND );
			g->Width		-= 16;
			if( obj->title )
			{
				c = ogw->used_font->tf_YSize + 1;
				obj->it_t = makeitext( ogw, obj->title, 0, -c );
				centeritext( obj->it_t, g->Width );
				g->Height -= c;
				g->TopEdge += c;
			}
			g->Flags		= GFLG_GADGHNONE | GFLG_GADGIMAGE;
			g->Activation	= GACT_RELVERIFY | GACT_IMMEDIATE | GACT_FOLLOWMOUSE;
			g->GadgetType 	= GTYP_BOOLGADGET;
			g->GadgetID 	= obj->id;

			obj->xchars = ( g->Width - 8 ) / ogw->lvfont->tf_XSize;
			obj->ychars = ( g->Height - 5 ) / ( ogw->lvfont->tf_YSize + 1 );

			g2 = g;

			b = makebevelborder( ogw, g->Width, g->Height, FALSE );
			b->LeftEdge -= g->Width;
			b->NextBorder->LeftEdge -= g->Width;

			if( obj->shortcut == 0xff )
			{
				obj->b_f = makebevelborder( ogw, g->Width - 4, ogw->lvfont->tf_YSize + 2, TRUE );
				if( obj->b_f )
				{
					obj->b_f->LeftEdge = -g->Width + 2;
					obj->b_f->NextBorder->LeftEdge = -g->Width + 2;
				}
			}


			/* Scroller-BorderGadget */
			obj->bordg = g = OGALLOC( ogw, sizeof( *g ) );
			if( !g )
				return( NULL );
			g->LeftEdge = g2->LeftEdge + g2->Width;
			g->TopEdge  = g2->TopEdge;
			g->Width	= 16;
			g->Height	= g2->Height - 24;
			g->Flags	= GFLG_GADGHNONE;
			g->GadgetType = GTYP_BOOLGADGET;
			g->GadgetID	  = 0x8000 | obj->id;
			g->GadgetRender = makebevelborder( ogw, g->Width, g->Height, FALSE );
			attachborder( b, g->GadgetRender );
			obj->b_b = g->GadgetRender;

			g->NextGadget = g2;
			g2 = g;

			/* Scroller-Scroller */
			autoknobimage = OGALLOC( ogw, sizeof( *autoknobimage ) );
			if( !autoknobimage )
				return( NULL );
			pi = OGALLOC( ogw, sizeof( *pi ) );
			if( !pi )
				return( NULL );
			obj->scroll = g = OGALLOC( ogw, sizeof( *g ) );
			if( !g )
				return( NULL );
			pi->Flags = PROPBORDERLESS | AUTOKNOB | FREEVERT;
			pi->VertBody = MAXBODY;
			*g = *g2;
			g->Width -= 8;
			g->LeftEdge += 4;
			g->Height -= 4;
			g->TopEdge += 2;
			g->Flags	= GFLG_GADGHCOMP;
			g->Activation = GACT_RELVERIFY | GACT_IMMEDIATE | GACT_FOLLOWMOUSE;
			g->GadgetType = GTYP_PROPGADGET;
			g->GadgetID	  = 0x9000 | obj->id;
			g->GadgetRender = autoknobimage;
			g->SpecialInfo = pi;
			g->UserData = obj;

			g->NextGadget = g2;
			g2 = g;

			/* Button-Up */
			g = OGALLOC( ogw, sizeof( *g ) );
			if( !g )
				return( NULL );
			*g = *g2;
			g->Width = 16;
			g->LeftEdge -= 4;
			g->TopEdge += g->Height + 2;
			g->Height = 12;
			g->Flags	= GFLG_GADGHCOMP;
			g->Activation = GACT_RELVERIFY | GACT_IMMEDIATE;
			g->GadgetType = GTYP_BOOLGADGET;
			g->GadgetID	  = 0xa000 | obj->id;
			g->GadgetRender = makearrowborder( ogw, g->Width, g->Height, TRUE );
			g->UserData = obj;

			g->NextGadget = g2;
			g2 = g;

			/* Button-Down  */
			g = OGALLOC( ogw, sizeof( *g ) );
			if( !g )
				return( NULL );
			*g = *g2;
			g->TopEdge += 12;
			g->GadgetID	  = 0xb000 | obj->id;
			g->GadgetRender = makearrowborder( ogw, g->Width, g->Height, FALSE );
			g->UserData = obj;

			g->NextGadget = g2;
			g2 = g;

			makelisttexts( ogw, obj );
			setlistscroller( ogw, obj );

			/*obj->g = g;*/

			break;

		case OGOBJ_STRING:
		case OGOBJ_INTEGER:
			xs = stextlen( ogw, obj->title );
			if( !xs )
				xs = -4;
			posgad( g, ogw, ogg, obj, ogg->ogp ? OGPOS_EXPAND_X : OGPOS_RIGHT );
			g->TopEdge += 2;
			g->Height = ogw->used_font->tf_YSize;
			g->Width -= xs + 12;
			g->LeftEdge += xs + 8;
			g->Flags		= GFLG_GADGHCOMP | GFLG_TABCYCLE;
			if( obj->disable )
				g->Flags |= GFLG_DISABLED;
			g->Activation	= GACT_RELVERIFY;
			if( obj->type == OGOBJ_INTEGER )
				g->Activation |= GACT_LONGINT;
			g->GadgetType 	= GTYP_STRGADGET;
			g->GadgetID 	= obj->id;
			b = g->GadgetRender = makestringborder( ogw, g->Width + 8, g->Height + 4, FALSE );
			b->TopEdge = b->NextBorder->TopEdge = -2;
			b->LeftEdge= b->NextBorder->LeftEdge = -4;
			if( obj->title )
			{
				it = makeitext( ogw, obj->title, - textlen( ogw, obj->title ) - 8, 0 );
				g->GadgetText = it;
			}
			si = OGALLOC( ogw, sizeof( *si ) );
			if( !si )
				return( NULL );
			g->SpecialInfo = si;

			si->Buffer = OGALLOC( ogw, obj->maxchars );
			if( !si->Buffer )
				return( NULL );
			si->UndoBuffer = undobuffer;
			si->MaxChars = obj->maxchars;
			if( obj->type == OGOBJ_INTEGER )
			{
				sprintf( si->Buffer, "%ld", obj->defaultvalue );
				si->LongInt = obj->defaultvalue;
			}
			else
			{
				if( obj->defaultstring )
					stccpy( si->Buffer, obj->defaultstring, obj->maxchars );
			}

			/* On V37++, add StringExtend & EditHook */
			if( ISV37 )
			{
				sex = OGALLOC( ogw, sizeof( *sex ) );
				if( !sex )
					return( NULL );
				sex->Pens[0] = ogw->pens[ TEXTPEN ];
				sex->Pens[2] = ogw->pens[ FILLTEXTPEN ];
				sex->Pens[3] = ogw->pens[ FILLPEN ];
				sex->InitialModes = SGM_EXITHELP;
				if( !ogw->string_workbuffer )
					ogw->string_workbuffer = OGALLOC( ogw, 8192 );
				sex->WorkBuffer = ogw->string_workbuffer;
				sex->EditHook = &stringhook;

				si->Extension = sex;
				g->Flags |= GFLG_STRINGEXTEND;
			}
			break;

		case OGOBJ_FUELGAUGE:
			obj->defaultstring = OGALLOC( ogw, 16 );
			if( !obj->defaultstring )
				return( NULL );
			strcpy( obj->defaultstring, "0%" );

			posgad( g, ogw, ogg, obj, OGPOS_EXPAND );
			g->Flags		= GFLG_GADGHNONE;
			if( obj->disable )
				g->Flags |= GFLG_DISABLED;
			g->GadgetType 	= GTYP_BOOLGADGET;
			g->GadgetID 	= obj->id;
			g->GadgetRender = makebevelborder( ogw, g->Width, g->Height, TRUE );
			g2 = g;

			/* Text/Image-Gadget */
			obj->im = OGALLOC( ogw, sizeof( *im ) );
			if( !obj->im )
				return( NULL );

			im = OGALLOC( ogw, sizeof( *im ) );
			if( !im )
				return( NULL );

			g = OGALLOC( ogw, sizeof( *g ) );
			if( !g )
				return( NULL );
			*g = *g2;
			g->GadgetID	  = 0x9000 | obj->id;
			g->Flags	 |= GFLG_GADGIMAGE;
			g->GadgetRender = obj->im;
			obj->im->PlaneOnOff = ogw->pens[ FILLPEN ];
			obj->im->LeftEdge = 2;
			obj->im->TopEdge = 1;
			obj->im->Width = g->Width - 4;
			obj->im->Height = g->Height - 2;
			obj->im->Depth = ogw->scr->RastPort.BitMap->Depth;
			*im = *obj->im;
			obj->im->NextImage = im;
			im->PlaneOnOff = 0;
			obj->it_c = g->GadgetText = makeitext( ogw, obj->defaultstring, 0, 2 );
			obj->it_c->DrawMode = JAM1;
			obj->xchars = obj->im->Width;

			makefuelimage( ogw, obj );

			g->NextGadget = g2;
			obj->g = g;

			break;

		case OGOBJ_PENSEL:
			xs = stextlen( ogw, obj->title );
			/* Let Gadtools create the Gadget */
			if( ISV37 )
			{
				initgt( ogw );
				posnewgad( &ng, ogw, ogg, obj, OGPOS_EXPAND_X );
				ng.ng_Width -= xs + 12 + ( ( ISV39 ) ? 0 :  24 );
				ng.ng_LeftEdge += xs + 12 + ( ( ISV39 ) ? 0 :  24 );
				ng.ng_GadgetID = obj->id;
				ng.ng_UserData = obj;
				ng.ng_Flags	   = PLACETEXT_LEFT;
				if( obj->title )
					ng.ng_GadgetText = obj->title;

				obj->num = 1 << ogw->scr->RastPort.BitMap->Depth;

				obj->g = ogw->gtlastg = CreateGadget( PALETTE_KIND, ogw->gtlastg, &ng,
					GT_Underscore, '_', 
					GTPA_IndicatorWidth, 24, 
					GTPA_Color, obj->defaultvalue,
					GTPA_Depth, ogw->scr->RastPort.BitMap->Depth,
					GA_Disabled, obj->disable,
					TAG_DONE
				);
				obj->isgadtools = ogw->usesgadtools = 1;

				return( NULL );
			}
			break;
	}

	return( g );
}


/* Create Gadget */
static void creategads( struct ogwin *ogw, struct oggroup *ogg )
{
	struct Gadget *g;
	struct ogobj *obj;
	struct IntuiText *it;

	/* Create Frame Gadget */
	g = OGALLOC( ogw, sizeof( *g ) );
	if( !g )
		return;
	g->LeftEdge = ogg->x + ogw->windowxoffs;
	g->TopEdge	= ogg->y + ogw->windowyoffs;
	g->Width	= g->Height = 1;
	g->Flags		= GFLG_GADGHNONE;
	g->GadgetType	= BOOLGADGET;
	g->GadgetID 	= (USHORT)~0;
	if( ogg->frame )
		g->GadgetRender = makeframeborder( ogw, ogg );

	if( ogg->title )
	{
		it = makeitext( ogw, ogg->title, 0, 1 );
		centeritext( it, ogg->xs );
		g->GadgetText = it;
		it->DrawMode = JAM2;
	}

	g->NextGadget = ogw->glist;
	ogw->glist = g;

	/* Create Object Gadgets */
	for( obj = (struct ogobj *) ogg->obj.mlh_Head;
		 obj->n.mln_Succ;
		 obj = (struct ogobj *) obj->n.mln_Succ )
	{
		g = makeobj( ogw, ogg, obj );

		if( g )
			attachgad( g, ogw->glist );
	}

}

static void mysetreqpos( UBYTE reqpos, struct NewWindow *nw )
{
	struct Screen *scr = nw->Screen;

	switch( reqpos )
	{
		case 0:
		default:	// REQPOS_POINTER
			nw->LeftEdge = scr->MouseX - 10;
			nw->TopEdge = scr->MouseY - 10;
			break;

		case 1:		// REQPOS_CENTERWIN
			nw->LeftEdge = w->LeftEdge + ( w->Width - nw->Width ) / 2;
			nw->TopEdge = w->TopEdge + ( w->Height - nw->Height ) / 2;
			break;

		case 2:		// REQPOS_CENTERSCR
			nw->LeftEdge = ( scr->Width - nw->Width ) / 2;
			nw->TopEdge = ( scr->Height - nw->Height ) / 2;
			break;

		case 3:		// REQPOS_TOPLEFTWIN
			nw->LeftEdge = w->LeftEdge;
			nw->TopEdge = w->TopEdge;
			break;

		case 4:		// REQPOS_TOPLEFTSCR
			nw->LeftEdge = nw->TopEdge = 0;
			break;
	}

	if( nw->LeftEdge < 0 )
		nw->LeftEdge = 0;
	if( nw->TopEdge < 0 )
		nw->TopEdge = 0;

	if( nw->TopEdge + nw->Height >= scr->Height )
		nw->TopEdge = scr->Height - nw->Height - 1;

	if( nw->LeftEdge + nw->Width >= scr->Width )
		nw->LeftEdge = scr->Width - nw->Width - 1;

	if( nw->LeftEdge < 0 )
		nw->LeftEdge = 0;
	if( nw->TopEdge < 0 )
		nw->TopEdge = 0;

}

struct Window * ogreOpenWindow( struct ogwin *ogwin )
{
	struct oggroup *grp;
	struct NewWindow nw;
	int gx, gy;
	int doing_relayout = FALSE;
	static struct TextAttr top80 = { "topaz.font", 8, 0, 0 };

redo:

	ogwin->currentg = NULL;
	ogwin->windowxoffs = ogwin->scr->WBorLeft + 4;
	ogwin->windowyoffs = ogwin->scr->WBorTop + ogwin->font->tf_YSize + 3;

	/* Calculate Object Sizes */
	for( grp = (struct oggroup *) ogwin->groups.mlh_Head;
		 grp->n.mln_Succ;
		 grp = (struct oggroup *) grp->n.mln_Succ )
	{
		calcgroupobjs( ogwin, grp );
		layoutlist( ogwin, &grp->obj, &gx, &gy, 2 );
		grp->xs = gx;
		grp->ys = gy;
		layoutgroupframe( ogwin, grp );
	}

	/* We now have groups of properly formated Rectangeles */
	/* We now must perform Group ordering */
	layoutgroups( ogwin );

	/* Check Widths */
	nw.Width = ogwin->windowx + ogwin->scr->WBorLeft + ogwin->scr->WBorRight + 4;
	nw.Height = ogwin->windowy + ogwin->scr->WBorTop + ogwin->scr->WBorBottom + ogwin->font->tf_YSize + 4;
	nw.LeftEdge = ( ogwin->screenx - nw.Width ) / 2;
	nw.TopEdge  = ( ogwin->screeny - nw.Height ) / 2;

	if( nw.LeftEdge < 0 || nw.TopEdge < 0 )
	{
		if( !doing_relayout )
		{
			doing_relayout = TRUE;
			ogwin->lvfont = ogwin->used_font = OpenFont( &top80 );
			ogwin->lvfnta = ogwin->used_fnta = &top80;
			ogwin->fontxsize = 8;
			CloseFont( ogwin->used_font );
			goto redo;
		}

		displaybeep();
		askreq( "Fenster\n%s\nkonnte nicht geöffnet werden:\nzu wenig Platz auf dem Bildschirm!", "Abbruch", ogwin->title );
		ogreExitWindow( ogwin );
		return( NULL );
	}

	/* Create Object Gadgets */
	for( grp = (struct oggroup *) ogwin->groups.mlh_Head;
		 grp->n.mln_Succ;
		 grp = (struct oggroup *) grp->n.mln_Succ )
	{
		creategads( ogwin, grp );
	}

	/* Attach Gadtools */
	if( ogwin->gtglist )
		attachgad( ogwin->gtglist, ogwin->glist );

	/* Open Window */
	memset( &nw, 0, sizeof( nw ) );
	nw.Width = ogwin->windowx + ogwin->scr->WBorLeft + ogwin->scr->WBorRight + 4;
	nw.Height = ogwin->windowy + ogwin->scr->WBorTop + ogwin->scr->WBorBottom + ogwin->font->tf_YSize + 4;

/*
	nw.LeftEdge = ( ogwin->screenx - nw.Width ) / 2;
	nw.TopEdge  = ( ogwin->screeny - nw.Height ) / 2;
*/

	nw.DetailPen = ogwin->pens[ DETAILPEN ];
	nw.BlockPen = ogwin->pens[ BLOCKPEN ];
	nw.Flags = ogwin->flags | WFLG_DRAGBAR | WFLG_ACTIVATE | WFLG_RMBTRAP;
	if( ogwin->flags & WFLG_ACTIVATE )
		nw.Flags &= ~WFLG_ACTIVATE;
	if( ogwin->flags & WFLG_RMBTRAP )
		nw.Flags &= ~WFLG_RMBTRAP;

	if( wbwindow )
		nw.Flags |= WFLG_DEPTHGADGET;

	nw.FirstGadget = ogwin->glist;
	nw.IDCMPFlags = ogwin->idcmp | IDCMP_REFRESHWINDOW | IDCMP_RAWKEY | IDCMP_CLOSEWINDOW;
	nw.Title = ogwin->title;
	nw.Screen = ogwin->scr;
	nw.MinWidth = 0;
	nw.MinHeight = 0;
	nw.MaxWidth	= (UWORD)~0;
	nw.MaxHeight = (UWORD)~0;
	nw.Type = CUSTOMSCREEN;

	mysetreqpos( prefs.reqpos, &nw );

	ogwin->w = OpenWindow( &nw );

	if( ogwin->usesgadtools )
		GT_RefreshWindow( ogwin->w, NULL );
	return( ogwin->w );
}

void ogreLVInit( struct ogwin *ogw, UWORD id )
{
	struct List *l = OGALLOC( ogw, sizeof( struct MinList ) );
	struct ogobj *obj = findobj( ogw, id );

	if( !l || !obj )
		return;
	NewList( l );
	obj->l = l;
}

/* Adjust top so that Item is visible */
static void adjustlv( struct ogobj *obj, int item )
{
	/* Is already visible ? */
	if( item < 0 || ( item >= obj->top && item < obj->top + obj->ychars ) )
		return;

	/* Zu hoch */
	if( item < obj->top )
	{
		obj->top = item;
		return;
	}
	/* Zu tief */
	obj->top = item - obj->ychars + 1;
	if( obj->top < 0 )
		obj->top = 0;

}

int ogreLVAddEntry( struct ogwin *ogw, UWORD id, char *txt, UWORD flags, void *userdata )
{
	struct ogrevn *vn;
	struct ogobj *obj;
	char *p;
	int c;

	obj = findobj( ogw, id );
	if( !obj )
		return( -1 );

	if( !obj->l )
		ogreLVInit( ogw, obj->id );
	if( !obj->l )
		return( -1 );

	vn = OGALLOC( ogw, sizeof( *vn ) );
	if( !vn )
		return( -1 );

	if( flags & 2 )
	{
		p = OGALLOC( ogw, strlen( txt ) +1 );
		if( !p )
			return( -1 );
		strcpy( p, txt );
		txt = p;
	}

	vn->sel = flags & 1;
	vn->txt = txt;
	vn->userdata = userdata;

	AddTail( obj->l, (struct Node *) vn );

	vn = (struct ogrevn *) vn->n.mln_Pred;

	c = 0;
	while( vn->n.mln_Pred )
	{
		if( !obj->flags && ( flags & 1 ) )
			vn->sel = 0;
		c++;
		vn = (struct ogrevn *) vn->n.mln_Pred;
	}

	if( ogw->w )
		adjustlv( obj, c );

	return( c );
}

#define isShift(im) ((im)->Qualifier&(IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))

static void activatenextstring( struct ogwin *ogw, struct ogobj *obj )
{
	struct Gadget *g = obj->g->NextGadget;
	int m;

	if( obj->top )
		return;

	for( ;; )
	{
		if( !g )
			g = ogw->w->FirstGadget;

		m = g->GadgetType & GTYP_GTYPEMASK;
		if( m == GTYP_STRGADGET && !( g->Flags & GFLG_DISABLED ) )
		{
			if( g == obj->g )
				return;
			ActivateGadget( g, ogw->w, NULL );
			return;
		}
		g = g->NextGadget;
	}
}

static void lvdeselectall( struct ogobj *obj )
{
	struct ogrevn *vn = ( struct ogrevn *) obj->l->lh_Head;

	while( vn->n.mln_Succ )
	{
		if( vn->sel )
		{
			vn->sel = 0;
			vn->changed = 0;
		}
		vn = (struct ogrevn *) vn->n.mln_Succ;
	}
}

/* Draw Listview Entries */
static void drawlistviewentries( struct ogwin *ogw, struct ogobj *obj )
{
	DrawImage( ogw->w->RPort, ( struct Image *) obj->g->GadgetRender, obj->g->LeftEdge, obj->g->TopEdge );
	PrintIText( ogw->w->RPort, ( struct IntuiText *) obj->g->GadgetText, obj->g->LeftEdge, obj->g->TopEdge );
}

/* Draw one listview entry */
static void drawlistviewentry( struct ogwin *ogw, struct ogobj *obj, int n )
{
	struct IntuiText *it, *oldit;
	struct Image *im, *oldim;

	if( n < 0 || n >= obj->ychars )
		return;
	n = obj->ychars - n - 1;

	/* Pointer auf entsprechende Objekte holen */
	for( it = obj->it_c, im = obj->im; n && it && im; it = it->NextText, im = im->NextImage, n-- );
	if( !im || !it )
		return;

	/* Alte Next speichern */
	oldit = it->NextText;
	oldim = im->NextImage;

	it->NextText = NULL;
	im->NextImage = NULL;

	DrawImage( ogw->w->RPort, im, obj->g->LeftEdge, obj->g->TopEdge );
	PrintIText( ogw->w->RPort, it, obj->g->LeftEdge, obj->g->TopEdge );

	it->NextText = oldit;
	im->NextImage = oldim;

}

/* Optimized Redraw */
static void drawlistviewchanged( struct ogwin *ogw, struct ogobj *obj )
{
	int c;
	struct ogrevn *vn;

	for( c = 0; c < obj->ychars; c++ )
	{
		vn = getentry( obj, c + obj->top );
		if( vn )
		{
			if( !vn->changed )
			{
				drawlistviewentry( ogw, obj, c );
				vn->changed = 1;
			}
		}
	}
}


/* Einen hoch */
static void lvup( struct ogwin *ogw, struct ogobj *obj )
{
	if( !obj->top )
		return;

	obj->top--;
	makelisttexts( ogw, obj );

	ScrollRaster( ogw->w->RPort,
		0, - ( ogw->lvfont->tf_YSize + 1 ),
		obj->g->LeftEdge + 2,
		obj->g->TopEdge + 2,
		obj->g->LeftEdge + obj->xs - 19,
		obj->g->TopEdge + 2 + ( obj->ychars * ( ogw->lvfont->tf_YSize + 1 ) )
	);

	drawlistviewentry( ogw, obj, 0 );
}

/* Einen runter */
static void lvdown( struct ogwin *ogw, struct ogobj *obj )
{
	if( obj->top >= obj->num - obj->ychars )
		return;

	obj->top++;
	makelisttexts( ogw, obj );

	ScrollRaster( ogw->w->RPort,
		0, ogw->lvfont->tf_YSize + 1,
		obj->g->LeftEdge + 2,
		obj->g->TopEdge + 2,
		obj->g->LeftEdge + obj->xs - 19,
		obj->g->TopEdge + 2 + ( obj->ychars * ( ogw->lvfont->tf_YSize + 1 ) )
	);

	drawlistviewentry( ogw, obj, obj->ychars - 1 );
}

static void lvmakevisible( struct ogwin *ogw, struct ogobj *obj, int newtop )
{
	int dir, delta;

	delta = abs( newtop - obj->top );
	dir = obj->top > newtop;

	if( !delta )
		return;

	if( delta >= ( obj->ychars - 2 ) )
	{
		obj->top = newtop;
		makelisttexts( ogw, obj );
		RefreshGList( obj->g, ogw->w, NULL, 1 );
		return;
	}

	while( delta-- )
	{
		if( dir )
			lvup( ogw, obj );
		else
			lvdown( ogw, obj );
	}

}


/* Process ListView events */
static void dolistview( struct ogwin *ogw, struct ogobj *obj )
{
	struct Gadget *g = ogw->cim.IAddress;
	int id = g->GadgetID >> 12;
	struct PropInfo *pi = obj->scroll->SpecialInfo;
	struct IntuiMessage *im;
	int newtop, ticker, oldticker = -1;
	struct ogrevn *vn;

	switch( id )
	{
		/* Scroller Event */
		case 0x9:
			if( ogw->cim.Class == IDCMP_GADGETUP )
			{
				newtop = FindScrollerTop( obj->num, obj->ychars, pi->VertPot );
				lvmakevisible( ogw, obj, newtop );

			}
			/* Down or Mousemove */
			for( ;; )
			{
				while( !( im = GetIMsg( ogw->w->UserPort ) ) )
					mWaitPort( ogw->w->UserPort );

				if( im->Class != IDCMP_MOUSEMOVE && im->Class != IDCMP_INTUITICKS )
					break;

				newtop = FindScrollerTop( obj->num, obj->ychars, pi->VertPot );
				lvmakevisible( ogw, obj, newtop );
				ReplyIMsg( im );
			}
			ReplyIMsg( im );
			newtop = FindScrollerTop( obj->num, obj->ychars, pi->VertPot );
			lvmakevisible( ogw, obj, newtop );
			break;

		/* Button Up */
		case 0xa:
			ticker = -1;
			for( ;; )
			{
				if( ( ticker-- ) <= 0 )
				{
					lvup( ogw, obj );
					setlistscroller( ogw, obj );
					ticker = ( ticker < -1 ) ? 3 : 0;
				}

				while( !( im = GetIMsg( ogw->w->UserPort ) ) )
					mWaitPort( ogw->w->UserPort );

				if( im->Class != IDCMP_INTUITICKS )
					break;

				ReplyIMsg( im );
			} 
			ReplyIMsg( im );
			break;

		/* Button Up */
		case 0xb:
			ticker = -1;
			for( ;; )
			{
				if( ( ticker-- ) <= 0 )
				{
					lvdown( ogw, obj );
					setlistscroller( ogw, obj );
					ticker = ( ticker < -1 ) ? 3 : 0;
				}

				while( !( im = GetIMsg( ogw->w->UserPort ) ) )
					mWaitPort( ogw->w->UserPort );

				if( im->Class != IDCMP_INTUITICKS )
					break;

				ReplyIMsg( im );
			} 
			ReplyIMsg( im );
			break;

		/* Select */
		case 0x0:
			if( ogw->cim.Class != IDCMP_GADGETDOWN )
				break;

			while( ogw->cim.Class != IDCMP_GADGETUP && ogw->cim.Class != IDCMP_MOUSEBUTTONS )
			{
				if( ogw->cim.MouseX <= g->LeftEdge + 4 ||
					ogw->cim.MouseY <= g->TopEdge + 2 ||
					ogw->cim.MouseX >= g->LeftEdge + g->Width - 8 ||
					ogw->cim.MouseY >= g->TopEdge + g->Height - 4 )
						goto redo;
				ticker = ( ogw->cim.MouseY - g->TopEdge - 2 ) / ( ogw->lvfont->tf_YSize + 1 );
				if( ticker != oldticker )
				{
					oldticker = ticker;
					vn = getentry( obj, obj->top + ticker );
					if( vn )
					{
						obj->defaultvalue = obj->top + ticker;
						obj->minval = obj->top + ticker;
						/* Do Multi Select */
						if( obj->flags && isShift( ( &ogw->cim ) ) )
						{
							vn->sel ^= 1;
							makelisttexts( ogw, obj );
							drawlistviewentry( ogw, obj, ticker );
							/*RefreshGList( obj->g, ogw->w, NULL, 1 );*/
						}
						else
						{
							if( !vn->sel || obj->flags )
							{
								lvdeselectall( obj );
								vn->sel = 1;
								vn->changed = 0;
								makelisttexts( ogw, obj );
								drawlistviewchanged( ogw, obj );
								/*RefreshGList( obj->g, ogw->w, NULL, 1 );*/
							}
						}
					}
				}
redo:
				ogw->cim.Class = 0;
				while( ogw->cim.Class != IDCMP_MOUSEBUTTONS && ogw->cim.Class != IDCMP_MOUSEMOVE && ogw->cim.Class != IDCMP_GADGETUP )
				{
					while( ! ( im = GetIMsg( ogw->w->UserPort ) ) )
						mWaitPort( ogw->w->UserPort );
					ogw->cim = *im;
					ReplyIMsg( im );
				}
			}
			ogw->cim.Class = IDCMP_GADGETUP;
			ogw->cim.Qualifier = 2;
			return;

	}

	ogw->cim.Class = 0;
}


/* Process LV shortcut */
static void dolvshortcut( struct ogwin *ogw, struct ogobj *obj )
{
	int c, n;
	struct ogrevn *vn;

	/* Standard select next/last */
	if( obj->shortcut != 0xff )
	{
		c = getfirstselentry( obj );
		n = getnumentries( obj );

		if( isShift( &ogw->cim ) )
			c--;
		else
			c++;

		if( c < 0 )
			c = n - 1;
		if( c >= n )
			c = 0;

		if( c >= 0)
		{
			lvdeselectall( obj );
			vn = getentry( obj, c );
			obj->minval = c;
			if( vn )
			{
				if( !vn->sel )
				{
					vn->sel = 1;
					vn->changed = 0;
				}
			}
			adjustlv( obj, c );
			makelisttexts( ogw, obj );
			drawlistviewchanged( ogw, obj );
			setlistscroller( ogw, obj );
		}

	}

}

/* Process Cursor LV */
static int dolvcursorshortcut( struct ogwin *ogw, struct ogobj *obj )
{
	int c, d, e, n, rc = 0;
	struct ogrevn *vn = NULL;
	BOOL isshift = ogw->cim.Qualifier & ( IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT );
	BOOL isctrl  = ogw->cim.Qualifier & IEQUALIFIER_CONTROL;

	/* Standard select next/last */
	n = getnumentries( obj );
	c = e = obj->defaultvalue;

	switch( ogw->cim.Code )
	{

		case 0x3d:	/* Home */
			isctrl = TRUE;

		case 0x3f:	/* Seitenweise */
			isshift = TRUE;

		case 0x3e:
		case 0x4c:
			if( isshift )
				c -= obj->ychars;
			if( isctrl )
				c = 0;
			else
				c--;
			break;

		case 0x1d:	/* Home */
			isctrl = TRUE;

		case 0x1f:	/* Seitenweise */
			isshift = TRUE;

		case 0x1e:
		case 0x4d:
			if( isshift )
				c += obj->ychars;
			if( isctrl )
				c = MAXINT;
			else
				c++;
			break;

		case 0x44:
		case 0x43: 
			if( obj->flags && ( getfirstselentry( obj ) != -1 ) )
			{
				rc = 2;
				break;
			}
			rc = 1;
		case 0x40:
			rc++;
			vn = getentry( obj, c );
			obj->minval = c;
			if( !obj->flags )
				lvdeselectall( obj );
			if( vn )
			{
				vn->sel ^= 1;
				vn->changed = 0;
			}
			break;

		default:
			return( rc );
	}

	if( c < 0 )
		c = 0;
	if( c >= n )
		c = n - 1;

	if( c >= 0)
	{
		d = obj->top;
		obj->defaultvalue = c;
		adjustlv( obj, c );
		/* Kein Scrolling */
		if( ( obj->top ) == d && !vn )
		{
			makelisttexts( ogw, obj );
			drawlistviewentry( ogw, obj, e - obj->top );
		}
		else
		{
			if( !vn )
			{
				c = obj->top;
				obj->top = d;
				drawlistviewentry( ogw, obj, e - obj->top );
				lvmakevisible( ogw, obj, c );
			}
			else
			{
				makelisttexts( ogw, obj );
				drawlistviewentries( ogw, obj );
			}
		}
		setlistscroller( ogw, obj );
		DrawBorder( ogw->w->RPort, obj->bordg->GadgetRender, obj->bordg->LeftEdge, obj->bordg->TopEdge );
	}
	return( rc );
}

static void replyimsg( struct ogwin *ogw, struct IntuiMessage *im )
{
	if( im && im != &ogw->cim )
		ReplyIMsg( im );
}

struct ogobj *findobjbyshortcut( struct ogwin *ogw, int rks )
{
	struct Gadget *g;
	struct ogobj *obj, *obj_onesc = NULL, *obj_onenter = NULL;

	/* Zuerst nach 1:1-Uebereinstimmung suchen */
	g = ogw->w->FirstGadget;
	/* Alle Gadgets durchgehen */
	while( g )
	{
		obj = g->UserData;
		if( obj )
		{
			if( obj->shortcut == rks )
				return( obj );

			if( obj->on_esc )
				obj_onesc = obj;
			if( obj->on_enter )
				obj_onenter = obj;

		}
		g = g->NextGadget;
	}
	/* Dann ungeshiftet suchen */
	if( ! ( rks & 0x80 ) )
		goto shubbi;
	rks &= 0x7f;
	g = ogw->w->FirstGadget;
	while( g )
	{
		obj = g->UserData;
		if( obj )
		{
			if( obj->shortcut == rks )
				return( obj );
		}
		g = g->NextGadget;
	}

shubbi:

	/* Keine Übereinstimmung, Enter/ESC? */
	if( ( rks == 0x45 ) || ( rks == 0x5d ) || ( rks == 0x0f ) )
		return( obj_onesc );
	else if( rks == 0x43 )
		return( obj_onenter );
/*	else if( rks == 0x5f )
		return( ogw->helpgad );*/

	return( NULL );
}

static void drawimage( struct ogwin *ogw, struct ogobj *obj, BOOL sel )
{
	struct Gadget *g = obj->g;

	/* unter V37 einfach nur invertieren */
	if( ! ( obj->isgadtools ) )
	{
		ClipBlit( ogw->w->RPort, g->LeftEdge, g->TopEdge,
				  ogw->w->RPort, g->LeftEdge, g->TopEdge,
				  g->Width, g->Height, 0x50 );
		return;
	}

	DrawImageState( ogw->w->RPort, g->GadgetRender, g->LeftEdge, g->TopEdge, sel ? IDS_SELECTED : IDS_NORMAL, ogw->dri );
}


struct IntuiMessage *ogreIM( struct ogwin *ogw )
{
	struct IntuiMessage *im;
	struct ogobj *obj;
	struct Gadget *g;
	long val;
	int c;
	int rks;

	if( ogw->usesgadtools )
		im = GT_GetIMsg( ogw->w->UserPort );
	else
		im = GetIMsg( ogw->w->UserPort );
	if( !im )
		return( NULL );

	if( im->IDCMPWindow != ogw->w )
		return( im );

	if( im->Class == IDCMP_REFRESHWINDOW )
	{
		if( ogw->usesgadtools )
		{
			GT_BeginRefresh( ogw->w );
			GT_EndRefresh( ogw->w, TRUE );
		}
		else
		{
			BeginRefresh( ogw->w );
			EndRefresh( ogw->w, TRUE );
		}
	}

	if( im->Class == IDCMP_INTUITICKS )
	{
		replyimsg( ogw, im );
		return( NULL );
	}

	/* Rawkey-Event */
	if( im->Class == IDCMP_RAWKEY )
	{
		rks = im->Code;

		/* Down */
		if( ( rks != 0x5f ) && ( ! ( rks & 0x80 ) ) )
		{
			/* Eventuell Cursor-Listview ? */
			if( ogw->hascursorlv &&
				( im->Code == 0x4c || im->Code == 0x4d || im->Code == 0x40 || im->Code == 0x43 || im->Code == 0x44 ||
				( im->Code >= 0x1d && im->Code <= 0x1f ) ||
				( im->Code >= 0x3d && im->Code <= 0x3f ) ) )
			{
				ogw->cim = *im;
				replyimsg( ogw, im );
				im = &ogw->cim;
				obj = findobj( ogw, ogw->hascursorlv );
				c = dolvcursorshortcut( ogw, obj );
				if( c )
				{
					im->Qualifier = ( c == 2 ) ? 1 : 0;
					im->Class = GADGETUP;
					im->Code = obj->id;
					return( im );
				}
				return( NULL );
			}

			if( isShift( im ) )	rks |= 0x80;
			ogw->cim = *im;
			replyimsg( ogw, im );
			im = &ogw->cim;
			obj = findobjbyshortcut( ogw, rks );
			if( !obj || obj->disable || ( obj->type != OGOBJ_BUTTON && obj->type != OGOBJ_CYCLE && obj->type != OGOBJ_CHECKBOX && obj->type != OGOBJ_LIST && obj->type != OGOBJ_PENSEL ) )
				return( im );

			ogw->has_down = TRUE;

			rks &= 0x7f;

			drawimage( ogw, obj, TRUE );

			c = TRUE;

			/* Weiterwarten... */
			for(;;)
			{
				while( ! ( im = GetIMsg( ogw->w->UserPort ) ) )
					mWaitPort( ogw->w->UserPort );
				if( im->Class == RAWKEY )
				{
					/* Aborted? */
					if( im->Code < 0x80 && im->Code != rks && c )
					{
						drawimage( ogw, obj, FALSE );
						c = FALSE;
						ogw->has_down = FALSE;
					}
					if( im->Code == ( rks | 0x80 ) )
						break;
				}
				ReplyIMsg( im );
			}

			ogw->cim = *im;
			ReplyIMsg( im );
			im = &ogw->cim;

			if( c )
			{
				drawimage( ogw, obj, FALSE );
				goto processkey;
			}
			
			return( NULL );
		}
		/* Gadget-Help */
		if( rks == 0x5f )
		{
			g = ogw->w->FirstGadget;

			while( g )
			{
				if( ( obj = g->UserData ) &&
					im->MouseX >= g->LeftEdge &&
					im->MouseY >= g->TopEdge &&
					im->MouseX < g->LeftEdge + g->Width &&
					im->MouseY < g->TopEdge + g->Height )
				{
redo:
					ogw->cim = *im;
					replyimsg( ogw, im );
					im = &ogw->cim;
					im->Class = IDCMP_GADGETHELP;
					if( obj->id == OGID_HELP )
						im->Code = (USHORT) -1;
					else
						im->Code = obj->id;
					return( im );
				}
				g = g->NextGadget;
			}

			ogw->cim = *im;
			replyimsg( ogw, im );
			im = &ogw->cim;
			im->Class = IDCMP_GADGETHELP;
			im->Code = ( USHORT ) -1;
			return( im );
		}
		rks &= 0x7f;

processkey:
		if( isShift( im ) )	rks |= 0x80;
		obj = findobjbyshortcut( ogw, rks );
		if( obj )
		{
			ogw->cim = *im;
			replyimsg( ogw, im );
			im = &ogw->cim;
			im->IAddress = obj->g;
			g = obj->g;
			if( obj->disable )
				return( NULL );
			if( ( g->GadgetType & GTYP_GTYPEMASK ) == GTYP_STRGADGET )
			{
				ActivateGadget( obj->g, ogw->w, NULL );
				return( NULL );
			}
			else
			{
				if( !ogw->has_down )
					return( NULL );
				ogw->has_down = FALSE;
				if( obj->type == OGOBJ_CHECKBOX )
				{
					if( obj->isgadtools )
					{
						obj->defaultvalue = !obj->defaultvalue;
						GT_SetGadgetAttrs( obj->g, ogw->w, NULL, GTCB_Checked, obj->defaultvalue, TAG_DONE );
					}
					else
					{
						g->Flags ^= GFLG_SELECTED;
						RefreshGList( obj->g, ogw->w, NULL, 1 );
					}
				}
				else if( obj->type == OGOBJ_LIST )
				{
					dolvshortcut( ogw, obj );
				}
				else if( obj->type == OGOBJ_CYCLE && obj->isgadtools )
				{
					c = obj->defaultvalue;
					if( isShift( im ) )
						c--;
					else
						c++;
					if( c < 0 )
						c = obj->num -1;
					if( c >= obj->num )
						c = 0;
					obj->defaultvalue = c;
					GT_SetGadgetAttrs( obj->g, ogw->w, NULL, GTCY_Active, c, TAG_DONE );
					im->Class = IDCMP_GADGETUP;
					im->Code  = obj->id;
					return( im );
				}
				else if( obj->type == OGOBJ_PENSEL && obj->isgadtools )
				{
					c = obj->defaultvalue;
					if( isShift( im ) )
						c--;
					else
						c++;
					if( c < 0 )
						c = obj->num -1;
					if( c >= obj->num )
						c = 0;
					obj->defaultvalue = c;
					GT_SetGadgetAttrs( obj->g, ogw->w, NULL, GTPA_Color, c, TAG_DONE );
					im->Class = IDCMP_GADGETUP;
					im->Code  = obj->id;
					return( im );
				}
				im->Class = GADGETUP;
				goto doevent;
			}
		}
	}


	if ( ! ( im->Class & ( IDCMP_GADGETUP | IDCMP_GADGETDOWN ) ) )
		return( im );

	g = (struct Gadget *) im->IAddress;
	obj = g->UserData;

	if( !obj )
		return( im );

	/* Event kopieren */
	ogw->cim = *im;
	replyimsg( ogw, im );
	im = &ogw->cim;

doevent:
	switch( obj->type )
	{
		case OGOBJ_BUTTON:
			if( obj->shortcut == 0x5f )
			{
				im->Class = IDCMP_GADGETHELP;
				im->Code = ( USHORT ) -1;
				return( im );
			}
			break;

		case OGOBJ_PENSEL:
			obj->defaultvalue = im->Code;
			break;

		case OGOBJ_CHECKBOX:
			obj->defaultvalue = ( obj->g->Flags & GFLG_SELECTED );
			im->Class = IDCMP_GADGETUP;
			break;

		case OGOBJ_CYCLE:
			if( obj->isgadtools )
			{
				obj->defaultvalue = im->Code;
				break;
			}
			if( isShift( im ) )
				obj->defaultvalue--;
			else
				obj->defaultvalue++;
			makecycletext( ogw, obj );
			RefreshGList( obj->g, ogw->w, NULL, 1 );
			break;

		case OGOBJ_STRING:
		case OGOBJ_INTEGER:
			/* Exit-Help */
			if( im->Class == IDCMP_GADGETUP && im->Code == 0x5f )
			{
				im->Class = IDCMP_GADGETHELP;
				im->Code = obj->id;
				break;
			}
			if( im->Class == IDCMP_GADGETUP && im->Code == 0x70 )
			{
				break;
			}
			/* Minval/Maxval prüfen */
			if( obj->type == OGOBJ_INTEGER )
			{
				val = ( ( struct StringInfo *) obj->g->SpecialInfo ) -> LongInt;
				if( val < obj->minval || val > obj->maxval )
				{
					DisplayBeep( ogw->scr );
					if( val < obj->minval )
						val = obj->minval;
					else
						val = obj->maxval;
					sprintf( ( ( struct StringInfo *) obj->g->SpecialInfo )->Buffer, "%ld", val );
					( ( struct StringInfo *) obj->g->SpecialInfo )->LongInt = val;
					RefreshGList( obj->g, ogw->w, NULL, 1 );
					ActivateGadget( obj->g, ogw->w, NULL );
					break;
				}

			}

			if( isShift( im ) )
			{
				break;
			}

			/* Nächstes aktivieren */
			activatenextstring( ogw, obj );
			break;

		case OGOBJ_LIST:
			dolistview( ogw, obj );
			break;

	}
	im->Code = obj->id;
	return( im->Class ? im : NULL );
}

void ogreIMReply( struct ogwin *ogw, struct IntuiMessage *im )
{
	replyimsg( ogw, im );
}

void __stdargs ogreEnable( struct ogwin *ogw, BOOL set, ULONG id1, ...)
{
	struct ogobj *obj;
	ULONG *p = &id1;

	set = !set;
	if( ogw->w )
	{
		while( *p )
		{
			obj = findobj( ogw, *p++ );
			if( !obj )
				continue;
			if( ( obj->disable && set ) || ( !obj->disable && !set ) )
				continue;
			obj->disable = set;
			if( obj->isgadtools )
			{
				GT_SetGadgetAttrs( obj->g, ogw->w, NULL, GA_Disabled, set, TAG_DONE );
			}
			else
			{
				if( !set )
				{
					obj->g->Flags &= ~GFLG_DISABLED;
					SetAPen( ogw->w->RPort, 0 );
					RectFill( ogw->w->RPort, obj->g->LeftEdge, obj->g->TopEdge, obj->g->LeftEdge + obj->g->Width - 1, obj->g->TopEdge + obj->g->Height - 1 );
					RefreshGList( obj->g, ogw->w, NULL, 1 );
					/*OnGadget( obj->g, ogw->w, NULL );*/
				}
				else
				{
					obj->g->Flags |= GFLG_DISABLED;
					RefreshGList( obj->g, ogw->w, NULL, 1 );
				}
			}
		}
	}
	else
	{
		while( *p )
		{
			obj = findobj( ogw, *p++ );
			if( !obj )
				continue;
			obj->disable = set;
		}

	}
	return;
}

LONG ogreValue( struct ogwin *ogw, UWORD id )
{
	struct ogobj *obj = findobj( ogw, id );

	if( !obj )
		return( 0 );

	switch( obj->type )
	{
		case OGOBJ_CHECKBOX:
			obj->defaultvalue = obj->g->Flags & GFLG_SELECTED;
			return( ( LONG ) obj->defaultvalue );
	
		case OGOBJ_CYCLE:
		case OGOBJ_PENSEL:
			return( ( LONG ) obj->defaultvalue );

		case OGOBJ_LIST:
			return( getfirstselentry( obj ) );

		case OGOBJ_INTEGER:
			return( ( ( struct StringInfo *) obj->g->SpecialInfo ) -> LongInt );

		case OGOBJ_STRING:
			return( ( LONG ) ( ( struct StringInfo *) obj->g->SpecialInfo ) -> Buffer );

	}
	return( 0 );
}

void ogreSetValue( struct ogwin *ogw, UWORD id, LONG val )
{
	struct ogobj *obj = findobj( ogw, id );
	int c, d;

	if( !obj )
		return;

	switch( obj->type )
	{
		case OGOBJ_CHECKBOX:
			obj->defaultvalue = val;
			if( obj->isgadtools )
			{
				GT_SetGadgetAttrs( obj->g, ogw->w, NULL, GTCB_Checked, val, TAG_DONE );
			}
			else
			{
				if( val )
					obj->g->Flags |= GFLG_SELECTED;
				else
					obj->g->Flags &= ~GFLG_SELECTED;
				RefreshGList( obj->g, ogw->w, NULL, 1 );
			}
			return;
	
		case OGOBJ_CYCLE:
			obj->defaultvalue = val;
			if( obj->isgadtools )
			{
				GT_SetGadgetAttrs( obj->g, ogw->w, NULL, GTCY_Active, val, TAG_DONE );
			}
			else
			{
				makecycletext( ogw, obj );
				RefreshGList( obj->g, ogw->w, NULL, 1 );
			}
			return;

		case OGOBJ_LIST:
			adjustlv( obj, val );
			makelisttexts( ogw, obj );
			drawlistviewentries( ogw, obj );
			setlistscroller( ogw, obj );
			return;

		case OGOBJ_INTEGER:
			sprintf( ( ( struct StringInfo *) obj->g->SpecialInfo )->Buffer, "%ld", val );
			( ( struct StringInfo *) obj->g->SpecialInfo )->LongInt = val;
			RefreshGList( obj->g, ogw->w, NULL, 1 );
			return;

		case OGOBJ_STRING:
			stccpy( ( ( struct StringInfo *) obj->g->SpecialInfo )->Buffer, (char *) val, obj->maxchars );
			RefreshGList( obj->g, ogw->w, NULL, 1 );
			return;

		case OGOBJ_TEXT:
			if( !strcmp( obj->defaultstring, (char *) val ) )
				break;
			c = IntuiTextLength( obj->it_c );
			d = textfit( ogw, (char *) val, obj->g->Width - 16 );
			d = min( d, 255 );
			memcpy( obj->defaultstring, (char *) val, d );
			obj->defaultstring[ d ] = 0;
			d = IntuiTextLength( obj->it_c );

			if( c >= d )
			{
				SetAPen( ogw->w->RPort, 0 );
				SetDrMd( ogw->w->RPort, JAM1 );
				RectFill( ogw->w->RPort, obj->g->LeftEdge + obj->it_c->LeftEdge + d - 1, obj->g->TopEdge + 2, obj->g->LeftEdge + obj->g->Width - 3, obj->g->TopEdge + obj->g->Height - 2 );
			}
			/*RefreshGList( obj->g, ogw->w, NULL, 1 );*/
			PrintIText( ogw->w->RPort, obj->it_c, obj->g->LeftEdge, obj->g->TopEdge);
			break;

		case OGOBJ_PENSEL:
			if( obj->defaultvalue == val )
				break;
			obj->defaultvalue = val;
			if( ISV37 )
			{
				GT_SetGadgetAttrs( obj->g, ogw->w, NULL, GTPA_Color, obj->defaultvalue, TAG_DONE );
			}
			break;

		case OGOBJ_FUELGAUGE:
			if( obj->defaultvalue != val )
			{
				obj->defaultvalue = val;
				if( makefuelimage( ogw, obj ) )
					RefreshGList( obj->g, ogw->w, NULL, 1 );
			}
			break;
	}
}

void ogreActivate( struct ogwin *ogw, UWORD id )
{
	struct ogobj *obj = findobj( ogw, id );

	if( !obj )
		return;

	if( obj->type != OGOBJ_STRING && obj->type != OGOBJ_INTEGER )
		return;

	ActivateGadget( obj->g, ogw->w, NULL );

}

struct ogrevn * ogreLVGetEntry( struct ogwin *ogw, UWORD id, int num )
{
	struct ogobj *obj = findobj( ogw, id );
	struct ogrevn *vn = (struct ogrevn *) obj->l->lh_Head;

	while( vn->n.mln_Succ )
	{
		if( !num-- )
			return( vn );
		vn = (struct ogrevn *) vn->n.mln_Succ;
	}
	return( NULL );
}

void ogreLVRefresh( struct ogwin *ogw, UWORD id )
{
	struct ogobj *obj = findobj( ogw, id );

	if( obj && obj->type == OGOBJ_LIST )
	{
		makelisttexts( ogw, obj );
		drawlistviewentries( ogw, obj );
		setlistscroller( ogw, obj );
	}
}

void ogreLVRemEntry( struct ogwin *ogw, UWORD id, int num )
{
/*	struct ogobj *obj = findobj( ogw, id );*/
	struct ogrevn *vn = ogreLVGetEntry( ogw, id, num );

	if( vn )
	{
		Remove( (struct Node *) vn );
	}
}

void ogreLVSetEntry( struct ogwin *ogw, UWORD id, int num, char *txt, UWORD flags )
{
	struct ogobj *obj = findobj( ogw, id );
	char *p;	
	struct ogrevn *vn = ogreLVGetEntry( ogw, id, num );

	if( ( flags & 1 ) && ! ( obj->flags ) )
		lvdeselectall( obj );

	if( vn )
	{
		vn->sel = flags & 1;
		vn->changed = 0;
		if( flags & 2 )
		{
			if( strlen( txt ) < strlen( vn->txt ) )
			{
				strcpy( vn->txt, txt );
			}
			else
			{
				p = OGALLOC( ogw, strlen( txt ) + 1 );
				if( !p )
					return;
				strcpy( p, txt );
				vn->txt = p;
			}
		}
		else
			vn->txt = txt;
	}
}

void ogreLVSetActive( struct ogwin *ogw, UWORD id, int num )
{
	struct ogobj *obj = findobj( ogw, id );

	if( obj )
	{
		obj->defaultvalue = num;
		adjustlv( obj, num );
		makelisttexts( ogw, obj );
		drawlistviewentries( ogw, obj );
		setlistscroller( ogw, obj );
		DrawBorder( ogw->w->RPort, obj->bordg->GadgetRender, obj->bordg->LeftEdge, obj->bordg->TopEdge );
	}
}

void ogreLVSelect( struct ogwin *ogw, UWORD id, int num )
{
	struct ogobj *obj = findobj( ogw, id );
	struct ogrevn *vn = ogreLVGetEntry( ogw, id, num );

	if( !obj )
		return;
	if( ! ( obj->flags ) )
		lvdeselectall( obj );

	if( vn )
	{
		adjustlv( obj, num );
		vn->sel = 1;
		vn->changed = 0;
		obj->defaultvalue = num;
	}
}

void ogreSetMaxVal( struct ogwin *ogw, UWORD id, int maxval )
{
	struct ogobj *obj = findobj( ogw, id );

	if( obj )
		obj->maxval = maxval;
}

int ogreLVGetNumEntries( struct ogwin *ogw, UWORD id )
{
	struct ogobj *obj = findobj( ogw, id );

	if( obj )
		return( getnumentries( obj ) );
	else
		return( NULL );
}

void ogreCopyStringValue( struct ogwin *ogw, UWORD id, char *to )
{
	char *p;

	p = ogreStringValue( ogw, id );
	if( p )
		strcpy( to, p );
	else
		*to = 0;

}

void ogreLockWindow( struct ogwin *ogw )
{
	if( !ogw->windowlocked )
	{
		ogw->windowlocked = TRUE;
		ogw->windowlock = rtLockWindow( ogw->w );
	}
}

void ogreUnlockWindow( struct ogwin *ogw )
{
	if( ogw->windowlocked )
	{
		ogw->windowlocked = FALSE;
		rtUnlockWindow( ogw->w, ogw->windowlock );
	}
}

struct IntuiMessage * ogreWaitIM( struct ogwin *ogw )
{
	struct IntuiMessage *im;

	while( ! ( im = ogreIM( ogw ) ) )
		mWaitPort( ogw->w->UserPort );

	return( im );
}

void ogreAddHelp( struct ogwin *ogw, UBYTE py )
{
	ogreAddButton( ogw, py, 0x5f, "Hilfe", OGID_HELP );
}

void ogreSetFlags16( struct ogwin *ogw, UWORD id, UWORD flag, UWORD *to )
{
	if( ogreValue( ogw, id ) )
		*to |= flag;
	else
		*to &= ~flag;
}

void ogreSetFlags32( struct ogwin *ogw, UWORD id, ULONG flag, ULONG *to )
{
	if( ogreValue( ogw, id ) )
		*to |= flag;
	else
		*to &= ~flag;
}

int ogreLVGetLastActive( struct ogwin *ogw, UWORD id )
{
	struct ogobj *obj = findobj( ogw, id );

	return( obj->minval );

}

int ogreLVGetActive( struct ogwin *ogw, UWORD id )
{
	struct ogobj *obj = findobj( ogw, id );

	return( ( int ) obj->defaultvalue );
}

int ogreLVFindEntry( struct ogwin *ogw, UWORD id, char *name )
{
	struct ogobj *obj = findobj( ogw, id );
	struct ogrevn *vn = (struct ogrevn *) obj->l->lh_Head;

	while( vn->n.mln_Succ )
	{
		if( !stricmp( name, vn->txt ) )
			return( TRUE );
		vn = (struct ogrevn *) vn->n.mln_Succ;
	}
	return( FALSE );
}
