home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
200-299
/
ff280.lzh
/
Graph
/
uio.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-11-20
|
37KB
|
1,220 lines
/*
* GRAPH, Version 1.00 - 4 August 1989
*
* Copyright 1989, David Gay. All Rights Reserved.
* This software is freely redistrubatable.
*/
/* User interface routines */
#include <exec/types.h>
#include <exec/interrupts.h>
#include <exec/ports.h>
#include <exec/io.h>
#include <exec/interrupts.h>
#include <devices/input.h>
#include <devices/inputevent.h>
#define INTUITIONPRIVATE
#include <intuition/intuitionbase.h>
#include <intuition/intuition.h>
#include <graphics/text.h>
#include <libraries/diskfont.h>
#include "libraries/arpbase.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <dos.h>
#include <stdarg.h>
#include <ctype.h>
#include "uio.h"
#include "graph.h"
#include "grph.h"
#include "list.h"
#include "object.h"
#include "user/gadgets.h"
#include "tracker.h"
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/diskfont.h>
#define NODOS
#include "proto/arp.h"
#define DEFAVAILSIZE 2048 /* Default space reserved for AvailFonts */
#define ARROW 42 /* Identifier of arrow gadget */
#define CROSS 666 /* Identifer of cross gadget */
struct fnode /* font node */
{
tnode node;
char name[FONTLEN];
};
tlist flist;
extern struct IntuitionBase *IntuitionBase;
/* Default graph window */
static struct NewWindow graph_win = {
0, 0,
640, 200,
-1, -1,
RAWKEY | REFRESHWINDOW | CLOSEWINDOW | MENUPICK | GADGETDOWN | GADGETUP | R
EQCLEAR | REQSET | MOUSEBUTTONS | MOUSEMOVE,
WINDOWSIZING | WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE | SIMPLE_REFRESH | AC
TIVATE,
NULL,
NULL,
"Graph",
NULL,
NULL,
85, 60,
-1, -1,
WBENCHSCREEN
};
/* The two icon images */
static UWORD chip arrow_data[] = {
0x7fff, 0x7fff, 0x601f, 0x603f, 0x607f, 0x607f, 0x603f, 0x661f, 0x6f0f, 0x7
f87, 0x7fc3, 0x7fe3, 0x7fff,
0x0000, 0x0000, 0x1fe0, 0x1fc0, 0x1f80, 0x1f80, 0x1fc0, 0x19e0, 0x10f0, 0x0
078, 0x003c, 0x001c, 0x0000
};
static struct Image arrow_image = {
-1, 0, 16, 13, 2,
arrow_data,
3, 0
};
static struct Gadget arrow = {
NULL,
-18, 18, 15, 13,
GADGHCOMP | GADGIMAGE | GRELRIGHT,
RELVERIFY | RIGHTBORDER | TOGGLESELECT,
BOOLGADGET,
(APTR)&arrow_image, NULL, NULL,
2,
NULL,
ARROW
};
static UWORD chip cross_data[] = {
0x7fff, 0x7f7f, 0x7f7f, 0x7f7f, 0x7f7f, 0x7e3f, 0x4081, 0x7e3f, 0x7f7f, 0x7
f7f, 0x7f7f, 0x7f7f, 0x7fff,
0x0000, 0x0080, 0x0080, 0x0080, 0x0080, 0x01c0, 0x3f7e, 0x01c0, 0x0080, 0x0
080, 0x0080, 0x0080, 0x0000
};
static struct Image cross_image = {
-1, 0, 16, 13, 2,
cross_data,
3, 0
};
static struct Gadget cross = {
NULL,
-18, 36, 15, 13,
GADGHCOMP | GADGIMAGE | GRELRIGHT | SELECTED,
RELVERIFY | RIGHTBORDER | TOGGLESELECT,
BOOLGADGET,
(APTR)&cross_image, NULL, NULL,
1,
NULL,
CROSS
};
static struct Memory *abort_mem; /* for abort requester */
static struct TextAttr alert_attr = { "topaz.font", 8 };
static struct TextFont *alert_font;
static struct Task *me;
static struct MsgPort *inputDevPort; /* for input device */
static struct IOStdReq *inputRequestBlock;
static struct Interrupt handlerStuff;
static int inputOpen;
static long window_sigs; /* Combined sigs of all windows */
static struct TextAttr font = { "topaz.font", 8 }; /* font for menus, requester
s, etc */
static struct Requester *req; /* Current requester */
static int ok; /* Value of last GadgetID */
static short reqdone; /* Req must go away. Don't activate next str g
adget */
static gadgevent *gadgethandler; /* Handler for gadget events */
/* Add .font extension to fname (assumed of size FONTLEN) */
char *addfont(char *fname)
{
return strncat(fname, ".font", FONTLEN - 1 - strlen(fname));
}
/* Removes .font extension if present */
char *remfont(char *fname)
{
int l = strlen(fname);
if (l >= 5 && strcmp(&fname[l - 5], ".font") == 0) fname[l - 5] = '\0';
return fname;
}
/* Make a list of font names, one entry per font. Sizes, etc ignored. */
int make_font_list(void)
{
int ok = FALSE;
char *abuf;
new_list(&flist);
if (abuf = AllocMem(DEFAVAILSIZE, 0L)) /* Alloc default avail buffer */
{
int needs = AvailFonts(abuf, DEFAVAILSIZE, AFF_MEMORY | AFF_DISK);
ok = TRUE;
if (needs != 0) /* Need a bigger buffer */
{
FreeMem(abuf, DEFAVAILSIZE);
if (abuf = AllocMem(DEFAVAILSIZE + needs, 0L))
if (AvailFonts(abuf, DEFAVAILSIZE + needs, AFF_MEMORY | AFF_DIS
K))
ok = FALSE; /* Definite failure */
}
if (ok) /* Construct font list */
{
struct AvailFontsHeader *hdr = (struct AvailFontsHeader *)abuf;
struct AvailFonts *fl = (struct AvailFonts *)(hdr + 1);
int i;
/* Add font entries to sorted list, by name. Duplicate entries remo
ved */
for (i = hdr->afh_NumEntries; i > 0; i--, fl++)
{
struct fnode *scan;
char *name = fl->af_Attr.ta_Name;
int cmp = -1;
remfont(name); /* remove extension */
/* Find insertion position */
for (scan = first(&flist); succ(scan) && (cmp = strcmp(name, sc
an->name)) > 0; scan = succ(scan))
;
if (cmp != 0) /* Not already present, add to list */
{
struct fnode *n = alloc_node(sizeof(struct fnode));
if (!n)
{
ok = FALSE;
break;
}
n->node.ln_Name = n->name;
n->name[FONTLEN - 1] = '\0';
strncpy(n->name, name, FONTLEN - 1);
/* Add at correct position */
insert(&flist, n, scan->node.ln_Pred);
}
}
if (!ok)
{
free_list((list *)&flist, sizeof(struct fnode));
new_list(&flist);
}
}
FreeMem(abuf, DEFAVAILSIZE + needs);
}
if (!ok) nomem(NULL);
return ok;
}
/* Implement mutual exclude seeing Intuition is lazy */
/* (for border gadgets) */
/* ------------------------------------------------- */
static void MutualExclude(struct Gadget *us, struct Gadget *gadg, struct Window
*win)
{
register int i;
register struct Gadget *gp;
register LONG mutex = us->MutualExclude;
UWORD pos;
/* scan gadget list */
for (i = 1, gp = gadg; gp && i != 0; i <<= 1, gp = gp->NextGadget)
if (i & mutex)
{
pos = RemoveGadget(win, gp);
gp->Flags &= ~SELECTED; /* unselect */
AddGadget(win, gp, pos);
}
pos = RemoveGadget(win, us);
us->Flags |= SELECTED;
AddGadget(win, us, pos);
RefreshWindowFrame(win); /* This works for border gadgets */
}
/* Implement mutual exclude seeing Intuition is lazy */
/* (for requester gadgets) */
static void MutEx(struct Gadget *us, struct Requester *req)
{
register int nb = 0, doneus = FALSE;
register struct Gadget *gp, *first = NULL;
register LONG mutex = us->MutualExclude;
UWORD pos;
/* scan gadget list */
for (gp = req->ReqGadget; gp && (mutex != 0 || !doneus); mutex >>= 1, gp =
gp->NextGadget)
{
if ((mutex & 1) || (doneus = gp == us))
{
if (!first) first = gp;
pos = RemoveGList(req->RWindow, gp, 1);
if (gp == us)
gp->Flags |= SELECTED; /* select */
else
gp->Flags &= ~SELECTED; /* unselect */
AddGList(req->RWindow, gp, pos, 1, req);
}
if (first) nb++;
}
if (first) RefreshGList(first, req->RWindow, req, nb);
}
/* Display requester, & handle everything until it goes away */
int DoRequest(struct Requester *r, struct graph *g, gadgevent *handle)
{
r->Flags |= NOISYREQ; /* We want keystrokes */
ok = FALSE;
if (Request(r, g->io.win))
{
/* setup vital info */
gadgethandler = handle;
req = r;
reqdone = FALSE;
while (next_command().command != reqgone) ; /* Wait till it leaves */
req = NULL; /* No req. present */
gadgethandler = NULL;
}
return ok;
}
/* Find first string gadget */
static struct Gadget *NextText(struct Gadget *look)
{
while (look && (look->GadgetType & ~GADGETTYPE) != STRGADGET) look = look->
NextGadget;
return look;
}
/* Default gadget handler, activates string gadgets in sequence & handles
mutual exclude. Will normally be called by custom handlers if they don't
have anything special to do.
Returens the new value of ok */
int std_ghandler(struct Gadget *gg, ULONG class, struct Requester *req, struct
graph *g)
{
if ((gg->GadgetType & ~GADGETTYPE) == STRGADGET && !reqdone) /* Activate ne
xt one */
{
struct Gadget *ng = NextText(gg->NextGadget);
if (!ng) ng = NextText(req->ReqGadget);
if (ng) ActivateGadget(ng, req->RWindow, req);
}
else if (gg->MutualExclude != 0) MutEx(gg, req);
return gg->GadgetID != 0;
}
/* Insert ins in front of into, checking for string overflow
( sizeof(into)=maxlen ) */
static char *strinsert(char *into, char *ins, int maxlen)
{
int delta = strlen(ins);
int start = strlen(into);
int i;
if (start + delta >= maxlen) start = maxlen - delta - 1;
for (i = start - 1; i >= 0; i--) into[i + delta] = into[i];
into[start + delta] = '\0';
memcpy(into, ins, delta);
return into;
}
/* Convert a lock to a path, store in to (maxlen chars long) */
static char *pathstr(char *to, long l, int maxlen)
{
long tl;
int notfirst = FALSE;
struct FileInfoBlock *fib = (struct FileInfoBlock *)AllocMem(sizeof(struct
FileInfoBlock), 0);
if (!fib) return(NULL);
to[0] = '\0';
do {
if (!Examine(l, fib))
{
to = NULL;
goto error;
}
if (fib->fib_DirEntryType > 0) strinsert(to, "/", maxlen);
/* Is this still necessary ? */
if (fib->fib_FileName[0] == '\0') strinsert(to, "RAM", maxlen);
else strinsert(to, fib->fib_FileName, maxlen);
tl = l;
l = ParentDir(l);
if (notfirst) UnLock(tl); /* Release allocated locks */
notfirst = TRUE;
} while (l);
*(strchr(to, '/')) = ':'; /* First name is disk name */
error:
FreeMem((char *)fib, sizeof(struct FileInfoBlock));
return(to);
}
/* Request a file from the user (save in file), return TRUE if OK,
FALSE if cancelled or failed. Currently uses arp file requester. */
int getfile(char *file, char *msg)
{
static char directory[DSIZE + 1];
static struct FileRequester FR;
char filename[FCHARS + 1];
filename[0] = '\0';
FR.fr_Hail = msg;
FR.fr_File = filename;
FR.fr_Dir = directory;
if (FileRequest(&FR))
{
long lock = Lock(directory, SHARED_LOCK);
if (lock)
{
if (!pathstr(file, lock, FILELEN)) /* get dir path */
{
UnLock(lock);
return FALSE;
}
strncat(file, filename, FILELEN - 1 - strlen(file));
UnLock(lock);
return TRUE;
}
else
alert(NULL, "Failed to lock directory", directory);
}
return FALSE;
}
/* Setup an "abort" requester, in graph g with text msg (must be as long as max
message) */
struct Requester *abort_request(struct graph *g, char *msg)
{
int len = strlen(msg);
struct Requester *req;
struct Gadget *gl = NULL;
int height, width;
static struct Gadget text = {
NULL,
10, 10, 1, 1,
GADGHNONE, 0L, BOOLGADGET | REQGADGET
};
/* Construct requester */
height = 8 * 1 + 10 + 12 + 25;
width = 8 * len + 2 * 10;
if (width < 85) width = 85;
text.GadgetText = NULL;
if ((abort_mem = NewMemory()) &&
(req = InitReq(50, 15, width, height, abort_mem)) &&
SetReqBorder(req, 1, abort_mem) &&
AddBox(&gl, TRUE, "Stop!", 0, RELVERIFY, (width - 65) / 2, height - 25,
65, 15, FALSE, abort_mem) &&
AddIntuiText(&text.GadgetText, msg, 0, 0, abort_mem))
{
SetReqGadgets(req, gl);
text.NextGadget = req->ReqGadget;
req->ReqGadget = &text;
if (!Request(req, g->io.win)) req = NULL; /* display req */
}
else
req = NULL;
if (!req) Free(abort_mem);
return req;
}
/* Change abort requester message. msg must not be longer than the first msg */
void set_abort_msg(struct Requester *req, char *msg)
{
req->ReqGadget->GadgetText->IText = msg;
RefreshGList(req->ReqGadget, req->RWindow, req, 1);
}
/* Clear abort requester */
void end_abort_request(struct Requester *req)
{
EndRequest(req, req->RWindow);
Free(abort_mem);
}
/* Has the user asked for an abort ? */
int aborted(struct Requester *req)
{
int abort = FALSE;
struct IntuiMessage *msg;
while (msg = (struct IntuiMessage *)GetMsg(req->RWindow->UserPort))
{
ULONG class = msg->Class;
ReplyMsg((struct Message *)msg);
if (class == REFRESHWINDOW) /* Ignore refreshes at this time */
{
BeginRefresh(req->RWindow);
EndRefresh(req->RWindow, TRUE);
}
else if (class == GADGETUP) abort = TRUE;
}
return abort;
}
/* Display a message in graph g. You pass as many string as you want, followed
by (char *)NULL. This will try very hard to actually display it, calling
alert with the first two strings if it fails. */
void message(struct graph *g, ...)
{
int nb, len;
va_list msgs;
char *scan;
struct Memory *m;
struct Requester *req;
struct Gadget *gl = NULL;
int height, width;
int ok = FALSE;
/* Find number of lines and maxmimum length */
nb = 0; len = 0;
va_start(msgs, g);
while (scan = va_arg(msgs, char *))
{
int nl = strlen(scan);
nb++;
if (nl > len) len = nl;
}
va_end(msgs);
/* Construct requester */
height = 8 * nb + 10 + 12 + 25;
width = 8 * len + 2 * 10;
if (width < 85) width = 85;
if ((m = NewMemory()) &&
(req = InitReq(50, 15, width, height, m)) &&
SetReqBorder(req, 1, m) &&
AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, (width - 65) / 2, hei
ght - 25, 65, 15, FALSE, m))
{
int y = 10 - 8;
ok = TRUE;
SetReqGadgets(req, gl);
/* Add message strings */
va_start(msgs, g);
while (ok && (scan = va_arg(msgs, char *)))
ok = ok && AddIntuiText(&req->ReqText, scan, 10, (y += 8), m);
va_end(msgs);
/* You'll have a surprise if you press Amiga-B ... */
if (ok && g) ok = DoRequest(req, g, std_ghandler);
}
Free(m);
if (!ok || !g) /* call alert */
{
va_start(msgs, g);
if (nb == 1)
alert(g ? g->io.win : NULL, va_arg(msgs, char *), NULL);
else if (nb >= 2)
{
char *m1 = va_arg(msgs, char *);
char *m2 = va_arg(msgs, char *);
alert(g ? g->io.win : NULL, m1, m2);
}
}
}
/* Display a two line auto request. Doesn't alloc any resources */
void alert(struct Window *win, char *msg1, char *msg2)
{
struct IntuiText text1, text2, negative;
const static struct IntuiText template = {
0, 1, JAM1,
8, 0,
&alert_attr
};
int width, height;
int ysize = alert_font ? alert_font->tf_YSize : 8;
text1 = text2 = negative = template;
text1.TopEdge = 8;
text1.IText = msg1;
width = IntuiTextLength(&text1) + 20;
height = 37 + 2 * ysize;
if (msg2 != NULL)
{
int w;
text1.NextText = &text2;
text2.TopEdge = text1.TopEdge + ysize;
text2.IText = msg2;
height += ysize;
w = IntuiTextLength(&text2) + 20;
if (w > width) width = w;
}
negative.LeftEdge = 6;
negative.TopEdge = 4;
negative.IText = "Ok";
AutoRequest(win, &text1, NULL, &negative, 0L, 0L, width, height);
}
/* Easy no mem requester */
void nomem(struct Window *win)
{
alert(win, "No memory !", NULL);
}
/* Return next menu selection that is a command (in graph g).
*choice is the item number of the next menu selection */
static struct cmd process(UWORD *choice, struct graph *g)
{
struct MenuItem *item;
UWORD itemnb, subnb;
struct cmd cmd;
struct pos *rect = (struct pos *)g->s.current;
/* Prepare command */
cmd.command = none;
cmd.g = g;
/* Try & find a command */
while (cmd.command == none && *choice != MENUNULL)
{
item = ItemAddress(g->io.menu, *choice);
itemnb = ITEMNUM(*choice);
subnb = SUBNUM(*choice);
/* Rem: illegal choices are disabled ==> no checking here */
switch (MENUNUM(*choice)) {
case 0 : switch (itemnb) { /* Project */
case 0 : /* New Graph */
cmd.command = _new_graph;
break;
case 1 : /* Delete Graph */
cmd.command = close;
break;
case 2 : /* Load Graph */
cmd.command = _load_graph;
break;
case 3 : /* Save Graph */
cmd.command = _save_graph;
break;
case 4 : /* Output Graph */
switch (subnb)
{
case 0 : /* To Printer */
cmd.command = print_graph;
break;
case 1 : /* To Disk */
cmd.command = iff_graph;
break;
}
break;
case 6 : /* Load Variables */
cmd.command = load_vars;
break;
case 7 : /* Save Variables */
cmd.command = save_vars;
break;
case 9 : /* Quit */
cmd.command = quit;
break;
} break;
case 1 : switch (itemnb) { /* Graph */
case 0 : /* Scale */
deselect(g);
cmd.command = limits;
break;
case 1 : /* Axes */
deselect(g);
cmd.command = axes;
break;
case 2 : /* Zoom */
cmd.command = zoom;
cmd.data.zoom_in.x0 = rect->x0;
cmd.data.zoom_in.y0 = rect->y0;
cmd.data.zoom_in.x1 = rect->x1;
cmd.data.zoom_in.y1 = rect->y1;
deselect(g);
break;
case 3 : /* Zoom Out */
cmd.command = zoom_out;
cmd.data.zoom_out = 2.0;
break;
case 4 : /* Center */
cmd.command = center;
cmd.data.pt.x = rect->x0;
cmd.data.pt.y = rect->y0;
deselect(g);
break;
} break;
case 2 : switch (itemnb) { /* Add */
case 0 : /* Function */
deselect(g);
cmd.command = add_function;
break;
case 1 : /* Label */
cmd.command = add_label;
cmd.data.pt.x = rect->x0;
cmd.data.pt.y = rect->y0;
deselect(g);
break;
} break;
case 3 : switch (itemnb) { /* Edit */
case 0 : /* Variables */
cmd.command = edit_vars;
break;
case 2 : /* Select function */
{ /* Processed locally */
struct object *o;
if (o = choose_object(g, "Select"))
{
deselect(g);
select_object(g, o);
}
}
break;
case 3 : /* Deselect */
/* Processed locally */
deselect(g);
break;
case 5 : /* Edit */
cmd.data.o = g->s.current;
cmd.command = edit;
break;
case 6 : /* Improve */
cmd.data.f = g->s.current;
cmd.command = improve;
break;
case 7 : /* Delete */
cmd.data.o = g->s.current;
cmd.command = del_object;
break;
} break;
}
*choice = item->NextSelect;
*choice = MENUNULL;
}
return cmd;
}
/* Return next command (in any graph) */
struct cmd next_command(void)
{
struct cmd cmd;
static int gone = FALSE;
cmd.command = none;
while (cmd.command == none) /* Wait for one */
{
struct graph *g;
/* Scan all graphs, checking for commands */
for (g = first(&graph_list); cmd.command == none && succ(g); g = succ(g
))
{
int moved = FALSE;
struct IntuiMessage *msg;
WORD sx, sy;
cmd.g = g;
/* Any pending menu selections ? */
if (!req && g->io.nextmenu != MENUNULL) cmd = process(&g->io.nextme
nu, g);
/* Check for messages on window */
while (cmd.command == none && (msg = (struct IntuiMessage *)GetMsg(
g->io.win->UserPort)))
{
/* Save interesting info */
ULONG class = msg->Class;
UWORD code = msg->Code;
UWORD qualifier = msg->Qualifier;
struct Gadget *gg = (struct Gadget *)msg->IAddress, *gadg;
sx = msg->MouseX; sy = msg->MouseY;
ReplyMsg((struct Message *)msg);
if (class == MOUSEMOVE) /* Accumulate moves */
moved = TRUE;
else
{
if (moved) mouse_move(g, sx, sy); /* process any mouse move
ment */
moved = FALSE;
/* Most messages imply that the mouse button is released. M
ake sure that the program thinks so */
if (class != MOUSEBUTTONS && class != REFRESHWINDOW) mouse_
up(g, sx, sy);
switch (class)
{
/* Note that most messages are ignored while a
requester is up in *any* window */
case RAWKEY:
/* Check for Amiga-V/B (Ok, Cancel shortcut) */
if (req && (qualifier & AMIGALEFT) && (code == KEYC
ODE_V || code == KEYCODE_B))
{
ok = code == KEYCODE_V;
/* Never let this happen while a string gadget
is active ... */
EndRequest(req, req->RWindow);
}
break;
case CLOSEWINDOW:
if (!req) cmd.command = close;
break;
case MENUPICK:
if (!req)
{
g->io.nextmenu = code;
cmd = process(&g->io.nextmenu, g);
}
break;
case REFRESHWINDOW:
{
int changed;
/* Refresh partially only if size hasn't change
d */
BeginRefresh(g->io.win);
changed = g->io.win->Width != g->io.oldwidth ||
g->io.win->Height != g->io.oldheight;
if (!changed) draw_graph(g, FALSE); /* No messa
ges during refresh !!! */
EndRefresh(g->io.win, TRUE);
if (changed)
{
set_scale(g);
draw_graph(g, TRUE);
}
/* Wait for refresh after requester's disappear
ance
before signaling it */
if (gone)
{
gone = FALSE;
cmd.command = reqgone;
}
}
break;
case REQSET: /* Activate first string gadget */
gadg = NextText(req->ReqGadget);
if (gadg && !reqdone) ActivateGadget(gadg, g->io.wi
n, req);
break;
case REQCLEAR:
/* Allow 1 refresh before signaling this. There is
probably a better way ! */
gone = TRUE;
break;
case GADGETUP: case GADGETDOWN:
/* Ack! Hack to avoid bug in string gadget activati
on (V1.2-1.3) */
if (class == GADGETUP && (gg->GadgetType & STRGADGE
T) != 0 && IntuitionBase->LibNode.lib_Version <= 34) IntuitionBase->ActiveGadget
= NULL;
/* Handle requester hgadgets */
if (gadgethandler) ok = gadgethandler(gg, class, re
q, g);
else if (gg->GadgetID == ARROW || gg->GadgetID == C
ROSS)
{ /* Select new mode */
MutualExclude(gg, g->io.gadgets, g->io.win);
set_mode(g, gg->GadgetID == ARROW);
}
break;
case MOUSEBUTTONS: /* Pass on to graph */
if (code == SELECTDOWN)
mouse_down(g, sx, sy);
else
mouse_up(g, sx, sy);
break;
}
}
}
/* Handle any pending moves */
if (moved) mouse_move(g, sx, sy);
}
/* Wait for something to happen */
if (cmd.command == none) Wait(window_sigs);
}
return cmd;
}
/* Enable/Disable various menus */
void disable_rect_menus(struct graph *g)
{
struct Window *win = g->io.win;
OffMenu(win, SHIFTMENU(1) | SHIFTITEM(2) | SHIFTSUB(NOSUB)); /* Zoom */
OffMenu(win, SHIFTMENU(1) | SHIFTITEM(4) | SHIFTSUB(NOSUB)); /* Center */
OffMenu(win, SHIFTMENU(2) | SHIFTITEM(1) | SHIFTSUB(NOSUB)); /* Label */
OffMenu(win, SHIFTMENU(3) | SHIFTITEM(3) | SHIFTSUB(NOSUB)); /* Deselect */
}
void enable_rect_menus(struct graph *g)
{
struct Window *win = g->io.win;
OnMenu(win, SHIFTMENU(1) | SHIFTITEM(2) | SHIFTSUB(NOSUB)); /* Zoom */
OnMenu(win, SHIFTMENU(1) | SHIFTITEM(4) | SHIFTSUB(NOSUB)); /* Center */
OnMenu(win, SHIFTMENU(2) | SHIFTITEM(1) | SHIFTSUB(NOSUB)); /* Label */
OnMenu(win, SHIFTMENU(3) | SHIFTITEM(3) | SHIFTSUB(NOSUB)); /* Deselect */
}
void disable_object_menus(struct graph *g)
{
struct Window *win = g->io.win;
OffMenu(win, SHIFTMENU(3) | SHIFTITEM(3) | SHIFTSUB(NOSUB)); /* Deselect */
OffMenu(win, SHIFTMENU(3) | SHIFTITEM(5) | SHIFTSUB(NOSUB)); /* Edit */
OffMenu(win, SHIFTMENU(3) | SHIFTITEM(6) | SHIFTSUB(NOSUB)); /* Improve */
OffMenu(win, SHIFTMENU(3) | SHIFTITEM(7) | SHIFTSUB(NOSUB)); /* Delete */
}
void enable_object_menus(struct graph *g)
{
struct Window *win = g->io.win;
OnMenu(win, SHIFTMENU(3) | SHIFTITEM(3) | SHIFTSUB(NOSUB)); /* Deselect */
OnMenu(win, SHIFTMENU(3) | SHIFTITEM(5) | SHIFTSUB(NOSUB)); /* Edit */
OnMenu(win, SHIFTMENU(3) | SHIFTITEM(6) | SHIFTSUB(NOSUB)); /* Improve */
OnMenu(win, SHIFTMENU(3) | SHIFTITEM(7) | SHIFTSUB(NOSUB)); /* Delete */
}
/* Convert double to nice string (must be of size NBLEN) */
char *double2str(char *to, double x)
{
int l;
if (x == NOVAL) to[0] = '\0';
else sprintf(to, "%-5.3g", x);
l = strlen(to);
while (l > 0 && to[--l] == ' ') to[l] = '\0';
return to;
}
/* Convert string to double */
double str2double(char *from)
{
double x;
if (sscanf(from, "%lf", &x) != 1) x = NOVAL;
return x;
}
/* convert x to a string (must be of size INTLEN) */
char *int2str(char *to, int x)
{
if (x == INOVAL) to[0] = '\0';
else sprintf(to, "%d", x);
return to;
}
/* convert string to integer */
int str2int(char *from)
{
int x;
if (sscanf(from, "%d", &x) != 1) x = INOVAL;
return x;
}
/* Removes leading & trailing blanks fron name. Returns name */
char *strip(char *name)
{
char *scan = name;
while (isspace(*scan)) scan++;
if (*scan)
{
char *copy = name;
while (*scan) *(copy++) = *(scan++);
while (isspace(*--copy))
;
*(copy + 1) = '\0';
}
else
*name = '\0';
return name;
}
/* Hack to allow you to press Amiga-V/B even while entering a string in a
string requester */
static long __saveds __asm handle_ok_cancel(register __a0 struct InputEvent *ev
, register __a1 void *dummy)
{
struct InputEvent *ep, *laste;
static struct InputEvent retkey;
if (req)
/* run down the list of events to see if they pressed the magic key */
for (ep = ev, laste = NULL; ep != NULL; ep = ep->ie_NextEvent)
{
if (ep->ie_Class == IECLASS_RAWKEY && (ep->ie_Qualifier & AMIGALEFT
) && (ep->ie_Code == KEYCODE_V || ep->ie_Code == KEYCODE_B) && IntuitionBase->Ac
tiveWindow == req->RWindow)
{
reqdone = TRUE; /* The requester is going away */
/* Add an extra "return key" event */
retkey.ie_Class = IECLASS_RAWKEY;
retkey.ie_SubClass = 0;
retkey.ie_Code = 0x44; /* return key */
retkey.ie_Qualifier = 0;
retkey.ie_position = ep->ie_position;
retkey.ie_TimeStamp = ep->ie_TimeStamp;
retkey.ie_NextEvent = ep;
/* we can handle this event so take it off the chain */
if (laste == NULL)
ev = &retkey;
else
laste->ie_NextEvent = &retkey;
break;
}
else
laste = ep;
}
/* pass on the pointer to the event */
return (long)ev;
}
/* Create window, menus for a new graph */
int init_uio(struct graph *g)
{
/* Create mode select gadgets */
struct Gadget *a = AllocMem(sizeof(struct Gadget), 0L);
struct Gadget *c = AllocMem(sizeof(struct Gadget), 0L);
ModSys(0, 1, JAM2, &font);
if (a && c)
{
struct Menu *ml = NULL, *project, *edit, *add, *graph;
struct MenuItem *print;
*a = arrow;
*c = cross;
a->NextGadget = c;
g->io.gadgets = graph_win.FirstGadget = a;
g->io.mem = NULL;
/* Create window & menus */
if (g->io.win = OpenWindow(&graph_win))
if ((g->io.mem = NewMemory()) &&
(project = AddMenu(&ml, NULL, "Project", MENUENABLED, g->io.mem
)) &&
AddItem(project, "New Graph", ITEMENABLED | HIGHCOMP, 0, 'N
', FALSE, g->io.mem) &&
AddItem(project, "Delete Graph", ITEMENABLED | HIGHCOMP, 0,
0, FALSE, g->io.mem) &&
AddItem(project, "Load Graph...", ITEMENABLED | HIGHCOMP, 0
, 'O', FALSE, g->io.mem) &&
AddItem(project, "Save Graph...", ITEMENABLED | HIGHCOMP, 0
, 'S', FALSE, g->io.mem) &&
(print = AddItem(project, "Output Graph", ITEMENABLED | HIG
HCOMP, 0, 0, TRUE, g->io.mem)) &&
AddSub(print, "To Printer", ITEMENABLED | HIGHCOMP, 0,
'P', g->io.mem) &&
AddSub(print, "To Disk...", ITEMENABLED | HIGHCOMP, 0,
0, g->io.mem) &&
AddRule(project, g->io.mem) &&
AddItem(project, "Load Variables...", ITEMENABLED | HIGHCOM
P, 0, 0, FALSE, g->io.mem) &&
AddItem(project, "Save Variables...", ITEMENABLED | HIGHCOM
P, 0, 0, FALSE, g->io.mem) &&
AddRule(project, g->io.mem) &&
AddItem(project, "Quit", ITEMENABLED | HIGHCOMP, 0, 'Q', FA
LSE, g->io.mem) &&
(graph = AddMenu(&ml, NULL, "Graph", MENUENABLED, g->io.mem)) &
&
AddItem(graph, "Scale...", ITEMENABLED | HIGHCOMP, 0, 'L',
FALSE, g->io.mem) &&
AddItem(graph, "Axes...", ITEMENABLED | HIGHCOMP, 0, 'X', F
ALSE, g->io.mem) &&
AddItem(graph, "Zoom", ITEMENABLED | HIGHCOMP, 0, 'Z', FALS
E, g->io.mem) &&
AddItem(graph, "Zoom out", ITEMENABLED | HIGHCOMP, 0, 0, FA
LSE, g->io.mem) &&
AddItem(graph, "Centre", ITEMENABLED | HIGHCOMP, 0, 'C', FA
LSE, g->io.mem) &&
(add = AddMenu(&ml, NULL, "Add", MENUENABLED, g->io.mem)) &&
AddItem(add, "Function...", ITEMENABLED | HIGHCOMP, 0, 'F',
FALSE, g->io.mem) &&
AddItem(add, "Label...", ITEMENABLED | HIGHCOMP, 0, 0, FALS
E, g->io.mem) &&
(edit = AddMenu(&ml, NULL, "Edit", MENUENABLED, g->io.mem)) &&
AddItem(edit, "Variables...", ITEMENABLED | HIGHCOMP, 0, 'V
', FALSE, g->io.mem) &&
AddRule(edit, g->io.mem) &&
AddItem(edit, "Select function...", ITEMENABLED | HIGHCOMP,
0, 0, FALSE, g->io.mem) &&
AddItem(edit, "Deselect", ITEMENABLED | HIGHCOMP, 0, 0, FAL
SE, g->io.mem) &&
AddRule(edit, g->io.mem) &&
AddItem(edit, "Edit...", ITEMENABLED | HIGHCOMP, 0, 'E', FA
LSE, g->io.mem) &&
AddItem(edit, "Improve", ITEMENABLED | HIGHCOMP, 0, 'I', FA
LSE, g->io.mem) &&
AddItem(edit, "Delete", ITEMENABLED | HIGHCOMP, 0, 0, FALSE
, g->io.mem))
{
SetMenuStrip(g->io.win, ml);
g->io.menu = ml;
disable_rect_menus(g);
disable_object_menus(g);
/* Add signal bit */
window_sigs |= 1 << g->io.win->UserPort->mp_SigBit;
return TRUE; /* all done ok */
}
else
{
Free(g->io.mem);
CloseWindow(g->io.win);
alert(NULL, "No memory !", NULL);
}
else alert(NULL, "Couldn't open window", NULL);
}
else
alert(NULL, "No memory !", NULL);
if (a) FreeMem(a, sizeof(struct Gadget));
if (c) FreeMem(c, sizeof(struct Gadget));
return FALSE;
}
/* Close window, etc */
void cleanup_uio(struct graph *g)
{
struct Gadget *gg, *next;
ClearMenuStrip(g->io.win);
CloseWindow(g->io.win);
Free(g->io.mem);
for (gg = g->io.gadgets; gg; gg = next)
{
next = gg->NextGadget;
FreeMem(gg, sizeof(struct Gadget));
}
/* Construct new signal list */
window_sigs = 0;
for (g = first(&graph_list); succ(g); g = succ(g))
window_sigs |= 1 << g->io.win->UserPort->mp_SigBit;
}
/* Global initialisation */
int init_user()
{
if (!make_font_list()) return FALSE;
/* Open alert font */
alert_font = OpenFont(&alert_attr);
/* Install input handler */
me = FindTask(0);
inputDevPort = CreatePort(0,0);
if (inputDevPort)
{
if (inputRequestBlock = CreateStdIO(inputDevPort))
{
handlerStuff.is_Data = NULL;
handlerStuff.is_Code = (void *)handle_ok_cancel;
handlerStuff.is_Node.ln_Pri = 51;
if (OpenDevice("input.device", 0, inputRequestBlock, 0) == 0)
{
inputOpen = TRUE;
inputRequestBlock->io_Command = IND_ADDHANDLER;
inputRequestBlock->io_Data = (APTR)&handlerStuff;
DoIO(inputRequestBlock);
return TRUE;
}
}
}
alert(NULL, "Couldn't install input handler", NULL);
return FALSE;
}
/* Global cleanup */
void cleanup_user()
{
if (inputOpen)
{
inputRequestBlock->io_Command = IND_REMHANDLER;
inputRequestBlock->io_Data = (APTR)&handlerStuff;
DoIO(inputRequestBlock);
CloseDevice(inputRequestBlock);
}
if (inputRequestBlock) DeleteStdIO(inputRequestBlock);
if (inputDevPort) DeletePort(inputDevPort);
free_list((list *)&flist, sizeof(struct fnode));
}