/* $Revision Header *** Header built automatically - do not edit! ***********
 *
 *	(C) Copyright 1991 by Torsten Jürgeleit
 *
 *	Name .....: gadgets2.c
 *	Created ..: Thursday 19-Dec-91 20:52:53
 *	Revision .: 7
 *
 *	Date        Author                 Comment
 *	=========   ====================   ====================
 *	08-Aug-92   Torsten Jürgeleit      alternate justifications (center,
 *					   right) of string in input gadget
 *	11-Jul-92   Torsten Jürgeleit      eg_Hotkey now always in lower case
 *	01-Jul-92   Torsten Jürgeleit      added support for custom slider
 *                                         knob image
 *	23-Apr-92   Torsten Jürgeleit      now all PRINTABLE characters can
 *                                         be used as hotkeys
 *	01-Apr-92   Torsten Jürgeleit      any references to gadget data
 *                                         via gl_Data removed
 *	25-Mar-92   Torsten Jürgeleit      now the ASCII chars `!'..`/' and
 *                                         `:'..`@' can be used as hotkeys
 *	05-Jan-92   Torsten Jürgeleit      now try to open font before
 *                                         initializing gadget;
 *                                         correct display of larger fonts
 *                                         for mutual exclude gadgets
 *	19-Dec-91   Torsten Jürgeleit      Created this file!
 *
 ****************************************************************************
 *
 *	Gadget support routines - part 2
 *
 * $Revision Header ********************************************************/

	/* Includes */

#include <exec/types.h>
#include <exec/memory.h>
#include <devices/inputevent.h>
#include <intuition/intuition.h>
#ifdef AZTEC_C
#include <functions.h>   /* needed for Aztec C - prototypes and pragmas for all Amiga system functions */
#endif
#include <libraries/memwatch.h>   /* header file for memory debug link library (Fish 240) - AFTER functions.h */
#include <string.h>
#include "/render/render.h"
#include "/texts/texts.h"
#include "/borders/borders.h"
#include "/language/language.h"
#include "gadgets.h"
#include "imports.h"

	/* Count entries in gadget data array */

   USHORT
count_gadget_data_entries(struct GadgetData  *gd)
{
   USHORT data_entries = 0;

   while (gd->gd_Type != INTUISUP_DATA_END &&
				      gd->gd_Type <= MAX_GADGET_DATA_TYPE) {
      data_entries++;
      gd++;
   }
   return(data_entries);
}
	/* Get buffer size for gadgets and borders */

   ULONG
get_gadget_buffer_size(struct GadgetList  *gl, struct GadgetData  *gd)
{
   struct RenderInfo  *ri = gl->gl_RenderInfo;
   USHORT i, data_entries = gl->gl_DataEntries;
   ULONG  buffer_size = 0;

   for (i = 0; i < data_entries; i++, gd++) {
      BYTE   **text;
      USHORT gadget_size, border_size, num, height, spacing,
	     type = gd->gd_Type;
      ULONG  flags = gd->gd_Flags;

      /* If monochrome display then set HIGHCOMP flag */
      if (ri->ri_ScreenDepth == 1) {
	 flags |= GADGET_DATA_FLAG_HIGH_COMP;
      }
      switch(type) {
	 case GADGET_DATA_TYPE_BUTTON :
	    gadget_size = sizeof(struct ExtendedGadget);
	    if ((flags & GADGET_DATA_FLAG_BUTTON_TOGGLE &&
				   flags & GADGET_DATA_FLAG_BUTTON_IMAGE) ||
				       flags & GADGET_DATA_FLAG_HIGH_COMP) {
	       border_size = BORDER_TYPE_BOX1_BUFFER_SIZE;
	    } else {
	       border_size = 2 * BORDER_TYPE_BOX1_BUFFER_SIZE;
	    }

	    /* Add image struct size if chip mem copies of image data needed */
	    if (gd->gd_Flags & GADGET_DATA_FLAG_BUTTON_IMAGE) {
	       if (check_gadget_image(gd->gd_SpecialData.gd_ButtonData.
					  gd_ButtonNormalRender) == FALSE) {
		  buffer_size += sizeof(struct Image);
	       }
	       if (check_gadget_image(gd->gd_SpecialData.gd_ButtonData.
					  gd_ButtonSelectRender) == FALSE) {
		  buffer_size += sizeof(struct Image);
	       }
	    }
	    break;

	 case GADGET_DATA_TYPE_CHECK :
	    gadget_size = sizeof(struct ExtendedGadget);
	    border_size = BORDER_TYPE_BOX1_BUFFER_SIZE;
	    break;

	 case GADGET_DATA_TYPE_MX :
	    text = gd->gd_SpecialData.gd_MXData.gd_MXTextArray;
	    num  = 0;
	    while (*text++) {
	       num++;
	    }
	    gadget_size = num * (sizeof(struct ExtendedGadget) +
			  sizeof(struct IntuiText)) + sizeof(struct MXData);
	    border_size = BORDER_TYPE_BOX1_BUFFER_SIZE;
	    break;

	 case GADGET_DATA_TYPE_STRING :
	 case GADGET_DATA_TYPE_INTEGER :

	    /* Calc size of input buffer */
	    if (type == GADGET_DATA_TYPE_STRING) {
	       num = gd->gd_SpecialData.gd_InputData.gd_InputLen;
	       if (flags & (GADGET_DATA_FLAG_STRING_UNSIGNED_DEC |
					GADGET_DATA_FLAG_STRING_SIGNED_DEC |
					       GADGET_DATA_FLAG_STRING_HEX |
					     GADGET_DATA_FLAG_STRING_BIN)) {
		  if (num < (MAX_BIN_NUM_DIGITS + 1)) {
		     num = MAX_BIN_NUM_DIGITS + 1;   /* identifier `%' + number */
		  }
	       }
	    } else {
	       num = MAX_DEC_NUM_DIGITS;
	    }
	    if (num & 1) {   /* odd input len ? */
	       num += 1;
	    } else {
	       num += 2;   /* inc for end of string marker */
	    }
	    gadget_size = sizeof(struct ExtendedGadget) +
		 sizeof(struct StringInfo) + num + sizeof(struct InputData);
	    border_size = BORDER_TYPE_BOX2_BUFFER_SIZE;
	    break;

	 case GADGET_DATA_TYPE_SLIDER :
	    gadget_size = sizeof(struct ExtendedGadget) +
			    sizeof(struct PropInfo) + sizeof(struct Image) +
						  sizeof(struct SliderData);
	    border_size = BORDER_TYPE_BOX1_BUFFER_SIZE;
	    break;

	 case GADGET_DATA_TYPE_SCROLLER :
	    if (flags & GADGET_DATA_FLAG_SCROLLER_NO_ARROWS) {
	       gadget_size = sizeof(struct ExtendedGadget) +
			    sizeof(struct PropInfo) + sizeof(struct Image) +
						sizeof(struct ScrollerData);
	       border_size = BORDER_TYPE_BOX1_BUFFER_SIZE;
	    } else {
	       gadget_size = 3 * sizeof(struct ExtendedGadget) +
			    sizeof(struct PropInfo) + sizeof(struct Image) +
						sizeof(struct ScrollerData);
	       if (flags & GADGET_DATA_FLAG_HIGH_COMP) {
		  border_size = 3 * BORDER_TYPE_BOX1_BUFFER_SIZE;
	       } else {
		  border_size = 5 * BORDER_TYPE_BOX1_BUFFER_SIZE;
	       }
	    }
	    break;

	 case GADGET_DATA_TYPE_CYCLE :
	    gadget_size = sizeof(struct ExtendedGadget) +
						   sizeof(struct CycleData);
	    if (flags & GADGET_DATA_FLAG_HIGH_COMP) {
	       border_size = BORDER_TYPE_BOX1_BUFFER_SIZE;
	    } else {
	       border_size = 2 * BORDER_TYPE_BOX1_BUFFER_SIZE;
	    }
	    break;

	 case GADGET_DATA_TYPE_COUNT :
	    gadget_size = sizeof(struct ExtendedGadget) +
						   sizeof(struct CountData);
	    border_size = 2 * BORDER_TYPE_BOX1_BUFFER_SIZE;
	    break;

	 case GADGET_DATA_TYPE_LISTVIEW :
	    if (flags & GADGET_DATA_FLAG_LISTVIEW_READ_ONLY) {
	       num = 0;
	    } else {
	       struct TextAttr  *ta;

	       if (!(ta = gd->gd_TextAttr)) {
		  ta = &gl->gl_RenderInfo->ri_TextAttr;
	       }
	       height  = gd->gd_Height;
	       spacing = gd->gd_SpecialData.gd_ListViewData.gd_ListViewSpacing;
	       if (!(flags & GADGET_DATA_FLAG_NO_BORDER)) {
		  height -= 2 * 1;
	       }
	       num = (height + spacing) / (ta->ta_YSize + spacing);
	    }
	    gadget_size = (3 + num) * sizeof(struct ExtendedGadget) +
			    sizeof(struct PropInfo) + sizeof(struct Image) +
						sizeof(struct ListViewData);
	    if (flags & GADGET_DATA_FLAG_HIGH_COMP) {
	       border_size = 4 * BORDER_TYPE_BOX1_BUFFER_SIZE;
	    } else {
	       border_size = 6 * BORDER_TYPE_BOX1_BUFFER_SIZE;
	    }
	    break;

	 case GADGET_DATA_TYPE_PALETTE :
	    num         = 1L << gd->gd_SpecialData.gd_PaletteData.gd_PaletteDepth;
	    gadget_size = num * (sizeof(struct ExtendedGadget) +
			 sizeof(struct Image)) + sizeof(struct PaletteData);
	    if (flags & GADGET_DATA_FLAG_HIGH_COMP) {
	       border_size = num * BORDER_TYPE_BOX1_BUFFER_SIZE;
	    } else {
	       border_size = num * (2 * BORDER_TYPE_BOX1_BUFFER_SIZE);
	    }
	    if (!(flags & GADGET_DATA_FLAG_PALETTE_NO_INDICATOR)) {
	       gadget_size += sizeof(struct ExtendedGadget) +
						       sizeof(struct Image);
	       border_size += BORDER_TYPE_BOX1_BUFFER_SIZE;
	    }
	    break;
      }
      buffer_size += gadget_size;
      if (!(flags & GADGET_DATA_FLAG_NO_BORDER)) {
	 buffer_size += border_size;
      }
   }
   return(buffer_size);
}
	/* Get buffer size for image data */

   ULONG
