/***************************************************************************
 *		  Copyright (C) 1994  Charles P. Peterson                  *
 *	     4007 Enchanted Sun, San Antonio, Texas 78244-1254             *
 *              Email: Charles_P_Peterson@fcircus.sat.tx.us                *
 *                                                                         *
 *		  This is free software with NO WARRANTY.                  *
 *	      See gfft.c, or run program itself, for details.              *
 *		      Support is available for a fee.                      *
 ***************************************************************************
 *
 * Program:     gfft--General FFT analysis
 * File:        wbtools.c
 * Purpose:     workbench GUI toolkit for GFFT
 * Author:      Charles Peterson (CPP)
 * History:     19-Nov-1993 CPP; Created.
 *              4-Aug-94 CPP (1.04); Filenames may contain spaces
 * Comments:    Workbench GUI.  Amiga Dependent!
 *              There may be other toolkits.  Mine is intended to be
 *              compatible with all releases of AmigaDOS.  It was
 *              started when I only had the Version 1 RKM's, but has been
 *              upgraded to correspond to the Version 3 RKM's.  It is
 *              simple (I think, anyway).  The basic model is:
 *              rows of 'text buttons.'  Possibly not visually
 *              indulgent.
 */

#ifdef AMIGA

#include <stdio.h>     /* sprintf() */
#include <string.h>
/*
 * Amiga includes
 */
#include <exec/types.h>
#include <exec/exec.h>
#include <workbench/workbench.h>
#include <workbench/icon.h>
#include <workbench/startup.h>
#include <intuition/intuition.h>
#include <clib/intuition_protos.h>
#include <clib/exec_protos.h>
#include <proto/icon.h>
#include <proto/dos.h>
#include <dos/dos.h>
#include <libraries/asl.h>
#include <clib/asl_protos.h>
#include <graphics/text.h>
#include <clib/graphics_protos.h>
#include <graphics/gfxmacros.h>  /* BNDRYOFF */

#include "gfft.h"
#include "wbench.h"

/*
 * Dialogue Window parameters...pretty good guesses for 2.0 and 1.3
 * reset later if drawinfo is available
 */
#define SHINE_PEN_20 2
#define SHADOW_PEN_20 1
#define SHINE_PEN_13 1
#define SHADOW_PEN_13 2
#define TEXT_PEN 1          /* Seems to work well under both 2.0 and 1.3 */
#define FILL_TEXT_PEN 2     /* ditto; hmmn, I like better than 2.0 default */
#define BACKGROUND_PEN 0    /* almost guaranteed now, but may be updated */

#define FONT_SIZE 8

#define FIRST_WINDOW_BUTTON_LEFT 12
#define FIRST_WINDOW_BUTTON_TOP 6

#define FIRST_REQUESTER_BUTTON_LEFT 10
#define FIRST_REQUESTER_BUTTON_TOP 4

#define BUTTON_SIDE_EDGE 8

#define BUTTON_WIDTH(WIDTH) ((WIDTH) * FONT_SIZE + 2 * BUTTON_SIDE_EDGE)

#define BUTTON_TOP_EDGE 3    /* Inside button to text; same as bottom edge*/
#define BUTTON_TOP_SPACE 2   /* Vertical space between buttons */
#define BUTTON_HEIGHT (FONT_SIZE + 2 * BUTTON_TOP_EDGE)

struct TextAttr Font = {
"topaz.font",
FONT_SIZE,
NULL,
NULL
};

static short shine_pen = SHINE_PEN_20;
static short shadow_pen = SHADOW_PEN_20;
static short text_pen = TEXT_PEN;
static short fill_text_pen = FILL_TEXT_PEN;
static short background_pen = BACKGROUND_PEN;
short Screen_Font_Height = 8;  /* Guess, corrected later for 2.0+ */

