[comp.sources.x] v12i017: tgif, Part01/23

william@CS.UCLA.EDU (William Cheng) (03/11/91)

Submitted-by: william@CS.UCLA.EDU (William Cheng)
Posting-number: Volume 12, Issue 17
Archive-name: tgif/part01

Tgif is a Xlib base 2-D drawing facility under X11.  It also supports
	hierarchical construction of drawings.
The README is in part 19 -- stay tuned :-}


Here's a short list of added features/bug fixes.

........................... tgif-1.23 => tgif-2.0 ...........................

1) Can import X11 bitmaps as new primitive objects.
2) Output X11 bitmap (xbm) or X11 pixmap (xpm) files.
3) Fix color PostScript output.  There are still some problem
   with printing to Apple LaserWriter.  Please read the BUGS
   section in tgif.man.
4) Scrollable message window (no scrollbars, just clicks).
5) Comment line (starts with %) are allowed in .obj and .sym files.
6) Handle more X defaults to setup initial fonts, styles, etc.
7) Keeping track of importing directory, and better handling
   of the popup window that enquires about file names.
8) The directory 'bitmaps' is renamed to 'xbm'.

........................... tgif-2.0 => tgif-2.1 ...........................

1) Fix small bugs in Makefile.noimake

---------------------------------> cut here <---------------------------------
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 23)."
# Contents:  align.c animate.c arc.c attr.c
# Wrapped by william@oahu on Wed Mar  6 09:56:55 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'align.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'align.c'\"
else
echo shar: Extracting \"'align.c'\" \(3897 characters\)
sed "s/^X//" >'align.c' <<'END_OF_FILE'
X/*
X * Author:	William Chia-Wei Cheng (william@cs.ucla.edu)
X *
X * Copyright (C) 1990, 1991, William Cheng.
X */
X#ifndef lint
Xstatic char RCSid[] =
X      "@(#)$Header: /tmp_mnt/n/kona/tangram/u/william/X11/TGIF2/RCS/align.c,v 2.0 91/03/05 12:46:11 william Exp $";
X#endif
X
X#include <stdio.h>
X#include <X11/Xlib.h>
X#include "const.h"
X#include "types.h"
X
X#include "drawing.e"	/* RedrawAreas () */
X#include "dup.e"	/* justDupped */
X#include "grid.e"	/* GridXY () */
X#include "mark.e"	/* HighLightForward (), HighLightReverse () */
X#include "move.e"	/* MoveObj () */
X#include "obj.e"	/* botObj */
X#include "select.e"	/* topSel */
X#include "setup.e"	/* fileModified */
X
Xint	horiAlign = ALIGN_L;
Xint	vertAlign = ALIGN_T;
X
Xvoid AlignSelObjs ()
X{
X   register struct SelRec	* sel_ptr;
X   register struct ObjRec	* obj_ptr;
X   register int			x = 0, y = 0;
X   int				pivot_x = 0, pivot_y = 0;
X   int				dx, dy, ltx, lty, rbx, rby;
X
X   if (topSel == NULL) return;
X
X   HighLightReverse ();
X   switch (horiAlign)
X   {
X      case ALIGN_L : pivot_x = selObjLtX; break;
X      case ALIGN_C : pivot_x = (selObjLtX + selObjRbX) / 2; break;
X      case ALIGN_R : pivot_x = selObjRbX; break;
X   }
X   switch (vertAlign)
X   {
X      case ALIGN_T : pivot_y = selObjLtY; break;
X      case ALIGN_M : pivot_y = (selObjLtY + selObjRbY) / 2; break;
X      case ALIGN_B : pivot_y = selObjRbY; break;
X   }
X
X   for (sel_ptr = topSel; sel_ptr != NULL; sel_ptr = sel_ptr->next)
X   {
X      obj_ptr = sel_ptr->obj;
X      switch (horiAlign)
X      {
X         case ALIGN_L : x = obj_ptr->obbox.ltx; break;
X         case ALIGN_C : x = (obj_ptr->obbox.ltx+obj_ptr->obbox.rbx) / 2; break;
X         case ALIGN_R : x = obj_ptr->obbox.rbx; break;
X      }
X      switch (vertAlign)
X      {
X         case ALIGN_T : y = obj_ptr->obbox.lty; break;
X         case ALIGN_M : y = (obj_ptr->obbox.lty+obj_ptr->obbox.rby) / 2; break;
X         case ALIGN_B : y = obj_ptr->obbox.rby; break;
X      }
X      if (horiAlign == ALIGN_N) x = pivot_x;
X      if (vertAlign == ALIGN_N) y = pivot_y;
X
X      dx = pivot_x - x;
X      dy = pivot_y - y;
X
X      MoveObj (obj_ptr, dx, dy);
X   }
X   ltx = selLtX; lty = selLtY; rbx = selRbX, rby = selRbY;
X   UpdSelBBox ();
X   RedrawAreas (botObj, ltx-(1<<zoomScale), lty-(1<<zoomScale),
X         rbx+(1<<zoomScale), rby+(1<<zoomScale), selLtX-(1<<zoomScale),
X         selLtY-(1<<zoomScale), selRbX+(1<<zoomScale), selRbY+(1<<zoomScale));
X   HighLightForward ();
X   SetFileModified (TRUE);
X   justDupped = FALSE;
X}
X
Xvoid AlignSelToGrid ()
X{
X   register struct SelRec	* sel_ptr;
X   register struct ObjRec	* obj_ptr;
X   register int			x = 0, y = 0;
X   int				grid_x, grid_y, dx, dy, ltx, lty, rbx, rby;
X
X   if (topSel == NULL) return;
X
X   HighLightReverse ();
X   for (sel_ptr = topSel; sel_ptr != NULL; sel_ptr = sel_ptr->next)
X   {
X      obj_ptr = sel_ptr->obj;
X      switch (horiAlign)
X      {
X         case ALIGN_L : x = obj_ptr->obbox.ltx; break;
X         case ALIGN_C : x = (obj_ptr->obbox.ltx+obj_ptr->obbox.rbx) / 2; break;
X         case ALIGN_R : x = obj_ptr->obbox.rbx; break;
X      }
X      switch (vertAlign)
X      {
X         case ALIGN_T : y = obj_ptr->obbox.lty; break;
X         case ALIGN_M : y = (obj_ptr->obbox.lty+obj_ptr->obbox.rby) / 2; break;
X         case ALIGN_B : y = obj_ptr->obbox.rby; break;
X      }
X      GridXY (x, y, &grid_x, &grid_y);
X      if (horiAlign == ALIGN_N) x = grid_x;
X      if (vertAlign == ALIGN_N) y = grid_y;
X
X      dx = (grid_x - x) << zoomScale;
X      dy = (grid_y - y) << zoomScale;
X
X      MoveObj (obj_ptr, dx, dy);
X   }
X   ltx = selLtX; lty = selLtY; rbx = selRbX, rby = selRbY;
X   UpdSelBBox ();
X   RedrawAreas (botObj, ltx-(1<<zoomScale), lty-(1<<zoomScale),
X         rbx+(1<<zoomScale), rby+(1<<zoomScale), selLtX-(1<<zoomScale),
X         selLtY-(1<<zoomScale), selRbX+(1<<zoomScale), selRbY+(1<<zoomScale));
X   HighLightForward ();
X   SetFileModified (TRUE);
X   justDupped = FALSE;
X}
END_OF_FILE
if test 3897 -ne `wc -c <'align.c'`; then
    echo shar: \"'align.c'\" unpacked with wrong size!
