[comp.sources.amiga] v89i208: graph - plot mathematical functions, Part05/07

page%swap@Sun.COM (Bob Page) (11/13/89)

Submitted-by: dg3i+@andrew.cmu.edu (David Gay)
Posting-number: Volume 89, Issue 208
Archive-name: applications/graph.5

# This is a shell archive.
# Remove anything above and including the cut line.
# Then run the rest of the file through 'sh'.
# Unpacked files will be owned by you and have default permissions.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: SHell ARchive
# Run the following text through 'sh' to create:
#	grph.h
#	label.c
#	list.c
#	list.h
#	lmkfile
#	lmko
#	lnk
#	lnko
#	make.shar
#	mv2dir
# This is archive 5 of a 7-part kit.
# This archive created: Sun Nov 12 18:23:31 1989
echo "extracting grph.h"
sed 's/^X//' << \SHAR_EOF > grph.h
X/*
X *                 GRAPH, Version 1.00 - 4 August 1989
X *
X *            Copyright 1989, David Gay. All Rights Reserved.
X *            This software is freely redistrubatable.
X */
X
X/* Routines for handling graphs */
X#ifndef GRPH_H
X#define GRPH_H
X
X#include "list.h"
X#include "user/gadgets.h"
X
X/* Various string lengths */
X#define TITLELEN 80
X#define GNAMELEN 20
X
X/* Store information on each axis */
Xstruct ax {
X    double min, max;
X    double ax, cstep; /* Axes positions, ax is the position of this axis on the
X other */
X                      /* cstep: interval for ticks */
X    int every;        /* Frequency of numbering on ticks */
X    int log;          /* log scale ? */
X};
X
X/* Information on coordinate system */
Xstruct axes {
X    struct ax x, y;
X    double ratio; /* y / x, NOVAL for none (>0 !!) */
X    int polar : 1; /* Not used */
X    int ok : 1;
X};
X
X/* User interface state */
Xstruct state {
X    int select_mode : 1;
X    int mouse : 1;          /* mouse moves expected */
X    double x, y;            /* mouse pos. */
X    struct object *current;
X};
X
X/* All information needed for user interface */
Xstruct io {
X    UWORD nextmenu;            /* For menu selections */
X    struct RWindow *rw;        /* Currently selected output */
X    int dpmx, dpmy;            /* Scale (in dots per meter) of output */
X    struct Window *win;        /* Window, and assoc. info */
X    WORD oldwidth, oldheight;
X    struct Gadget *gadgets;
X    struct Menu *menu;
X    struct Memory *mem;
X    char title[TITLELEN];
X    struct TextFont *digits;   /* Font for displaying digits on graph */
X};
X
X/* A graph, made up from the above components */
X
Xstruct graph {
X    node node;
X    int ok : 1;
X    int saved : 1;
X    char name[GNAMELEN];
X    struct io io;
X    list o_list;  /* List of objects in graph */
X    struct axes a;
X    struct state s;
X};
X
X/* Open font name, in pts points (use graph scale). Takes nearest size */
Xstruct TextFont *open_font(struct graph *g, char *name, int pts, int style, int
X flags);
X/* Convert size in inches to dots in selected output */
Xint xinch2dots(struct graph *g, double x);
Xint yinch2dots(struct graph *g, double y);
X
X/* objects */
Xstruct object *add_object(struct graph *g, struct object *o);
Xvoid remove_object(struct graph *g, struct object *o);
Xvoid select_object(struct graph *g, struct object *o);
Xvoid deselect(struct graph *g);
X
X/* User has used mouse, do any necessary housekeeping (move, select objects, et
Xc) */
Xvoid mouse_down(struct graph *g, WORD sx, WORD sy);
Xvoid mouse_move(struct graph *g, WORD sx, WORD sy);
Xvoid mouse_up(struct graph *g, WORD sx, WORD sy);
X
X/* Ask user to : */
Xstruct object *choose_object(struct graph *g, char *op); /* Select object by na
Xme */
Xvoid enter_limits(struct graph *g); /* Define coord system */
Xvoid enter_axes(struct graph *g);   /* Choose axes display options */
X
X/* Change graph: */
Xint set_dpm(struct graph *g, int dpmx, int dpmy); /* set new scale (in dpm) */
Xvoid set_thin(struct graph *g, struct RastPort *rp); /* Use thin lines */
Xvoid set_pensize(struct graph *g, struct RastPort *rp, double ptsize); /* Use l
Xines ptsize points wide */
Xvoid set_mode(struct graph *g, int newmode); /* Select select/point mode */
Xvoid set_scale(struct graph *g);      /* Window size has changed */
Xvoid zoom_in(struct graph *g, double x0, double y0, double x1, double y1); /* S
Xet new coord limits */
Xvoid zoom_factor(struct graph *g, double factor); /* Zoom in by a factor */
Xvoid center_graph(struct graph *g, double x, double y); /* Recenter around poin
Xt */
X
X/* Output routines: */
Xvoid draw_graph(struct graph *g, int allow_mes); /* Draw graph */
Xvoid refresh_graph(struct graph *g, int allow_mes, struct Region *ref); /* Redr
Xaw inside region ref only */
Xstruct Region *full_refresh(struct graph *g); /* Return a region covering the w
Xhole graph */
Xvoid set_title(struct graph *g);   /* Change graph title */
Xvoid prt_graph(struct graph *g);   /* Output graph to printer */
Xvoid iff_todisk(struct graph *g);  /* Output graph as an ILBM file */
X
X/* Manipulate graphs : */
Xstruct graph *load_graph(struct graph *from, FILE *f);
Xint save_graph(struct graph *g, FILE *f);
Xstruct graph *new_graph(struct graph *from); /* from allows you to display mess
Xages ... (NULL if none) */
Xvoid delete_graph(struct graph *g);
X
X/* Global init/cleanup. Must be called */
Xint init_grph(void);
Xvoid cleanup_grph(void);
X
X#endif
X
SHAR_EOF
echo "extracting label.c"
sed 's/^X//' << \SHAR_EOF > label.c
X/*
X *                 GRAPH, Version 1.00 - 4 August 1989
X *
X *            Copyright 1989, David Gay. All Rights Reserved.
X *            This software is freely redistrubatable.
X */
X
X#include <exec/types.h>
X#include <intuition/intuition.h>
X#include <graphics/text.h>
X#include <string.h>
X#include <limits.h>
X
X#include "object.h"
X#include "object/default.h"
X#include "file.h"
X#include "graph.h"
X#include "uio.h"
X#include "coords.h"
X#include "grph.h"
X#include "user/gadgets.h"
X#include "graphics.h"
X#include "tracker.h"
X
X#include <proto/exec.h>
X#include <proto/intuition.h>
X#include <proto/graphics.h>
X
X#define LABELLEN 256
X#define LABELHEIGHT 10
X#define LABELFONT "topaz.font"
X#define FONTLIST 2
X
X/* The various justification possibilities */
Xenum justify { top, centre, bottom };
X
X/* (private) class label, inherits from object */
Xstruct label
X{
X    struct object o;
X    char text[LABELLEN]; /* What to display, \ for newlines */
X    BYTE colour;
X    char fname[FONTLEN]; /* font name */
X    int fheight;         /* font height */
X    double x, y;         /* text position */
X    double dx, dy;       /* offset from position, in inches */
X    enum justify jx, jy; /* justification (x & y axes) */
X
X    char selected;
X    /* Temp, etc vars */
X    char broken[LABELLEN];   /* Text, separated into lines (separated by NULLs)
X */
X    int nblines;             /* number of lines */
X    struct Rectangle extent; /* Size of rectangle taken by text */
X    int bw, bh;              /* Size of bitmap (for moving) */
X    struct Rectangle lims;   /* Rectangle taken up on screen */
X    int x0, y0;              /* x & y in screen coords (wthout ddx, ddy) */
X    struct TextFont *font, *newfont; /* the font (newfont for inform/confirm) *
X/
X    double oldx, oldy;       /* position before move */
X    int ddx, ddy;            /* dx, dy in pixels */
X    struct Region *ref;
X    struct RastPort bkgd;    /* Rastport & bitmap for moves */
X    struct BitMap bkgd_bm;
X};
X
X/*-------------------------------------------------------------------------*/
X/*                       label class implementation                        */
X/*-------------------------------------------------------------------------*/
X
X/* Allocates bitmap for saving background while moving */
X/* Assumes 2 bit planes */
Xstatic int alloc_bkgd_label(struct label *this)
X{
X    BYTE *data;
X
X    if (data = AllocMem(2 * RASSIZE(this->bw, this->bh), MEMF_CHIP))
X    {
X        InitBitMap(&this->bkgd_bm, 2, this->bw, this->bh);
X        this->bkgd_bm.Planes[0] = (PLANEPTR)data;
X        this->bkgd_bm.Planes[1] = (PLANEPTR)(data + RASSIZE(this->bw, this->bh)
X);
X        InitRastPort(&this->bkgd);
X        this->bkgd.BitMap = &this->bkgd_bm;
X    }
X    return data != 0;
X}
X
X/* Frees bitmap alloced above */
Xstatic void free_bkgd_label(struct label *this)
X{
X    FreeMem(this->bkgd_bm.Planes[0], 2 * RASSIZE(this->bw, this->bh));
X}
X
X/* Save scrren background into temp space */
Xstatic void save_bkgd_label(struct label *this)
X{
X    ClipBlit(this->o.g->io.rw->rp, this->lims.MinX, this->lims.MinY, &this->bkg
Xd, 0, 0, this->bw, this->bh, 0xc0);
X}
X
X/* Copies saved background back to the screen */
Xstatic void restore_bkgd_label(struct label *this)
X{
X    ClipBlit(&this->bkgd, 0, 0, this->o.g->io.rw->rp, this->lims.MinX, this->li
Xms.MinY, this->bw, this->bh, 0xc0);
X}
X
X/* Do all the precalculations */
Xstatic void setup_label(struct label *this)
X{
X    struct TextFont *font = this->font;
X    char *srch, *nl;
X
X    this->ddx = xinch2dots(this->o.g, this->dx);
X    this->ddy = yinch2dots(this->o.g, this->dy);
X
X    /* Break up label & calculate rectangle used */
X    srch = strcpy(this->broken, this->text);
X    this->nblines = 0;
X    this->extent.MaxX = 0;
X    this->extent.MinX = INT_MAX;
X    do
X    {
X        struct TextExtent te;
X
X        nl = strchr(srch, '\\');
X
X        if (nl && *(nl + 1) == '\\') /* add single slash */
X            movmem(nl + 1, nl, LABELLEN - (nl - this->broken) - 1);
X        else
X        {
X            this->nblines++;
X            if (nl) *nl = '\0';
X            /* Check space for this line */
X            TextExtent(srch, font, &te);
X            if (te.te_Extent.MaxX > this->extent.MaxX) this->extent.MaxX = te.t
Xe_Extent.MaxX;
X            if (te.te_Extent.MinX < this->extent.MinX) this->extent.MinX = te.t
Xe_Extent.MinX;
X        }
X        srch = nl + 1;
X    } while (nl);
X
X    this->extent.MinY = 0;
X    this->extent.MaxY = this->nblines * font->tf_YSize;
X    this->bw = this->extent.MaxX - this->extent.MinX + 1;
X    this->bh = this->extent.MaxY - this->extent.MinY + 1;
X}
X
X/* Work out rectangle used by text */
Xstatic void calc_rect(struct label *this)
X{
X    struct graph *g = this->o.g;
X    struct RWindow *rw = g->io.rw;
X    int delta, x0, y0;
X
X    /* Find origin */
X    /* Default */
X    x0 = (this->x0 = ftol(rw->sx(rw, this->x))) + this->ddx;
X    y0 = (this->y0 = ftol(rw->sy(rw, this->y))) + this->ddy;
X
X    /* Adjust for justification */
X    switch (this->jx)
X    {
X        case centre:
X            x0 -= this->bw / 2;
X            break;
X        case bottom: /* right */
X            x0 -= this->bw;
X            break;
X    }
X    switch (this->jy)
X    {
X        case centre:
X            y0 -= this->bh / 2;
X            break;
X        case bottom: /* right */
X            y0 -= this->bh;
X            break;
X    }
X    /* Extent defines actual rectangle */
X    this->lims.MinX = x0 + this->extent.MinX;
X    this->lims.MaxX = x0 + this->extent.MaxX;
X    this->lims.MinY = y0 + this->extent.MinY;
X    this->lims.MaxY = y0 + this->extent.MaxY;
X
X    /* Make sure that it stays visible */
X    /* Could one reduce the number of flops ? */
X    /* Idea: Generalise inform/confirm */
X    if ((delta = ftol(rw->sx(rw, g->a.x.min)) - this->lims.MinX) > 0 ||
X        (delta = ftol(rw->sx(rw, g->a.x.max)) - this->lims.MaxX) < 0)
X    {
X        this->x0 += delta;
X        this->lims.MinX += delta;
X        this->lims.MaxX += delta;
X    }
X    if ((delta = ftol(rw->sy(rw, g->a.y.max)) - this->lims.MinY) > 0 ||
X        (delta = ftol(rw->sy(rw, g->a.y.min)) - this->lims.MaxY) < 0)
X    {
X        this->y0 += delta;
X        this->lims.MinY += delta;
X        this->lims.MaxY += delta;
X    }
X}
X
X/* Add the current position to the region */
Xstatic void add_region(struct label *this)
X{
X    if (!this->ref) this->ref = NewRegion();
X    if (this->ref && !OrRectRegion(this->ref, &this->lims))
X    {
X        DisposeRegion(this->ref);
X        this->ref = NULL;
X    }
X    if (!this->ref) nomem(this->o.g->io.win);
X}
X
X/* Were we clicked on ? */
Xstatic int down_label(struct label *this)
X{
X    struct graph *g = this->o.g;
X    WORD sx = ftol(g->io.rw->sx(g->io.rw, g->s.x));
X    WORD sy = ftol(g->io.rw->sy(g->io.rw, g->s.y));
X    int inside;
X
X    calc_rect(this);
X    inside = sx >= this->lims.MinX && sx <= this->lims.MaxX &&
X             sy >= this->lims.MinY && sy <= this->lims.MaxY;
X    if (inside)
X    {
X        /* Setup internal info for move */
X        this->o.mx = sx - this->x0;
X        this->o.my = sy - this->y0;
X        if (alloc_bkgd_label(this))
X        {
X            save_bkgd_label(this);
X            if (this->selected)
X            {
X                SetDrMd(&this->bkgd, COMPLEMENT);
X                RectFill(&this->bkgd, 0, 0, this->bw - 1, this->bh - 1);
X            }
X            this->ref = NULL;
X            add_region(this); /* Original pos. will probably need refreshing */
X     
X            this->oldx = this->x; this->oldy = this->y;
X        }
X        else /* failed, no mem */
X        {
X            nomem(this->o.g->io.win);
X            inside = FALSE;
X        }
X    }
X    return inside;
X}
X
X/* Reverse label's rectangle (eg for selection) */
Xstatic void reverse_label(struct label *this)
X{
X    struct RastPort *rp = this->o.g->io.rw->rp;
X
X    SetDrMd(rp, COMPLEMENT);
X    RectFill(rp, this->lims.MinX, this->lims.MinY, this->lims.MaxX, this->lims.
XMaxY);
X}
X
X/* Draw label */
Xstatic void draw_label(struct label *this, int allow_mes)
X{
X    struct graph *g = this->o.g;
X    struct RastPort *rp = g->io.rw->rp;
X    char *str;
X    int i;
X
X    calc_rect(this);
X    SetAPen(rp, this->colour);
X    SetDrMd(rp, JAM1);
X    SetFont(rp, this->font);
X
X    /* Draw all the lines of text */
X    Move(rp, this->lims.MinX - this->extent.MinX, this->lims.MinY - this->exten
Xt.MinY + this->font->tf_Baseline);
X    for (str = this->broken, i = this->nblines; i; i--)
X    {
X        int l = strlen(str);
X
X        Text(rp, str, l);
X        Move(rp, this->lims.MinX - this->extent.MinX, rp->cp_y + this->font->tf
X_YSize);
X
X        str += l + 1; /* Onto next string */
X    }
X
X    if (this->selected) reverse_label(this);
X}
X
X/* We're now selected */
Xstatic void select_label(struct label *this)
X{
X    this->selected = TRUE;
X    if (this->o.g->ok && this->o.g->io.rw)
X    {
X        calc_rect(this);
X        reverse_label(this);
X    }
X}
X
X/* A quick walk around town ... */
Xstatic void move_label(struct label *this)
X{
X    restore_bkgd_label(this); /* erase label */
X    this->x = this->o.g->s.x;
X    this->y = this->o.g->s.y;
X    calc_rect(this);
X    save_bkgd_label(this);    /* Save background */
X    draw_label(this, TRUE);   /* & draw at new pos */
X}
X
X/* Mouse buttonb released, refresh needed ? */
Xstatic struct Region *up_label(struct label *this)
X{
X    restore_bkgd_label(this); /* Restore at last pos */
X    this->x = this->o.g->s.x;
X    this->y = this->o.g->s.y;
X    calc_rect(this);
X    free_bkgd_label(this);
X    if (this->x != this->oldx || this->y != this->oldy) /* we moved */
X    {
X        add_region(this); /* Refresh at new pos */
X        return this->ref;
X    }
X    else
X    {
X        draw_label(this, TRUE); /* Just redraw, no refresh needed */
X        DisposeRegion(this->ref);
X        return NULL;
X    }
X}
X
X/* End of selection, unhighlight */
Xstatic struct Region *deselect_label(struct label *this)
X{
X    this->selected = FALSE;
X    if (this->o.g->ok && this->o.g->io.rw)
X    {
X        calc_rect(this);
X        reverse_label(this);
X    }
X    return NULL;
X}
X
X/* Handle edit requester */
Xint edit_handler(struct Gadget *gg, ULONG class, struct Requester *req, struct
Xgraph *g)
X{
X    if (gg->GadgetID == FONTLIST) /* User played with font list */
X    {
X        if (ModifyList(gg, req, req->RWindow, class == GADGETUP) == 2)
X        {
X            /* Double click -> exit */
X            EndRequest(req, req->RWindow);
X            return TRUE;
X        }
X        return FALSE;
X    }
X    else return std_ghandler(gg, class, req, g);
X}
X
X/* Allow user to edit us */
Xstatic int edit_label(struct label *this, struct Region **ref)
X{
X    struct Requester *req;
X    struct Memory *m;
X    struct Gadget *gl = NULL;
X    int ret = FALSE;
X    char text[LABELLEN], dx[NBLEN], dy[NBLEN], x[NBLEN], y[NBLEN], fname[FONTLE
XN], fheight[INTLEN], colour[INTLEN];
X    struct Gadget *leftg, *ctrxg, *rightg, *topg, *ctryg, *bottomg;
X
X    this->ref = NULL;
X
X    /* Create requester */
X    strcpy(text, this->text);
X    double2str(dx, this->dx);
X    double2str(dy, this->dy);
X    double2str(x, this->x);
X    double2str(y, this->y);
X    strcpy(fname, this->fname);
X    remfont(fname);
X    int2str(fheight, this->fheight);
X    int2str(colour, this->colour);
X
X    if ((m = NewMemory()) &&
X        (req = InitReq(50, 15, 395, 166, m)) &&
X        SetReqBorder(req, 1, m) &&
X        AddIntuiText(&req->ReqText, "Edit Label", 158, 6, m) &&
X        AddText(&gl, 0, "Text ", FALSE, text, LABELLEN, TRUE, 0, RELVERIFY, 49,
X 20, 335, 10, TRUE, m) &&
X        AddText(&gl, 0, "X = ", FALSE, x, NBLEN, TRUE, 0, RELVERIFY, 43, 40, 56
X, 10, TRUE, m) &&
X        AddText(&gl, 0, "dX = ", FALSE, dx, NBLEN, TRUE, 0, RELVERIFY, 147, 40,
X 56, 10, TRUE, m) &&
X        (leftg = AddRadio(&gl, 0, "left", TRUE, SELECTED * (this->jx == top), R
XELVERIFY, 16 + 32, 210, 40, 10, 10, m)) &&
X        (ctrxg = AddRadio(&gl, 0, "centre", TRUE, SELECTED * (this->jx == centr
Xe), RELVERIFY, 8 + 32, 260, 40, 10, 10, m)) &&
X        (rightg = AddRadio(&gl, 0, "right", TRUE, SELECTED * (this->jx == botto
Xm), RELVERIFY, 16 + 8, 326, 40, 10, 10, m)) &&
X        AddText(&gl, 0, "Y = ", FALSE, y, NBLEN, TRUE, 0, RELVERIFY, 43, 60, 56
X, 10, TRUE, m) &&
X        AddText(&gl, 0, "dY = ", FALSE, dy, NBLEN, TRUE, 0, RELVERIFY, 147, 60,
X 56, 10, TRUE, m) &&
X        (topg = AddRadio(&gl, 0, "top", TRUE, SELECTED * (this->jy == top), REL
XVERIFY, 512 + 1024, 210, 60, 10, 10, m)) &&
X        (ctryg = AddRadio(&gl, 0, "centre", TRUE, SELECTED * (this->jy == centr
Xe), RELVERIFY, 256 + 1024, 260, 60, 10, 10, m)) &&
X        (bottomg = AddRadio(&gl, 0, "bottom", TRUE, SELECTED * (this->jy == bot
Xtom), RELVERIFY, 256 + 512, 326, 60, 10, 10, m)) &&
X        AddText(&gl, 0, "Colour ", FALSE, colour, INTLEN, TRUE, 0, RELVERIFY, 2
X36, 80, 32, 10, TRUE, m) &&
X        AddText(&gl, 0, "Size ", FALSE, fheight, INTLEN, TRUE, 0, RELVERIFY, 22
X0, 150, 32, 10, TRUE, m) &&
X        AddList(&gl, FONTLIST, "Font", &flist, fname, FONTLEN, 0, RELVERIFY, 11
X, 80, 160, 80, TRUE, m) &&
X        AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 255, 100, 65, 15, FAL
XSE, m) &&
X        AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 255, 130, 65, 15
X, FALSE, m))
X    {
X        SetReqGadgets(req, gl);
X        if (ret = DoRequest(req, this->o.g, edit_handler) && *stpblk(text) != '
X\0')
X        {
X            /* Update label */
X            double new;
X            int fh;
X            struct TextFont *newfont;
X
X            add_region(this); /* Refresh needed at old pos */
X
X            /* New justification, etc */
X            if ((this->colour = str2int(colour)) == INOVAL) this->colour = 1;
X            strcpy(this->text, text);
X            if ((new = str2double(x)) != NOVAL) this->x = new;
X            if ((new = str2double(y)) != NOVAL) this->y = new;
X            if ((this->dx = str2double(dx)) == NOVAL) this->dx = 0.0;
X            if ((this->dy = str2double(dy)) == NOVAL) this->dy = 0.0;
X
X            if (leftg->Flags & SELECTED) this->jx = top;
X            else if (ctrxg->Flags & SELECTED) this->jx = centre;
X            else this->jx = bottom;
X
X            if (topg->Flags & SELECTED) this->jy = top;
X            else if (ctryg->Flags & SELECTED) this->jy = centre;
X            else this->jy = bottom;
X
X            /* Check font */
X            addfont(fname);
X            if ((fh = str2int(fheight)) == INOVAL || fh <= 0) fh = LABELHEIGHT;
X     
X            if (newfont = open_font(this->o.g, fname, fh, 0, 0))
X            {
X                strcpy(this->fname, fname);
X                this->fheight = fh;
X                CloseFont(this->font);
X                this->font = newfont;
X            }
X            else message(this->o.g, "Invalid font specified", (char *)NULL);
X
X            /* Do precalculation */
X            setup_label(this);
X            calc_rect(this);
X            add_region(this); /* New position needs refreshing */
X        }
X    }
X    Free(m);
X    *ref = this->ref;
X    return ret;
X}
X
X/* No vsriables used in labels */
Xint var_change_label(struct label *this, char *name)
X{
X    return FALSE;
X}
X
X/* Confirm changes made */
Xstatic void confirm_label(struct label *this, int ok)
X{
X    if (ok)
X    {
X        CloseFont(this->font);
X        this->font = this->newfont;
X        setup_label(this);
X    }
X    else CloseFont(this->newfont); /* failed */
X}
X
X/* Resolution has changed */
Xstatic int inform_label(struct label *this, int ok)
X{
X    if (this->newfont = open_font(this->o.g, this->fname, this->fheight, 0, 0))
X     
X        return TRUE;
X
X    message(this->o.g, "Couldn't open font", (char *)NULL);
X    return FALSE;
X
X}
X
X/* Write label to file */
Xstatic int save_label(struct label *this, FILE *f)
X{
X    short tag = LABEL_TAG;
X    short end = LABEL_END;
X
X    return WRITE(f, tag) &&
X           WRITE(f, this->text) &&
X           WRITE(f, this->colour) &&
X           WRITE(f, this->fname) &&
X           WRITE(f, this->fheight) &&
X           WRITE(f, this->x) &&
X           WRITE(f, this->y) &&
X           WRITE(f, this->dx) &&
X           WRITE(f, this->dy) &&
X           WRITE(f, end);
X}
X
X/* free label */
Xstatic struct Region *delete_label(struct label *this)
X{
X    struct Region *ref;
X
X    /* Label's position will need refreshing */
X    this->ref = NULL;
X    if (this->o.g->ok && this->o.g->io.rw) add_region(this);
X    ref = this->ref;
X
X    if (this->font) CloseFont(this->font);
X    FreeMem(this, sizeof(struct label));
X
X    return ref;
X}
X
X/* Initialise label structure */
Xstatic struct label *make_label(struct graph *g)
X{
X    struct label *this = AllocMem(sizeof(struct label), 0L);
X    const static struct label def_l = {
X        {
X            { NULL },
X            NULL, "", TRUE, 0, 0,
X            (void *)delete_label, (void *)select_label, (void *)deselect_label,
X     
X            (void *)down_label, (void *)move_label, (void *)up_label,
X            (void *)edit_label, (void *)draw_label, (void *)notdone,
X            (void *)notdone, (void *)var_change_label, (void *)save_label,
X            (void *)inform_label, (void *)confirm_label
X        },
X        "", 1, LABELFONT, LABELHEIGHT, NOVAL, NOVAL, 0.0, 0.0, FALSE
X    };
X
X    if (this)
X    {
X        *this = def_l;
X        this->o.g = g;
X        /* Default font *must* be there */
X        if (this->font = open_font(g, LABELFONT, LABELHEIGHT, 0, 0))
X        {
X            return this;
X        }
X        else
X            message(g, "Couldn't open font", (char *)NULL);
X        FreeMem(this, sizeof(struct label));
X    }
X    else
X        message(g, "No memory !", (char *)NULL);
X    return NULL;
X}
X
X/* Load label from file */
Xstruct label *load_label(struct graph *g, FILE *f)
X{
X    struct label *this = make_label(g);
X
X    if (this)
X    {
X        short tag;
X
X        if (READ(f, this->text) &&
X            READ(f, this->colour) &&
X            READ(f, this->fname) &&
X            READ(f, this->fheight) &&
X            READ(f, this->x) &&
X            READ(f, this->y) &&
X            READ(f, this->dx) &&
X            READ(f, this->dy) &&
X            READ(f, tag) &&
X            tag == LABEL_END)
X        {
X            struct TextFont *newfont;
X
X            if (newfont = open_font(this->o.g, this->fname, this->fheight, 0, 0
X))
X            {
X                CloseFont(this->font);
X                this->font = newfont;
X            }
X            else /* Lack of font isn't drastic */
X            {
X                message(g, "No such font available", this->fname, (char *)NULL)
X;
X                strcpy(this->fname, LABELFONT);
X            }
X            setup_label(this);
X            return this;
X        }
X        delete_label(this);
X    }
X    return NULL;
X}
X
X/* Create a new label, at pos. (x,y). Asks user for text */
Xstruct label *new_label(struct graph *g, double x, double y)
X{
X    struct label *this = make_label(g);
X
X    if (this)
X    {
X        /* Create requester */
X        struct Requester *req;
X        struct Memory *m;
X        struct Gadget *gl = NULL;
X        int ret = FALSE;
X
X        this->x = x;
X        this->y = y;
X
X        if ((m = NewMemory()) &&
X            (req = InitReq(50, 20, 160, 65, m)) &&
X            SetReqBorder(req, 1, m) &&
X            AddIntuiText(&req->ReqText, "Add Label", 44, 6, m) &&
X            AddText(&gl, TRUE, "Text ", FALSE, this->text, LABELLEN, TRUE, 0, R
XELVERIFY | ENDGADGET, 49, 20, 100, 10, TRUE, m) &&
X            AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 8, 40, 65, 15, FA
XLSE, m) &&
X            AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 88, 40, 65,
X15, FALSE, m))
X        {
X            SetReqGadgets(req, gl);
X            if (ret = DoRequest(req, g, std_ghandler) && *stpblk(this->text) !=
X '\0')
X            {
X                /* Create it */
X                setup_label(this);
X                if (g->ok && g->io.rw) draw_label(this, TRUE);
X                Free(m);
X                return this;
X            }
X        }
X        Free(m);
X        delete_label(this);
X    }
X    else
X        message(g, "No memory !", (char *)NULL);
X    return NULL;
X}
X
SHAR_EOF
echo "extracting list.c"
sed 's/^X//' << \SHAR_EOF > list.c
X/*
X *                 GRAPH, Version 1.00 - 4 August 1989
X *
X *            Copyright 1989, David Gay. All Rights Reserved.
X *            This software is freely redistrubatable.
X */
X
X#include <exec/types.h>
X#include <stddef.h>
X#include "list.h"
X#include "tracker.h"
X
X/* Free all elements in list (each of size size) */
Xvoid free_list(list *l, size_t size)
X{
X    node *scan, *next;
X
X    for (scan = first(l); next = succ(scan); scan = next)
X        FreeMem(scan, size);
X
X    /* Be safe */
X    new_list(l);
X}
X
SHAR_EOF
echo "extracting list.h"
sed 's/^X//' << \SHAR_EOF > list.h
X/*
X *                 GRAPH, Version 1.00 - 4 August 1989
X *
X *            Copyright 1989, David Gay. All Rights Reserved.
X *            This software is freely redistrubatable.
X */
X
X/* Simplify and "genericize" list operations */
X#ifndef LIST_H
X#define LIST_H
X
X#include <exec/nodes.h>
X#include <exec/lists.h>
X#include <stddef.h>
X
X/* The standard list elements */
Xtypedef struct MinList list;
Xtypedef struct MinNode node;
Xtypedef struct List tlist; /* Typed list */
Xtypedef struct Node tnode; /* Typed (&named) node */
X
X#define new_list(list) NewList((tlist *)(list))
X
X#define add_head(list, node) AddHead((tlist *)(list), (tnode *)(node))
X#define add_tail(list, node) AddTail((tlist *)(list), (tnode *)(node))
X#define rem_head(list) (void *)RemHead((tlist *)(list))
X#define rem_tail(list) (void *)RemTail((tlist *)(list))
X
X#define remove(node) Remove((tnode *)(node))
X#define insert(list, node, pos) Insert((tlist *)(list), (tnode *)(node), (tnode
X *)(pos))
X
X#define first(list) ((void *)((tlist *)(list))->lh_Head)
X#define last(list) ((void *)((tlist *)(list))->lh_Tail)
X#define empty(list) (((tlist *)(list))->lh_TailPred == (tnode *)(list))
X
X#define succ(node) (void *)(((tnode *)(node))->ln_Succ)
X#define pred(node) (void *)(((tnode *)(node))->ln_Pred)
X
X#define alloc_node(size) AllocMem((size), 0L)
X
X/* Free all elements of a homogeneous list */
Xvoid free_list(list *l, size_t size);
X
X#endif
X
SHAR_EOF
echo "extracting lmkfile"
sed 's/^X//' << \SHAR_EOF > lmkfile
XFLAGS = -Hsmall.sym -csf -d3 -v -oo/
XINCS = object.h uio.h list.h grph.h coords.h graph.h
X
X.c.o:
X    lc $(FLAGS) $*
X
Xgraph: graph.d
X    blink from graph.d to graph nodebug
X
Xgraph.d: small.sym o/graph.o o/coords.o o/grph.o o/uio.o o/tracker.o o/list.o o
X/pos.o o/label.o o/f_of_x.o o/x_y.o o/r_of_t.o o/function.o o/default.o o/r_t.o
Xo/graphics.o o/gadgets.o
X    blink with lnk
X
Xsmall.sym: smallsym.c
X    lc -ph -osmall.sym smallsym.c
X
Xo/gadgets.o: gadgets/gadgets.c user/gadgets.h
X
Xo/graphics.o: graphics.c graphics.h
X
Xo/graph.o: graph.c $(INCS)
X
Xo/grph.o: grph.c $(INCS) graphics.h
X
Xo/uio.o: uio.c $(INCS)
X
Xo/coords.o: coords.c coords.h
X
Xo/list.o: list.c list.h
X
Xo/default.o: object/default.c object/default.h $(INCS)
X
Xo/pos.o: object/pos.c object/default.h $(INCS)
X
Xo/label.o: object/label.c object/default.h $(INCS) graphics.h
X
Xo/function.o: object/function.c object/function.h object/default.h $(INCS)
X
Xo/f_of_x.o: object/f_of_x.c object/function.h object/default.h $(INCS)
X
Xo/x_y.o: object/x_y.c object/function.h object/default.h $(INCS)
X
Xo/r_of_t.o: object/r_of_t.c object/function.h object/default.h $(INCS)
X
Xo/r_t.o: object/r_t.c object/function.h object/default.h $(INCS)
X
Xo/tracker.o: divers/tracker.c tracker.h
X    lc -v -O -m1t -oo/ divers/tracker
X
SHAR_EOF
echo "extracting lmko"
sed 's/^X//' << \SHAR_EOF > lmko
XFLAGS = -Hsmall.sym -csf -O -v -ooO/
XINCS = object.h uio.h list.h grph.h coords.h graph.h
X
X.c.o:
X    lc $(FLAGS) $*
X
Xgraph: small.sym oO/graph.o oO/coords.o oO/grph.o oO/uio.o oO/list.o oO/pos.o o
XO/label.o oO/f_of_x.o oO/x_y.o oO/r_of_t.o oO/function.o oO/default.o oO/r_t.o o
XO/graphics.o oO/gadgets.o
X    blink with lnkO
X
Xsmall.sym: smallsym.c
X    lc -ph -osmall.sym smallsym.c
X
XoO/gadgets.o: gadgets/gadgets.c user/gadgets.h
X
XoO/graphics.o: graphics.c graphics.h
X
XoO/graph.o: graph.c $(INCS)
X
XoO/grph.o: grph.c $(INCS) graphics.h
X
XoO/uio.o: uio.c $(INCS)
X
XoO/coords.o: coords.c coords.h
X
XoO/list.o: list.c list.h
X
XoO/default.o: object/default.c object/default.h $(INCS)
X
XoO/pos.o: object/pos.c object/default.h $(INCS)
X
XoO/label.o: object/label.c object/default.h $(INCS) graphics.h
X
XoO/function.o: object/function.c object/function.h object/default.h $(INCS)
X
XoO/f_of_x.o: object/f_of_x.c object/function.h object/default.h $(INCS)
X
XoO/x_y.o: object/x_y.c object/function.h object/default.h $(INCS)
X
XoO/r_of_t.o: object/r_of_t.c object/function.h object/default.h $(INCS)
X
XoO/r_t.o: object/r_t.c object/function.h object/default.h $(INCS)
X
SHAR_EOF
echo "extracting lnk"
sed 's/^X//' << \SHAR_EOF > lnk
XFROM LIB:c.o+o/graph.o+o/coords.o+o/uio.o+o/grph.o+o/tracker.o+o/list.o+o/gadge
Xts.o+o/pos.o+o/label.o+o/f_of_x.o+o/x_y.o+o/r_of_t.o+o/function.o+o/default.o+o/
Xr_t.o+o/graphics.o
XTO graph.d
XLIB lib:eval.lib+lib:lcmieee.lib+lib:lcm.lib+LIB:lc.lib+LIB:amiga.lib
XADDSYM
XVERBOSE
XBATCH
Xsc
X
SHAR_EOF
echo "extracting lnko"
sed 's/^X//' << \SHAR_EOF > lnko
Xfrom lib:c.o oO/graphics.o oO/coords.o oO/graph.o oO/grph.o oO/uio.o oO/gadgets
X.o oO/label.o oO/function.o oO/f_of_x.o oO/x_y.o oO/r_t.o oO/r_of_t.o oO/list.o
X oO/default.o oO/pos.o
XTO graph
XLIB lib:eval.lib+lib:lcmieee.lib+lib:lcm.lib+LIB:lc.lib+LIB:amiga.lib
XNODEBUG
XVERBOSE
XBATCH
Xsc
SHAR_EOF
echo "extracting make.shar"
sed 's/^X//' << \SHAR_EOF > make.shar
Xshar >graph.sh1 -p X README coords.c coords.h default.c default.h file.h functi
Xon.c +
X                function.h f_of_x.c gadgets.c
Xshar >graph.sh2 -p X gadgets.h graph.c graph.doc graph.h graphics.c graphics.h
Xshar >graph.sh3 -p X grph.c grph.h label.c
Xshar >graph.sh4 -p X list.c list.h lmkfile lmkO lnk lnkO mv2dir object.guidelin
Xes +
X                object.h pos.c r_of_t.c r_t.c smallsym.c tracker.c tracker.h
Xshar >graph.sh5 -p X uio.c uio.h x_y.c tracker.README make.shar
SHAR_EOF
echo "extracting mv2dir"
sed 's/^X//' << \SHAR_EOF > mv2dir
Xmakedir o
Xmakedir oO
Xmakedir gadgets
Xmakedir user
Xmakedir object
Xmakedir divers
Xrename gadgets.h user/gadgets.h
Xrename gadgets.c gadgets/gadgets.c
Xrename default.c object/default.c
Xrename default.h object/default.h
Xrename f_of_x.c object/f_of_x.c
Xrename function.c object/function.c
Xrename function.h object/function.h
Xrename label.c object/label.c
Xrename pos.c object/pos.c
Xrename r_of_t.c object/r_of_t.c
Xrename r_t.c object/r_t.c
Xrename x_y.c object/x_y.c
Xrename tracker.c divers
X
X
SHAR_EOF
echo "End of archive 5 (of 7)"
# if you want to concatenate archives, remove anything after this line
exit