#include "cp.h"

#define SIZETIC  5  /* size major tik in pixels */
#define BOXOFF   10  /* add to filename box size */
#define TIKCOLOR 2  /* color for tiks */
#define BORDER   20 /* size between filename boxes */

struct RastPort *rp;
struct ViewPort *vp;

struct World wd;
struct CurView cv;
struct CurView ov;

WORD WIDTH;
WORD HEIGHT;
WORD OFFSET;

WORD xoff;
WORD yoff;

LONG precision = 2L;

/* Draw everything if full is TRUE autoscale */

void DrawView ( BOOL full )
{

      vp = &(Scr-> ViewPort); /* Always reinit since could be new screen */
      rp = PlotWindowWnd-> RPort;

	if (cv.xmin>=cv.xmax||cv.ymin>=cv.ymax)	FindWorld ();

     if( !(IsListEmpty(SetList)))
       {

          if( full ) FindWorld ();
	
		if (! HandlePlotWindowIDCMP()) Death(0);

          SetAPen(rp,1);

          OFFSET = rp->Font->tf_YSize + 2 * BORDER + Scr-> BarHeight;
          HEIGHT = PlotWindowWnd-> Height - OFFSET - ( CPANEL ? 4 : 3 ) * GADHEIGHT;

          yoff = OFFSET + HEIGHT;

          xoff = rp-> Font-> tf_XSize * 6 + BORDER + SIZETIC;

          DrawFileNameBoxes( yoff - HEIGHT);

          if ( WIDTH < BORDER || HEIGHT < BORDER ) Death(20);

          DrawColorBox( xoff , yoff, WIDTH, HEIGHT, 14);

          XAxis();
          YAxis();
          LabelTitle();
          
          DrawAllSets ();

          if ( sym ) SymAllSets();
          if ( grid ) Grid();
       }
     else
     	Erase( TRUE );
     	
}

/* Draw all sets in SetList */

void DrawAllSets ()
{
WORD p = 4;
struct Set *node;

     for ( node = (struct Set *)SetList-> lh_Head; node-> snode.ln_Succ; node = (struct Set *)node-> snode.ln_Succ )
       {

          SetAPen(rp,min(p,lastcolor));

          DrawSet ( node-> FirstPoint );

          p++;

          if ( p > lastcolor - 2 ) p = 4;

    	     if(! HandlePlotWindowIDCMP())	Death(5);

       }
}

/* Draw symbols on all sets */

void SymAllSets ()
{
struct Set *node;

     SetDrMd( rp, JAM2);

     if (depth > 2)
          SetAPen(rp,15);
     else
          SetAPen(rp,1);

     for ( node = (struct Set *)SetList-> lh_Head; node-> snode.ln_Succ; node = (struct Set *)node-> snode.ln_Succ )
       {

          SymSet ( node-> FirstPoint );

    	     if(! HandlePlotWindowIDCMP())	Death(5);

       }
}

/* Adjust view so all data sets show */

void FindWorld ()
{
struct Set *node;

     node = (struct Set *)SetList-> lh_Head;

     wd.xmax = node-> xmax;
     wd.xmin = node-> xmin;
     wd.ymax = node-> ymax;
     wd.ymin = node-> ymin;

     for ( node = (struct Set *)SetList-> lh_Head; node-> snode.ln_Succ; node = (struct Set *)node-> snode.ln_Succ )
       {

          wd.xmax = max( wd.xmax, node-> xmax);
          wd.xmin = min( wd.xmin, node-> xmin);
          wd.ymax = max( wd.ymax, node-> ymax);
          wd.ymin = min( wd.ymin, node-> ymin);

       }

     ov.xmax = cv.xmax = wd.xmax;
     ov.xmin = cv.xmin = wd.xmin;
     ov.ymax = cv.ymax = wd.ymax;
     ov.ymin = cv.ymin = wd.ymin;

     wd.xdelta = wd.xmax - wd.xmin;
     wd.ydelta = wd.ymax - wd.ymin;

     ov.xdelta = cv.xdelta = wd.xdelta;
     ov.ydelta = cv.ydelta = wd.ydelta;
}

/* Draw one set */

