/* The routines in this file are copyright (c) 1987 by Helene (Lee) Taran.
 * Permission is granted for use and free distribution as long as the
 * original author's name is included with the code.
 */

/*
 * Reformatted, and modified to compile without warnings and errors
 * under SAS/C -6.5x by gduncan@philips.oz.au (GMD). This included
 * proto generation, renaming of some literals to avoid name collisions,
 * and Amiga Version string (also displayed in Title bar).
 * No original version number, this version arbitrarily named 1.1. 
 * - otherwise no functional changes.
 * GMD - Sep 94
 */

#include "all.h"


int DrawAFrame = TRUE;
int CurveType = OPENB_NATURAL;


/* InRange : returns TRUE iff the mouse position is in the selection
 * range of the given control point position
 */

int
InRange (mouse, control)
     REAL_POINT *mouse, *control;
{
  return ((mouse->x >= control->x - CONTROL_RADIUS) &&
	  (mouse->x <= control->x + CONTROL_RADIUS) &&
	  (mouse->y >= control->y - CONTROL_RADIUS) &&
	  (mouse->y <= control->y + CONTROL_RADIUS));
}

/* Select_ControlPoint : returns the member of Control_Points that is
 * is selected at <x,y>. Returns FALSE if no point is selected.
 */

DLISTPTR
Select_ControlPoint (x, y)
     SHORT x, y;
{
  REAL_POINT tmp;
  int InRange ();
  DLISTPTR Find_Element ();

  tmp.x = (float) x;
  tmp.y = (float) y;
  return (Find_Element (&tmp, &Control_Points, InRange));
}


/* Print Instruction: prints a string in the upper left hand corner
 * of the window.  Assumes that the current pen color is the the
 * color you want the string to appear in.
 */

void
PrintInstruction (w, instr)
     WINDOW *w;
     char *instr;
{
  Move (w->RPort, w->LeftEdge + w->BorderLeft + 1,
	w->TopEdge + w->BorderTop + 1);
  Text (w->RPort, instr, strlen (instr));
}

/* GetPoint : Waits for the user to select a point in window <w> and returns its
 * x,y coordinates in terms of a REAL_POINT structure.
 */


DLISTPTR
GetPoint (w)
     WINDOW *w;
{
  REAL_POINT *tmp;
  DLISTPTR p;
  INTUIMESSAGE mcopy, *msg;
  RASTPORT *rp = w->RPort;
  BYTE old_mode = rp->DrawMode;

  if (!((tmp = (REAL_POINT *) calloc (1, sizeof (REAL_POINT))) &&
	(p = (DLISTPTR) calloc (1, sizeof (DLIST_ELEMENT)))))
    {
      fprintf (stderr, "splines : trouble in paradise : can't allocate point\n");
      panic (0);
    }
  SetDrMd (rp, COMPLEMENT);
  PrintInstruction (w, "Select A Point");
  while (1)
    {
      Wait (1 << w->UserPort->mp_SigBit);
      while (msg = (INTUIMESSAGE *) GetMsg (w->UserPort))
	{
	  mcopy = *msg;
	  ReplyMsg ((MESSAGE *) msg);
	  if ((msg->Class == MOUSEBUTTONS) && (msg->Code == SELECTDOWN) &&
	      Inside_Window (msg->MouseX, msg->MouseY, w))
	    {
	      tmp->x = (float) msg->MouseX;
	      tmp->y = (float) msg->MouseY;
	      PrintInstruction (w, "Select A Point");
	      SetDrMd (rp, old_mode);
	      PlopDot (w, tmp);
	      p->contents = tmp;
	      return (p);
	    }
	}
    }
}


/* PrintError: prints a error string to the window's upper left hand
 * corner for approx. 1.6 seconds.  The string is drawn in the complement
 * of the background so that it doesn't destroy what's already drawn in the
 * window. After the delay, the string is complemented out again so it
 * disappears.
 */

void
PrintError (w, str)
     WINDOW *w;
     char *str;
{
  RASTPORT *rp = w->RPort;
  BYTE old_mode = rp->DrawMode;
  SetDrMd (rp, COMPLEMENT);
  PrintInstruction (w, str);
  Delay (80l);
  PrintInstruction (w, str);
  SetDrMd (rp, old_mode);
}

