
/*  XTrkCad - Model Railroad CAD
 *  Copyright (C) 2005 Dave Bullis
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include "ccurve.h"
#include "cbezier.h"
#include "compound.h"
#include "cundo.h"
#include "drawgeom.h"
#include "fileio.h"
#include "param.h"
#include "track.h"
#include "common-ui.h"

static long drawGeomCurveMode;

#define contextSegs(N) DYNARR_N( trkSeg_t, context->Segs_da, N )

static dynArr_t points_da;
static dynArr_t anchors_da;
static dynArr_t select_da;

#define points(N) DYNARR_N( pts_t, points_da, N )
#define point_selected(N) DYNARR_N( wBool_t, select_da, N)
#define anchors(N) DYNARR_N( trkSeg_t, anchors_da, N)

static void EndPoly( drawContext_t * context, int cnt, wBool_t open)
{
	trkSeg_p segPtr;
	track_p trk;
	pts_t * pts;
	int inx;

	if (context->State==0 || cnt == 0) {
		return;
	}

	if ( cnt < 3 ) {
		DYNARR_RESET( trkSeg_t, tempSegs_da );
		ErrorMessage( MSG_POLY_SHAPES_3_SIDES );
		return;
	}
	pts = (pts_t*)MyMalloc( (cnt) * sizeof (pts_t) );
	for ( inx=0; inx<cnt; inx++ ) {
		pts[inx].pt = tempSegs(inx).u.l.pos[0];
		pts[inx].pt_type = wPolyLineStraight;
	}
	DYNARR_SET( trkSeg_t, tempSegs_da, 1 );
	segPtr = &tempSegs(0);
	segPtr->type = ( (context->Op == OP_POLY
	                  || context->Op == OP_POLYLINE )? SEG_POLY:SEG_FILPOLY );
	segPtr->u.p.cnt = cnt;
	segPtr->u.p.pts = pts;
	segPtr->u.p.angle = 0.0;
	segPtr->u.p.orig = zero;
	segPtr->u.p.polyType = open?POLYLINE:FREEFORM;
	UndoStart( _("Create Lines"), "newDraw" );
	trk = MakeDrawFromSeg( zero, 0.0, segPtr );
	DrawNewTrack( trk );
	DYNARR_RESET( trkSeg_t, tempSegs_da );
}



static void DrawGeomOk( BOOL_T started )
{
	track_p trk;
	int inx;

	if (tempSegs_da.cnt <= 0) {
		return;
	}
	if (!started) {
		UndoStart( _("Create Lines"), "newDraw" );
	}
	for ( inx=0; inx<tempSegs_da.cnt; inx++ ) {
		trk = MakeDrawFromSeg( zero, 0.0, &tempSegs(inx) );
		DrawNewTrack( trk );
	}
	DYNARR_RESET( trkSeg_t, tempSegs_da );
}

static void CreateEndAnchor(coOrd p, wBool_t lock)
{
	DIST_T d = tempD.scale*0.15;

	DYNARR_APPEND(trkSeg_t,anchors_da,1);
	int i = anchors_da.cnt-1;
	anchors(i).type = lock?SEG_FILCRCL:SEG_CRVLIN;
	anchors(i).color = wDrawColorBlue;
	anchors(i).u.c.center = p;
	anchors(i).u.c.radius = d/2;
	anchors(i).u.c.a0 = 0.0;
	anchors(i).u.c.a1 = 360.0;
	anchors(i).lineWidth = 0;
}

static void CreateLineAnchor(coOrd p, coOrd p0)
{
	DIST_T d = tempD.scale*0.15;
	coOrd p1;
	ANGLE_T a = FindAngle(p0,p);
	Translate(&p1,p,a,d*5);
	DYNARR_APPEND(trkSeg_t,anchors_da,1);
	int i = anchors_da.cnt-1;
	anchors(i).type = SEG_STRLIN;
	anchors(i).color = wDrawColorBlue;
	anchors(i).u.l.pos[0] = p;
	anchors(i).u.l.pos[1] = p0;
	anchors(i).lineWidth = 0;
}

static void CreateSquareAnchor(coOrd p)
{
	DIST_T d = tempD.scale*0.15;
	int i = anchors_da.cnt;
	DYNARR_SET(trkSeg_t,anchors_da,i+4);
	for (int j =0; j<4; j++) {
		anchors(i+j).type = SEG_STRLIN;
		anchors(i+j).color = wDrawColorBlue;
		anchors(i+j).lineWidth = 0;
	}
	anchors(i).u.l.pos[0].x = anchors(i+2).u.l.pos[1].x =
	                                  anchors(i+3).u.l.pos[0].x = anchors(i+3).u.l.pos[1].x = p.x-d/2;

	anchors(i).u.l.pos[0].y = anchors(i).u.l.pos[1].y =
	                                  anchors(i+1).u.l.pos[0].y =	anchors(i+3).u.l.pos[1].y = p.y-d/2;

	anchors(i).u.l.pos[1].x =
	        anchors(i+1).u.l.pos[0].x = anchors(i+1).u.l.pos[1].x =
	                        anchors(i+2).u.l.pos[0].x = p.x+d/2;

	anchors(i+1).u.l.pos[1].y =
	        anchors(i+2).u.l.pos[0].y = anchors(i+2).u.l.pos[1].y =
	                        anchors(i+3).u.l.pos[0].y = p.y+d/2;
}

BOOL_T FindTempNear(drawContext_t *context, coOrd *p)
{
	if (context->State == 2) {
		if ((context->Op >= OP_CURVE1) && (context->Op <= OP_CURVE4)) {
			if (context->ArcData.type == curveTypeCurve) {
				ANGLE_T a = FindAngle(context->ArcData.curvePos,*p);
				if (IsClose(FindDistance(context->ArcData.curvePos,
				                         *p)-context->ArcData.curveRadius) &&
				    (a>=context->ArcData.a0) && (a<=context->ArcData.a0+context->ArcData.a1)) {
					Translate(p,context->ArcData.curvePos,a,context->ArcData.curveRadius);
					return TRUE;
				}
			} else {
				if (IsClose(LineDistance(p,tempSegs(0).u.l.pos[0],tempSegs(0).u.l.pos[1]))) {
					return TRUE;
				}
			}
		} else if ( (context->Op >=OP_LINE) && (context->Op <= OP_BENCH)) {
			if (IsClose(LineDistance(p,tempSegs(0).u.l.pos[0],tempSegs(0).u.l.pos[1]))) {
				return TRUE;
			}
		}
	}
	return FALSE;
}

/**
 * Create and draw a graphics primitive (lines, arc, circle). The complete handling of mouse
 * movements and clicks during the editing process is done here.
 *
 * \param action IN mouse action
 * \param pos IN position of mouse pointer
 * \param context IN/OUT parameters for drawing op
 * \return next command state
 *
 * Note - Poly supports both clicking points and/or dragging sides. Close is space or enter.
 * Note - This routine will be recalled to C_UPDATE the last action if the State is 2 and the user updates the dialog
 *
 */