void DrawSet ( struct Point *ThisPoint )
{
LONG qx, qy;
LONG le, te, re, be;

struct Rectangle rect;
struct Region *new_region;
struct Region *old_region;

     rect.MinX = xoff;
     rect.MaxX = xoff + WIDTH;
     rect.MinY = yoff - HEIGHT;
     rect.MaxY = yoff;

     le = PlotWindowWnd-> LeftEdge;
     te = PlotWindowWnd-> TopEdge;
     re = PlotWindowWnd-> LeftEdge + PlotWindowWnd-> Width;
     be = PlotWindowWnd-> TopEdge + PlotWindowWnd-> Height;

     if ( ! (new_region = NewRegion())) return;

     if ( ! (OrRectRegion( new_region, &rect))) return;

     if (( old_region = InstallClipRegion( PlotWindowWnd-> WLayer, new_region ))) return;

     qx = ScaleX( ThisPoint-> xval);
     qy = ScaleY( ThisPoint-> yval);

     if ( qx < le ) qx = le;
     if ( qx > re ) qx = re;
     if ( qy < te ) qy = te;
     if ( qy > be ) qy = be;

     Move ( rp, qx, qy );

     do
       {

          ThisPoint = ThisPoint-> NextPoint;

          qx = ScaleX( ThisPoint-> xval);

          /* need to change if not time sampled data */
          if ( qx < le ) continue;
          if ( qx > re && RealTime ) break;

          qy = ScaleY( ThisPoint-> yval);

          if ( qy < te ) qy = te;
          if ( qy > be ) qy = be;

          Draw ( rp, qx, qy);

       } while ( ThisPoint-> NextPoint );

     new_region = InstallClipRegion(PlotWindowWnd->WLayer, old_region);

     DisposeRegion(new_region);
}

/* draw symbols on one set */

void SymSet ( struct Point *ThisPoint )
{
LONG qx, qy;
WORD dx, dy;
BOOL clip;

     dx = xoff + WIDTH;
     dy = yoff - HEIGHT;

     do {


          clip = FALSE;

          qx = ScaleX( ThisPoint-> xval);
          qy = ScaleY( ThisPoint-> yval);

          if ( qx < xoff )
            {
               qx = xoff;
               clip = TRUE;
            }
          else if ( qx > dx )
            {
               qx = dx;
               clip = TRUE;
            }
          if ( qy > yoff )
            {
               qy = yoff;
               clip = TRUE;
            }
          else if ( qy < dy )
            {
               qy = dy;
               clip = TRUE;
            }

          if ( !clip )
            {
               Move ( rp, qx - 1, qy + 1);
               Draw ( rp, qx + 1, qy - 1);
               Move ( rp, qx + 1, qy + 1);
               Draw ( rp, qx - 1, qy - 1);
            }

          ThisPoint = ThisPoint-> NextPoint;

     } while ( ThisPoint );
}

/* Draw recessed bevel box filled with color */

void DrawColorBox ( WORD xs ,WORD ys , WORD xw ,WORD yh, WORD color)
{

     SetAPen( rp, (MONO ? 0 : color));

     RectFill( rp, xs, ys - yh - 1, xs + xw, ys + 1 );

     DrawBevelBox( rp, xs - 2, ys - yh - 1 , xw + 5, yh + 4, GT_VisualInfo, VisualInfo, GTBB_Recessed, TRUE, TAG_DONE);
}


/* Draw Color boxes with filenames in them */

WORD DrawFileNameBoxes( WORD ys)
{
struct Set *node;
struct TextExtent txex;
WORD p = 4, h = 0, w = 0, xs, ns = 0;


     for ( node = (struct Set *)SetList-> lh_Head; node-> snode.ln_Succ; node = (struct Set *)node-> snode.ln_Succ )
       {
          TextExtent( rp, node-> fn, strlen( node-> fn ), &txex);

          w = max( w, txex.te_Width);
          h = max( h, txex.te_Height);

          ns++;
       }

     w += BOXOFF;
     h += BOXOFF;

     SetBPen( rp, 1);

     if ( ns > 1 )
          xs = PlotWindowWnd-> Width - w - BORDER;
     else
       {
          xs = ( PlotWindowWnd-> Width / 2 - w / 2);
          ys = (WORD)(txex.te_Height * 1.5);
       }

     WIDTH = PlotWindowWnd-> Width - (ns > 1 ? w + 2 * BORDER : xoff) - xoff; /* if only one set fnbox on top so width = windowwidth - 2*xoff */

	Erase(FALSE); /* need to erase before drawing fnboxes but could not get calc width till now */
	
	if (NOFNAME) /* if not drawing filename boxes set box symetrical and return */
	  {
	  	WIDTH = PlotWindowWnd-> Width - ( 2 * xoff);
	  	return((WORD)xoff);
	  }

     for ( node = (struct Set *)SetList-> lh_Head; node-> snode.ln_Succ; node = (struct Set *)node-> snode.ln_Succ )
       {
          SetAPen( rp, p);

          ys += h;

          TextExtent( rp, node-> fn, strlen( node-> fn ), &txex);

          if ( MONO == FALSE ) DrawColorBox( xs , ys, w, h, p );

          SetDrMd( rp, (JAM2 | INVERSVID));

          Move ( rp, xs + w/2 - txex.te_Width/2 , ys - BOXOFF / 2 );
          Text( rp, node-> fn, strlen( node-> fn));

          ys += BORDER;

          SetDrMd( rp, JAM2);

          p++;
          if ( p > lastcolor - 2 ) p = 4;
       }

     return (WORD)( ns > 1 ? w + 2 * BORDER : xoff ); /* return no longer used for anything */
}

