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.
- */
-
- #include <exec/types.h>
- #include <intuition/intuition.h>
- #include <graphics/text.h>
- #include <string.h>
- #include <limits.h>
-
- #include "object.h"
- #include "object/default.h"
- #include "file.h"
- #include "graph.h"
- #include "uio.h"
- #include "coords.h"
- #include "grph.h"
- #include "user/gadgets.h"
- #include "graphics.h"
- #include "tracker.h"
-
- #include <proto/exec.h>
- #include <proto/intuition.h>
- #include <proto/graphics.h>
-
- #define LABELLEN 256
- #define LABELHEIGHT 10
- #define LABELFONT "topaz.font"
- #define FONTLIST 2
-
- /* The various justification possibilities */
- enum justify { top, centre, bottom };
-
- /* (private) class label, inherits from object */
- struct label
- {
- struct object o;
- char text[LABELLEN]; /* What to display, \ for newlines */
- BYTE colour;
- char fname[FONTLEN]; /* font name */
- int fheight; /* font height */
- double x, y; /* text position */
- double dx, dy; /* offset from position, in inches */
- enum justify jx, jy; /* justification (x & y axes) */
-
- char selected;
- /* Temp, etc vars */
- char broken[LABELLEN]; /* Text, separated into lines (separated by NULLs)
- */
- int nblines; /* number of lines */
- struct Rectangle extent; /* Size of rectangle taken by text */
- int bw, bh; /* Size of bitmap (for moving) */
- struct Rectangle lims; /* Rectangle taken up on screen */
- int x0, y0; /* x & y in screen coords (wthout ddx, ddy) */
- struct TextFont *font, *newfont; /* the font (newfont for inform/confirm) *
- /
- double oldx, oldy; /* position before move */
- int ddx, ddy; /* dx, dy in pixels */
- struct Region *ref;
- struct RastPort bkgd; /* Rastport & bitmap for moves */
- struct BitMap bkgd_bm;
- };
-
- /*-------------------------------------------------------------------------*/
- /* label class implementation */
- /*-------------------------------------------------------------------------*/
-
- /* Allocates bitmap for saving background while moving */
- /* Assumes 2 bit planes */
- static int alloc_bkgd_label(struct label *this)
- {
- BYTE *data;
-
- if (data = AllocMem(2 * RASSIZE(this->bw, this->bh), MEMF_CHIP))
- {
- InitBitMap(&this->bkgd_bm, 2, this->bw, this->bh);
- this->bkgd_bm.Planes[0] = (PLANEPTR)data;
- this->bkgd_bm.Planes[1] = (PLANEPTR)(data + RASSIZE(this->bw, this->bh)
- );
- InitRastPort(&this->bkgd);
- this->bkgd.BitMap = &this->bkgd_bm;
- }
- return data != 0;
- }
-
- /* Frees bitmap alloced above */
- static void free_bkgd_label(struct label *this)
- {
- FreeMem(this->bkgd_bm.Planes[0], 2 * RASSIZE(this->bw, this->bh));
- }
-
- /* Save scrren background into temp space */
- static void save_bkgd_label(struct label *this)
- {
- ClipBlit(this->o.g->io.rw->rp, this->lims.MinX, this->lims.MinY, &this->bkg
- d, 0, 0, this->bw, this->bh, 0xc0);
- }
-
- /* Copies saved background back to the screen */
- static void restore_bkgd_label(struct label *this)
- {
- ClipBlit(&this->bkgd, 0, 0, this->o.g->io.rw->rp, this->lims.MinX, this->li
- ms.MinY, this->bw, this->bh, 0xc0);
- }
-
- /* Do all the precalculations */
- static void setup_label(struct label *this)
- {
- struct TextFont *font = this->font;
- char *srch, *nl;
-
- this->ddx = xinch2dots(this->o.g, this->dx);
- this->ddy = yinch2dots(this->o.g, this->dy);
-
- /* Break up label & calculate rectangle used */
- srch = strcpy(this->broken, this->text);
- this->nblines = 0;
- this->extent.MaxX = 0;
- this->extent.MinX = INT_MAX;
- do
- {
- struct TextExtent te;
-
- nl = strchr(srch, '\\');
-
- if (nl && *(nl + 1) == '\\') /* add single slash */
- movmem(nl + 1, nl, LABELLEN - (nl - this->broken) - 1);
- else
- {
- this->nblines++;
- if (nl) *nl = '\0';
- /* Check space for this line */
- TextExtent(srch, font, &te);
- if (te.te_Extent.MaxX > this->extent.MaxX) this->extent.MaxX = te.t
- e_Extent.MaxX;
- if (te.te_Extent.MinX < this->extent.MinX) this->extent.MinX = te.t
- e_Extent.MinX;
- }
- srch = nl + 1;
- } while (nl);
-
- this->extent.MinY = 0;
- this->extent.MaxY = this->nblines * font->tf_YSize;
- this->bw = this->extent.MaxX - this->extent.MinX + 1;
- this->bh = this->extent.MaxY - this->extent.MinY + 1;
- }
-
- /* Work out rectangle used by text */
- static void calc_rect(struct label *this)
- {
- struct graph *g = this->o.g;
- struct RWindow *rw = g->io.rw;
- int delta, x0, y0;
-
- /* Find origin */
- /* Default */
- x0 = (this->x0 = ftol(rw->sx(rw, this->x))) + this->ddx;
- y0 = (this->y0 = ftol(rw->sy(rw, this->y))) + this->ddy;
-
- /* Adjust for justification */
- switch (this->jx)
- {
- case centre:
- x0 -= this->bw / 2;
- break;
- case bottom: /* right */
- x0 -= this->bw;
- break;
- }
- switch (this->jy)
- {
- case centre:
- y0 -= this->bh / 2;
- break;
- case bottom: /* right */
- y0 -= this->bh;
- break;
- }
- /* Extent defines actual rectangle */
- this->lims.MinX = x0 + this->extent.MinX;
- this->lims.MaxX = x0 + this->extent.MaxX;
- this->lims.MinY = y0 + this->extent.MinY;
- this->lims.MaxY = y0 + this->extent.MaxY;
-
- /* Make sure that it stays visible */
- /* Could one reduce the number of flops ? */
- /* Idea: Generalise inform/confirm */
- if ((delta = ftol(rw->sx(rw, g->a.x.min)) - this->lims.MinX) > 0 ||
- (delta = ftol(rw->sx(rw, g->a.x.max)) - this->lims.MaxX) < 0)
- {
- this->x0 += delta;
- this->lims.MinX += delta;
- this->lims.MaxX += delta;
- }
- if ((delta = ftol(rw->sy(rw, g->a.y.max)) - this->lims.MinY) > 0 ||
- (delta = ftol(rw->sy(rw, g->a.y.min)) - this->lims.MaxY) < 0)
- {
- this->y0 += delta;
- this->lims.MinY += delta;
- this->lims.MaxY += delta;
- }
- }
-
- /* Add the current position to the region */
- static void add_region(struct label *this)
- {
- if (!this->ref) this->ref = NewRegion();
- if (this->ref && !OrRectRegion(this->ref, &this->lims))
- {
- DisposeRegion(this->ref);
- this->ref = NULL;
- }
- if (!this->ref) nomem(this->o.g->io.win);
- }
-
- /* Were we clicked on ? */
- static int down_label(struct label *this)
- {
- struct graph *g = this->o.g;
- WORD sx = ftol(g->io.rw->sx(g->io.rw, g->s.x));
- WORD sy = ftol(g->io.rw->sy(g->io.rw, g->s.y));
- int inside;
-
- calc_rect(this);
- inside = sx >= this->lims.MinX && sx <= this->lims.MaxX &&
- sy >= this->lims.MinY && sy <= this->lims.MaxY;
- if (inside)
- {
- /* Setup internal info for move */
- this->o.mx = sx - this->x0;
- this->o.my = sy - this->y0;
- if (alloc_bkgd_label(this))
- {
- save_bkgd_label(this);
- if (this->selected)
- {
- SetDrMd(&this->bkgd, COMPLEMENT);
- RectFill(&this->bkgd, 0, 0, this->bw - 1, this->bh - 1);
- }
- this->ref = NULL;
- add_region(this); /* Original pos. will probably need refreshing */
-
- this->oldx = this->x; this->oldy = this->y;
- }
- else /* failed, no mem */
- {
- nomem(this->o.g->io.win);
- inside = FALSE;
- }
- }
- return inside;
- }
-
- /* Reverse label's rectangle (eg for selection) */
- static void reverse_label(struct label *this)
- {
- struct RastPort *rp = this->o.g->io.rw->rp;
-
- SetDrMd(rp, COMPLEMENT);
- RectFill(rp, this->lims.MinX, this->lims.MinY, this->lims.MaxX, this->lims.
- MaxY);
- }
-
- /* Draw label */
- static void draw_label(struct label *this, int allow_mes)
- {
- struct graph *g = this->o.g;
- struct RastPort *rp = g->io.rw->rp;
- char *str;
- int i;
-
- calc_rect(this);
- SetAPen(rp, this->colour);
- SetDrMd(rp, JAM1);
- SetFont(rp, this->font);
-
- /* Draw all the lines of text */
- Move(rp, this->lims.MinX - this->extent.MinX, this->lims.MinY - this->exten
- t.MinY + this->font->tf_Baseline);
- for (str = this->broken, i = this->nblines; i; i--)
- {
- int l = strlen(str);
-
- Text(rp, str, l);
- Move(rp, this->lims.MinX - this->extent.MinX, rp->cp_y + this->font->tf
- _YSize);
-
- str += l + 1; /* Onto next string */
- }
-
- if (this->selected) reverse_label(this);
- }
-
- /* We're now selected */
- static void select_label(struct label *this)
- {
- this->selected = TRUE;
- if (this->o.g->ok && this->o.g->io.rw)
- {
- calc_rect(this);
- reverse_label(this);
- }
- }
-
- /* A quick walk around town ... */
- static void move_label(struct label *this)
- {
- restore_bkgd_label(this); /* erase label */
- this->x = this->o.g->s.x;
- this->y = this->o.g->s.y;
- calc_rect(this);
- save_bkgd_label(this); /* Save background */
- draw_label(this, TRUE); /* & draw at new pos */
- }
-
- /* Mouse buttonb released, refresh needed ? */
- static struct Region *up_label(struct label *this)
- {
- restore_bkgd_label(this); /* Restore at last pos */
- this->x = this->o.g->s.x;
- this->y = this->o.g->s.y;
- calc_rect(this);
- free_bkgd_label(this);
- if (this->x != this->oldx || this->y != this->oldy) /* we moved */
- {
- add_region(this); /* Refresh at new pos */
- return this->ref;
- }
- else
- {
- draw_label(this, TRUE); /* Just redraw, no refresh needed */
- DisposeRegion(this->ref);
- return NULL;
- }
- }
-
- /* End of selection, unhighlight */
- static struct Region *deselect_label(struct label *this)
- {
- this->selected = FALSE;
- if (this->o.g->ok && this->o.g->io.rw)
- {
- calc_rect(this);
- reverse_label(this);
- }
- return NULL;
- }
-
- /* Handle edit requester */
- int edit_handler(struct Gadget *gg, ULONG class, struct Requester *req, struct
- graph *g)
- {
- if (gg->GadgetID == FONTLIST) /* User played with font list */
- {
- if (ModifyList(gg, req, req->RWindow, class == GADGETUP) == 2)
- {
- /* Double click -> exit */
- EndRequest(req, req->RWindow);
- return TRUE;
- }
- return FALSE;
- }
- else return std_ghandler(gg, class, req, g);
- }
-
- /* Allow user to edit us */
- static int edit_label(struct label *this, struct Region **ref)
- {
- struct Requester *req;
- struct Memory *m;
- struct Gadget *gl = NULL;
- int ret = FALSE;
- char text[LABELLEN], dx[NBLEN], dy[NBLEN], x[NBLEN], y[NBLEN], fname[FONTLE
- N], fheight[INTLEN], colour[INTLEN];
- struct Gadget *leftg, *ctrxg, *rightg, *topg, *ctryg, *bottomg;
-
- this->ref = NULL;
-
- /* Create requester */
- strcpy(text, this->text);
- double2str(dx, this->dx);
- double2str(dy, this->dy);
- double2str(x, this->x);
- double2str(y, this->y);
- strcpy(fname, this->fname);
- remfont(fname);
- int2str(fheight, this->fheight);
- int2str(colour, this->colour);
-
- if ((m = NewMemory()) &&
- (req = InitReq(50, 15, 395, 166, m)) &&
- SetReqBorder(req, 1, m) &&
- AddIntuiText(&req->ReqText, "Edit Label", 158, 6, m) &&
- AddText(&gl, 0, "Text ", FALSE, text, LABELLEN, TRUE, 0, RELVERIFY, 49,
- 20, 335, 10, TRUE, m) &&
- AddText(&gl, 0, "X = ", FALSE, x, NBLEN, TRUE, 0, RELVERIFY, 43, 40, 56
- , 10, TRUE, m) &&
- AddText(&gl, 0, "dX = ", FALSE, dx, NBLEN, TRUE, 0, RELVERIFY, 147, 40,
- 56, 10, TRUE, m) &&
- (leftg = AddRadio(&gl, 0, "left", TRUE, SELECTED * (this->jx == top), R
- ELVERIFY, 16 + 32, 210, 40, 10, 10, m)) &&
- (ctrxg = AddRadio(&gl, 0, "centre", TRUE, SELECTED * (this->jx == centr
- e), RELVERIFY, 8 + 32, 260, 40, 10, 10, m)) &&
- (rightg = AddRadio(&gl, 0, "right", TRUE, SELECTED * (this->jx == botto
- m), RELVERIFY, 16 + 8, 326, 40, 10, 10, m)) &&
- AddText(&gl, 0, "Y = ", FALSE, y, NBLEN, TRUE, 0, RELVERIFY, 43, 60, 56
- , 10, TRUE, m) &&
- AddText(&gl, 0, "dY = ", FALSE, dy, NBLEN, TRUE, 0, RELVERIFY, 147, 60,
- 56, 10, TRUE, m) &&
- (topg = AddRadio(&gl, 0, "top", TRUE, SELECTED * (this->jy == top), REL
- VERIFY, 512 + 1024, 210, 60, 10, 10, m)) &&
- (ctryg = AddRadio(&gl, 0, "centre", TRUE, SELECTED * (this->jy == centr
- e), RELVERIFY, 256 + 1024, 260, 60, 10, 10, m)) &&
- (bottomg = AddRadio(&gl, 0, "bottom", TRUE, SELECTED * (this->jy == bot
- tom), RELVERIFY, 256 + 512, 326, 60, 10, 10, m)) &&
- AddText(&gl, 0, "Colour ", FALSE, colour, INTLEN, TRUE, 0, RELVERIFY, 2
- 36, 80, 32, 10, TRUE, m) &&
- AddText(&gl, 0, "Size ", FALSE, fheight, INTLEN, TRUE, 0, RELVERIFY, 22
- 0, 150, 32, 10, TRUE, m) &&
- AddList(&gl, FONTLIST, "Font", &flist, fname, FONTLEN, 0, RELVERIFY, 11
- , 80, 160, 80, TRUE, m) &&
- AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 255, 100, 65, 15, FAL
- SE, m) &&
- AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 255, 130, 65, 15
- , FALSE, m))
- {
- SetReqGadgets(req, gl);
- if (ret = DoRequest(req, this->o.g, edit_handler) && *stpblk(text) != '
- \0')
- {
- /* Update label */
- double new;
- int fh;
- struct TextFont *newfont;
-
- add_region(this); /* Refresh needed at old pos */
-
- /* New justification, etc */
- if ((this->colour = str2int(colour)) == INOVAL) this->colour = 1;
- strcpy(this->text, text);
- if ((new = str2double(x)) != NOVAL) this->x = new;
- if ((new = str2double(y)) != NOVAL) this->y = new;
- if ((this->dx = str2double(dx)) == NOVAL) this->dx = 0.0;
- if ((this->dy = str2double(dy)) == NOVAL) this->dy = 0.0;
-
- if (leftg->Flags & SELECTED) this->jx = top;
- else if (ctrxg->Flags & SELECTED) this->jx = centre;
- else this->jx = bottom;
-
- if (topg->Flags & SELECTED) this->jy = top;
- else if (ctryg->Flags & SELECTED) this->jy = centre;
- else this->jy = bottom;
-
- /* Check font */
- addfont(fname);
- if ((fh = str2int(fheight)) == INOVAL || fh <= 0) fh = LABELHEIGHT;
-
- if (newfont = open_font(this->o.g, fname, fh, 0, 0))
- {
- strcpy(this->fname, fname);
- this->fheight = fh;
- CloseFont(this->font);
- this->font = newfont;
- }
- else message(this->o.g, "Invalid font specified", (char *)NULL);
-
- /* Do precalculation */
- setup_label(this);
- calc_rect(this);
- add_region(this); /* New position needs refreshing */
- }
- }
- Free(m);
- *ref = this->ref;
- return ret;
- }
-
- /* No vsriables used in labels */
- int var_change_label(struct label *this, char *name)
- {
- return FALSE;
- }
-
- /* Confirm changes made */
- static void confirm_label(struct label *this, int ok)
- {
- if (ok)
- {
- CloseFont(this->font);
- this->font = this->newfont;
- setup_label(this);
- }
- else CloseFont(this->newfont); /* failed */
- }
-
- /* Resolution has changed */
- static int inform_label(struct label *this, int ok)
- {
- if (this->newfont = open_font(this->o.g, this->fname, this->fheight, 0, 0))
-
- return TRUE;
-
- message(this->o.g, "Couldn't open font", (char *)NULL);
- return FALSE;
-
- }
-
- /* Write label to file */
- static int save_label(struct label *this, FILE *f)
- {
- short tag = LABEL_TAG;
- short end = LABEL_END;
-
- return WRITE(f, tag) &&
- WRITE(f, this->text) &&
- WRITE(f, this->colour) &&
- WRITE(f, this->fname) &&
- WRITE(f, this->fheight) &&
- WRITE(f, this->x) &&
- WRITE(f, this->y) &&
- WRITE(f, this->dx) &&
- WRITE(f, this->dy) &&
- WRITE(f, end);
- }
-
- /* free label */
- static struct Region *delete_label(struct label *this)
- {
- struct Region *ref;
-
- /* Label's position will need refreshing */
- this->ref = NULL;
- if (this->o.g->ok && this->o.g->io.rw) add_region(this);
- ref = this->ref;
-
- if (this->font) CloseFont(this->font);
- FreeMem(this, sizeof(struct label));
-
- return ref;
- }
-
- /* Initialise label structure */
- static struct label *make_label(struct graph *g)
- {
- struct label *this = AllocMem(sizeof(struct label), 0L);
- const static struct label def_l = {
- {
- { NULL },
- NULL, "", TRUE, 0, 0,
- (void *)delete_label, (void *)select_label, (void *)deselect_label,
-
- (void *)down_label, (void *)move_label, (void *)up_label,
- (void *)edit_label, (void *)draw_label, (void *)notdone,
- (void *)notdone, (void *)var_change_label, (void *)save_label,
- (void *)inform_label, (void *)confirm_label
- },
- "", 1, LABELFONT, LABELHEIGHT, NOVAL, NOVAL, 0.0, 0.0, FALSE
- };
-
- if (this)
- {
- *this = def_l;
- this->o.g = g;
- /* Default font *must* be there */
- if (this->font = open_font(g, LABELFONT, LABELHEIGHT, 0, 0))
- {
- return this;
- }
- else
- message(g, "Couldn't open font", (char *)NULL);
- FreeMem(this, sizeof(struct label));
- }
- else
- message(g, "No memory !", (char *)NULL);
- return NULL;
- }
-
- /* Load label from file */
- struct label *load_label(struct graph *g, FILE *f)
- {
- struct label *this = make_label(g);
-
- if (this)
- {
- short tag;
-
- if (READ(f, this->text) &&
- READ(f, this->colour) &&
- READ(f, this->fname) &&
- READ(f, this->fheight) &&
- READ(f, this->x) &&
- READ(f, this->y) &&
- READ(f, this->dx) &&
- READ(f, this->dy) &&
- READ(f, tag) &&
- tag == LABEL_END)
- {
- struct TextFont *newfont;
-
- if (newfont = open_font(this->o.g, this->fname, this->fheight, 0, 0
- ))
- {
- CloseFont(this->font);
- this->font = newfont;
- }
- else /* Lack of font isn't drastic */
- {
- message(g, "No such font available", this->fname, (char *)NULL)
- ;
- strcpy(this->fname, LABELFONT);
- }
- setup_label(this);
- return this;
- }
- delete_label(this);
- }
- return NULL;
- }
-
- /* Create a new label, at pos. (x,y). Asks user for text */
- struct label *new_label(struct graph *g, double x, double y)
- {
- struct label *this = make_label(g);
-
- if (this)
- {
- /* Create requester */
- struct Requester *req;
- struct Memory *m;
- struct Gadget *gl = NULL;
- int ret = FALSE;
-
- this->x = x;
- this->y = y;
-
- if ((m = NewMemory()) &&
- (req = InitReq(50, 20, 160, 65, m)) &&
- SetReqBorder(req, 1, m) &&
- AddIntuiText(&req->ReqText, "Add Label", 44, 6, m) &&
- AddText(&gl, TRUE, "Text ", FALSE, this->text, LABELLEN, TRUE, 0, R
- ELVERIFY | ENDGADGET, 49, 20, 100, 10, TRUE, m) &&
- AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 8, 40, 65, 15, FA
- LSE, m) &&
- AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 88, 40, 65,
- 15, FALSE, m))
- {
- SetReqGadgets(req, gl);
- if (ret = DoRequest(req, g, std_ghandler) && *stpblk(this->text) !=
- '\0')
- {
- /* Create it */
- setup_label(this);
- if (g->ok && g->io.rw) draw_label(this, TRUE);
- Free(m);
- return this;
- }
- }
- Free(m);
- delete_label(this);
- }
- else
- message(g, "No memory !", (char *)NULL);
- return NULL;
- }
-
-