STATUS_T DrawGeomMouse(
        wAction_t action,
        coOrd pos,
        drawContext_t *context)
{
//	static int lastValid = FALSE;
	static BOOL_T locked;
	static coOrd pos0, pos0x, pos1, lastPos, movePos;
	trkSeg_p segPtr;
	pts_t *pts;
	int inx;
	static int segCnt;
	DIST_T d;
	ANGLE_T a1,a2;
	static ANGLE_T line_angle;
//	BOOL_T createTrack;

	switch (action&0xFF) {

	case C_UPDATE:
		if (context->State == 0 ) { return C_TERMINATE; }
		DYNARR_SET( trkSeg_t, tempSegs_da, 1 );
		if (context->Op != OP_POLY && context->Op != OP_FILLPOLY
		    && context->Op != OP_POLYLINE && context->State == 1) { return C_TERMINATE; }
		switch (context->Op) {
		case OP_CIRCLE1:
		case OP_CIRCLE2:
		case OP_CIRCLE3:
		case OP_FILLCIRCLE1:
		case OP_FILLCIRCLE2:
		case OP_FILLCIRCLE3:
			tempSegs(0).u.c.radius = context->radius;
			break;
		case OP_CURVE1:
		case OP_CURVE2:
		case OP_CURVE3:
		case OP_CURVE4:
			if (context->ArcData.type == curveTypeCurve) {
				if (tempSegs(0).u.c.radius != context->radius) {
					coOrd end;
					Translate(&end,context->ArcData.curvePos,context->ArcData.a0,
					          context->ArcData.curveRadius);
					tempSegs(0).u.c.radius = context->radius;
					Translate(&tempSegs(0).u.c.center,end,context->ArcData.a0+180,context->radius);
					context->ArcData.curvePos = tempSegs(0).u.c.center;
					context->ArcData.curveRadius = tempSegs(0).u.c.radius;
				}
				tempSegs(0).u.c.a1 = context->angle;
				context->ArcData.a1 = tempSegs(0).u.c.a1;
				Translate(&context->ArcData.pos1,context->ArcData.curvePos,context->ArcData.a0,
				          context->ArcData.curveRadius);
				Translate(&context->ArcData.pos2,context->ArcData.curvePos,
				          context->ArcData.a0+context->ArcData.a1,context->ArcData.curveRadius);
			} else {
				Translate(&tempSegs(0).u.l.pos[1],tempSegs(0).u.l.pos[0],context->angle,
				          context->length);
			}
			break;
		case OP_LINE:
		case OP_BENCH:
		case OP_TBLEDGE:
			a1 = FindAngle(pos0,pos1);
			Translate(&tempSegs(0).u.l.pos[1],tempSegs(0).u.l.pos[0],context->angle,
			          context->length);
			lastPos = pos1 = tempSegs(0).u.l.pos[1];
			context->angle = NormalizeAngle(context->angle);
			break;
		case OP_BOX:
		case OP_FILLBOX:
			pts = tempSegs(0).u.p.pts;
			a1 = FindAngle(pts[0].pt,pts[1].pt);
			Translate(&pts[1].pt,pts[0].pt,a1,context->length);
			a2 = FindAngle(pts[0].pt,pts[3].pt);
			Translate(&pts[2].pt,pts[1].pt,a2,context->width);
			Translate(&pts[3].pt,pts[0].pt,a2,context->width);
			break;
		case OP_POLY:
		case OP_FILLPOLY:
		case OP_POLYLINE:
			DYNARR_SET( trkSeg_t, tempSegs_da, segCnt );
			if (segCnt>1) {
				ANGLE_T an = FindAngle(tempSegs(segCnt-2).u.l.pos[0],
				                       tempSegs(segCnt-2).u.l.pos[1]);
				an = an+context->angle;
				Translate(&tempSegs(segCnt-1).u.l.pos[1],tempSegs(segCnt-1).u.l.pos[0],an,
				          context->length);
			} else {
				Translate(&tempSegs(0).u.l.pos[1],tempSegs(0).u.l.pos[0],context->angle,
				          context->length);
			}
			pos1 = lastPos = tempSegs(segCnt-1).u.l.pos[1];
			context->angle = fabs(context->angle);
			if (context->angle >180) { context->angle = context->angle - 180.0; }
			break;
		default:
			break;
		}
		context->Changed = TRUE;					//Update made
		MainRedraw();
		DYNARR_RESET( trkSeg_t, anchors_da );
		return C_CONTINUE;

	case C_START:
		context->State = 0;
		context->Changed = FALSE;
		segCnt = 0;
		CleanSegs(&tempSegs_da);
		DYNARR_RESET( trkSeg_t, tempSegs_da );
		DYNARR_RESET( trkSeg_t, anchors_da );
		locked = FALSE;
		if (!magneticSnap) {
			InfoMessage(_("+Alt for Magnetic Snap"));
		} else {
			InfoMessage(_("+Alt to inhibit Magnetic Snap"));
		}
		wSetCursor(mainD.d,defaultCursor);
		movePos = zero;
		context->UndoStarted = FALSE;
		return C_CONTINUE;

	case wActionMove:
		locked = FALSE;
		wSetCursor(mainD.d,defaultCursor);
		if ((context->State == 0 &&
		     context->Op != OP_FILLCIRCLE2 && context->Op != OP_CIRCLE2) ||
		    context->State ==2 ||
		    (context->State == 1 &&
		     (context->Op == OP_POLY || context->Op == OP_FILLPOLY
		      || context->Op == OP_POLYLINE))) {
			DYNARR_RESET( trkSeg_t, anchors_da );
			wSetCursor(mainD.d,defaultCursor);
			switch (context->Op) {  	//Snap pos to nearest line for lines and some curves
			case OP_CURVE1:
			case OP_CURVE2:
			case OP_CURVE3:
			case OP_CURVE4:
			case OP_CIRCLE2:
			case OP_CIRCLE3:
			case OP_FILLCIRCLE2:
			case OP_FILLCIRCLE3:
			case OP_LINE:
			case OP_DIMLINE:
			case OP_BENCH:
			case OP_TBLEDGE:
			case OP_BOX:
			case OP_FILLBOX:
			case OP_POLY:
			case OP_FILLPOLY:
			case OP_POLYLINE:;
				if (((MyGetKeyState() & WKEY_ALT)==0) == magneticSnap ) {
					coOrd p = pos;
					track_p t;
					if (((t=OnTrack(&p,FALSE,FALSE))!=NULL) && (IsClose(FindDistance(p,pos))) ) {
						if (context->Op == OP_DIMLINE ) {
							CreateEndAnchor(p,FALSE);
							// wSetCursor(mainD.d,wCursorNone);
							movePos = p;
							locked = TRUE;
						} else if (!IsTrack(t)) {
							CreateEndAnchor(p,FALSE);
							// wSetCursor(mainD.d,wCursorNone);
							movePos = p;
							locked = TRUE;
						}
					}
				}
				if (!locked && SnapPos(&pos)) {
					CreateEndAnchor(pos,FALSE);
					// wSetCursor(mainD.d,wCursorNone);
					movePos = pos;
					locked = TRUE;
				}
				break;
			default:
				;
			}
		}
		return C_CONTINUE;

	case wActionRDown:
	case wActionLDown:
		DYNARR_RESET( trkSeg_t, anchors_da );
		wSetCursor(mainD.d,defaultCursor);
		if (context->State == 2) {
			DYNARR_SET( trkSeg_t, tempSegs_da, segCnt );
			if ((context->Op == OP_POLY || context->Op == OP_FILLPOLY
			     || context->Op == OP_POLYLINE)) {
				EndPoly(context, segCnt, context->Op==OP_POLYLINE);
			} else {
				DrawGeomOk(TRUE);
			}
			context->UndoStarted = FALSE;
			segCnt = 0;
			DYNARR_RESET( trkSeg_t, anchors_da );
			context->State = 0;
			TryCheckPoint();
		}
		DYNARR_SET( trkSeg_t, tempSegs_da, 1 );
		context->Started = TRUE;
		line_angle = 90.0;
		if ((context->Op == OP_CURVE1 && context->State != 2) ||
		    (context->Op == OP_CURVE2 && context->State == 0) ||
		    (context->Op == OP_CURVE3 && context->State != 0) ||
		    (context->Op == OP_CURVE4 && context->State != 2) ||
		    (context->Op == OP_CIRCLE2 && context->State != 0) ||
		    (context->Op == OP_CIRCLE3 && context->State == 0) ||
		    (context->Op == OP_FILLCIRCLE2 && context->State != 0) ||
		    (context->Op == OP_FILLCIRCLE3 && context->State == 0) ||
		    (context->Op == OP_LINE) || (context->Op == OP_DIMLINE) ||
		    (context->Op == OP_BENCH) || (context->Op == OP_TBLEDGE) ||
		    (context->Op == OP_BOX) || (context->Op == OP_FILLBOX) ||
		    (context->Op == OP_POLY) || (context->Op == OP_POLYLINE)
		    || (context->Op == OP_FILLPOLY) ) {
			if (locked) { pos = movePos; }
		}
		if ((context->Op == OP_CURVE1 || context->Op == OP_CURVE2
		     || context->Op == OP_CURVE3 || context->Op == OP_CURVE4)
		    && context->State == 1) {
			;
		} else {
			pos0 = pos;
			pos1 = pos;
		}

		switch (context->Op) {
		case OP_LINE:
		case OP_DIMLINE:
		case OP_BENCH:
			switch (context->Op) {
			case OP_LINE:
				tempSegs(0).type = SEG_STRLIN;
				tempSegs(0).color = lineColor;
				break;
			case OP_DIMLINE:
				tempSegs(0).type = SEG_DIMLIN;
				tempSegs(0).color = wDrawColorBlack;
				break;
			case OP_BENCH:
				tempSegs(0).type = SEG_BENCH;
				tempSegs(0).color = benchColor;
				break;
			}
			tempSegs(0).lineWidth = lineWidth;
			tempSegs(0).u.l.pos[0] = tempSegs(0).u.l.pos[1] = pos;
			if ( context->Op == OP_BENCH || context->Op == OP_DIMLINE ) {
				tempSegs(0).u.l.option = context->benchOption;
			} else {
				tempSegs(0).u.l.option = 0;
			}
			context->message(
			        _("Drag next point, +Alt reverse Magnetic Snap or +Ctrl lock to 90 deg") );
			break;
		case OP_TBLEDGE:
			OnTableEdgeEndPt( NULL, &pos );
			tempSegs(0).type = SEG_TBLEDGE;
			tempSegs(0).color = wDrawColorBlack;
			tempSegs(0).lineWidth = (mainD.scale<=16)?(3/context->D->dpi*context->D->scale)
			                        :0;
			tempSegs(0).u.l.pos[0] = tempSegs(0).u.l.pos[1] = pos;
			tempSegs(0).u.l.option = 0;
			context->message(
			        _("Drag next point, +Alt reverse Magnetic Snap, or +Ctrl to lock to 90 degrees") );
			break;
		case OP_CURVE1: case OP_CURVE2: case OP_CURVE3: case OP_CURVE4:
			if (context->State == 0) {
				switch ( context->Op ) {
				case OP_CURVE1: drawGeomCurveMode = crvCmdFromEP1; break;
				case OP_CURVE2: drawGeomCurveMode = crvCmdFromTangent; break;
				case OP_CURVE3: drawGeomCurveMode = crvCmdFromCenter; break;
				case OP_CURVE4: drawGeomCurveMode = crvCmdFromChord; break;
				}
				CreateCurve( C_START, pos, FALSE, lineColor, lineWidth, drawGeomCurveMode,
				             &anchors_da, context->message );
				CreateCurve( C_DOWN, pos, FALSE, lineColor, lineWidth, drawGeomCurveMode,
				             &anchors_da, context->message );
			}
			break;
		case OP_CIRCLE1:
		case OP_CIRCLE2:
		case OP_CIRCLE3:
		case OP_FILLCIRCLE1:
		case OP_FILLCIRCLE2:
		case OP_FILLCIRCLE3:
			tempSegs(0).type = SEG_CRVLIN;
			tempSegs(0).color = lineColor;
			if ( context->Op >= OP_CIRCLE1 && context->Op <= OP_CIRCLE3 ) {
				tempSegs(0).lineWidth = lineWidth;
			} else {
				tempSegs(0).lineWidth = 0;
			}
			tempSegs(0).u.c.a0 = 0;
			tempSegs(0).u.c.a1 = 360;
			tempSegs(0).u.c.radius = 0;
			tempSegs(0).u.c.center = pos;
			context->message( _("Drag to set radius") );
			context->State = 1;
			break;
		case OP_FILLBOX:
			lineWidth = 0;
		/* no break */
		case OP_BOX:
			DYNARR_SET( trkSeg_t, tempSegs_da, 4 );
			for ( inx=0; inx<4; inx++ ) {
				tempSegs(inx).type = SEG_STRLIN;
				tempSegs(inx).color = lineColor;
				tempSegs(inx).lineWidth = lineWidth;
				tempSegs(inx).u.l.pos[0] = tempSegs(inx).u.l.pos[1] = pos;
			}
			context->message( _("Drag set box size") );
			break;
		case OP_POLY:
		case OP_FILLPOLY:
		case OP_POLYLINE:
			DYNARR_SET( trkSeg_t, tempSegs_da, segCnt );
			wBool_t first_spot = FALSE;
			if (segCnt == 1 && tempSegs(0).type == SEG_CRVLIN) {
				coOrd start;
				start = tempSegs(0).u.c.center;
				tempSegs(0).type = SEG_STRLIN;
				tempSegs(0).u.l.pos[0] = start;
				first_spot=TRUE;
			} else {
				DYNARR_APPEND( trkSeg_t, tempSegs_da, 10 );
			}
			segPtr = &tempSegs(tempSegs_da.cnt-1);
			segPtr->type = SEG_STRLIN;
			segPtr->color = lineColor;
			segPtr->lineWidth = (context->Op==OP_POLY
			                     || context->Op==OP_POLYLINE ? lineWidth : 0);
			//End if over start
			if ( segCnt>2 && IsClose(FindDistance(tempSegs(0).u.l.pos[0], pos ))) {
				segPtr->u.l.pos[0] = tempSegs(segCnt-1).u.l.pos[1];
				segPtr->u.l.pos[1] = tempSegs(0).u.l.pos[0];
				EndPoly(context, tempSegs_da.cnt, context->Op==OP_POLYLINE);
				DYNARR_RESET(pts_t, points_da);
				DYNARR_RESET(trkSeg_t,tempSegs_da);
				context->State = 0;
				segCnt = 0;
				return C_TERMINATE;
			}
			if (!first_spot) {
				if ( tempSegs_da.cnt == 1) {
					segPtr->u.l.pos[0] = pos;
				} else {
					segPtr->u.l.pos[0] = segPtr[-1].u.l.pos[1];
				}
			}
			segPtr->u.l.pos[1] = pos;
			context->State = 1;
			segCnt = tempSegs_da.cnt;
			context->message(_("+Alt - reverse Magnetic Snap or +Ctrl - lock to 90 deg"));
			break;
		}
		return C_CONTINUE;

	case wActionRDrag:
	case wActionLDrag:
		DYNARR_RESET(trkSeg_t, anchors_da );
		coOrd p = pos1 = pos;
		BOOL_T locked = FALSE, poslocked = FALSE;
		if ((context->Op == OP_CURVE1 && context->State == 1) ||
		    (context->Op == OP_CURVE2 && context->State == 0) ||
		    (context->Op == OP_CURVE4 && context->State != 1) ||
		    (context->Op == OP_CIRCLE2 && context->State != 0) ||
		    (context->Op == OP_CIRCLE3 && context->State == 0) ||
		    (context->Op == OP_FILLCIRCLE2 && context->State != 0) ||
		    (context->Op == OP_FILLCIRCLE3 && context->State == 0) ||
		    (context->Op == OP_BOX ) ||
		    (context->Op == OP_FILLBOX ) ||
		    (context->Op == OP_DIMLINE ) || (context->Op == OP_TBLEDGE) ||
		    (context->Op == OP_LINE ) || (context->Op == OP_BENCH) ||
		    (context->Op == OP_POLY) || (context->Op == OP_POLYLINE)
		    || (context->Op == OP_FILLPOLY) ) {
			if ( ( (MyGetKeyState() & WKEY_ALT)==0) == magneticSnap) {
				p = pos;
				if ((OnTrack( &p, FALSE, FALSE )!=NULL) && (IsClose(FindDistance(p,pos)))) {
					poslocked = TRUE;
					pos1 = p;

				}
			}
			if (!poslocked) {  //Set up poslock and pos1 for later
				p = pos;
				if (SnapPos(&p)) {
					poslocked = TRUE;
					pos1 = p;
				}
			}
		}

		switch (context->Op) {
		case OP_TBLEDGE:
			if ((MyGetKeyState() & WKEY_CTRL) ==
			    WKEY_CTRL) {  //If +Ctrl, snap to table edge end
				p = pos;
				if (OnTableEdgeEndPt( NULL, &p )) {
					locked = TRUE;
					pos1 = p;
				}
			}
		/* no break */
		case OP_LINE:
		case OP_DIMLINE:
		case OP_BENCH:
			if (!locked
			    && ((MyGetKeyState() & WKEY_CTRL) ==
			        WKEY_CTRL )) { //If not found already +Ctl = Right Angle
				//Snap to Right-Angle from previous or from 0
				DIST_T l = FindDistance(pos0, pos);
				ANGLE_T angle2 = NormalizeAngle(FindAngle(pos0, pos)-line_angle);
				int quad = (int)((angle2 + 45.0) / 90.0);
				if (tempSegs_da.cnt != 1 && (quad == 2)) {
					pos1 = pos0;
				} else if (quad == 1 || quad == 3) {
					if (tempSegs_da.cnt != 1) {
						l = fabs(l*cos(D2R(((quad==1)?line_angle+90.0:line_angle-90.0)-FindAngle(pos,
						                   pos0))));
					}
					Translate( &pos1, pos0, NormalizeAngle(quad==1?line_angle+90.0:line_angle-90.0),
					           l );
				} else {
					if (tempSegs_da.cnt != 1) {
						l = fabs(l*cos(D2R(((quad==0
						                     ||quad==4)?line_angle:line_angle+180.0)-FindAngle(pos,pos0))));
					}
					Translate( &pos1, pos0, NormalizeAngle((quad==0
					                                        ||quad==4)?line_angle:line_angle+180.0), l );
				}
				CreateLineAnchor(pos1,pos0);
			}
			DYNARR_SET( trkSeg_t, tempSegs_da, 1 );
			tempSegs(0).u.l.pos[1] = pos1;
			context->message( _("Length = %s, Angle = %0.2f"),
			                  FormatDistance(FindDistance( pos0, pos1 )),
			                  PutAngle(FindAngle( pos0, pos1 )) );
			if (anchors_da.cnt == 0) { CreateEndAnchor(pos1, FALSE); }
			break;
		case OP_POLY:
		case OP_FILLPOLY:
		case OP_POLYLINE:
			if ((MyGetKeyState() & WKEY_CTRL) == WKEY_CTRL ) {
				coOrd last_point = zero;
				ANGLE_T last_angle;
//				ANGLE_T initial_angle;
				if (tempSegs_da.cnt == 1) {
					last_angle = 90.0;
					last_point = tempSegs(0).u.l.pos[0];
//					initial_angle = 90.0;
				} else {
					last_point = tempSegs(tempSegs_da.cnt-2).u.l.pos[1];
					last_angle = FindAngle(tempSegs(tempSegs_da.cnt-2).u.l.pos[0],
					                       tempSegs(tempSegs_da.cnt-2).u.l.pos[1]);
//					initial_angle = FindAngle(tempSegs(0).u.l.pos[0],tempSegs(0).u.l.pos[1]);
				}
				//Snap to Right-Angle from previous or from 0
				DIST_T l = FindDistance(tempSegs(tempSegs_da.cnt-1).u.l.pos[0], pos);
				ANGLE_T angle2 = NormalizeAngle(FindAngle(tempSegs(tempSegs_da.cnt
				                                -1).u.l.pos[0], pos)-last_angle);
				int quad = (int)((angle2+45.0)/90.0);
				if (tempSegs_da.cnt != 1 && (quad == 2)) {
					pos = tempSegs(tempSegs_da.cnt-1).u.l.pos[0];
				} else if (quad == 1 || quad == 3) {
					if (tempSegs_da.cnt != 1) {
						l = fabs(l*cos(D2R(((quad==1)?last_angle+90.0:last_angle-90.0)-FindAngle(pos,
						                   last_point))));
					}
					Translate( &pos, tempSegs(tempSegs_da.cnt-1).u.l.pos[0],
					           NormalizeAngle(quad==1?last_angle+90.0:last_angle-90.0), l );
				} else {
					if (tempSegs_da.cnt != 1) {
						l = fabs(l*cos(D2R(((quad==0
						                     ||quad==4)?last_angle:last_angle+180.0)-FindAngle(pos,last_point))));
					}
					Translate( &pos, tempSegs(tempSegs_da.cnt-1).u.l.pos[0], NormalizeAngle((quad==0
					                ||quad==4)?last_angle:last_angle+180.0), l );
				}
				CreateEndAnchor(pos,TRUE);
				if (FindDistance(pos,last_point)>0.0) { CreateLineAnchor(pos,last_point); }
				//If there is any point on this line that will give a 90 degree return to the first point, show it
				if (tempSegs_da.cnt > 1) {
					coOrd intersect;
					ANGLE_T an_this = FindAngle(tempSegs(tempSegs_da.cnt-2).u.l.pos[1],pos);
					if (FindIntersection(&intersect,tempSegs(0).u.l.pos[0],an_this+90.0,
					                     tempSegs(tempSegs_da.cnt-2).u.l.pos[1],an_this)) {
						ANGLE_T an_inter = FindAngle(tempSegs(tempSegs_da.cnt-2).u.l.pos[1],intersect);
						if (fabs(DifferenceBetweenAngles(an_inter,an_this))<90.0) {
							CreateSquareAnchor(intersect);
							d = FindDistance(intersect,pos);
							if (IsClose(d)) {
								pos = intersect;
							}
						}
					}
				}
			} else if (poslocked) { pos = pos1; }

			tempSegs(tempSegs_da.cnt-1).type = SEG_STRLIN;
			tempSegs(tempSegs_da.cnt-1).u.l.pos[1] = pos;
			context->message( _("Length = %s, Angle = %0.2f"),
			                  FormatDistance(FindDistance( tempSegs(tempSegs_da.cnt-1).u.l.pos[0], pos )),
			                  PutAngle(FindAngle( tempSegs(tempSegs_da.cnt-1).u.l.pos[0], pos )) );
			segCnt = tempSegs_da.cnt;
			break;
		case OP_CURVE1: case OP_CURVE2: case OP_CURVE3: case OP_CURVE4:
			if (context->State == 0) {
				pos0x = pos1;
				CreateCurve( C_MOVE, pos, FALSE, lineColor, lineWidth, drawGeomCurveMode,
				             &anchors_da, context->message );
			} else {
				PlotCurve( drawGeomCurveMode, pos0, pos0x, pos1, &context->ArcData, FALSE,
				           0.0 );
				DYNARR_SET( trkSeg_t, tempSegs_da, 1 );
				tempSegs(0).color = lineColor;
				tempSegs(0).lineWidth = lineWidth;
				if (context->ArcData.type == curveTypeStraight) {
					tempSegs(0).type = SEG_STRLIN;
					tempSegs(0).u.l.pos[0] = pos0;
					tempSegs(0).u.l.pos[1] = context->ArcData.pos1;
					CreateEndAnchor(pos0, FALSE);
					CreateEndAnchor(context->ArcData.pos1, FALSE);
					context->message( _("Straight Line: Length=%s Angle=%0.3f"),
					                  FormatDistance(FindDistance( pos0, context->ArcData.pos1 )),
					                  PutAngle(FindAngle( pos0, context->ArcData.pos1 )) );
				} else if (context->ArcData.type == curveTypeNone) {
					DYNARR_RESET( trkSeg_t, tempSegs_da );
					context->message( _("Back") );
				} else if (context->ArcData.type == curveTypeCurve) {
					tempSegs(0).type = SEG_CRVLIN;
					tempSegs(0).u.c.center = context->ArcData.curvePos;
					tempSegs(0).u.c.radius = context->ArcData.curveRadius;
					tempSegs(0).u.c.a0 = context->ArcData.a0;
					tempSegs(0).u.c.a1 = context->ArcData.a1;
					d = D2R(context->ArcData.a1);
					if (d < 0.0) {
						d = 2*M_PI+d;
					}
					if ( d*context->ArcData.curveRadius > mapD.size.x+mapD.size.y ) {
						ErrorMessage( MSG_CURVE_TOO_LARGE );
						DYNARR_RESET( trkSeg_t, tempSegs_da );
						context->ArcData.type = curveTypeNone;
						return C_CONTINUE;
					}
					context->message( _("Curved Line: Radius=%s Angle=%0.3f Length=%s"),
					                  FormatDistance(context->ArcData.curveRadius), context->ArcData.a1,
					                  FormatDistance(context->ArcData.curveRadius*d) );
					if (context->Op == OP_CURVE1 || context->Op == OP_CURVE4 ) {
						DrawArrowHeadsArray(&anchors_da,pos1,FindAngle(context->ArcData.curvePos,pos),
						                    TRUE,wDrawColorRed);
					} else if (context->Op == OP_CURVE2 || context->Op == OP_CURVE3 ) {
						CreateEndAnchor(context->ArcData.pos2,FALSE);
						DrawArrowHeadsArray(&anchors_da,context->ArcData.pos2,
						                    FindAngle(context->ArcData.curvePos,context->ArcData.pos2)+90,TRUE,
						                    wDrawColorRed);
					}
					CreateEndAnchor(context->ArcData.curvePos,TRUE);
				}
			}
			if (anchors_da.cnt == 0) { CreateEndAnchor(pos, FALSE); }
			break;
		case OP_CIRCLE1:
		case OP_FILLCIRCLE1:
			break;
		case OP_CIRCLE2:
		case OP_FILLCIRCLE2:
			tempSegs(0).u.c.center = pos1;
			if (context->State == 1 && locked) { CreateEndAnchor(pos1, FALSE); }
			else { wSetCursor(mainD.d,defaultCursor); }
			tempSegs(0).u.c.radius = FindDistance( pos0, pos1 );
			context->message( _("Radius = %s"),
			                  FormatDistance(FindDistance( pos0, pos1 )) );
			break;
		case OP_CIRCLE3:
		case OP_FILLCIRCLE3:
			if (context->State == 1) { CreateEndAnchor(pos0, TRUE); }
			wSetCursor(mainD.d,defaultCursor);
			tempSegs(0).u.c.radius = FindDistance( pos0, pos1 );
			context->message( _("Radius = %s"),
			                  FormatDistance(FindDistance( pos0, pos1 )) );
			break;
		case OP_BOX:
		case OP_FILLBOX:
			DYNARR_SET( trkSeg_t, tempSegs_da, 4 );
			tempSegs(0).u.l.pos[1].x = tempSegs(1).u.l.pos[0].x =
			                                   tempSegs(1).u.l.pos[1].x = tempSegs(2).u.l.pos[0].x = pos1.x;
			tempSegs(1).u.l.pos[1].y = tempSegs(2).u.l.pos[0].y =
			                                   tempSegs(2).u.l.pos[1].y = tempSegs(3).u.l.pos[0].y = pos1.y;
			if (locked) { CreateEndAnchor(pos1,FALSE); }
			context->message( _("Width = %s, Height = %s"),
			                  FormatDistance(fabs(pos1.x - pos0.x)), FormatDistance(fabs(pos1.y - pos0.y)) );
			break;
		}
		wSetCursor(mainD.d,wCursorNone);
		return C_CONTINUE;

	case wActionLUp:
	case wActionRUp:
//		lastValid = FALSE;
//		createTrack = FALSE;
		//Note - pos1 is last drag point
		wSetCursor(mainD.d,defaultCursor);
		if ((context->Op == OP_POLY) || (context->Op == OP_POLYLINE)
		    || (context->Op == OP_FILLPOLY )
		    || (context->Op == OP_BOX) || (context->Op == OP_FILLBOX) ) {
			;
		} else if (context->Op == OP_LINE || context->Op == OP_DIMLINE ||
		           context->Op == OP_BENCH || context->Op == OP_TBLEDGE ) {
			tempSegs(0).u.l.pos[1] = pos1;
		} else if ((context->Op>=OP_FILLCIRCLE1 && context->Op<=OP_FILLCIRCLE3) ||
		           (context->Op>=OP_CIRCLE1 && context->Op<=OP_CIRCLE3)) {
			;
		} else {
			PlotCurve( drawGeomCurveMode, pos0, pos0x, pos1, &context->ArcData, FALSE,
			           0.0 );
			if (context->ArcData.type == curveTypeStraight) {
				DYNARR_SET(trkSeg_t,tempSegs_da,1);
				tempSegs(0).type = SEG_STRLIN;
				tempSegs(0).u.l.pos[0] = pos0;
				tempSegs(0).u.l.pos[1] = context->ArcData.pos1;
			} else if (context->ArcData.type == curveTypeNone) {
				DYNARR_RESET(trkSeg_t,tempSegs_da);
			} else if (context->ArcData.type == curveTypeCurve) {
				DYNARR_SET(trkSeg_t,tempSegs_da,1);
				tempSegs(0).type = SEG_CRVLIN;
				tempSegs(0).u.c.center = context->ArcData.curvePos;
				tempSegs(0).u.c.radius = context->ArcData.curveRadius;
				tempSegs(0).u.c.a0 = context->ArcData.a0;
				tempSegs(0).u.c.a1 = context->ArcData.a1;
			}
		}
		switch ( context->Op ) {
		case OP_LINE:
		case OP_DIMLINE:
		case OP_BENCH:
		case OP_TBLEDGE:
//			lastValid = TRUE;
			lastPos = pos1;
			context->length = FindDistance(pos1,pos0);
			context->angle = FindAngle(pos0,pos1);
			context->State = 2;
			segCnt = tempSegs_da.cnt;
			break;
		case OP_CURVE1: case OP_CURVE2: case OP_CURVE3: case OP_CURVE4:
			if (context->State == 0) {
				context->State = 1;
				context->ArcAngle = FindAngle( pos0, pos1 );
				pos0x = pos1;
				CreateCurve( C_UP, pos, FALSE, lineColor, lineWidth, drawGeomCurveMode,
				             &anchors_da, context->message );
				context->message( _("Drag on Red arrows to adjust curve") );
				context->show = FALSE;
				return C_CONTINUE;
			} else {
				DYNARR_SET(trkSeg_t,tempSegs_da,1);
				if (context->ArcData.type == curveTypeCurve) {
					segPtr = &tempSegs(0);
					segPtr->type = SEG_CRVLIN;
					segPtr->color = lineColor;
					segPtr->lineWidth = lineWidth;
					segPtr->u.c.center = context->ArcData.curvePos;
					segPtr->u.c.radius = context->ArcData.curveRadius;
					segPtr->u.c.a0 = context->ArcData.a0;
					segPtr->u.c.a1 = context->ArcData.a1;
					context->radius = context->ArcData.curveRadius;
					context->angle = context->ArcData.a1;
				} else if (context->ArcData.type == curveTypeStraight) {
					segPtr = &tempSegs(0);
					segPtr->type = SEG_STRLIN;
					segPtr->color = lineColor;
					segPtr->lineWidth = lineWidth;
					segPtr->u.l.pos[0] = pos0;
					segPtr->u.l.pos[1] = pos1;
					context->radius = 0;
					context->length = FindDistance(pos0,pos1);
					context->angle = FindAngle(pos0,pos1);
				}
//				lastValid = TRUE;
				lastPos = pos1;
				context->State = 2;
				if (context->Op == OP_CURVE1 || context->Op == OP_CURVE4 ) {
					DrawArrowHeadsArray(&anchors_da,pos1,FindAngle(context->ArcData.curvePos,pos),
					                    TRUE,wDrawColorRed);
				} else if (context->Op == OP_CURVE2 || context->Op == OP_CURVE3 ) {
					CreateEndAnchor(context->ArcData.pos2,FALSE);
					DrawArrowHeadsArray(&anchors_da,context->ArcData.pos2,
					                    FindAngle(context->ArcData.curvePos,context->ArcData.pos2)+90,TRUE,
					                    wDrawColorRed);
				}
				CreateEndAnchor(context->ArcData.curvePos,TRUE);
				/*drawContext = context;
				DrawGeomOp( I2VP(context->Op) );*/
			}
			break;
		case OP_CIRCLE1:
		case OP_CIRCLE2:
		case OP_CIRCLE3:
		case OP_FILLCIRCLE1:
		case OP_FILLCIRCLE2:
		case OP_FILLCIRCLE3:
			DYNARR_SET( trkSeg_t, tempSegs_da, 1 );
			if ( context->Op>=OP_FILLCIRCLE1 && context->Op<=OP_FILLCIRCLE3 ) {
				tempSegs(0).type = SEG_FILCRCL;
			}
			context->State = 2;
			context->radius = tempSegs(0).u.c.radius;
			break;
		case OP_BOX:
		case OP_FILLBOX:
			pts = (pts_t*)MyMalloc( 4 * sizeof (pts_t) );
			for ( inx=0; inx<4; inx++ ) {
				pts[inx].pt = tempSegs(inx).u.l.pos[0];
				pts[inx].pt_type = wPolyLineStraight;
			}
			DYNARR_SET( trkSeg_t, tempSegs_da, 1 );
			tempSegs(0).type = (context->Op == OP_FILLBOX)?SEG_FILPOLY:SEG_POLY;
			tempSegs(0).u.p.cnt = 4;
			tempSegs(0).u.p.pts = pts;
			tempSegs(0).u.p.angle = 0.0;
			tempSegs(0).u.p.orig = zero;
			tempSegs(0).u.p.polyType = RECTANGLE;
			/*drawContext = context;
			DrawGeomOp( I2VP(context->Op) );*/
			context->length = FindDistance(pts[0].pt,pts[1].pt);
			context->width = FindDistance(pts[3].pt,pts[0].pt);
			context->State = 2;
			segCnt = tempSegs_da.cnt;
			break;
		case OP_POLY:
		case OP_FILLPOLY:
		case OP_POLYLINE:
			DYNARR_SET( trkSeg_t, tempSegs_da, segCnt );
			DYNARR_RESET( trkSeg_t, anchors_da );
			//End if close to start
			if ( segCnt>2 && IsClose(FindDistance(tempSegs(0).u.l.pos[0], pos))) {
				EndPoly(context, tempSegs_da.cnt, context->Op==OP_POLYLINE);
				DYNARR_RESET(pts_t, points_da);
				CleanSegs(&tempSegs_da);
				context->State = 0;
				segCnt = 0;
				return C_TERMINATE;
			}
			//If too short, remove last segment
			if (IsClose(FindDistance(tempSegs(segCnt-1).u.l.pos[0],pos))) {
				if (tempSegs_da.cnt>1) {
					--tempSegs_da.cnt;
					segCnt = tempSegs_da.cnt;
					wBeep();
				} else {   //First spot only
					tempSegs(0).color = wDrawColorRed;
					tempSegs(0).type = SEG_CRVLIN;
					tempSegs(0).u.c.a1 = 360;
					tempSegs(0).u.c.radius = tempD.scale*0.15/2;
					tempSegs(0).u.c.center = pos;
					segCnt = tempSegs_da.cnt;
				}
				return C_CONTINUE;
			}
			int text_inx = tempSegs_da.cnt-1;
			//tempSegs(tempSegs_da.cnt-1).u.l.pos[1] = pos;
			context->length = FindDistance(tempSegs(text_inx).u.l.pos[0],
			                               tempSegs(text_inx).u.l.pos[1]);
			if (text_inx>1) {
				ANGLE_T an = FindAngle(tempSegs(text_inx-1).u.l.pos[0],
				                       tempSegs(text_inx-1).u.l.pos[1]);
				context->angle = NormalizeAngle(FindAngle(tempSegs(text_inx).u.l.pos[0],
				                                tempSegs(text_inx).u.l.pos[1])-an);
			} else {
				context->angle = FindAngle(tempSegs(1).u.l.pos[0],tempSegs(1).u.l.pos[1]);
			}
			context->State = 1;
			context->index = text_inx;
			segCnt = tempSegs_da.cnt;
			return C_CONTINUE;
		}
		context->Started = FALSE;
		/*CheckOk();*/
		if (context->State == 2 && IsCurCommandSticky()) {
			segCnt = tempSegs_da.cnt;
			UndoStart("Create Lines","Sticky Draw");
			context->UndoStarted = TRUE;
			return C_CONTINUE;
		}
		DrawGeomOk(FALSE);
		context->State = 0;
		context->Changed = FALSE;
		context->message("");
		return C_TERMINATE;

	case wActionText:
		DYNARR_RESET(trkSeg_t, anchors_da );
		int key = (action>>8&0xFF);
		if ( key == 0x0D ||
		     key == ' ' ||
		     (key == 0x09
		      && ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) !=
		          WKEY_SHIFT))) {   //Tab continue
			if ((context->Op == OP_POLY) || (context->Op == OP_FILLPOLY)
			    || (context->Op == OP_POLYLINE)) {
				DYNARR_SET( trkSeg_t, tempSegs_da, segCnt );
				//If last segment wasn't just a point, add another starting on its end
				if (!IsClose(FindDistance(tempSegs(segCnt-1).u.l.pos[0],
				                          tempSegs(segCnt-1).u.l.pos[1]))) {
					DYNARR_APPEND(trkSeg_t,tempSegs_da,1);
					segPtr = &DYNARR_LAST( trkSeg_t, tempSegs_da );
					segPtr->type = SEG_STRLIN;
					segPtr->u.l.pos[0] = segPtr[-1].u.l.pos[1];
					segPtr->u.l.pos[1] = tempSegs(0).u.l.pos[0];
				}
				EndPoly(context, tempSegs_da.cnt, context->Op == OP_POLYLINE);
				DYNARR_RESET(pts_t, points_da);
				DYNARR_RESET(trkSeg_t,tempSegs_da);
			} else {
				if (context->State == 2) {
					DYNARR_SET( trkSeg_t, tempSegs_da, segCnt );
					DrawGeomOk(context->UndoStarted);
					context->UndoStarted = FALSE;

				}
			}
			context->State = 0;
			segCnt = 0;
			if (key == 0x0D) { return C_CONTINUE; }					//Esc - go to Reset
			else { return C_TERMINATE; }							//Space/Enter/Tab - end command
		} else if (key == 0x09
		           && ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) ==
		               WKEY_SHIFT)) {  //Tab plus shift - abandon
			context->State = 0;
			segCnt = 0;
			return C_TERMINATE;
		}
		return C_CONTINUE;

	case C_CONFIRM:
		if (context->State==2 && IsCurCommandSticky()) {
			DrawGeomOk(context->UndoStarted);
		}
		context->Changed = FALSE;
		return C_CONTINUE;

	case C_CANCEL:
		DYNARR_RESET(trkSeg_t, anchors_da );
		DYNARR_RESET( trkSeg_t, tempSegs_da );
		context->message( "" );
		context->Changed = FALSE;
		context->State = 0;
		segCnt = 0;