get_image_buffer_size(struct GadgetList  *gl, struct GadgetData  *gd)
{
   USHORT i, data_entries = gl->gl_DataEntries;
   ULONG  buffer_size = 0;

   for (i = 0; i < data_entries; i++, gd++) {
      switch (gd->gd_Type) {
	 case GADGET_DATA_TYPE_BUTTON :
	    if (gd->gd_Flags & GADGET_DATA_FLAG_BUTTON_IMAGE) {
	       struct Image  *image;

	       image = gd->gd_SpecialData.gd_ButtonData.gd_ButtonNormalRender;
	       if (check_gadget_image(image) == FALSE) {
		  buffer_size += (image->Width / 16 + (image->Width & 15 ?
				 1 : 0)) * image->Height * image->Depth * 2;
	       }
	       image = gd->gd_SpecialData.gd_ButtonData.gd_ButtonSelectRender;
	       if (check_gadget_image(image) == FALSE) {
		  buffer_size += (image->Width / 16 + (image->Width & 15 ?
				 1 : 0)) * image->Height * image->Depth * 2;
	       }
	    }
	    break;

	 case GADGET_DATA_TYPE_SLIDER :
	    if (gd->gd_Flags & GADGET_DATA_FLAG_SLIDER_IMAGE) {
	       struct Image  *image;

	       image = (struct Image *)gd->gd_TextAttr;
	       if (check_gadget_image(image) == FALSE) {
		  buffer_size += (image->Width / 16 + (image->Width & 15 ?
				 1 : 0)) * image->Height * image->Depth * 2;
	       }
	    }
	    break;
      }
   }
   return(buffer_size);
}
	/* Initialize gadgets from gadget list */

   VOID