fi
# end of 'align.c'
fi
if test -f 'animate.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'animate.c'\"
else
echo shar: Extracting \"'animate.c'\" \(8049 characters\)
sed "s/^X//" >'animate.c' <<'END_OF_FILE'
X/*
X * Author:	William Chia-Wei Cheng (william@cs.ucla.edu)
X *
X * Copyright (C) 1990, 1991, William Cheng.
X */
X#ifndef lint
Xstatic char RCSid[] =
X      "@(#)$Header: /tmp_mnt/n/kona/tangram/u/william/X11/TGIF2/RCS/animate.c,v 2.0 91/03/05 12:46:35 william Exp $";
X#endif
X
X#include <X11/Xlib.h>
X#include "const.h"
X#include "types.h"
X
X#include "color.e"
X#include "raster.e"
X#include "select.e"
X#include "setup.e"
X
X#define SEND_SPEED 8
X
X#define TOKEN_R 8
X
Xstatic XPoint	savedToken[5];
X
Xvoid AnimateSend (PolyPtr, Speed, Pixel)
X   struct PolyRec	* PolyPtr;
X   int			Speed, Pixel;
X{
X   register int		delta, i;
X   register XPoint	* token;
X   int			x, y, num_pts, j, x_dist, y_dist;
X   XPoint		* v;
X   struct BBRec		bbox;
X   double		slope, delta_x, delta_y;
X   XGCValues		values;
X
X   values.foreground = Pixel;
X   values.function = GXxor;
X   values.line_style = FillSolid;
X   values.line_width = 0;
X   XChangeGC (mainDisplay, drawGC,
X         GCForeground | GCFunction | GCLineStyle | GCLineWidth, &values);
X
X   bbox.ltx = 0; bbox.lty = 0; bbox.rbx = 2*TOKEN_R; bbox.rby = 2*TOKEN_R;
X
X   num_pts = PolyPtr->n;
X   v = PolyPtr->vlist;
X   token = (XPoint *) calloc (5, sizeof(XPoint));
X
X   for (j = 0; j < num_pts-1; j++)
X   {
X      x = OFFSET_X(v[j].x);
X      y = OFFSET_Y(v[j].y);
X      token[0].x = (short)(x - TOKEN_R); token[0].y = (short)(y - TOKEN_R);
X      token[1].x = (short)(x + TOKEN_R); token[1].y = (short)(y - TOKEN_R);
X      token[2].x = (short)(x + TOKEN_R); token[2].y = (short)(y + TOKEN_R);
X      token[3].x = (short)(x - TOKEN_R); token[3].y = (short)(y + TOKEN_R);
X      token[4].x = (short)(x - TOKEN_R); token[4].y = (short)(y - TOKEN_R);
X      XFillPolygon (mainDisplay, drawWindow, drawGC, token, 5, Convex,
X            CoordModeOrigin);
X      if (v[j].x == v[j+1].x)
X      {  /* moving vertical */
X         if ((y_dist = (v[j+1].y-v[j].y)>>zoomScale) > 0)
X         {  /* moving down */
X            for (delta = 0; delta < y_dist; delta += Speed)
X            {
X               XFillPolygon (mainDisplay, drawWindow, drawGC, token, 5, Convex,
X                     CoordModeOrigin);
X               for (i = 0; i < 5; i++) token[i].y += Speed;
X               XFillPolygon (mainDisplay, drawWindow, drawGC, token, 5, Convex,
X                     CoordModeOrigin);
X            }
X         }
X         else
X         {  /* moving up */
X            for (delta = y_dist; delta < 0; delta += Speed)
X            {
X               XFillPolygon (mainDisplay, drawWindow, drawGC, token, 5, Convex,
X                     CoordModeOrigin);
X               for (i = 0; i < 5; i++) token[i].y -= Speed;
X               XFillPolygon (mainDisplay, drawWindow, drawGC, token, 5, Convex,
X                     CoordModeOrigin);
X            }
X         }
X      }
X      else if (v[j].y == v[j+1].y)
X      {  /* moving horizontal */
X         if ((x_dist = (v[j+1].x-v[j].x)>>zoomScale) > 0)
X         {  /* moving right */
X            for (delta = 0; delta < x_dist; delta += Speed)
X            {
X               XFillPolygon (mainDisplay, drawWindow, drawGC, token, 5, Convex,
X                     CoordModeOrigin);
X               for (i = 0; i < 5; i++) token[i].x += Speed;
X               XFillPolygon (mainDisplay, drawWindow, drawGC, token, 5, Convex,
X                     CoordModeOrigin);
X            }
X         }
X         else
X         {  /* moving left */
X            for (delta = x_dist; delta < 0; delta += Speed)
X            {
X               XFillPolygon (mainDisplay, drawWindow, drawGC, token, 5, Convex,
X                     CoordModeOrigin);
X               for (i = 0; i < 5; i++) token[i].x -= Speed;
X               XFillPolygon (mainDisplay, drawWindow, drawGC, token, 5, Convex,
X                     CoordModeOrigin);
X            }
X         }
X      }
X      else
X      {  /* moving diagonally */
X         x_dist = (v[j+1].x-v[j].x)>>zoomScale;
X         y_dist = (v[j+1].y-v[j].y)>>zoomScale;
X         for (i = 0; i < 5; i++)
X         {
X            savedToken[i].x = token[i].x;
X            savedToken[i].y = token[i].y;
X         }
X         if (abs (x_dist) > abs (y_dist))
X         {  /* moving in the x direction */
X            slope = (double)y_dist / (double)x_dist;
X            if (x_dist > 0)
X            {  /* moving right */
X               for (delta = 0; delta < x_dist; delta += Speed)
X               {
X                  XFillPolygon (mainDisplay, drawWindow, drawGC, token, 5,
X                        Convex, CoordModeOrigin);
X                  delta_y = slope * (double)delta;
X                  for (i = 0; i < 5; i++)
X                  {
X                     token[i].x = savedToken[i].x + delta;
X                     token[i].y = savedToken[i].y + delta_y;
X                  }
X                  XFillPolygon (mainDisplay, drawWindow, drawGC, token, 5,
X                        Convex, CoordModeOrigin);
X               }
X            }
X            else
X            {  /* moving left */
X               for (delta = 0; delta > x_dist; delta -= Speed)
X               {
X                  XFillPolygon (mainDisplay, drawWindow, drawGC, token, 5,
X                        Convex, CoordModeOrigin);
X                  delta_y = slope * (double)delta;
X                  for (i = 0; i < 5; i++)
X                  {
X                     token[i].x = savedToken[i].x + delta;
X                     token[i].y = savedToken[i].y + delta_y;
X                  }
X                  XFillPolygon (mainDisplay, drawWindow, drawGC, token, 5,
X                        Convex, CoordModeOrigin);
X               }
X            }
X         }
X         else
X         {  /* moving in the y direction */
X            slope = (double)x_dist / (double)y_dist;
X            if (y_dist > 0)
X            {  /* moving down */
X               for (delta = 0; delta < y_dist; delta += Speed)
X               {
X                  XFillPolygon (mainDisplay, drawWindow, drawGC, token, 5,
X                        Convex, CoordModeOrigin);
X                  delta_x = slope * (double)delta;
X                  for (i = 0; i < 5; i++)
X                  {
X                     token[i].x = savedToken[i].x + delta_x;
X                     token[i].y = savedToken[i].y + delta;
X                  }
X                  XFillPolygon (mainDisplay, drawWindow, drawGC, token, 5,
X                        Convex, CoordModeOrigin);
X               }
X            }
X            else
X            {  /* moving up */
X               for (delta = 0; delta > y_dist; delta -= Speed)
X               {
X                  XFillPolygon (mainDisplay, drawWindow, drawGC, token, 5,
X                        Convex, CoordModeOrigin);
X                  delta_x = slope * (double)delta;
X                  for (i = 0; i < 5; i++)
X                  {
X                     token[i].x = savedToken[i].x + delta_x;
X                     token[i].y = savedToken[i].y + delta;
X                  }
X                  XFillPolygon (mainDisplay, drawWindow, drawGC, token, 5,
X                        Convex, CoordModeOrigin);
X               }
X            }
X         }
X      }
X      XFillPolygon (mainDisplay, drawWindow, drawGC, token, 5, Convex,
X            CoordModeOrigin);
X   }
X   cfree (token);
X}
X
Xvoid AnimateSel ()
X{
X   if (topSel != botSel || topSel == NULL || topSel->obj->type != OBJ_POLY)
X   {
X      Msg ("Please select only one POLY object.");
X      return;
X   }
X   AnimateSend (topSel->obj->detail.p, SEND_SPEED,
X         xorColorPixels[topSel->obj->color]);
X}
X
Xvoid AnimateFlashColor(ObjPtr, ColorIndex)
X   struct ObjRec	* ObjPtr;
X   int			ColorIndex;
X{
X   int	saved_color_index = ObjPtr->color;
X
X   ObjPtr->color = ColorIndex;
X   DrawPolyObj (drawWindow, drawOrigX, drawOrigY, ObjPtr);
X   ObjPtr->color = saved_color_index;
X   DrawPolyObj (drawWindow, drawOrigX, drawOrigY, ObjPtr);
X}
X
Xvoid FlashSelColor ()
X{
X   register int	i;
X
X   if (topSel != botSel || topSel == NULL || topSel->obj->type != OBJ_POLY)
X   {
X      Msg ("Please select only one POLY object.");
X      return;
X   }
X   for (i = 0; i < maxColors; i++)
X      if (strcmp ("white", colorMenuItems[i]) == 0)
X         break;
X   AnimateFlashColor (topSel->obj, i);
X}
END_OF_FILE
if test 8049 -ne `wc -c <'animate.c'`; then
    echo shar: \"'animate.c'\" unpacked with wrong size!