/* Adjust xmin and xmax to even nubers and draw tiks with text */

void XAxis()
{
     LOGX ? logXAxis() : linXAxis();
}

/* Adjust ymin and ymax to even nubers and draw tiks with text */

void YAxis()
{
     LOGY ? logYAxis() : linYAxis();
}

void logXAxis()
{
LONG j, k, l;
double q, r;
struct TextExtent txex;

     /* Cant do negative log scale set lin */

     if( cv.xmin <= 0.0 )
       {
          SetWindowTitles( PlotWindowWnd, NULL, "Cant do LOG  X value <= zero" );
          LOGX = FALSE;
          linXAxis();
          return;
       }

     j = (LONG) log10( 1.00001 * cv.xmin );
     if( log10( cv.xmin ) <= 0.0 ) j-- ;
     cv.xmin = pow( 10.0, (double)j );

     k = (LONG) log10( 0.99999 * cv.xmax );
     if( log10( cv.xmax ) > 0.0 ) k++ ;
     cv.xmax = pow( 10.0, (double)k );

     cv.xdec = k - j;

     cv.xmode = -1;

     cv.xdelta = cv.xmax - cv.xmin;

     cv.xfact = 1;

	if (strlen(XLAB))
	  {	
          TextExtent( rp, XLAB, strlen( XLAB ), &txex);

          SetAPen( rp, (MONO ? 1 : TIKCOLOR));
          SetBPen( rp, 0);

          Move ( rp, xoff + WIDTH/2 - txex.te_Width/2, yoff + 2 * GADHEIGHT);
          Text( rp, XLAB, strlen( XLAB ));

	  }

     for( q = cv.xmin ; q < cv.xmax; j++)
       {
          ticX( q, TRUE);
          for( l = 2; l < 10; l++)
            {
               r = q * l;
               if( r > cv.xmax ) break;
               ticX( r, FALSE);
            }
          q = pow( 10.0, (double)j );
       }

     ticX( cv.xmax, TRUE);
}

void logYAxis()
{
LONG j, k, l;
double q, r;

     /* Cant do negative log scale set lin */

     if( cv.ymin <= 0.0 )
       {

          SetWindowTitles( PlotWindowWnd, NULL, "Cant do LOG  Y value <= zero" );

          LOGY = FALSE;
          linYAxis();
          return;
       }

     if (YLAB) LabelY(YLAB);

     j = (LONG) log10( 1.00001 * cv.ymin );
     if( log10( cv.ymin ) <= 0.0 ) j-- ;
     cv.ymin = pow( 10.0, (double)j );

     k = (LONG) log10( 0.99999 * cv.ymax );
     if( log10( cv.ymax ) > 0.0 ) k++ ;
     cv.ymax = pow( 10.0, (double)k );

     cv.ydec = k - j;

     cv.ymode = -1;

     cv.ydelta = cv.ymax - cv.ymin;

     cv.yfact = 1;

     for( q = cv.ymin ; q < cv.ymax; j++)
       {
          ticY( q, TRUE);
          for( l = 2; l < 10; l++)
            {
               r = q * l;
               if( r > cv.ymax ) break;
               ticY( r, FALSE);
            }
          q = pow( 10.0, (double)j );
       }

     ticY( cv.ymax, TRUE);
}

void linXAxis()
{
double a, p;
LONG b;
WORD k;
UBYTE s[32], t[128];
struct TextExtent txex;

     /* if x all the same value kluge */

     if ( cv.xmax <= cv.xmin )
       {
          if ( cv.xmax == 0.0 ) cv.xmax = 1.0;
          cv.xmax *= 1.01;
          cv.xmin *= 0.99;
       }

     /* end kluge */

     /* Calculate X View */

     cv.xtik = cv.xsubt = cv.xmode = cv.xprec = 0.0;


     tik( cv.xmin, cv.xmax, &cv.xtik, &cv.xsubt, &cv.xmode, &cv.xprec);

     a = cv.xmin / cv.xtik;
     Round ( &a );
     b = (LONG)a;
     if ( a < 0 && b != a ) b--;
     cv.xmin = cv.xtik * b;

     a = cv.xmax / cv.xtik;
     Round ( &a );
     b = (LONG)a;
     if ( a > 0 && b != a ) b++;
     cv.xmax = cv.xtik * b;

     cv.xdelta = cv.xmax - cv.xmin;

     SetDrMd( rp, JAM1);

	if ( XLAB) strcpy( t, XLAB);
	else       strcpy(t,"");

     if ( cv.xmode )
       {
          CalcMode ( cv.xdelta , &cv.xfact );
          sprintf( s, "x %.0le", cv.xfact);
          E2xTen( s );
		
		if (XLAB)
		  {
		  	strcat( t,"  ");
		  	strcat( t, s);
		  }
		else strcpy( t, s);
       }

	if (strlen(t))
	  {	
          TextExtent( rp, t, strlen( t ), &txex);

          SetAPen( rp, (MONO ? 1 : TIKCOLOR));

          Move ( rp, xoff + WIDTH/2 - txex.te_Width/2, yoff + 2 * GADHEIGHT);
          Text( rp, t, strlen( t ));

	  }

     /* Draw Tick Marks */

     a = p = cv.xmin;
     do
       {
          ticX( a, TRUE );
          a += cv.xtik;
          for ( k = 1; k <= cv.xsubt && p <= cv.xmax; k++)
            {
               ticX( p, FALSE);
               p = a - k * cv.xtik / cv.xsubt;
            }
       } while ( p < cv.xmax );

     ticX( cv.xmax, TRUE);
}