//		lastValid = FALSE;
		return C_TERMINATE;

	case C_REDRAW:
		DrawSegsDA( &tempD, NULL, zero, 0.0, &tempSegs_da, trackGauge, wDrawColorBlack,
		            0 );
		DrawSegsDA( &tempD, NULL, zero, 0.0, &anchors_da, 0.0, wDrawColorBlack, 0 );
		return C_CONTINUE;

	case C_CMDMENU:

		return C_CONTINUE;

	default:
		return C_CONTINUE;
	}
}
static int polyInx;
static int lineInx;
static int curveInx;

typedef enum {POLY_NONE, POLY_SELECTED, POLYPOINT_SELECTED} PolyState_e;
static PolyState_e polyState = POLY_NONE;
static coOrd rotate_origin;
static ANGLE_T rotate_angle;
//static dynArr_t origin_da;


void static CreateCircleAnchor(wBool_t selected,coOrd center, DIST_T rad,
                               ANGLE_T angle)
{
	DYNARR_RESET(trkSeg_t,anchors_da);
	double d = tempD.scale*0.15;
	DYNARR_APPEND(trkSeg_t,anchors_da,2);
	anchors(0).type = (selected)?SEG_FILCRCL:SEG_CRVLIN;
	anchors(0).u.c.a1 = 360.0;
	anchors(0).color = wDrawColorBlue;
	anchors(0).u.c.radius = d/2;
	PointOnCircle(&anchors(0).u.c.center,center,rad,angle);
}

