home *** CD-ROM | disk | FTP | other *** search
- /*
- * GRAPH, Version 1.00 - 4 August 1989
- *
- * Copyright 1989, David Gay. All Rights Reserved.
- * This software is freely redistrubatable.
- */
-
- /* Graph manipulation */
-
- #include <exec/types.h>
- #include <graphics/gfxbase.h>
- #include <graphics/rastport.h>
- #include <intuition/intuition.h>
- #include <devices/prtbase.h>
- #include <devices/printer.h>
- #include <stdio.h>
- #include <string.h>
- #include <math.h>
- #include <limits.h>
- #include <iff/iff.h>
- #include <iff/ilbm.h>
-
- #include "grph.h"
- #include "file.h"
- #include "graphics.h"
- #include "graph.h"
- #include "uio.h"
- #include "object.h"
- #include "list.h"
- #include "coords.h"
- #include "user/gadgets.h"
- #include "tracker.h"
-
- #include <proto/exec.h>
- #include <proto/graphics.h>
- #include <proto/diskfont.h>
- #include <proto/intuition.h>
-
- #define INCH 2.54e-2
- #define DIGHEIGHT 8 /* Digit font size, in points (1 point = 1/72 inch) */
- #define XTICK 0.05 /* Size of tick for X axis, In inches */
- #define YTICK 0.05
- #define XTEXT 0.12
- #define YTEXT 0.09
-
- #define MAXPRINTPAGES 1 /* Max length for printing */
- #define CHOOSELIST 2 /* for choose req */
- #define IFFDISK 2 /* For iff req */
-
- /* A function to send a slice of output to the chosen device (disk/file) */
- typedef int (*prtfunc)(struct graph *g, struct RastPort *rp, int w, int h, int
- y, int slice, struct Requester *abreq);
-
- extern struct GfxBase *GfxBase;
-
- static UWORD scr_dpmx, scr_dpmy; /* The screen 'resolution' */
-
- /* Data for printer output */
- static struct IODRPReq *prtio;
- static struct MsgPort *prtport;
- static struct PrinterExtendedData *ped;
- static struct Preferences *prtprefs;
- static struct ColorMap *prtcm;
-
- /* Data for iff output */
- static FILE *iff_file;
- static long form_pos, body_pos;
- static char iff_filename[FILELEN];
- static struct Gadget *iffg;
-
- static char *prt_error[] = {
- "Unknown error",
- "Print cancelled",
- "Not a graphics printer !",
- "Obsolete",
- "Illegal print dimensions",
- "Obsolete",
- "No memory (internal)",
- "No memory (for buffers)"
- };
-
- #define MAX_PRT_ERROR (sizeof(prt_error) / sizeof(char *) - 1)
-
- /* Check that ax can be displayed */
- static int ax_ok(const struct ax *a, const struct ax *other)
- {
- return (a->ax == NOVAL ||
- ((!other->log || a->ax > 0.0) &&
- (a->cstep == NOVAL ||
- (a->cstep > 0.0 &&
- (a->every == INOVAL || a->every > 0)))));
- }
-
- /* Check that ax has legal values */
- static int ax_ok2(const struct ax *a)
- {
- return a->min != NOVAL && a->max != NOVAL && a->min < a->max &&
- (!a->log || a->min > 0.0);
- }
-
- /* Check if graph is displayable */
- static int graph_ok(struct graph *g)
- {
- g->a.ok = ax_ok(&g->a.x, &g->a.y) && ax_ok(&g->a.y, &g->a.x) &&
- (g->a.ratio == NOVAL || g->a.ratio > 0.0);
-
- return ax_ok2(&g->a.x) && ax_ok2(&g->a.x);
- }
-
- /* Redraw graph after changes */
- static void check_graph(struct graph *g)
- {
- g->saved = FALSE;
- g->ok = graph_ok(g);
- set_scale(g);
- draw_graph(g, TRUE);
- }
-
- /* Find object in graph by name */
- static struct object *find_object(struct graph *g, char *name)
- {
- struct object *o;
-
- for (o = first(&g->o_list); succ(o); o = succ(o))
- if (strcmp(o->name, name) == 0) return o;
-
- return NULL;
- }
-
- /* Convert inches to rastport dots, using current dpm */
- /* Use integer arithmetic if needs to be called often */
- int xinch2dots(struct graph *g, double x)
- {
- return (int)(x * INCH * g->io.dpmx + 0.5);
- }
-
- int yinch2dots(struct graph *g, double y)
- {
- return (int)(y * INCH * g->io.dpmy + 0.5);
- }
-
- /* Open font in pts points */
- struct TextFont *open_font(struct graph *g, char *name, int pts, int style, int
- flags)
- {
- struct TextAttr ta;
- struct TextFont *tf1, *tf2;
-
- ta.ta_Name = name;
- ta.ta_YSize = yinch2dots(g, pts / 72.0);
- ta.ta_Style = style;
- ta.ta_Flags = flags;
-
- tf1 = OpenFont(&ta);
- if (!tf1)
- return OpenDiskFont(&ta);
- else if (tf1->tf_YSize != ta.ta_YSize)
- {
- tf2 = OpenDiskFont(&ta);
-
- if (tf2)
- {
- CloseFont(tf1);
- return tf2;
- }
- else
- return tf2;
- }
- else
- return tf1;
- }
-
- /* add object to graph (object is already displayed) */
- struct object *add_object(struct graph *g, struct object *o)
- {
- if (o)
- {
- if (o->name[0] != '\0' && find_object(g, o->name))
- {
- message(g, "Name already used", (char *)NULL);
- refresh_graph(g, TRUE, o->delete(o));
- return NULL;
- }
- add_head(&g->o_list, o);
- g->saved = FALSE;
- }
- return o;
- }
-
- /* Remove object & redisplay graph */
- void remove_object(struct graph *g, struct object *o)
- {
- if (o == g->s.current)
- {
- o->deselect(o);
- g->s.current = NULL;
- disable_rect_menus(g);
- disable_object_menus(g);
- }
- remove(o);
- g->saved = FALSE;
- refresh_graph(g, TRUE, o->delete(o));
- }
-
- /* Make object o selected */
- void select_object(struct graph *g, struct object *o)
- {
- if (o)
- {
- g->s.current = o;
- o->select(o); /* Inform object of this */
- enable_object_menus(g);
- set_title(g);
- }
- }
-
- /* Deslect current object */
- void deselect(struct graph *g)
- {
- struct Region *ref;
-
- /* Deselect object */
- ref = g->s.current ? g->s.current->deselect(g->s.current) : NULL;
- g->s.current = NULL;
-
- disable_rect_menus(g);
- disable_object_menus(g);
- refresh_graph(g, TRUE, ref);
- }
-
- /* User pressed mouse button */
- void mouse_down(struct graph *g, WORD sx, WORD sy)
- {
- if (g->ok && g->io.rw)
- {
- /* Get real pos */
- g->s.x = g->io.rw->x(g->io.rw, sx);
- g->s.y = g->io.rw->y(g->io.rw, sy);
- /* If nothing selected, or if not clicking in selected object */
- if (!g->s.current || !g->s.current->down(g->s.current))
- {
- deselect(g);
-
- if (g->s.select_mode) /* Try to select something */
- {
- struct object *o;
-
- for (o = first(&g->o_list); succ(o); o = succ(o))
- if (o->down(o)) /* Inside object ? */
- {
- select_object(g, o);
- break; /* exit for loop */
- }
- }
- else /* Start a new rectangle */
- if (g->s.current = (struct object *)new_pos(g))
- enable_rect_menus(g);
-
- }
- if (g->s.current) /* Something is now selected, keep track of mouse */
- {
- /* Adjust position for offset in object */
- g->s.x = g->io.rw->x(g->io.rw, sx - g->s.current->mx);
- g->s.y = g->io.rw->y(g->io.rw, sy - g->s.current->my);
- ReportMouse(g->io.win, TRUE);
- g->s.mouse = TRUE;
- }
- set_title(g);
- }
- }
-
- /* Mouse has moved */
- void mouse_move(struct graph *g, WORD sx, WORD sy)
- {
- if (g->s.mouse)
- {
- /* Adjust for offset, calc pos in coord system */
- sx -= g->s.current->mx;
- sy -= g->s.current->my;
- g->s.x = g->io.rw->x(g->io.rw, sx);
- g->s.y = g->io.rw->y(g->io.rw, sy);
-
- /* Inform selection of movement */
- g->s.current->move(g->s.current);
-
- set_title(g);
- }
- }
-
- /* Mouse button released */
- void mouse_up(struct graph *g, WORD sx, WORD sy)
- {
- if (g->s.mouse) /* mouse was down */
- {
- g->saved = FALSE; ./* Graph has very probably changed */
- g->s.mouse = FALSE;
-
- sx -= g->s.current->mx;
- sy -= g->s.current->my;
- g->s.x = g->io.rw->x(g->io.rw, sx);
- g->s.y = g->io.rw->y(g->io.rw, sy);
-
- ReportMouse(g->io.win, FALSE);
- /* Redaw whatever is necessary */
- refresh_graph(g, TRUE, g->s.current->up(g->s.current));
- }
- }
-
- /* Handler for object selection requester */
- static int choose_handler(struct Gadget *gg, ULONG class, struct Requester *req
- , struct graph *g)
- {
- if (gg->GadgetID == CHOOSELIST) /* In a list */
- {
- if (ModifyList(gg, req, req->RWindow, class == GADGETUP) == 2)
- {
- EndRequest(req, req->RWindow);
- return TRUE;
- }
- }
- else return std_ghandler(gg, class, req, g);
- }
-
- /* Ask user to choose an object, by name */
- struct object *choose_object(struct graph *g, char *op)
- {
- struct object *o, *sel = NULL;
- char name[FNAMELEN];
- tlist l;
- char what[30];
- int ok;
-
- /* Construct title */
- what[29] = '\0'; name[0] = '\0';
- strncpy(what, op, 29);
- strncat(what, " function", 29 - strlen(what));
-
- /* Construct list of named objects */
- new_list(&l);
- ok = TRUE;
- for (o = first(&g->o_list); succ(o); o = succ(o))
- if (o->name[0] != '\0')
- {
- tnode *n = alloc_node(sizeof(tnode));
-
- if (!n)
- {
- ok = FALSE;
- break;
- }
- n->ln_Name = o->name;
- add_tail(&l, n);
- }
-
- if (ok) /* list constructed ok */
- {
- /* Create requester */
- struct Requester *req;
- struct Memory *m;
- struct Gadget *gl = NULL;
-
- if ((m = NewMemory()) &&
- (req = InitReq(50, 20, 200, 120, m)) &&
- SetReqBorder(req, 1, m) &&
- AddIntuiText(&req->ReqText, what, 100 - 4 * strlen(what), 6, m) &&
- AddList(&gl, CHOOSELIST, "Name", &l, name, FNAMELEN, 0, RELVERIFY |
- ENDGADGET, 20, 20, 160, 80, TRUE, m) &&
- AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 18, 95, 65, 15, F
- ALSE, m) &&
- AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 118, 95, 65,
- 15, FALSE, m))
- {
- SetReqGadgets(req, gl);
- if (DoRequest(req, g, choose_handler))
- {
- /* Remove blanks */
- strip(name);
- if (*name)
- {
- sel = find_object(g, name);
- if (!sel) message(g, "No such function", (char *)NULL);
- }
- }
- }
- Free(m);
- }
- free_list((list *)&l, sizeof(tnode));
- return sel;
- }
-
- /* Define coordinate system */
- void enter_limits(struct graph *g)
- {
- struct Requester *req;
- struct Memory *m;
- struct Gadget *gl = NULL, *x_log, *y_log;
- char xmin[NBLEN], xmax[NBLEN], ymin[NBLEN], ymax[NBLEN], ratio[NBLEN];
-
- double2str(xmin, g->a.x.min);
- double2str(xmax, g->a.x.max);
- double2str(ymin, g->a.y.min);
- double2str(ymax, g->a.y.max);
- double2str(ratio, g->a.ratio);
-
- if ((m = NewMemory()) &&
- (req = InitReq(50, 20, 325, 105, m)) &&
- SetReqBorder(req, 1, m) &&
- AddIntuiText(&req->ReqText, "Limits", 138, 6, m) &&
- AddText(&gl, 0, "X: Min ", FALSE, xmin, NBLEN, TRUE, 0, RELVERIFY, 67,
- 20, 80, 10, TRUE, m) &&
- AddText(&gl, 0, "Max ", FALSE, xmax, NBLEN, TRUE, 0, RELVERIFY, 190, 20
- , 80, 10, TRUE, m) &&
- (x_log = AddOption(&gl, 0, "Log", FALSE, g->a.x.log * SELECTED, 0, 305,
- 20, 10, 10, m)) &&
- AddText(&gl, 0, "Y: Min ", FALSE, ymin, NBLEN, TRUE, 0, RELVERIFY, 67,
- 40, 80, 10, TRUE, m) &&
- AddText(&gl, 0, "Max ", FALSE, ymax, NBLEN, TRUE, 0, RELVERIFY, 190, 40
- , 80, 10, TRUE, m) &&
- (y_log = AddOption(&gl, 0, "Log", FALSE, g->a.y.log * SELECTED, 0, 305,
- 40, 10, 10, m)) &&
- AddText(&gl, 0, "Ratio (Y/X) ", FALSE, ratio, NBLEN, TRUE, 0, RELVERIFY
- , 107, 60, 80, 10, TRUE, m) &&
- AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 49, 80, 65, 15, FALSE
- , m) &&
- AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 211, 80, 65, 15,
- FALSE, m))
- {
- SetReqGadgets(req, gl);
- if (DoRequest(req, g, std_ghandler))
- {
- g->a.x.min = str2double(xmin);
- g->a.x.max = str2double(xmax);
- g->a.x.log = (x_log->Flags & SELECTED) != 0;
- g->a.y.min = str2double(ymin);
- g->a.y.max = str2double(ymax);
- g->a.y.log = (y_log->Flags & SELECTED) != 0;
- g->a.ratio = str2double(ratio);
- check_graph(g);
- }
- }
- Free(m);
- }
-
- /* Choose axes display options */
- void enter_axes(struct graph *g)
- {
- struct Requester *req;
- struct Memory *m;
- struct Gadget *gl = NULL;
- char ax_x[NBLEN], ax_y[NBLEN], step_x[NBLEN], step_y[NBLEN],
- every_x[INTLEN], every_y[INTLEN];
-
- double2str(ax_x, g->a.x.ax);
- double2str(step_x, g->a.x.cstep);
- int2str(every_x, g->a.x.every);
- double2str(ax_y, g->a.y.ax);
- double2str(step_y, g->a.y.cstep);
- int2str(every_y, g->a.y.every);
-
- if ((m = NewMemory()) &&
- (req = InitReq(50, 15, 225, 165, m)) &&
- SetReqBorder(req, 1, m) &&
- AddIntuiText(&req->ReqText, "Axes", 96, 6, m) &&
- AddText(&gl, 0, "X: Axe at ", FALSE, ax_x, NBLEN, TRUE, 0, RELVERIFY, 9
- 1, 20, 80, 10, TRUE, m) &&
- AddText(&gl, 0, " Ticks every ", FALSE, step_x, NBLEN, TRUE, 0, RELVE
- RIFY, 131, 40, 80, 10, TRUE, m) &&
- AddText(&gl, 0, " numbered every ", FALSE, every_x, INTLEN, TRUE, 0,
- RELVERIFY, 155, 60, 32, 10, TRUE, m) &&
- AddText(&gl, 0, "Y: Axe at ", FALSE, ax_y, NBLEN, TRUE, 0, RELVERIFY, 9
- 1, 80, 80, 10, TRUE, m) &&
- AddText(&gl, 0, " Ticks every ", FALSE, step_y, NBLEN, TRUE, 0, RELVE
- RIFY, 131, 100, 80, 10, TRUE, m) &&
- AddText(&gl, 0, " numbered every ", FALSE, every_y, INTLEN, TRUE, 0,
- RELVERIFY, 155, 120, 32, 10, TRUE, m) &&
- AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 24, 140, 65, 15, FALS
- E, m) &&
- AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 136, 140, 65, 15
- , FALSE, m))
- {
- SetReqGadgets(req, gl);
- if (DoRequest(req, g, std_ghandler))
- {
- g->a.x.ax = str2double(ax_x);
- g->a.x.cstep = str2double(step_x);
- g->a.x.every = str2int(every_x);
- g->a.y.ax = str2double(ax_y);
- g->a.y.cstep = str2double(step_y);
- g->a.y.every = str2int(every_y);
- check_graph(g);
- }
- }
- Free(m);
- }
-
- /* Change mode */
- void set_mode(struct graph *g, int newmode)
- {
- if (newmode != g->s.select_mode) deselect(g);
- g->s.select_mode = newmode;
- }
-
- /* Recalc & display title */
- /* assumes GNAMELEN < TITLELEN */
- void set_title(struct graph *g)
- {
- strcpy(g->io.title, g->name);
- if (!g->ok) strncat(g->io.title, "(Bad)", TITLELEN - 1 - strlen(g->io.title
- ));
- if (g->s.current)
- if (g->s.current->name[0] != '\0')
- {
- strncat(g->io.title, ", function is ", TITLELEN - 1 - strlen(g->io.
- title));
- strncat(g->io.title, g->s.current->name, TITLELEN - 1 - strlen(g->i
- o.title));
- if (!g->s.current->ok) strncat(g->io.title, "(Bad)", TITLELEN - 1 -
- strlen(g->io.title));
- }
- else strncat(g->io.title, ", object selected", TITLELEN -1 - strlen(g->
- io.title));
- else strncat(g->io.title, ", nothing selected", TITLELEN - 1 - strlen(g->io
- .title));
- if (g->s.mouse)
- {
- char x[NBLEN], y[NBLEN];
-
- double2str(x, g->s.x); double2str(y, g->s.y);
- strncat(g->io.title, " x=", TITLELEN - 1 - strlen(g->io.title));
- strncat(g->io.title, x, TITLELEN - 1 - strlen(g->io.title));
- strncat(g->io.title, ", y=", TITLELEN - 1 - strlen(g->io.title));
- strncat(g->io.title, y, TITLELEN - 1 - strlen(g->io.title));
- }
-
- SetWindowTitles(g->io.win, g->io.title, "Graph");
- }
-
- /* Window has changed size, recreate coord system, taking into account the
- desired ratio */
- void set_scale(struct graph *g)
- {
- /* Standard borders */
- long x0offset = g->io.win->BorderLeft + 8;
- long x1offset = g->io.win->BorderRight + 8;
- long y0offset = g->io.win->BorderBottom + 8;
- long y1offset = g->io.win->BorderTop + 8;
-
- /* Save size used */
- g->io.oldwidth = g->io.win->Width; g->io.oldheight = g->io.win->Height;
-
- /* Delete old coords */
- if (g->io.rw) g->io.rw->delete(g->io.rw);
-
- /* Create new coords at max size */
- g->io.rw = new_RWindow(g->io.win->RPort, g->io.win->Width, g->io.win->Heigh
- t,
- x0offset, y0offset, x1offset, y1offset,
- g->a.x.min, g->a.y.min, g->a.x.max, g->a.y.max,
- g->a.x.log, g->a.y.log, TRUE);
- if (!g->io.rw)
- {
- message(g, "Couldn't make coords", (char *)NULL);
- return;
- }
-
- SetRast(g->io.win->RPort, 0); /* Clear whole window */
-
- if (g->ok && g->a.ok && g->a.ratio != NOVAL)
- {
- /* Adjust for desired ratio */
- double r;
-
- /* Current ratio */
- r = g->a.ratio /
- fabs(((g->io.rw->sy(g->io.rw, g->a.y.log ? 10.0 : 2.0) - g->io.rw->
- sy(g->io.rw, 1.0)) * scr_dpmx) /
- ((g->io.rw->sx(g->io.rw, g->a.x.log ? 10.0 : 2.0) - g->io.rw->
- sx(g->io.rw, 1.0)) * scr_dpmy));
-
- g->io.rw->delete(g->io.rw);
-
- /* Adjust borders */
- if (r > 1.0) /* make X smaller */
- {
- long width = g->io.win->Width - x0offset - x1offset;
- long delta = width - width / r;
-
- x0offset += delta / 2;
- x1offset += delta - delta / 2;
- }
- else /* make Y smaller */
- {
- long height = g->io.win->Height - y0offset - y1offset;
- long delta = height - height * r;
-
- y0offset += delta / 2;
- y1offset += delta - delta / 2;
- }
- /* & create new coord system */
- g->io.rw = new_RWindow(g->io.win->RPort, g->io.win->Width, g->io.win->H
- eight,
- x0offset, y0offset, x1offset, y1offset,
- g->a.x.min, g->a.y.min, g->a.x.max, g->a.y.max,
- g->a.x.log, g->a.y.log, TRUE);
- if (!g->io.rw)
- {
- message(g, "Couldn't make coords", (char *)NULL);
- return;
- }
- }
- }
-
- /* Change output resolution.
- This may require opening of new resources (eg fonts) in the objects, which
- can obviously fail, yet we don't want the graph to be left in an inconsis-
- tent state, hence inform & confirm (cf object.guidelines). */
- int set_dpm(struct graph *g, int dpmx, int dpmy)
- {
- int olddpmx = g->io.dpmx, olddpmy = g->io.dpmy;
- struct TextFont *digits;
-
- g->io.dpmx = dpmx; g->io.dpmy = dpmy;
- /* Open correct font for this resolution */
- if (digits = open_font(g, "digits.font", DIGHEIGHT, 0, 0))
- {
- int ok = TRUE;
- struct object *scan, *scan2;
-
- /* Inform objects */
- for (scan = first(&g->o_list); ok && succ(scan); scan = succ(scan))
- if (!scan->inform(scan)) ok = FALSE;
-
- if (ok)
- {
- /* Everything worked, confoirm changes */
- for (scan = first(&g->o_list); ok && succ(scan); scan = succ(scan))
-
- scan->confirm(scan, TRUE);
-
- /* Free old resources */
- CloseFont(g->io.digits);
- g->io.digits = digits;
- return TRUE;
- }
- /* Return to previous state */
- for (scan2 = first(&g->o_list); scan2 != scan; scan2 = succ(scan2))
- scan2->confirm(scan2, FALSE);
-
- CloseFont(digits);
- }
- else
- message(g, "Couldn't open digits.font", (char *)NULL);
- g->io.dpmx = olddpmx; g->io.dpmy = olddpmy;
- return FALSE;
- }
-
- /* Set pen to one ptsize wide. Should really modify g->io.rw->rp, but ... *
- /
- void set_pensize(struct graph *g, struct RastPort *rp, double ptsize)
- {
- int xsize = xinch2dots(g, ptsize / 72.0);
- int ysize = yinch2dots(g, ptsize / 72.0);
-
- if ((xsize & 1) == 0) xsize++;
- if ((ysize & 1) == 0) ysize++;
-
- rp->PenWidth = xsize;
- rp->PenHeight = ysize;
- }
-
- /* Use a "thin" line (1 pixel wide) */
- void set_thin(struct graph *g, struct RastPort *rp)
- {
- rp->PenWidth = 1;
- rp->PenWidth = 1;
- }
-
- /* Change graph limits */
- void zoom_in(struct graph *g, double x0, double y0, double x1, double y1)
- {
- if (g->ok && x0 != x1 && y0 != y1)
- {
- double xmin = min(x0, x1);
- double xmax = max(x0, x1);
- double ymin = min(y0, y1);
- double ymax = max(y0, y1);
-
- g->a.x.min = max(g->a.x.min, xmin);
- g->a.x.max = min(g->a.x.max, xmax);
- g->a.y.min = max(g->a.y.min, ymin);
- g->a.y.max = min(g->a.y.max, ymax);
-
- check_graph(g);
- }
- else
- message(g, "No rectangle to zoom into", (char *)NULL);
- }
-
- /* Calculate new limits for ax a for a zoom factor of mult */
- static void zoom_ax(struct ax *a, double mult)
- {
- if (a->log)
- {
- /* Zoom on a log scale ... Real fun with this one :-) */
- double centre = sqrt(a->min * a->max);
- double delta = pow(centre, 1.0 - mult);
-
- a->min = pow(a->min, mult) * delta;
- a->max = pow(a->max, mult) * delta;
- }
- else
- {
- /* ax becomes mult times longer, with same centre */
- double centre = (a->min + a->max) / 2;
- double delta = centre - a->min;
-
- a->min = centre - mult * delta;
- a->max = centre + mult * delta;
- }
- }
-
- /* Zoom out by a factor factor */
- void zoom_factor(struct graph *g, double factor)
- {
- if (g->ok)
- {
- zoom_ax(&g->a.x, factor);
- zoom_ax(&g->a.y, factor);
- check_graph(g);
- }
- else
- message(g, "No scale set !", (char *)NULL);
- }
-
- /* Define new centre for ax */
- static void center_ax(struct ax *a, double centre)
- {
- if (a->log)
- {
- /* more & more fun ... */
- double delta = sqrt(a->max / a->min);
-
- a->max = centre * delta;
- a->min = centre / delta;
- }
- else
- {
- /* obvious */
- double delta = (a->max - a->min) / 2.0;
-
- a->max = centre + delta;
- a->min = centre - delta;
- }
- }
-
- /* New centre for graph */
- void center_graph(struct graph *g, double x, double y)
- {
- if (g->ok && x != NOVAL)
- {
- center_ax(&g->a.x, max(min(x, g->a.x.max), g->a.x.min));
- center_ax(&g->a.y, max(min(y, g->a.y.max), g->a.y.min));
- check_graph(g);
- }
- else
- message(g, "Nothing to center on", (char *)NULL);
- }
-
- /* Redraw ax a (of graph g), at position xorig on other ax. y_ax is true for
- drawing of y axis */
- static void draw_ax(struct graph *g, struct ax *a, double xorig, int y_ax)
- {
- struct TextFont *oldfont, *digits = g->io.digits;
- struct RWindow *const rwin = g->io.rw;
- struct RastPort *const rp = rwin->rp;
- int xtick = yinch2dots(g, XTICK), ytick = xinch2dots(g, YTICK);
- int xtext = xinch2dots(g, XTEXT), ytext = yinch2dots(g, YTEXT);
-
- oldfont = rp->Font;
- SetFont(rp, digits);
- SetDrMd(rp, JAM1);
- if (a->ax != NOVAL)
- {
- /* Draw ax */
- if (y_ax)
- {
- RMove(rwin, a->ax, a->max);
- Draw(rwin->rp, rwin->rp->cp_x, ftol(rwin->sy(rwin, a->min)));
- }
- else
- {
- RMove(rwin, a->max, a->ax);
- Draw(rwin->rp, ftol(rwin->sx(rwin, a->min)), rwin->rp->cp_y);
- }
- if (a->cstep != NOVAL)
- {
- /* Draw ticks and numbers */
- if (a->log)
- {
- /* logarithmic ax */
- double nax;
- int emin, emax, e, count, i;
-
- /* Normalise origin (0 < nax < 10). There will be count ticks,
- at nax, nax + cstep, nax + 2 * cstep, etc for every exponent
-
- value between min & max */
- nax = xorig * pow(10.0, -floor(log10(xorig)));
- /* Exponent range */
- emin = floor(log10(a->min / nax));
- emax = ceil(log10(a->max / nax));
- /* Number of ticks for every exponent value */
- count = ceil(9 * nax / a->cstep);
-
- for (e = emin; e <= emax; e++)
- {
- double const p = pow(10.0, (double)e);
- double const st = a->cstep * p; /* step between ticks */
- double x = p * nax; /* POos. of main tick */
- long cx, cy;
-
- /* Display main value (at nax, with exponent) */
- if (a->every != INOVAL && x != xorig)
- {
- if (y_ax)
- RMove(rwin, a->ax, x);
- else
- RMove(rwin, x, a->ax);
-
- cx = rp->cp_x; cy = rp->cp_y;
-
- if (e == 0)
- {
- /* don't display 10^0 */
- char nb[NBLEN];
- int l;
-
- /* Display nax */
- double2str(nb, nax);
- l = strlen(nb);
- if (y_ax)
- Move(rp, cx + xtext, cy + digits->tf_Baseline /
- 2);
- else
- Move(rp, cx - digits->tf_XSize * l / 2, cy + di
- gits->tf_Baseline + ytext);
- Text(rp, nb, l);
- }
- else
- {
- char nb[NBLEN + 3], expo[NBLEN];
- int l1, l2;
-
- if (nax == 1)
- strcpy(nb, "10");
- else
- {
- double2str(nb, nax);
- strcat(nb, "*10");
- }
- sprintf(expo, "%d", e);
- l1 = strlen(nb);
- l2 = strlen(expo);
- /* Display base */
- if (y_ax)
- Move(rp, cx + xtext, cy + digits->tf_Baseline /
- 2);
- else
- Move(rp, cx, cy + digits->tf_Baseline + digits-
- >tf_Baseline / 2 + ytext);
- Text(rp, nb, l1);
- /* Display exponent */
- Move(rp, rp->cp_x, rp->cp_y - digits->tf_Baseline /
- 2);
- Text(rp, expo, l2);
-
- }
- }
- /* Now for the ticks ... */
- for (i = 0; i < count; i++, x += st)
- {
- /* Draw tick */
- if (y_ax)
- RMove(rwin, a->ax, x);
- else
- RMove(rwin, x, a->ax);
-
- cx = rp->cp_x; cy = rp->cp_y;
-
- if (y_ax)
- {
- Move(rp, cx + ytick, cy);
- Draw(rp, cx - ytick, cy);
- }
- else
- {
- Move(rp, cx, cy + xtick);
- Draw(rp, cx, cy - xtick);
- }
- /* Display digits */
- if (i != 0 && a->every != INOVAL && (i % a->every) == 0
- )
- {
- char nb[NBLEN];
- int l;
-
- /* Only display mantissa */
- double2str(nb, nax + i * a->cstep);
- l = strlen(nb);
- if (y_ax)
- Move(rp, cx + xtext, cy + digits->tf_Baseline /
- 2);
- else
- Move(rp, cx - digits->tf_XSize * l / 2 + 1, cy
- + digits->tf_Baseline + ytext);
- Text(rp, nb, l);
- }
- }
- }
- }
- else
- {
- /* linear ax */
- long count, disp_digits;
- double x;
-
- /* Number of ticks */
- count = ceil((a->min - xorig) / a->cstep);
- /* First tick at which to show value */
- disp_digits = a->every == INOVAL ?
- count - 1 : /* No digits displayed */
- a->every * (long)ceil((a->min - xorig) / (a->cs
- tep * a->every));
-
- for(x = count * a->cstep + xorig; x <= a->max; x += a->cstep, c
- ount++)
- {
- long cx, cy;
-
- /* Draw tick */
- if (y_ax)
- RMove(rwin, a->ax, x);
- else
- RMove(rwin, x, a->ax);
-
- cx = rp->cp_x; cy = rp->cp_y;
-
- if (y_ax)
- {
- Move(rp, cx + ytick, cy);
- Draw(rp, cx - ytick, cy);
- }
- else
- {
- Move(rp, cx, cy + xtick);
- Draw(rp, cx, cy - xtick);
- }
-
- /* Display digits */
- if (count == disp_digits)
- {
- char nb[NBLEN];
- int l;
-
- /* Next one in every ticks */
- disp_digits += a->every;
-
- if (count != 0) /* Not at origin */
- {
- double2str(nb, x);
- l = strlen(nb);
- if (y_ax)
- Move(rp, cx + xtext, cy + digits->tf_Baseline /
- 2);
- else
- Move(rp, cx - digits->tf_XSize * l / 2, cy + di
- gits->tf_Baseline + ytext);
- Text(rp, nb, l);
- }
- }
- }
- }
- }
- }
- SetFont(rp, oldfont);
- }
-
- /* Draws directly into the rastport, used internally. allow_mes nust be FALSE
- if called during window refresh */
- static void do_draw(struct graph *g, int allow_mes)
- {
- struct object *o;
-
- if (g->ok && g->io.rw)
- {
- /* Draw axes */
- SetAPen(g->io.rw->rp, 1L);
- if (g->a.ok)
- {
- draw_ax(g, &g->a.x, g->a.y.ax, FALSE);
- draw_ax(g, &g->a.y, g->a.x.ax, TRUE);
- }
-
- /* Draw objects */
- for (o = first(&g->o_list); succ(o); o = succ(o))
- if (o != g->s.current && o->ok) o->draw(o, allow_mes);
-
- /* Current object is always last so that it appears "on top" */
- if (g->s.current && g->s.current->ok) g->s.current->draw(g->s.current,
- allow_mes);
- }
- }
-
- /* Redraw graph completely */
- void draw_graph(struct graph *g, int allow_mes)
- {
- if (allow_mes) set_title(g);
-
- SetRast(g->io.rw->rp, 0); /* Clear window */
-
- do_draw(g, allow_mes);
- }
-
- /* Redraw graph partially (ref is NULL for no redraw). ref is disposed when
- refresh is done */
- void refresh_graph(struct graph *g, int allow_mes, struct Region *ref)
- {
- if (ref)
- {
- if (g->io.rw)
- {
- /* Setup clipping */
- struct Region *oldRegion = InstallClipRegion(g->io.rw->rp->Layer, r
- ef);
-
- SetRast(g->io.rw->rp, 0);
- do_draw(g, allow_mes);
-
- InstallClipRegion(g->io.rw->rp->Layer, oldRegion);
- }
- DisposeRegion(ref);
- }
- }
-
- /* Returns a region that will fully refresh g.
- (makes a copy of the current region) */
- struct Region *full_refresh(struct graph *g)
- {
- struct Region *r;
-
- if ((r = NewRegion()) && g->io.rw)
- {
- struct Region *old = InstallClipRegion(g->io.rw->rp->Layer, NULL);
-
- /* Make copy */
- if (!OrRegionRegion(old, r))
- {
- DisposeRegion(r);
- r = NULL;
- }
-
- InstallClipRegion(g->io.rw->rp->Layer, old);
- }
- return r;
- }
-
- /* Open printer.device */
- static int open_prt(void)
- {
- if (prtport = CreatePort(0L, 0L))
- {
- if (prtio = (struct IODRPReq *)CreateExtIO(prtport, sizeof(struct IODRP
- Req)))
- {
- if (OpenDevice("printer.device", 0, (struct IORequest *)prtio, 0) =
- = 0)
- {
- ped = &((struct PrinterData *)prtio->io_Device)->pd_SegmentData
- ->ps_PED;
- prtprefs = &((struct PrinterData *)prtio->io_Device)->pd_Prefer
- ences;
-
- return TRUE;
- }
- DeleteExtIO((struct IORequest *)prtport);
- }
- DeletePort(prtport);
- }
- return FALSE;
- }
-
- /* Close printer device */
- static void close_prt(void)
- {
- CloseDevice((struct IORequest *)prtio);
- DeleteExtIO((struct IORequest *)prtio);
- DeletePort(prtport);
- }
-
- /* Easy access to DumpRPort. wait : DoIO or SendIO ? */
- static void prt_raster(int wait, struct RastPort *rp, struct ColorMap *cm, ULON
- G m, UWORD sx, UWORD sy, UWORD w, UWORD h, LONG dc, LONG dr, UWORD special)
- {
- prtio->io_RastPort = rp;
- prtio->io_ColorMap = cm;
- prtio->io_Modes = m;
- prtio->io_SrcX = sx;
- prtio->io_SrcY = sy;
- prtio->io_SrcWidth = w;
- prtio->io_SrcHeight = h;
- prtio->io_DestCols = dc;
- prtio->io_DestRows = dr;
- prtio->io_Special = special;
- prtio->io_Command = PRD_DUMPRPORT;
- if (wait) DoIO(prtio);
- else SendIO(prtio);
- }
-
- /* Print a slice of the dump to the printer */
- static int prt_slice(struct graph *g, struct RastPort *rp, int w, int h, int y,
- int slice, struct Requester *abreq)
- {
- struct RWindow *old = g->io.rw;
- int ret = FALSE;
- ULONG prtsig = 1 << prtio->io_Message.mn_ReplyPort->mp_SigBit;
- ULONG winsig = 1 << g->io.win->UserPort->mp_SigBit;
-
- /* Create coords for slice */
- g->io.rw = new_RWindow(rp, w, slice,
- 0, y + slice - h, 0, -y,
- g->a.x.min, g->a.y.min, g->a.x.max, g->a.y.max,
- g->a.x.log, g->a.y.log, FALSE);
- if (g->io.rw)
- {
- int done = FALSE;
-
- /* Draw into rastport. Note that it may be > 1024 x 1024 ! */
- BigSetRast(rp, 0);
- do_draw(g, TRUE);
- prt_raster(FALSE, rp, prtcm, 0L, 0, 0, (UWORD)w, (UWORD)slice, w, slice
- , SPECIAL_NOFORMFEED);
-
- do { /* Wait for end of printing or abort */
- Wait(prtsig | winsig);
- if (aborted(abreq))
- {
- done = TRUE;
- ret = FALSE; /* Stop! */
- if (!CheckIO(prtio))
- {
- AbortIO(prtio);
- WaitIO(prtio);
- }
- prtio->io_Error = 0;
- }
- else if (CheckIO(prtio))
- {
- done = TRUE;
- ret = prtio->io_Error == 0;
- }
- } while (!done);
- g->io.rw->delete(g->io.rw);
- }
- else
- nomem(g->io.win);
- g->io.rw = old;
- return ret;
- }
-
- /* Work out the max size for a slice (don't use more than half the largest
- chunk of chip ram). The height must be a multiple of quanta */
- static int get_slice_height(int w, int h, int quanta)
- {
- long use = AvailMem(MEMF_CHIP | MEMF_LARGEST) / 2;
- long min = 2 * RASSIZE(w, quanta);
- long nb = use / min;
-
- if (nb == 0) /* Not much mem ... */ return quanta;
- else if (nb * quanta > h) return h;
- else return nb * quanta;
- }
-
- /* Create a 2 plane Rastport with clipping at its limits (-> Layer) */
- static struct RastPort *alloc_ras(int w, int h)
- {
- struct Layer_Info *li;
- struct BitMap *bm;
- BYTE *data;
- struct Layer *l;
-
- /* Alloc components */
- if (li = NewLayerInfo())
- {
- if (bm = AllocMem(sizeof(struct BitMap), 0L))
- {
- if (data = AllocMem(2 * RASSIZE(w, h), MEMF_CHIP))
- {
- /* Set up data structure */
- InitBitMap(bm, 2, w, h);
- bm->Planes[0] = (PLANEPTR)data;
- bm->Planes[1] = (PLANEPTR)(data + RASSIZE(w, h));
-
- if (l = CreateUpfrontLayer(li, bm, 0, 0, w - 1, h - 1, LAYERSIM
- PLE, NULL))
- return l->rp;
-
- FreeMem(data, 2 * RASSIZE(w, h));
- }
- FreeMem(bm, sizeof(struct BitMap));
- }
- DisposeLayerInfo(li);
- }
- return NULL;
- }
-
- /* Free rastport created by alloc_ras */
- static void free_ras(struct RastPort *rp)
- {
- struct Layer_Info *li = rp->Layer->LayerInfo;
- struct BitMap *bm = rp->BitMap;
-
- DeleteLayer(li, rp->Layer);
- FreeMem(bm->Planes[0], bm->BytesPerRow * bm->Rows * bm->Depth);
- FreeMem(bm, sizeof(struct BitMap));
- DisposeLayerInfo(li);
- }
-
- /* Print graph into a bitmap which is w by h pixels, resolution xdpm, ydpm,
- quanta is the size of the print head (if any, 1 otherwise). dump_slice is
- called for every slice.
- Rem: printing is broken into horizontal slices, according to available
- memory */
- static void prt(struct graph *g, int w, int h, int quanta, int xdpm, int ydpm,
- prtfunc dump_slice)
- {
- int slice, y, ok = TRUE;
- struct RastPort *rp;
- struct Requester *abreq;
- struct Requester *req;
- struct Memory *m;
- struct Gadget *gl = NULL, *thin;
- char size[NBLEN];
-
- size[0] = '\0';
-
- /* Ask user for print characteristics (pen size) */
- if ((m = NewMemory()) &&
- (req = InitReq(50, 20, 180, 85, m)) &&
- SetReqBorder(req, 1, m) &&
- AddIntuiText(&req->ReqText, "Print Characteristics", 6, 6, m) &&
- (thin = AddRadio(&gl, 0, "Thin", TRUE, SELECTED, RELVERIFY, 2, 11, 20,
- 10, 10, m)) &&
- AddRadio(&gl, 0, "Thick,", TRUE, 0, RELVERIFY, 1, 11, 40, 10, 10, m) &&
-
- AddText(&gl, 0, "Size ", FALSE, size, NBLEN, TRUE, 0, RELVERIFY, 128, 4
- 1, 32, 10, TRUE, m) &&
- AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 13, 60, 65, 15, FALSE
- , m) &&
- AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 103, 60, 65, 15,
- FALSE, m))
- {
- SetReqGadgets(req, gl);
- if (DoRequest(req, g, std_ghandler))
- {
- double ptsize = str2double(size);
-
- if ((thin->Flags & SELECTED) || (ptsize > 0.0 && ptsize != NOVAL))
- {
- /* Set up for printing */
- if (set_dpm(g, xdpm, ydpm))
- {
- slice = get_slice_height(w, h, quanta);
- if (rp = alloc_ras(w, slice))
- {
- if (abreq = abort_request(g, "Printing, slice
- "))
- {
- if (thin->Flags & SELECTED) set_thin(g, rp);
- else set_pensize(g, rp, ptsize);
-
- /* Print all the slices */
- for (y = 0; ok && y < h; y += slice)
- {
- char msg[30];
-
- sprintf(msg, "Printing, slice %d of %d", y / sl
- ice + 1, (h + slice - 1) / slice);
- set_abort_msg(abreq, msg);
- ok = dump_slice(g, rp, w, h, y, min(slice, h -
- y), abreq);
- }
- end_abort_request(abreq);
- }
- else
- message(g, "Abort requester failed", (char *)NULL);
-
- free_ras(rp);
- }
- else
- nomem(g->io.win);
- /* Return to screen */
- set_dpm(g, scr_dpmx, scr_dpmy);
- }
- }
- else
- message(g, "Illegal line size", (char *)NULL);
- }
- }
- Free(m);
- }
-
- /* get max size of printed output */
- static int get_max_size(struct graph *g, int *w, int *h, int *quanta)
- {
- prt_raster(TRUE, g->io.win->RPort, prtcm, 0L, 0, 0, g->io.win->Width, g->io
- .win->Height, LONG_MAX, LONG_MAX, SPECIAL_NOPRINT);
-
- *w = prtio->io_DestCols;
- *h = prtio->io_DestRows;
- /* If length = infinity, use MAXPRINTPAGES pages */
- if (*h == LONG_MAX)
- *h = (ped->ped_YDotsInch * MAXPRINTPAGES * prtprefs->PaperLength) / (pr
- tprefs->PrintSpacing == SIX_LPI ? 6 : 8);
- *quanta = ped->ped_NumRows;
-
- return prtio->io_Error == 0;
- }
-
- /* Determine size which fits asked for ratio (when no absolute size set in
- preferences) */
- static int get_size(struct graph *g, int *w, int *h, int *quanta)
- {
- if (get_max_size(g, w, h, quanta))
- {
- if (g->ok && g->a.ok && g->a.ratio != NOVAL)
- {
- /* adjust for ratio */
- double r = g->a.ratio /
- fabs((*h / (g->a.y.log ? log10(g->a.y.max / g->a.y.min) : (g->a
- .y.max - g->a.y.min)) * ped->ped_XDotsInch) /
- (*w / (g->a.x.log ? log10(g->a.x.max / g->a.x.min) : (g->a
- .x.max - g->a.x.min)) * ped->ped_YDotsInch));
-
- if (r > 1.0) /* make X smaller */
- *w /= r;
- else /* make Y smaller */
- *h *= r;
- }
- if (*w == 0) *w = 1;
- if (*h == 0) *h = 1;
- return TRUE;
- }
- return FALSE;
- }
-
- /* determine size to use when user has set abs. size in preferences */
- static int get_abs_size(struct graph *g, int *w, int *h, int *quanta)
- {
- if (get_max_size(g, w, h, quanta))
- {
- if (g->ok && g->a.ok && g->a.ratio != NOVAL)
- {
- /* Adjust only if dimension is free (size set to 0) */
- double r = g->a.ratio /
- fabs((*h / (g->a.y.log ? log10(g->a.y.max / g->a.y.min) : (g->a
- .y.max - g->a.y.min)) * ped->ped_XDotsInch) /
- (*w / (g->a.x.log ? log10(g->a.x.max / g->a.x.min) : (g->a
- .x.max - g->a.x.min)) * ped->ped_YDotsInch));
-
- if (r > 1.0 && prtprefs->PrintMaxWidth == 0) /* make X smaller */
- *w /= r;
- else if (r < 1.0 && prtprefs->PrintMaxHeight == 0) /* make Y smalle
- r */
- *h *= r;
- }
- if (*w == 0) *w = 1;
- if (*h == 0) *h = 1;
- return TRUE;
- }
- return FALSE;
- }
-
- /* Print a graph */
- void prt_graph(struct graph *g)
- {
- int w, h, quanta;
-
- if (g->ok)
- if (open_prt())
- {
- prtprefs->PrintFlags &= ~INTEGER_SCALING; /* We produce nice output
- anyway ! */
- prtprefs->PrintAspect = ASPECT_HORIZ; /* No support for vertical pl
- ots */
-
- switch (prtprefs->PrintFlags & DIMENSIONS_MASK)
- {
- case MULTIPLY_DIMENSIONS: /* Ignored */
- prtprefs->PrintFlags &= ~DIMENSIONS_MASK;
- /* FALLTHROUGH */
- case IGNORE_DIMENSIONS:
- case BOUNDED_DIMENSIONS:
- if (get_size(g, &w, &h, &quanta))
- {
- prtprefs->PrintFlags &= ~DIMENSIONS_MASK;
- prt(g, w, h, quanta, (int)(ped->ped_XDotsInch / INCH),
- (int)(ped->ped_YDotsInch / INCH), prt_slice);
- }
- break;
-
- case ABSOLUTE_DIMENSIONS:
- case PIXEL_DIMENSIONS:
- if (get_abs_size(g, &w, &h, &quanta))
- {
- prtprefs->PrintFlags &= ~DIMENSIONS_MASK;
- prt(g, w, h, quanta, (int)(ped->ped_XDotsInch / INCH),
- (int)(ped->ped_YDotsInch / INCH), prt_slice);
- }
- break;
- }
- if (prtio->io_Error > 0) /* Printer error */
- message(g, "Printer Error", prt_error[prtio->io_Error > MAX_PRT
- _ERROR ? 0 : prtio->io_Error], (char *)NULL);
- close_prt();
- }
- else
- message(g, "Couldn't open printer\n", (char *)NULL);
- }
-
- /* Write slice into body. Must add byteRun1 compression */
- static int write_iffslice(struct BitMap *bm)
- {
- int y, plane;
-
- for (y = 0; y < bm->Rows; y++)
- {
- /* Interleave bit planes */
- for (plane = 0; plane < bm->Depth; plane++)
- if (!fwrite(bm->Planes[plane] + y * bm->BytesPerRow, bm->BytesPerRo
- w, 1, iff_file))
- return FALSE;
- }
- return TRUE;
- }
-
- /* Draw & write into slice for iff output */
- static int iff_slice(struct graph *g, struct RastPort *rp, int w, int h, int y,
- int slice, struct Requester *abreq)
- {
- struct RWindow *old = g->io.rw;
- int ret = FALSE;
-
- g->io.rw = new_RWindow(rp, w, slice,
- 0, y + slice - h, 0, -y,
- g->a.x.min, g->a.y.min, g->a.x.max, g->a.y.max,
- g->a.x.log, g->a.y.log, FALSE);
- if (g->io.rw)
- {
- BigSetRast(rp, 0);
- do_draw(g, TRUE);
- if (write_iffslice(rp->BitMap))
- {
- if (!aborted(abreq)) ret = TRUE;
- }
- else
- message(g, "Error writing file", (char *)NULL);
-
- g->io.rw->delete(g->io.rw);
- }
- else
- nomem(g->io.win);
- g->io.rw = old;
- return ret;
- }
-
- /* Write ILBM header to file (BMHD, CMAP & start of BODY). Save positions for
- writing sizes */
- static int start_iff(char *name, int w, int h, int xdpi, int ydpi)
- {
- if (iff_file = fopen(name, "w"))
- {
- if (fwrite("FORM", 4, 1, iff_file) && (form_pos = ftell(iff_file)) != -
- 1L &&
- fwrite("\0\0\0\0ILBMBMHD\0\0\0\024", 16, 1, iff_file))
- {
- static BitMapHeader bm = {
- 0, 0, 0, 0, 2, mskNone, cmpNone, 0, 0
- };
- bm.w = w; bm.h = h;
- bm.xAspect = ydpi; bm.yAspect = xdpi;
- bm.pageWidth = w; bm.pageHeight = h;
-
- if (fwrite((char *)&bm, sizeof(bm), 1, iff_file) &&
- fwrite("CMAP\0\0\0\14", 8, 1, iff_file) &&
- fwrite("\xff\xff\xff\0\0\0\0\0\0\0\0\0", 12, 1, iff_file) &&
- fwrite("BODY", 4, 1, iff_file) && (body_pos = ftell(iff_file))
- != -1 &&
- fwrite("\0\0\0\0", 4, 1, iff_file))
- {
- return TRUE;
- }
- }
- /* If failed, delete file */
- if (fclose(iff_file) == 0) unlink(name);
- }
- return FALSE;
- }
-
- /* Write end of iff_file, ie pad, write lengths & close */
- static int end_iff(void)
- {
- long end = ftell(iff_file), end2 = end;
-
- if (end != -1)
- {
- if ((end & 1) == 0 || (end2++, fwrite("\0", 1, 1, iff_file))) /* pad. y
- uck. */
- {
- long formlen = end2 - form_pos - 4; /* Includes pad byte */
- long bodylen = end - body_pos - 4; /* Doesn't */
-
- if (fseek(iff_file, form_pos, 0) != -1 &&
- fwrite((char *)&formlen, sizeof(long), 1, iff_file) &&
- fseek(iff_file, body_pos, 0) != -1 &&
- fwrite((char *)&bodylen, sizeof(long), 1, iff_file))
- {
- return fclose(iff_file) == 0;
- }
- }
- }
- return FALSE;
- }
-
- /* Handle iff requester: display file req when user clicks on disk */
- static int iff_handler(struct Gadget *gg, ULONG class, struct Requester *req, s
- truct graph *g)
- {
- if (gg->GadgetID == IFFDISK)
- {
- char file[FILELEN];
-
- if (getfile(file, "IFF Output file"))
- {
- UWORD pos = RemoveGList(req->RWindow, iffg, 1);
- strcpy(iff_filename, file);
- RefreshGList(iffg, req->RWindow, req, 1);
- AddGList(req->RWindow, iffg, pos, 1, req);
- }
- ActivateGadget(iffg, req->RWindow, req);
- return FALSE;
- }
- else return std_ghandler(gg, class, req, g);
- }
-
- /* Output graph as ILBM. Asks for bitmap size, and resolution. Ignores graph
- ratio. */
- void iff_todisk(struct graph *g)
- {
- struct Requester *req;
- struct Memory *m;
- struct Gadget *gl = NULL;
- char xsize[NBLEN], ysize[NBLEN], xdpi[NBLEN], ydpi[NBLEN];
-
- xsize[0] = '\0'; ysize[0] = '\0';
- strcpy(xdpi, "72"); strcpy(ydpi, "72");
-
- iff_filename[0] = '\0';
- if ((m = NewMemory()) &&
- (req = InitReq(50, 20, 280, 110, m)) &&
- SetReqBorder(req, 1, m) &&
- AddIntuiText(&req->ReqText, "Write IFF", 104, 6, m) &&
- (iffg = AddText(&gl, 0, "File ", FALSE, iff_filename, FILELEN, TRUE, 0,
- RELVERIFY, 51, 20, 144, 10, TRUE, m)) &&
- AddBox(&gl, IFFDISK, "Disk", 0, RELVERIFY, 205, 17, 65, 15, FALSE, m) &
- &
- AddText(&gl, 0, "Size: X ", FALSE, xsize, INTLEN, TRUE, 0, RELVERIFY, 7
- 5, 45, 32, 10, TRUE, m) &&
- AddText(&gl, 0, "Y ", FALSE, ysize, INTLEN, TRUE, 0, RELVERIFY, 140, 45
- , 32, 10, TRUE, m) &&
- AddText(&gl, 0, "DPI: X ", FALSE, xdpi, INTLEN, TRUE, 0, RELVERIFY, 83,
- 65, 32, 10, TRUE, m) &&
- AddText(&gl, 0, "Y ", FALSE, ydpi, INTLEN, TRUE, 0, RELVERIFY, 140, 65,
- 32, 10, TRUE, m) &&
- AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 38, 85, 65, 15, FALSE
- , m) &&
- AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 178, 85, 65, 15,
- FALSE, m))
- {
- SetReqGadgets(req, gl);
- if (DoRequest(req, g, iff_handler))
- {
- int w = str2int(xsize);
- int h = str2int(ysize);
- int xdp = str2int(xdpi);
- int ydp = str2int(ydpi);
-
- if (w > 0 && h > 0 && xdp > 0 && ydp > 0 &&
- w != NOVAL && h != NOVAL && xdp != NOVAL && ydp != NOVAL)
- if (start_iff(iff_filename, w, h, xdp, ydp))
- {
- prt(g, w, h, 1, (int)(xdp / INCH), (int)(ydp / INCH), iff_s
- lice);
- if (!end_iff())
- message(g, "Error writing file", (char *)NULL);
- }
- else
- message(g, "Error writing file", (char *)NULL);
- else
- message(g, "Illegal dimensions !", (char *)NULL);
- }
- }
- Free(m);
- }
-
- /* Write graph to file f */
- int save_graph(struct graph *g, FILE *f)
- {
- int ok = FALSE;
- short tag = GRAPH_TAG;
-
- /* Write graph information */
- if (WRITE(f, tag) &&
- WRITE(f, g->io.win->LeftEdge) &&
- WRITE(f, g->io.win->TopEdge) &&
- WRITE(f, g->io.win->Width) &&
- WRITE(f, g->io.win->Height) &&
- WRITE(f, g->name) &&
- WRITE(f, g->a))
- {
- struct object *scan;
-
- ok = TRUE;
- /* Write all objects */
- for (scan = first(&g->o_list); ok && succ(scan); scan = succ(scan))
- {
- if (!scan->save(scan, f)) ok = FALSE;
- }
- /* Write end tag */
- if (ok)
- {
- tag = GRAPH_END;
- ok = WRITE(f, tag);
- g->saved = TRUE;
- }
- }
- return ok;
- }
-
- /* Load & create new graph from file f (graph tag already read) */
- struct graph *load_graph(struct graph *from, FILE *f)
- {
- struct graph *g = new_graph(from);
-
- if (g)
- {
- WORD leftedge, topedge, width, height;
- int ok = FALSE;
-
- /* Read graph info */
- if (READ(f, leftedge) &&
- READ(f, topedge) &&
- READ(f, width) &&
- READ(f, height) &&
- READ(f, g->name) &&
- READ(f, g->a))
- {
- int done = FALSE;
-
- ok = TRUE;
- do /* Read objects */
- {
- short tag;
- struct object *o = NULL;
-
- if (READ(f, tag))
- switch (tag) /* We have to know which objects exist ... */
- {
- case GRAPH_END:
- done = TRUE;
- break;
- case LABEL_TAG:
- o = (struct object *)load_label(g, f);
- break;
- case FUNCTION_TAG:
- o = (struct object *)load_function(g, f);
- break;
- default:
- message(g, "File is not a graph", (char *)NULL);
- break;
- }
- ok = done || o != NULL;
- if (o)
- add_tail(&g->o_list, o);
- } while (!done && ok);
-
- }
- if (!ok)
- {
- delete_graph(g);
- g = NULL;
- }
- else /* All ok, display */
- {
- check_graph(g);
- g->saved = TRUE;
- }
- }
- return g;
- }
-
- /* Delete a graph */
- void delete_graph(struct graph *g)
- {
- struct object *o, *next;
-
- /* Deselect */
- if (g->s.current) g->s.current->deselect(g->s.current);
-
- /* Delete all objects */
- for (o = first(&g->o_list); next = succ(o); o = next)
- {
- struct Region *ref = o->delete(o);
-
- DisposeRegion(ref);
- }
-
- /* Delete all local resources */
- if (g->io.rw) g->io.rw->delete(g->io.rw);
- CloseFont(g->io.digits);
- cleanup_uio(g); /* Clears menus, closes window ... */
- FreeMem(g, sizeof(struct graph));
- }
-
- /* Create a new graph */
- struct graph *new_graph(struct graph *from)
- {
- struct graph *const g = AllocMem(sizeof(struct graph), 0L);
- char *msg;
- const static struct graph def_g = { /* Default values */
- { NULL },
- FALSE, TRUE,
- "Graph",
- { MENUNULL },
- { NULL },
- {
- {
- NOVAL, NOVAL,
- NOVAL, NOVAL,
- INOVAL,
- FALSE
- },
- {
- NOVAL, NOVAL,
- NOVAL, NOVAL,
- INOVAL,
- FALSE
- },
- NOVAL,
- FALSE, FALSE
- },
- {
- FALSE, FALSE,
- NOVAL, NOVAL,
- NULL
- }
- };
-
- if (g)
- {
- *g = def_g;
- g->io.dpmx = scr_dpmx; g->io.dpmy = scr_dpmy;
- new_list(&g->o_list); /* no objects */
- if (g->io.digits = open_font(g, "digits.font", DIGHEIGHT, 0, 0))
- {
- if (init_uio(g)) /* Open window */
- {
- set_scale(g);
- draw_graph(g, TRUE); /* & display */
- return g;
- }
- else msg = "No window";
- CloseFont(g->io.digits);
- }
- else msg = "digits.font missing";
- FreeMem(g, sizeof(struct graph));
- }
- else msg = "No memory !";
-
- message(from, "Couldn't create graph", msg, (char *)NULL);
-
- return NULL;
- }
-
- /* Global initialisation */
- int init_grph(void)
- {
- struct Screen wbscr;
-
- /* Find screen resolution */
- scr_dpmx = GfxBase->NormalDPMX;
- scr_dpmy = GfxBase->NormalDPMY;
- if (!GetScreenData((char *)&wbscr, sizeof(struct Screen), WBENCHSCREEN, NUL
- L))
- return alert(NULL, "No Workbench !", NULL), FALSE;
-
- if (wbscr.ViewPort.Modes & HIRES) scr_dpmx *= 2;
- if (wbscr.ViewPort.Modes & LACE) scr_dpmy *= 2;
-
- /* Color map for printer. Add colours ? */
- if (!(prtcm = GetColorMap(4))) return nomem(NULL), FALSE;
- SetRGB4CM(prtcm, 0, 15, 15, 15);
- SetRGB4CM(prtcm, 1, 0, 0, 0);
- SetRGB4CM(prtcm, 2, 0, 0, 0);
- SetRGB4CM(prtcm, 3, 0, 0, 0);
-
- return TRUE;
- }
-
- /* Free any global resources */
- void cleanup_grph(void)
- {
- if (prtcm) FreeColorMap(prtcm);
- }
-
-