void linYAxis()
{
double a, p;
LONG b;
WORD k;
UBYTE s[32], t[128];

     /* if y all the same value kluge */

     if ( cv.ymax == cv.ymin )
       {
          if ( cv.ymax == 0.0 ) cv.ymax = 1.0;
          cv.ymax *= 1.01;
          cv.ymin *= 0.99;
       }

     /* end kluge */

     /* Calculate Y View */

     cv.ytik = cv.ysubt = cv.ymode = cv.yprec = 0.0;

     tik( cv.ymin, cv.ymax, &cv.ytik, &cv.ysubt, &cv.ymode, &cv.yprec);

     a = cv.ymin / cv.ytik;
     Round ( &a );
     b = (LONG)a;
     if ( a < 0 && b != a ) b--;
     cv.ymin = cv.ytik * b;

     a = cv.ymax / cv.ytik;
     Round ( &a );
     b = (LONG)a;
     if ( a > 0 && b != a ) b++;
     cv.ymax = cv.ytik * b;

     cv.ydelta = cv.ymax - cv.ymin;


     SetDrMd( rp, JAM1);

	if ( YLAB) strcpy( t, YLAB);
	else       strcpy(t,"");


     if ( cv.ymode )
       {
          CalcMode ( cv.ydelta , &cv.yfact );

          sprintf( s, "%.0le", cv.yfact);
          E2xTen( s );

		if (YLAB)
		  {
		  	strcat( t,"  ");
		  	strcat( t, s);
		  }
		else strcpy( t, s);


       }

	if (strlen(t))  LabelY(t);

     /* Draw Tick Marks */

     a = p = cv.ymin;
     do
       {
          ticY( a , TRUE);
          a += cv.ytik;
          for ( k = 1; k <= cv.ysubt && p <= cv.ymax; k++)
            {
               ticY( p, FALSE);
               p = a - k * cv.ytik / cv.ysubt;
            }
       } while ( p < cv.ymax );

     ticY( cv.ymax, TRUE);
}

/* Y label text needs to be rotated 90 degrees */

void LabelY(UBYTE *lab)
{
struct TextExtent txex;

     TextExtent( rp, lab, strlen( lab ), &txex);
     
     SetAPen( rp, (MONO ? 1 : TIKCOLOR));

	Move(rp,(SHORT)(txex.te_Height*1.5), yoff - HEIGHT/2 + txex.te_Width/2);

	VertText(rp,lab,strlen(lab));
}

void LabelTitle()
{
struct TextExtent txex;
	
	if (strlen(TITLE))
	  {
          TextExtent( rp, TITLE, strlen( TITLE ), &txex);

          SetAPen( rp, (MONO ? 1 : TIKCOLOR));

          Move ( rp, xoff + WIDTH/2 - txex.te_Width/2, PlotWindowWnd-> TopEdge + 1);
          Text( rp, TITLE, strlen( TITLE ));
       }
}

void Grid()
{
     if (! IsListEmpty(SetList))
       {
     	LOGX ? logXGrid() : linXGrid() ;
     	LOGY ? logYGrid() : linYGrid() ;
       }
}

void logXGrid()
{
double q;
double j, k;
LONG x;

     SetDrMd( rp, COMPLEMENT);
     SetDrPt( rp, 0x3333);

     j = log10( cv.xmin ) + 1.0;
     k = log10( cv.xmax );

     for( j; j < k; j += 1.0)
       {
          q = pow( 10.0, (double)j );
          x = ScaleX( q );
          if ( x < xoff + WIDTH - 1 )
            {
               Move( rp, x, yoff );
               Draw( rp, x, yoff - HEIGHT );
            }
       }

     SetDrPt( rp, 0xFFFF);
}


void logYGrid()
{
double q;
double j, k;
LONG y;

     SetDrMd( rp, COMPLEMENT);
     SetDrPt( rp, 0x3333);

     j = log10( cv.ymin ) + 1.0;
     k = log10( cv.ymax );

     for( j; j < k; j += 1.0)
       {
          q = pow( 10.0, (double)j );
          y = ScaleY( q );
          if ( y > yoff - HEIGHT + 1 )
            {
               Move( rp, xoff, y );
               Draw( rp, xoff + WIDTH, y );
            }
       }

     SetDrPt( rp, 0xFFFF);
}