void static CreateLineAnchors(int index, coOrd p0, coOrd p1)
{
	DYNARR_RESET(trkSeg_t,anchors_da);
	double d = tempD.scale*0.15;
	DYNARR_APPEND(trkSeg_t,anchors_da,2);
	anchors(0).type = (index ==0)?SEG_FILCRCL:SEG_CRVLIN;
	anchors(0).u.c.a1 = 360.0;
	anchors(0).color = wDrawColorBlue;
	anchors(0).u.c.radius = d/2;
	anchors(0).u.c.center = p0;
	DYNARR_APPEND(trkSeg_t,anchors_da,1);
	anchors(1).type = (index ==1)?SEG_FILCRCL:SEG_CRVLIN;
	anchors(1).u.c.a1 = 360.0;
	anchors(1).color = wDrawColorBlue;
	anchors(1).u.c.radius = d/2;
	anchors(1).u.c.center = p1;
	if (index>=0) { wSetCursor(mainD.d,wCursorNone); }
}
void static CreateBoxAnchors(int index, pts_t pt[4])
{
	DYNARR_RESET(trkSeg_t,anchors_da);
//	double d = tempD.scale*0.15;
	ANGLE_T a = FindAngle(pt[0].pt,pt[1].pt);
	ANGLE_T diag = FindAngle(pt[0].pt,pt[2].pt);
	if (index>=0) { wSetCursor(mainD.d,wCursorNone); }
	for (int i=0; i<4; i++) {
		DYNARR_SET(trkSeg_t,anchors_da,anchors_da.cnt+5);
		DrawArrowHeads(&DYNARR_N(trkSeg_t,anchors_da,anchors_da.cnt-5),pt[i].pt,
		               (diag>a?45.0:-45.0)+a+(90.0*(i)),TRUE,i==index?wDrawColorRed:wDrawColorBlue);
	}
	coOrd pp;
	for (int i=0; i<4; i++) {
		pp.x = (i==3?((((pt[0].pt.x - pt[i].pt.x)/2))+pt[i].pt.x):((
		                        pt[i+1].pt.x - pt[i].pt.x)/2)+pt[i].pt.x);
		pp.y = (i==3?((((pt[0].pt.y - pt[i].pt.y)/2))+pt[i].pt.y):((
		                        pt[i+1].pt.y - pt[i].pt.y)/2)+pt[i].pt.y);

		DYNARR_SET(trkSeg_t,anchors_da,anchors_da.cnt+5);
		DrawArrowHeads(&DYNARR_N(trkSeg_t,anchors_da,anchors_da.cnt-5),pp,90.0*(i-1)+a,
		               TRUE,i==index+5?wDrawColorRed:wDrawColorBlue);
	}
}

void static CreateOriginAnchor(coOrd origin, wBool_t trans_selected)
{
	double d = tempD.scale*0.15;
	DYNARR_APPEND(trkSeg_t,anchors_da,2);
	int i = anchors_da.cnt-1;
	coOrd p0,p1;
	Translate(&p0,origin,0,d*4);
	Translate(&p1,origin,0,-d*4);
	anchors(i).type = SEG_STRLIN;
	anchors(i).u.l.pos[0] = p0;
	anchors(i).u.l.pos[1] = p1;
	anchors(i).color = trans_selected?wDrawColorAqua:wDrawColorBlue;
	anchors(i).lineWidth = 0;
	DYNARR_APPEND(trkSeg_t,anchors_da,1);
	Translate(&p0,origin,90,d*4);
	Translate(&p1,origin,90,-d*4);
	i = anchors_da.cnt-1;
	anchors(i).type = SEG_STRLIN;
	anchors(i).u.l.pos[0] = p0;
	anchors(i).u.l.pos[1] = p1;
	anchors(i).color = wDrawColorBlue;
	anchors(i).lineWidth = 0;
	if (trans_selected) { wSetCursor(mainD.d,wCursorNone); }
}

void static CreateCurveAnchors(int index, coOrd pm, coOrd pc, coOrd p0,
                               coOrd p1)
{
	DYNARR_RESET(trkSeg_t,anchors_da);
	double d = tempD.scale*0.15;
	DYNARR_APPEND(trkSeg_t,anchors_da,9);
	anchors(0).type = (index ==0)?SEG_FILCRCL:SEG_CRVLIN;
	anchors(0).u.c.a1 = 360.0;
	anchors(0).color = wDrawColorBlue;
	anchors(0).u.c.radius = d/2;
	anchors(0).u.c.center = p0;
	anchors(0).lineWidth = 0;
	DYNARR_APPEND(trkSeg_t,anchors_da,8);
	anchors(1).type = (index ==1)?SEG_FILCRCL:SEG_CRVLIN;
	anchors(1).u.c.a1 = 360.0;
	anchors(1).color = wDrawColorBlue;
	anchors(1).u.c.radius = d/2;
	anchors(1).u.c.center = p1;
	anchors(1).lineWidth = 0;
	DYNARR_SET(trkSeg_t,anchors_da,anchors_da.cnt+5);
	DrawArrowHeads(&DYNARR_N(trkSeg_t,anchors_da,anchors_da.cnt-5),pm,FindAngle(pm,
	                pc),TRUE,index==2?wDrawColorAqua:wDrawColorBlue);
	if (index>=0) { wSetCursor(mainD.d,wCursorNone); }
	else { wSetCursor(mainD.d,defaultCursor); }
}

void static CreatePolyAnchors(int index)
{
	DYNARR_RESET(trkSeg_t,anchors_da);
	double d = tempD.scale*0.15;
	for ( int inx=0; inx<points_da.cnt; inx++ ) {
		DYNARR_APPEND(trkSeg_t,anchors_da,3);

		anchors(inx).type = point_selected(inx)?SEG_FILCRCL:SEG_CRVLIN;
		anchors(inx).u.c.a0 = 0.0;
		anchors(inx).u.c.a1 = 360.0;
		anchors(inx).lineWidth = 0;
		anchors(inx).color = wDrawColorBlue;
		anchors(inx).u.c.radius = d/2;
		anchors(inx).u.c.center = points(inx).pt;
	}
	if (index>=0) {
		DYNARR_APPEND(trkSeg_t,anchors_da,1);
		int inx = anchors_da.cnt-1;
		anchors(inx).type = SEG_STRLIN;
		anchors(inx).u.l.pos[0] = points(index==0?points_da.cnt-1:index-1).pt;
		anchors(inx).u.l.pos[1] = points(index).pt;
		anchors(inx).color = wDrawColorBlue;
		anchors(inx).lineWidth = 0;
		DYNARR_APPEND(trkSeg_t,anchors_da,1);
		inx = anchors_da.cnt-1;
		int index0 = index==0?points_da.cnt-1:index-1;
		ANGLE_T an0 = FindAngle(points(index0).pt, points(index).pt);
		ANGLE_T an1 = FindAngle(points(index0==0?points_da.cnt-1:index0-1).pt,
		                        points(index0).pt);
		anchors(inx).type = SEG_CRVLIN;
		if (DifferenceBetweenAngles(an0,an1)<=0) {
			anchors(inx).u.c.a1 = DifferenceBetweenAngles(an0,an1)-180;
			anchors(inx).u.c.a0 = an0;
		} else {
			anchors(inx).u.c.a1 = 180-DifferenceBetweenAngles(an0,an1);
			anchors(inx).u.c.a0 = NormalizeAngle(180+an1);
		}
		anchors(inx).color = wDrawColorBlue;
		anchors(inx).u.c.radius = d;
		anchors(inx).u.c.center = points(index0).pt;
	}
}

void CreateMovingAnchor(coOrd pos,BOOL_T fill)
{
	double d = tempD.scale*0.15;
	DYNARR_APPEND(trkSeg_t,anchors_da,1);
	int inx = anchors_da.cnt-1;
	anchors(inx).type = fill?SEG_FILCRCL:SEG_CRVLIN;
	anchors(inx).u.c.a0 = 0.0;
	anchors(inx).u.c.a1 = 360.0;
	anchors(inx).lineWidth = 0;
	anchors(inx).color = wDrawColorBlue;
	anchors(inx).u.c.radius = d/4;
	anchors(inx).u.c.center = pos;
	wSetCursor(mainD.d,wCursorNone);
}

/*
 * Modify Polygons. Polygons have a variable number of nodes.
 *
 * Each point has an anchor and selecting the node allows it to be moved
 * Selecting a point between nodes adds a node ready for dragging
 * The last selected node can be deleted
 *
 */
static STATUS_T DrawGeomPolyModify(
        wAction_t action,
        coOrd pos,
        drawModContext_t *context)
{
	double d;
	static int selected_count;
	static int segInx;
	static int prev_inx;
//	static wDrawColor save_color;
//	static wBool_t drawnAngle;
//	static double currentAngle;
//	static double baseAngle;
//	static BOOL_T lock;

	switch ( action&0xFF ) {
	case C_START:
//			lock = FALSE;
		DistanceSegs( context->orig, context->angle, context->segCnt, context->segPtr,
		              &pos, &segInx );
		if (segInx == -1) {
			return C_ERROR;
		}
		if (context->type != SEG_POLY && context->type != SEG_FILPOLY) {
			return C_ERROR;
		}
		prev_inx = -1;
		polyState = POLY_SELECTED;
		polyInx = -1;
		//Copy points
		DYNARR_RESET( pts_t, points_da);
		DYNARR_RESET( wBool_t, select_da);
		for (int inx=0; inx<context->segPtr->u.p.cnt; inx++) {
			DYNARR_APPEND(pts_t, points_da,3);
			DYNARR_APPEND(wBool_t,select_da,3);
			REORIGIN( points(inx).pt, context->segPtr[segInx].u.p.pts[inx].pt,
			          context->angle, context->orig );
			points(inx).pt_type = context->segPtr[segInx].u.p.pts[inx].pt_type;
			point_selected(inx) = FALSE;
		}
		context->prev_inx = -1;
		context->max_inx = points_da.cnt-1;
		selected_count=0;
		rotate_origin = context->orig;
		rotate_angle = context->angle;
		context->p0 = points(0).pt;
		context->p1 = points(1).pt;
		//Show points
		DYNARR_SET( trkSeg_t, tempSegs_da, 1 );
		tempSegs(0).lineWidth = context->segPtr->lineWidth;
//			save_color = context->segPtr->color;
		tempSegs(0).color = wDrawColorRed;
		tempSegs(0).type = context->type;
		tempSegs(0).u.p.cnt = context->segPtr[segInx].u.p.cnt;
		tempSegs(0).u.p.angle = 0.0;
		tempSegs(0).u.p.orig = zero;
		tempSegs(0).u.p.polyType = context->segPtr[segInx].u.p.polyType;
		tempSegs(0).u.p.pts = &points(0);
		CreatePolyAnchors( -1);
		InfoMessage(_("Select points or use context menu"));
		ClrAllTrkBitsRedraw( TB_UNDRAWN, TRUE );
		UndrawNewTrack( context->trk );
		return C_CONTINUE;
	case wActionMove:
		DYNARR_RESET(trkSeg_t,anchors_da);
		CreatePolyAnchors(context->prev_inx);
		for (int i = 0; i<points_da.cnt; i++) {
			if (IsClose(FindDistance(pos,points(i).pt))) {
				CreateMovingAnchor(points(i).pt,TRUE);
				return C_CONTINUE;
			}
		}
		wSetCursor(mainD.d,defaultCursor);
		int pInx=0;
		coOrd pm0,pm1;
		DIST_T dm = DIST_INF;
		for ( int inx=0; inx<points_da.cnt; inx++ ) {
			pm0 = pos;
			DIST_T ddm = LineDistance( &pm0, points( inx==0?points_da.cnt-1:inx-1).pt,
			                           points(inx).pt );
			if ( dm > ddm ) {
				dm = ddm;
				pm1 = pm0;
				pInx = inx;
			}
		}
		if (!IsClose(dm)) { return C_CONTINUE; }
		int inxm = pInx==0?points_da.cnt-1:pInx-1;
		dm = FindDistance( points(inxm).pt, pm1 );
		DIST_T ddm = FindDistance( points(inxm).pt, points(pInx).pt );
		if ( (dm > 0.25*ddm) && (dm < 0.75*ddm)) {
			CreateMovingAnchor(pm1,FALSE);
		} else {
			if (dm < FindDistance( points(pInx).pt, pm1 )) {
				CreateMovingAnchor(points(inxm).pt,TRUE);
			} else {
				CreateMovingAnchor(points(pInx).pt,TRUE);
			}
		}
		return C_CONTINUE;
		break;
	case C_DOWN:
		d = DIST_INF;
		polyInx = -1;
		coOrd p0;
		double dd;
		int inx;
		if ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) != WKEY_SHIFT) {
			if (selected_count <2 ) {
				//Wipe out selection(s) if we don't have multiple already (i,e. move with >1 selected)
				for (int i=0; i<points_da.cnt; i++) {
					point_selected(i) = FALSE;
				}
				selected_count = 0;
			} else {
				for (int i=0; i<points_da.cnt; i++) {
					if (IsClose(FindDistance(pos,points(i).pt)) && point_selected(i)==TRUE) {
						point_selected(i) = FALSE;
						selected_count--;
					}
				}
			}
		}
		//Select Point (polyInx)
		for ( int inx=0; inx<points_da.cnt; inx++ ) {
			p0 = pos;
			dd = LineDistance( &p0, points( inx==0?points_da.cnt-1:inx-1).pt,
			                   points(inx).pt );
			if ( d > dd ) {
				d = dd;
				polyInx = inx;
			}
		}
		if (!IsClose(d)) {	//Not on/near object - de-select all points
			for (int i=0; i<points_da.cnt; i++) {
				point_selected(i) = FALSE;
			}
			polyInx = -1;
			selected_count = 0;
			CreatePolyAnchors( -1);
			context->prev_inx = -1;
			return C_CONTINUE; //Not close to any line
		}
		polyState = POLYPOINT_SELECTED;
		inx = polyInx==0?points_da.cnt-1:polyInx-1;
		//Find if the point is to be added
		d = FindDistance( points(inx).pt, pos );
		dd = FindDistance( points(inx).pt, points(polyInx).pt );
		if ( d < 0.25*dd ) {
			polyInx = inx;
		} else if ( d > 0.75*dd ) {
			;
		} else {
			if (selected_count ==
			    0) {					//Only add a new point if no points are already selected!
				DYNARR_APPEND(wBool_t,select_da,1);
				for (int i=0; i<select_da.cnt; i++) {
					if (i == polyInx) { point_selected(i) = TRUE; }
					else { point_selected(i) = FALSE; }
				}
				selected_count=1;
				DYNARR_APPEND(pts_t,points_da,1);
				tempSegs(0).u.p.pts = &points(0);
				for (inx=points_da.cnt-1; inx>polyInx; inx-- ) {
					points(inx) = points(inx-1);
				}
				points(polyInx).pt_type = wPolyLineStraight;
				tempSegs(0).u.p.cnt = points_da.cnt;
				context->max_inx = points_da.cnt-1;
			}
		}
		//If already selected (multiple points), not using shift (to add) select, and on object move to first point
		if (selected_count>0
		    && ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) != WKEY_SHIFT)) {
			for (int i=0; i<points_da.cnt; i++) {
				if (IsClose(FindDistance(pos,points(i).pt))) {

					point_selected(i) = FALSE;

				}
				if (point_selected(i) == TRUE) {
					polyInx = i;
				}
			}
		}
		pos = points(polyInx).pt;  		//Move to point
		if (point_selected(polyInx)) {					//Already selected
		} else {
			point_selected(polyInx) = TRUE;
			++selected_count;
		}
		//Work out before and after point
		int first_inx = -1;
		if (selected_count >0 && selected_count < points_da.cnt-2) {
			for (int i=0; i<points_da.cnt; i++) {
				if (point_selected(i)) {
					first_inx = i;
					break;
				}
			}
		}
		int last_inx = -1;
