/***************************************************************************
* 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
* 14-Dec-94 CPP (1.16); Fix message indicator for >4 colors
* 14-Dec-94 CPP (1.17); Fix button gadgets for >4 colors
* 5-Jan-95 CPP (1.18); Use system default font if possible
* 17-Jan-95 CPP (1.20); Size shells nicely
* 26-Jan-95 CPP (1.26); Allow largest possible font size
* 27-Jan-95 CPP (1.27); Report window open failure
* 28-Jan-95 CPP (1.29); Labeled radio buttons
* 28-Jan-95 CPP (1.30); Tall action buttons
* 6-Feb-95 CPP (1.31); Progress requester gadgets
* 6-Feb-95 CPP (1.32); Render to window while requester on
* 10-Feb-95 CPP (1.34); Thicker requester borders
*
* Comments: Workbench GUI. Amiga Dependent!
* There may be other toolkits. Mine is intended to be
* compatible with all releases of AmigaDOS, be fairly
* simple, and have a 3d-like look. I've had to make
* some small compromises: non-toggle gadgets only
* have their borders change when selected (the only good way
* to get around this is to have multiple images...with about
* an order of magnitude increase in complexity...or by using
* BOOPSI, which is fairly complicated itself and 2.0+
* dependent, or use MUI, which would not only necessitate
* a complete re-write but also would introduce some copyright
* inconsistencies. So, my rationalization anyway is that
* there is no _perfect_ choice, and the only better choices
* would take much more of my time to implement. I haven't
* made enough money on it so far to justify that.
*/
#ifdef AMIGA
#define GUI_DEBUG
#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 <intuition/sghooks.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 <proto/graphics.h> /* GfxBase */
#include <graphics/gfxbase.h>
#include "gfft.h"
#include "wbench.h"
#include "settings.h"
#define USE_MAX_ROWS_FOR_FONT_CHECK
/*
* Dialogue Window parameters...pretty good guesses for 2.0 and 1.3
* reset later (some require drawinfo to be available for reset)
*/
#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 FILL_PEN 3
#define BACKGROUND_PEN 0 /* almost guaranteed now, but may be updated */
#define DEFAULT_SCREEN_DEPTH 2
#define DEFAULT_SCREEN_FONT_HEIGHT 8
#define DEFAULT_FONT_HEIGHT 8
#define DEFAULT_FONT_WIDTH 8
#define FONT_COLUMNS_REQUIRED 80
#define FONT_ROWS_REQUIRED 24
#define DEFAULT_SHELL_WIDTH 640
#define DEFAULT_SHELL_HEIGHT 200
#define WINDOW_LEFT 0 /* Same as right edge */
#define WINDOW_TOP 0 /* Allow for WB title & click area above */
#define FIRST_WINDOW_BUTTON_LEFT 12
#define FIRST_WINDOW_BUTTON_TOP 6
#define FIRST_REQUESTER_BUTTON_LEFT 12
#define FIRST_REQUESTER_BUTTON_TOP 6
#define BUTTON_SIDE_EDGE (Font_Width)
#define BUTTON_TOP_EDGE 3 /* Inside button to text; same as bottom edge*/
#define BUTTON_TOP_SPACE 2 /* Vertical space between buttons */
/*
* Use the following when possible
*/
#define BUTTON_WIDTH(WIDTH) ((WIDTH) * Font_Width + 2 * BUTTON_SIDE_EDGE)
#define BUTTON_HEIGHT (Font_Height + 2 * BUTTON_TOP_EDGE)
#define BUTTON_SPACING (BUTTON_HEIGHT + BUTTON_TOP_SPACE)
#define BUTTON_TOP(row) (first_button_top + row * BUTTON_SPACING)
#define WINDOW_HEIGHT(max_rows) (BUTTON_TOP(max_rows) + \
BUTTON_TOP_SPACE) /* for the bottom edge */
struct TextAttr FontA = {
"topaz.font",
DEFAULT_FONT_HEIGHT,
NULL,
NULL
};
struct TextAttr *FontAp = &FontA;
struct TextFont *fontp = NULL; /* Set if system default font used */
static short shine_pen = SHINE_PEN_20;
static short shadow_pen = SHADOW_PEN_20;
static short text_pen = TEXT_PEN;
static short fill_pen = FILL_PEN;
static short fill_text_pen = FILL_TEXT_PEN;
static short background_pen = BACKGROUND_PEN;
short Screen_Font_Height = DEFAULT_SCREEN_FONT_HEIGHT;
short Font_Height = DEFAULT_FONT_HEIGHT;
short Font_Width = DEFAULT_FONT_WIDTH;
static short screen_depth = DEFAULT_SCREEN_DEPTH;
static short first_button_left = FIRST_WINDOW_BUTTON_LEFT;
static short first_button_top = FIRST_WINDOW_BUTTON_TOP +
DEFAULT_FONT_HEIGHT;
static short max_rows = 0;
static int gadget_type_mode = NULL;
static struct IntuiText *next_textp = NULL;
static struct Gadget *next_gadgetp = NULL;
static struct Requester *current_requesterp = NULL;
#define REQUESTER_STACK_DEPTH 10
static struct Requester *requester_stack[REQUESTER_STACK_DEPTH] =
{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
static int requester_stack_index = 0;
struct Library *IntuitionBase = NULL;
BOOLEAN Old_Intuition = FALSE;
short Max_Columns = 0;
int Shell_Width = DEFAULT_SHELL_WIDTH;
int Shell_Height = DEFAULT_SHELL_HEIGHT;
extern struct Library *AslBase; /* from filereq.c */
extern struct FileRequester *File_Requesterp;
static struct Gadget *text_button__new (char *text, short tcol, short trow);
void open_libraries (void)
{
/*
* Intuition is currently the only library for which we need to know
* version number, hence, we have to open it explicitly.
*/
if (!IntuitionBase)
{
IntuitionBase = OpenLibrary ("intuition.library", 37);
if (IntuitionBase == NULL)
{
Old_Intuition = TRUE;
IntuitionBase = OpenLibrary ("intuition.library", 0);
if (IntuitionBase == NULL)
{
error_message (CANT_OPEN_INTUITION);
gabort (EXIT_FAILURE);
}
}
}
}
void setup_window_defaults (int max_rows)
{
struct Screen *screen;
struct DrawInfo *draw_info;
if (Old_Intuition)
{
shine_pen = SHINE_PEN_13; /* These usually work for 1.3... */
shadow_pen = SHADOW_PEN_13; /* Should do this better someday */
/* everything else is defaulted */
}
else /* Ok, Rev 37 or greater, get pens and fonts */
{
if (screen = LockPubScreen (NULL))
{
if (draw_info = GetScreenDrawInfo (screen))
{
/* vars not used outside this block */
char *system_default_font_name;
short system_default_font_height;
short system_default_font_width;
short screen_width;
short screen_height;
short save_font_height;
shine_pen = draw_info->dri_Pens[SHINEPEN];
shadow_pen = draw_info->dri_Pens[SHADOWPEN];
text_pen = draw_info->dri_Pens[TEXTPEN];
fill_pen = draw_info->dri_Pens[FILLPEN];
fill_text_pen = draw_info->dri_Pens[FILLTEXTPEN];
background_pen = draw_info->dri_Pens[BACKGROUNDPEN];
screen_depth = draw_info->dri_Depth;
screen_width = screen->Width;
screen_height = screen->Height;
Screen_Font_Height =
draw_info->dri_Font->tf_YSize;
first_button_top = FIRST_WINDOW_BUTTON_TOP +
Screen_Font_Height;
/*
* Get system default font (always monospaced) info...
* (Maybe if I make some money on this, I'll rewrite to
* use the screen font (which might be proportional).
* Test to see that font permits max_rows and
* FONT_COLUMNS_REQUIRED
* before using (otherwise, we're defaulting to TOPAZ 8).
*/
system_default_font_name =
GfxBase->DefaultFont->tf_Message.mn_Node.ln_Name;
system_default_font_height =
GfxBase->DefaultFont->tf_YSize;
system_default_font_width =
GfxBase->DefaultFont->tf_XSize;
save_font_height = Font_Height;
Font_Height = system_default_font_height;
if (!Topaz &&
#ifndef FORCE_FONT
#ifndef USE_MAX_ROWS_FOR_FONT_CHECK
(screen_height / system_default_font_height >=
FONT_ROWS_REQUIRED) &&
#else
(WINDOW_HEIGHT(max_rows) <= screen_height) &&
#endif
#endif
(screen_width / system_default_font_width >=
FONT_COLUMNS_REQUIRED))
{
FontA.ta_Name = system_default_font_name;
FontA.ta_YSize = system_default_font_height;
Font_Height = system_default_font_height;
Font_Width = system_default_font_width;
fontp = GfxBase->DefaultFont;
/* Looks nicer without resetting shell height, upped later if needed */
Shell_Width = FONT_COLUMNS_REQUIRED *
system_default_font_width;
}
else
{
Font_Height = save_font_height;
Shell_Height = FONT_ROWS_REQUIRED *
system_default_font_height;
Shell_Width = FONT_COLUMNS_REQUIRED *
system_default_font_width;
if (Shell_Height > screen_height)
Shell_Height = screen_height;
if (Shell_Width > screen_width)
Shell_Width = screen_width;
}
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;
}
}
void gadget__begin (int gadget_type_flag)
{
gadget_type_mode = gadget_type_flag;
Max_Columns = 0;
max_rows = 0;
next_textp = NULL;
next_gadgetp = NULL;
if (gadget_type_mode == 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 Border *requester_border__new (short height, short width,
short top_pen, short bottom_pen)
{
struct Border *rborder;
struct Border *nborder;
rborder = border__new (height-1, width-1, top_pen, bottom_pen);
nborder = rborder->NextBorder->NextBorder = border__new
(height-3, width-3, top_pen, bottom_pen);
nborder->LeftEdge += 1;
nborder->TopEdge += 1;
nborder->NextBorder->LeftEdge += 1;
nborder->NextBorder->TopEdge += 1;
nborder = nborder->NextBorder->NextBorder = border__new
(height-5, width-5, top_pen, bottom_pen);
nborder->LeftEdge += 2;
nborder->TopEdge += 2;
nborder->NextBorder->LeftEdge += 2;
nborder->NextBorder->TopEdge += 2;
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] = 1; /* Looks a little nicer, I think, than 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 *progress_gadget__new (short length, short tcol, short trow)
{
struct Gadget *gadgetp;
gadgetp = message_gadget__new (length, tcol, trow);
gadgetp->UserData = NULL;
return gadgetp;
}
void progress_gadget__clear (struct Gadget *gadgetp, struct Window *windowp)
{
gadgetp->UserData = NULL;
if (gadgetp->GadgetText)
message_gadget__write (gadgetp, NullString, windowp);
}
void progress_gadget__update (struct Gadget *gadgetp,
int percentage,
struct Window *windowp)
{
struct RastPort *rport;
UBYTE save_apen;
struct Requester *requesterp;
int last_percentage = (int) gadgetp->UserData;
if (percentage == -1 || last_percentage == -1)
{
if (last_percentage == -1) return;
message_gadget__write (gadgetp, "Unable to measure progress...",
windowp);
gadgetp->UserData = (APTR) -1;
return;
}
if (last_percentage >= percentage) return;
if (percentage > 100 ) percentage = 100;
gadgetp->UserData = (APTR) percentage;
if (windowp)
{
short x1, y1, x2, y2;
x1 = gadgetp->LeftEdge + 3;
y1 = gadgetp->TopEdge + 2;
x2 = x1 + (gadgetp->Width - 7) * (percentage/100.0);
y2 = y1 + gadgetp->Height - 5;
RemoveGadget (windowp, gadgetp);
requesterp =
(gadgetp->GadgetType & GTYP_REQGADGET) ?
current_requesterp :
NULL;
rport = (requesterp) ?
requesterp->ReqLayer->rp :
windowp->RPort;
save_apen = rport->FgPen;
SetAPen (rport, (UBYTE) fill_pen);
RectFill (rport, x1, y1, x2, y2);
SetAPen (rport, (UBYTE) save_apen);
AddGList (windowp, gadgetp, -1, 1, requesterp);
refresh_gadget (gadgetp, windowp);
}
}
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 *labeled_radio_button__new
(char *label, char *text, short tcol, short trow)
{
short button_offset = strlen (label) + 2;
struct Gadget *gadgetp = radio_button__new (text, tcol + button_offset,
trow);
gadgetp->GadgetText->NextText = button_text__new (label);
gadgetp->GadgetText->NextText->LeftEdge -= BUTTON_SIDE_EDGE*2 +
strlen (label) * Font_Width;
return gadgetp;
}
struct Gadget *radio_button__new (char *text, short tcol, short trow)
{
struct Gadget *gadgetp;
gadgetp = text_button__new (text, tcol, trow);
gadgetp->SelectRender = button_border__new (BUTTON_WIDTH(strlen (text)),
shadow_pen, shine_pen);
gadgetp->Flags = GFLG_GADGHIMAGE;
gadgetp->Activation &= ~GACT_RELVERIFY;
gadgetp->Activation &= ~TOGGLESELECT;
gadgetp->Activation |= GADGIMMEDIATE;
return gadgetp;
}
struct Gadget *tall_action_button__new (char *text, short tcol, short trow)
{
struct Gadget *gadgetp;
struct Border *borderp;
gadgetp = action_button__new (text, tcol, trow);
/*
* Add extra borders to make button appear taller
*/
if (screen_depth > 1)
{
borderp = (struct Border *) gadgetp->GadgetRender;
borderp->NextBorder->NextBorder = button_border__new
(BUTTON_WIDTH(strlen (text)), shine_pen,
shadow_pen);
borderp = borderp->NextBorder->NextBorder;
borderp->XY[1] += 1;
#if FALSE
borderp->XY[0] += 1;
borderp->XY[2] += 1;
borderp->XY[3] += 1;
borderp->XY[4] += -1;
borderp->XY[5] += 1;
#endif
borderp = borderp->NextBorder;
borderp->XY[0] += 0;
borderp->XY[1] += 1;
borderp->XY[2] += 1;
borderp->XY[3] += 1;
borderp->XY[4] += 1;
borderp->XY[5] += 1;
borderp = (struct Border *) gadgetp->SelectRender;
borderp->NextBorder->NextBorder = button_border__new
(BUTTON_WIDTH(strlen (text)), shadow_pen,
shine_pen);
borderp = borderp->NextBorder->NextBorder;
borderp->XY[1] += 1;
#if FALSE
borderp->XY[0] += 1;
borderp->XY[2] += 1;
borderp->XY[3] += 1;
borderp->XY[4] += -1;
borderp->XY[5] += 1;
#endif
borderp = borderp->NextBorder;
borderp->XY[0] += 0;
borderp->XY[1] += 1;
borderp->XY[2] += 1;
borderp->XY[3] += 1;
borderp->XY[4] += 1;
borderp->XY[5] += 1;
}
return gadgetp;
}
struct Gadget *action_button__new (char *text, short tcol, short trow)
{
struct Gadget *gadgetp;
gadgetp = text_button__new (text, tcol, trow);
if (screen_depth > 1)
{
gadgetp->SelectRender = button_border__new
(BUTTON_WIDTH(strlen (text)), shadow_pen, shine_pen);
gadgetp->Flags = GFLG_GADGHIMAGE;
}
return gadgetp;
}
static 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;
}
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_Width;
gadgetp->TopEdge = first_button_top + trow * BUTTON_SPACING;
gadgetp->Width = BUTTON_WIDTH (length);
gadgetp->Height = BUTTON_HEIGHT;
gadgetp->Activation = GACT_RELVERIFY;
gadgetp->GadgetType = GTYP_BOOLGADGET | gadget_type_mode;
gadgetp->GadgetRender = button_border__new (BUTTON_WIDTH (length),
shine_pen, shadow_pen);
gadgetp->SelectRender = NULL;
gadgetp->Flags = GFLG_GADGHCOMP;
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;
if (fontp)
{
struct StringExtend *string_extendp =
gcalloc (1, sizeof (struct StringExtend), NOTHING_SPECIAL);
string_extendp->Font = fontp;
string_extendp->Pens[0] = text_pen;
string_extendp->Pens[1] = background_pen;
string_extendp->ActivePens[0] = text_pen;
string_extendp->ActivePens[1] = background_pen;
string_info->Extension = string_extendp;
}
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 | gadget_type_mode;
string_gadgetp->Activation |= GADGIMMEDIATE;
if (fontp) string_gadgetp->Flags |= GFLG_STRINGEXTEND;
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_Width + 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_Height;
bottom_xy[2] = container_length * Font_Width;
bottom_xy[3] = Font_Height;
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_Width;
textst->TopEdge = BUTTON_TOP_EDGE + BUTTON_TOP(trow);
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 = FontAp;
/* textst->ITextFont = NULL; This gives screen font, may be prop font */
textst->IText = text;
textst->NextText = NULL;
return textst;
}
void refresh_gadget (struct Gadget *gadgetp, struct Window *windowp)
{
struct Requester *requesterp =
(gadgetp->GadgetType & GTYP_REQGADGET) ?
current_requesterp :
NULL;
RefreshGList (gadgetp, windowp, 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 & GFLG_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 & GFLG_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 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'--though I don't really use
* 'complementing' here anymore--I use explicit colors to be compatible with
* larger numbers of colors).
*
* 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 */
struct Requester *requesterp =
(gadgetp->GadgetType & GTYP_REQGADGET) ?
current_requesterp :
NULL;
if (windowp)
{
/* if (!(gadgetp->Flags & GFLG_SELECTED)) /* pushing my luck too far*/
{
RemoveGadget (windowp, gadgetp);
gadgetp->Flags |= GFLG_SELECTED;
gadgetp->GadgetText->FrontPen = fill_text_pen;
gadgetp->GadgetText->BackPen = fill_pen;
rport = (requesterp) ?
requesterp->ReqLayer->rp :
windowp->RPort;
save_apen = rport->FgPen;
SetAPen (rport, (UBYTE) fill_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, 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 */
struct Requester *requesterp =
(gadgetp->GadgetType & GTYP_REQGADGET) ?
current_requesterp :
NULL;
if (windowp)
{
if (gadgetp->Flags & GFLG_SELECTED)
{
RemoveGadget (windowp, gadgetp);
gadgetp->Flags &= ~GFLG_SELECTED;
gadgetp->GadgetText->FrontPen = text_pen;
gadgetp->GadgetText->BackPen = background_pen;
rport = (requesterp) ?
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, 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 */
struct Requester *requesterp =
(gadgetp->GadgetType & GTYP_REQGADGET) ?
current_requesterp :
NULL;
if (gadgetp->Flags & GFLG_DISABLED) return;
if (!windowp)
{
gadgetp->Flags |= GFLG_DISABLED;
return;
}
RemoveGadget (windowp, gadgetp);
gadgetp->Flags |= GFLG_DISABLED;
rport = (requesterp) ?
requesterp->ReqLayer->rp :
windowp->RPort;
save_apen = rport->FgPen;
if (gadgetp->Flags & GFLG_SELECTED)
{
SetAPen (rport, (UBYTE) fill_pen);
}
else
{
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, requesterp);
refresh_gadget (gadgetp, windowp);
}
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 */
struct Requester *requesterp =
(gadgetp->GadgetType & GTYP_REQGADGET) ?
current_requesterp :
NULL;
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 = (requesterp) ?
requesterp->ReqLayer->rp :
windowp->RPort;
save_apen = rport->FgPen;
if (gadgetp->Flags & GFLG_SELECTED)
{
SetAPen (rport, (UBYTE) fill_pen);
}
else
{
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, requesterp);
refresh_gadget (gadgetp, windowp);
}
void message_gadget__write (struct Gadget *gadgetp, char *message, struct
Window *windowp)
{
struct RastPort *rport;
UBYTE save_apen; /* I preserve this one, dunno if necessary */
struct Requester *requesterp =
(gadgetp->GadgetType & GTYP_REQGADGET) ?
current_requesterp :
NULL;
if (windowp) RemoveGadget (windowp, gadgetp);
if (gadgetp->GadgetText) gfree (gadgetp->GadgetText);
if (!message || !strlen(message))
{
gadgetp->GadgetText = NULL;
}
else
{
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 = (requesterp) ?
requesterp->ReqLayer->rp :
windowp->RPort;
save_apen = rport->FgPen;
SetAPen (rport, (UBYTE) background_pen);
RectFill (rport, x1, y1, x2, y2);
SetAPen (rport, (UBYTE) save_apen);
AddGList (windowp, gadgetp, -1, 1, requesterp);
refresh_gadget (gadgetp, windowp);
}
}
struct Window *window__new (char *title)
{
struct NewWindow new_window; /* parameter structure to create window */
struct Window *windowp = NULL;
short height = WINDOW_HEIGHT (max_rows);
short width = (Max_Columns * Font_Width) +
(2 * (FIRST_WINDOW_BUTTON_LEFT + BUTTON_SIDE_EDGE));
if (Shell_Height < height) Shell_Height = height;
if (Shell_Width < width) Shell_Width = width;
new_window.LeftEdge = WINDOW_LEFT;
new_window.TopEdge = WINDOW_TOP;
new_window.Height = height;
new_window.Width = width;
new_window.DetailPen = 0;
new_window.BlockPen = 1;
new_window.Title = title;
new_window.Flags = SMART_REFRESH | ACTIVATE | WINDOWCLOSE |
WINDOWDRAG | WINDOWDEPTH | NOCAREREFRESH;
new_window.IDCMPFlags = IDCMP_CLOSEWINDOW | IDCMP_GADGETUP |
IDCMP_GADGETDOWN | IDCMP_RAWKEY;
if (Old_Intuition)
{
new_window.Type = WBENCHSCREEN;
}
else
{
new_window.Type = PUBLICSCREEN; /* It's the latest thing */
}
new_window.FirstGadget = next_gadgetp;
new_window.Screen = NULL;
new_window.BitMap = NULL;
new_window.MinWidth = 0;
new_window.MinHeight = 0;
new_window.MaxWidth = 0;
new_window.MaxHeight = 0;
/* Try to open the window. Like the call to OpenLibrary(), if
* the OpenWindow call is successful, it returns a pointer to
* the structure for your new window. If the OpenWindow() call
* fails, it returns a zero.
*/
if ((windowp = (struct Window *) OpenWindow (&new_window)) == NULL )
{
error_message (WINDOW_OPEN_FAILED);
gabort (EXIT_FAILURE);
}
return windowp;
}
struct Requester *requester__new (void)
{
struct Requester *requesterp;
short height = (max_rows * (Font_Height + (2 * BUTTON_TOP_EDGE)))
+ ((max_rows - 1) * BUTTON_TOP_SPACE) +
+ (2 * FIRST_REQUESTER_BUTTON_TOP);
short width = (Max_Columns * Font_Width) +
(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))
{
if (++requester_stack_index >= REQUESTER_STACK_DEPTH)
{
error_message (REQUESTER_STACK_OVERFLOW);
EndRequest (rp, wp);
return FALSE;
}
requester_stack[requester_stack_index] = current_requesterp;
current_requesterp = rp;
return TRUE;
}
return FALSE;
}
void requester__remove (struct Requester *rp, struct Window *wp)
{
current_requesterp = requester_stack[requester_stack_index];
if (requester_stack_index) requester_stack_index--;
EndRequest (rp, wp);
}
BOOLEAN ignore_tooltype (char *tooltype)
{
if (!strncmp (tooltype, "TOOLPRI", 7)) return TRUE;
if (!strncmp (tooltype, "STARTPRI", 8)) return TRUE;
if (!strncmp (tooltype, "DONOTWAIT", 9)) return TRUE;
if (!strncmp (tooltype, "FILETYPE", 8)) return TRUE;
if (!strncmp (tooltype, "DUMMY", 5)) return TRUE;
return FALSE;
}
#endif /* ifdef AMIGA */