void linXGrid()
{
double a;
WORD x;

     SetDrMd( rp, COMPLEMENT);
     SetDrPt( rp, 0x3333);

     a = cv.xmin;

     while ( a  < cv.xmax - cv.xtik )
       {
          a += cv.xtik;
          x = ScaleX( (double)a );
          if ( x < xoff + WIDTH - 1 )
            {
               Move( rp, x, yoff);
               Draw( rp, x, yoff - HEIGHT);
            }
       }

     SetDrPt( rp, 0xFFFF);
}

void linYGrid()
{
double a;
WORD y;

     SetDrMd( rp, COMPLEMENT);
     SetDrPt( rp, 0x3333);

     a = cv.ymin;

     while ( a < cv.ymax - cv.ytik )
       {
          a += cv.ytik;
          y = ScaleY( (double)a );
          if ( y > yoff - HEIGHT + 1 )
            {
               Move( rp, xoff, y );
               Draw( rp, xoff + WIDTH, y );
            }
       }

     SetDrPt( rp, 0xFFFF);
}

/* Color entire window with pen zero then refresh gadgets if control panel on*/

void Erase( BOOL all )
{
struct Rectangle frect;
struct Rectangle drect;
struct Region *new_region;
struct Region *old_region;

 
     SetDrMd( rp, JAM2);

	if ( !(IsListEmpty(SetList)) || ! all )
	  {
	     frect.MinX = 0;
     	frect.MaxX = PlotWindowWnd-> Width;
	     frect.MinY = 0;
     	frect.MaxY = PlotWindowWnd-> Height;

	     drect.MinX = xoff;
     	drect.MaxX = xoff + WIDTH;
	     drect.MinY = yoff - HEIGHT;
     	drect.MaxY = yoff;

	     if ( ! (new_region = NewRegion())) return;

	     if ( ! (OrRectRegion(  new_region, &frect))) return;
     	if ( ! (XorRectRegion( new_region, &drect))) return;

	     if (( old_region = InstallClipRegion( PlotWindowWnd-> WLayer, new_region ))) return;
	
		EraseRect( rp, 0, 0, PlotWindowWnd-> Width, PlotWindowWnd-> Height);

	     new_region = InstallClipRegion(PlotWindowWnd->WLayer, old_region);

	     DisposeRegion(new_region);
	  }
	else
		SetRast( rp, 0);

     if ( CPANEL ) RefreshGadgets( PlotWindowGadgets[0], PlotWindowWnd, NULL);

}

/* Draw an XAxis tik and put text if major */

void ticX ( double val, BOOL major)
{
LONG x, y;
UBYTE tx[32];
UBYTE *txp;
UBYTE fm[32];
double rs;
struct TextExtent txex;

     x = ScaleX((double) val);
     y = yoff + 3;
     Move ( rp, x, y);
     txp = tx;

     if ( major )
          y += SIZETIC;
     else
          y += SIZETIC/2;

     SetDrMd( rp, JAM2);
     SetBPen(rp,0);
     SetAPen( rp, ( MONO ? 1 : TIKCOLOR));

     Draw( rp, x, y);

     if ( major )
       {
          if ( cv.xmode == 1 )
            {
               rs = val / cv.xfact;
               Round( &rs );
               sprintf( tx, "%lg", rs);
            }
          else if ( cv.xmode == 0 )
            {
               sprintf( fm, "%%.%hdlf", cv.xprec);
               sprintf( tx, fm, val);
            }
          else if ( cv.xmode == -1 )
            {
               sprintf( tx, "%le", val);
               E2xTen( tx );
               txp++;
            }

          TextExtent( rp, txp, strlen( txp ), &txex);
          Move ( rp, x - txex.te_Width/2, y + txex.te_Height + SIZETIC / 2 );
          Text( rp, txp, strlen( txp ));
       }

}

/* Draw a YAxis tik and put text if major */

void ticY ( double val, BOOL major)
{
LONG x, y;
UBYTE tx[32];
UBYTE *txp;
UBYTE fm[32];
double rs;
struct TextExtent txex;

     y = ScaleY((double) val);
     x = xoff - 3;
     Move ( rp, x, y);
     txp = tx;

     if ( major )
          x -= SIZETIC;
     else
          x -= SIZETIC/2;

     SetDrMd( rp, JAM2);
     SetBPen( rp, 0);
     SetAPen( rp, (MONO ? 1 : TIKCOLOR));

     Draw( rp, x, y);

     if ( major )
       {
          if ( cv.ymode == 1 )
            {
               rs = val / cv.yfact;
               Round( &rs );
               sprintf( tx, "%lg", rs);
            }
          else if ( cv.ymode == 0 )
            {
               sprintf( fm, "%%.%hdlf", cv.yprec);
               sprintf( tx, fm, val);
            }
          else if ( cv.ymode == -1 )
            {
               sprintf( tx, "%le", val);
               E2xTen( tx );
               txp++;
            }


          TextExtent(rp, txp, strlen( txp ), &txex);
          Move( rp, x - txex.te_Width - SIZETIC / 2, y + txex.te_Height/2 - 1);
          Text( rp, txp, strlen( txp ));
       }
}