static short first_button_left = FIRST_WINDOW_BUTTON_LEFT;
static short first_button_top = FIRST_WINDOW_BUTTON_TOP + 8;
static short max_rows = 0;
static int gadget_mode_flag = NULL;
static struct IntuiText *next_textp = NULL;
static struct Gadget *next_gadgetp = NULL;
static struct Requester *current_requesterp = NULL;

struct Library *IntuitionBase = NULL;
BOOLEAN Old_Intuition = FALSE;
short Max_Columns = 0;

extern struct Library *AslBase;   /* from filereq.c */
extern struct FileRequester *File_Requesterp;

void open_libraries (void)
{
    struct Screen *screen;
    struct DrawInfo *draw_info;

    if (!IntuitionBase)
    {
/*
 * What the hey! SAS C automatically opens libraries for me
 * if I don't define their globals.  It automagically closes them too!
 * This is OK unless I need to specify version, or provide for case
 * (as with newer libraries) where the library may be unavailable.
 */

/*	IconBase = OpenLibrary ("icon.library", 0); */
/*	if (IconBase == NULL) gabort (EXIT_FAILURE); */

	IntuitionBase = OpenLibrary ("intuition.library", 37);
	if (IntuitionBase == NULL) 
	{
	    Old_Intuition = TRUE;
	    shine_pen = SHINE_PEN_13;  /* These usually work for 1.3... */
	    shadow_pen = SHADOW_PEN_13;  /* Should do this better someday */
	    IntuitionBase = OpenLibrary ("intuition.library", 0);
	    if (IntuitionBase == NULL)
	    {
		error_message (CANT_OPEN_INTUITION);
		gabort (EXIT_FAILURE);
	    }
	}
	else  /* Ok, Rev 37 or greater, get pens for default screen */
	{
	    if (screen = LockPubScreen (NULL))
	    {
		if (draw_info = GetScreenDrawInfo (screen))
		{
		    shine_pen = draw_info->dri_Pens[SHINEPEN];
		    shadow_pen = draw_info->dri_Pens[SHADOWPEN];
		    text_pen = draw_info->dri_Pens[TEXTPEN];
/*		    fill_text_pen = draw_info->dri_Pens[FILLTEXTPEN]; */
		    background_pen = draw_info->dri_Pens[BACKGROUNDPEN];
		    Screen_Font_Height = 
		      draw_info->dri_Font->tf_YSize;
		    FreeScreenDrawInfo (screen, draw_info);
		}
		UnlockPubScreen (NULL, screen);
	    }
	}
    }
}

void close_amiga_stuff (void)
{
    if (IntuitionBase)
    {
	CloseLibrary (IntuitionBase);
	IntuitionBase = NULL;
    }
    if (File_Requesterp)
    {
	FreeAslRequest(File_Requesterp);
	File_Requesterp = NULL;
    }
    if (AslBase)
    {
        CloseLibrary(AslBase);
	AslBase = NULL;
    }
}


struct Border *requester_border__new (short height, short width,
			    short top_pen, short bottom_pen)
{
    struct Border *rborder;

    rborder = border__new (height-1, width-1, top_pen, bottom_pen);
    return rborder;
}


struct Border *button_border__new (short width, short top_pen,
				   short bottom_pen)
{

    struct Border *bborder;

    bborder = border__new (BUTTON_HEIGHT-1, width-1, top_pen, bottom_pen);
    return bborder;
}