init_gadgets(struct GadgetList  *gl, struct GadgetData  *gd,
					       SHORT hoffset, SHORT voffset)
{
   struct RenderInfo  *ri = gl->gl_RenderInfo;
   BYTE   *buffer = gl->gl_GadgetBuffer, *image_buffer = gl->gl_ImageBuffer;
   USHORT i, data_entries = gl->gl_DataEntries;

   for (i = 0; i < data_entries; i++, gd++) {
      struct ExtendedGadget  *egad, *first_egad;
      struct Image           *image;
      struct IntuiText       itext;
      struct MXData          *mx;
      struct InputData       *id;
      struct SliderData      *sl;
      struct ScrollerData    *sc;
      struct CycleData       *cy;
      struct CountData       *co;
      struct ListViewData    *lv;
      struct PaletteData     *pd;
      struct TextAttr        *ta;
      struct TextFont        *tf;
      BYTE   **text;
      USHORT j, max_width, num, len, xoffset, yoffset, xmin, ymin,
	     xnum, ynum, yinc, spacing, text_height,
	     type = gd->gd_Type, left_edge = gd->gd_LeftEdge + hoffset,
	     top_edge = gd->gd_TopEdge + voffset, width = gd->gd_Width,
	     height = gd->gd_Height;
      ULONG  min, max, flags = gd->gd_Flags;

      /* Get ptr to extended gadget and reserve buffer */
      egad    = gl->gl_Gadgets[i] = (struct ExtendedGadget *)buffer;
      buffer += sizeof(struct ExtendedGadget);

      /* Save ptr to first gadget of ISUP object */
      first_egad = egad;

      /* Save absolut gadget position - needed by modify_gadget() */
      egad->eg_BorderLeftEdge = left_edge;
      egad->eg_BorderTopEdge  = top_edge;

      /* Open text font and save data */
      if (type == GADGET_DATA_TYPE_SLIDER &&
				  (flags & GADGET_DATA_FLAG_SLIDER_IMAGE)) {
	 /* Use default font */
	 ta = &ri->ri_TextAttr;
	 tf = ri->ri_TextFont;
      } else {

	 /* Use font given in gd_TextAttr */
	 if (!(ta = gd->gd_TextAttr) || !(ta = ask_font(ri, ta))) {

	    /* Use default font */
	    ta = &ri->ri_TextAttr;
	    tf = ri->ri_TextFont;
	 } else {
	    if (!(tf = open_font(ri, ta))) {

	       /* Use default font */
	       ta = &ri->ri_TextAttr;
	       tf = ri->ri_TextFont;
	    } else {
	       egad->eg_Flags |= EXTENDED_GADGET_FLAG_CLOSE_FONT;
	    }
	 }
      }
      egad->eg_TextAttr = ta;
      egad->eg_TextFont = tf;
      text_height       = ta->ta_YSize;

      /* Init intui text */
      itext.ITextFont = ta;

      /* Calc border offsets */
      if (flags & GADGET_DATA_FLAG_NO_BORDER) {
	 xoffset = 0;
	 yoffset = 0;
      } else {
	 switch (type) {
	    case GADGET_DATA_TYPE_MX :
	       xoffset = 8;
	       yoffset = 4;
	       break;

	    case GADGET_DATA_TYPE_STRING :
	    case GADGET_DATA_TYPE_INTEGER :
	       xoffset = 6;
	       yoffset = 3;
	       break;

	    case GADGET_DATA_TYPE_CYCLE :
	    case GADGET_DATA_TYPE_COUNT :
	       xoffset = 2;
	       yoffset = 1;
	       break;

	    default :
	       xoffset = 4;
	       yoffset = 2;
	       break;
	 }
      }

      /* Inner window position needed ? */
      if (ri->ri_Flags & RENDER_INFO_FLAG_INNER_WINDOW) {
	 left_edge += ri->ri_WindowBorderLeft;
	 top_edge  += ri->ri_WindowBorderTop;
      }

      /* If fixed gadget dimensions or data buffers so init them yet */
      switch (type) {
	 case GADGET_DATA_TYPE_CHECK :

	    /* Calc fixed dimensions of check gadget */
	    width  = IMAGE_CHECK_WIDTH + 2 * IMAGE_HORIZ_OFFSET;
	    height = IMAGE_CHECK_HEIGHT + 2 * IMAGE_VERT_OFFSET;
	    break;

	 case GADGET_DATA_TYPE_MX :

	    /* Calc fixed dimensions of mx gadget */
	    width  = IMAGE_KNOB_WIDTH;
	    height = IMAGE_KNOB_HEIGHT;

	    /* Calc vertical offset between mx gadget */
	    if ((yinc = text_height) < height) {
	       yinc = height;
	    }
	    yinc += gd->gd_SpecialData.gd_MXData.gd_MXSpacing;

	    /* Count mx gadgets and calc maximal text width */
	    text      = gd->gd_SpecialData.gd_MXData.gd_MXTextArray;
	    num       = 0;
	    max_width = 0;
	    while (*text) {
	       itext.IText = (UBYTE *)get_language_text(*text++,
						  gl->gl_LanguageTextArray);
	       if ((len = IntuiTextLength(&itext)) > max_width) {
		  max_width = len;
	       }
	       num++;
	    }

	    /* Left and top edge of gadget */
	    if (flags & GADGET_DATA_FLAG_TEXT_LEFT) {
	       left_edge += max_width + xoffset + 8;
	    } else {
	       left_edge += xoffset;
	    }
	    if (text_height > height) {
	       top_edge += (text_height - height) / 2 + yoffset;
	    } else {
	       top_edge += yoffset;
	    }

	    /* Init mx data */
	    mx                 = (struct MXData *)buffer;
	    buffer            += sizeof(struct MXData);
	    mx->mx_TextEntries = num;
	    break;

	 case GADGET_DATA_TYPE_STRING :
	 case GADGET_DATA_TYPE_INTEGER :

	    /* Calc fixed height of input gadgets */
	    height = ri->ri_TextAttr.ta_YSize + 2 * yoffset;

	    /* Init input data */
	    id                  = (struct InputData *)buffer;
	    buffer             += sizeof(struct InputData);
	    id->id_ActivateNext = gd->gd_SpecialData.gd_InputData.gd_InputActivateNext;
	    id->id_ActivatePrev = gd->gd_SpecialData.gd_InputData.gd_InputActivatePrev;
	    break;

	 case GADGET_DATA_TYPE_SLIDER :

	    /* Init slider data */
	    sl      = (struct SliderData *)buffer;
	    buffer += sizeof(struct SliderData);
	    break;

	 case GADGET_DATA_TYPE_SCROLLER :

	    /* Calc minimum dimensions of scroller gadget */
	    if (!(flags & GADGET_DATA_FLAG_SCROLLER_NO_ARROWS)) {
	       xmin = IMAGE_ARROW_WIDTH + IMAGE_HORIZ_OFFSET + xoffset;
	       ymin = IMAGE_ARROW_HEIGHT + IMAGE_VERT_OFFSET + yoffset;
	       if (flags & GADGET_DATA_FLAG_ORIENTATION_VERT) {
		  if (width < xmin) {
		     width = xmin;
		  }
		  if (height < 3 * ymin) {
		     height = 3 * ymin;
		  }
	       } else {
		  if (width < 3 * xmin) {
		     width = 3 * xmin;
		  }
		  if (height < ymin) {
		     height = ymin;
		  }
	       }
	    }

	    /* Init scroller data */
	    sc      = (struct ScrollerData *)buffer;
	    buffer += sizeof(struct ScrollerData);
	    break;

	 case GADGET_DATA_TYPE_CYCLE :

	    /* Init cycle data */
	    cy      = (struct CycleData *)buffer;
	    buffer += sizeof(struct CycleData);
	    break;

	 case GADGET_DATA_TYPE_COUNT :

	    /* Init count data */
	    co      = (struct CountData *)buffer;
	    buffer += sizeof(struct CountData);
	    break;

	 case GADGET_DATA_TYPE_LISTVIEW :

	    /* Calc minimum dimension of list view gadget */
	    xmin = IMAGE_ARROW_WIDTH + IMAGE_HORIZ_OFFSET + xoffset;
	    ymin = IMAGE_ARROW_HEIGHT + IMAGE_VERT_OFFSET + yoffset;
	    if (height < 3 * ymin) {
	       height = 3 * ymin;
	    }
	    spacing = gd->gd_SpecialData.gd_ListViewData.gd_ListViewSpacing;
	    yinc    = text_height + spacing;
	    num     = (height - 2 * yoffset + spacing) / yinc;
	    height  = num * yinc + 2 * yoffset;

	    /* Init list view data */
	    lv      = (struct ListViewData *)buffer;
	    buffer += sizeof(struct ListViewData);
	    break;

	 case GADGET_DATA_TYPE_PALETTE :

	    /* Calc dimension of color squares of palette */
	    min  = gd->gd_SpecialData.gd_PaletteData.gd_PaletteColorOffset;
	    max  = 1L << gd->gd_SpecialData.gd_PaletteData.gd_PaletteDepth;
	    xnum = max;   /* start with all squares in a horizontal line */
	    ynum = 1;
	    while (xnum > 1 && (width / xnum) / 2 < height / ynum) {
	       xnum /= 2;
	       ynum *= 2;
	    }
	    if (!(flags & GADGET_DATA_FLAG_PALETTE_NO_INDICATOR)) {

	       /* Insert color indicator */
	       if (flags & GADGET_DATA_FLAG_PALETTE_INDICATOR_TOP) {
		  ynum++;
	       } else {
		  xnum++;
	       }
	    }

	    /* Calc gadget dimension */
	    if (xnum == 1) {
	       xmin = width;
	    } else {
	       xmin  = (width - 2 * (xnum - 1)) / xnum;
	       width = xmin * xnum + 2 * (xnum - 1);
	    }
	    if (ynum == 1) {
	       ymin = height;
	    } else {
	       ymin   = (height - 1 * (ynum - 1)) / ynum;
	       height = ymin * ynum + 1 * (ynum - 1);
	    }

	    /* Init palette data */
	    pd      = (struct PaletteData *)buffer;
	    buffer += sizeof(struct PaletteData);
	    break;
      }

      /* Init gadget */
      switch (type) {
	 case GADGET_DATA_TYPE_BUTTON :
	    buffer = init_extended_gadget(egad, buffer, gl, gd, i,
		    EXTENDED_GADGET_TYPE_BUTTON, left_edge, top_edge, width,
								    height);
	    break;

	 case GADGET_DATA_TYPE_CHECK :
	    buffer = init_extended_gadget(egad, buffer, gl, gd, i,
		     EXTENDED_GADGET_TYPE_CHECK, left_edge, top_edge, width,
								    height);
	    break;

	 case GADGET_DATA_TYPE_MX :

	    /* Init all mx gadgets */
	    text = gd->gd_SpecialData.gd_MXData.gd_MXTextArray;
	    for (j = 0; j < num; j++, text++) {
	       buffer = init_extended_gadget(egad, buffer, gl, gd, i,
			EXTENDED_GADGET_TYPE_MX, left_edge, top_edge, width,
								    height);
	       buffer = init_mx_text(egad, buffer, get_language_text(*text,
		       gl->gl_LanguageTextArray), width, height, flags, ta);
	       egad->eg_Gadget.GadgetID = j;   /* num of mx gadget */
	       if (j < (num - 1)) {   /* another mx gadget ? */
		  top_edge += yinc;
		  egad      = egad->eg_NextGadget =
					    (struct ExtendedGadget *)buffer;
		  buffer   += sizeof(struct ExtendedGadget);
	       }
	    }

	    /* Calc border offsets first - need old height */
	    if (!(flags & GADGET_DATA_FLAG_NO_BORDER)) {
	       if (flags & GADGET_DATA_FLAG_TEXT_LEFT) {
		  left_edge = -(max_width + xoffset + 8);
	       } else {
		  left_edge = -xoffset;   /* default right */
	       }
	       if (text_height > height) {
		  top_edge = -((text_height - height) / 2 + yoffset);
	       } else {
		  top_edge = -yoffset;
	       }
	    }

	    /* Calc border dimension and draw it */
	    width += max_width + 2 * xoffset + 8;
	    height = yinc * num + 2 * yoffset -
				  gd->gd_SpecialData.gd_MXData.gd_MXSpacing;
	    if (!(flags & GADGET_DATA_FLAG_NO_BORDER)) {
	       first_egad->eg_Render = (APTR)buffer;
	       buffer                = init_border(ri, buffer, left_edge,
			 top_edge, width, height, BORDER_DATA_TYPE_BOX1_IN);
	       first_egad->eg_Flags |= EXTENDED_GADGET_FLAG_RENDER_BORDER;
	    }
	    break;

	 case GADGET_DATA_TYPE_STRING :
	    buffer = init_extended_gadget(egad, buffer, gl, gd, i,
		    EXTENDED_GADGET_TYPE_STRING, left_edge, top_edge, width,
								    height);
	    break;

	 case GADGET_DATA_TYPE_INTEGER :
	    buffer = init_extended_gadget(egad, buffer, gl, gd, i,
		   EXTENDED_GADGET_TYPE_INTEGER, left_edge, top_edge, width,
								    height);
	    break;

	 case GADGET_DATA_TYPE_SLIDER :

	    /* Init slider data */
	    sl->sl_Min = gd->gd_SpecialData.gd_SliderData.gd_SliderMin;
	    sl->sl_Max = gd->gd_SpecialData.gd_SliderData.gd_SliderMax;
	    buffer = init_extended_gadget(egad, buffer, gl, gd, i,
		      EXTENDED_GADGET_TYPE_SLIDER_PROP, left_edge, top_edge,
							     width, height);
	    break;

	 case GADGET_DATA_TYPE_SCROLLER :

	    /* Init scroller data */
	    sc->sc_Total   = gd->gd_SpecialData.gd_ScrollerData.gd_ScrollerTotal;
	    sc->sc_Visible = gd->gd_SpecialData.gd_ScrollerData.gd_ScrollerVisible;

	    /* Init scroller gadgets */
	    if (flags & GADGET_DATA_FLAG_SCROLLER_NO_ARROWS) {
	       buffer = init_extended_gadget(egad, buffer, gl, gd, i,
			      EXTENDED_GADGET_TYPE_SCROLLER_PROP, left_edge,
						   top_edge, width, height);
	    } else {
	       if (flags & GADGET_DATA_FLAG_ORIENTATION_VERT) {

		  /* Create vertical scroller - prop gadget first */
		  buffer = init_extended_gadget(egad, buffer, gl, gd, i,
			      EXTENDED_GADGET_TYPE_SCROLLER_PROP, left_edge,
				  top_edge, width, height - 2 * (ymin + 1));
		  /* Init scroller up arrow gadget */
		  egad    = egad->eg_NextGadget = (struct ExtendedGadget *)
								     buffer;
		  buffer += sizeof(struct ExtendedGadget);
		  buffer  = init_extended_gadget(egad, buffer, gl, gd, i,
				EXTENDED_GADGET_TYPE_SCROLLER_UP, left_edge,
			     top_edge + height - 2 * ymin - 1, width, ymin);
		  /* Change type of vertical scroller arrow gadget for correct counting */
		  egad->eg_Type = EXTENDED_GADGET_TYPE_SCROLLER_DOWN;

		  /* Init scroller down arrow gadget */
		  egad    = egad->eg_NextGadget = (struct ExtendedGadget *)
								     buffer;
		  buffer += sizeof(struct ExtendedGadget);
		  buffer  = init_extended_gadget(egad, buffer, gl, gd, i,
			      EXTENDED_GADGET_TYPE_SCROLLER_DOWN, left_edge,
				     top_edge + height - ymin, width, ymin);
		  /* Change type of vertical scroller arrow gadget for correct counting */
		  egad->eg_Type = EXTENDED_GADGET_TYPE_SCROLLER_UP;
	       } else {

		  /* Create horizontal scroller - prop gadget first */
		  buffer = init_extended_gadget(egad, buffer, gl, gd, i,
			      EXTENDED_GADGET_TYPE_SCROLLER_PROP, left_edge,
				  top_edge, width - 2 * (xmin + 1), height);
		  /* Init scroller left arrow gadget */
		  egad    = egad->eg_NextGadget = (struct ExtendedGadget *)
								     buffer;
		  buffer += sizeof(struct ExtendedGadget);
		  buffer  = init_extended_gadget(egad, buffer, gl, gd, i,
			     EXTENDED_GADGET_TYPE_SCROLLER_LEFT, left_edge +
			      width - 2 * xmin - 1, top_edge, xmin, height);
		  /* Init scroller right arrow gadget */
		  egad    = egad->eg_NextGadget = (struct ExtendedGadget *)
								     buffer;
		  buffer += sizeof(struct ExtendedGadget);
		  buffer  = init_extended_gadget(egad, buffer, gl, gd, i,
			    EXTENDED_GADGET_TYPE_SCROLLER_RIGHT, left_edge +
				      width - xmin, top_edge, xmin, height);
	       }
	    }
	    break;

	 case GADGET_DATA_TYPE_CYCLE :

	    /* Count entries and calc max width of cycle text array */
       	    text = gd->gd_SpecialData.gd_CycleData.gd_CycleTextArray;
	    num  = max_width = 0;
	    while (*text) {
	       itext.IText = (UBYTE *)get_language_text(*text++,
						  gl->gl_LanguageTextArray);
	       if ((len = IntuiTextLength(&itext)) > max_width) {
		  max_width = len;
	       }
	       num++;
	    }

	    /* Init cycle data */
	    image              = &ri->ri_Images[IMAGE_CYCLE];
	    xmin               = image->LeftEdge + image->Width +
								xoffset + 4;
	    cy->cy_LeftEdge    = left_edge + xmin + (SHORT)(width -
						  max_width - xmin - 4) / 2;
	    cy->cy_TopEdge     = top_edge + (SHORT)(height - text_height) / 2;
	    cy->cy_Width       = max_width;
	    cy->cy_Height      = text_height;
	    cy->cy_EntryHeight = text_height +
			    gd->gd_SpecialData.gd_CycleData.gd_CycleSpacing;
	    cy->cy_TextArray   = gd->gd_SpecialData.gd_CycleData.gd_CycleTextArray;
	    cy->cy_TextEntries = num;
	    buffer             = init_extended_gadget(egad, buffer, gl, gd,
		  i, EXTENDED_GADGET_TYPE_CYCLE, left_edge, top_edge, width,
								    height);
	    break;

	 case GADGET_DATA_TYPE_COUNT :

	    /* Calc max width of count value */
	    min = gd->gd_SpecialData.gd_CountData.gd_CountMin;
	    max = gd->gd_SpecialData.gd_CountData.gd_CountMax;
	    if (flags & GADGET_DATA_FLAG_COUNT_SIGNED_DEC) {
	       len       = convert_signed_dec((LONG)min, (BYTE *)NULL, 0);
	       max_width = convert_signed_dec((LONG)max, (BYTE *)NULL, 0);
	    } else {
	       len       = convert_unsigned_dec(min, (BYTE *)NULL, 0);
	       max_width = convert_unsigned_dec(max, (BYTE *)NULL, 0);
	    }
	    if (len > max_width) {
	       max_width = len;
	    }
	    itext.IText = (UBYTE *)"8";
	    max_width  *= IntuiTextLength(&itext);

	    /* Init count data */
	    co->co_LeftEdge = left_edge + (SHORT)(width - max_width) / 2;
	    co->co_TopEdge  = top_edge + (SHORT)(height - text_height) / 2;
	    co->co_Width    = max_width;
	    co->co_Height   = text_height;
	    co->co_Min      = min;
	    co->co_Max      = max;
	    buffer          = init_extended_gadget(egad, buffer, gl, gd, i,
		     EXTENDED_GADGET_TYPE_COUNT, left_edge, top_edge, width,
								    height);
	    break;

	 case GADGET_DATA_TYPE_LISTVIEW :

	    /* Init list view data */
	    lv->lv_LeftEdge       = left_edge + xoffset;
	    lv->lv_TopEdge        = top_edge + yoffset;
	    lv->lv_Width          = width - 2 * xoffset - xmin - 2;
	    lv->lv_Height         = height - 2 * yoffset;
	    lv->lv_VisibleEntries = num;
	    lv->lv_EntryHeight    = yinc;

	    /* Create vertical scroller - prop gadget first */
	    left_edge += width - xmin;
	    buffer     = init_extended_gadget(egad, buffer, gl, gd, i,
		    EXTENDED_GADGET_TYPE_LISTVIEW_PROP, left_edge, top_edge,
					     xmin, height - 2 * (ymin + 1));
	    /* Create entry field border */
	    if (!(flags & GADGET_DATA_FLAG_NO_BORDER)) {
	       USHORT border_type;

	       ((struct Border *)egad->eg_Render)->NextBorder->NextBorder =
						    (struct Border *)buffer;
	       if (flags & GADGET_DATA_FLAG_LISTVIEW_READ_ONLY) {
		  border_type = BORDER_DATA_TYPE_BOX1_IN;
	       } else {
		  border_type = BORDER_DATA_TYPE_BOX1_OUT;
	       }
	       buffer = init_border(ri, buffer, -(width + xoffset - xmin),
			   -yoffset, width - xmin - 2, height, border_type);
	    }

	    /* Init list view up arrow gadget */
	    egad    = egad->eg_NextGadget = (struct ExtendedGadget *)buffer;
	    buffer += sizeof(struct ExtendedGadget);
	    buffer  = init_extended_gadget(egad, buffer, gl, gd, i,
		     EXTENDED_GADGET_TYPE_LISTVIEW_UP, left_edge, top_edge +
					 height - 2 * ymin - 1, xmin, ymin);
	    /* Init list view down arrow gadget */
	    egad    = egad->eg_NextGadget = (struct ExtendedGadget *)buffer;
	    buffer += sizeof(struct ExtendedGadget);
	    buffer  = init_extended_gadget(egad, buffer, gl, gd, i,
		   EXTENDED_GADGET_TYPE_LISTVIEW_DOWN, left_edge, top_edge +
						 height - ymin, xmin, ymin);
	    /* Init list view entry gadgets */
	    if (!(flags & GADGET_DATA_FLAG_LISTVIEW_READ_ONLY)) {
	       left_edge = lv->lv_LeftEdge;
	       top_edge  = lv->lv_TopEdge;
	       for (j = 0; j < num; j++, top_edge += yinc) {
		  egad            = egad->eg_NextGadget =
					    (struct ExtendedGadget *)buffer;
		  buffer         += sizeof(struct ExtendedGadget);
		  buffer          = init_extended_gadget(egad, buffer, gl,
				 gd, i, EXTENDED_GADGET_TYPE_LISTVIEW_ENTRY,
				   left_edge, top_edge, lv->lv_Width, yinc);
		  egad->eg_Gadget.GadgetID = j;   /* num of entry gadget */
	       }
	    }
	    break;

	 case GADGET_DATA_TYPE_PALETTE :

	    /* Init palette data */
	    pd->pd_ColorOffset = min;
	    pd->pd_MaxColors   = max;

	    /* Build color indicator */
	    if (!(flags & GADGET_DATA_FLAG_PALETTE_NO_INDICATOR)) {
	       if (flags & GADGET_DATA_FLAG_PALETTE_INDICATOR_TOP) {
		  buffer    = init_extended_gadget(egad, buffer, gl, gd, i,
			  EXTENDED_GADGET_TYPE_PALETTE_INDICATOR, left_edge,
						     top_edge, width, ymin);
		  top_edge += ymin + 1;
		  ynum--;
	       } else {
		  buffer     = init_extended_gadget(egad, buffer, gl, gd, i,
			  EXTENDED_GADGET_TYPE_PALETTE_INDICATOR, left_edge,
						    top_edge, xmin, height);
		  left_edge += xmin + 2;
		  xnum--;
	       }
	       egad    = egad->eg_NextGadget = (struct ExtendedGadget *)
								     buffer;
	       buffer += sizeof(struct ExtendedGadget);
	    }

	    /* Build color gadgets */
	    num = gd->gd_SpecialData.gd_PaletteData.gd_PaletteColorOffset;
	    for (j = 0; j < ynum; j++, top_edge += ymin + 1) {
	       USHORT k, temp_left_edge = left_edge;

	       for (k = 0; k < xnum; k++, temp_left_edge += xmin + 2) {
		  buffer = init_extended_gadget(egad, buffer, gl, gd, i,
			 EXTENDED_GADGET_TYPE_PALETTE_COLOR, temp_left_edge,
						      top_edge, xmin, ymin);
		  ((struct Image *)egad->eg_Render)->PlaneOnOff =
					   egad->eg_Gadget.GadgetID = num++;
		  if (j < (ynum - 1) || k < (xnum - 1)) {
		     egad    = egad->eg_NextGadget =
					    (struct ExtendedGadget *)buffer;
		     buffer += sizeof(struct ExtendedGadget);
		  }
	       }
	    }
	    break;
      }

      /* Save absolut gadget dimension - needed by editor */
      first_egad->eg_BorderWidth  = width;
      first_egad->eg_BorderHeight = height;

      /* Init text */
      if (gd->gd_Text) {
	 init_gadget_text(first_egad, get_language_text(gd->gd_Text,
		       gl->gl_LanguageTextArray), width, height, flags, ta);
      }

      /* Init images */
      if (image_buffer) {
	 switch (type) {
	    case GADGET_DATA_TYPE_BUTTON :
	       if (flags & GADGET_DATA_FLAG_BUTTON_IMAGE) {
		  image_buffer = init_image_data(egad, image_buffer);
	       }
	       break;

	    case GADGET_DATA_TYPE_SLIDER :
	       if (flags & GADGET_DATA_FLAG_SLIDER_IMAGE) {
		  image_buffer = init_image_data(egad, image_buffer);
	       }
	       break;
	 }
      }

      /* Finally set gadget flags and special data */
      set_gadget_attributes(gl, i, 0xffffffffL, flags,
					gd->gd_SpecialData.gd_Data.gd_Data1,
					gd->gd_SpecialData.gd_Data.gd_Data2,
				       gd->gd_SpecialData.gd_Data.gd_Data3);
   }
}
	/* Init extended gadget */

   STATIC BYTE *
