rs@uunet.UU.NET (Rich Salz) (08/06/87)
Submitted-by: "Alan W. Paeth" <awpaeth%watcgl.waterloo.edu@RELAY.CS.NET>
Posting-number: Volume 10, Issue 92
Archive-name: lemming/Part02
#!/bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #!/bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
# lemmain.c
# lemmark.c
# lemmisc.c
# lemobj.c
# lemobjsup.c
# lemop.c
# lempic.c
# lemrc.c
# lemselect.c
# lemspecial.c
# lemstart.c
# lemstop.c
# lemtext.c
# lemtick.c
# lemundo.c
# lemvec.c
# lemx.c
# This archive created: Fri Jun 12 18:35:10 1987
# By: watcgl!awpaethexport PATH; PATH=/bin:$PATH
if test -f 'lemmain.c'
then
echo shar: over-writing existing file "'lemmain.c'"
fi
cat << \SHAR_EOF > 'lemmain.c'
/*
* lemmain.c - little editor for mice and other furry rodents (aka lemming)
*
* copyright (c) by Alan W. Paeth, 1987. All rights reserved.
*/
#include "lem.h"
main(argc, argv)
char **argv;
{
int x, y, xup, yup, mup;
int event, near, drag, dragdist;
char ch;
startup(argc, argv);
while(1)
{
event = getevent(&x, &y, &xup, &yup, &ch);
if (event != NOEVT) msgclear();
switch(event)
{
case NOEVT: idle(); break;
case ALPHA: charadd(line, ch); break;
case CNTRL: switch(ch)
{
case C(Q): if (quitconfirm()) break;
case C(A): all(SELECT, 0); break;
case C(B): remake(BOX); break;
case C(C): copysel(); break;
case C(D): objcompress(); all(DELETE, 0); undo=UNDODEL; break;
case C(E): remake(ELLI); break;
case C(F): forceattr(); break;
case C(G): addgroup(); break;
case '\177': /* <DEL> */
case C(H): chardel(line,1); break; /* <BS> */
case C(I): cycleselect(); markdelete(); break; /* <TAB> */
case C(J): /* <LF>, */
case C(M): if (markon) stringadd(); break; /* <CR> */
/* case C(K): curveify(); break; */
case C(L): redraw(); break;
case C(N): all(DESELECT, 0); break;
case C(O): writepic(); break;
case C(P): removegroup(); break;
case C(R): readfile(); break;
case C(S): specialfunc(); break;
case C(T): tickset(); break;
case C(U): undocmd(); break;
case C(V): remake(LINE); break;
case C(W): writefile(); break;
case C(X): cutlines(); break;
case C([): all(DESELECT, 0); markdelete(); break; /* <ESC> */
case C(^): help(); break; /* ^^ */
default: break;
} break;
case MOUSE: markobj = objnearany(x, y);
near = markon && (dist(x, y, markx, marky) < MARKTOL);
dragdist = near ? (anysel ? 0 : MARKTOL) : DRAGTOL;
drag = dist(x,y,xup,yup) > dragdist;
if (markobj) objectalign(markobj, &x, &y); else spacealign(&x, &y);
if (drag) /* drag stuff */
{
if (near)
{
markhide(); /* for cleaner update */
mup = objnearany(xup, yup);
if (mup && (mup != markobj)) objectalign(mup, &xup, &yup);
else spacealign(&xup, &yup);
if (anysel) moveselect(xup-markx, yup-marky);
else if (markobj) tugunselect(markx, marky, xup, yup);
markupdate(xup, yup);
}
else rectselect(x, y, xup, yup);
}
else /* draw (move mark) cases */
{
if (near) markdelete();
else
{
markhide(); /* for cleaner update */
if (markon && !anysel) lineadd(markx, marky, x, y);
markupdate(x, y);
}
}
break;
}
}
}
SHAR_EOF
if test -f 'lemmark.c'
then
echo shar: over-writing existing file "'lemmark.c'"
fi
cat << \SHAR_EOF > 'lemmark.c'
/*
* lemmark.c - mark control
*
* copyright (c) by Alan W. Paeth, 1987. All rights reserved.
*/
#include "lem.h"
markadd(x, y)
{
markdraw(x, y, markobj ? MARKONOBJCOL : MARKONREGCOL);
markx = x;
marky = y;
markon = 1;
}
markdelete()
{
markhide();
markon = 0;
}
markhide()
{
if (markon) markdraw(markx, marky, MARKOFFCOL);
}
markupdate(x, y)
{
markdelete();
markobj = objnearany(x, y);
markadd(x, y);
}
markdraw(x, y, col)
{
drawvec(x-MARKSIZE, y, x+MARKSIZE, y, col, 1, EMPHNONE);
drawvec(x, y-MARKSIZE, x, y+MARKSIZE, col, 1, EMPHNONE);
}
SHAR_EOF
if test -f 'lemmisc.c'
then
echo shar: over-writing existing file "'lemmisc.c'"
fi
cat << \SHAR_EOF > 'lemmisc.c'
/*
* lemmisc.c - low-level routines
*
* copyright (c) by Alan W. Paeth, 1987. All rights reserved.
*/
#include "lem.h"
redraw()
{
int i;
erase();
if (tickflag) tickdraw();
forobjects
{
objectop(i, UNDEL, UNDEL);
objectop(i, SEL, SEL);
}
if (markon) markadd(markx, marky);
}
idle()
{
}
SHAR_EOF
if test -f 'lemobj.c'
then
echo shar: over-writing existing file "'lemobj.c'"
fi
cat << \SHAR_EOF > 'lemobj.c'
/*
* lemobj.c - object dispatch
*
* copyright (c) by Alan W. Paeth, 1987. All rights reserved.
*/
#include "lem.h"
objresize(i)
{
switch(Otype)
{
case LINE: lineresize(i); break;
case TEXT: textresize(i); break;
case BOX: boxresize(i); break;
case ELLI: elliresize(i); break;
}
}
objnearpt(i, x, y)
{
switch(Otype)
{
case LINE: return(linenearpt(i, x, y)); break;
case TEXT: return(textnearpt(i, x, y)); break;
case BOX: return( boxnearpt(i, x, y)); break;
case ELLI: return(ellinearpt(i, x, y)); break;
}
}
objinrect(i, xl, yl, xh, yh)
{
switch(Otype)
{
case TEXT: return(textinrect(i, xl, yl, xh, yh)); break;
case LINE: return(lineinrect(i, xl, yl, xh, yh)); break;
case BOX: return( boxinrect(i, xl, yl, xh, yh)); break;
case ELLI: return(elliinrect(i, xl, yl, xh, yh)); break;
}
}
objcantug(i, x, y)
{
switch(Otype)
{
case TEXT: return(textcantug(i, x, y)); break;
case LINE: return(linecantug(i, x, y)); break;
case BOX: return( boxcantug(i, x, y)); break;
case ELLI: return(ellicantug(i, x, y)); break;
}
}
objtug(i, xs, ys, xe, ye)
{
switch(Otype)
{
case TEXT: texttug(i, xs, ys, xe, ye); break;
case LINE: linetug(i, xs, ys, xe, ye); break;
case BOX: boxtug(i, xs, ys, xe, ye); break;
case ELLI: ellitug(i, xs, ys, xe, ye); break;
}
}
objectalign(i, x, y)
int *x, *y;
{
switch(Otype)
{
case TEXT: textalign(i, x, y); break;
case BOX: boxalign(i, x, y); break;
case LINE: linealign(i, x, y); break;
case ELLI: ellialign(i, x, y); break;
}
}
objmove(i, x, y)
{
switch(Otype)
{
case LINE: linemove(i, x, y); break;
case TEXT: textmove(i, x, y); break;
case BOX: boxmove(i, x, y); break;
case ELLI: ellimove(i, x, y); break;
}
}
objaffine(i, m11, m12, m21, m22)
float m11, m12, m21, m22;
{
switch(Otype)
{
case LINE: lineaffine(i, m11, m12, m21, m22); break;
case TEXT: textaffine(i, m11, m12, m21, m22); break;
case BOX: boxaffine(i, m11, m12, m21, m22); break;
case ELLI: elliaffine(i, m11, m12, m21, m22); break;
}
}
objdraw(i, col)
{
switch(Otype)
{
case LINE: linedraw(i, col); break;
case TEXT: textdraw(i, col); break;
case BOX: boxdraw(i, col); break;
case ELLI: ellidraw(i, col); break;
}
}
SHAR_EOF
if test -f 'lemobjsup.c'
then
echo shar: over-writing existing file "'lemobjsup.c'"
fi
cat << \SHAR_EOF > 'lemobjsup.c'
/*
* lemobjsup.c - superclass for generic object operations
*
* copyright (c) by Alan W. Paeth, 1987. All rights reserved.
*/
#include <math.h> /* to define "double floor()" */
#include "lem.h"
objsupnearpt(i, x, y)
{
if (ptinrect(x, y, Oxl, Oyl, Oxh, Oyh, LINETOL) == 0) return(0);
return(1);
}
objsupinrect(i, xl, yl, xh, yh)
{
return(ptinrect(Oxl, Oyl, xl, yl, xh, yh, LINETOL) &&
ptinrect(Oxh, Oyh, xl, yl, xh, yh, LINETOL));
}
objsupcantug(i, x, y)
{
return(objnearpt(i, x, y));
}
objsuptug(i, xs, ys, xe, ye)
{
if (dist(Oxs, Oys, xs, ys) < TUGPROX) objmove(i, xe-xs, ye-ys);
}
objsupalign(i, x, y)
int *x, *y;
{
if (dist(Oxs, Oys, *x, *y) < ENDTOL)
{
*x = Oxs;
*y = Oys;
}
}
objsupmove(i, x, y)
{
Oxs += x;
Oxe += x;
Oys += y;
Oye += y;
}
objsupaffine(i, m11, m12, m21, m22, both)
float m11, m12, m21, m22;
{
float x1, y1;
if (both)
{
x1 = floor((m11*Oxs + m12*Oys) + 0.5);
y1 = floor((m21*Oxs + m22*Oys) + 0.5);
Oxs = x1;
Oys = y1;
x1 = floor((m11*Oxe + m12*Oye) + 0.5);
y1 = floor((m21*Oxe + m22*Oye) + 0.5);
Oxe = x1;
Oye = y1;
}
else
{
x1 = floor((m11*Oxcen + m12*Oycen) + 0.5);
y1 = floor((m21*Oxcen + m22*Oycen) + 0.5);
/*
* move only the center point, don't the other endpoint
* (presumably object dimensions -- this is a text element).
*/
objmove(i, (int)(x1-Oxcen), (int)(y1-Oycen));
}
}
SHAR_EOF
if test -f 'lemop.c'
then
echo shar: over-writing existing file "'lemop.c'"
fi
cat << \SHAR_EOF > 'lemop.c'
/*
* lemop.c - operate on objects (and update the display)
*
* copyright (c) by Alan W. Paeth, 1987. All rights reserved.
*/
#include "lem.h"
objectop(i, instatus, outstatus)
{
int col;
if (i && (Ostat == instatus))
{
if ( instatus == SEL) anysel--;
if (outstatus == SEL) anysel++;
Ostat = outstatus;
switch(Ostat)
{
case DEL: col = ERASECOL; break;
case UNDEL: col = DRAWCOL; break;
case SEL: col = SELECTCOL; break;
}
objdraw(i, col);
if (Odel && (i == markobj)) markobj = 0;
changes |= ( (instatus == DEL) || (outstatus == DEL) );
if ( instatus == DEL)
return(1);
}
return(0);
}
any(i, opcode)
{
if (Ogroup) all(opcode, Ogroup);
else
switch(opcode)
{
case SELECT: objectop(i, UNDEL, SEL); break;
case DESELECT: objectop(i, SEL, UNDEL); break;
case DELETE: objectop(i, SEL, DEL); break;
case UNDELETE: objectop(i, DEL, SEL); break;
}
}
all(opcode, group)
{
int i, saveg;
forobjects
{
if (!group || Ogroup == group)
{
saveg = Ogroup;
Ogroup = 0;
any(i, opcode);
Ogroup = saveg;
}
}
}
SHAR_EOF
if test -f 'lempic.c'
then
echo shar: over-writing existing file "'lempic.c'"
fi
cat << \SHAR_EOF > 'lempic.c'
/*
* lempic.c - PIC output processor
*
* copyright (c) by Alan W. Paeth, 1987. All rights reserved.
*/
#include "lem.h"
#define PTSSCALE 96.0
#define PENSCALE 12 /* ln03 dimp troff drivers like 13 (!a common PntSz) */
int curx, cury, curw, curh, ps, pemph;
FILE *f;
writepicint(fname)
char *fname;
{
int i;
f = (fname && (strlen(fname) > 1)) ? fopen(fname, "w") : 0;
if (f)
{
curx = cury = curw = curh = ps = pemph= -1;
fprintf(f, ".PS\n");
forobjects
{
if (Odel) continue;
switch (Otype)
{
case TEXT: ptext(i);
at(Oxs, Oys);
break;
case LINE: thick(i);
pline(i);
em(i);
from(Oxs, Oys);
to(Oxe, Oye);
break;
case BOX: thick(i);
fprintf(f, "box");
em(i);
at(Ox, Oy);
size(Ow, Oh);
break;
case ELLI: thick(i);
fprintf(f, "ellipse");
em(i);
at(Ox, Oy);
size(Ow,Oh);
break;
}
fprintf(f, ";\n");
}
fprintf(f, ".PE\n");
fclose(f);
msgpost("pic output done");
}
else msgpost("pic output failed");
free(fname);
}
writepic()
{
char *fname;
fname = prompt("pic file: ");
writepicint(fname);
free(fname);
}
thick(i)
{
if (ps != lemfont[Osizer].thick)
{
ps = lemfont[Osizer].thick;
fprintf(f, ".ps %d\n", ps*PENSCALE);
}
}
pt(x, y)
{
fprintf(f, " %.3fi,%.3fi", (float)(x)/PTSSCALE, (float)(y)/PTSSCALE);
}
at(x, y)
{
fprintf(f, " at");
pt(x, y);
}
from(x, y)
{
if ((x == curx) && (y == cury)) return;
fprintf(f, " from");
pt(x, y);
curx = x;
cury = y;
}
to(x, y)
{
fprintf(f, " to");
pt(x,y);
curx = x;
cury = y;
}
size(w, h)
{
w = ABS(w);
h = ABS(h);
if ((w == curw) && (h == curh)) fprintf(f, " same");
else
{
fprintf(f, " wid %.3fi ht %.3fi",
(float)(w)/PTSSCALE, (float)(h)/PTSSCALE);
curw = w;
curh = h;
}
}
ptext(i)
{
int fontflag;
char *ft;
fontflag = ((Oemph != pemph) || (lemfont[Osizer].psize != ps));
pemph = Oemph;
ps = lemfont[Osizer].psize;
fprintf(f, "\"");
if (fontflag)
{
switch(Oemph)
{
case EMPHNONE: ft = lemfont[Osizer].tyr; break;
case EMPHBOLD: ft = lemfont[Osizer].tyb; break;
case EMPHITAL: ft = lemfont[Osizer].tyi; break;
}
fprintf(f, "\\f%s%s", strlen(ft) > 1 ? "(" : "", ft );
}
fprintf(f, "\\s%d%s\"",lemfont[Osizer].psize, Otext);
switch(Oalign)
{
case ALIGNLEFT: fprintf(f, " ljust"); break;
case ALIGNRGHT: fprintf(f, " rjust"); break;
case ALIGNCENT:
default: break;
}
}
pline(i)
{
fprintf(f, "line");
switch(Oalign)
{
case ALIGNLEFT: fprintf(f, " <-"); break;
case ALIGNRGHT: fprintf(f, " ->"); break;
case ALIGNCENT:
default: break;
}
}
em(i)
{
switch(Oemph)
{
case EMPHBOLD: fprintf(f, " dashed"); break;
case EMPHITAL: fprintf(f, " dotted"); break;
case EMPHNONE:
default: break;
}
}
SHAR_EOF
if test -f 'lemrc.c'
then
echo shar: over-writing existing file "'lemrc.c'"
fi
cat << \SHAR_EOF > 'lemrc.c'
/*
* lemrc.c - get default fonts from local file.
*
* copyright (c) by Alan W. Paeth, 1987. All rights reserved.
*/
#include "lem.h"
#include "lemfont.h"
#define FONTPATH "/usr/local/lib/BFont/"
#define FONTEXTN ".bf"
char *getenv();
leminit()
{
char rcname[100], rcline[RCLINE];
FILE *f;
int i, items;
/*
* generate local and global names
*/
sprintf(rcname, "./%s", RCNAME);
f = fopen(rcname, "r");
if (!f)
{
sprintf(rcname, "%s/%s", getenv("HOME"), RCNAME);
f = fopen(rcname, "r");
}
if (!f)
{
/* err("no %s file exists", RCGLOBAL); */
lemfont[1].psize = DEFPSIZEFT;
lemfont[1].thick = DEFDENSEFT;
lemfont[1].dsp = DEFIKRFT;
lemfont[1].tyr = DEFTYRFT;
lemfont[1].tyb = DEFTYBFT;
lemfont[1].tyi = DEFTYIFT;
lemfont[1].psr = DEFPSRFT;
lemfont[1].psb = DEFPSBFT;
lemfont[1].psi = DEFPSIFT;
rclen = 1;
}
else
{
while(1)
{
char dsp[20], tyr[20], tyb[20], tyi[20];
char psr[20], psb[20], psi[20];
fgets(rcline, RCLINE, f);
if (feof(f)) break;
if ((rcline[0] >= '0') && (rcline[0] <= '9'))
{
rclen++;
if (rclen >= RCLEN) err(".rc file too long");
items = sscanf(rcline, "%d %d %s %s %s %s %s %s %s",
&lemfont[rclen].psize, &lemfont[rclen].thick,
dsp, tyr, tyb, tyi, psr, psb, psi);
if (items != RCWIDTH) err("wrong line length in .rc file");
lemfont[rclen].dsp = salloc(dsp);
lemfont[rclen].tyr = salloc(tyr);
lemfont[rclen].tyb = salloc(tyb);
lemfont[rclen].tyi = salloc(tyi);
lemfont[rclen].psr = salloc(psr);
lemfont[rclen].psb = salloc(psb);
lemfont[rclen].psi = salloc(psi);
}
}
if (rclen == 0) err(".lemrc file was empty");
}
rclen++;
if (f) fclose(f);
/*
* now set up default display fonts
*/
for (i=1; i<rclen; i++)
{
char fontname[100];
sprintf(fontname, "%s%s%d%s",
FONTPATH, lemfont[i].dsp, lemfont[i].psize, FONTEXTN);
bfont[i] = fontload(fontname);
if (!bfont[i]) err("can't load font \"%s\"", fontname);
}
}
SHAR_EOF
if test -f 'lemselect.c'
then
echo shar: over-writing existing file "'lemselect.c'"
fi
cat << \SHAR_EOF > 'lemselect.c'
/*
* lemselect.c - object selection and proximity testing
*
* copyright (c) by Alan W. Paeth, 1987. All rights reserved.
*/
#include "lem.h"
cycleselect()
{
if (markobj)
{
if (objs[markobj]->stat == UNDEL) any(markobj, SELECT);
else if (objs[markobj]->stat == SEL) any(markobj, DESELECT);
}
}
rectselect(x0, y0, x1, y1)
{
int i, mode, xl, yl, xh, yh;
xl = MIN(x0, x1);
yl = MIN(y0, y1);
xh = MAX(x0, x1);
yh = MAX(y0, y1);
mode = (y0 < y1) ? DESELECT : SELECT;
forobjects
{
if (objinrect(i, xl, yl, xh, yh)) any(i, mode);
}
}
objnearany(x, y)
{
int i;
if (i = objnear(x, y, UNDEL)) return(i);
return(objnear(x, y, SEL));
}
objnear(x, y, stat)
{
int i;
forobjsrev /* reverse order search - most recent appears first */
{
if (Ostat == stat)
{
if (objnearpt(i, x, y)) return(i);
}
}
return(0);
}
SHAR_EOF
if test -f 'lemspecial.c'
then
echo shar: over-writing existing file "'lemspecial.c'"
fi
cat << \SHAR_EOF > 'lemspecial.c'
/*
* lemspecial.c - extra functions for random applications
*
* copyright (c) by Alan W. Paeth, 1987. All rights reserved.
*/
#include "lem.h"
#include <math.h>
specialfunc()
{
char ch;
msgpost("<F>lip <C>cw <M>agnify <R>otate <S>tretch <A>lign: ");
ch = getstroke();
switch(UC(ch))
{
case 'F': flip(); break;
case 'C': ccw(); break;
case 'M': magnify(); break;
case 'R': rotate(); break;
case 'S': stretch(); break;
case 'A': align(); break;
default: msgpost("unknown transformation"); break;
}
}
transform(m11, m12, m21, m22)
float m11, m12, m21, m22;
{
int i;
/*
* record inverse transformation and set undo flag for undoing
*/
undo = UNDOAFF;
unx = markx;
uny = marky;
un11 = m11;
un12 = m12;
un21 = m21;
un22 = m22;
/*
* now do the transformations
*/
forobjects
{
if (Osel)
{
objectop(i, SEL, DEL);
objmove(i, -markx, -marky);
objaffine(i, m11, m12, m21, m22);
objmove(i, markx, marky);
objresize(i);
objectop(i, DEL, SEL);
}
}
}
flip()
{
if (markon)
{
transform(-1.0, 0.0, 0.0, 1.0, 1);
msgpost("flip done");
}
else msgpost("flip -- no mark present");
}
ccw()
{
if (markon)
{
transform(0.0, -1.0, 1.0, 0.0, 0);
msgpost("ccw turn done");
}
else msgpost("ccw -- no mark present");
}
magnify()
{
int x1, y1, x2, y2, xs, ys, xe, ye;
float mag, outlen;
if (findmark(&x1, &y1, &x2, &y2))
{
xs = x2-markx;
ys = y2-marky;
xe = x1-markx;
ye = y1-marky;
outlen = xs*xs+ys*ys;
if (outlen != 0.0)
{
mag = sqrt((float)(xe*xe+ye*ye)/outlen);
mag = (mag < 0.1) ? 0.1 : (mag > 10.0 ? 10.0 : mag);
transform(mag, 0.0, 0.0, mag, 1);
msgpost("magnify done");
}
msgpost("null magnify ignored");
}
}
stretch()
{
int x1, y1, x2, y2, xs, ys, xe, ye;
float xmag, ymag;
if (findmark(&x1, &y1, &x2, &y2))
{
xs = x2-markx;
ys = y2-marky;
xe = x1-markx;
ye = y1-marky;
xmag = (xs == 0) ? 1.0 : (float)(xe)/xs;
ymag = (ys == 0) ? 1.0 : (float)(ye)/ys;
xmag = (xmag < 0.1) ? 0.1 : (xmag > 10.0 ? 10.0 : xmag);
ymag = (ymag < 0.1) ? 0.1 : (ymag > 10.0 ? 10.0 : ymag);
transform(xmag, 0.0, 0.0, ymag, 1);
msgpost("stretch done");
}
}
rotate()
{
int x1, y1, x2, y2, xs, ys, xe, ye;
float s, c, hy;
if (findmark(&x1, &y1, &x2, &y2))
{
xs = x2-markx;
ys = y2-marky;
xe = x1-markx;
ye = y1-marky;
hy = sqrt((float)( (xs*xs + ys*ys) * (xe*xe + ye*ye) ));
if (hy != 0.0)
{
c = (xs*xe+ys*ye)/hy;
s = (xs*ye-xe*ys)/hy;
transform(c, -s, s, c, 0);
msgpost("rotate done");
}
else msgpost("null rotation ignored");
}
}
align()
{
int x1, y1, x2, y2, xs, ys, xe, ye, scale;
float m11, m12, m21, m22, det;
if (findmark(&x1, &y1, &x2, &y2))
{
xs = x2-markx;
ys = y2-marky;
xe = x1-markx;
ye = y1-marky;
scale = MAX(MAX(ABS(xs),ABS(ys)),MAX(ABS(xe),ABS(ye)));
det = xe*ys - xs*ye;
m11 = (float)( ys*scale)/det;
m12 = (float)(-xs*scale)/det;
m21 = (float)(-ye*scale)/det;
m22 = (float)( xe*scale)/det;
transform(m11, m12, m21, m22, 1);
msgpost("align done");
}
}
findmark(x1, y1, x2, y2)
int *x1, *y1, *x2, *y2;
{
int i, s, e, arrow, straight;
arrow = straight = 0;
if (!markon)
{
msgpost("transform: no mark present");
return(0);
}
else
{
forobjects
{
if (Otype != LINE) continue;
s = (Oxs == markx) && (Oys == marky);
e = (Oxe == markx) && (Oye == marky);
if (s || e)
{
switch (Oalign)
{
case ALIGNCENT: *x1 = s ? Oxe : Oxs;
*y1 = s ? Oye : Oys;
straight++;
break;
case ALIGNLEFT: if (s)
{
msgpost("transform: arrowhead at origin");
return(0);
}
*x2 = Oxs;
*y2 = Oys;
arrow++;
break;
case ALIGNRGHT: if (e)
{
msgpost("transform: arrowhead at origin");
return(0);
}
*x2 = Oxe;
*y2 = Oye;
arrow++;
break;
}
}
}
}
if ((arrow == 1) && (straight == 1)) return(1);
/*
* errors
*/
if (arrow+straight == 0)
msgpost("transform: no basis vectors at mark");
else if (arrow != 1)
msgpost("transform: exactly one arrow basis vector needed");
else if (straight != 1)
msgpost("transform: exactly one non-arrow basis vector needed");
return(0);
}
SHAR_EOF
if test -f 'lemstart.c'
then
echo shar: over-writing existing file "'lemstart.c'"
fi
cat << \SHAR_EOF > 'lemstart.c'
/*
* lemstart.c - check command line, plus some housecleaning
*
* copyright (c) by Alan W. Paeth, 1987. All rights reserved.
*/
#include "lem.h"
startup(argc, argv)
char **argv;
{
int i, plotmode;
plotmode = 0;
/*
* initialize based on probable .rc file
*/
leminit();
/*
* set up object defaults
*/
lastobj = 1; /* no objects */
setattr('0'); /* default attr's (as if '0' typed) */
gtype = LINE; /* draw lines by default */
undo = UNDONONE; /* no operation to undo */
/*
* start user code and refresh the display
*/
start();
redraw();
/*
* command line prompt
*/
msgpost("lemming ver 1 -- 'ctrl ^' for help");
/*
* possible file name on cmd line
*/
changes = 0; /* no changes at present */
/*
* do all command line parsing
*/
for(i=1; i<argc; i++)
{
if (argv[i][0] == '-')
{
switch(argv[i][1])
{
case 'p':
case 'P': plotmode = 1; break;
default: err("unknown command line flag"); break;
}
}
else
{
if (!firstfile) firstfile = argv[i]; /* record first input file */
readfileint(argv[i]);
}
}
if (plotmode)
{
char outname[80];
sprintf(outname, "%s.pic", firstfile);
writepicint(outname);
stop();
exit(0);
}
}
SHAR_EOF
if test -f 'lemstop.c'
then
echo shar: over-writing existing file "'lemstop.c'"
fi
cat << \SHAR_EOF > 'lemstop.c'
/*
* lemstop.c - quit and error returns from lemming.
*
* copyright (c) by Alan W. Paeth, 1987. All rights reserved.
*/
#include "lem.h"
quitconfirm()
{
char c;
if (changes)
{
msgpost("quit: [y] to confirm: ");
c = getstroke();
if (UC(c) != 'Y')
{
msgpost("quit aborted.");
return(1);
}
}
markdelete();
stop();
exit(0);
}
err(msg, arg)
char *msg;
{
fprintf(stderr, "\nlem: ", msg, arg);
fprintf(stderr, msg, arg);
fprintf(stderr, "\n");
exit(1);
}
SHAR_EOF
if test -f 'lemtext.c'
then
echo shar: over-writing existing file "'lemtext.c'"
fi
cat << \SHAR_EOF > 'lemtext.c'
/*
* lemtext.c - text primitives
*
* copyright (c) by Alan W. Paeth, 1987. All rights reserved.
*/
#include "lem.h"
#include "lemfont.h"
textadd(x0, y0, s)
char *s;
{
int i;
if ((!s) || (strlen(s) == 0)) return;
i = objalloc(TEXT);
Otext = salloc(s);
Oxs = x0;
Oys = y0;
textresize(i);
objnew(i);
}
textresize(i)
{
Oxe = fontmeasure(bfont[Osizer], Otext, Oemph);
Oye = lemfont[Osizer].psize;
}
textnearpt(i, x, y)
{
return(ptinrect(x, y, Oxlt, Oylt, Oxht, Oyht, TEXTTOL)); /* must be ON the text */
}
textinrect(i, xl, yl, xh, yh)
{
return(ptinrect(Oxlt, Oylt, xl, yl, xh, yh, TEXTTOL) &&
ptinrect(Oxht, Oyht, xl, yl, xh, yh, TEXTTOL) );
}
textcantug(i, x, y)
{
return(textnearpt(i, x, y));
}
texttug(i, xs, ys, xe, ye)
{
Oxs += xe-xs;
Oys += ye-ys;
}
textalign(i, x, y)
int *x, *y;
{
*x = Oxs;
*y = Oys;
}
textmove(i, x, y)
{
Oxs += x;
Oys += y;
}
textaffine(i, m11, m12, m21, m22)
float m11, m12, m21, m22;
{
objsupaffine(i, m11, m12, m21, m22, 0);
}
textdraw(i, col)
{
fontwrite(Osizer, Oxlt, Oys, Otext, Oemph, col);
}
SHAR_EOF
if test -f 'lemtick.c'
then
echo shar: over-writing existing file "'lemtick.c'"
fi
cat << \SHAR_EOF > 'lemtick.c'
/*
* lemtick.c - perform ticking
*
* copyright (c) by Alan W. Paeth, 1987. All rights reserved.
*/
#include "lem.h"
#include "lemfont.h"
tickalign(x, y)
int *x, *y;
{
if (tickflag && (ticksize < 6))
{
tx = 1<<ticksize;
ty = 1<<ticksize;
*x = ((*x-txoff+tx/2) / tx) * tx + txoff;
*y = ((*y-tyoff+ty/2) / ty) * ty + tyoff;
}
if (tickflag && (ticksize >= 6))
{
int xl, yi, yl, d1, d2, d3, d4;
tx = 1<<(ticksize-3);
ty = (tx*14+7)/16;
yi = ((*y-tyoff)/ty);
yl = yi*ty + tyoff;
xl = (((*x-txoff+((yi&0x1)?tx/2:0))/tx)*tx-((yi&0x1)?tx/2:0))+txoff;
d1 = dist(*x,*y,xl ,yl);
d2 = dist(*x,*y,xl+tx/2 ,yl+ty);
d3 = dist(*x,*y,xl+tx ,yl);
d4 = dist(*x,*y,xl+3*tx/2,yl+ty);
if ((d1<=d2) && (d1<=d3) && (d1<=d4)) { *x = xl; *y = yl; }
if ((d2<=d1) && (d2<=d3) && (d2<=d4)) { *x = xl+tx/2; *y = yl+ty; }
if ((d3<=d1) && (d3<=d2) && (d3<=d4)) { *x = xl+tx; *y = yl; }
if ((d4<=d1) && (d4<=d2) && (d4<=d3)) { *x = xl+3*tx/2; *y = yl+ty; }
}
}
tickset()
{
char ch;
int tmpx, tmpy;
tickflag = !tickflag;
if (tickflag)
{
msgpost("ticksize[1-5/6-9]: ");
ch = getstroke();
msgclear();
if ((ch < '0') || (ch > '9'))
{
tickflag = 0;
return;
}
ticksize = ch - '0';
tmpx = markon ? markx : 0;
tmpy = markon ? marky : 0;
txoff = 0;
tyoff = 0;
tickalign(&tmpx, &tmpy); /* sets tx and ty as well */
txoff = (markon ? markx : 0) - tmpx;
tyoff = (markon ? marky : 0) - tmpy;
while (tyoff > 0) tyoff -= ty;
while (tyoff < 0) tyoff += ty;
while (txoff > 0) txoff -= tx;
while (txoff < 0) txoff += tx;
}
tickdraw();
if (!tickflag)
{
txoff = 0;
tyoff = 0;
}
}
tickdraw()
{
int x, y, xstep, ystep;
xstep = tx;
ystep = ty;
while (xstep<MINTICK) xstep *= 2;
while (ystep<MINTICK) ystep *= 2;
if (ticksize < 6)
{
for(y = tyoff ; y<screenh; y+=ystep)
for (x = txoff; x<screenw; x+=xstep)
{
drawvec(x, y, x + tickdot, y, tickflag ? TICKONCOL:TICKOFFCOL,
1,EMPHNONE); /* tickdot sets 0/1 width dot */
}
}
else
{
int ylim, iy;
ylim = screenh/ty;
y = tyoff;
for(iy=0; iy<ylim; iy++)
{
y += ty;
for (x = txoff + ((iy&0x1) ? 0 : (tx/2)); x<screenw; x+=tx)
if ((x>0) && (y>0))
drawvec(x, y, x + tickdot, y,
tickflag ? TICKONCOL:TICKOFFCOL,1,EMPHNONE);
}
}
}
SHAR_EOF
if test -f 'lemundo.c'
then
echo shar: over-writing existing file "'lemundo.c'"
fi
cat << \SHAR_EOF > 'lemundo.c'
/*
* lemundo.c - undo last operation
*
* copyright (c) by Alan W. Paeth, 1987. All rights reserved.
*/
#include "lem.h"
undocmd()
{
float d;
switch(undo)
{
case UNDOMOVE: moveselect(-unx, -uny);
break;
case UNDOTUG: tugunselect(unxe, unye, unx, uny);
break;
case UNDOAFF: d = (un11 * un22) - (un21 * un12);
if (d == 0.0) return; /* no-op if singular */
transform(un22/d, -un12/d, -un21/d, un11/d);
break;
case UNDODEL: all(UNDELETE, 0);
undo = UNDONONE;
break;
default: undo = UNDONONE;
case UNDONONE: msgpost("cannot undo last operation"); break;
}
}
SHAR_EOF
if test -f 'lemvec.c'
then
echo shar: over-writing existing file "'lemvec.c'"
fi
cat << \SHAR_EOF > 'lemvec.c'
/*
* lemvec.c - line to point scan conversion
*
* copyright (c) by Alan W. Paeth, 1987. All rights reserved.
*/
/*
*
* Programmed by Alan Paeth, University of Waterloo, January, 1984
*
* This code rasterizes vectors. A call of the form:
*
* drawline(x0, y0, x1, y1, wid, val, emph)
*
* with val the output color, and emph one of EMPHITAL, EMPHBOLD, (otherwise)
* generates a vector of specified which is dotted, dashed, or plain,
* respectively.
*
* output pixels are set by calls to:
*
* setpixelrun(x, y, wid, val, parity)
*
* which should set pixels (x,y) through (x+wid-1,y) to color (val) if
* parity is 0 (as it is at endpoints and some intermediate locations).
*
* viewport clipping is done (using integer math) to the dimensions specified
* in the globals "screenw" and "screenh"
*
*/
#include "lem.h"
#define Nextflag { mask>>=1; if (++flag >= 16) { flag = 0; mask = emph; } }
#define SOLID 0xffffffff /* only solid should have sign bit set */
#define DASHES 0x00ff00ff
#define DOTS 0x03030303
#define ONE 0x4000
#define POINT_FIVE 0x2000
#define SCALEUP 14
#define TOPFLAG 8
#define BOTTOMFLAG 4
#define LEFTFLAG 2
#define RIGHTFLAG 1
code(x, y)
float x, y;
{
int c = 0;
if (x < 0) c |= LEFTFLAG; else if (x >= screenw) c |= RIGHTFLAG;
if (y < 0) c |= BOTTOMFLAG; else if (y >= screenh) c |= TOPFLAG;
return c;
}
drawline(x1, y1, x2, y2, wid, val, emph) /* generic brand clipped line code */
{
int c, c1, c2;
long x, y;
if ((x1==x2) && (y1==y2)) return; /* no motion -- fast return */
c1 = code((float)(x1), (float)(y1));
c2 = code((float)(x2), (float)(y2));
while (c1 || c2)
{
if (c1 & c2) return; /* bitwise AND, not statement AND */
c = c1 ? c1 : c2;
if (c & LEFTFLAG)
y = y1 + ((y2 - y1) * ( (x = 0) - x1)) / (x2 - x1);
else if (c & RIGHTFLAG)
y = y1 + ((y2 - y1) * ( (x = screenw) - x1)) / (x2 - x1);
else if (c & TOPFLAG)
x = x1 + ((x2 - x1) * ( (y = screenh) - y1)) / (y2 - y1);
else if (c & BOTTOMFLAG)
x = x1 + ((x2 - x1) * ( (y = 0) - y1)) / (y2 - y1);
if (c == c1)
{
x1 = x;
y1 = y;
c1 = code(x, y);
}
else
{
x2 = x;
y2 = y;
c2 = code(x, y);
}
}
fastdrawline(x1, y1, x2, y2, wid, val, emph);
}
fastdrawline(x1, y1, x2, y2, wid, val, emph)
/*
*
* Draws a line of pixels=val from (x1, y1) to (x2, y2) very fast.
*
* This is algorithm A1 from "Filtering Edges for Grey-Scale Displays" by
* Gupta & Sproull (Computer Graphics 15,3 August 1981). No anti-aliasing
* is being done here. However the variable 'v' can be * used to turn on
* pixels to the left and right (above and below) the line since v is
* horizontal distance from the center of the line to the pixel at (x, y).
*
* Last Hacked by: Alan Paeth
*/
int x1, y1, x2, y2, val, emph;
{
register x, y; /* current position in line */
int incr; /* y increment = + or - 1 */
int dx, dy; /* change in x, y */
int m; /* slope of line ( * 2 ** 14 ) */
int s; /* threshold for diagonal move */
register v; /* dist from line to pixel */
int mm1; /* m - (1 << 9) */
int mask;
int flag;
flag = 0;
emph = (emph == EMPHITAL) ? DOTS : ((emph == EMPHBOLD) ? DASHES : SOLID);
mask = emph;
if (y2 > y1) /* make y1 > y2 by symmetries */
{
x = x1; x1 = x2; x2 = x;
y = y1; y1 = y2; y2 = y;
}
incr = 1;
dy = y1 - y2;
if ((dx = x2 - x1) < 0)
{
dx = -dx;
incr = -1;
}
v = 0;
if (dx > dy)
{
m = ((long)dy << SCALEUP) / (long)dx;
s = POINT_FIVE - m;
mm1 = m - ONE;
y = y1;
for( x = x1; x != x2; x += incr )
{
if (mask & 0x1) setpixelrunv(x, y, wid, val, flag & 0x1);
Nextflag;
if( v >= s ) { --y; v += mm1; } /* diagonal move */
else v += m; /* horizontal move */
}
setpixelrunv(x, y, wid, val, 0);
}
else
{
if( dy > 0 )
{
m = ((long)dx << SCALEUP) / (long)dy;
s = POINT_FIVE - m;
mm1 = m - ONE;
}
x = x1;
for( y = y1; y > y2; --y )
{
if (mask & 0x1) setpixelrunh(x, y, wid, val, flag&0x1);
Nextflag;
if ( v >= s ) { x += incr; v += mm1; } /* diagonal move */
else v += m; /* vertical move */
}
setpixelrunh(x, y, wid, val, 0);
}
}
SHAR_EOF
if test -f 'lemx.c'
then
echo shar: over-writing existing file "'lemx.c'"
fi
cat << \SHAR_EOF > 'lemx.c'
/*
* lemx.c - lemming driver for X window software
*
* copyright (c) by Alan W. Paeth, 1987. All rights reserved.
*/
#include "lem.h"
#include <X/Xlib.h>
#define EV (ButtonPressed | ButtonReleased | KeyPressed | ExposeWindow | ExposeRegion)
Window win;
int xsave, ysave, drawcol, erasecol, selectcol, markoncol, markoffcol, lut;
int sysmsgloc;
char sysmsg[120];
unsigned char maptab[256]; /* bit reversing table */
start()
{
screenw = 512;
screenh = 512;
if ((XOpenDisplay("")) == NULL) err("display open failed");
win = XCreateWindow(RootWindow, screenw/2, screenh/2, screenw, screenh,
2, WhitePixmap, BlackPixmap);
if (win == NULL) err("window open failed");
lut = DisplayCells() > 2;
XMapWindow(win);
XSelectInput(win, EV);
if (lut)
{
cblack = findcolor(0,0,0);
cwhite = findcolor(1,1,1);
cred = findcolor(1,0,0);
cgreen = findcolor(0,1,0);
tickdot = 0;
}
else
{
cwhite = 1;
cblack = 0;
cred = 2;
cgreen = 1;
tickdot = 1;
}
setcursor();
}
stop()
{
}
getevent(xdn, ydn, xup, yup, ch)
int *xdn, *ydn, *xup, *yup;
char *ch;
{
int ret, count;
XEvent ev;
XWindowEvent(win, EV, &ev);
ret = NOEVT;
switch(ev.type)
{
case ButtonPressed: xsave = mx(&ev);
ysave = my(&ev);
break;
case ButtonReleased: *xdn = xsave;
*ydn = ysave;
*xup = mx(&ev);
*yup = my(&ev);
ret = MOUSE;
break;
case KeyPressed: *ch = *XLookupMapping(&ev, &count);
if (*ch)
{
if ((*ch >= ' ') && (*ch != '\177'))
ret = ALPHA;
else if (*ch > 0) ret = CNTRL;
}
break;
case ExposeRegion:
case ExposeWindow: checkwindowsize();
redraw();
break;
}
XFlush();
return(ret);
}
checkwindowsize()
{
WindowInfo winfo;
XQueryWindow(win, &winfo);
screenw = winfo.width;
screenh = winfo.height;
}
setcursor()
{
Cursor c;
static short cur_bgnd[] = {
0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x03e0, 0x0630, 0x7c1f, 0x7c1f,
0x7c1f, 0x0630, 0x03e0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x0000 };
static short cur_fgnd[] = {
0x0080, 0x0080, 0x0080, 0x0080, 0x03e0, 0x0630, 0x0410, 0x7c1f,
0x0410, 0x0630, 0x03e0, 0x0080, 0x0080, 0x0080, 0x0080, 0x0000 };
c = XCreateCursor(16, 16, cur_fgnd, cur_bgnd, 7,7,cwhite,cblack,GXcopy);
XDefineCursor(win, c);
}
setpixelrunh(x0, y0, wid, col, dotflag)
{
if (col == cred)
{
col = (dotflag) ? cblack: cwhite; /* checkerboard select */
}
XPixSet(win, x0, (screenh-1)-y0, wid, 1, col);
}
setpixelrunv(x0, y0, wid, col, dotflag)
{
if (col == cred)
{
col = (dotflag) ? cblack: cwhite; /* checkerboard select */
}
XPixSet(win, x0, (screenh-1)-y0, 1, wid, col);
}
drawvec(x0, y0, x1, y1, col, wid, emph)
{
#define SOLID SolidLine
#define DASHES XMakePattern(0x00ff,16,1)
#define DOTS XMakePattern(0x0303,16,1)
Vertex chain[2];
int pattern;
if (lut)
{
/* XLine(win,x0,screenh-y0,x1,screenh-y1,wid,wid,col,GXcopy,AllPlanes); */
chain[0].x = x0 - wid/2;
chain[0].y = screenh-y0 - wid/2;
chain[0].flags = VertexDrawLastPoint;
chain[1].x = x1 - wid/2;
chain[1].y = screenh-y1 - wid/2;
chain[1].flags = VertexDrawLastPoint;
pattern = (emph==EMPHNONE) ? SOLID : ((emph==EMPHBOLD) ? DASHES : DOTS);
XDrawDashed(win, chain, 2, wid, wid, col, pattern, GXcopy, AllPlanes);
}
else drawline(x0-wid/2, y0+wid/2, x1-wid/2, y1+wid/2, wid, col, emph);
/* SUN version does not understand dots and dashes -- we must do it all */
}
charshow(str)
char *str;
{
int i;
for(i=0; i<strlen(str); i++) sysmsg[sysmsgloc++] = str[i];
sysmsg[sysmsgloc] = '\0';
fontwrite(SYSFONT, 10, 10, sysmsg, EMPHNONE, cgreen);
XFlush();
}
charunshow(n)
{
fontwrite(SYSFONT, 10, 10, sysmsg, EMPHNONE, cblack);
while (n--)
{
if (sysmsgloc) sysmsg[--sysmsgloc] = '\0';
}
fontwrite(SYSFONT, 10, 10, sysmsg, EMPHNONE, cgreen);
XFlush();
}
erase()
{
XPixSet(win, 0, 0, screenw, screenh, cblack);
fontwrite(SYSFONT, 10, 10, sysmsg, EMPHNONE, cgreen);
XFlush();
}
/*
* internal stuff
*/
findcolor(r, g, b)
int r, g, b;
{
Color c;
c.red = r*65535;
c.green= g*65535;
c.blue = b*65535;
if (!XGetHardwareColor(&c))
{
/* err("no more room in color table"); */
return(b*4+g*2+r);
}
return(c.pixel);
}
mx(ev)
XKeyEvent *ev;
{
return(ev->x);
}
my(ev)
XKeyEvent *ev;
{
return(screenh - ev->y + 1);
}
writescan(x, y, pixels, outaddr, color)
int x, y, pixels, *outaddr, color;
{
if (pixels <= 0) return; /* PARANOIA: should not ever happen */
if (!lut && color == cred)
{
register int i, lim;
lim = (pixels+31)/32;
if ((x^y) & 0x1) for(i=0; i<lim; i++) outaddr[i] &= 0x55555555;
else for(i=0; i<lim; i++) outaddr[i] &= 0xaaaaaaaa;
color = cwhite;
}
swapshorts(outaddr, (pixels+31)/8);
XBitmapBitsPut(win, x, y, pixels, 1,
outaddr, color, cblack, 0, GXcopy, AllPlanes);
}
swapshorts(buf, len)
register unsigned char *buf;
{
unsigned char c1, c2, c3, c4;
register int count, i;
if (!maptab[1]) maptabinit();
count = len/4;
for (i=0; i<count; i++)
{
c1 = *buf++;
c2 = *buf++;
c3 = *buf++;
c4 = *buf;
*buf-- = maptab[c1];
*buf-- = maptab[c2];
*buf-- = maptab[c3];
*buf = maptab[c4];
buf += 4;
}
}
maptabinit()
{
register int i, j;
unsigned char mask;
for(i = 0; i<256; i++)
{
mask = 0;
for(j = 0; j < 8; j++) if (i & (1<<j)) mask |= 1<<(7-j);
maptab[i] = mask;
}
}
SHAR_EOF
# End of shell archive
exit 0
--
Rich $alz "Anger is an energy"
Cronus Project, BBN Labs rsalz@bbn.com
Moderator, comp.sources.unix sources@uunet.c
c
cs)