/* Routine does everything when Zoom gadget selected */

void Zoom()
{
BOOL   running = TRUE;
BOOL   select = FALSE;
LONG   j = 0, k = 0;
WORD   selco[2];
static WORD Cross [2];
struct IntuiMessage *m;
double a,b,c,d;

     ReportMouse( TRUE, PlotWindowWnd);
     SetMouseQueue( PlotWindowWnd, 1 );
     do {

       Wait ( 1L << PlotWindowWnd-> UserPort-> mp_SigBit );

       while( m = GT_GetIMsg( PlotWindowWnd->UserPort )) {

          CopyMem(( char * )m, ( char * )&PlotWindowMsg, (long)sizeof( struct IntuiMessage ));

          GT_ReplyIMsg( m );

          switch ( PlotWindowMsg.Class ) {

               case IDCMP_MOUSEMOVE:

                    if ( PlotWindowMsg.MouseX > xoff && PlotWindowMsg.MouseX < xoff + WIDTH
                         && PlotWindowMsg.MouseY < yoff && PlotWindowMsg.MouseY > yoff - HEIGHT)
                      {
                         SetDrMd( rp, COMPLEMENT);

                         if ( k )
                           {
                              Move( rp, xoff, Cross[1]);
                              Draw( rp, xoff + WIDTH, Cross[1]);

                              Move( rp, Cross[0], yoff);
                              Draw( rp, Cross[0], yoff - HEIGHT);
                           }


                         Move( rp, xoff, PlotWindowMsg.MouseY);
                         Draw( rp, xoff + WIDTH, PlotWindowMsg.MouseY);

                         Move( rp, PlotWindowMsg.MouseX, yoff);
                         Draw( rp, PlotWindowMsg.MouseX, yoff - HEIGHT);

                         if ( select )
                           {
                              if ( j )
                                {
                                   Move( rp, selco[0], selco[1]);
                                   Draw( rp, selco[0], Cross[1]);
                                   Move( rp, selco[0], selco[1]);
                                   Draw( rp, Cross[0], selco[1]);
                                }

                              Move( rp, selco[0], selco[1]);
                              Draw( rp, selco[0], PlotWindowMsg.MouseY);
                              Move( rp, selco[0], selco[1]);
                              Draw( rp, PlotWindowMsg.MouseX, selco[1]);

                              j++;
                           }

                         Cross[0] = PlotWindowMsg.MouseX;
                         Cross[1] = PlotWindowMsg.MouseY;

                         k++;
                      }

                    break;

               case IDCMP_MOUSEBUTTONS:
                    if (PlotWindowMsg.Code == SELECTUP) running = FALSE;
                    else if (PlotWindowMsg.Code == SELECTDOWN)
                      {
                         select = TRUE;
                         selco[0] = PlotWindowMsg.MouseX;
                         selco[1] = PlotWindowMsg.MouseY;
                         SetRGB4( &Scr-> ViewPort, 17,15,15,4);  /* set xpointer yellow for select */

                      }
                    break;

               case IDCMP_VANILLAKEY:

                              if ( k )
                                {
                                   Move( rp, xoff, Cross[1]);
                                   Draw( rp, xoff + WIDTH, Cross[1]);

                                   Move( rp, Cross[0], yoff);
                                   Draw( rp, Cross[0], yoff - HEIGHT);
                                   goto end;
                                }

               default:
                    break;
          }
       }
     } while ( running);

    	SetPointer( PlotWindowWnd, WAITPointer, WAITHEIGHT, WAITWIDTH, WAITXOFF , WAITYOFF);    /* Set pointer cross for zoom */
     
     if ( selco[0] == PlotWindowMsg.MouseX || selco[1] == PlotWindowMsg.MouseY )
       {
	     ReportMouse( FALSE, PlotWindowWnd);
          DrawView( FALSE );
          return;
       }
     if ( select )
       {
       
       	/* save unzoom settings */
       	ov.xmin   = cv.xmin;
       	ov.xmax   = cv.xmax;
       	ov.ymin   = cv.ymin;
       	ov.ymax   = cv.ymax;
       	ov.xdelta = cv.xdelta;
       	ov.ydelta = cv.ydelta;
       	

          a = ZoomX( selco[0] );
          b = ZoomX( PlotWindowMsg.MouseX );
          c = ZoomY( selco[1] );
          d = ZoomY( PlotWindowMsg.MouseY );

          cv.xmin = min( a, b);
          cv.xmax = max( a, b);

          cv.ymin = min( c, d);
          cv.ymax = max( c, d);

          cv.xdelta = cv.xmax - cv.xmin;
          cv.ydelta = cv.ymax - cv.ymin;

	     DrawView( FALSE );
     
      }
end:
      SetRGB4( &Scr-> ViewPort, 17,7, 8,15);  /* set pointer blue */

      ReportMouse( FALSE, PlotWindowWnd);

}