init_extended_gadget(struct ExtendedGadget  *egad, BYTE *buffer,
	  struct GadgetList  *gl, struct GadgetData  *gd, USHORT data_entry,
	       USHORT type, USHORT left_edge, USHORT top_edge, USHORT width,
							      USHORT height)
{
   struct RenderInfo  *ri = gl->gl_RenderInfo;
   struct Gadget      *gad = &egad->eg_Gadget;
   struct StringInfo  *sinfo;
   struct PropInfo    *pinfo;
   struct Image       *image;
   ULONG  flags = gd->gd_Flags;
   USHORT len;

   /* If monochrome display then set HIGHCOMP flag */
   if (ri->ri_ScreenDepth == 1) {
      flags |= GADGET_DATA_FLAG_HIGH_COMP;
   }

   /* Init extended gadget */
   egad->eg_Type       = type;
   egad->eg_Flags      = 0;
   egad->eg_DataType   = gd->gd_Type;
   egad->eg_DataEntry  = data_entry;
   egad->eg_DataFlags  = flags;
   egad->eg_GadgetList = gl;

   /* Init normal gadget */
   gad->LeftEdge      = left_edge;
   gad->TopEdge       = top_edge;
   gad->Width         = width;
   gad->Height        = height;
   gad->MutualExclude = ISUP_ID;
   switch (type) {
      case EXTENDED_GADGET_TYPE_BUTTON :
	 gad->GadgetType = BOOLGADGET;
	 if (flags & GADGET_DATA_FLAG_BUTTON_TOGGLE) {
	    gad->Activation = RELVERIFY | TOGGLESELECT;
	    if (flags & GADGET_DATA_FLAG_BUTTON_IMAGE) {
	       gad->Flags = GADGIMAGE | GADGHIMAGE;
	       buffer     = init_button_image(egad, gd, buffer);
	    }
	 } else {
	    gad->Activation = RELVERIFY;
	    if (flags & GADGET_DATA_FLAG_BUTTON_IMAGE) {
	       if ((flags & GADGET_DATA_FLAG_NO_BORDER) &&
				    !(flags & GADGET_DATA_FLAG_HIGH_COMP)) {
		  gad->Flags = GADGIMAGE | GADGHIMAGE;
		  buffer     = init_button_image(egad, gd, buffer);
	       } else {
		  buffer          = init_button_image(egad, gd, buffer);
		  egad->eg_Flags |= EXTENDED_GADGET_FLAG_RENDER_IMAGE;
	       }
	    }
	 }
	 break;

      case EXTENDED_GADGET_TYPE_CHECK :
      case EXTENDED_GADGET_TYPE_MX :
	 gad->GadgetType = BOOLGADGET;
	 gad->Activation = TOGGLESELECT | GADGIMMEDIATE;
	 gad->Flags      = GADGIMAGE | GADGHIMAGE;
	 if (type == EXTENDED_GADGET_TYPE_CHECK) {
	    gad->GadgetRender = (APTR)&ri->ri_Images[IMAGE_CHECK_UNSELECTED];
	    gad->SelectRender = (APTR)&ri->ri_Images[IMAGE_CHECK_SELECTED];
	 } else {
	    gad->GadgetRender = (APTR)&ri->ri_Images[IMAGE_KNOB_UNSELECTED];
	    gad->SelectRender = (APTR)&ri->ri_Images[IMAGE_KNOB_SELECTED];
	 }
	 break;

      case EXTENDED_GADGET_TYPE_STRING :
      case EXTENDED_GADGET_TYPE_INTEGER :
	 gad->GadgetType = STRGADGET;
	 if (type == EXTENDED_GADGET_TYPE_STRING) {
	    gad->Activation = RELVERIFY;
	 } else {
	    gad->Activation = RELVERIFY | LONGINT;
	 }
	 if (flags & GADGET_DATA_FLAG_INPUT_CENTER) {
	    gad->Activation |= STRINGCENTER;
	 } else {
	    if (flags & GADGET_DATA_FLAG_INPUT_RIGHT) {
	       gad->Activation |= STRINGRIGHT;
	    }
	 }
	 gad->Flags       = GADGHCOMP;
	 gad->SpecialInfo = (APTR)buffer;

	 /* Calc size of input buffer */
	 if (type == GADGET_DATA_TYPE_STRING) {
	    len = gd->gd_SpecialData.gd_InputData.gd_InputLen;
	    if (flags & (GADGET_DATA_FLAG_STRING_UNSIGNED_DEC |
					GADGET_DATA_FLAG_STRING_SIGNED_DEC |
					       GADGET_DATA_FLAG_STRING_HEX |
					     GADGET_DATA_FLAG_STRING_BIN)) {
	       if (len < (MAX_BIN_NUM_DIGITS + 1)) {
		  len = MAX_BIN_NUM_DIGITS + 1;   /* identifier `%' + number */
	       }
	    }
	 } else {
	    len = MAX_DEC_NUM_DIGITS;
	 }

	 /* Init string info */
	 sinfo           = (struct StringInfo *)buffer;
	 buffer         += sizeof(struct StringInfo);
	 sinfo->Buffer   = (UBYTE *)buffer;
	 sinfo->MaxChars = len + 1;
	 if (len & 1) {   /* input len odd */
	    buffer += len + 1;
	 } else {
	    buffer += len + 2;
	 }
	 break;

      case EXTENDED_GADGET_TYPE_SLIDER_PROP :
      case EXTENDED_GADGET_TYPE_SCROLLER_PROP :
      case EXTENDED_GADGET_TYPE_LISTVIEW_PROP :
	 gad->GadgetType   = PROPGADGET;
	 gad->Activation   = GADGIMMEDIATE | RELVERIFY | FOLLOWMOUSE;
	 if (flags & GADGET_DATA_FLAG_HIGH_COMP) {
	    gad->Flags = GADGHCOMP;
	 } else {
	    gad->Flags = GADGHNONE;
	 }
	 gad->GadgetRender = (APTR)buffer;   /* needed for auto knob */
	 buffer           += sizeof(struct Image);
	 gad->SpecialInfo  = (APTR)buffer;

	 /* Init prop info */
	 pinfo   = (struct PropInfo *)buffer;
	 buffer += sizeof(struct PropInfo);
	 if (type == EXTENDED_GADGET_TYPE_SLIDER_PROP &&
	       (flags & GADGET_DATA_FLAG_SLIDER_IMAGE) && gd->gd_TextAttr) {
	    pinfo->Flags = PROPBORDERLESS;
	    CopyMem((BYTE *)gd->gd_TextAttr, (BYTE *)gad->GadgetRender,
						(LONG)sizeof(struct Image));
	    egad->eg_Flags |= EXTENDED_GADGET_FLAG_KNOB_IMAGE;
	 } else {
	    pinfo->Flags = AUTOKNOB | PROPBORDERLESS;
	 }
	 if (type == EXTENDED_GADGET_TYPE_LISTVIEW_PROP || (flags &
				       GADGET_DATA_FLAG_ORIENTATION_VERT)) {
	    pinfo->Flags |= FREEVERT;
	 } else {
	    pinfo->Flags |= FREEHORIZ;
	 }
	 break;

      case EXTENDED_GADGET_TYPE_SCROLLER_LEFT :
      case EXTENDED_GADGET_TYPE_SCROLLER_RIGHT :
      case EXTENDED_GADGET_TYPE_SCROLLER_UP :
      case EXTENDED_GADGET_TYPE_SCROLLER_DOWN :
      case EXTENDED_GADGET_TYPE_LISTVIEW_UP :
      case EXTENDED_GADGET_TYPE_LISTVIEW_DOWN :
	 gad->GadgetType = BOOLGADGET;
	 gad->Activation = GADGIMMEDIATE | RELVERIFY;
	 switch (type) {
	    case EXTENDED_GADGET_TYPE_SCROLLER_LEFT :
	       egad->eg_Render = (APTR)&ri->ri_Images[IMAGE_ARROW_LEFT];
	       break;

	    case EXTENDED_GADGET_TYPE_SCROLLER_RIGHT :
	       egad->eg_Render = (APTR)&ri->ri_Images[IMAGE_ARROW_RIGHT];
	       break;

	    case EXTENDED_GADGET_TYPE_SCROLLER_UP :
	    case EXTENDED_GADGET_TYPE_LISTVIEW_UP :
	       egad->eg_Render = (APTR)&ri->ri_Images[IMAGE_ARROW_UP];
	       break;

	    case EXTENDED_GADGET_TYPE_SCROLLER_DOWN :
	    case EXTENDED_GADGET_TYPE_LISTVIEW_DOWN :
	       egad->eg_Render = (APTR)&ri->ri_Images[IMAGE_ARROW_DOWN];
	       break;
	 }
	 egad->eg_Flags |= EXTENDED_GADGET_FLAG_RENDER_IMAGE;
	 break;

      case EXTENDED_GADGET_TYPE_CYCLE :
	 gad->GadgetType = BOOLGADGET;
	 gad->Activation = TOGGLESELECT | GADGIMMEDIATE;
	 egad->eg_Render = (APTR)&ri->ri_Images[IMAGE_CYCLE];
	 egad->eg_Flags |= EXTENDED_GADGET_FLAG_RENDER_IMAGE;
	 break;

      case EXTENDED_GADGET_TYPE_COUNT :
	 gad->GadgetType = BOOLGADGET;
	 gad->Activation = TOGGLESELECT | GADGIMMEDIATE;
	 egad->eg_Render = (APTR)&ri->ri_Images[IMAGE_COUNT_LEFT];
	 egad->eg_Flags |= EXTENDED_GADGET_FLAG_RENDER_IMAGE;
	 break;

      case EXTENDED_GADGET_TYPE_LISTVIEW_ENTRY :
	 gad->GadgetType = BOOLGADGET;
	 gad->Activation = RELVERIFY;
	 gad->Flags      = GADGHCOMP;
	 break;

      case EXTENDED_GADGET_TYPE_PALETTE_INDICATOR :
      case EXTENDED_GADGET_TYPE_PALETTE_COLOR :
	 gad->GadgetType = BOOLGADGET;
	 gad->Activation = RELVERIFY;

	 /* Init image */
	 image   = (struct Image *)buffer;
	 buffer += sizeof(struct Image);
	 if (flags & GADGET_DATA_FLAG_NO_BORDER) {
	    image->Width  = width;
	    image->Height = height;
	 } else {
	    image->Width  = width - 2 * 4;
	    image->Height = height - 2 * 2;
	 }
	 image->Depth    = ri->ri_ScreenDepth;
	 egad->eg_Render = (APTR)image;
	 egad->eg_Flags |= EXTENDED_GADGET_FLAG_RENDER_IMAGE;
	 break;
   }
   if (flags & GADGET_DATA_FLAG_DISABLED) {
      gad->Flags |= GADGDISABLED;
   }
   return(init_gadget_border(buffer, ri, egad, flags));
}
	/* Init gadget border */

   STATIC BYTE *