struct Border *border__new (short height, short width, short top_pen,
			    short bottom_pen)
{
    short *xy_pairs_u, *xy_pairs_l;
    struct Border *border_u, *border_l;

    xy_pairs_u = gcalloc (6, sizeof (short), NOTHING_SPECIAL);
    xy_pairs_l = gcalloc (6, sizeof (short), NOTHING_SPECIAL);
    border_u = gcalloc (1, sizeof (struct Border), NOTHING_SPECIAL);
    border_l = gcalloc (1, sizeof (struct Border), NOTHING_SPECIAL);

    xy_pairs_u[0] = 0;
    xy_pairs_u[1] = height;
    xy_pairs_u[2] = 0;
    xy_pairs_u[3] = 0;
    xy_pairs_u[4] = width;
    xy_pairs_u[5] = 0;

    xy_pairs_l[0] = 0;
    xy_pairs_l[1] = height;
    xy_pairs_l[2] = width;
    xy_pairs_l[3] = height;
    xy_pairs_l[4] = width;
    xy_pairs_l[5] = 0;

    border_u->LeftEdge = 0;
    border_u->TopEdge = 0;
    border_u->XY = xy_pairs_u;
    border_u->FrontPen = top_pen;
    border_u->DrawMode = JAM1;
    border_u->NextBorder = border_l;
    border_u->Count = 3;

    border_l->LeftEdge = 0;
    border_l->TopEdge = 0;
    border_l->XY = xy_pairs_l;
    border_l->FrontPen = bottom_pen;
    border_l->DrawMode = JAM1;
    border_l->NextBorder = NULL;
    border_l->Count = 3;

    return border_u;
}
    

struct Gadget *radio_button__new (char *text, short tcol, short trow)
{
    struct Gadget *gadgetp;

    gadgetp = toggle_button__new (text, tcol, trow);
    gadgetp->Activation &= ~TOGGLESELECT;
    return gadgetp;
}

struct Gadget *toggle_button__new (char *text, short tcol, short trow)
{
    struct Gadget *gadgetp;

    gadgetp = text_button__new (text, tcol, trow);
    gadgetp->Activation &= ~GACT_RELVERIFY;
    gadgetp->Activation |= GADGIMMEDIATE;
    gadgetp->Activation |= TOGGLESELECT;
    return gadgetp;
}


struct Gadget *message_gadget__new (short length, short tcol, short trow)
{
    struct Gadget *mgadgetp;

    mgadgetp = gadget__new (length, tcol, trow);
    mgadgetp->Flags = GFLG_GADGHNONE;
    mgadgetp->Activation = NULL;
    mgadgetp->GadgetRender = button_border__new (BUTTON_WIDTH (length),
						 shadow_pen, shine_pen);
    mgadgetp->GadgetText = NULL;
    return mgadgetp;
}

struct Gadget *text_button__new (char *text, short tcol, short trow)
{
    struct Gadget *gadgetp;

    gadgetp = gadget__new (strlen (text), tcol, trow);

    gadgetp->GadgetText = button_text__new (text);
    return gadgetp;
}

void gadget__begin (int gadget_flag)
{
    gadget_mode_flag = gadget_flag;
    Max_Columns = 0;
    max_rows = 0;
    next_textp = NULL;
    next_gadgetp = NULL;

    if (gadget_mode_flag == GTYP_REQGADGET)
    {
	first_button_left = FIRST_REQUESTER_BUTTON_LEFT;
	first_button_top = FIRST_REQUESTER_BUTTON_TOP;
    }
    else
    {
	first_button_left = FIRST_WINDOW_BUTTON_LEFT;
	first_button_top = FIRST_WINDOW_BUTTON_TOP + Screen_Font_Height;
    }
}

struct Gadget *gadget__new (short length, short tcol, short trow)
{
    struct Gadget *gadgetp;
    short local_max_column = length + tcol;

    if (local_max_column > Max_Columns) Max_Columns = local_max_column;
    if (trow + 1 > max_rows) max_rows = trow + 1;

    gadgetp = gcalloc (1, sizeof (struct Gadget), NOTHING_SPECIAL);

    gadgetp->NextGadget = next_gadgetp;
    next_gadgetp = gadgetp;