fi
# end of 'animate.c'
fi
if test -f 'arc.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'arc.c'\"
else
echo shar: Extracting \"'arc.c'\" \(19449 characters\)
sed "s/^X//" >'arc.c' <<'END_OF_FILE'
X/*
X * Author:	William Chia-Wei Cheng (william@cs.ucla.edu)
X *
X * Copyright (C) 1990, 1991, William Cheng.
X */
X#ifndef lint
Xstatic char RCSid[] =
X      "@(#)$Header: /tmp_mnt/n/kona/tangram/u/william/X11/TGIF2/RCS/arc.c,v 2.0 91/03/05 12:46:37 william Exp $";
X#endif
X
X#include <math.h>
X#include <stdio.h>
X#include <X11/Xlib.h>
X#include "const.h"
X#include "types.h"
X
X#include "color.e"
X#include "cursor.e"
X#include "file.e"
X#include "grid.e"
X#include "obj.e"
X#include "pattern.e"
X#include "poly.e"
X#include "raster.e"
X#include "ruler.e"
X#include "select.e"
X#include "setup.e"
X
X#ifndef M_PI
X#define M_PI 3.14159265358979323846
X#endif
X
X#define EXPAND_BBOX(bbox,x,y) \
X   if ((x)<(bbox)->ltx) (bbox)->ltx=(x); if ((y)<(bbox)->lty) (bbox)->lty=(y); \
X   if ((x)>(bbox)->rbx) (bbox)->rbx=(x); if ((y)>(bbox)->rby) (bbox)->rby=(y)
X
Xint	arcDrawn = FALSE;
X
Xstatic
Xint ArcDirection (xc, yc, x1, y1, x2, y2)
X   int	xc, yc, x1, y1, x2, y2;
X{
X   register int		dx, dy, radius;
X   register double	theta1, theta2;
X
X   dx = x1-xc; dy = y1-yc;
X   radius = (int)sqrt((double)(dx*dx+dy*dy));
X   theta1 = atan2 ((double)(dy), (double)(dx));
X   theta2 = atan2 ((double)(y2-yc), (double)(x2-xc));
X   if (theta1 < 0) theta1 += 2*M_PI;
X   if (theta2 < 0) theta2 += 2*M_PI;
X
X   if (theta2 > theta1)
X   {
X      if (theta2-theta1 >= 2*M_PI-theta2+theta1)
X         return (ARC_CCW);
X      else
X         return (ARC_CW);
X   }
X   else if (theta1 > theta2)
X   {
X      if (theta1-theta2 >= 2*M_PI-theta1+theta2)
X         return (ARC_CW);
X      else
X         return (ARC_CCW);
X   }
X   else
X      return (ARC_CCW);
X}
X
Xvoid PointsToArc (xc, yc, x1, y1, x2, y2, dir, ltx, lty, w, h, angle1, angle2)
X   int	xc, yc, x1, y1, x2, y2, dir;
X   int	* ltx, * lty, * w, * h, * angle1, * angle2;
X{
X   register int	dx, dy, radius, theta1, theta2, d_theta;
X
X   dx = x1-xc; dy = y1-yc;
X   radius = (int)sqrt((double)(dx*dx+dy*dy));
X   *ltx = xc-radius; *lty = yc-radius;
X   *w = *h = 2*radius;
X   theta1 = (int)(atan2 ((double)(dy),(double)(dx))/M_PI*(-180));
X   theta2 = (y2-yc == 0 && x2-xc == 0) ?
X         0 : (int)(atan2 ((double)(y2-yc),(double)(x2-xc))/M_PI*(-180));
X   /* NOTE:  *angle1 must be between -180 degrees and +180 degrees */
X   *angle1 = theta1*64;
X   d_theta = theta2-theta1;
X   switch (dir)
X   {
X      case ARC_CCW: if (d_theta < 0) d_theta = 360 + d_theta; break;
X      case ARC_CW:  if (d_theta > 0) d_theta = d_theta - 360; break;
X   }
X   *angle2 = d_theta * 64;
X}
X
Xvoid ArcRealX2Y2 (ArcPtr, RealX2, RealY2)
X   register struct ArcRec	* ArcPtr;
X   int				* RealX2, * RealY2;
X{
X   register double	angle_in_radian;
X   int			w = ArcPtr->w, h = ArcPtr->h;
X
X   angle_in_radian = (ArcPtr->angle1+ArcPtr->angle2)*M_PI/180/64;
X   *RealX2 = ArcPtr->xc + round((w/2)*cos(angle_in_radian));
X   *RealY2 = ArcPtr->yc - round((h/2)*sin(angle_in_radian));
X}
X
Xvoid CalcArcBBox (ArcPtr, bbox)
X   struct ArcRec		* ArcPtr;
X   register struct BBRec	* bbox;
X{
X   register int	theta1, theta2;
X   int		real_x2, real_y2, dir = ArcPtr->dir;
X   int		ltx = ArcPtr->ltx, lty = ArcPtr->lty;
X   int		w = ArcPtr->w, h = ArcPtr->h;
X   int		pass_theta1 = FALSE, coverage = 0, angle;
X
X   theta1 = (ArcPtr->angle1)/64;
X   theta2 = theta1 + (ArcPtr->angle2)/64;
X
X   ArcRealX2Y2 (ArcPtr, &real_x2, &real_y2);
X
X   if (ArcPtr->fill == NONEPAT)
X   {  /* don't counter the center of the arc */
X      bbox->ltx = min(ArcPtr->x1,real_x2);
X      bbox->lty = min(ArcPtr->y1,real_y2);
X      bbox->rbx = max(ArcPtr->x1,real_x2);
X      bbox->rby = max(ArcPtr->y1,real_y2);
X   }
X   else
X   {
X      bbox->ltx = min(ArcPtr->xc,min(ArcPtr->x1,real_x2));
X      bbox->lty = min(ArcPtr->yc,min(ArcPtr->y1,real_y2));
X      bbox->rbx = max(ArcPtr->xc,max(ArcPtr->x1,real_x2));
X      bbox->rby = max(ArcPtr->yc,max(ArcPtr->y1,real_y2));
X   }
X
X   if (theta2 < -180) theta2 += 360;
X   if (theta2 > 180) theta2 -= 360;
X
X   if (theta1 < 0) theta1 += 360;
X   if (theta2 < 0) theta2 += 360;
X
X   if (dir == ARC_CCW)
X   {
X      angle = 0;
X      while (angle < theta2 || !pass_theta1)
X      {
X         if (angle >= theta1 && !pass_theta1)
X         {
X            pass_theta1 = TRUE;
X            if (theta2 > theta1 && angle >= theta2) break;
X            if (theta2 < theta1) angle -= 360;
X         }
X         if (pass_theta1) coverage |= 1 << (((angle+360)/90) % 4);
X         angle = (angle == 360) ? 0 : (angle+90);
X      }
X   }
X   else
X   {
X      angle = 360;
X      while (angle > theta2 || !pass_theta1)
X      {
X         if (angle <= theta1 && !pass_theta1)
X         {
X            pass_theta1 = TRUE;
X            if (theta2 < theta1 && angle <= theta2) break;
X            if (theta2 > theta1) angle += 360;
X         }
X         if (pass_theta1) coverage |= 1 << ((angle/90) % 4);
X         angle = (angle == 0) ? 360 : (angle-90);
X      }
X   }
X   if (coverage & 0x1) { EXPAND_BBOX(bbox,(int)(ltx+w),(int)(lty+h/2)); }
X   if (coverage & 0x2) { EXPAND_BBOX(bbox,(int)(ltx+w/2),lty); }
X   if (coverage & 0x4) { EXPAND_BBOX(bbox,ltx,(int)(lty+h/2)); }
X   if (coverage & 0x8) { EXPAND_BBOX(bbox,(int)(ltx+w/2),(int)(lty+h)); }
X}
X
Xstatic
Xvoid DumpArcPSPath (FP, xc, yc, xr, yr, dir, a1, a2, outline, blank1, blank2)
X   FILE	* FP;
X   int	xc, yc, xr, yr, dir, a1, a2, outline;
X   char	* blank1, * blank2;
X{
X   fprintf (FP, "%snewpath\n", blank1);
X   if (outline) fprintf (FP, "%s%1d %1d moveto\n", blank2, xc, yc);
X   switch (dir)
X   {
X      case ARC_CCW:
X         fprintf (FP, "%s%1d %1d %1d %1d %1d %1d tgifarc\n", blank2,
X               xc, yc, xr, yr, a1, a2);
X         break;
X      case ARC_CW:
X         fprintf (FP, "%s%1d %1d %1d %1d %1d %1d tgifarcn\n", blank2,
X               xc, yc, xr, yr, a1, a2);
X         break;
X   }
X   if (outline) fprintf (FP, "%s%1d %1d lineto ", blank2, xc, yc);
X}
X
Xvoid DumpArcObj (FP, ObjPtr)
X   FILE			* FP;
X   struct ObjRec	* ObjPtr;
X{
X   register struct ArcRec	* arc_ptr = ObjPtr->detail.a;
X   int				i;
X   int				fill, width, pen, dash, color_index;
X   int				xc, yc, xr, yr, dir, angle1, angle2;
X
X   fill = arc_ptr->fill;
X   width = arc_ptr->width;
X   pen = arc_ptr->pen;
X   dash = arc_ptr->dash;
X   xc = arc_ptr->xc; yc = arc_ptr->yc;
X   xr = (int)(arc_ptr->w/2); yr = (int)(arc_ptr->h/2);
X   dir = arc_ptr->dir;
X   angle1 = -(int)(arc_ptr->angle1/64);
X   angle2 = -(int)(arc_ptr->angle2/64) + angle1;
X
X   if (fill == NONEPAT && pen == NONEPAT) return;
X
X   color_index = ObjPtr->color;
X   if (colorDump)
X      fprintf (FP, "%.3f %.3f %.3f setrgbcolor\n",
X            ((float)tgifColors[color_index].red/maxRGB),
X            ((float)tgifColors[color_index].green/maxRGB),
X            ((float)tgifColors[color_index].blue/maxRGB));
X
X   switch (fill)
X   {
X      case NONEPAT: break;
X      case SOLIDPAT:
X         DumpArcPSPath (FP,xc,yc,xr,yr,dir,angle1,angle2,TRUE,"","   ");
X         fprintf (FP, "   fill\n");
X         break;
X      case BACKPAT:
X         DumpArcPSPath (FP,xc,yc,xr,yr,dir,angle1,angle2,TRUE,"","   ");
X         fprintf (FP, "   closepath 1 setgray fill\n");
X         if (colorDump)
X            fprintf (FP, "   %.3f %.3f %.3f setrgbcolor\n",
X                  ((float)tgifColors[color_index].red/maxRGB),
X                  ((float)tgifColors[color_index].green/maxRGB),
X                  ((float)tgifColors[color_index].blue/maxRGB));
X         else
X            fprintf (FP, "   0 setgray\n");
X         break;
X      default:
X         fprintf (FP, "gsave\n");
X         if (!colorDump)
X            fprintf (FP, "   pat%1d 8 1 0 72 300 32 div div setpattern\n",fill);
X         DumpArcPSPath (FP,xc,yc,xr,yr,dir,angle1,angle2,TRUE,"   ","      ");
X         if (colorDump)
X         {
X            fprintf (FP, "   closepath clip\n");
X            DumpPatFill (FP, fill, 8, ObjPtr->bbox, "   ");
X         }
X         else
X            fprintf (FP, "   fill\n");
X         fprintf (FP, "grestore\n");
X         break;
X   }
X
X   fprintf (FP, "%1d setlinewidth\n", widthOfLine[width]);
X   if (dash != 0)
X   {
X      fprintf (FP, "[");
X      for (i = 0; i < dashListLength[dash]-1; i++)
X         fprintf (FP, "%1d ", (int)(dashList[dash][i]));
X      fprintf (FP, "%1d] 0 setdash\n",
X            (int)(dashList[dash][dashListLength[dash]-1]));
X   }
X
X   switch (pen)
X   {
X      case NONEPAT: break;
X      case SOLIDPAT:
X         DumpArcPSPath (FP,xc,yc,xr,yr,dir,angle1,angle2,FALSE,"","   ");
X         fprintf (FP, "stroke\n");
X         break;
X      case BACKPAT:
X         DumpArcPSPath (FP,xc,yc,xr,yr,dir,angle1,angle2,FALSE,"","   ");
X         fprintf (FP, "1 setgray stroke 0 setgray\n");
X         break;
X      default:
X         fprintf (FP, "gsave\n");
X         if (!colorDump)
X            fprintf (FP, "   pat%1d 8 1 0 72 300 32 div div setpattern\n", pen);
X         DumpArcPSPath (FP,xc,yc,xr,yr,dir,angle1,angle2,FALSE,"   ","      ");
X         if (colorDump)
X         {
X            fprintf (FP, "   strokepath clip\n");
X            DumpPatFill (FP, pen, 8, ObjPtr->bbox, "   ");
X         }
X         else
X            fprintf (FP, "   stroke\n");
X         fprintf (FP, "grestore\n");
X         break;
X   }
X   if (dash != 0) fprintf (FP, "[] 0 setdash\n");
X   fprintf (FP, "1 setlinewidth\n\n");
X}
X 
Xvoid DrawArcObj (window, XOff, YOff, ObjPtr)
X   Window		window;
X   int			XOff, YOff;
X   struct ObjRec	* ObjPtr;
X{
X   struct ArcRec	* arc_ptr = ObjPtr->detail.a;
X   int			fill, width, pen, dash, pixel, real_x_off, real_y_off;
X   int			ltx, lty, w, h, angle1, angle2;
X   XGCValues		values;
X
X   real_x_off = (XOff >> zoomScale) << zoomScale;
X   real_y_off = (YOff >> zoomScale) << zoomScale;
X
X   ltx = (arc_ptr->ltx - real_x_off) >> zoomScale;
X   lty = (arc_ptr->lty - real_y_off) >> zoomScale;
X   w = (arc_ptr->w) >> zoomScale;
X   h = (arc_ptr->h) >> zoomScale;
X   angle1 = arc_ptr->angle1;
X   angle2 = arc_ptr->angle2;
X
X   fill = ObjPtr->detail.a->fill;
X   width = ObjPtr->detail.a->width;
X   pen = ObjPtr->detail.a->pen;
X   dash = ObjPtr->detail.a->dash;
X   pixel = colorPixels[ObjPtr->color];
X
X   if (fill != 0)
X   {
X      values.foreground = (fill == 2) ? myBgPixel : pixel;
X      values.function = GXcopy;
X      values.fill_style = FillOpaqueStippled;
X      values.stipple = patPixmap[fill];
X      XChangeGC (mainDisplay, drawGC,
X            GCForeground | GCFunction | GCFillStyle | GCStipple, &values);
X      XFillArc (mainDisplay, window, drawGC, ltx, lty, w, h, angle1, angle2);
X   }
X   if (pen != 0)
X   {
X      values.foreground = (pen == 2) ? myBgPixel : pixel;
X      values.function = GXcopy;
X      values.fill_style = FillOpaqueStippled;
X      values.stipple = patPixmap[pen];
X      values.line_width = widthOfLine[width] >> zoomScale;
X      if (dash != 0)
X      {
X         XSetDashes (mainDisplay, drawGC, 0, dashList[dash],
X               dashListLength[dash]);
X         values.line_style = LineOnOffDash;
X      }
X      else
X         values.line_style = LineSolid;
X      XChangeGC (mainDisplay, drawGC,
X            GCForeground | GCFunction | GCFillStyle | GCStipple | GCLineWidth |
X            GCLineStyle, &values);
X      XDrawArc (mainDisplay, window, drawGC, ltx, lty, w, h, angle1, angle2);
X   }
X}
X
Xvoid UpdArcBBox (ObjPtr)
X   struct ObjRec	* ObjPtr;
X{
X   struct ArcRec	* arc_ptr = ObjPtr->detail.a;
X   struct BBRec		bbox;
X   int			w;
X
X   ObjPtr->x = arc_ptr->xc;
X   ObjPtr->y = arc_ptr->yc;
X
X   CalcArcBBox (arc_ptr, &bbox);
X
X   ObjPtr->bbox.ltx = ObjPtr->obbox.ltx = bbox.ltx;
X   ObjPtr->bbox.lty = ObjPtr->obbox.lty = bbox.lty;
X   ObjPtr->bbox.rbx = ObjPtr->obbox.rbx = bbox.rbx;
X   ObjPtr->bbox.rby = ObjPtr->obbox.rby = bbox.rby;
X
X   w = widthOfLine[arc_ptr->width];
X
X   ObjPtr->bbox.ltx -= w;
X   ObjPtr->bbox.lty -= w;
X   ObjPtr->bbox.rbx += w;
X   ObjPtr->bbox.rby += w;
X}
X
Xstatic
Xvoid CreateArcObj (xc, yc, x1, y1, x2, y2, dir, ltx, lty, w, h, angle1, angle2)
X   int	xc, yc, x1, y1, x2, y2, dir, ltx, lty, w, h, angle1, angle2;
X{
X   struct ArcRec	* arc_ptr;
X   struct ObjRec	* obj_ptr;
X
X   arc_ptr = (struct ArcRec *) calloc (1, sizeof(struct ArcRec));
X   arc_ptr->fill = objFill;
X   arc_ptr->width = lineWidth;
X   arc_ptr->pen = penPat;
X   arc_ptr->dash = curDash;
X
X   arc_ptr->xc = (xc<<zoomScale)+drawOrigX;
X   arc_ptr->yc = (yc<<zoomScale)+drawOrigY;
X   arc_ptr->x1 = (x1<<zoomScale)+drawOrigX;
X   arc_ptr->y1 = (y1<<zoomScale)+drawOrigY;
X   arc_ptr->x2 = (x2<<zoomScale)+drawOrigX;
X   arc_ptr->y2 = (y2<<zoomScale)+drawOrigY;
X   arc_ptr->dir = dir;
X   arc_ptr->ltx = (ltx<<zoomScale)+drawOrigX;
X   arc_ptr->lty = (lty<<zoomScale)+drawOrigY;
X   arc_ptr->w = w<<zoomScale;
X   arc_ptr->h = h<<zoomScale;
X   arc_ptr->angle1 = angle1; arc_ptr->angle2 = angle2;
X
X   obj_ptr = (struct ObjRec *) calloc (1, sizeof(struct ObjRec));
X   obj_ptr->detail.a = arc_ptr;
X
X   UpdArcBBox (obj_ptr);
X
X   obj_ptr->type = OBJ_ARC;
X   obj_ptr->color = colorIndex;
X   obj_ptr->id = objId++;
X   obj_ptr->dirty = FALSE;
X   obj_ptr->fattr = obj_ptr->lattr = NULL;
X   AddObj (NULL, topObj, obj_ptr);
X}
X 
Xstatic
Xvoid ContinueArc (OrigX, OrigY)
X   int	OrigX, OrigY;
X{
X   int 		grid_x, grid_y, first_x = 0, first_y = 0;
X   int 		end_x, end_y, saved_x, saved_y;
X   int 		done = FALSE, drawing_arc = FALSE;
X   int		dir = INVALID, ltx, lty, w, h, angle1, angle2;
X   char		msg[80];
X   XGCValues	values;
X   XEvent	input;
X   XMotionEvent	* motion_ev;
X
X   values.foreground = xorColorPixels[colorIndex];
X   values.function = GXxor;
X   values.fill_style = FillSolid;
X   values.line_width = 0;
X   values.line_style = LineSolid;
X   XChangeGC (mainDisplay, drawGC,
X         GCForeground | GCFunction | GCFillStyle | GCLineWidth | GCLineStyle,
X         &values);
X
X   grid_x = saved_x = OrigX;
X   grid_y = saved_y = OrigY; 
X   XDrawLine (mainDisplay, drawWindow, drawGC, OrigX, OrigY, saved_x, saved_y);
X
X   XGrabPointer (mainDisplay, drawWindow, FALSE,
X         PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
X         GrabModeAsync, GrabModeAsync, None, handCursor, CurrentTime);
X   
X   Msg ("Please specify the start of an arc.");
X   while (!done)
X   {
X      XNextEvent (mainDisplay, &input);
X      if (input.type == ButtonPress)
X      {
X         if (drawing_arc)
X         {
X            XUngrabPointer (mainDisplay, CurrentTime);
X            XDrawArc (mainDisplay, drawWindow, drawGC, ltx, lty, w, h,
X                  angle1, angle2);
X            done = TRUE;
X            Msg ("");
X         }
X         else
X         {
X            XDrawLine (mainDisplay, drawWindow, drawGC, OrigX, OrigY,
X                  saved_x, saved_y);
X            first_x = saved_x;
X            first_y = saved_y;
X            drawing_arc = TRUE;
X            if (OrigX == grid_x && OrigY == grid_y)
X            {  /* fake it as if the 1st point is ok but the 2nd point is bad */
X               XUngrabPointer (mainDisplay, CurrentTime);
X               grid_x = first_x;
X               grid_y = first_y;
X               done = TRUE;
X            }
X            Msg ("Please specify the end of the arc.");
X         }
X      }
X      else if (input.type == MotionNotify)
X      {
X         motion_ev = &(input.xmotion);
X         end_x = motion_ev->x;
X         end_y = motion_ev->y;
X         GridXY (end_x, end_y, &grid_x, &grid_y);
X         if (grid_x != saved_x || grid_y != saved_y)
X         {
X            if (drawing_arc)
X            {  /* finished with the center and the first point on the arc */
X               if (dir == INVALID)
X               {
X                  dir = ArcDirection (OrigX, OrigY, first_x, first_y,
X                        grid_x, grid_y);
X                  ltx = OrigX; lty = OrigY; w = 0; h = 0; angle1 = angle2 = 0;
X                  if (dir == ARC_CW)
X                     sprintf (msg, "Please specify the end of the arc.  (%s).",
X                           "clockwise");
X                  else
X                     sprintf (msg, "Please specify the end of the arc.  (%s).",
X                           "counter-clockwise");
X                  Msg (msg);
X               }
X               XDrawArc (mainDisplay, drawWindow, drawGC, ltx, lty, w, h,
X                     angle1, angle2);
X               saved_x = grid_x;
X               saved_y = grid_y;
X               PointsToArc (OrigX, OrigY, first_x, first_y, saved_x, saved_y,
X                     dir, &ltx, &lty, &w, &h, &angle1, &angle2);
X               XDrawArc (mainDisplay, drawWindow, drawGC, ltx, lty, w, h,
X                     angle1, angle2);
X            }
X            else
X            {  /* looking for the first point on the arc */
X               XDrawLine (mainDisplay, drawWindow, drawGC, OrigX, OrigY,
X                     saved_x, saved_y);
X               saved_x = grid_x;
X               saved_y = grid_y;
X               XDrawLine (mainDisplay, drawWindow, drawGC, OrigX, OrigY,
X                     saved_x, saved_y);
X            }
X         }
X         MarkRulers (grid_x, grid_y);
X      }
X   }
X   if (first_x != grid_x || first_y != grid_y)
X   {
X      CreateArcObj (OrigX, OrigY, first_x, first_y, saved_x, saved_y, dir,
X            ltx, lty, w, h, angle1, angle2);
X      DrawArcObj (drawWindow, drawOrigX, drawOrigY, topObj);
X      arcDrawn = TRUE;
X      SetFileModified (TRUE);
X   }
X}
X
Xvoid DrawArc (input)
X   XEvent	* input;
X{
X   XButtonEvent	* button_ev;
X   int		mouse_x, mouse_y, grid_x, grid_y;
X
X   if (input->type != ButtonPress) return;
X
X   button_ev = &(input->xbutton);
X   if (button_ev->button == Button1)
X   {
X      mouse_x = button_ev->x;
X      mouse_y = button_ev->y;
X      GridXY (mouse_x, mouse_y, &grid_x, &grid_y);
X      ContinueArc (grid_x, grid_y);
X   }
X}
X
Xvoid SaveArcObj (FP, ObjPtr)
X   FILE				* FP;
X   register struct ObjRec	* ObjPtr;
X{
X   register struct ArcRec	* arc_ptr = ObjPtr->detail.a;
X
X   fprintf (FP, "arc('%s',", colorMenuItems[ObjPtr->color]);
X   fprintf (FP, "%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,\
X         %1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,",
X         arc_ptr->fill, arc_ptr->width, arc_ptr->pen, arc_ptr->dash,
X         arc_ptr->ltx, arc_ptr->lty, arc_ptr->xc, arc_ptr->yc,
X         arc_ptr->x1, arc_ptr->y1, arc_ptr->x2, arc_ptr->y2,
X         arc_ptr->dir, arc_ptr->w, arc_ptr->h, arc_ptr->angle1, arc_ptr->angle2,
X         ObjPtr->id);
X   SaveAttrs (FP, ObjPtr->lattr);
X   fprintf (FP, ")");
X}
X
Xvoid ReadArcObj (Inbuf, ObjPtr)
X   char			* Inbuf;
X   struct ObjRec	* * ObjPtr;
X{
X   register struct ArcRec	* arc_ptr;
X   char				color_str[20], * s;
X   int				fill, width, pen, dash, ltx, lty, w, h;
X   int				xc, yc, x1, y1, x2, y2, dir, angle1, angle2;
X
X   * ObjPtr = (struct ObjRec *) calloc (1, sizeof(struct ObjRec));
X   s = FindChar ('(', Inbuf);
X   s = ParseStr (s, ',', color_str);
X   arc_ptr = (struct ArcRec *) calloc (1, sizeof(struct ArcRec));
X
X   if (fileVersion > 8)
X   {
X      sscanf (s, "%d , %d , %d , %d , %d , %d , %d , %d , %d , \
X            %d, %d , %d , %d , %d , %d , %d , %d , %d",
X            &fill, &width, &pen, &dash, &ltx, &lty, &xc, &yc, &x1, &y1,
X            &x2, &y2, &dir, &w, &h, &angle1, &angle2, &((*ObjPtr)->id));
X      if ((*ObjPtr)->id >= objId) objId = (*ObjPtr)->id + 1;
X   }
X
X   arc_ptr->fill = fill;
X   arc_ptr->width = width;
X   arc_ptr->pen = pen;
X   arc_ptr->dash = dash;
X
X   arc_ptr->xc = xc;         arc_ptr->yc = yc;
X   arc_ptr->x1 = x1;         arc_ptr->y1 = y1;
X   arc_ptr->x2 = x2;         arc_ptr->y2 = y2;
X   arc_ptr->dir = dir;
X   arc_ptr->ltx = ltx;       arc_ptr->lty = lty;
X   arc_ptr->w = w;           arc_ptr->h = h;
X   arc_ptr->angle1 = angle1; arc_ptr->angle2 = angle2;
X
X   (*ObjPtr)->detail.a = arc_ptr;
X   UpdArcBBox (*ObjPtr);
X
X   (*ObjPtr)->type = OBJ_ARC;
X   (*ObjPtr)->color = FindColorIndex (color_str);
X   (*ObjPtr)->dirty = FALSE;
X}
X
Xvoid FreeArcObj (ObjPtr)
X   struct ObjRec	* ObjPtr;
X{
X   cfree (ObjPtr->detail.a);
X   cfree (ObjPtr);
X}
END_OF_FILE
if test 19449 -ne `wc -c <'arc.c'`; then
    echo shar: \"'arc.c'\" unpacked with wrong size!