init_gadget_border(BYTE *buffer, struct RenderInfo  *ri,
				  struct ExtendedGadget  *egad, ULONG flags)
{
   struct Gadget  *gad = &egad->eg_Gadget;
   USHORT width = gad->Width, height = gad->Height;

   switch (egad->eg_Type) {
      case EXTENDED_GADGET_TYPE_BUTTON :
	 if ((flags & GADGET_DATA_FLAG_BUTTON_TOGGLE) &&
				  (flags & GADGET_DATA_FLAG_BUTTON_IMAGE)) {
	    /* Init non toggle border out */
	    if (!(flags & GADGET_DATA_FLAG_NO_BORDER)) {
	       egad->eg_Render = (APTR)buffer;
	       egad->eg_Flags |= EXTENDED_GADGET_FLAG_RENDER_BORDER;
	       buffer          = init_border(ri, buffer, 0, 0, width,
					 height, BORDER_DATA_TYPE_BOX1_OUT);
	    }
	 } else {

	    /* Init toggle border */
	    if (flags & GADGET_DATA_FLAG_HIGH_COMP) {
	       gad->Flags |= GADGHCOMP;
	       if (!(flags & GADGET_DATA_FLAG_NO_BORDER)) {
		  gad->GadgetRender = (APTR)buffer;
		  buffer            = init_border(ri, buffer, 0, 0, width,
					 height, BORDER_DATA_TYPE_BOX1_OUT);
	       }
	    } else {
	       if (!(flags & GADGET_DATA_FLAG_NO_BORDER)) {
		  gad->Flags       |= GADGHIMAGE;
		  gad->GadgetRender = (APTR)buffer;
		  buffer            = init_border(ri, buffer, 0, 0, width,
					 height, BORDER_DATA_TYPE_BOX1_OUT);
		  gad->SelectRender = (APTR)buffer;
		  buffer            = init_border(ri, buffer, 0, 0, width,
					  height, BORDER_DATA_TYPE_BOX1_IN);
	       } else {
		  if (!(gad->Flags & GADGHIMAGE)) {
		     gad->Flags |= GADGHNONE;
		  }
	       }
	    }
	 }
	 break;

      case EXTENDED_GADGET_TYPE_CHECK :

	 /* Init non toggle border out */
	 if (!(flags & GADGET_DATA_FLAG_NO_BORDER)) {
	    egad->eg_Render = (APTR)buffer;
	    egad->eg_Flags |= EXTENDED_GADGET_FLAG_RENDER_BORDER;
	    buffer          = init_border(ri, buffer, 0, 0, width, height,
						 BORDER_DATA_TYPE_BOX1_OUT);
	 }
	 break;

      case EXTENDED_GADGET_TYPE_SCROLLER_LEFT :
      case EXTENDED_GADGET_TYPE_SCROLLER_RIGHT :
      case EXTENDED_GADGET_TYPE_SCROLLER_UP :
      case EXTENDED_GADGET_TYPE_SCROLLER_DOWN :
      case EXTENDED_GADGET_TYPE_LISTVIEW_UP :
      case EXTENDED_GADGET_TYPE_LISTVIEW_DOWN :
      case EXTENDED_GADGET_TYPE_CYCLE :
      case EXTENDED_GADGET_TYPE_COUNT :
      case EXTENDED_GADGET_TYPE_PALETTE_COLOR :

	 /* Init toggle border */
	 if (flags & GADGET_DATA_FLAG_HIGH_COMP) {
	    gad->Flags |= GADGHCOMP;
	    if (!(flags & GADGET_DATA_FLAG_NO_BORDER)) {
	       gad->GadgetRender = (APTR)buffer;
	       buffer            = init_border(ri, buffer, 0, 0,
				  width, height, BORDER_DATA_TYPE_BOX1_OUT);
	    }
	 } else {
	    if (!(flags & GADGET_DATA_FLAG_NO_BORDER)) {
	       gad->Flags       |= GADGHIMAGE;
	       gad->GadgetRender = (APTR)buffer;
	       buffer            = init_border(ri, buffer, 0, 0, width,
					 height, BORDER_DATA_TYPE_BOX1_OUT);
	       gad->SelectRender = (APTR)buffer;
	       buffer            = init_border(ri, buffer, 0, 0, width,
					  height, BORDER_DATA_TYPE_BOX1_IN);
	    } else {
	       gad->Flags |= GADGHNONE;
	    }
	 }
	 break;

      case EXTENDED_GADGET_TYPE_PALETTE_INDICATOR :

	 /* Init non toggle border in */
	 gad->Flags |= GADGHNONE;
	 if (!(flags & GADGET_DATA_FLAG_NO_BORDER)) {
	    gad->GadgetRender = (APTR)buffer;
	    buffer            = init_border(ri, buffer, 0, 0, width, height,
						  BORDER_DATA_TYPE_BOX1_IN);
	 }
	 break;

      case EXTENDED_GADGET_TYPE_STRING :
      case EXTENDED_GADGET_TYPE_INTEGER :

	 /* Init input border */
	 if (!(flags & GADGET_DATA_FLAG_NO_BORDER)) {
	    gad->GadgetRender = (APTR)buffer;
	    gad->LeftEdge    += 6;
	    gad->TopEdge     += 3;
	    gad->Width       -= 2 * 6;
	    gad->Height      -= 2 * 3;
	    buffer            = init_border(ri, buffer, -6, -3, width,
					 height, BORDER_DATA_TYPE_BOX2_OUT);
	 }
	 break;

      case EXTENDED_GADGET_TYPE_SLIDER_PROP :
      case EXTENDED_GADGET_TYPE_SCROLLER_PROP :
      case EXTENDED_GADGET_TYPE_LISTVIEW_PROP :

	 /* Init prop border */
	 if (!(flags & GADGET_DATA_FLAG_NO_BORDER)) {
	    egad->eg_Render = (APTR)buffer;
	    egad->eg_Flags |= EXTENDED_GADGET_FLAG_RENDER_BORDER;
	    gad->LeftEdge  += 4;
	    gad->TopEdge   += 2;
	    gad->Width     -= 2 * 4;
	    gad->Height    -= 2 * 2;
	    buffer          = init_border(ri, buffer, -4, -2, width, height,
						 BORDER_DATA_TYPE_BOX1_OUT);
	 }
	 break;
   }
   return(buffer);
}
	/* Init gadget text */

   STATIC VOID