    gadgetp->LeftEdge = first_button_left + tcol * FONT_SIZE;
    gadgetp->TopEdge = first_button_top + trow * 
      (2 * BUTTON_TOP_EDGE + BUTTON_TOP_SPACE + FONT_SIZE);
    gadgetp->Width = BUTTON_WIDTH (length);
    gadgetp->Height = FONT_SIZE + 2 * BUTTON_TOP_EDGE;
    gadgetp->Activation = GACT_RELVERIFY;
    gadgetp->GadgetType = GTYP_BOOLGADGET;
    gadgetp->GadgetRender = button_border__new (BUTTON_WIDTH (length),
						shine_pen, shadow_pen);
/*    gadgetp->SelectRender = button_border__new (BUTTON_WIDTH (length)
 *                                                shadow_pen, shine_pen);
 *    gadgetp->Flags = GADGHIMAGE;
 */
    gadgetp->Flags = GFLG_GADGHCOMP | gadget_mode_flag;
    gadgetp->SelectRender = NULL;

    gadgetp->GadgetText = NULL;
    gadgetp->MutualExclude = NULL;
    gadgetp->SpecialInfo = NULL;
    gadgetp->GadgetID = NULL;
    gadgetp->UserData = NULL;
    return gadgetp;
}


struct StringInfo *string_info__new (short max_chars, short vis_chars)
{
    struct StringInfo *string_info;

    string_info = gcalloc (1, sizeof (struct StringInfo), NOTHING_SPECIAL);

    string_info->Buffer = gcalloc (1, max_chars+1, NOTHING_SPECIAL);
    string_info->MaxChars = max_chars+1;
    string_info->UndoBuffer = NULL;
    string_info->BufferPos = 0;
    string_info->DispPos = 0;
    string_info->CTop = BUTTON_TOP_EDGE;
    string_info->CLeft = BUTTON_SIDE_EDGE;
    string_info->DispCount = vis_chars;

    return string_info;
}


struct Gadget *string_gadget__new (char *prompt, char *initial_name,
					  short max_chars, 
					  short length, short tcol, 
					  short trow)
{
    struct Gadget *string_gadgetp;
    struct Border *borderp;
    struct Border *bottomp;
    short *bottom_xy;
    short right_text_offset, right_border_offset;
    short container_length, container_tcol;
    
/*
 * (Damn! Intuition doesn't allow user offset for string gadget container
 *  offsets within overall gadget area, so must do it manually.)
 */
    container_length = length - (strlen (prompt) + 2);
    container_tcol = tcol + (strlen (prompt) + 2);

    string_gadgetp = gadget__new (container_length, container_tcol, trow);

    string_gadgetp->GadgetType = GTYP_STRGADGET;
    string_gadgetp->Activation |= GADGIMMEDIATE;

    string_gadgetp->SpecialInfo = string_info__new (max_chars, length-4);

    string_gadgetp->GadgetText = button_text__new (prompt);

    right_border_offset = BUTTON_SIDE_EDGE;
    right_text_offset = BUTTON_SIDE_EDGE*2 + strlen (prompt) * 
      FONT_SIZE + right_border_offset;

    string_gadgetp->GadgetText->LeftEdge -= right_text_offset;

    string_gadgetp->LeftEdge += right_border_offset;
    borderp = (struct Border *) string_gadgetp->GadgetRender;
    borderp->XY[0] -= right_border_offset;
    borderp->XY[2] -= right_border_offset;
    borderp->XY[4] -= right_border_offset;
    borderp = borderp->NextBorder;
    borderp->XY[0] -= right_border_offset;
    borderp->XY[2] -= right_border_offset;
    borderp->XY[4] -= right_border_offset;
    string_gadgetp->Width -= right_border_offset + BUTTON_SIDE_EDGE;

    string_gadgetp->TopEdge += BUTTON_TOP_EDGE;
    string_gadgetp->GadgetText->TopEdge -= BUTTON_TOP_EDGE;
    borderp = (struct Border *) string_gadgetp->GadgetRender;
    borderp->XY[1] -= BUTTON_TOP_EDGE;
    borderp->XY[3] -= BUTTON_TOP_EDGE;
    borderp->XY[5] -= BUTTON_TOP_EDGE;
    borderp = borderp->NextBorder;
    borderp->XY[1] -= BUTTON_TOP_EDGE;
    borderp->XY[3] -= BUTTON_TOP_EDGE;
    borderp->XY[5] -= BUTTON_TOP_EDGE;
    string_gadgetp->Height -= BUTTON_TOP_EDGE * 2;
/*
 * Add "bottom line"
 */
    bottomp = gcalloc (1, sizeof (struct Border), NOTHING_SPECIAL);
    bottom_xy = gcalloc (4, sizeof (short), NOTHING_SPECIAL);

    bottom_xy[0] = 0;
    bottom_xy[1] = FONT_SIZE;
    bottom_xy[2] = container_length * FONT_SIZE;
    bottom_xy[3] = FONT_SIZE;
    
    bottomp->LeftEdge = 0;
    bottomp->TopEdge = 0;
    bottomp->XY = bottom_xy;
    bottomp->FrontPen = shadow_pen;
    bottomp->DrawMode = JAM1;
    bottomp->NextBorder = NULL;
    bottomp->Count = 2;

    borderp->NextBorder = bottomp;

    if (initial_name)
    {
	struct StringInfo *string_info = string_gadgetp->SpecialInfo;
	strcpy (string_info->Buffer, initial_name);
    }

    return string_gadgetp;
}