fi
# end of 'arc.c'
fi
if test -f 'attr.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'attr.c'\"
else
echo shar: Extracting \"'attr.c'\" \(28217 characters\)
sed "s/^X//" >'attr.c' <<'END_OF_FILE'
X/*
X * Author:	William Chia-Wei Cheng (william@cs.ucla.edu)
X *
X * Copyright (C) 1990, 1991, William Cheng.
X */
X#ifndef lint
Xstatic char RCSid[] =
X      "@(#)$Header: /tmp_mnt/n/kona/tangram/u/william/X11/TGIF2/RCS/attr.c,v 2.0 91/03/05 12:46:41 william Exp $";
X#endif
X
X#include <stdio.h>
X#include <X11/Xlib.h>
X#include "const.h"
X#include "types.h"
X
X#include "choice.e"
X#include "color.e"
X#include "cursor.e"
X#include "dialog.e"
X#include "drawing.e"
X#include "dup.e"
X#include "file.e"
X#include "font.e"
X#include "mainloop.e"
X#include "mark.e"
X#include "menu.e"
X#include "msg.e"
X#include "obj.e"
X#include "raster.e"
X#include "select.e"
X#include "setup.e"
X#include "text.e"
X
X#define PAINT 0
X#define ERASE 1
X
Xstatic struct AttrRec	* topAttr = NULL, * botAttr = NULL;
X
Xvoid LinkInAttr (PrevPtr, NextPtr, AttrPtr)
X   struct AttrRec	* PrevPtr, * NextPtr, * AttrPtr;
X   /* add AttrPtr between PrevPtr and NextPtr */
X{
X   AttrPtr->prev = PrevPtr;
X   AttrPtr->next = NextPtr;
X
X   if (PrevPtr == NULL)
X      topAttr = AttrPtr;
X   else
X      PrevPtr->next = AttrPtr;
X
X   if (NextPtr == NULL)
X      botAttr = AttrPtr;
X   else
X      NextPtr->prev = AttrPtr;
X}
X
Xvoid FreeAttr (AttrPtr)
X   struct AttrRec	* AttrPtr;
X   /* This routine only frees the attribute record, not   */
X   /*    the text record, which must be freed explicitly. */
X{
X   cfree (AttrPtr);
X}
X
Xvoid UnlinkAttr (AttrPtr)
X   struct AttrRec	* AttrPtr;
X{
X   struct ObjRec	* own_ptr;
X   struct AttrRec	* * top_attr_ad;
X   struct AttrRec	* * bot_attr_ad;
X
X   own_ptr = AttrPtr->owner;
X 
X   top_attr_ad = &(own_ptr->fattr);
X   bot_attr_ad = &(own_ptr->lattr);
X     
X   if (*top_attr_ad == AttrPtr)
X      *top_attr_ad = AttrPtr->next;
X   else
X      AttrPtr->prev->next = AttrPtr->next;
X
X   if (*bot_attr_ad == AttrPtr)
X      *bot_attr_ad = AttrPtr->prev;
X   else
X      AttrPtr->next->prev = AttrPtr->prev;
X}
X
Xstatic
Xchar * FindEqual(s)
X   register char	* s;
X{
X   while (*s != '=' && *s != '\0') s++;
X   return ((*s == '=') ? (s) : (char *)NULL);
X}
X
Xstatic
Xvoid ParseAttrStr(Str, name, s)
X   char	* Str, * name, * s;
X{
X   char	* eq_ptr, * str_ptr, * ptr;
X
X   if ((eq_ptr = FindEqual(Str)) != NULL)
X   {
X      eq_ptr++;
X      ptr = name;
X      str_ptr = Str;
X      do
X      {
X         *ptr = *str_ptr; 
X         ptr++;
X         str_ptr++;
X      } while (str_ptr != eq_ptr);
X 
X      *ptr = '\0';
X
X      ptr = s;
X      do 
X      {
X         *ptr = *str_ptr; 
X         ptr++;
X         str_ptr++;
X      } while (*str_ptr != '\0');
X
X      *ptr = '\0';
X   }
X   else
X   {
X      *name = '\0';
X      strcpy (s, Str);
X   }
X} 
X
Xvoid UpdateAttr (TextPtr, AttrPtr)
X   struct TextRec	* TextPtr;
X   struct AttrRec	* AttrPtr;
X   /* This routine updates the name and value in the AttrRec */
X   /*   and its ObjRec after an attribute was edited.        */
X{
X   char	s[MAXSTRING+1], name[MAXSTRING+1];
X
X   if (AttrPtr->nameshown)
X   {
X      ParseAttrStr (TextPtr->first->s, name, s);
X      strcpy (AttrPtr->s, s);
X      strcpy (AttrPtr->name, name);
X   }
X   else
X   {
X      strcpy (s, TextPtr->first->s);
X      strcpy (AttrPtr->s, s);
X   }
X
X   if (!(AttrPtr->shown))
X      TextPtr->first->s[0] = '\0';
X   else
X   {
X      if (AttrPtr->nameshown)
X      {
X         strcat (name, s);
X         strcpy (TextPtr->first->s, name);
X      }
X      else
X          strcpy (TextPtr->first->s, s);
X   }
X   UpdTextBBox (AttrPtr->obj);
X}
X
Xvoid DrawAttrs (Win, XOff, YOff, AttrPtr)
X   Window		Win;
X   int			XOff, YOff;
X   struct AttrRec	* AttrPtr;
X{
X   struct AttrRec	* ptr;
X
X   for (ptr = AttrPtr; ptr != NULL; ptr = ptr->next)
X      if (ptr->shown)
X         DrawTextObj(Win, XOff, YOff, ptr->obj);
X}
X
Xvoid MoveAttrs (AttrPtr, Dx, Dy)
X   int			Dx, Dy;
X   struct AttrRec	* AttrPtr;
X{
X   struct AttrRec	* ptr;
X
X   for (ptr = AttrPtr; ptr != NULL; ptr = ptr->next)
X   {
X      ptr->obj->x += Dx;
X      ptr->obj->y += Dy;
X      ptr->obj->bbox.ltx += Dx;
X      ptr->obj->bbox.lty += Dy;
X      ptr->obj->bbox.rbx += Dx;
X      ptr->obj->bbox.rby += Dy;
X      ptr->obj->obbox.ltx += Dx;
X      ptr->obj->obbox.lty += Dy;
X      ptr->obj->obbox.rbx += Dx;
X      ptr->obj->obbox.rby += Dy;
X   }
X}
X
Xvoid DelAllAttrs (AttrPtr)
X   struct AttrRec	* AttrPtr;
X{
X   struct AttrRec	* ptr;
X
X   for (ptr = AttrPtr; ptr != NULL; ptr = ptr->next)
X   {
X      FreeTextObj(ptr->obj);
X      FreeAttr(ptr);
X   }
X}
X
Xstatic
Xstruct AttrRec	* NewAttr (OwnerObjPtr, ObjPtr, Inherited)
X   struct ObjRec	* ObjPtr;
X   struct ObjRec	* OwnerObjPtr;
X   short		Inherited;
X{
X   struct AttrRec	* attr_ptr;
X    
X   attr_ptr = (struct AttrRec *) calloc (1, sizeof(struct AttrRec));
X   attr_ptr->shown = TRUE;
X   attr_ptr->nameshown = TRUE;
X   attr_ptr->inherited = Inherited;
X   attr_ptr->obj = ObjPtr;
X   attr_ptr->next= attr_ptr->prev = NULL;
X   attr_ptr->owner = OwnerObjPtr;
X   ObjPtr->detail.t->attr = attr_ptr;
X
X   return attr_ptr;
X}
X
Xstatic
Xvoid DupAnAttr (FromAttrPtr, ToAttrPtr)
X   register struct AttrRec	* FromAttrPtr, * ToAttrPtr;
X{
X   struct ObjRec	* text_obj_ptr;
X
X   text_obj_ptr = (struct ObjRec *) calloc (1, sizeof(struct ObjRec));
X   DupObjBasics (FromAttrPtr->obj, text_obj_ptr);
X   DupTextObj (FromAttrPtr->obj->detail.t, text_obj_ptr);
X
X   strcpy(ToAttrPtr->name, FromAttrPtr->name);
X   strcpy(ToAttrPtr->s, FromAttrPtr->s);
X   ToAttrPtr->shown = FromAttrPtr->shown;
X   ToAttrPtr->nameshown = FromAttrPtr->nameshown;
X   ToAttrPtr->inherited = FromAttrPtr->inherited;
X   ToAttrPtr->obj = text_obj_ptr;
X   ToAttrPtr->next= ToAttrPtr->prev = NULL;
X   text_obj_ptr->detail.t->attr = ToAttrPtr;
X}
X
Xvoid DupAttrs (FromObjPtr, ToObjPtr)
X   register struct ObjRec	* FromObjPtr, * ToObjPtr;
X{
X   register struct AttrRec	* to_attr_ptr, * from_attr_ptr;
X
X   topAttr = botAttr = NULL;
X   from_attr_ptr = FromObjPtr->fattr;
X   for ( ; from_attr_ptr != NULL; from_attr_ptr = from_attr_ptr->next)
X   {
X      to_attr_ptr = (struct AttrRec *) calloc (1, sizeof(struct AttrRec));
X      to_attr_ptr->owner = ToObjPtr;
X      DupAnAttr (from_attr_ptr, to_attr_ptr);
X      LinkInAttr (NULL, topAttr, to_attr_ptr);
X   }
X   ToObjPtr->fattr = topAttr;
X   ToObjPtr->lattr = botAttr;
X}
X
Xstatic
Xvoid AddAttr(ObjPtr, TextObjPtr)
X   struct ObjRec	* ObjPtr, * TextObjPtr;
X{
X   struct AttrRec	* attr_ptr;
X   struct TextRec	* text_ptr;
X   char			name[MAXSTRING+1], value[MAXSTRING+1];
X
X   text_ptr = TextObjPtr->detail.t; 
X
X   ParseAttrStr(text_ptr->first->s, name, value);
X   topAttr = ObjPtr->fattr;
X   botAttr = ObjPtr->lattr;
X
X   UnlinkObj (TextObjPtr);
X   TextObjPtr->next = TextObjPtr->prev = NULL;
X   attr_ptr = NewAttr (ObjPtr, TextObjPtr, FALSE); 
X   UpdateAttr (text_ptr, attr_ptr); 
X   LinkInAttr (NULL, topAttr, attr_ptr);
X
X   ObjPtr->fattr = topAttr;
X   ObjPtr->lattr = botAttr;
X}
X
Xvoid AddAttrs ()
X{
X   struct ObjRec	* owner_ptr = NULL;
X   struct SelRec	* sel_ptr;
X   int			text_count = 0, sel_ltx, sel_lty, sel_rbx, sel_rby;
X
X   for (sel_ptr = topSel; sel_ptr != NULL; sel_ptr = sel_ptr->next)
X      switch (sel_ptr->obj->type)
X      {
X         case OBJ_TEXT: text_count++; break;
X
X         case OBJ_BOX:
X         case OBJ_OVAL:
X         case OBJ_POLYGON:
X         case OBJ_POLY:
X         case OBJ_SYM:
X         case OBJ_GROUP:
X         case OBJ_ICON:
X         case OBJ_ARC:
X         case OBJ_RCBOX:
X         case OBJ_XBM:
X            if (owner_ptr != NULL)
X            {
X               Msg("Two non-text objects selected.");
X               return;
X            }
X            owner_ptr = sel_ptr->obj;
X            break; 
X      }
X 
X   if (text_count == 0)
X   {
X      Msg("No text objects selected to add as attributes.");
X      return;
X   }
X   if (owner_ptr == NULL)
X   {
X      Msg("No objects (other than TEXT objects) selected.");
X      return;
X   }
X
X   HighLightReverse ();
X   sel_ltx = selLtX; sel_lty = selLtY;
X   sel_rbx = selRbX; sel_rby = selRbY;
X
X   for (sel_ptr = botSel;  sel_ptr != NULL; sel_ptr = sel_ptr->prev)
X      if (sel_ptr->obj->type == OBJ_TEXT)
X         AddAttr(owner_ptr, sel_ptr->obj);
X
X   RemoveAllSel ();
X   UnlinkObj (owner_ptr);
X   AddObj (NULL, topObj, owner_ptr);
X   topSel = botSel = (struct SelRec *) calloc (1, sizeof(struct SelRec));
X   topSel->obj = owner_ptr;
X   topSel->prev = NULL;
X   botSel->next = NULL;
X   AdjObjBBox (owner_ptr);
X   UpdSelBBox ();
X   RedrawAreas (botObj, sel_ltx-(1<<zoomScale), sel_lty-(1<<zoomScale),
X         sel_rbx+(1<<zoomScale), sel_rby+(1<<zoomScale),
X         selLtX-(1<<zoomScale), selLtY-(1<<zoomScale),
X         selRbX+(1<<zoomScale), selRbY+(1<<zoomScale));
X   HighLightForward ();
X   justDupped = FALSE;
X}
X
Xstatic
Xvoid SaveAttr (FP, AttrPtr)
X   FILE			* FP;
X   struct AttrRec	* AttrPtr;
X{
X   fprintf (FP, "attr(\"");
X   SaveString (FP, AttrPtr->name);
X   fprintf (FP, "\", \"");
X   SaveString (FP, AttrPtr->s);
X   fprintf (FP, "\", %1d, %1d, %1d,\n",
X         AttrPtr->shown, AttrPtr->nameshown, AttrPtr->inherited);
X  
X   SaveTextObj (FP, AttrPtr->obj);
X   fprintf (FP, ")");         
X}
X
Xvoid SaveAttrs (FP, BotAttrPtr)
X   FILE			* FP;
X   struct AttrRec	* BotAttrPtr;
X{
X 
X   struct AttrRec       * ptr;
X
X   fprintf (FP, "[\n");
X
X   for (ptr = BotAttrPtr; ptr != NULL; ptr = ptr->prev)
X     {
X       SaveAttr (FP, ptr);
X       if (ptr->prev != NULL)
X         fprintf (FP, ",\n");
X     }
X
X   if (BotAttrPtr == NULL)
X      fprintf (FP, "]");
X   else
X      fprintf (FP, "\n]");
X}
X
Xstatic
Xchar * ReadAttrString (Str)
X   char	* Str;
X{
X   register char	* s = Str;
X
X   for (s = Str; *s != '\0' && *s != '"'; s++)
X      if (*s == '\\')
X         s++;
X
X   if (*s == '"') s++;
X   return (s);
X}
X
Xint ReadAttr (FP, AttrPtr, PRTGIF)
X   FILE			* FP;
X   struct AttrRec	* * AttrPtr;
X   int			PRTGIF;
X{
X   struct ObjRec	* TextObj;
X   char			inbuf[MAXSTRING+1], * s;
X   char			name[MAXSTRING+1], value[MAXSTRING+1];
X   int			len, shown, nameshown, inherited;
X 
X   fgets (inbuf, MAXSTRING, FP); 
X
X   if (inbuf[0] == ']')  return (FALSE);
X
X   *AttrPtr = (struct AttrRec *)  calloc (1, sizeof(struct AttrRec)); 
X
X   len = strlen(inbuf) - 1;
X   inbuf[len] = '\0';
X
X   strcpy(name, FindChar ('"', inbuf));
X   s = ReadAttrString (inbuf);
X   s = FindChar (',', s);
X   strcpy(value, FindChar ('"', s));
X   s = ReadAttrString (value);
X   s = FindChar (',', s);
X   sscanf (s, "%d, %d, %d", &shown, &nameshown, &inherited);
X
X   s = ReadString (name);
X   *(--s) = '\0';
X   strcpy ((*AttrPtr)->name, name);
X   s = ReadString (value);
X   *(--s) = '\0';
X   strcpy ((*AttrPtr)->s, value);
X
X   (*AttrPtr)->shown = shown;
X   (*AttrPtr)->nameshown = nameshown;
X   (*AttrPtr)->inherited = inherited;
X
X   ReadObj (FP, &TextObj, PRTGIF);
X   TextObj->detail.t->attr = *AttrPtr;
X   (*AttrPtr)->obj = TextObj;
X
X   return (TRUE);
X}
X
Xstatic
Xint ShowAndUpdAttrNames (Force)
X   int	Force;
X   /* Force will force attribute name to be shown whether the attribute */
X   /*    is inherited or not.                                           */
X   /* returns TRUE if any attribute names are updated                   */
X   /* This routine concatinate the 'name' and 's' first of every        */
X   /*    attribute of the selected object and assign that to the        */
X   /*    first line of the text object the attribute pointer points to. */
X{
X   struct SelRec	* sel_ptr;
X   struct ObjRec	* obj_ptr;
X   struct AttrRec	* attr_ptr;
X   int			picture_changed = FALSE, obj_changed;
X   int			len1, len2;
X   char			* s, msg[80];
X
X   for (sel_ptr = topSel; sel_ptr != NULL; sel_ptr = sel_ptr->next)
X   {
X      obj_ptr = sel_ptr->obj;
X      attr_ptr = obj_ptr->fattr;
X      if (attr_ptr != NULL)
X      {
X         obj_changed = FALSE;
X         for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next)
X         {
X            if (!(attr_ptr->nameshown) && (Force || !(attr_ptr->inherited)))
X            {
X               s = attr_ptr->obj->detail.t->first->s;
X               strcpy (s, attr_ptr->name);
X
X               len1 = strlen (attr_ptr->name);
X               len2 = strlen (attr_ptr->s);
X               if (len1+len2 >= MAXSTRING)
X               {
X                  sprintf (msg, "String length exceeds %1d.  String truncated.",
X                        MAXSTRING);
X                  Msg (msg);
X                  attr_ptr->s[MAXSTRING-len1] = '\0';
X               }
X
X               strcat (s, attr_ptr->s);
X               attr_ptr->nameshown = TRUE;
X               UpdTextBBox (attr_ptr->obj);
X               if (attr_ptr->shown) obj_changed = picture_changed = TRUE;
X            }
X         }
X         if (obj_changed) AdjObjBBox (obj_ptr);
X      }
X   }
X   return (picture_changed);
X}
X
Xvoid ShowAllAttrNames ()
X{
X   if (ShowAndUpdAttrNames (TRUE))
X   {
X      HighLightReverse ();
X      UpdSelBBox ();
X      RedrawAnArea (botObj, selLtX-(1<<zoomScale), selLtY-(1<<zoomScale),
X            selRbX+(1<<zoomScale), selRbY+(1<<zoomScale));
X      HighLightForward ();
X      SetFileModified (TRUE);
X   }
X}
X
Xstatic
Xint HideAndUpdAttrNames ()
X   /* returns TRUE if any attribute names are updated */
X   /* For all the first line of the selected object's attributes,    */
X   /*    this routine change them to the 's' field of the attribute. */
X{
X   struct SelRec	* sel_ptr;
X   struct ObjRec	* obj_ptr;
X   struct AttrRec	* attr_ptr;
X   int			picture_changed = FALSE, obj_changed;
X   char			* s;
X
X   for (sel_ptr = topSel; sel_ptr != NULL; sel_ptr = sel_ptr->next)
X   {
X      obj_ptr = sel_ptr->obj;
X      attr_ptr = obj_ptr->fattr;
X      if (attr_ptr != NULL)
X      {
X         obj_changed = FALSE;
X         for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next)
X         {
X            if (attr_ptr->nameshown && *(attr_ptr->name) != '\0')
X            {
X               attr_ptr->nameshown = FALSE;
X               s = attr_ptr->obj->detail.t->first->s;
X               strcpy (s, attr_ptr->s);
X               UpdTextBBox (attr_ptr->obj);
X               if (attr_ptr->shown) obj_changed = picture_changed = TRUE;
X            }
X         }
X         if (obj_changed) AdjObjBBox (obj_ptr);
X      }
X   }
X   return (picture_changed);
X}
X
Xvoid HideAllAttrNames ()
X{
X   int	sel_ltx, sel_lty, sel_rbx, sel_rby;
X
X   sel_ltx = selLtX; sel_lty = selLtY; sel_rbx = selRbX; sel_rby = selRbY;
X
X   if (HideAndUpdAttrNames ())
X   {
X      HighLightReverse ();
X      UpdSelBBox ();
X      RedrawAnArea (botObj, sel_ltx-(1<<zoomScale), sel_lty-(1<<zoomScale),
X            sel_rbx+(1<<zoomScale), sel_rby+(1<<zoomScale));
X      HighLightForward ();
X      SetFileModified (TRUE);
X   }
X}
X
Xvoid DetachGroupAttrs (ObjPtr, TopSelPtr, BotSelPtr)
X   struct ObjRec	* ObjPtr;
X   struct SelRec	* * TopSelPtr, * * BotSelPtr;
X{
X   struct AttrRec	* attr_ptr = ObjPtr->fattr;
X   struct SelRec	* new_sel_ptr;
X   int			len1, len2;
X   char			* s, msg[80];
X
X   for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next)
X   {
X      if (!(attr_ptr->nameshown))
X      {
X         s = attr_ptr->obj->detail.t->first->s;
X         strcpy (s, attr_ptr->name);
X
X         len1 = strlen (attr_ptr->name);
X         len2 = strlen (attr_ptr->s);
X         if (len1+len2 >= MAXSTRING)
X         {
X            sprintf (msg, "String length exceeds %1d.  String truncated.",
X                  MAXSTRING);
X            Msg (msg);
X            attr_ptr->s[MAXSTRING-len1] = '\0';
X         }
X
X         strcat (s, attr_ptr->s);
X         UpdTextBBox (attr_ptr->obj);
X      }
X
X      attr_ptr->obj->detail.t->attr = NULL;
X
X      attr_ptr->obj->prev = NULL;
X      attr_ptr->obj->next = ObjPtr->detail.r->first;
X
X      if (attr_ptr->obj->next == NULL)
X         ObjPtr->detail.r->last = attr_ptr->obj;
X      else
X          attr_ptr->obj->next->prev = attr_ptr->obj;
X      ObjPtr->detail.r->first = attr_ptr->obj;
X
X      new_sel_ptr = (struct SelRec *) calloc (1, sizeof(struct SelRec));
X      new_sel_ptr->obj = attr_ptr->obj;
X
X      new_sel_ptr->prev = NULL;
X      new_sel_ptr->next = *TopSelPtr;
X
X      if (new_sel_ptr->next == NULL)
X         *BotSelPtr = new_sel_ptr;
X      else
X         (*TopSelPtr)->prev = new_sel_ptr;
X      *TopSelPtr = new_sel_ptr;
X
X      cfree (attr_ptr);
X   }
X}
X
Xvoid DetachAttrs ()
X{
X   struct SelRec	* sel_ptr, * new_sel_ptr;
X   struct ObjRec	* obj_ptr;
X   struct AttrRec	* attr_ptr, * attr_ptr_next;
X   int			picture_changed, obj_changed;
X
X   HighLightReverse ();
X   picture_changed = ShowAndUpdAttrNames (FALSE);
X
X   for (sel_ptr = topSel; sel_ptr != NULL; sel_ptr = sel_ptr->next)
X   {
X      obj_ptr = sel_ptr->obj;
X      attr_ptr = obj_ptr->fattr;
X      if (attr_ptr != NULL)
X      {
X         topAttr = botAttr = NULL;
X         for ( ; attr_ptr != NULL; attr_ptr = attr_ptr_next)
X         {
X            attr_ptr_next = attr_ptr->next;
X            if (obj_ptr->type == OBJ_ICON && attr_ptr->inherited)
X            {
X               LinkInAttr (NULL, topAttr, attr_ptr);
X               continue;
X            }
X
X            if (!(attr_ptr->shown)) obj_changed = picture_changed = TRUE;
X            attr_ptr->obj->detail.t->attr = NULL;
X            AddObj (obj_ptr->prev, obj_ptr, attr_ptr->obj);
X            new_sel_ptr = (struct SelRec *) calloc (1, sizeof(struct SelRec));
X            new_sel_ptr->obj = obj_ptr->prev;
X            AddSel (sel_ptr->prev, sel_ptr, new_sel_ptr);
X            cfree (attr_ptr);
X         }
X         obj_ptr->fattr = topAttr;
X         obj_ptr->lattr = botAttr;
X         AdjObjBBox (obj_ptr);
X      }
X   }
X   if (picture_changed)
X   {
X      UpdSelBBox ();
X      RedrawAnArea (botObj, selLtX-(1<<zoomScale), selLtY-(1<<zoomScale),
X            selRbX+(1<<zoomScale), selRbY+(1<<zoomScale));
X      SetFileModified (TRUE);
X   }
X   HighLightForward ();
X}
X
Xvoid UpdAttr (AttrPtr)
X   struct AttrRec	* AttrPtr;
X   /* Update the text object's string value associated with AttrPtr */
X{
X   int	len1, len2;
X   char	msg[80];
X
X   if (AttrPtr->nameshown)
X   {
X      strcpy (AttrPtr->obj->detail.t->first->s, AttrPtr->name);
X
X      len1 = strlen (AttrPtr->name);
X      len2 = strlen (AttrPtr->s);
X      if (len1+len2 >= MAXSTRING)
X      {
X         sprintf (msg, "String length exceeds %1d.  String truncated.",
X               MAXSTRING);
X         Msg (msg);
X         AttrPtr->s[MAXSTRING-len1] = '\0';
X      }
X
X      strcat (AttrPtr->obj->detail.t->first->s, AttrPtr->s);
X   }
X   else
X      strcpy (AttrPtr->obj->detail.t->first->s, AttrPtr->s);
X   UpdTextBBox(AttrPtr->obj);
X}
X
Xstatic
Xint MoveOneAttr (ObjPtr, AttrPtr)
X   struct ObjRec	* ObjPtr;
X   struct AttrRec	* AttrPtr;
X{
X   struct ObjRec	* text_obj_ptr;
X   int          	x, y, grid_x, grid_y, dx, dy, placing = TRUE;
X   int          	ltx, lty, rbx, rby, changed = FALSE, moved = FALSE;
X   int			orig_x, orig_y, grid_orig_x, grid_orig_y;
X   XEvent		input;
X
X   text_obj_ptr = AttrPtr->obj;
X   Msg ("LEFT--show and move.  MIDDLE--toggle name shown.  RIGHT--hide attr.");
X
X   orig_x = OFFSET_X(text_obj_ptr->x);
X   orig_y = OFFSET_Y(text_obj_ptr->y);
X   GridXY (orig_x, orig_y, &grid_orig_x, &grid_orig_y);
X   ltx = OFFSET_X(text_obj_ptr->bbox.ltx);
X   lty = OFFSET_Y(text_obj_ptr->bbox.lty);
X   rbx = OFFSET_X(text_obj_ptr->bbox.rbx)+1;
X   rby = OFFSET_Y(text_obj_ptr->bbox.rby)+1;
X   SelBox (drawWindow, revDefaultGC, ltx, lty, rbx, rby);
X
X   XGrabPointer (mainDisplay, drawWindow, FALSE,
X         PointerMotionMask | ButtonPressMask,
X         GrabModeAsync, GrabModeAsync, None, handCursor, CurrentTime);
X   XWarpPointer (mainDisplay, None, drawWindow, 0, 0, 0, 0, orig_x, orig_y);
X
X   dx = dy = 0;
X   grid_x = grid_orig_x; grid_y = grid_orig_y;
X
X   while (placing)
X   {
X      XNextEvent (mainDisplay, &input);
X      if (input.type == MotionNotify)
X      {
X         x = input.xmotion.x;
X         y = input.xmotion.y;
X         GridXY (x, y, &grid_x, &grid_y);
X
X         if (moved = (grid_x != grid_orig_x+dx || grid_y != grid_orig_y+dy))
X         {
X            SelBox (drawWindow, revDefaultGC, ltx+dx, lty+dy, rbx+dx, rby+dy);
X            MarkRulers (grid_x, grid_y);
X         }
X
X         dx = grid_x - grid_orig_x;
X         dy = grid_y - grid_orig_y;
X
X         if (moved)
X            SelBox (drawWindow, revDefaultGC, ltx+dx, lty+dy, rbx+dx, rby+dy);
X      }
X      else if (input.type == ButtonPress)
X      {
X         XUngrabPointer (mainDisplay, CurrentTime);
X         placing = FALSE;
X         SelBox (drawWindow, revDefaultGC, ltx+dx, lty+dy, rbx+dx, rby+dy);
X         Msg ("");
X         switch (input.xbutton.button)
X         {
X            case Button1:
X               if (!(AttrPtr->shown))
X               {
X                  changed = TRUE;
X                  AttrPtr->shown = TRUE;
X               }
X               if (dx != 0 || dy != 0)
X               {
X                  MoveObj (text_obj_ptr, dx<<zoomScale, dy<<zoomScale);
X                  AdjObjBBox (ObjPtr);
X                  return (TRUE);
X               }
X               else
X               {
X                  if (changed) AdjObjBBox (ObjPtr);
X                  return (changed);
X               }
X               break;
X            case Button2:
X               if (!(AttrPtr->nameshown) || *(AttrPtr->name) != '\0')
X                  AttrPtr->nameshown = !AttrPtr->nameshown;
X               UpdAttr (AttrPtr);
X               if (AttrPtr->shown)
X               {
X                  AdjObjBBox (ObjPtr);
X                  return (TRUE);
X               }
X               return (FALSE);
X            case Button3:
X               if (AttrPtr->shown)
X               {
X                  AttrPtr->shown = FALSE;
X                  AdjObjBBox (ObjPtr);
X                  return (TRUE);
X               }
X               return (FALSE);
X         }
X      }
X   }
X}
X
Xstatic
Xint ChangeAttrJust (ObjPtr, AttrPtr)
X   struct ObjRec	* ObjPtr;
X   struct AttrRec	* AttrPtr;
X{
X   struct ObjRec	* text_obj_ptr;
X   int          	x, y, grid_x, grid_y, dx, dy, placing = TRUE;
X   int          	ltx, lty, rbx, rby, moved = FALSE;
X   int			orig_x, orig_y, grid_orig_x, grid_orig_y;
X   int			old_just = 0, new_just = 0;
X   XEvent		input;
X
X   text_obj_ptr = AttrPtr->obj;
X   Msg ("LEFT--left, MIDDLE--center, RIGHT--right justified.");
X
X   orig_x = OFFSET_X(text_obj_ptr->x);
X   orig_y = OFFSET_Y(text_obj_ptr->y);
X   GridXY (orig_x, orig_y, &grid_orig_x, &grid_orig_y);
X   ltx = OFFSET_X(text_obj_ptr->bbox.ltx);
X   lty = OFFSET_Y(text_obj_ptr->bbox.lty);
X   rbx = OFFSET_X(text_obj_ptr->bbox.rbx)+1;
X   rby = OFFSET_Y(text_obj_ptr->bbox.rby)+1;
X   SelBox (drawWindow, revDefaultGC, ltx, lty, rbx, rby);
X
X   XGrabPointer (mainDisplay, drawWindow, FALSE,
X         PointerMotionMask | ButtonPressMask,
X         GrabModeAsync, GrabModeAsync, None, handCursor, CurrentTime);
X   XWarpPointer (mainDisplay, None, drawWindow, 0, 0, 0, 0, orig_x, orig_y);
X
X   dx = dy = 0;
X   grid_x = grid_orig_x; grid_y = grid_orig_y;
X
X   while (placing)
X   {
X      XNextEvent (mainDisplay, &input);
X      if (input.type == MotionNotify)
X      {
X         x = input.xmotion.x;
X         y = input.xmotion.y;
X         GridXY (x, y, &grid_x, &grid_y);
X
X         if (moved = (grid_x != grid_orig_x+dx || grid_y != grid_orig_y+dy))
X         {
X            SelBox (drawWindow, revDefaultGC, ltx+dx, lty+dy, rbx+dx, rby+dy);
X            MarkRulers (grid_x, grid_y);
X         }
X
X         dx = grid_x - grid_orig_x;
X         dy = grid_y - grid_orig_y;
X
X         if (moved)
X            SelBox (drawWindow, revDefaultGC, ltx+dx, lty+dy, rbx+dx, rby+dy);
X      }
X      else if (input.type == ButtonPress)
X      {
X         XUngrabPointer (mainDisplay, CurrentTime);
X         placing = FALSE;
X         SelBox (drawWindow, revDefaultGC, ltx+dx, lty+dy, rbx+dx, rby+dy);
X         Msg ("");
X         old_just = text_obj_ptr->detail.t->just;
X         switch (input.xbutton.button)
X         {
X            case Button1: new_just = JUST_L; break;
X            case Button2: new_just = JUST_C; break;
X            case Button3: new_just = JUST_R; break;
X         }
X         if (old_just != new_just)
X         {
X            text_obj_ptr->detail.t->just = new_just;
X            UpdTextBBox (text_obj_ptr);
X            AdjObjBBox (ObjPtr);
X            return (TRUE);
X         }
X         return (FALSE);
X      }
X   }
X}
X
Xvoid MoveAttr ()
X{
X   struct ObjRec	* obj_ptr;
X   struct AttrRec	* attr_ptr, * attr_ptr1;
X   int			num_attrs = 0, i, index, x, y;
X   int			picture_changed, sel_ltx, sel_lty, sel_rbx, sel_rby;
X   int			* fore_colors, * pixel_ptr, * valid, * flag_ptr;
X   int			len1, len2;
X   char			* * attrStrs, * s, buf[MAXSTRING], msg[80];
X   unsigned int		button;
X
X   if (topSel != botSel || topSel == NULL)
X   { Msg ("Please select only ONE object."); return; }
X
X   obj_ptr = topSel->obj;
X   attr_ptr1 = attr_ptr = obj_ptr->fattr;
X
X   for ( ; attr_ptr1 != NULL; attr_ptr1 = attr_ptr1->next, num_attrs++) ;
X
X   if (num_attrs == 0)
X   { Msg ("Selected object currently has NO attributes."); return; }
X
X   attrStrs = (char * *) calloc (num_attrs, sizeof(char *));
X   fore_colors = pixel_ptr = (int *) calloc (num_attrs, sizeof(int));
X   valid = flag_ptr = (int *) calloc (num_attrs, sizeof(int));
X
X   attr_ptr1 = attr_ptr;
X   for (i = 0; i < num_attrs; i++, attr_ptr1 = attr_ptr1->next)
X   {
X      s = (char *) calloc (MAXSTRING, sizeof(char));
X      attrStrs[i] = s;
X      strcpy (s, attr_ptr1->name);
X
X      len1 = strlen (attr_ptr1->name);
X      len2 = strlen (attr_ptr1->s);
X      if (len1+len2 >= MAXSTRING)
X      {
X         sprintf (msg, "String length exceeds %1d.  String truncated.",
X               MAXSTRING);
X         Msg (msg);
X         attr_ptr1->s[MAXSTRING-len1] = '\0';
X      }
X
X      strcat (s, attr_ptr1->s);
X      *pixel_ptr++ = colorPixels[attr_ptr1->obj->color];
X      *flag_ptr++ = TRUE;
X   }
X
X   Msg ("Hold down left button to see attributes.");
X   strcpy (buf, "Left button move/see attributes.  ");
X   strcat (buf, "Middle button change attribute justifications.");
X   Msg (buf);
X   button = CornerLoop (&x, &y);
X   index = TextMenuLoop (x, y, attrStrs, num_attrs, fore_colors, valid, True);
X   if (index != INVALID)
X   {
X      attr_ptr1 = attr_ptr;
X      for (i = 0; i < index; i++, attr_ptr1 = attr_ptr1->next) ;
X      sel_ltx = selLtX; sel_lty = selLtY; sel_rbx = selRbX; sel_rby = selRbY;
X      if (button == Button1)
X      {
X         if (picture_changed = MoveOneAttr (obj_ptr, attr_ptr1))
X         {
X            HighLightReverse ();
X            UpdSelBBox ();
X            RedrawAreas (botObj, sel_ltx-(1<<zoomScale), sel_lty-(1<<zoomScale),
X                  sel_rbx+(1<<zoomScale), sel_rby+(1<<zoomScale),
X                  selLtX-(1<<zoomScale), selLtY-(1<<zoomScale),
X                  selRbX+(1<<zoomScale), selRbY+(1<<zoomScale));
X            SetFileModified (TRUE);
X            HighLightForward ();
X         }
X      }
X      else if (button == Button2)
X      {
X         if (picture_changed = ChangeAttrJust (obj_ptr, attr_ptr1))
X         {
X            HighLightReverse ();
X            UpdSelBBox ();
X            RedrawAreas (botObj, sel_ltx-(1<<zoomScale), sel_lty-(1<<zoomScale),
X                  sel_rbx+(1<<zoomScale), sel_rby+(1<<zoomScale),
X                  selLtX-(1<<zoomScale), selLtY-(1<<zoomScale),
X                  selRbX+(1<<zoomScale), selRbY+(1<<zoomScale));
X            SetFileModified (TRUE);
X            HighLightForward ();
X         }
X      }
X   }
X
X   for (i = 0; i < num_attrs; i++) cfree (attrStrs[i]);
X   cfree (attrStrs);
X   justDupped = FALSE;
X}
X
Xvoid CopyAndUpdateAttrs (ToObjPtr, FromObjPtr)
X   struct ObjRec	* ToObjPtr, * FromObjPtr;
X{
X   register struct AttrRec	* to_attr_ptr, * from_attr_ptr;
X
X   topAttr = botAttr = NULL;
X   from_attr_ptr = FromObjPtr->fattr;
X   for ( ; from_attr_ptr != NULL; from_attr_ptr = from_attr_ptr->next)
X   {
X      to_attr_ptr = ToObjPtr->fattr;
X      for ( ; to_attr_ptr != NULL; to_attr_ptr = to_attr_ptr->next)
X      {
X         if (from_attr_ptr->obj->color == to_attr_ptr->obj->color &&
X               strcmp (from_attr_ptr->name, to_attr_ptr->name) == 0)
X         {
X            if (*(from_attr_ptr->s) != '\0')
X            {
X               strcpy (to_attr_ptr->s, from_attr_ptr->s);
X               UpdAttr (to_attr_ptr);
X            }
X            break;
X         }
X      }
X      if (to_attr_ptr == NULL)
X      {  /* new attribute */
X         to_attr_ptr = (struct AttrRec *) calloc (1, sizeof(struct AttrRec));
X         to_attr_ptr->owner = ToObjPtr;
X         DupAnAttr (from_attr_ptr, to_attr_ptr);
X         LinkInAttr (NULL, topAttr, to_attr_ptr);
X      }
X   }
X   if (topAttr != NULL)
X   {
X      topAttr->prev = NULL;
X      botAttr->next = ToObjPtr->fattr;
X
X      if (ToObjPtr->fattr != NULL) ToObjPtr->fattr->prev = botAttr;
X      ToObjPtr->fattr = topAttr;
X      if (ToObjPtr->lattr == NULL) ToObjPtr->lattr = botAttr;
X      AdjObjBBox (ToObjPtr);
X   }
X}
END_OF_FILE
if test 28217 -ne `wc -c <'attr.c'`; then
    echo shar: \"'attr.c'\" unpacked with wrong size!
fi
# end of 'attr.c'
fi
echo shar: End of archive 1 \(of 23\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 23 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
---------------------------------> cut here <---------------------------------
-- 
Bill Cheng // UCLA Computer Science Department // (213) 206-7135
3277 Boelter Hall // Los Angeles, California 90024 // USA
william@CS.UCLA.EDU      ...!{uunet|ucbvax}!cs.ucla.edu!william