/* When mode is exponential keep in engineering units */

void CalcMode ( double delta , double *fact )
{
UBYTE s[32];
WORD e;
WORD j = 0, k = 0;

     sprintf( s ,"%.0le", delta);

     while ( s[k] != 'e' ) ++k;

     sscanf( &s[++k], "%hd", &e);

     if ( e < 1 )  while( j > e ) j -= 3;
     else  while( j+1 < e ) j += 3;

     *fact = pow( 10.0, (double)j );
}

/* Change exponetial to X10 */

void E2xTen( UBYTE *s)
{
WORD e;
WORD k = 0;

     while ( s[k] != 'e' && s[k] != 'E') ++k;

     sscanf( &s[++k], "%hd", &e);

     sprintf( s,"* 10%+hd",e);
}

/* Write X and Y to screen when mouse select
   Erase text if mouse has moved more than 3
   pixels since seldown */

void Identify(WORD x, WORD y, BOOL SelDOWN)
{
static WORD ox;
static WORD oy;
struct TextExtent txex;
static double zx;
static double zy;
UBYTE txt[32];
UBYTE fmt[8];

     SetDrMd( rp, COMPLEMENT);

     if( SelDOWN )
       {
          SetDrMd( rp, JAM1);
          SetAPen(rp,15);
          WritePixel( rp, x, y);
          SetAPen(rp,min(12,lastcolor));
          WritePixel( rp, x+1, y+1);
          WritePixel( rp, x+1, y-1);
          WritePixel( rp, x-1, y-1);
          WritePixel( rp, x-1, y+1);

          SetAPen(rp,13);
          WritePixel( rp, x+2, y+2);
          WritePixel( rp, x+2, y-2);
          WritePixel( rp, x-2, y-2);
          WritePixel( rp, x-2, y+2);

          zx = ZoomX( x );
          zy = ZoomY( y );

          SetDrMd( rp, COMPLEMENT);
       }

     else if ( (x >= ox - 3 && x <= ox + 3 )  && ( y >= oy - 3 && y <= oy + 3 ))
       {
          SetDrMd( rp, JAM1);
          x = ox;
          y = oy;
       }
     else
       {
          x = ox;
          y = oy;
       }


     if (depth > 2)
          SetAPen(rp,15);
     else
          SetAPen(rp,1);

	sprintf( fmt ,"%%.%ldlE", precision);
     sprintf( txt ,fmt, zx);

     TextExtent( rp, txt, strlen( txt ), &txex);
     Move ( rp, x+6, y + txex.te_Height);
     Text (rp,txt, strlen(txt));

     sprintf( txt ,fmt, zy);

     TextExtent( rp, txt, strlen( txt ), &txex);
     Move ( rp, x+6, y-2 );
     Text (rp,txt, strlen(txt));

     ox = x;
     oy = y;
}