struct IntuiText *requester_text__new (char *text, short tcol, short trow)
{
    struct IntuiText *textst;
    short local_max_column = tcol + strlen (text);

    if (local_max_column > Max_Columns) Max_Columns = local_max_column;
    if (trow + 1 > max_rows) max_rows = trow + 1;

    textst = button_text__new (text);
    textst->LeftEdge = first_button_left + BUTTON_SIDE_EDGE + 
      tcol * FONT_SIZE;
    textst->TopEdge = first_button_top + BUTTON_TOP_EDGE + 
      trow * (2 * BUTTON_TOP_EDGE + BUTTON_TOP_SPACE + FONT_SIZE);
    textst->NextText = next_textp;
    next_textp = textst;

    return textst;
}

struct IntuiText *button_text__new (char *text)
{
    struct IntuiText *textst;

    textst = gcalloc (1, sizeof (struct IntuiText), NOTHING_SPECIAL);

    textst->FrontPen = TEXT_PEN;
    textst->BackPen = BACKGROUND_PEN;
    textst->DrawMode = JAM1;
    textst->LeftEdge = BUTTON_SIDE_EDGE;
    textst->TopEdge = BUTTON_TOP_EDGE;
    textst->ITextFont = &Font;
    textst->IText = text;
    textst->NextText = NULL;
    return textst;
}

void refresh_gadget (struct Gadget *gadgetp, struct Window *windowp)
{
    RefreshGList (gadgetp, windowp, current_requesterp, 1);
}

void toggle_button__toggle (struct Gadget *gadgetp, 
		     char *(*on_function)(char *arg),
		     char *(*off_function)(char *arg),
		     struct Window *windowp)
{
    if (!(gadgetp->Flags & SELECTED))
    {
	(*off_function) (NullString);
    }
    else
    {
	(*on_function) (NullString);
    }
}

void radio_button__toggle (struct Gadget *gadgetp, 
		     char *(*on_function)(char *arg),
		     char *(*off_function)(char *arg),
		     struct Window *windowp)
{
/*
 * Must do imagery here for radio buttons
 */
    if (gadgetp->Flags & SELECTED)
    {
	(*off_function) (NullString);
	radio_button__out (gadgetp, windowp);
    }
    else
    {
	(*on_function) (NullString);
	radio_button__in (gadgetp, windowp);
    }
}

char *string_gadget__apply (struct Gadget *string_gadgetp,
			    char *(*apply_function)(char *arg))
{
    struct StringInfo *string_infop = 
      string_gadgetp->SpecialInfo;
    char *buffer = string_infop->Buffer;
    buffer[string_infop->NumChars] = '\0';
    (*apply_function) (buffer);
    return buffer;
}