//			int  next_inx = -1;
		ANGLE_T an1, an0;
		if (first_inx >=0) {
			if (first_inx == 0) {
				last_inx = points_da.cnt-1;
			} else {
				last_inx = first_inx-1;
			}
//				if (first_inx == points_da.cnt-1) {
//					next_inx = 0;
//				} else {
//					next_inx = first_inx+1;
//				}
			context->length = FindDistance(points(last_inx).pt,points(first_inx).pt);
			an1 = FindAngle(points(last_inx).pt,points(first_inx).pt);
			an0 = FindAngle(points(last_inx==0?(points_da.cnt-1):(last_inx-1)).pt,
			                points(last_inx).pt);
			if (DifferenceBetweenAngles(an0,an1)<=0) {
				context->rel_angle = 180+DifferenceBetweenAngles(an0,an1);
			} else {
				context->rel_angle = 180-DifferenceBetweenAngles(an0,an1);
			}
		} else {

		}
		context->prev_inx = first_inx;
		context->p0 = points(0).pt;
		context->p1 = points(1).pt;
		//Show three anchors only
		CreatePolyAnchors(first_inx);
		return C_CONTINUE;
	case C_LDOUBLE:
		return C_CONTINUE;
	case C_MOVE:
		DYNARR_SET( trkSeg_t, tempSegs_da, 1 );
		if (polyState != POLYPOINT_SELECTED) {
			return C_CONTINUE;
		}
		//Moving with Point Selected
		if (polyInx<0) { return C_ERROR; }
		first_inx = -1;
		if (selected_count >0 && selected_count < points_da.cnt-2) {
			for (int i=0; i<points_da.cnt; i++) {
				if (point_selected(i)) {
					first_inx = i;
					break;
				}
			}
		}
		last_inx = -1;
//			next_inx = -1;
		coOrd intersect;
		wBool_t show_intersect = FALSE;
		if (first_inx >=0) {
			if (first_inx == 0) {
				last_inx = points_da.cnt-1;
			} else {
				last_inx = first_inx-1;
			}
//				if (first_inx == points_da.cnt-1) {
//					next_inx = 0;
//				} else {
//					next_inx = first_inx+1;
//				}
			//Lock to 90 degrees first/last point
			if ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == WKEY_CTRL ) {
				ANGLE_T last_angle;
//					ANGLE_T next_angle;
				coOrd last_point,next_point;
				if (first_inx == 0) {
					last_point = points(points_da.cnt-1).pt;
					last_angle = FindAngle(points(points_da.cnt-2).pt,last_point);
				} else if (first_inx == 1) {
					last_point = points(0).pt;
					last_angle = FindAngle(points(points_da.cnt-1).pt,last_point);
				} else {
					last_point = points(first_inx-1).pt;
					last_angle = FindAngle(points(first_inx-2).pt,last_point);
				}
				if (first_inx == points_da.cnt-1) {
					next_point = points(0).pt;
//						next_angle = FindAngle(next_point,points(1).pt);
				} else if (first_inx == points_da.cnt-2) {
					next_point = points(points_da.cnt-1).pt;
//						next_angle = FindAngle(next_point,points(0).pt);
				} else {
					next_point = points(first_inx+1).pt;
//						next_angle = FindAngle(next_point,points(first_inx+2).pt);
				}
				coOrd diff;
				diff.x = pos.x - points(polyInx).pt.x;
				diff.y = pos.y - points(polyInx).pt.y;
				coOrd pos_lock = points(first_inx).pt;
				pos_lock.x += diff.x;
				pos_lock.y += diff.y;
				//Snap to Right-Angle from previous or from 0
				DIST_T l = FindDistance(last_point, pos_lock);
				ANGLE_T angle2 = NormalizeAngle(FindAngle(last_point, pos_lock)-last_angle);
				int quad = (int)((angle2+45.0)/90.0);
				if (tempSegs_da.cnt != 1 && (quad == 2)) {
					pos_lock = last_point;
				} else if (quad == 1 || quad == 3) {
					l = fabs(l*cos(D2R(((quad==1)?last_angle+90.0:last_angle-90.0)-FindAngle(
					                           pos_lock,last_point))));
					Translate( &pos_lock, last_point,
					           NormalizeAngle((quad==1)?last_angle+90.0:last_angle-90.0), l );
				} else {
					l = fabs(l*cos(D2R(((quad==0
					                     ||quad==4)?last_angle:last_angle+180.0)-FindAngle(pos_lock,last_point))));
					Translate( &pos_lock, last_point, NormalizeAngle((quad==0
					                ||quad==4)?last_angle:last_angle+180.0), l );
				}
				diff.x = pos_lock.x - points(first_inx).pt.x;
				diff.y = pos_lock.y - points(first_inx).pt.y;
				pos.x 	= points(polyInx).pt.x+diff.x;
				pos.y 	= points(polyInx).pt.y+diff.y;
				if (selected_count<2) {
					if (FindIntersection(&intersect,last_point,last_angle+90.0,next_point,
					                     last_angle+180.0)) {
						show_intersect = TRUE;
					}
				}
				d = FindDistance(intersect,pos_lock);
				if (IsClose(d)) {
					pos = intersect;
				}
				InfoMessage( _("Length = %s, Last angle = %0.2f"),
				             FormatDistance(FindDistance(pos_lock,last_point)),
				             PutAngle(FindAngle(pos_lock,last_point)));

			} else { SnapPos(&pos); }  //If not using CTL and snap enabled
		}
		context->prev_inx = first_inx;
		coOrd diff;
		diff.x = pos.x - points(polyInx).pt.x;
		diff.y = pos.y - points(polyInx).pt.y;
		//points(polyInx) = pos;
		for (int i=0; i<points_da.cnt; i++) {
			if (point_selected(i)) {
				points(i).pt.x = points(i).pt.x + diff.x;
				points(i).pt.y = points(i).pt.y + diff.y;
			}
		}
		if (first_inx>=0) {
			context->length = FindDistance(points(first_inx).pt,points(last_inx).pt);
			an1 = FindAngle(points(last_inx).pt,points(first_inx).pt);
			an0 = FindAngle(points(first_inx==0?(points_da.cnt-1):(first_inx-1)).pt,
			                points(first_inx).pt);
			context->rel_angle = NormalizeAngle(180-(an1-an0));
		}
		CreatePolyAnchors(first_inx);
		if (show_intersect) {
			CreateSquareAnchor(intersect);
		}
		context->p0 = points(0).pt;
		context->p1 = points(1).pt;
		return C_CONTINUE;
	case C_UP:
		context->prev_inx = -1;
		if (segInx == -1 || polyState != POLYPOINT_SELECTED) {
			return C_CONTINUE;        //Didn't get a point selected/added
		}
		polyState = POLY_SELECTED;  //Return to base state
		DYNARR_RESET( trkSeg_t, anchors_da );
		CreatePolyAnchors(polyInx);  //Show last selection
		prev_inx = polyInx;
		for (int i=0; i<points_da.cnt; i++) {
			if (point_selected(i)) {
				first_inx = i;
				break;
			}
		}
		last_inx = first_inx==0?(points_da.cnt-1):(first_inx-1);
		if (first_inx>=0) {
			context->length = FindDistance(points(first_inx).pt,points(last_inx).pt);
			an1 = FindAngle(points(last_inx).pt,points(first_inx).pt);
			an0 = FindAngle(points(last_inx==0?(points_da.cnt-1):(last_inx-1)).pt,
			                points(last_inx).pt);
			if (DifferenceBetweenAngles(an0,an1)<=0) {
				context->rel_angle = 180+DifferenceBetweenAngles(an0,an1);
			} else {
				context->rel_angle = 180-DifferenceBetweenAngles(an0,an1);
			}
		}
		context->prev_inx = first_inx;
		context->p0 = points(0).pt;
		context->p1 = points(1).pt;
		polyInx = -1;
		return C_CONTINUE;
	case C_UPDATE:
		if (context->prev_inx>=0) {
			int last_index = context->prev_inx==0?(points_da.cnt-1):(context->prev_inx-1);
			an0 = FindAngle(points(last_index==0?(points_da.cnt-1):(last_index-1)).pt,
			                points(last_index).pt);
			an1 = FindAngle(points(last_index).pt,points(context->prev_inx).pt);
			if (DifferenceBetweenAngles(an0,an1)<=0) {
				an1 = NormalizeAngle(an0-(180-context->rel_angle));
			} else {
				an1 = NormalizeAngle((180-context->rel_angle)+an0);
			}
			Translate(&points(prev_inx).pt,points(last_index).pt,an1,context->length);
		}
		context->rel_angle = fabs(context->rel_angle);
		if (context->rel_angle >180) { context->rel_angle = context->rel_angle - 180.0; }
		CreatePolyAnchors(prev_inx);
		context->p0 = points(0).pt;
		context->p1 = points(1).pt;
		break;
	case C_TEXT:
		DYNARR_SET( trkSeg_t, tempSegs_da, 1 );
		if (action>>8 == 'o') {  //"o" -> origin mode
			MenuMode(I2VP(1));
			InfoMessage("Move Origin Mode: Place Origin, p for Points, Enter or Esc");
			return C_CONTINUE;
		}
		if (((prev_inx>=0 && tempSegs(0).u.p.polyType != POLYLINE) ||
		     ((tempSegs(0).u.p.polyType == POLYLINE) && (prev_inx>=1)
		      && (prev_inx<=points_da.cnt-2)) ) &&
		    ((action>>8 == 's') || (action>>8 == 'v') || (action>>8 == 'r')))  {
			switch(action>>8) {
			case 's':
				points(context->prev_inx).pt_type = wPolyLineSmooth;
				return C_CONTINUE;
			case 'v':
				points(context->prev_inx).pt_type = wPolyLineStraight;
				return C_CONTINUE;
			case 'r':
				points(context->prev_inx).pt_type = wPolyLineRound;
				return C_CONTINUE;
			default:;
			}
		}
		if ((action>>8 == 'g') && (tempSegs(0).type == SEG_POLY)
		    && (tempSegs(0).u.p.polyType == POLYLINE) ) {
			tempSegs(0).u.p.polyType = FREEFORM;
			context->subtype=FREEFORM;
			context->open = FALSE;
			CreatePolyAnchors( -1);
			return C_CONTINUE;
		}
		if ((action>>8 == 'l') && (tempSegs(0).type == SEG_POLY)
		    && (tempSegs(0).u.p.polyType != POLYLINE)) {
			tempSegs(0).u.p.polyType = POLYLINE;
			context->subtype=POLYLINE;
			context->open = TRUE;
			CreatePolyAnchors( -1);
			return C_CONTINUE;
		}
		if ((action>>8 == 'f') && (tempSegs(0).type == SEG_POLY)
		    && (tempSegs(0).u.p.polyType != POLYLINE )) {
			tempSegs(0).type = SEG_FILPOLY;
			context->type =  SEG_FILPOLY;
			context->subtype=tempSegs(0).u.p.polyType;
			context->filled = TRUE;
			CreatePolyAnchors( -1);
			return C_CONTINUE;
		}
		if ((action>>8 == 'u') && (tempSegs(0).type == SEG_FILPOLY) ) {
			tempSegs(0).type = SEG_POLY;
			context->type =  SEG_POLY;
			context->subtype=tempSegs(0).u.p.polyType;
			context->filled = FALSE;
			CreatePolyAnchors( -1);
			return C_CONTINUE;
		}
		//Delete or backspace deletes last selected index
		if (action>>8 == 127 || action>>8 == 8) {
			if (polyState == POLY_SELECTED && prev_inx >=0) {
				if (selected_count >1) {
					ErrorMessage( MSG_POLY_MULTIPLE_SELECTED );
					return C_CONTINUE;
				}
				if (points_da.cnt <= 3) {
					ErrorMessage( MSG_POLY_SHAPES_3_SIDES );
					return C_CONTINUE;
				}
				for (int i=0; i<points_da.cnt; i++) {
					point_selected(i) = FALSE;
					if (i>=prev_inx && i<points_da.cnt-1) {
						points(i) = points(i+1);
					}
				}
				points_da.cnt--;
				select_da.cnt--;
				selected_count=0;
				tempSegs(0).u.p.cnt = points_da.cnt;
				context->max_inx = points_da.cnt-1;
			} else {
				ErrorMessage( MSG_POLY_NOTHING_SELECTED );
			}
			prev_inx = -1;
			context->prev_inx = -1;
			polyInx = -1;
			polyState = POLY_SELECTED;
			CreatePolyAnchors( -1);
			InfoMessage(_("Point Deleted"));
			return C_CONTINUE;
		}
		if (action>>8 != 32 && action>>8 != 13 && action>>8 !=9) { return C_CONTINUE; }
		if (action>>8 == 9 && (MyGetKeyState() & WKEY_SHIFT) != 0) { return C_TERMINATE; }
	/* no break */
	case C_CONFIRM:
	case C_OK:
	case C_FINISH:
		//copy changes back into track
		if (polyState != POLY_SELECTED) {
			polyState = POLY_NONE;
			DYNARR_RESET(trkSeg_t,anchors_da);
			DYNARR_RESET(trkSeg_t,tempSegs_da);
			return C_TERMINATE;
		}
		//If ends overlap precisely remove last segment and close if >3 points
		DIST_T dist = FindDistance(points(0).pt,points(points_da.cnt-1).pt);
		if (IsClose(dist*4) && points_da.cnt>3
		    && tempSegs(0).u.p.polyType == POLYLINE) {
			tempSegs(0).u.p.polyType = FREEFORM;
			context->subtype=FREEFORM;
			context->open = FALSE;
			points_da.cnt--;
			select_da.cnt--;
			selected_count=0;
			tempSegs(0).u.p.cnt = points_da.cnt;
			context->max_inx = points_da.cnt-1;
		}
		pts_t * oldPts = context->segPtr[segInx].u.p.pts;
		void * newPts = (pts_t*)MyMalloc( points_da.cnt * sizeof (pts_t) );
		context->segPtr[segInx].u.p.pts = newPts;
		context->segPtr[segInx].u.p.cnt = points_da.cnt;
		context->orig = rotate_origin;
		context->angle = rotate_angle;
		for (int i=0; i<points_da.cnt; i++) {
			pos = points(i).pt;
			pos.x -= context->orig.x;
			pos.y -= context->orig.y;
			Rotate( &pos, zero, -context->angle );
			context->segPtr[segInx].u.p.pts[i].pt = pos;
			context->segPtr[segInx].u.p.pts[i].pt_type = points(i).pt_type;
		}
		MyFree(oldPts);
		polyState = POLY_NONE;
		DYNARR_RESET(trkSeg_t,anchors_da);
		DYNARR_RESET(trkSeg_t,points_da);
		DYNARR_RESET(trkSeg_t,tempSegs_da);
		if ((action&0xFF)==C_CONFIRM) {
			return C_CONTINUE;
		} else {
			return C_TERMINATE;
		}
	case C_REDRAW:
		if (polyState == POLY_NONE) { return C_CONTINUE; }
		DrawSegsDA( &tempD, NULL, zero, 0.0, &tempSegs_da, trackGauge, wDrawColorBlack,
		            0 );
		DrawSegsDA( &tempD, NULL, zero, 0.0, &anchors_da, trackGauge, wDrawColorBlack,
		            0 );
		break;
	default:
		;
	}
	return C_CONTINUE;
}