init_gadget_text(struct ExtendedGadget  *egad, BYTE *text, USHORT width,
			   USHORT height, ULONG flags, struct TextAttr  *ta)
{
   /* Search hotkey in gadget text */
   if (flags & GADGET_DATA_FLAG_HOTKEY) {
      BYTE   *ptr = text;
      USHORT i;

      for (i = 0; *ptr; i++) {
	 BYTE c;

	 if (*ptr++ == '_' && (c = *ptr)) {

	    /* Only printable characters are allowed as hotkeys */
	    c = tolower(c);
	    if (c >= ' ' && c <= '~') {
	       egad->eg_Hotkey    = (USHORT)c;
	       egad->eg_HotkeyPos = i + 1;
	       egad->eg_Flags    |= EXTENDED_GADGET_FLAG_HOTKEY;
	       break;
	    }
	 }
      }
   }

   /* Ignore text if no output is required */
   if (!(flags & GADGET_DATA_FLAG_NO_TEXT_OUTPUT)) {
      struct IntuiText  itext;
      SHORT  text_width, text_height, xoffset, yoffset, left_edge, top_edge;
      USHORT type = egad->eg_DataType;

      /* Calc text dimension */
      itext.IText     = (UBYTE *)text;
      itext.ITextFont = ta;
      text_width      = IntuiTextLength(&itext);
      if (egad->eg_Flags & EXTENDED_GADGET_FLAG_HOTKEY) {
	 itext.IText = (UBYTE *)&hotkey_id[0];
	 text_width -= IntuiTextLength(&itext);
      }
      text_height = ta->ta_YSize;

      /* Calc border offset */
      if (flags & GADGET_DATA_FLAG_NO_BORDER) {
	 xoffset = 0;
	 yoffset = 0;
      } else {
	 switch (type) {
	    case GADGET_DATA_TYPE_MX :
	       xoffset = 8;
	       yoffset = 4;
	       break;

	    case GADGET_DATA_TYPE_STRING :
	    case GADGET_DATA_TYPE_INTEGER :
	       xoffset = 6;
	       yoffset = 3;
	       break;

	    case GADGET_DATA_TYPE_SLIDER :
	    case GADGET_DATA_TYPE_SCROLLER :
	    case GADGET_DATA_TYPE_LISTVIEW :
	       xoffset = 4;
	       yoffset = 2;
	       break;

	    default :
	       xoffset = 0;
	       yoffset = 0;
	       break;
	 }
      }

      /* Calc text pos */
      switch (type) {
	 case GADGET_DATA_TYPE_MX :
	    if (flags & GADGET_DATA_FLAG_TEXT_LEFT) {
	       left_edge = -(width - egad->eg_Gadget.Width - xoffset -
					   (SHORT)(width - text_width) / 2);
	    } else {
	       left_edge = (SHORT)(width - text_width) / 2 - xoffset;
	    }
	    if (text_height > IMAGE_KNOB_HEIGHT) {
	       top_edge = -((text_height - IMAGE_KNOB_HEIGHT) / 2);
	    } else {
	       top_edge = 0;
	    }
	    top_edge -= (text_height + yoffset + 4);
	    break;

	 case GADGET_DATA_TYPE_LISTVIEW :
	    left_edge = -(width - egad->eg_Gadget.Width - xoffset -
					   (SHORT)(width - text_width) / 2);
	    top_edge  = -(text_height + yoffset + 4);
	    break;

	 case GADGET_DATA_TYPE_PALETTE :
	    left_edge = (SHORT)(width - text_width) / 2;
	    top_edge  = -(text_height + 4);
	    break;

	 default :

	    /* Calc horizontal pos */
	    if (flags & GADGET_DATA_FLAG_TEXT_LEFT) {
	       left_edge = -(text_width + xoffset + 8);
	    } else {
	       if (flags & GADGET_DATA_FLAG_TEXT_RIGHT) {
		  left_edge = width - xoffset + 8;
	       } else {
		  left_edge = (SHORT)(width - 2 * xoffset - text_width) / 2;
	       }
	    }

	    /* Calc vertical pos */
	    if (flags & GADGET_DATA_FLAG_TEXT_ABOVE) {
	       top_edge = -(text_height + yoffset + 4);
	    } else {
	       if (flags & GADGET_DATA_FLAG_TEXT_BELOW) {
		  top_edge = height - yoffset + 4;
	       } else {
		  top_edge = (SHORT)(height - 2 * yoffset - text_height) / 2;
	       }
	    }
	    break;
      }

      /* Save position and width of text */
      egad->eg_Text         = text;
      egad->eg_TextLeftEdge = left_edge;
      egad->eg_TextTopEdge  = top_edge;
      egad->eg_TextWidth    = text_width;
   }
}
	/* Init mutual exclude gadget text */

   STATIC BYTE *