void
DrawConstructionLine (w, p0, p1)	/* draws a dotted line from p0 to p1 */
     WINDOW *w;
     REAL_POINT *p0, *p1;
{
  RASTPORT *rp = w->RPort;
  BYTE old_pen = rp->FgPen;	/* save the old pen color */
  USHORT old_pat = rp->LinePtrn;	/* save the old line pattern */

  SetAPen (rp, AFRAME_COLOR);
  SetDrPt (rp, 0xcccc);		/* use a dotted line */
  Move (rp, (SHORT) p0->x, (SHORT) p0->y);
  Draw (rp, (SHORT) p1->x, (SHORT) p1->y);
  SetDrPt (rp, old_pat);
  SetAPen (rp, old_pen);

}

/* Edit_Curve : pops up the curve style editing menu in <w> and allows
 * the user to alter the current curve style
 */
void
Edit_CurveStyle (w)
     WINDOW *w;
{
  int option = PopUp (&CurveMenu, w);
  switch (option)
    {
    case TOGGLEAFRAME:
      DrawAFrame = !DrawAFrame;
      Redraw (w);
      break;
    case REDRAW:
      Redraw (w);
      break;
    case OPENB_TRIPLE:
      if (LENGTH (&Control_Points) < 4)
	{
	  PrintError (w, "?Error: Triple Knot option require minimum of 4 points");
	  return;
	}
      /* othewise fall through to action for the next case */
    case OPENB_NATURAL:
    case CLOSEDB:
    case CLOSED_INTRPL:
    case OPEN_INTRPL:
      if (option != CurveType)
	{
	  CurveType = option;
	  Redraw (w);
	}
      break;
    case QUIT:
      close_things ();
      exit (0);
      break;
    }
}


/* Edit_ControlPoint : pops up the control point editing menu in <w> and
 * allows the user to alter the given control point <p>.  Assumes
 * that <p> is the control point that the user just selected.
 */

void
Edit_ControlPoint (w, p)
     WINDOW *w;
     DLISTPTR p;
{
  int option = PopUp (&PointMenu, w);
  switch (option)
    {
    case ADD_AFTER:
      if (LENGTH (&Control_Points) == MAXG)
	{
	  PrintError (w, "No! Don't you think you've added enough points?");
	  return;
	}
      else
	Insert_After (p, GetPoint (w), &Control_Points);
      break;

    case ADD_BEFORE:
      if (LENGTH (&Control_Points) == MAXG)
	{
	  PrintError (w, "No! Don't you think you've added enough points?");
	  return;
	}
      else
	Insert_Before (p, GetPoint (w), &Control_Points);
      break;

    case MOVE_POINT:
      {
	DLISTPTR tmp;
	EraseDot (w, p->contents);
	free (p->contents);
	tmp = GetPoint (w);
	p->contents = tmp->contents;
	free (tmp);
	break;
      }
    case REMOVE_POINT:
      {
	int len = LENGTH (&Control_Points);
	if ((len == 4) && (CurveType == OPENB_TRIPLE))
	  {
	    PrintError (w, "?Error: Triple Knot option require minimum of 4 points");
	    return;
	  }
	else if (len == 3)
	  PrintError (w, "?Error: you must have a minimum of 3 control points");
	else
	  {
	    Remove_Element (p, &Control_Points);
	    free (p->contents);
	    free (p);
	  }
      }
      break;
    default:
      return;
    }
  Redraw (w);
}

void
EraseDot (w, dot)
     WINDOW *w;
     REAL_POINT *dot;
{
  control_image.PlanePick = 0;
  PlopDot (w, dot);
  control_image.PlanePick = 1;
}

void
PlopDot (w, point)
     WINDOW *w;
     REAL_POINT *point;
{
  DrawImage (w->RPort, &control_image, (SHORT) point->x, (SHORT) point->y);
}

void
Draw_ControlPoints (w)
     WINDOW *w;
{
  DLISTPTR tmp = &Control_Points;
  while ((tmp = tmp->next) != &Control_Points)
    PlopDot (w, POINT (tmp));
}

void
Redraw (w)
     WINDOW *w;
{
  RASTPORT *rp = w->RPort;
  SetRast (rp, ERASE);
  SetAPen (rp, CURVECOLOR);
  Draw_ControlPoints (w);
  switch (CurveType)
    {
    case CLOSEDB:
      Draw_Closed_Bspline (w, &Control_Points);
      break;
    case CLOSED_INTRPL:
      Draw_Closed_Ispline (w, &Control_Points);
      break;
    case OPEN_INTRPL:
      Draw_Open_Ispline (w, &Control_Points);
      break;
    case OPENB_TRIPLE:
      Draw_TripleKnot_Bspline (w, &Control_Points);
      break;
    default:
      Draw_Natural_Bspline (w, &Control_Points);
      break;
    }
}

/*--*/
€