void BuildCircleContext(drawModContext_t * context,int segInx)
{
	context->radius = fabs(context->segPtr[segInx].u.c.radius);
	REORIGIN( context->pc, context->segPtr[segInx].u.c.center, context->angle,
	          context->orig );
	PointOnCircle( &context->p0, context->segPtr[segInx].u.c.center,
	               fabs(context->segPtr[segInx].u.c.radius), context->segPtr[segInx].u.c.a0 );
	REORIGIN( context->p0, context->p0, context->angle, context->orig );
	PointOnCircle( &context->p1, context->segPtr[segInx].u.c.center,
	               fabs(context->segPtr[segInx].u.c.radius),
	               context->segPtr[segInx].u.c.a0 + context->segPtr[segInx].u.c.a1);
	REORIGIN( context->p1, context->p1, context->angle, context->orig );
	if (context->segPtr[segInx].u.c.a1<360) {
		context->arc_angle = context->segPtr[segInx].u.c.a1;
		PointOnCircle( &context->pm, context->segPtr[segInx].u.c.center,
		               fabs(context->segPtr[segInx].u.c.radius),
		               context->segPtr[segInx].u.c.a0 + (context->segPtr[segInx].u.c.a1/2));
		REORIGIN( context->pm, context->pm, context->angle, context->orig );
		coOrd cm;
		cm = context->pm;
		ANGLE_T a = FindAngle(context->p1,context->p0);
		Rotate(&cm,context->p1,-a );
		context->disp = cm.x-context->p1.x;
	} else {
		context->pm = context->p0;
		context->disp = 0;
		context->arc_angle = 360.0;
	}
}

void CreateSelectedAnchor(coOrd pos)
{
	double d = tempD.scale*0.15;
	DYNARR_APPEND(trkSeg_t,anchors_da,1);
	int inx = anchors_da.cnt-1;
	anchors(inx).type = SEG_FILCRCL;
	anchors(inx).u.c.a0 = 0.0;
	anchors(inx).u.c.a1 = 360.0;
	anchors(inx).color = wDrawColorBlue;
	anchors(inx).u.c.radius = d/2;
	anchors(inx).u.c.center = pos;
}

/*
 * Rotate Object Dialogs.
 *
 *  Each Draw object has a rotation origin which all the points are offset from.
 *  Formerly this has been set to the origin, but it doesn't have to be. By setting
 *  to a point on the shape this allows assembly by aligning parts to a common point on a base object.
 *  The angle is always set to zero when the Modify finishes but can be altered via Describe.
 *
 *  First locate the origin, and then place a rotation arm which is (optionally) rotated about the origin.
 *  Also supports whole object translate using translate anchor.
 **/

STATUS_T DrawGeomOriginMove(
        wAction_t action,
        coOrd pos,
        drawModContext_t * context)
{

	switch ( action&0xFF ) {
	case C_START:
		context->state = MOD_ORIGIN;
		context->rotate_state = TRUE;
		context->rot_moved = TRUE;
		DYNARR_RESET(trkSeg_t,anchors_da);
		CreateOriginAnchor(context->rot_center,FALSE);
		if ((tempSegs(0).type == SEG_POLY || tempSegs(0).type == SEG_FILPOLY)
		    && (context->prev_inx>=0)) {
			CreateSelectedAnchor(points(context->prev_inx).pt);
		}
		InfoMessage("Move Origin Mode: Place Origin, 0-4, c or l, Enter or Esc");
		return C_CONTINUE;
		break;
	case wActionMove:
		CreateOriginAnchor(context->rot_center, FALSE);
		if ((tempSegs(0).type == SEG_POLY || tempSegs(0).type == SEG_FILPOLY)
		    && (context->prev_inx>=0)) {
			CreateSelectedAnchor(points(context->prev_inx).pt);
		}
		return C_CONTINUE;
		break;
	case C_DOWN:
		if (context->state == MOD_ORIGIN || context->state == MOD_AFTER_ORIG) {
			context->state = MOD_ORIGIN;
			DYNARR_RESET(trkSeg_t,anchors_da);
			if (IsClose(FindDistance(pos,context->rot_center))) {
				pos = context->rot_center;
			} else {
				context->rot_center = pos;
			}
			CreateOriginAnchor(context->rot_center, TRUE);
			if ((tempSegs(0).type == SEG_POLY || tempSegs(0).type == SEG_FILPOLY)
			    && (context->prev_inx>=0)) {
				CreateSelectedAnchor(points(context->prev_inx).pt);
			}
		}
		return C_CONTINUE;
		break;
	case C_MOVE:
		if (context->state == MOD_ORIGIN || context->state == MOD_AFTER_ORIG) {
			context->rot_center = pos;
			DYNARR_RESET(trkSeg_t,anchors_da);
			CreateOriginAnchor(context->rot_center, TRUE);
			if ((tempSegs(0).type == SEG_POLY || tempSegs(0).type == SEG_FILPOLY)
			    && (context->prev_inx>=0)) {
				CreateSelectedAnchor(points(context->prev_inx).pt);
			}
		}
		return C_CONTINUE;
		break;
	case C_UP:
		DYNARR_RESET(trkSeg_t,anchors_da);
		if (context->state == MOD_ORIGIN) {
			context->state = MOD_AFTER_ORIG;
		}
		CreateOriginAnchor(context->rot_center,FALSE);
		if ((tempSegs(0).type == SEG_POLY || tempSegs(0).type == SEG_FILPOLY)
		    && (context->prev_inx>=0)) {
			CreateSelectedAnchor(points(context->prev_inx).pt);
		}
		return C_CONTINUE;
		break;
	case C_UPDATE:
		DYNARR_RESET(trkSeg_t,anchors_da);
		if (context->state == MOD_AFTER_ORIG) {
			if (context->rot_center.x != context->rel_center.x &&
			    context->rot_center.y != context->rel_center.y ) {
				context->rel_center = context->rot_center;
				CreateOriginAnchor(context->rot_center, FALSE);
				if ((tempSegs(0).type == SEG_POLY || tempSegs(0).type == SEG_FILPOLY)
				    && (context->prev_inx>=0)) {
					CreateSelectedAnchor(points(context->prev_inx).pt);
				}
			}
		}
		return C_CONTINUE;
		break;
	case C_TEXT:
		DYNARR_SET( trkSeg_t, tempSegs_da, 1 );
		if ((context->state == MOD_ORIGIN || context->state == MOD_AFTER_ORIG) &&
		    ((action>>8 >= '0' && action>>8 <= '1') || action>>8 == 'l' || action>>8 == 'm'
		     || action>>8 == 'p')) {
			// 0,1,2,3,4 -> reset rot center
			if (action>>8 == '0') {
				context->rot_center = zero;
			} else if (action>>8 == '1') {
				context->rot_center = context->p0;
			} else if (action>>8 == '2') {
				context->rot_center = context->p1;
			} else if (tempSegs(0).type == SEG_POLY || tempSegs(0).type == SEG_FILPOLY) {
				if (action>>8 == '3' || action>>8 == '4') {
					context->rot_center = action>>8 == '3'?points(2).pt:points(3).pt;
				} else if (action>>8 == 'l') {   //"l" - last selected
					if (context->prev_inx !=-1) {
						context->rot_center = points(context->prev_inx).pt;
					}
				} else if (action>>8 == 'm') {
					context->rot_center = FindCentroid(points_da.cnt,&points(0));
				}
			}
			if (action>>8 == 'p') {     //"p" - points mode
				MenuMode(I2VP(0));
				return C_CONTINUE;
			}
			context->rel_center = context->rot_center;
			context->rot_angle = 0;
			DYNARR_RESET(trkSeg_t,anchors_da);
			context->state = MOD_AFTER_ORIG;
			CreateOriginAnchor(context->rot_center, FALSE);
			if ((tempSegs(0).type == SEG_POLY || tempSegs(0).type == SEG_FILPOLY)
			    && (context->prev_inx>=0)) {
				CreateSelectedAnchor(points(context->prev_inx).pt);
			}
			return C_CONTINUE;
		}
		break;
	case C_FINISH:
		context->rotate_state = FALSE;
		context->state = MOD_STARTED;
		return C_CONTINUE;
		break;
	default:
		break;
	}
	return C_CONTINUE;


}

/*
 * Base Modify function for Draw objects.
 */