/*
 * (1.04) Names in requesters may include spaces, so
 * must be quoted
 */
char *name_string_gadget__apply (struct Gadget *string_gadgetp,
				 char *(*apply_function)(char *arg))
{
    char *enquote_buffer;
    struct StringInfo *string_infop = 
      string_gadgetp->SpecialInfo;
    char *buffer = string_infop->Buffer;
    buffer[string_infop->NumChars] = '\0';

    if (!string_infop->NumChars)
    {
	(*apply_function) (buffer);  /* Null String; don't enquote */
    }
    else
    {
	enquote_buffer = gmalloc (string_infop->NumChars + 8, 
				  NOTHING_SPECIAL);
	sprintf (enquote_buffer, "\"%s\"", buffer);
	(*apply_function) (enquote_buffer);
	gfree (enquote_buffer);
    }
    return buffer;
}

void string_gadget__reset (struct Gadget *string_gadgetp,
			    char *new_string,
			    struct Window *windowp)
{
    struct StringInfo *string_infop = 
      string_gadgetp->SpecialInfo;
    char *buffer = string_infop->Buffer;
    int string_length = 0;
    if (!new_string || (string_length = strlen (new_string)) <= 0)
    {
	buffer[0] = '\0';
    }
    else
    {
	strcpy (buffer, new_string);
    }
    string_infop->NumChars = string_length;
    refresh_gadget (string_gadgetp, windowp);
}


void message_requester (struct Window *windowp, char *message_text)
{
    extern char *Got_It_S;
    struct IntuiText *mtextp = button_text__new (message_text);
    struct IntuiText *got_it_textp = button_text__new (Got_It_S);

    if (Old_Intuition)
    {
	mtextp->DrawMode = JAM2 | INVERSVID;
	got_it_textp->DrawMode = JAM2 | INVERSVID;
    }

    AutoRequest (windowp, mtextp, NULL, got_it_textp,
		     IDCMP_GADGETDOWN,
		     IDCMP_GADGETDOWN, 640, 50);

    gfree (mtextp);
    gfree (got_it_textp);
}

/*
 * I very much like the appearance of gadgets whose background and text are
 * complemented when selected. Complementing also works well with 3-d gadget
 * borders.  And, I find the use of 'images' to be inefficient and difficult
 * in comparison with Intuition borders and text.  Therefore, I have decided
 * NOT to follow the guidelines for 'mutually exclusive' gadgets on page 140
 * of the Amiga Rom Kernel Reference Manual, Third Edition, which
 * specifically advise against this combination (mutually exclusive gadgets
 * using complementing).
 *
 * However, I have chosen instead to follow the guidelines for 'Updating
 * a Gadget's Imagery' on pages 129-130.  Before a radio_button is
 * refreshed in either selected or unselected state, the background
 * behind it is restored ("cleared") with RectFill.  I do this very
 * carefully as you will see.
 *
 * This concept has been extended to cover other features, such as
 * gadget disable and enable, which I couldn't get to work before.
 *
 * This should be acceptable and stable with future released of Intuition.
 * At least, there is some hope.  And it works with 1.2-2.1 for sure.
 *
 * It now even handles requester gadgets properly.
 */

void radio_button__in (struct Gadget *gadgetp, struct Window *windowp)
{
    struct RastPort *rport;
    short x1, y1, x2, y2;
    UBYTE save_apen;  /* I preserve this one, dunno if necessary */

    if (windowp)
    {
	if (!(gadgetp->Flags & GFLG_SELECTED))  /* pushing my luck */
	{
	    RemoveGadget (windowp, gadgetp); 
	    gadgetp->Flags |= GFLG_SELECTED;

	    rport = (current_requesterp) ? 
	      current_requesterp->ReqLayer->rp :
		windowp->RPort;

	    save_apen = rport->FgPen;

	    SetAPen (rport, (UBYTE) background_pen);
	    SetDrMd (rport, JAM1);
	    SetAfPt (rport, NULL, 0);
	    SetWrMsk (rport, (UBYTE) 0xff);
	    BNDRYOFF (rport);
	    x1 = gadgetp->LeftEdge;
	    y1 = gadgetp->TopEdge;
	    x2 = x1 + gadgetp->Width - 1;
	    y2 = y1 + gadgetp->Height - 1;
	    
	    RectFill (rport, x1, y1, x2, y2);
	    
	    SetAPen (rport, (UBYTE) save_apen);
	    
	    AddGList (windowp, gadgetp, -1, 1, current_requesterp);
	    refresh_gadget (gadgetp, windowp);
	}
    }
    else  /* if (!windowp) */
    {
	gadgetp->Flags |= GFLG_SELECTED;
    }
}
    