int CrossHair()
{
LONG   k = 0;
BOOL  xlock = FALSE, ylock = FALSE;
static WORD Cross [2];
struct IntuiMessage *m;
double x, y;
WORD running = TRUE;
UBYTE txt[128];
UBYTE fmt[64];

	sprintf( fmt ,"Y = %%-%ld.%ldlE   X = %%-%ld.%ldlE", precision+6,precision,precision+6,precision);

    	SetPointer( PlotWindowWnd, IDPointer, IDWIDTH, IDHEIGHT, IDXOFF , IDYOFF);

     ReportMouse( TRUE, PlotWindowWnd);
     SetMouseQueue( PlotWindowWnd, 1 );
     do {

       Wait ( 1L << PlotWindowWnd-> UserPort-> mp_SigBit );

       while( m = GT_GetIMsg( PlotWindowWnd->UserPort )) {

          CopyMem(( char * )m, ( char * )&PlotWindowMsg, (long)sizeof( struct IntuiMessage ));

          GT_ReplyIMsg( m );

          switch ( PlotWindowMsg.Class ) {

               case IDCMP_MOUSEMOVE:

                    if ( PlotWindowMsg.MouseX > xoff && PlotWindowMsg.MouseX < xoff + WIDTH
                         && PlotWindowMsg.MouseY < yoff && PlotWindowMsg.MouseY > yoff - HEIGHT)
                      {
				     SetDrMd( rp, COMPLEMENT);

                         if ( k )
                           {
                              if (!ylock)
                                {  
                              	Move( rp, xoff, Cross[1]);
                              	Draw( rp, xoff + WIDTH, Cross[1]);
                                }

                              if (!xlock)
                                {
                                	Move( rp, Cross[0], yoff);
                              	Draw( rp, Cross[0], yoff - HEIGHT);
                                }
                           }

					if (!ylock)
					  {
                         	Move( rp, xoff, PlotWindowMsg.MouseY);
	                         Draw( rp, xoff + WIDTH, PlotWindowMsg.MouseY);
     	                    Cross[1] = PlotWindowMsg.MouseY;
				          y = ZoomY( Cross[1] );
				       }

                         if (!xlock)
                           {
                           	Move( rp, PlotWindowMsg.MouseX, yoff);
                         	Draw( rp, PlotWindowMsg.MouseX, yoff - HEIGHT);
	                         Cross[0] = PlotWindowMsg.MouseX;
				          x = ZoomX( Cross[0] );
                           }


	                    sprintf( txt ,fmt, y , x);
     	               SetWindowTitles( PlotWindowWnd, txt, txt );	

                         k++;
                      }

                    break;

               case IDCMP_MOUSEBUTTONS:
                    if (PlotWindowMsg.Code == SELECTDOWN)
                         Identify( Cross[0], Cross[1], TRUE);
                    else if (PlotWindowMsg.Code == SELECTUP)
                         Identify( Cross[0], Cross[1], FALSE);
               
                    break;

               case IDCMP_VANILLAKEY:
				switch (PlotWindowMsg.Code)
				  {  
				  	case  32 : /* hit space , same as X */
						if (!xlock) xlock = TRUE;
						else xlock = FALSE;
						break;
				  	case 'x' : /* hit x */
				  	case 'X' : /* hit X */
						if (!xlock) xlock = TRUE;
						else xlock = FALSE;
						break;
				  	case 'y' : /* hit y */
				  	case 'Y' : /* hit Y */
						if (!ylock) ylock = TRUE;
						else ylock = FALSE;
						break;
					default:
						running = FALSE;
						break;
				  }
				
				break;

               default:
               	running = FALSE;
                    break;
          }
       }
     } while ( running);


     if ( k )
       {
             SetDrMd( rp, COMPLEMENT);

             Move( rp, xoff, Cross[1]);
             Draw( rp, xoff + WIDTH, Cross[1]);

             Move( rp, Cross[0], yoff);
             Draw( rp, Cross[0], yoff - HEIGHT);
       }
     
      ReportMouse( FALSE, PlotWindowWnd);

	return (1);
}

int Measure(WORD startX, WORD startY)
{
LONG   k = 0;
double orX, orY;
double dx, dy;
struct IntuiMessage *m;
WORD running = TRUE;
static WORD oldX, oldY;
UBYTE txt[128];
UBYTE fmt[64];


	orX = ZoomX(startX);
	orY = ZoomY(startY);

	sprintf( fmt ,"deltaY = %%-%ld.%ldlE   deltaX = %%-%ld.%ldlE", precision+6,precision,precision+6,precision);

    	SetPointer( PlotWindowWnd, MSPointer, MSWIDTH, MSHEIGHT, MSXOFF , MSYOFF);

     ReportMouse( TRUE, PlotWindowWnd);
     SetMouseQueue( PlotWindowWnd, 1 );
     do {

       Wait ( 1L << PlotWindowWnd-> UserPort-> mp_SigBit );

       while( m = GT_GetIMsg( PlotWindowWnd->UserPort )) {

          CopyMem(( char * )m, ( char * )&PlotWindowMsg, (long)sizeof( struct IntuiMessage ));

          GT_ReplyIMsg( m );

          switch ( PlotWindowMsg.Class ) {

               case IDCMP_MOUSEMOVE:

                    if ( PlotWindowMsg.MouseX > xoff && PlotWindowMsg.MouseX < xoff + WIDTH
                         && PlotWindowMsg.MouseY < yoff && PlotWindowMsg.MouseY > yoff - HEIGHT)
                      {
				     SetDrMd( rp, COMPLEMENT);

                         if ( k )
                           {
                              Move( rp, startX, startY);
                              Draw( rp, oldX, oldY);
                           }

                         Move( rp, startX, startY);
                         Draw( rp, PlotWindowMsg.MouseX, PlotWindowMsg.MouseY);

    	                    oldX = PlotWindowMsg.MouseX;
    	                    oldY = PlotWindowMsg.MouseY;

			          dy = ZoomY( PlotWindowMsg.MouseY ) - orY;
			          dx = ZoomX( PlotWindowMsg.MouseX ) - orX;

	                    sprintf( txt ,fmt, dy , dx);
     	               SetWindowTitles( PlotWindowWnd, txt, txt );	

                         k++;
                      }

                    break;

               default:
               	running = FALSE;
                    break;
          }
       }
     } while ( running);


     
     ReportMouse( FALSE, PlotWindowWnd);

	Delay (10);
     while( m = GT_GetIMsg( PlotWindowWnd->UserPort )) GT_ReplyIMsg( m );

	return (1);
}