init_mx_text(struct ExtendedGadget  *egad, BYTE *buffer, BYTE *text,
	     USHORT width, USHORT height, ULONG flags, struct TextAttr  *ta)
{
   struct RenderInfo  *ri = egad->eg_GadgetList->gl_RenderInfo;
   struct IntuiText   *itext;

   itext            = (struct IntuiText *)buffer;
   buffer          += sizeof(struct IntuiText);
   itext->FrontPen  = (flags & GADGET_DATA_FLAG_TEXT_COLOR2 ?
					 ri->ri_TextPen2 : ri->ri_TextPen1);
   itext->BackPen   = ri->ri_BackPen;
   itext->DrawMode  = JAM2;
   itext->IText     = (UBYTE *)text;
   itext->ITextFont = ta;
   itext->TopEdge   = (SHORT)(height - ta->ta_YSize) / 2;
   if (flags & GADGET_DATA_FLAG_TEXT_LEFT) {
      itext->LeftEdge = -(IntuiTextLength(itext) + 8);
   } else {
      itext->LeftEdge = width + 8;   /* default right */
   }
   egad->eg_Gadget.GadgetText = itext;
   return(buffer);
}
	/* Check image for valid chip mem data */

   STATIC BOOL
check_gadget_image(struct Image  *image)
{
   BYTE *data;
   BOOL result;

   if (image && (data = (BYTE *)image->ImageData) &&
					   !(TypeOfMem(data) & MEMF_CHIP)) {
      result = FALSE;
   } else {
      result = TRUE;
   }
   return(result);
}
	/* Init image of button gadget */

   STATIC BYTE *