void radio_button__out (struct Gadget *gadgetp, struct Window *windowp)
{
    struct RastPort *rport;
    short x1, y1, x2, y2;
    UBYTE save_apen;  /* I preserve this one, dunno if necessary */

    if (windowp)
    {
	if (gadgetp->Flags & GFLG_SELECTED)
	{
	    RemoveGadget (windowp, gadgetp);
	    gadgetp->Flags &= ~GFLG_SELECTED;

	    rport = (current_requesterp) ? 
	      current_requesterp->ReqLayer->rp :
	      windowp->RPort;

	    save_apen = rport->FgPen;

	    SetAPen (rport, (UBYTE) background_pen);
	    SetDrMd (rport, JAM1);
	    SetAfPt (rport, NULL, 0);
	    SetWrMsk (rport, (UBYTE) 0xff);
	    BNDRYOFF (rport);
	    x1 = gadgetp->LeftEdge;
	    y1 = gadgetp->TopEdge;
	    x2 = x1 + gadgetp->Width - 1;
	    y2 = y1 + gadgetp->Height - 1;

	    RectFill (rport, x1, y1, x2, y2);

	    SetAPen (rport, (UBYTE) save_apen);

	    AddGList (windowp, gadgetp, -1, 1, current_requesterp);
	    refresh_gadget (gadgetp, windowp);
	}
    }
    else /* if (!windowp) */
    {
	gadgetp->Flags &= ~GFLG_SELECTED;
    }
}

void gadget__disable (struct Gadget *gadgetp, struct Window *windowp)
{
    struct RastPort *rport;
    short x1, y1, x2, y2;
    UBYTE save_apen;  /* I preserve this one, dunno if necessary */

    if (gadgetp->Flags & GFLG_DISABLED) return;

    if (!windowp)
    {
	gadgetp->Flags |= GFLG_DISABLED;
	return;
    }

/* #define OFF_GADGET_OK */

#ifdef OFF_GADGET_OK
    OffGadget (gadgetp, windowp, current_requesterp);
#else

/* I thought I had figured it all out, but another OffGadget bug fooled */
/* even me.  A different gadget gets hosed.  So, here I am doing */
/* it my way again. (I was already doing this for OnGadget and almost */
/* everything else anyway...but I had figured OffGadget would be OK.) */
/* Oh well.  (See additional lengthy comments written earlier above.) */

    RemoveGadget (windowp, gadgetp);
    gadgetp->Flags |= GFLG_DISABLED;

    rport = (current_requesterp) ? current_requesterp->ReqLayer->rp :
      windowp->RPort;

    save_apen = rport->FgPen;

    SetAPen (rport, (UBYTE) background_pen);
    SetDrMd (rport, JAM1);
    SetAfPt (rport, NULL, 0);
    SetWrMsk (rport, (UBYTE) 0xff);
    BNDRYOFF (rport);
    x1 = gadgetp->LeftEdge;
    y1 = gadgetp->TopEdge;
    x2 = x1 + gadgetp->Width - 1;
    y2 = y1 + gadgetp->Height - 1;
	
    RectFill (rport, x1, y1, x2, y2);
	
    SetAPen (rport, (UBYTE) save_apen);

    AddGList (windowp, gadgetp, -1, 1, current_requesterp);
    refresh_gadget (gadgetp, windowp);

#endif /* OffGadget not OK */

}