STATUS_T DrawGeomModify(
        wAction_t action,
        coOrd pos,
        drawModContext_t * context)
{
	ANGLE_T a;
	coOrd p0, p1, pc, pm;
	static coOrd start_pos;
	static wIndex_t segInx;
//	static EPINX_T segEp;
	static ANGLE_T segA1;
	static int inx_line, inx_origin;
//	static int inx_other;
	static BOOL_T corner_mode;
	static BOOL_T polyMode;
//	static ANGLE_T original_angle;
	int inx, inx2;
//	int inx1;
	DIST_T d, d1, d2, dd;
//	coOrd * newPts = NULL;
	switch ( action&0xFF ) {
	case C_START:
		DYNARR_SET( trkSeg_t, tempSegs_da, 1 );
		if (!context->rotate_state && !context->rot_moved) {
			context->rot_center.x = context->orig.x;
			context->rot_center.y = context->orig.y;
		}
		context->state = MOD_STARTED;
		context->rotate_state = FALSE;
		context->last_inx=-1;
		lineInx = -1;
		curveInx = -1;
		segInx = -1;
		polyMode = FALSE;
		DistanceSegs( context->orig, context->angle, context->segCnt, context->segPtr,
		              &pos, &segInx );
		if (segInx == -1) {
			return C_ERROR;
		}
		context->type = context->segPtr[segInx].type;
		switch(context->type) {
		case SEG_TBLEDGE:
		case SEG_STRLIN:
		case SEG_DIMLIN:
		case SEG_BENCH:
			REORIGIN( p0, context->segPtr[segInx].u.l.pos[0], context->angle,
			          context->orig );
			REORIGIN( p1, context->segPtr[segInx].u.l.pos[1], context->angle,
			          context->orig );
			tempSegs(0).type = SEG_STRLIN;
			tempSegs(0).color = wDrawColorRed;
			tempSegs(0).u.l.pos[0] = p0;
			tempSegs(0).u.l.pos[1] = p1;
			tempSegs(0).lineWidth = 0;
			tempSegs(0).u.l.option = context->segPtr[segInx].u.l.option;
			context->p0 = p0;
			context->p1 = p1;
			CreateLineAnchors(-1,p0,p1);
			break;
		case SEG_CRVLIN:
		case SEG_FILCRCL:
			BuildCircleContext(context,segInx);
			tempSegs(0).type = SEG_CRVLIN;
			tempSegs(0).color = wDrawColorRed;
			tempSegs(0).u.c.center = context->pc;
			tempSegs(0).u.c.radius = context->radius;
			tempSegs(0).u.c.a0 = context->segPtr[segInx].u.c.a0;
			tempSegs(0).u.c.a1 = context->segPtr[segInx].u.c.a1;
			tempSegs(0).lineWidth = 0;
			if (tempSegs(0).u.c.a1<360.0) {
				CreateCurveAnchors(-1,context->pm,context->pc,context->p0,context->p1);
			} else {
				CreateCircleAnchor(FALSE,tempSegs(0).u.c.center,tempSegs(0).u.c.radius,
				                   FindAngle(tempSegs(0).u.c.center,pos));
			}
			context->last_inx = 2;
			break;
		case SEG_POLY:
		case SEG_FILPOLY:
			if (context->segPtr[segInx].u.p.polyType !=RECTANGLE) {
				polyMode = TRUE;
				return DrawGeomPolyModify(action,pos,context);
			} else {
				tempSegs(0).type = SEG_POLY;
				tempSegs(0).color = wDrawColorRed;
				DYNARR_RESET( pts_t, points_da);
				for (int inx=0; inx<context->segPtr->u.p.cnt; inx++) {
					DYNARR_APPEND(pts_t, points_da,3);
					REORIGIN( points(inx).pt, context->segPtr[segInx].u.p.pts[inx].pt,
					          context->angle, context->orig );
				}
				tempSegs(0).u.p.pts = &points(0);
				tempSegs(0).u.p.cnt = points_da.cnt;
				tempSegs(0).lineWidth = 0;
				context->p0 = points(0).pt;
				CreateBoxAnchors(-1,&context->segPtr[segInx].u.p.pts[0]);
				context->p0 = points(0).pt;
				context->p1 = points(1).pt;

			}
			break;
		case SEG_TEXT:
			InfoMessage("Text can only be modified with Property command");
			wBeep();
			return C_ERROR;
		default:
			;
		}
		InfoMessage("Points Mode - Select and drag Anchor Point");
		return C_CONTINUE;
		break;
	case wActionMove:
		if (context->rotate_state) { return DrawGeomOriginMove(action,pos,context); }
		if (polyMode) { return DrawGeomPolyModify(action,pos,context); }
		DYNARR_RESET(trkSeg_t,anchors_da);
		wSetCursor(mainD.d,defaultCursor);
		switch( context->type) {
		case SEG_TBLEDGE:
		case SEG_STRLIN:
		case SEG_DIMLIN:
		case SEG_BENCH:
			DYNARR_RESET(trkSeg_t,anchors_da);
			CreateLineAnchors(lineInx,context->p0,context->p1);
			dd = FindDistance( context->p0, pos );
			if ( IsClose(dd)) {
				CreateMovingAnchor(context->p0,TRUE);
			} else {
				dd = FindDistance( context->p1, pos );
				if ( IsClose(dd)) {
					CreateMovingAnchor(context->p1,TRUE);
				}
			}
			break;
		case SEG_CRVLIN:
		case SEG_FILCRCL:
			DYNARR_RESET(trkSeg_t,anchors_da);
			if (tempSegs(0).u.c.a1 >= 360.0) {
				if (IsClose(FindDistance(context->pc,pos)-context->radius)) {
					coOrd p;
					Translate(&p,context->pc,FindAngle(context->pc,pos),context->radius);
					CreateMovingAnchor(p,TRUE);
					DYNARR_SET(trkSeg_t,anchors_da,anchors_da.cnt+5);
					DrawArrowHeads(&DYNARR_N(trkSeg_t,anchors_da,anchors_da.cnt-5),p,
					               FindAngle(context->pc,pos),TRUE,wDrawColorBlue);
				}
			} else {
				CreateCurveAnchors(curveInx,context->pm,context->pc,context->p0,context->p1);
				dd = FindDistance( context->p0, pos );
				if ( IsClose(dd)) {
					CreateMovingAnchor(context->p0,TRUE);
				} else {
					dd = FindDistance( context->p1, pos );
					if ( IsClose(dd)) {
						CreateMovingAnchor(context->p1,TRUE);
					} else {
						dd = FindDistance( context->pm, pos );
						if ( IsClose(dd)) {
							CreateMovingAnchor(context->pm,TRUE);
						}
					}
				}
			}
			break;
		case SEG_POLY:
		case SEG_FILPOLY:;
			CreateBoxAnchors(-1,&points(0));
			break;
		default:;
		}
		return C_CONTINUE;
		break;
	case C_DOWN:
		DYNARR_SET( trkSeg_t, tempSegs_da, 1 );
		if (context->rotate_state) { return DrawGeomOriginMove(action,pos,context); }
		if (polyMode) { return DrawGeomPolyModify(action,pos,context); }
		corner_mode = FALSE;
		segInx = 0;
		context->state = MOD_STARTED;
		tempSegs(0).lineWidth = context->segPtr[segInx].lineWidth;
		tempSegs(0).color = context->segPtr[segInx].color;
		switch ( context->type ) {
		case SEG_TBLEDGE:
		case SEG_STRLIN:
		case SEG_DIMLIN:
		case SEG_BENCH:
			p0 = context->p0;
			p1 = context->p1;
			lineInx = -1;
			dd = FindDistance( p0, pos );
			if ( IsClose(dd)) {
				lineInx = 0;
			} else {
				dd = FindDistance( p1, pos );
				if ( IsClose(dd)) {
					lineInx = 1;
				}
			}
			if (lineInx < 0 ) {
				InfoMessage( _("Not close to end of line"));
			} else {
				if (context->type == SEG_TBLEDGE) {
					InfoMessage("End selected, drag to move +Ctl to lock to other edge end, +Shift lock to line");
				} else {
					InfoMessage("End selected, drag to reposition +Shift lock to line");
				}
				context->state = MOD_SELECTED_PT;
			}
			tempSegs(0).color = wDrawColorBlack;
			tempSegs(0).lineWidth = 0;
			tempSegs(0).type = context->type;
			tempSegs(0).u.l.pos[0] = p0;
			tempSegs(0).u.l.pos[1] = p1;
			tempSegs(0).u.l.option = context->segPtr[segInx].u.l.option;
			segA1 = FindAngle( p1, p0 );
			CreateLineAnchors(lineInx,p0,p1);
			break;
		case SEG_CRVLIN:
		case SEG_FILCRCL:
			curveInx = -1;
			tempSegs(0).color = wDrawColorBlack;
			tempSegs(0).lineWidth = 0;
			tempSegs(0).type = context->type;
			tempSegs(0).u.c.center = context->pc;
			tempSegs(0).u.c.radius = context->radius;
			if (context->segPtr[segInx].u.c.a1 >= 360.0) {
				tempSegs(0).u.c.a0 = 0.0;
				tempSegs(0).u.c.a1 = 360.0;
				InfoMessage("Drag to Change Radius");
				CreateCircleAnchor(TRUE,tempSegs(0).u.c.center,tempSegs(0).u.c.radius,
				                   FindAngle(tempSegs(0).u.c.center,pos));
			} else {
				p0 = context->p0;
				p1 = context->p1;
				pm = context->pm;
				pc = context->pc;
				tempSegs(0).u.c.a0 = FindAngle(context->pc,context->p0);
				tempSegs(0).u.c.a1 = DifferenceBetweenAngles(FindAngle(context->pc,context->p0),
				                     FindAngle(context->pc,context->p1));
				tempSegs(0).u.c.center = context->pc;
				tempSegs(0).u.c.radius = context->radius;
				curveInx = -1;
				dd = FindDistance( p0, pos );
				if ( IsClose(dd)) {
					curveInx = 0;
				} else {
					dd = FindDistance( p1, pos );
					if ( IsClose(dd)) {
						curveInx = 1;
					} else {
						dd = FindDistance( pm, pos );
						if ( IsClose(dd)) {
							curveInx = 2;
						}
					}
				}
				if (curveInx < 0) {
					InfoMessage( _("Not close to ends or middle of mine, reselect"));
					return C_CONTINUE;
				} else {
					if (curveInx <2 ) {
						InfoMessage("Drag to move end, +Ctrl to lock to other objects");
					} else {
						InfoMessage("Drag to change radius");
					}
				}
				if (tempSegs(0).u.c.a1 < 360.0) {
					CreateCurveAnchors(curveInx,pm,pc,p0,p1);
				}
			}
			context->state = MOD_SELECTED_PT;
			break;
		case SEG_POLY:
		case SEG_FILPOLY:
			d = 10000;
			polyInx = 0;
			wSetCursor(mainD.d,wCursorNone);
			for ( inx=0; inx<4; inx++ ) {
				if (IsClose(FindDistance(pos,points(inx).pt))) {
					corner_mode = TRUE;
					polyInx = inx;
					break;
				}
				p0 = pos;
				dd = LineDistance( &p0, points( inx==0?3:inx-1).pt, points( inx ).pt );
				if ( d > dd ) {
					d = dd;
					inx_line = inx;
				}
			}
			if (!corner_mode) {
				d1 = FindDistance( points(inx_line).pt, pos );
				d2 = FindDistance( points(inx_line==0?3:inx_line-1).pt, pos );
				if (d2<d1) {
					polyInx = inx_line==0?3:inx_line-1;
				} else {
					polyInx = inx_line;
				}
			}
//			inx1 = (polyInx==0?3:polyInx-1);  //Prev point
			inx2 = (polyInx==3?0:polyInx+1);  //Next Point
			inx_origin = (inx2==3?0:inx2+1);  //Opposite point
			if ( corner_mode ) {
				start_pos = pos;
				pos = points(inx).pt;
				DYNARR_SET(trkSeg_t,anchors_da,5);
				DrawArrowHeads( &anchors(0), pos, FindAngle(points(polyInx).pt,
				                points(inx_origin).pt), TRUE, wDrawColorRed );
				InfoMessage( _("Drag to Move Corner Point"));
			} else {
				start_pos = pos;
				pos.x = (points(inx_line).pt.x + points(inx_line==0?3:inx_line-1).pt.x)/2;
				pos.y = (points(inx_line).pt.y + points(inx_line==0?3:inx_line-1).pt.y)/2;
				DYNARR_SET(trkSeg_t,anchors_da,5);
				DrawArrowHeads( &anchors(0), pos, FindAngle(points(polyInx).pt,pos)+90, TRUE,
				                wDrawColorRed );
				InfoMessage( _("Drag to Move Edge "));
			}
			context->state = MOD_SELECTED_PT;
			return C_CONTINUE;
		case SEG_TEXT:
			segInx = -1;
			return C_ERROR;
		default:
			CHECK( FALSE ); /* CHECKME */

		}
		if ( FindDistance( p0, pos ) >= FindDistance( p1, pos ) ) {
			switch ( context->type ) {
			case SEG_TBLEDGE:
			case SEG_STRLIN:
			case SEG_DIMLIN:
			case SEG_BENCH:
				segA1 = NormalizeAngle( segA1 + 180.0 );
				break;
			default:
				;
			}
		}
		UndrawNewTrack( context->trk );
		return C_CONTINUE;
	case C_MOVE:

		if (context->rotate_state) { return DrawGeomOriginMove(action,pos,context); }
		if (polyMode) { return DrawGeomPolyModify(action,pos,context); }
		if (context->state != MOD_SELECTED_PT) { return C_CONTINUE; }
		BOOL_T locked = FALSE;
		switch (tempSegs(0).type) {
		case SEG_TBLEDGE:
			if ( (MyGetKeyState() & WKEY_CTRL) ==
			     WKEY_CTRL ) { //Special Snap to Table End Point if Ctrl
				if (OnTableEdgeEndPt( NULL, &pos )) {
					locked = TRUE;
				}
			}
		/* No Break*/
		case SEG_STRLIN:
		case SEG_DIMLIN:
		case SEG_BENCH:
			if (!locked) {
				if ((MyGetKeyState() & WKEY_SHIFT) != 0) {     //Shift is on same line
					d = FindDistance( pos, tempSegs(0).u.l.pos[1-lineInx] );
					Translate( &pos, tempSegs(0).u.l.pos[1-lineInx], segA1, d );
					locked = TRUE;
				} else if (((MyGetKeyState() & WKEY_ALT) == 0) ==
				           magneticSnap )  {  //M.S. Either on or Off
					if (OnTrack( &pos, FALSE, FALSE )!=NULL) {
						CreateEndAnchor(pos,TRUE);
						locked = TRUE;
					}
				}
			};
			if (!locked) {
				if (SnapPos(&pos)) { locked = TRUE; }
			}
			break;
		default:
			break;
		}
		int prior_pnt, next_pnt, orig_pnt;
		ANGLE_T prior_angle, next_angle, line_angle;
		switch (tempSegs(0).type) {
		case SEG_TBLEDGE:
		case SEG_STRLIN:
		case SEG_DIMLIN:
		case SEG_BENCH:
			if (lineInx<0 || lineInx>1) { return C_CONTINUE; }
			tempSegs(0).u.l.pos[lineInx] = pos;
			InfoMessage( _("Length = %0.3f Angle = %0.3f"),
			             FindDistance( tempSegs(0).u.l.pos[lineInx], tempSegs(0).u.l.pos[1-lineInx] ),
			             FindAngle( tempSegs(0).u.l.pos[1-lineInx], tempSegs(0).u.l.pos[lineInx] ) );
			context->p0 = tempSegs(0).u.l.pos[0];
			context->p1 = tempSegs(0).u.l.pos[1];
			p0 = context->p0;
			p1 = context->p1;
			CreateLineAnchors(lineInx, p0, p1);
			break;
		case SEG_CRVLIN:
		case SEG_FILCRCL:
			if (tempSegs(0).u.c.a1 >= 360.0) {
				tempSegs(0).u.c.radius = FindDistance( context->pc, pos );
				CreateCircleAnchor(TRUE,tempSegs(0).u.c.center,tempSegs(0).u.c.radius,
				                   FindAngle(tempSegs(0).u.c.center,pos));
			} else {
				if (context->state != MOD_SELECTED_PT) { return C_CONTINUE; }
				if (curveInx < 0 || curveInx > 2) { return C_CONTINUE; }
				wSetCursor(mainD.d,wCursorNone);
				p0 = context->p0;
				p1 = context->p1;
				pc = context->pc;
				pm = context->pm;
				if ( (MyGetKeyState() & WKEY_SHIFT) != 0) {
					//Preserve Radius, Change swept angle
					a = FindAngle( pc, pos );
					if (curveInx==0) {
						tempSegs(0).u.c.a1 = NormalizeAngle(FindAngle(pc,p1)-a);
						tempSegs(0).u.c.a0 = a;
					} else if (curveInx ==1) {
						tempSegs(0).u.c.a1 = NormalizeAngle(a-tempSegs(0).u.c.a0);
					}
					PointOnCircle(&p0,pc,context->radius,tempSegs(0).u.c.a0);
					PointOnCircle(&p1,pc,context->radius,tempSegs(0).u.c.a0+tempSegs(0).u.c.a1);
					context->p0 = p0;
					context->p1 = p1;
					PointOnCircle(&pm,pc,context->radius,tempSegs(0).u.c.a0+(tempSegs(0).u.c.a1/2));
					context->pm = pm;
				} else {
					if (curveInx == 0 || curveInx == 1) {
						p0 = context->p0;
						p1 = context->p1;
						/* Preserve Curve "Deflection" */
						d = context->disp;  	// Original Deflection
						if (curveInx == 0) {
							context->p0 = p0 = pos;
						} else {
							context->p1 = p1 = pos;
						}
						coOrd posx; //Middle of chord
						posx.x = (p1.x-p0.x)/2.0+p0.x;
						posx.y = (p1.y-p0.y)/2.0+p0.y;			//Middle of chord
						ANGLE_T a0 = FindAngle( p1, p0 );
						DIST_T d0 = FindDistance( p0, p1 )/2.0;
						DIST_T r = 1000.0;
						if ( fabs(d) >= 0.01 ) {
							d2 = sqrt( d0*d0 + d*d )/2.0;
							r = d2*d2*2.0/d;
							if ( fabs(r) > 1000.0 ) {
								r = ((r > 0)? 1 : -1) *1000.0;
							}
						} else {
							r = ((r > 0) ? 1 : -1 ) *1000.0;
						}
						a0 -= 90.0;
						if (r<0) {
							coOrd pt = p0;
							p0 = p1;
							p1 = pt;
							a0 += 180.0;
						}
						context->radius = tempSegs(0).u.c.radius = fabs(r);
						Translate( &pc, posx, a0, fabs(r)-fabs(d) );
						context->pc = tempSegs(0).u.c.center = pc;
						tempSegs(0).u.c.a0 = FindAngle(pc,p0);
						context->arc_angle = tempSegs(0).u.c.a1 = NormalizeAngle(FindAngle(pc,
						                     p1)-FindAngle(pc,p0));
						PointOnCircle(&pm,pc,context->radius,
						              tempSegs(0).u.c.a0+(tempSegs(0).u.c.a1/2.0));
						context->pm = pm;
					} else {
						//Change radius using chord
						p0 = context->p0;
						p1 = context->p1;
						pm = context->pm;
						ANGLE_T a0 = FindAngle( p1, p0 );
						DIST_T d0 = FindDistance( p0, p1 )/2.0;
						coOrd pos2 = pos;
						Rotate( &pos2, p1, -a0 );
						pos2.x -= p1.x;
						DIST_T r = 1000.0;
						if ( fabs(pos2.x) >= 0.01 ) {
							d2 = sqrt( d0*d0 + pos2.x*pos2.x )/2.0;
							r = d2*d2*2.0/pos2.x;
							if ( fabs(r) > 1000.0 ) {
								r = ((r > 0) ? 1 :  -1 ) *1000.0;
							}
						} else {
							r = ((r > 0) ? 1 :  -1 ) *1000.0;
						}
						coOrd posx; //Middle of chord
						posx.x = (p1.x-p0.x)/2.0 + p0.x;
						posx.y = (p1.y-p0.y)/2.0 + p0.y;
						a0 -= 90.0;
						if (r<0) {
							coOrd pt = p0;
							p0 = p1;
							p1 = pt;
							a0 += 180.0;
						}
						Translate( &pc, posx, a0, fabs(r) - fabs(pos2.x) );
						context->pc = tempSegs(0).u.c.center = pc;
						context->radius = tempSegs(0).u.c.radius = fabs(r);
						a0 = FindAngle( pc, p0 );
						ANGLE_T a1 = FindAngle( pc, p1 );
						tempSegs(0).u.c.a0 = a0;
						tempSegs(0).u.c.a1 = NormalizeAngle(a1-a0);
						PointOnCircle(&pm,pc,context->radius,a0+(NormalizeAngle(a1-a0)/2));
						context->p0 = p0;
						context->p1 = p1;
						context->pm = pm;
						context->disp = pos2.x;
					}
				}
				if (tempSegs(0).u.c.a1 < 360.0) {
					CreateCurveAnchors(curveInx,pm,pc,p0,p1);
				}
			}
			break;
		case SEG_POLY:
		case SEG_FILPOLY:
			wSetCursor(mainD.d,wCursorNone);
			if (!corner_mode) {
				/* Constrain movement to be perpendicular */
				d = FindDistance(start_pos, pos);
				line_angle = NormalizeAngle(FindAngle(points(inx_line).pt,
				                                      points(inx_line==3?0:inx_line+1).pt));
				a = FindAngle(pos,start_pos);
				Translate( &pos, start_pos, line_angle, - d*cos(D2R(line_angle-a)));
			}
			d = FindDistance(start_pos,pos);
			a = FindAngle(start_pos, pos);
			start_pos = pos;
			prior_pnt = (polyInx == 0)?3:polyInx-1;
			next_pnt = (polyInx == 3)?0:polyInx+1;
			orig_pnt = (prior_pnt == 0)?3:prior_pnt-1;
			Translate( &points(polyInx).pt, points(polyInx).pt, a, d);
			d = FindDistance(points(orig_pnt).pt,points(polyInx).pt);
			a = FindAngle(points(orig_pnt).pt,points(polyInx).pt);
			prior_angle = FindAngle(points(orig_pnt).pt,points(prior_pnt).pt);
			Translate( &points(prior_pnt).pt, points(orig_pnt).pt, prior_angle,
			           d*cos(D2R(prior_angle-a)));
			next_angle = FindAngle(points(orig_pnt).pt,points(next_pnt).pt);
			Translate( &points(next_pnt).pt, points(orig_pnt).pt, next_angle,
			           d*cos(D2R(next_angle-a)));
			if (!corner_mode) {
				pos.x = (points(inx_line).pt.x + points(inx_line==0?3:inx_line-1).pt.x)/2;
				pos.y = (points(inx_line).pt.y + points(inx_line==0?3:inx_line-1).pt.y)/2;
				DYNARR_SET(trkSeg_t,anchors_da,5);
				DrawArrowHeads( &anchors(0), pos, FindAngle(points(inx_line).pt,
				                points(inx_line==0?3:inx_line-1).pt)+90, TRUE, wDrawColorRed );
				InfoMessage( _("Drag to Move Edge"));
			} else {
				pos = points(polyInx).pt;
				DYNARR_SET(trkSeg_t,anchors_da,5);
				DrawArrowHeads( &anchors(0), pos, FindAngle(points(polyInx).pt,
				                points(inx_origin).pt), TRUE, wDrawColorRed );
				InfoMessage( _("Drag to Move Corner Point"));
			}
			context->p0 = points(0).pt;
			context->p1 = points(1).pt;
			break;
		default:
			;
		}
		return C_CONTINUE;
	case C_UP:
		if (context->rotate_state) { return DrawGeomOriginMove(action, pos, context); }
		if (polyMode) {
			int rc;
			rc = DrawGeomPolyModify(action,pos,context);
			if (context->prev_inx != -1) {
				context->state = MOD_AFTER_PT;
			}
			return rc;
		}
		wSetCursor(mainD.d,defaultCursor);
		if (segInx == -1) {
			return C_CONTINUE;
		}
		switch (tempSegs(0).type) {
		case SEG_TBLEDGE:
		case SEG_STRLIN:
		case SEG_DIMLIN:
		case SEG_BENCH:
			p0 = context->p0;
			p1 = context->p1;
			context->abs_angle = FindAngle(p0,p1);
			context->length = FindDistance(p0,p1);
			CreateLineAnchors(lineInx,p0,p1);
			context->last_inx = lineInx;
			break;
		case SEG_CRVLIN:
		case SEG_FILCRCL:
			if ( (tempSegs(0).type == SEG_FILCRCL) || (tempSegs(0).u.c.a1 == 360.0
			                || tempSegs(0).u.c.a1 == 0.0) ) {
				context->radius = fabs(tempSegs(0).u.c.radius);
				context->arc_angle = 360.0;
				CreateCircleAnchor(FALSE,tempSegs(0).u.c.center,tempSegs(0).u.c.radius,
				                   FindAngle(tempSegs(0).u.c.center,pos));
			} else {
				p0 = context->p0;
				p1 = context->p1;
				pc = context->pc;
				pm = context->pm;
				context->radius = fabs(tempSegs(0).u.c.radius);
				context->arc_angle = tempSegs(0).u.c.a1;
				CreateCurveAnchors(curveInx,pm,pc,p0,p1);
				a = FindAngle(p1,p0);
				Rotate(&pm,p1,-a);
				context->disp = pm.x-p1.x;
			}
			context->last_inx = curveInx;
			break;
		case SEG_POLY:
		case SEG_FILPOLY:
			CreateBoxAnchors(-1,tempSegs(0).u.p.pts);
			context->width = FindDistance(tempSegs(0).u.p.pts[0].pt,
			                              tempSegs(0).u.p.pts[1].pt);
			context->height = FindDistance(tempSegs(0).u.p.pts[1].pt,
			                               tempSegs(0).u.p.pts[2].pt);
			context->last_inx = polyInx;
			if (corner_mode) { context->last_inx +=5; }
			break;
		default:
			;
		}
		context->state = MOD_AFTER_PT;
		curveInx = -1;
		lineInx = -1;
		polyInx = -1;
		InfoMessage("Enter/Space to Accept, ESC to Reject");
		return C_CONTINUE;
	case C_UPDATE:
		if (context->rotate_state) { return DrawGeomOriginMove(action, pos, context); }

		if (polyMode) { return DrawGeomPolyModify(action,pos,context); }
		if (context->state == MOD_AFTER_PT) {
			switch (tempSegs(0).type) {
			case SEG_TBLEDGE:
			case SEG_STRLIN:
			case SEG_DIMLIN:
			case SEG_BENCH:
				context->abs_angle = NormalizeAngle(context->abs_angle);
				Translate(&tempSegs(0).u.l.pos[1],tempSegs(0).u.l.pos[0],context->abs_angle,
				          context->length);
				CreateLineAnchors(context->last_inx,tempSegs(0).u.l.pos[0],
				                  tempSegs(0).u.l.pos[1]);
				context->p0 = tempSegs(0).u.l.pos[0];
				context->p1 = tempSegs(0).u.l.pos[1];
				break;
			case SEG_CRVLIN:
			case SEG_FILCRCL:
				if (tempSegs(0).u.c.a1 == 360.0 || tempSegs(0).u.c.a1 == 0.0) {
					tempSegs(0).u.c.a1 = 360.0;
					tempSegs(0).u.c.radius = context->radius;
					Translate(&p0,tempSegs(0).u.c.center,tempSegs(0).u.c.a0,tempSegs(0).u.c.radius);
					context->p0 = p0;
					context->p1 = p0;
					context->pm = p0;
					context->pc = tempSegs(0).u.c.center;
					break;
				}
				if (context->radius < 0) { //swap ends
					context->radius = fabs(context->radius);
					p1 = context->p0;
					p0 = context->p1;
					a = FindAngle(context->pc,context->pm);
					Translate(&pm,context->pm,a+180,2*context->disp);
					Translate(&pc,pm,a,context->radius);
					context->pm = pm;
					context->pc = pc;
					context->p0 = p0;
					context->p1 = p1;
				} else {
					pm = context->pm;
					pc = context->pc;
					p0 = context->p0;
					p1 = context->p1;
				}
				if (context->last_inx == 0) {
					p1 = context->p1;
					pc = context->pc;
					a = FindAngle(p1,pc);
					Translate(&pc,p1,a,context->radius);
					context->pc = pc;
					PointOnCircle( &p0, context->pc, context->radius,
					               NormalizeAngle(a+180-context->arc_angle) );
					context->p0 = p0;
					PointOnCircle( &pm, context->pc, context->radius,
					               NormalizeAngle(a+180-(context->arc_angle/2)));
					context->pm = pm;
				} else if (context->last_inx == 1) {
					p0 = context->p0;
					pc = context->pc;
					a = FindAngle(p0,pc);
					Translate(&pc,p0,a,context->radius);
					context->pc = pc;
					PointOnCircle( &p1, context->pc, context->radius,
					               NormalizeAngle(a+180+context->arc_angle) );
					context->p1 = p1;
					PointOnCircle( &pm, context->pc, context->radius,
					               NormalizeAngle(a+180+(context->arc_angle/2)));
					context->pm = pm;
				} else {   // Middle if neither
					a = FindAngle(context->pm,context->pc);
					Translate(&pc,context->pm,a,context->radius);
					context->pc = pc;
					PointOnCircle( &p1, context->pc, context->radius,
					               NormalizeAngle(FindAngle(context->pc,context->pm)+(context->arc_angle/2)) );
					PointOnCircle( &p0, context->pc, context->radius,
					               NormalizeAngle(FindAngle(context->pc,context->pm)-(context->arc_angle/2)) );
					context->p1 = p1;
					context->p0 = p0;
				}
				a = FindAngle(p1,p0);
				Rotate(&pm,p1,-a);
				context->disp = pm.x-p1.x;
				tempSegs(0).u.c.center = context->pc;
				tempSegs(0).u.c.a0 = FindAngle(context->pc,context->p0);
				tempSegs(0).u.c.a1 = NormalizeAngle(FindAngle(context->pc,
				                                    context->p1)-tempSegs(0).u.c.a0);
				if (tempSegs(0).u.c.a1 == 0.0) { tempSegs(0).u.c.a1 = 360.0; }
				tempSegs(0).u.c.radius = context->radius;
				CreateCurveAnchors(context->last_inx,context->pm,context->pc,context->p0,
				                   context->p1);
				break;
			case SEG_POLY:
			case SEG_FILPOLY:
				a = NormalizeAngle(FindAngle(points(0).pt,points(3).pt));
				Translate( &points(3).pt, points(0).pt, a, context->height);
				Translate( &points(2).pt, points(1).pt, a, context->height);
				a = NormalizeAngle(FindAngle(points(0).pt,points(1).pt));;
				Translate( &points(1).pt, points(0).pt, a, context->width);
				Translate( &points(2).pt, points(3).pt, a, context->width);
				CreateBoxAnchors(context->last_inx,&points(0));
				break;
			default:
				break;
			}
		}
		break;
	case wActionExtKey:
		if ((((action>>8)&0xFF)== wAccelKey_Del)
		    && polyMode) { //Convert Del key to be BackSpace in PolyModify
			return DrawGeomPolyModify(C_TEXT+((int)(127<<8)),pos,context);
		}
		break;
	case C_TEXT:
		DYNARR_SET( trkSeg_t, tempSegs_da, 1 );
		if (context->rotate_state) { DrawGeomOriginMove(action, pos, context); }

		if (polyMode) { return DrawGeomPolyModify(action,pos,context); }

		if (action>>8 == 'o') {
			MenuMode(I2VP(1));
		}
		if (context->subtype == RECTANGLE) {
			switch (action>>8) {
			case 'f':
				tempSegs(0).type = SEG_FILPOLY;
				context->type = SEG_FILPOLY;
				break;
			case 'u':
				tempSegs(0).type = SEG_POLY;
				context->type = SEG_POLY;
				break;
			}
		}

		if (action>>8 != 32 && action>>8 != 13) { return C_CONTINUE; }
	/* no break */
	case C_CONFIRM:
		return C_CONTINUE;
	/* no break*/
	case C_OK:
	case C_FINISH:
		UndoStart("Modify Draw", "OK");
		UndoModify(context->trk);
		if (polyMode) {
			DrawGeomPolyModify(action,pos,context);
			context->segPtr[segInx].type = context->type;
			context->segPtr[segInx].u.p.polyType = context->subtype;
			if (context->segPtr[segInx].type == SEG_FILPOLY) {
				context->segPtr[segInx].u.p.polyType =
				        FREEFORM;        //Ensure Filled is closed
			}
			context->state = MOD_NONE;
			DrawNewTrack( context->trk );
			DYNARR_RESET( trkSeg_t, tempSegs_da );
			return C_TERMINATE;
		}
		//copy changes back into track
		context->orig.x = context->rot_center.x;
		context->orig.y = context->rot_center.y;
		context->rot_moved = FALSE;
		context->angle = 0.0;
		switch (tempSegs(0).type) {
		case SEG_TBLEDGE:
		case SEG_STRLIN:
		case SEG_DIMLIN:
		case SEG_BENCH:
			for (int i=0; i<2; i++) {
				pos = i==0?context->p0:context->p1;
				pos.x -= context->rot_center.x;
				pos.y -= context->rot_center.y;
				context->segPtr[segInx].u.l.pos[i] = pos;
			}
			break;
		case SEG_CRVLIN:
		case SEG_FILCRCL:
			pc = context->pc;
			pc.x -= context->rot_center.x;
			pc.y -= context->rot_center.y;
			context->segPtr[segInx].u.c.center = pc;
			p0 = context->p0;
			p0.x -= context->rot_center.x;
			p0.y -= context->rot_center.y;
			p1 = context->p1;
			p1.x -= context->rot_center.x;
			p1.y -= context->rot_center.y;
			context->segPtr[segInx].u.c.a0 = FindAngle(pc,p0);
			context->segPtr[segInx].u.c.a1 = NormalizeAngle(FindAngle(pc,p1)-FindAngle(pc,
			                                 p0));
			if (context->segPtr[segInx].u.c.a1 == 0) { context->segPtr[segInx].u.c.a1 = 360.0; }
			context->segPtr[segInx].u.c.radius = context->radius;
			break;
		case SEG_POLY:
		case SEG_FILPOLY:
			for (int i=0; i<4; i++) {
				pos = points(i).pt;
				pos.x -= context->rot_center.x;
				pos.y -= context->rot_center.y;
				context->segPtr[segInx].u.p.pts[i].pt = pos;
			}
			break;
		default:
			break;
		}
		context->state = MOD_NONE;
		context->rotate_state = FALSE;
		context->last_inx = -1;
		DYNARR_RESET(trkSeg_t,anchors_da);
		DYNARR_RESET( trkSeg_t, tempSegs_da );
		DrawNewTrack( context->trk );
		return C_TERMINATE;
	case C_REDRAW:
		if (polyMode) { return DrawGeomPolyModify(action,pos,context); }
		if (context->state == MOD_NONE) { return C_CONTINUE; }
		DrawSegsDA( &tempD, NULL, zero, 0.0, &tempSegs_da, trackGauge, wDrawColorBlack,
		            0 );
		DrawSegsDA( &tempD, NULL, zero, 0.0, &anchors_da, trackGauge, wDrawColorBlack,
		            0 );
		break;
	case C_CANCEL:
		context->state = MOD_NONE;
		context->rotate_state = FALSE;
		context->rot_moved = FALSE;
		polyMode = FALSE;
		DYNARR_RESET(trkSeg_t,anchors_da);
		DYNARR_RESET( trkSeg_t, tempSegs_da );
		DrawNewTrack( context->trk );
		break;
	default:
		;
	}
	return C_CONTINUE;
}