init_button_image(struct ExtendedGadget  *egad, struct GadgetData  *gd,
							       BYTE *buffer)
{
   struct Gadget  *gad = &egad->eg_Gadget;
   struct Image   *image = gd->gd_SpecialData.gd_ButtonData.
						      gd_ButtonNormalRender;
   if (gad->Flags & GADGIMAGE) {
      if (check_gadget_image(image) == FALSE) {
	 CopyMem((BYTE *)image, buffer, (LONG)sizeof(struct Image));
	 image   = (struct Image *)buffer;
	 buffer += sizeof(struct Image);
      }
      gad->GadgetRender = (APTR)image;
      if (gad->Flags & GADGHIMAGE) {
	 if (!(image = gd->gd_SpecialData.gd_ButtonData.
						   gd_ButtonSelectRender)) {
	    gad->Flags &= ~GADGHIGHBITS;
	    gad->Flags |= GADGHNONE;
	 } else {
	    if (check_gadget_image(image) == FALSE) {
	       CopyMem((BYTE *)image, buffer, (LONG)sizeof(struct Image));
	       image   = (struct Image *)buffer;
	       buffer += sizeof(struct Image);
	    }
	    gad->SelectRender = (APTR)image;
	 }
      }
   } else {
      if (check_gadget_image(image) == FALSE) {
	 CopyMem((BYTE *)image, buffer, (LONG)sizeof(struct Image));
	 image   = (struct Image *)buffer;
	 buffer += sizeof(struct Image);
      }
      egad->eg_Render = (APTR)image;
   }
   return(buffer);
}
	/* Init image data - make chipmem copy if needed */

   STATIC BYTE *
init_image_data(struct ExtendedGadget  *egad, BYTE *buffer)
{
   struct Gadget  *gad = &egad->eg_Gadget;
   struct Image   *image;
   LONG  size;
   BYTE  *data;
   UBYTE flags = egad->eg_Flags;

   switch (egad->eg_Type) {
      case EXTENDED_GADGET_TYPE_BUTTON :

	 /* Check normal button image */
	 if (flags & EXTENDED_GADGET_FLAG_RENDER_IMAGE) {
	    image = (struct Image *)egad->eg_Render;
	 } else {
	    image = (struct Image *)gad->GadgetRender;
	 }
	 if ((data = (BYTE *)image->ImageData) &&
					   !(TypeOfMem(data) & MEMF_CHIP)) {
	    size = (image->Width / 16 + (image->Width & 15 ? 1 : 0))
					 * image->Height * image->Depth * 2;
	    CopyMem(data, buffer, size);
	    image->ImageData = (UWORD *)buffer;
	    buffer          += size;
	 }

	 /* Check selected button image */
	 if ((image = (struct Image *)gad->SelectRender) &&
					(data = (BYTE *)image->ImageData) &&
					   !(TypeOfMem(data) & MEMF_CHIP)) {
	    size = (image->Width / 16 + (image->Width & 15 ? 1 : 0))
					 * image->Height * image->Depth * 2;
	    CopyMem(data, buffer, size);
	    image->ImageData = (UWORD *)buffer;
	    buffer          += size;
	 }
	 break;

      case EXTENDED_GADGET_TYPE_SLIDER_PROP :

	 /* Check image of proportional gadget knob */
	 if (flags & EXTENDED_GADGET_FLAG_KNOB_IMAGE) {
	    image = (struct Image *)gad->GadgetRender;
	    if ((data = (BYTE *)image->ImageData) &&
					   !(TypeOfMem(data) & MEMF_CHIP)) {
	       size = (image->Width / 16 + (image->Width & 15 ? 1 : 0))
					 * image->Height * image->Depth * 2;
	       CopyMem(data, buffer, size);
	       image->ImageData = (UWORD *)buffer;
	       buffer          += size;
	    }
	 }
	 break;
   }
   return(buffer);
}