void gadget__enable (struct Gadget *gadgetp, struct Window *windowp)
{
    struct RastPort *rport;
    short x1, y1, x2, y2;
    UBYTE save_apen;  /* I preserve this one, dunno if necessary */

    if (!(gadgetp->Flags & GFLG_DISABLED)) return;

    if (!windowp)
    {
	gadgetp->Flags |= GFLG_DISABLED;
	return;
    }

/* Yes, of course, OnGadget isn't smart enough for border gadgets */

    RemoveGadget (windowp, gadgetp);
    gadgetp->Flags &= ~GFLG_DISABLED;

    rport = (current_requesterp) ? current_requesterp->ReqLayer->rp :
      windowp->RPort;

    save_apen = rport->FgPen;

    SetAPen (rport, (UBYTE) background_pen);
    SetDrMd (rport, JAM1);
    SetAfPt (rport, NULL, 0);
    SetWrMsk (rport, (UBYTE) 0xff);
    BNDRYOFF (rport);
    x1 = gadgetp->LeftEdge;
    y1 = gadgetp->TopEdge;
    x2 = x1 + gadgetp->Width - 1;
    y2 = y1 + gadgetp->Height - 1;
	
    RectFill (rport, x1, y1, x2, y2);
	
    SetAPen (rport, (UBYTE) save_apen);

    AddGList (windowp, gadgetp, -1, 1, current_requesterp);
    refresh_gadget (gadgetp, windowp);
}


void message_gadget__write (struct Gadget *gadgetp, char *message, struct
			    Window *windowp)
{
    struct RastPort *rport;

    if (windowp) RemoveGadget (windowp, gadgetp);

    if (gadgetp->GadgetText) gfree (gadgetp->GadgetText);
    gadgetp->GadgetText = button_text__new (message);
    gadgetp->GadgetText->FrontPen = fill_text_pen;

    if (windowp)
    {
	short x1, y1, x2, y2;

	x1 = gadgetp->LeftEdge;
	y1 = gadgetp->TopEdge;
	x2 = x1 + gadgetp->Width - 1;
	y2 = y1 + gadgetp->Height - 1;

	rport = (current_requesterp) ? current_requesterp->ReqLayer->rp :
	  windowp->RPort;

	RectFill (rport, x1, y1, x2, y2);
	AddGList (windowp, gadgetp, -1, 1, current_requesterp);
	refresh_gadget (gadgetp, windowp);
    }
}


struct Requester *requester__new (void)
{
    struct Requester *requesterp;
    short height = (max_rows * (FONT_SIZE + (2 * BUTTON_TOP_EDGE)))
                     + ((max_rows - 1) * BUTTON_TOP_SPACE) +
		     + (2 * FIRST_REQUESTER_BUTTON_TOP);
    short width = (Max_Columns * FONT_SIZE) + 
      (2 * (FIRST_REQUESTER_BUTTON_LEFT + BUTTON_SIDE_EDGE));

    requesterp = gmalloc (sizeof (struct Requester), NOTHING_SPECIAL);
    InitRequester (requesterp);
    requesterp->BackFill = background_pen;
    requesterp->ReqBorder = requester_border__new (height, width, shine_pen,
						   shadow_pen);
    requesterp->Width = width;
    requesterp->Height = height;
    requesterp->RelLeft = 0;
    requesterp->RelTop = 0;
    requesterp->Flags = POINTREL;
    return requesterp;
}

BOOLEAN requester__display (struct Requester *rp, struct Window *wp)
{
    if (Request (rp, wp))
    {
	current_requesterp = rp;
	return TRUE;
    }
    return FALSE;
}

void requester__remove (struct Requester *rp, struct Window *wp)
{
    current_requesterp = NULL;
    EndRequest (rp, wp);
}


#endif  /* ifdef AMIGA */

